diff --git a/packages/pds/src/config/config.ts b/packages/pds/src/config/config.ts index de66d9f8028..7f24c9ebced 100644 --- a/packages/pds/src/config/config.ts +++ b/packages/pds/src/config/config.ts @@ -37,11 +37,11 @@ export const envToCfg = (env: ServerEnvironment): ServerConfig => { dbCfg = { dialect: 'pg', url: env.dbPostgresUrl, - migrationUrl: env.dbPostgresMigrationUrl || env.dbPostgresUrl, + migrationUrl: env.dbPostgresMigrationUrl ?? env.dbPostgresUrl, schema: env.dbPostgresSchema, pool: { idleTimeoutMs: env.dbPostgresPoolIdleTimeoutMs ?? 10000, - maxUses: env.dbPostgresPoolMaxUses || Infinity, + maxUses: env.dbPostgresPoolMaxUses ?? Infinity, size: env.dbPostgresPoolSize ?? 10, }, } @@ -60,7 +60,7 @@ export const envToCfg = (env: ServerEnvironment): ServerConfig => { provider: 'disk', location: env.blobstoreDiskLocation, tempLocation: - env.blobstoreDiskTmpLocation || path.join(os.tmpdir(), 'pds/blobs'), + env.blobstoreDiskTmpLocation ?? path.join(os.tmpdir(), 'pds/blobs'), } } else { throw new Error('Must configure either S3 or disk blobstore') @@ -84,10 +84,10 @@ export const envToCfg = (env: ServerEnvironment): ServerConfig => { } const identityCfg: ServerConfig['identity'] = { - plcUrl: env.didPlcUrl || 'https://plc.bsky-sandbox.dev', - cacheMaxTTL: env.didCacheMaxTTL || DAY, - cacheStaleTTL: env.didCacheStaleTTL || HOUR, - resolverTimeout: env.resolverTimeout || 3 * SECOND, + plcUrl: env.didPlcUrl ?? 'https://plc.bsky-sandbox.dev', + cacheMaxTTL: env.didCacheMaxTTL ?? DAY, + cacheStaleTTL: env.didCacheStaleTTL ?? HOUR, + resolverTimeout: env.resolverTimeout ?? 3 * SECOND, recoveryDidKey: env.recoveryDidKey ?? null, serviceHandleDomains, } @@ -109,7 +109,9 @@ export const envToCfg = (env: ServerEnvironment): ServerConfig => { emailCfg = null } else { if (!env.emailFromAddress || !env.emailSmtpUrl) { - throw new Error('Partial email config') + throw new Error( + 'Partial email config, must set both emailFromAddress and emailSmtpUrl', + ) } emailCfg = { smtpUrl: env.emailSmtpUrl, @@ -122,7 +124,9 @@ export const envToCfg = (env: ServerEnvironment): ServerConfig => { moderationEmailCfg = null } else { if (!env.moderationEmailAddress || !env.moderationEmailSmtpUrl) { - throw new Error('Partial email config') + throw new Error( + 'Partial moderation email config, must set both emailFromAddress and emailSmtpUrl', + ) } moderationEmailCfg = { smtpUrl: env.moderationEmailSmtpUrl, diff --git a/packages/pds/src/config/env.ts b/packages/pds/src/config/env.ts index efb2fee43d0..8dde8710e32 100644 --- a/packages/pds/src/config/env.ts +++ b/packages/pds/src/config/env.ts @@ -3,98 +3,92 @@ import { envInt, envStr, envBool, envList } from './util' export const readEnv = (): ServerEnvironment => { return { // service - port: envInt(process.env.PDS_PORT), - hostname: envStr(process.env.PDS_HOSTNAME), - serviceDid: envStr(process.env.PDS_SERVICE_DID), - version: envStr(process.env.PDS_VERSION), - privacyPolicyUrl: envStr(process.env.PDS_PRIVACY_POLICY_URL), - termsOfServiceUrl: envStr(process.env.PDS_TERMS_OF_SERVICE_URL), + port: envInt('PDS_PORT'), + hostname: envStr('PDS_HOSTNAME'), + serviceDid: envStr('PDS_SERVICE_DID'), + version: envStr('PDS_VERSION'), + privacyPolicyUrl: envStr('PDS_PRIVACY_POLICY_URL'), + termsOfServiceUrl: envStr('PDS_TERMS_OF_SERVICE_URL'), // db: one required // sqlite - dbSqliteLocation: envStr(process.env.PDS_DB_SQLITE_LOCATION), + dbSqliteLocation: envStr('PDS_DB_SQLITE_LOCATION'), // postgres - dbPostgresUrl: envStr(process.env.PDS_DB_POSTGRES_URL), - dbPostgresMigrationUrl: envStr(process.env.PDS_DB_POSTGRES_MIGRATION_URL), - dbPostgresSchema: envStr(process.env.PDS_DB_POSTGRES_SCHEMA), - dbPostgresPoolSize: envInt(process.env.PDS_DB_POSTGRES_POOL_SIZE), - dbPostgresPoolMaxUses: envInt(process.env.PDS_DB_POSTGRES_POOL_MAX_USES), - dbPostgresPoolIdleTimeoutMs: envInt( - process.env.PDS_DB_POSTGRES_POOL_IDLE_TIMEOUT_MS, - ), + dbPostgresUrl: envStr('PDS_DB_POSTGRES_URL'), + dbPostgresMigrationUrl: envStr('PDS_DB_POSTGRES_MIGRATION_URL'), + dbPostgresSchema: envStr('PDS_DB_POSTGRES_SCHEMA'), + dbPostgresPoolSize: envInt('PDS_DB_POSTGRES_POOL_SIZE'), + dbPostgresPoolMaxUses: envInt('PDS_DB_POSTGRES_POOL_MAX_USES'), + dbPostgresPoolIdleTimeoutMs: envInt('PDS_DB_POSTGRES_POOL_IDLE_TIMEOUT_MS'), // blobstore: one required // s3 - blobstoreS3Bucket: envStr(process.env.PDS_BLOBSTORE_S3_BUCKET), + blobstoreS3Bucket: envStr('PDS_BLOBSTORE_S3_BUCKET'), // disk - blobstoreDiskLocation: envStr(process.env.PDS_BLOBSTORE_DISK_LOCATION), - blobstoreDiskTmpLocation: envStr( - process.env.PDS_BLOBSTORE_DISK_TMP_LOCATION, - ), + blobstoreDiskLocation: envStr('PDS_BLOBSTORE_DISK_LOCATION'), + blobstoreDiskTmpLocation: envStr('PDS_BLOBSTORE_DISK_TMP_LOCATION'), // identity - didPlcUrl: envStr(process.env.PDS_DID_PLC_URL), - didCacheStaleTTL: envInt(process.env.PDS_DID_CACHE_STALE_TTL), - didCacheMaxTTL: envInt(process.env.PDS_DID_CACHE_MAX_TTL), - resolverTimeout: envInt(process.env.PDS_ID_RESOLVER_TIMEOUT), - recoveryDidKey: envStr(process.env.PDS_RECOVERY_DID_KEY), - serviceHandleDomains: envList(process.env.PDS_SERVICE_HANDLE_DOMAINS), + didPlcUrl: envStr('PDS_DID_PLC_URL'), + didCacheStaleTTL: envInt('PDS_DID_CACHE_STALE_TTL'), + didCacheMaxTTL: envInt('PDS_DID_CACHE_MAX_TTL'), + resolverTimeout: envInt('PDS_ID_RESOLVER_TIMEOUT'), + recoveryDidKey: envStr('PDS_RECOVERY_DID_KEY'), + serviceHandleDomains: envList('PDS_SERVICE_HANDLE_DOMAINS'), // invites - inviteRequired: envBool(process.env.PDS_INVITE_REQUIRED), - inviteInterval: envInt(process.env.PDS_INVITE_INTERVAL), - inviteEpoch: envInt(process.env.PDS_INVITE_EPOCH), + inviteRequired: envBool('PDS_INVITE_REQUIRED'), + inviteInterval: envInt('PDS_INVITE_INTERVAL'), + inviteEpoch: envInt('PDS_INVITE_EPOCH'), // email - emailSmtpUrl: envStr(process.env.PDS_EMAIL_SMTP_URL), - emailFromAddress: envStr(process.env.PDS_EMAIL_FROM_ADDRESS), - moderationEmailSmtpUrl: envStr(process.env.PDS_MODERATION_EMAIL_SMTP_URL), - moderationEmailAddress: envStr(process.env.PDS_MODERATION_EMAIL_ADDRESS), + emailSmtpUrl: envStr('PDS_EMAIL_SMTP_URL'), + emailFromAddress: envStr('PDS_EMAIL_FROM_ADDRESS'), + moderationEmailSmtpUrl: envStr('PDS_MODERATION_EMAIL_SMTP_URL'), + moderationEmailAddress: envStr('PDS_MODERATION_EMAIL_ADDRESS'), // subscription - maxSubscriptionBuffer: envInt(process.env.PDS_MAX_SUBSCRIPTION_BUFFER), - repoBackfillLimitMs: envInt(process.env.PDS_REPO_BACKFILL_LIMIT_MS), - sequencerLeaderEnabled: envBool(process.env.PDS_SEQUENCER_LEADER_ENABLED), - sequencerLeaderLockId: envInt(process.env.PDS_SEQUENCER_LEADER_LOCK_ID), + maxSubscriptionBuffer: envInt('PDS_MAX_SUBSCRIPTION_BUFFER'), + repoBackfillLimitMs: envInt('PDS_REPO_BACKFILL_LIMIT_MS'), + sequencerLeaderEnabled: envBool('PDS_SEQUENCER_LEADER_ENABLED'), + sequencerLeaderLockId: envInt('PDS_SEQUENCER_LEADER_LOCK_ID'), // appview - bskyAppViewUrl: envStr(process.env.PDS_BSKY_APP_VIEW_URL), - bskyAppViewDid: envStr(process.env.PDS_BSKY_APP_VIEW_DID), - bskyAppViewModeration: envBool(process.env.PDS_BSKY_APP_VIEW_MODERATION), - bskyAppViewCdnUrlPattern: envStr( - process.env.PDS_BSKY_APP_VIEW_CDN_URL_PATTERN, - ), + bskyAppViewUrl: envStr('PDS_BSKY_APP_VIEW_URL'), + bskyAppViewDid: envStr('PDS_BSKY_APP_VIEW_DID'), + bskyAppViewModeration: envBool('PDS_BSKY_APP_VIEW_MODERATION'), + bskyAppViewCdnUrlPattern: envStr('PDS_BSKY_APP_VIEW_CDN_URL_PATTERN'), // rate limits - rateLimitsEnabled: envBool(process.env.PDS_RATE_LIMITS_ENABLED), - rateLimitBypassKey: envStr(process.env.PDS_RATE_LIMIT_BYPASS_KEY), - rateLimitBypassIps: envList(process.env.PDS_RATE_LIMIT_BYPASS_IPS), + rateLimitsEnabled: envBool('PDS_RATE_LIMITS_ENABLED'), + rateLimitBypassKey: envStr('PDS_RATE_LIMIT_BYPASS_KEY'), + rateLimitBypassIps: envList('PDS_RATE_LIMIT_BYPASS_IPS'), // redis - redisScratchAddress: envStr(process.env.PDS_REDIS_SCRATCH_ADDRESS), - redisScratchPassword: envStr(process.env.PDS_REDIS_SCRATCH_PASSWORD), + redisScratchAddress: envStr('PDS_REDIS_SCRATCH_ADDRESS'), + redisScratchPassword: envStr('PDS_REDIS_SCRATCH_PASSWORD'), // crawlers - crawlers: envList(process.env.PDS_CRAWLERS), + crawlers: envList('PDS_CRAWLERS'), // secrets - jwtSecret: envStr(process.env.PDS_JWT_SECRET), - adminPassword: envStr(process.env.PDS_ADMIN_PASSWORD), - moderatorPassword: envStr(process.env.PDS_MODERATOR_PASSWORD), - triagePassword: envStr(process.env.PDS_TRIAGE_PASSWORD), + jwtSecret: envStr('PDS_JWT_SECRET'), + adminPassword: envStr('PDS_ADMIN_PASSWORD'), + moderatorPassword: envStr('PDS_MODERATOR_PASSWORD'), + triagePassword: envStr('PDS_TRIAGE_PASSWORD'), // keys: only one of each required // kms - repoSigningKeyKmsKeyId: envStr(process.env.PDS_REPO_SIGNING_KEY_KMS_KEY_ID), + repoSigningKeyKmsKeyId: envStr('PDS_REPO_SIGNING_KEY_KMS_KEY_ID'), // memory repoSigningKeyK256PrivateKeyHex: envStr( - process.env.PDS_REPO_SIGNING_KEY_K256_PRIVATE_KEY_HEX, + 'PDS_REPO_SIGNING_KEY_K256_PRIVATE_KEY_HEX', ), // kms - plcRotationKeyKmsKeyId: envStr(process.env.PDS_PLC_ROTATION_KEY_KMS_KEY_ID), + plcRotationKeyKmsKeyId: envStr('PDS_PLC_ROTATION_KEY_KMS_KEY_ID'), // memory plcRotationKeyK256PrivateKeyHex: envStr( - process.env.PDS_PLC_ROTATION_KEY_K256_PRIVATE_KEY_HEX, + 'PDS_PLC_ROTATION_KEY_K256_PRIVATE_KEY_HEX', ), } } diff --git a/packages/pds/src/config/util.ts b/packages/pds/src/config/util.ts index 653e84bcf3b..2bf858621bf 100644 --- a/packages/pds/src/config/util.ts +++ b/packages/pds/src/config/util.ts @@ -1,21 +1,25 @@ import { parseIntWithFallback } from '@atproto/common' -export const envInt = (str: string | undefined): number | undefined => { +export const envInt = (name: string): number | undefined => { + const str = process.env[name] return parseIntWithFallback(str, undefined) } -export const envStr = (str: string | undefined): string | undefined => { +export const envStr = (name: string): string | undefined => { + const str = process.env[name] if (str === undefined || str.length === 0) return undefined return str } -export const envBool = (str: string | undefined): boolean | undefined => { +export const envBool = (name: string): boolean | undefined => { + const str = process.env[name] if (str === 'true' || str === '1') return true if (str === 'false' || str === '0') return false return undefined } -export const envList = (str: string | undefined): string[] => { +export const envList = (name: string): string[] => { + const str = process.env[name] if (str === undefined || str.length === 0) return [] return str.split(',') } diff --git a/services/pds/index.js b/services/pds/index.js index a99b7ae980e..67872f3bd74 100644 --- a/services/pds/index.js +++ b/services/pds/index.js @@ -25,7 +25,7 @@ const pkg = require('@atproto/pds/package.json') const main = async () => { const env = readEnv() - env.version ||= pkg.version + env.version ??= pkg.version const cfg = envToCfg(env) const secrets = envToSecrets(env) const pds = await PDS.create(cfg, secrets)