alf: the atproto Latency Fabric alf.fly.dev/
7
fork

Configure Feed

Select the types of activity you want to include in your feed.

at main 67 lines 2.9 kB view raw
1// ABOUTME: Configuration management for ALF (Atproto Latency Fabric) service 2 3import dotenv from 'dotenv'; 4 5// Load environment variables 6dotenv.config(); 7 8export interface ServiceConfig { 9 port: number; 10 serviceUrl: string; 11 plcRoot: string; 12 /** URL for resolving ATProto handles (e.g. a PDS or AppView). Defaults to Bsky AppView. */ 13 handleResolverUrl: string; 14 databaseType: 'sqlite' | 'postgres'; 15 databasePath: string; 16 databaseUrl?: string; 17 encryptionKey: string; 18 /** Optional URL to POST to after a draft is successfully published */ 19 postPublishWebhookUrl?: string; 20 /** Maximum number of active drafts per user. null = unlimited. */ 21 maxDraftsPerUser: number | null; 22 /** When true, createSchedule is rejected with a 403. For demo deployments. */ 23 disableRecurring: boolean; 24 /** 25 * Comma-separated ATProto collection NSIDs to allow. Defaults to "*" (all collections). 26 * Used to build the OAuth scope: `repo:<collection>?action=create`. 27 * Example: "app.bsky.feed.post" to restrict to Bluesky posts only. 28 */ 29 allowedCollections: string; 30 /** OAuth scope string derived from allowedCollections. Single source of truth. */ 31 oauthScope: string; 32} 33 34export const getConfig = (): ServiceConfig => { 35 const databaseType = (process.env.DATABASE_TYPE || 'sqlite') as 'sqlite' | 'postgres'; 36 37 const maxDraftsPerUserRaw = process.env.MAX_DRAFTS_PER_USER; 38 const maxDraftsPerUser = maxDraftsPerUserRaw ? parseInt(maxDraftsPerUserRaw, 10) : null; 39 40 const config = { 41 port: parseInt(process.env.ALF_PORT || process.env.PORT || '1986', 10), 42 serviceUrl: process.env.ALF_SERVICE_URL || process.env.SERVICE_URL || 'http://localhost:1986', 43 plcRoot: process.env.PLC_ROOT || 'https://plc.directory', 44 handleResolverUrl: process.env.HANDLE_RESOLVER_URL || process.env.PDS_URL || 'https://api.bsky.app', 45 databaseType, 46 databasePath: process.env.DATABASE_PATH || './data/alf.db', 47 databaseUrl: process.env.DATABASE_URL, 48 encryptionKey: process.env.ENCRYPTION_KEY || '', 49 postPublishWebhookUrl: process.env.POST_PUBLISH_WEBHOOK_URL, 50 maxDraftsPerUser, 51 disableRecurring: ['true', '1', 'yes'].includes((process.env.DISABLE_RECURRING || '').toLowerCase()), 52 allowedCollections: process.env.ALLOWED_COLLECTIONS || '*', 53 oauthScope: `atproto repo:${process.env.ALLOWED_COLLECTIONS || '*'}?action=create blob:*/*`, 54 }; 55 56 if (config.databaseType === 'postgres' && !config.databaseUrl) { 57 throw new Error('DATABASE_URL is required when DATABASE_TYPE is "postgres"'); 58 } 59 if (!config.encryptionKey) { 60 throw new Error('ENCRYPTION_KEY is required - generate with: node -e "console.log(require(\'crypto\').randomBytes(32).toString(\'hex\'))"'); 61 } 62 if (!/^[0-9a-fA-F]{64}$/.test(config.encryptionKey)) { 63 throw new Error('ENCRYPTION_KEY must be a 64-character hex string (32 bytes)'); 64 } 65 66 return config as ServiceConfig; 67};