import { readFileSync } from 'node:fs'; import { THREADS } from '../../src/constants/threads.ts'; export interface ThreadsConfig { accessToken: string; siteUrl: string; stateDir: string; imageDir: string; imageBaseUrl: string; } export function loadThreadsConfig(path: string | URL = new URL('../../.env.threads.json', import.meta.url), optional = false): ThreadsConfig { const defaults: ThreadsConfig = { accessToken: '', siteUrl: THREADS.siteUrl, stateDir: 'data/threads', imageDir: 'dist/threads-captures', imageBaseUrl: `${THREADS.siteUrl}/threads-captures/`, }; let contents: string; try { contents = readFileSync(path, 'utf8'); } catch (error) { if (optional && (error as NodeJS.ErrnoException).code === 'ENOENT') return defaults; throw new Error('Cannot read .env.threads.json; copy .env.threads.sample.json and configure it.'); } let value: unknown; try { value = JSON.parse(contents); } catch { throw new Error('Invalid JSON in .env.threads.json'); } if (!value || typeof value !== 'object' || Array.isArray(value)) throw new Error('Invalid .env.threads.json: expected an object'); const config = { ...defaults, ...value } as ThreadsConfig; for (const field of Object.keys(defaults) as (keyof ThreadsConfig)[]) { if (typeof config[field] !== 'string' || (field !== 'accessToken' && !config[field].trim())) { throw new Error(`Invalid .env.threads.json field: ${field}`); } } for (const field of ['siteUrl', 'imageBaseUrl'] as const) { try { if (!['http:', 'https:'].includes(new URL(config[field]).protocol)) throw new Error(); } catch { throw new Error(`Invalid .env.threads.json field: ${field}`); } } return config; }