aboutsummaryrefslogtreecommitdiffstats
path: root/packages
diff options
context:
space:
mode:
Diffstat (limited to 'packages')
-rw-r--r--packages/shared/config.ts331
1 files changed, 164 insertions, 167 deletions
diff --git a/packages/shared/config.ts b/packages/shared/config.ts
index 86ff6235..3ade6d5d 100644
--- a/packages/shared/config.ts
+++ b/packages/shared/config.ts
@@ -139,182 +139,179 @@ const allEnv = z.object({
DB_WAL_MODE: stringBool("false"),
});
-const serverConfigSchema = allEnv
- .transform((val) => {
- return {
- apiUrl: val.API_URL,
- publicUrl: val.NEXTAUTH_URL,
- publicApiUrl: `${val.NEXTAUTH_URL}/api`,
- signingSecret: () => {
- if (!val.NEXTAUTH_SECRET) {
- throw new Error("NEXTAUTH_SECRET is not set");
- }
- return val.NEXTAUTH_SECRET;
- },
- auth: {
- disableSignups: val.DISABLE_SIGNUPS,
- disablePasswordAuth: val.DISABLE_PASSWORD_AUTH,
- emailVerificationRequired: val.EMAIL_VERIFICATION_REQUIRED,
- oauth: {
- allowDangerousEmailAccountLinking:
- val.OAUTH_ALLOW_DANGEROUS_EMAIL_ACCOUNT_LINKING,
- wellKnownUrl: val.OAUTH_WELLKNOWN_URL,
- clientSecret: val.OAUTH_CLIENT_SECRET,
- clientId: val.OAUTH_CLIENT_ID,
- scope: val.OAUTH_SCOPE,
- name: val.OAUTH_PROVIDER_NAME,
- timeout: val.OAUTH_TIMEOUT,
- },
- },
- email: {
- smtp: val.SMTP_HOST
- ? {
- host: val.SMTP_HOST,
- port: val.SMTP_PORT,
- secure: val.SMTP_SECURE,
- user: val.SMTP_USER,
- password: val.SMTP_PASSWORD,
- from: val.SMTP_FROM,
- }
- : undefined,
- },
- inference: {
- isConfigured: !!val.OPENAI_API_KEY || !!val.OLLAMA_BASE_URL,
- numWorkers: val.INFERENCE_NUM_WORKERS,
- jobTimeoutSec: val.INFERENCE_JOB_TIMEOUT_SEC,
- fetchTimeoutSec: val.INFERENCE_FETCH_TIMEOUT_SEC,
- openAIApiKey: val.OPENAI_API_KEY,
- openAIBaseUrl: val.OPENAI_BASE_URL,
- ollamaBaseUrl: val.OLLAMA_BASE_URL,
- ollamaKeepAlive: val.OLLAMA_KEEP_ALIVE,
- textModel: val.INFERENCE_TEXT_MODEL,
- imageModel: val.INFERENCE_IMAGE_MODEL,
- inferredTagLang: val.INFERENCE_LANG,
- contextLength: val.INFERENCE_CONTEXT_LENGTH,
- maxOutputTokens: val.INFERENCE_MAX_OUTPUT_TOKENS,
- outputSchema:
- val.INFERENCE_SUPPORTS_STRUCTURED_OUTPUT !== undefined
- ? val.INFERENCE_SUPPORTS_STRUCTURED_OUTPUT
- ? ("structured" as const)
- : ("plain" as const)
- : val.INFERENCE_OUTPUT_SCHEMA,
- enableAutoTagging: val.INFERENCE_ENABLE_AUTO_TAGGING,
- enableAutoSummarization: val.INFERENCE_ENABLE_AUTO_SUMMARIZATION,
- },
- embedding: {
- textModel: val.EMBEDDING_TEXT_MODEL,
- },
- crawler: {
- numWorkers: val.CRAWLER_NUM_WORKERS,
- headlessBrowser: val.CRAWLER_HEADLESS_BROWSER,
- browserWebUrl: val.BROWSER_WEB_URL,
- browserWebSocketUrl: val.BROWSER_WEBSOCKET_URL,
- browserConnectOnDemand: val.BROWSER_CONNECT_ONDEMAND,
- jobTimeoutSec: val.CRAWLER_JOB_TIMEOUT_SEC,
- navigateTimeoutSec: val.CRAWLER_NAVIGATE_TIMEOUT_SEC,
- downloadBannerImage: val.CRAWLER_DOWNLOAD_BANNER_IMAGE,
- storeScreenshot: val.CRAWLER_STORE_SCREENSHOT,
- fullPageScreenshot: val.CRAWLER_FULL_PAGE_SCREENSHOT,
- fullPageArchive: val.CRAWLER_FULL_PAGE_ARCHIVE,
- downloadVideo: val.CRAWLER_VIDEO_DOWNLOAD,
- maxVideoDownloadSize: val.CRAWLER_VIDEO_DOWNLOAD_MAX_SIZE,
- downloadVideoTimeout: val.CRAWLER_VIDEO_DOWNLOAD_TIMEOUT_SEC,
- enableAdblocker: val.CRAWLER_ENABLE_ADBLOCKER,
- ytDlpArguments: val.CRAWLER_YTDLP_ARGS,
- screenshotTimeoutSec: val.CRAWLER_SCREENSHOT_TIMEOUT_SEC,
- },
- ocr: {
- langs: val.OCR_LANGS,
- cacheDir: val.OCR_CACHE_DIR,
- confidenceThreshold: val.OCR_CONFIDENCE_THRESHOLD,
- },
- search: {
- numWorkers: val.SEARCH_NUM_WORKERS,
+const serverConfigSchema = allEnv.transform((val, ctx) => {
+ const obj = {
+ apiUrl: val.API_URL,
+ publicUrl: val.NEXTAUTH_URL,
+ publicApiUrl: `${val.NEXTAUTH_URL}/api`,
+ signingSecret: () => {
+ if (!val.NEXTAUTH_SECRET) {
+ throw new Error("NEXTAUTH_SECRET is not set");
+ }
+ return val.NEXTAUTH_SECRET;
+ },
+ auth: {
+ disableSignups: val.DISABLE_SIGNUPS,
+ disablePasswordAuth: val.DISABLE_PASSWORD_AUTH,
+ emailVerificationRequired: val.EMAIL_VERIFICATION_REQUIRED,
+ oauth: {
+ allowDangerousEmailAccountLinking:
+ val.OAUTH_ALLOW_DANGEROUS_EMAIL_ACCOUNT_LINKING,
+ wellKnownUrl: val.OAUTH_WELLKNOWN_URL,
+ clientSecret: val.OAUTH_CLIENT_SECRET,
+ clientId: val.OAUTH_CLIENT_ID,
+ scope: val.OAUTH_SCOPE,
+ name: val.OAUTH_PROVIDER_NAME,
+ timeout: val.OAUTH_TIMEOUT,
},
- logLevel: val.LOG_LEVEL,
- logNoColor: val.NO_COLOR,
- demoMode: val.DEMO_MODE
+ },
+ email: {
+ smtp: val.SMTP_HOST
? {
- email: val.DEMO_MODE_EMAIL,
- password: val.DEMO_MODE_PASSWORD,
+ host: val.SMTP_HOST,
+ port: val.SMTP_PORT,
+ secure: val.SMTP_SECURE,
+ user: val.SMTP_USER,
+ password: val.SMTP_PASSWORD,
+ from: val.SMTP_FROM,
}
: undefined,
- dataDir: val.DATA_DIR,
- assetsDir: val.ASSETS_DIR ?? path.join(val.DATA_DIR, "assets"),
- maxAssetSizeMb: val.MAX_ASSET_SIZE_MB,
- serverVersion: val.SERVER_VERSION,
- disableNewReleaseCheck: val.DISABLE_NEW_RELEASE_CHECK,
- usingLegacySeparateContainers: val.USING_LEGACY_SEPARATE_CONTAINERS,
- webhook: {
- timeoutSec: val.WEBHOOK_TIMEOUT_SEC,
- retryTimes: val.WEBHOOK_RETRY_TIMES,
- numWorkers: val.WEBHOOK_NUM_WORKERS,
- },
- proxy: {
- httpProxy: val.CRAWLER_HTTP_PROXY,
- httpsProxy: val.CRAWLER_HTTPS_PROXY,
- noProxy: val.CRAWLER_NO_PROXY,
- },
- assetPreprocessing: {
- numWorkers: val.ASSET_PREPROCESSING_NUM_WORKERS,
- },
- ruleEngine: {
- numWorkers: val.RULE_ENGINE_NUM_WORKERS,
- },
- assetStore: {
- type: val.ASSET_STORE_S3_ENDPOINT
- ? ("s3" as const)
- : ("filesystem" as const),
- s3: {
- endpoint: val.ASSET_STORE_S3_ENDPOINT,
- region: val.ASSET_STORE_S3_REGION,
- bucket: val.ASSET_STORE_S3_BUCKET,
- accessKeyId: val.ASSET_STORE_S3_ACCESS_KEY_ID,
- secretAccessKey: val.ASSET_STORE_S3_SECRET_ACCESS_KEY,
- forcePathStyle: val.ASSET_STORE_S3_FORCE_PATH_STYLE,
- },
- },
- prometheus: {
- metricsToken: val.PROMETHEUS_AUTH_TOKEN,
- },
- rateLimiting: {
- enabled: val.RATE_LIMITING_ENABLED,
- },
- stripe: {
- secretKey: val.STRIPE_SECRET_KEY,
- publishableKey: val.STRIPE_PUBLISHABLE_KEY,
- webhookSecret: val.STRIPE_WEBHOOK_SECRET,
- priceId: val.STRIPE_PRICE_ID,
- isConfigured: !!val.STRIPE_SECRET_KEY && !!val.STRIPE_PUBLISHABLE_KEY,
+ },
+ inference: {
+ isConfigured: !!val.OPENAI_API_KEY || !!val.OLLAMA_BASE_URL,
+ numWorkers: val.INFERENCE_NUM_WORKERS,
+ jobTimeoutSec: val.INFERENCE_JOB_TIMEOUT_SEC,
+ fetchTimeoutSec: val.INFERENCE_FETCH_TIMEOUT_SEC,
+ openAIApiKey: val.OPENAI_API_KEY,
+ openAIBaseUrl: val.OPENAI_BASE_URL,
+ ollamaBaseUrl: val.OLLAMA_BASE_URL,
+ ollamaKeepAlive: val.OLLAMA_KEEP_ALIVE,
+ textModel: val.INFERENCE_TEXT_MODEL,
+ imageModel: val.INFERENCE_IMAGE_MODEL,
+ inferredTagLang: val.INFERENCE_LANG,
+ contextLength: val.INFERENCE_CONTEXT_LENGTH,
+ maxOutputTokens: val.INFERENCE_MAX_OUTPUT_TOKENS,
+ outputSchema:
+ val.INFERENCE_SUPPORTS_STRUCTURED_OUTPUT !== undefined
+ ? val.INFERENCE_SUPPORTS_STRUCTURED_OUTPUT
+ ? ("structured" as const)
+ : ("plain" as const)
+ : val.INFERENCE_OUTPUT_SCHEMA,
+ enableAutoTagging: val.INFERENCE_ENABLE_AUTO_TAGGING,
+ enableAutoSummarization: val.INFERENCE_ENABLE_AUTO_SUMMARIZATION,
+ },
+ embedding: {
+ textModel: val.EMBEDDING_TEXT_MODEL,
+ },
+ crawler: {
+ numWorkers: val.CRAWLER_NUM_WORKERS,
+ headlessBrowser: val.CRAWLER_HEADLESS_BROWSER,
+ browserWebUrl: val.BROWSER_WEB_URL,
+ browserWebSocketUrl: val.BROWSER_WEBSOCKET_URL,
+ browserConnectOnDemand: val.BROWSER_CONNECT_ONDEMAND,
+ jobTimeoutSec: val.CRAWLER_JOB_TIMEOUT_SEC,
+ navigateTimeoutSec: val.CRAWLER_NAVIGATE_TIMEOUT_SEC,
+ downloadBannerImage: val.CRAWLER_DOWNLOAD_BANNER_IMAGE,
+ storeScreenshot: val.CRAWLER_STORE_SCREENSHOT,
+ fullPageScreenshot: val.CRAWLER_FULL_PAGE_SCREENSHOT,
+ fullPageArchive: val.CRAWLER_FULL_PAGE_ARCHIVE,
+ downloadVideo: val.CRAWLER_VIDEO_DOWNLOAD,
+ maxVideoDownloadSize: val.CRAWLER_VIDEO_DOWNLOAD_MAX_SIZE,
+ downloadVideoTimeout: val.CRAWLER_VIDEO_DOWNLOAD_TIMEOUT_SEC,
+ enableAdblocker: val.CRAWLER_ENABLE_ADBLOCKER,
+ ytDlpArguments: val.CRAWLER_YTDLP_ARGS,
+ screenshotTimeoutSec: val.CRAWLER_SCREENSHOT_TIMEOUT_SEC,
+ },
+ ocr: {
+ langs: val.OCR_LANGS,
+ cacheDir: val.OCR_CACHE_DIR,
+ confidenceThreshold: val.OCR_CONFIDENCE_THRESHOLD,
+ },
+ search: {
+ numWorkers: val.SEARCH_NUM_WORKERS,
+ },
+ logLevel: val.LOG_LEVEL,
+ logNoColor: val.NO_COLOR,
+ demoMode: val.DEMO_MODE
+ ? {
+ email: val.DEMO_MODE_EMAIL,
+ password: val.DEMO_MODE_PASSWORD,
+ }
+ : undefined,
+ dataDir: val.DATA_DIR,
+ assetsDir: val.ASSETS_DIR ?? path.join(val.DATA_DIR, "assets"),
+ maxAssetSizeMb: val.MAX_ASSET_SIZE_MB,
+ serverVersion: val.SERVER_VERSION,
+ disableNewReleaseCheck: val.DISABLE_NEW_RELEASE_CHECK,
+ usingLegacySeparateContainers: val.USING_LEGACY_SEPARATE_CONTAINERS,
+ webhook: {
+ timeoutSec: val.WEBHOOK_TIMEOUT_SEC,
+ retryTimes: val.WEBHOOK_RETRY_TIMES,
+ numWorkers: val.WEBHOOK_NUM_WORKERS,
+ },
+ proxy: {
+ httpProxy: val.CRAWLER_HTTP_PROXY,
+ httpsProxy: val.CRAWLER_HTTPS_PROXY,
+ noProxy: val.CRAWLER_NO_PROXY,
+ },
+ assetPreprocessing: {
+ numWorkers: val.ASSET_PREPROCESSING_NUM_WORKERS,
+ },
+ ruleEngine: {
+ numWorkers: val.RULE_ENGINE_NUM_WORKERS,
+ },
+ assetStore: {
+ type: val.ASSET_STORE_S3_ENDPOINT
+ ? ("s3" as const)
+ : ("filesystem" as const),
+ s3: {
+ endpoint: val.ASSET_STORE_S3_ENDPOINT,
+ region: val.ASSET_STORE_S3_REGION,
+ bucket: val.ASSET_STORE_S3_BUCKET,
+ accessKeyId: val.ASSET_STORE_S3_ACCESS_KEY_ID,
+ secretAccessKey: val.ASSET_STORE_S3_SECRET_ACCESS_KEY,
+ forcePathStyle: val.ASSET_STORE_S3_FORCE_PATH_STYLE,
},
- quotas: {
- free: {
- bookmarkLimit: val.FREE_QUOTA_BOOKMARK_LIMIT ?? null,
- assetSizeBytes: val.FREE_QUOTA_ASSET_SIZE_BYTES ?? null,
- browserCrawlingEnabled: val.FREE_BROWSER_CRAWLING_ENABLED ?? null,
- },
- paid: {
- bookmarkLimit: val.PAID_QUOTA_BOOKMARK_LIMIT ?? null,
- assetSizeBytes: val.PAID_QUOTA_ASSET_SIZE_BYTES ?? null,
- browserCrawlingEnabled: val.PAID_BROWSER_CRAWLING_ENABLED ?? null,
- },
+ },
+ prometheus: {
+ metricsToken: val.PROMETHEUS_AUTH_TOKEN,
+ },
+ rateLimiting: {
+ enabled: val.RATE_LIMITING_ENABLED,
+ },
+ stripe: {
+ secretKey: val.STRIPE_SECRET_KEY,
+ publishableKey: val.STRIPE_PUBLISHABLE_KEY,
+ webhookSecret: val.STRIPE_WEBHOOK_SECRET,
+ priceId: val.STRIPE_PRICE_ID,
+ isConfigured: !!val.STRIPE_SECRET_KEY && !!val.STRIPE_PUBLISHABLE_KEY,
+ },
+ quotas: {
+ free: {
+ bookmarkLimit: val.FREE_QUOTA_BOOKMARK_LIMIT ?? null,
+ assetSizeBytes: val.FREE_QUOTA_ASSET_SIZE_BYTES ?? null,
+ browserCrawlingEnabled: val.FREE_BROWSER_CRAWLING_ENABLED ?? null,
},
- database: {
- walMode: val.DB_WAL_MODE,
+ paid: {
+ bookmarkLimit: val.PAID_QUOTA_BOOKMARK_LIMIT ?? null,
+ assetSizeBytes: val.PAID_QUOTA_ASSET_SIZE_BYTES ?? null,
+ browserCrawlingEnabled: val.PAID_BROWSER_CRAWLING_ENABLED ?? null,
},
- };
- })
- .refine(
- (val) => {
- if (val.auth.emailVerificationRequired && !val.email.smtp) {
- return false;
- }
- return true;
},
- {
- message: "To enable email verification, SMTP settings must be configured",
+ database: {
+ walMode: val.DB_WAL_MODE,
},
- );
+ };
+ if (obj.auth.emailVerificationRequired && !obj.email.smtp) {
+ ctx.addIssue({
+ code: z.ZodIssueCode.custom,
+ message: "To enable email verification, SMTP settings must be configured",
+ fatal: true,
+ });
+ return z.NEVER;
+ }
+ return obj;
+});
const serverConfig = serverConfigSchema.parse(process.env);
// Always explicitly pick up stuff from server config to avoid accidentally leaking stuff