Skip to content

Commit

Permalink
Add simple config migrator
Browse files Browse the repository at this point in the history
  • Loading branch information
whatuserever committed Feb 13, 2025
1 parent 05b6b16 commit 97cbd8a
Show file tree
Hide file tree
Showing 6 changed files with 147 additions and 3 deletions.
6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -98,10 +98,12 @@
"react-dom": "^18.3.1",
"svelte": "^4.2.19",
"web-vitals": "^4.2.3",
"ynab": "^1.19.0"
"ynab": "^1.19.0",
"zod": "^3.24.2"
},
"resolutions": {
"underscore": "1.12.1",
"ws": "8.17.1"
}
},
"packageManager": "[email protected]+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
}
3 changes: 2 additions & 1 deletion packages/main/src/backend/configManager/configManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { configFilePath } from '@/app-globals';
import { type Config } from '@/backend/commonTypes';
import { decrypt, encrypt } from '@/backend/configManager/encryption/crypto';
import { existsSync, promises as fs } from 'fs';
import { migrateConfig } from './configMigration/configMigrator';
import configExample from './defaultConfig';
import logger from '/@/logging/logger';

Expand All @@ -19,7 +20,7 @@ export async function getConfig(configPath: string = configFilePath): Promise<Co
logger.log('Empty config file found, returning default config');
return configExample;
}
return config;
return migrateConfig(config);
} catch (e) {
logger.error('Failed to parse config file, returning default config', e);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { z } from 'zod';
import { type Config } from '../../commonTypes';
import { isOriginalConfig } from './versions/original';
import { migrateOriginalToV1, v1ConfigSchema } from './versions/v1';

const latestConfigSchema = v1ConfigSchema;

// migrations[n] should be a function that converts version n to version n+1
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const migrations: Record<number, (config: any) => any> = {};

export function migrateConfig(config: unknown): Config {
let currentConfig = config;
// original config does not have version key and must be handled separately
if (isOriginalConfig(config)) {
currentConfig = migrateOriginalToV1(config);
}
let currentVersion = getConfigVersion(currentConfig);

while (migrations[currentVersion]) {
currentConfig = migrations[currentVersion](currentConfig);
currentVersion = getConfigVersion(currentConfig);
}

return latestConfigSchema.parse(currentConfig) as Config;
}

function getConfigVersion(config: unknown): keyof typeof migrations {
const versionSchema = z.object({ version: z.number().int().positive() });
return versionSchema.parse(config).version;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import { z } from 'zod';

export const outputVendorNameSchema = z.enum(['ynab', 'googleSheets', 'json', 'csv']);

export const companyTypeSchema = z.enum([
'hapoalim',
'hapoalimBeOnline',
'beinleumi',
'union',
'amex',
'isracard',
'visaCal',
'max',
'leumiCard',
'otsarHahayal',
'discount',
'mercantile',
'mizrahi',
'leumi',
'massad',
'yahav',
'behatsdaa',
'beyahadBishvilha',
'oneZero',
'pagi',
]);

export const googleSheetsConfigSchema = z.object({
active: z.boolean(),
options: z.object({
credentials: z.any(),
spreadsheetId: z.string(),
}),
});

export const ynabConfigSchema = z.object({
active: z.boolean(),
options: z.object({
accessToken: z.string(),
accountNumbersToYnabAccountIds: z.record(z.string(), z.string()),
budgetId: z.string(),
maxPayeeNameLength: z.number().optional(),
}),
});

export const jsonConfigSchema = z.object({
active: z.boolean(),
options: z.object({
filePath: z.string(),
}),
});

export const csvConfigSchema = z.object({
active: z.boolean(),
options: z.object({
filePath: z.string(),
}),
});

export const outputVendorsSchema = z.object({
[outputVendorNameSchema.Values.googleSheets]: googleSheetsConfigSchema.optional(),
[outputVendorNameSchema.Values.ynab]: ynabConfigSchema.optional(),
[outputVendorNameSchema.Values.json]: jsonConfigSchema.optional(),
[outputVendorNameSchema.Values.csv]: csvConfigSchema.optional(),
});

export const accountToScrapeConfigSchema = z.object({
id: z.string(),
key: companyTypeSchema,
name: z.string(),
loginFields: z.any(),
active: z.boolean().optional(),
});

export const scrapingSchema = z.object({
numDaysBack: z.number(),
showBrowser: z.boolean(),
accountsToScrape: z.array(accountToScrapeConfigSchema),
chromiumPath: z.string().optional(),
maxConcurrency: z.number().optional(),
timeout: z.number(),
periodicScrapingIntervalHours: z.number().optional(),
});

export const originalConfigSchema = z.object({
outputVendors: outputVendorsSchema,
scraping: scrapingSchema,
useReactUI: z.boolean().optional(),
});

export function isOriginalConfig(obj: unknown): obj is z.infer<typeof originalConfigSchema> {
const parseResult = originalConfigSchema.strict().safeParse(obj);
return parseResult.success;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { z } from 'zod';
import { originalConfigSchema } from './original';

export const v1ConfigSchema = originalConfigSchema.extend({ version: z.literal(1) });

export function migrateOriginalToV1(v1Config: z.infer<typeof originalConfigSchema>): z.infer<typeof v1ConfigSchema> {
return {
...v1Config,
version: 1,
};
}
5 changes: 5 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -6493,3 +6493,8 @@ [email protected]:
version "3.23.8"
resolved "https://registry.yarnpkg.com/zod/-/zod-3.23.8.tgz#e37b957b5d52079769fb8097099b592f0ef4067d"
integrity sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==

zod@^3.24.2:
version "3.24.2"
resolved "https://registry.yarnpkg.com/zod/-/zod-3.24.2.tgz#8efa74126287c675e92f46871cfc8d15c34372b3"
integrity sha512-lY7CDW43ECgW9u1TcT3IoXHflywfVqDYze4waEz812jR/bZ8FHDsl7pFQoSZTz5N+2NqRXs8GBwnAwo3ZNxqhQ==

0 comments on commit 97cbd8a

Please sign in to comment.