(options: RemoteConfigProfileOptions)
| 13 | import { parseSourceValue } from '../utils/source-value.ts'; |
| 14 | |
| 15 | function readRemoteConfigFile(options: RemoteConfigProfileOptions): ResolvedRemoteConfigProfile { |
| 16 | const env = options.env ?? process.env; |
| 17 | const resolvedPath = resolveRemoteConfigPath(options); |
| 18 | if (!fs.existsSync(resolvedPath)) { |
| 19 | throw new AppError('INVALID_ARGS', `Remote config file not found: ${resolvedPath}`); |
| 20 | } |
| 21 | |
| 22 | let raw: string; |
| 23 | try { |
| 24 | raw = fs.readFileSync(resolvedPath, 'utf8'); |
| 25 | } catch (error) { |
| 26 | throw new AppError('INVALID_ARGS', `Failed to read remote config file: ${resolvedPath}`, { |
| 27 | cause: error instanceof Error ? error.message : String(error), |
| 28 | }); |
| 29 | } |
| 30 | |
| 31 | let parsed: unknown; |
| 32 | try { |
| 33 | parsed = JSON.parse(raw); |
| 34 | } catch (error) { |
| 35 | throw new AppError('INVALID_ARGS', `Invalid JSON in remote config file: ${resolvedPath}`, { |
| 36 | cause: error instanceof Error ? error.message : String(error), |
| 37 | }); |
| 38 | } |
| 39 | |
| 40 | if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) { |
| 41 | throw new AppError( |
| 42 | 'INVALID_ARGS', |
| 43 | `Remote config file must contain a JSON object: ${resolvedPath}`, |
| 44 | ); |
| 45 | } |
| 46 | |
| 47 | const profile: RemoteConfigProfile = {}; |
| 48 | const source = parsed as Record<string, unknown>; |
| 49 | const configDir = path.dirname(resolvedPath); |
| 50 | for (const [rawKey, rawValue] of Object.entries(source)) { |
| 51 | const spec = getRemoteConfigFieldSpec(rawKey as keyof RemoteConfigProfile); |
| 52 | if (!spec) { |
| 53 | throw new AppError( |
| 54 | 'INVALID_ARGS', |
| 55 | `Unsupported remote config key "${rawKey}" in remote config file ${resolvedPath}.`, |
| 56 | ); |
| 57 | } |
| 58 | const parsedValue = parseSourceValue( |
| 59 | spec, |
| 60 | rawValue, |
| 61 | `remote config file ${resolvedPath}`, |
| 62 | rawKey, |
| 63 | ); |
| 64 | (profile as Record<string, unknown>)[spec.key] = |
| 65 | typeof parsedValue === 'string' && 'path' in spec && spec.path |
| 66 | ? resolveUserPath(parsedValue, { cwd: configDir, env }) |
| 67 | : parsedValue; |
| 68 | } |
| 69 | |
| 70 | return { resolvedPath, profile }; |
| 71 | } |
| 72 |
no test coverage detected