Something went wrong. Try again.
Migrating content using the Ghost API to Offprint / Standard Site on atproto
Something went wrong. Try again.
12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485import 'dotenv/config';import { program } from 'commander';import { createRequire } from 'node:module';
const require = createRequire(import.meta.url);const { version } = require('../package.json');
export interface Config { ghostUrl: string; ghostApiKey: string; atpIdentifier?: string; atpAppPassword?: string; atpService: string; publicationAtUri: string; exportDir: string; stateFile: string; sessionFile: string; oauthClientId?: string; oauthScope: string; oauthSessionFile: string; oauthStateFile: string; dryRun: boolean; verbose: boolean;}
function requireEnv(name: string, value: string | undefined): string { if (!value) { throw new Error(`Missing required configuration: ${name}`); } return value;}
export function loadConfig(argv?: string[]): Config { program .name('ghostoff') .description('Export Ghost posts to Offprint via AT Protocol') .version(version) .option('--ghost-url <url>', 'Ghost publication URL') .option('--ghost-api-key <key>', 'Ghost Content API key') .option('--atproto-identifier <id>', 'atproto handle or DID') .option('--atproto-app-password <password>', 'atproto app password') .option('--atproto-service <service>', 'atproto PDS/service URL') .option('--publication-at-uri <uri>', 'existing site.standard.publication AT-URI') .option('--oauth-client-id <url>', 'OAuth client_id URL (default: http://localhost dev mode)') .option('--oauth-scope <scope>', 'OAuth requested scope', 'atproto transition:generic') .option('--oauth-session-file <file>', 'OAuth session store file', 'ghostoff-oauth-session.json') .option('--oauth-state-file <file>', 'OAuth transient state store file', 'ghostoff-oauth-state.json') .option('--export-dir <dir>', 'local asset export/cache directory', 'ghostoff-export') .option('--state-file <file>', 'idempotency state file', 'ghostoff-state.json') .option('--session-file <file>', 'persisted password session file', 'ghostoff-session.json') .option('--dry-run', 'build records without uploading', false) .option('--verbose', 'verbose logging', false);
program.parse(argv); const opts = program.opts();
const ghostUrl = requireEnv('GHOST_URL or --ghost-url', opts.ghostUrl ?? process.env.GHOST_URL); const ghostApiKey = requireEnv('GHOST_API_KEY or --ghost-api-key', opts.ghostApiKey ?? process.env.GHOST_API_KEY); const atpIdentifier = opts.atprotoIdentifier ?? process.env.ATP_IDENTIFIER ?? undefined; const atpAppPassword = opts.atprotoAppPassword ?? process.env.ATP_APP_PASSWORD ?? undefined; const atpService = opts.atprotoService ?? process.env.ATP_SERVICE ?? 'https://bsky.social'; const publicationAtUri = requireEnv( 'ATPUBLICATION_AT_URI or --publication-at-uri', opts.publicationAtUri ?? process.env.ATPUBLICATION_AT_URI );
return { ghostUrl: ghostUrl.replace(/\/$/, ''), ghostApiKey, atpIdentifier, atpAppPassword, atpService: atpService.replace(/\/$/, ''), publicationAtUri, exportDir: opts.exportDir, stateFile: opts.stateFile, sessionFile: opts.sessionFile, oauthClientId: opts.oauthClientId ?? process.env.GHOSTOFF_OAUTH_CLIENT_ID ?? undefined, oauthScope: opts.oauthScope ?? process.env.GHOSTOFF_OAUTH_SCOPE ?? 'atproto transition:generic', oauthSessionFile: opts.oauthSessionFile ?? 'ghostoff-oauth-session.json', oauthStateFile: opts.oauthStateFile ?? 'ghostoff-oauth-state.json', dryRun: !!opts.dryRun, verbose: !!opts.verbose, };}