diff --git a/apps/backend/config/default.cjs b/apps/backend/config/default.cjs index eaec9fc3..251e516c 100644 --- a/apps/backend/config/default.cjs +++ b/apps/backend/config/default.cjs @@ -20,6 +20,7 @@ module.exports = { ocr: { projectRoot: path.resolve(__dirname, '../subservices/ocr-worker'), + baseUrl: '', }, data: { diff --git a/apps/backend/src/config/runtime.js b/apps/backend/src/config/runtime.js index 1e59876d..215cf5d1 100644 --- a/apps/backend/src/config/runtime.js +++ b/apps/backend/src/config/runtime.js @@ -1,544 +1,686 @@ // @ts-check -import fs from 'node:fs' -import path from 'node:path' -import process from 'node:process' -import { createRequire } from 'node:module' -import { fileURLToPath } from 'node:url' +import fs from "node:fs"; +import path from "node:path"; +import process from "node:process"; +import { createRequire } from "node:module"; +import { fileURLToPath } from "node:url"; /** @typedef {import('../types/runtime-config.js').RuntimeConfig} RuntimeConfig */ -const require = createRequire(import.meta.url) -const CURRENT_DIR = path.dirname(fileURLToPath(import.meta.url)) -export const PROJECT_ROOT = path.resolve(CURRENT_DIR, '../..') -const WORKSPACE_ROOT = path.resolve(PROJECT_ROOT, '../..') -const CONFIG_ROOT = path.join(PROJECT_ROOT, 'config') +const require = createRequire(import.meta.url); +const CURRENT_DIR = path.dirname(fileURLToPath(import.meta.url)); +export const PROJECT_ROOT = path.resolve(CURRENT_DIR, "../.."); +const WORKSPACE_ROOT = path.resolve(PROJECT_ROOT, "../.."); +const CONFIG_ROOT = path.join(PROJECT_ROOT, "config"); loadEnvFiles([ - path.join(WORKSPACE_ROOT, '.env'), - path.join(PROJECT_ROOT, '.env'), -]) + path.join(WORKSPACE_ROOT, ".env"), + path.join(PROJECT_ROOT, ".env"), +]); -const defaultConfig = /** @type {RuntimeConfig} */ (loadConfig(path.join(CONFIG_ROOT, 'default.cjs'))) +const defaultConfig = /** @type {RuntimeConfig} */ ( + loadConfig(path.join(CONFIG_ROOT, "default.cjs")) +); -export const runtimeConfig = /** @type {RuntimeConfig} */ (applyEnvOverrides(defaultConfig)) +export const runtimeConfig = /** @type {RuntimeConfig} */ ( + applyEnvOverrides(defaultConfig) +); function loadConfig(configPath) { if (!fs.existsSync(configPath)) { - return {} + return {}; } - const loaded = require(configPath) - return isPlainObject(loaded) ? loaded : {} + const loaded = require(configPath); + return isPlainObject(loaded) ? loaded : {}; } function loadEnvFiles(filePaths) { for (const filePath of filePaths) { - loadEnvFile(filePath) + loadEnvFile(filePath); } } function loadEnvFile(filePath) { if (!fs.existsSync(filePath)) { - return + return; } - const rawText = fs.readFileSync(filePath, 'utf8') - const lines = rawText.split(/\r?\n/) + const rawText = fs.readFileSync(filePath, "utf8"); + const lines = rawText.split(/\r?\n/); for (const rawLine of lines) { - const line = rawLine.trim() + const line = rawLine.trim(); - if (!line || line.startsWith('#')) { - continue + if (!line || line.startsWith("#")) { + continue; } - const separatorIndex = line.indexOf('=') + const separatorIndex = line.indexOf("="); if (separatorIndex <= 0) { - continue + continue; } - const key = line.slice(0, separatorIndex).trim() + const key = line.slice(0, separatorIndex).trim(); if (!key || key in process.env) { - continue + continue; } - process.env[key] = parseEnvValue(line.slice(separatorIndex + 1)) + process.env[key] = parseEnvValue(line.slice(separatorIndex + 1)); } } function parseEnvValue(rawValue) { - const value = String(rawValue || '').trim() + const value = String(rawValue || "").trim(); if (!value) { - return '' + return ""; } - const quote = value[0] + const quote = value[0]; if ((quote === '"' || quote === "'") && value.endsWith(quote)) { - return value.slice(1, -1) + return value.slice(1, -1); } - return value + return value; } function applyEnvOverrides(baseConfig) { - const nextConfig = deepMerge(baseConfig, {}) + const nextConfig = deepMerge(baseConfig, {}); - const port = parseInteger(process.env.PORT) + const port = parseInteger(process.env.PORT); if (port !== null) { - nextConfig.server.port = port + nextConfig.server.port = port; } - const chromePath = String(process.env.CHROME_PATH || '').trim() + const chromePath = String(process.env.CHROME_PATH || "").trim(); if (chromePath) { - nextConfig.browser.chromePath = chromePath + nextConfig.browser.chromePath = chromePath; } - const browserHeadless = parseBoolean(process.env.TENCENT_BROWSER_HEADLESS) + const browserHeadless = parseBoolean(process.env.TENCENT_BROWSER_HEADLESS); if (browserHeadless !== null) { - nextConfig.browser.headless = browserHeadless + nextConfig.browser.headless = browserHeadless; } - const browserDevtools = parseBoolean(process.env.TENCENT_BROWSER_DEVTOOLS) + const browserDevtools = parseBoolean(process.env.TENCENT_BROWSER_DEVTOOLS); if (browserDevtools !== null) { - nextConfig.browser.devtools = browserDevtools + nextConfig.browser.devtools = browserDevtools; } - const browserKeepAlive = parseBoolean(process.env.TENCENT_BROWSER_KEEP_ALIVE) + const browserKeepAlive = parseBoolean(process.env.TENCENT_BROWSER_KEEP_ALIVE); if (browserKeepAlive !== null) { - nextConfig.browser.keepAlive = browserKeepAlive + nextConfig.browser.keepAlive = browserKeepAlive; } - const browserPrewarm = parseBoolean(process.env.TENCENT_BROWSER_PREWARM) + const browserPrewarm = parseBoolean(process.env.TENCENT_BROWSER_PREWARM); if (browserPrewarm !== null) { - nextConfig.browser.prewarm = browserPrewarm + nextConfig.browser.prewarm = browserPrewarm; } - const browserSlowMoMs = parseInteger(process.env.TENCENT_BROWSER_SLOW_MO) + const browserSlowMoMs = parseInteger(process.env.TENCENT_BROWSER_SLOW_MO); if (browserSlowMoMs !== null) { - nextConfig.browser.slowMoMs = browserSlowMoMs + nextConfig.browser.slowMoMs = browserSlowMoMs; } - const sessionDebug = parseBoolean(process.env.TENCENT_SESSION_DEBUG) + const sessionDebug = parseBoolean(process.env.TENCENT_SESSION_DEBUG); if (sessionDebug !== null) { - nextConfig.session.debug = sessionDebug + nextConfig.session.debug = sessionDebug; } - - const ocrProjectRoot = String(process.env.OCR_PROJECT_ROOT || '').trim() + const ocrProjectRoot = String(process.env.OCR_PROJECT_ROOT || "").trim(); if (ocrProjectRoot) { - nextConfig.ocr.projectRoot = ocrProjectRoot + nextConfig.ocr.projectRoot = ocrProjectRoot; } - const dataRoot = String(process.env.DATA_ROOT || '').trim() + const ocrBaseUrl = String(process.env.OCR_BASE_URL || "").trim(); + if (ocrBaseUrl) { + nextConfig.ocr.baseUrl = ocrBaseUrl; + } + + const dataRoot = String(process.env.DATA_ROOT || "").trim(); if (dataRoot) { - nextConfig.data.root = path.resolve(dataRoot) + nextConfig.data.root = path.resolve(dataRoot); } - const logLevel = String(process.env.LOG_LEVEL || '').trim() + const logLevel = String(process.env.LOG_LEVEL || "").trim(); if (logLevel) { - nextConfig.logging.level = logLevel + nextConfig.logging.level = logLevel; } - const databaseUrl = String(process.env.DATABASE_URL || '').trim() + const databaseUrl = String(process.env.DATABASE_URL || "").trim(); if (databaseUrl) { - nextConfig.database.url = databaseUrl + nextConfig.database.url = databaseUrl; } - const databaseSsl = parseBoolean(process.env.DATABASE_SSL) + const databaseSsl = parseBoolean(process.env.DATABASE_SSL); if (databaseSsl !== null) { - nextConfig.database.ssl = databaseSsl + nextConfig.database.ssl = databaseSsl; } - const databaseMaxConnections = parseInteger(process.env.DATABASE_MAX_CONNECTIONS) + const databaseMaxConnections = parseInteger( + process.env.DATABASE_MAX_CONNECTIONS + ); if (databaseMaxConnections !== null) { - nextConfig.database.maxConnections = databaseMaxConnections + nextConfig.database.maxConnections = databaseMaxConnections; } - const claimBaseUrl = String(process.env.CLAIM_BASE_URL || '').trim() + const claimBaseUrl = String(process.env.CLAIM_BASE_URL || "").trim(); if (claimBaseUrl) { - nextConfig.orders.claimBaseUrl = claimBaseUrl + nextConfig.orders.claimBaseUrl = claimBaseUrl; } else { - const appBaseUrl = String(process.env.APP_BASE_URL || '').trim() + const appBaseUrl = String(process.env.APP_BASE_URL || "").trim(); if (appBaseUrl) { - nextConfig.orders.claimBaseUrl = `${appBaseUrl.replace(/\/+$/, '')}/#/claim` + nextConfig.orders.claimBaseUrl = `${appBaseUrl.replace( + /\/+$/, + "" + )}/#/claim`; } } - const tokenTtlHours = parseInteger(process.env.CLAIM_TOKEN_TTL_HOURS) + const tokenTtlHours = parseInteger(process.env.CLAIM_TOKEN_TTL_HOURS); if (tokenTtlHours !== null) { - nextConfig.orders.tokenTtlHours = tokenTtlHours + nextConfig.orders.tokenTtlHours = tokenTtlHours; } - const adminSessionSecret = String(process.env.ADMIN_SESSION_SECRET || '').trim() + const adminSessionSecret = String( + process.env.ADMIN_SESSION_SECRET || "" + ).trim(); if (adminSessionSecret) { - nextConfig.admin.sessionSecret = adminSessionSecret + nextConfig.admin.sessionSecret = adminSessionSecret; } - const adminSessionTtlHours = parseInteger(process.env.ADMIN_SESSION_TTL_HOURS) + const adminSessionTtlHours = parseInteger( + process.env.ADMIN_SESSION_TTL_HOURS + ); if (adminSessionTtlHours !== null) { - nextConfig.admin.sessionTtlHours = adminSessionTtlHours + nextConfig.admin.sessionTtlHours = adminSessionTtlHours; } - const adminDefaultUsers = parseJsonArray(process.env.ADMIN_DEFAULT_USERS_JSON) + const adminDefaultUsers = parseJsonArray( + process.env.ADMIN_DEFAULT_USERS_JSON + ); if (adminDefaultUsers) { - nextConfig.admin.defaultUsers = adminDefaultUsers + nextConfig.admin.defaultUsers = adminDefaultUsers; } - const agisoAppSecret = String(process.env.AGISO_APP_SECRET || '').trim() + const agisoAppSecret = String(process.env.AGISO_APP_SECRET || "").trim(); if (agisoAppSecret) { - nextConfig.platforms.agiso.appSecret = agisoAppSecret + nextConfig.platforms.agiso.appSecret = agisoAppSecret; } - const agisoTradeDetailEndpoint = String(process.env.AGISO_TRADE_DETAIL_ENDPOINT || '').trim() + const agisoTradeDetailEndpoint = String( + process.env.AGISO_TRADE_DETAIL_ENDPOINT || "" + ).trim(); if (agisoTradeDetailEndpoint) { - nextConfig.platforms.agiso.tradeDetail.endpoint = agisoTradeDetailEndpoint + nextConfig.platforms.agiso.tradeDetail.endpoint = agisoTradeDetailEndpoint; } - const agisoTradeDetailApiVersion = String(process.env.AGISO_TRADE_DETAIL_API_VERSION || '').trim() + const agisoTradeDetailApiVersion = String( + process.env.AGISO_TRADE_DETAIL_API_VERSION || "" + ).trim(); if (agisoTradeDetailApiVersion) { - nextConfig.platforms.agiso.tradeDetail.apiVersion = agisoTradeDetailApiVersion + nextConfig.platforms.agiso.tradeDetail.apiVersion = + agisoTradeDetailApiVersion; } - const agisoTradeDetailTimeoutMs = parseInteger(process.env.AGISO_TRADE_DETAIL_TIMEOUT_MS) + const agisoTradeDetailTimeoutMs = parseInteger( + process.env.AGISO_TRADE_DETAIL_TIMEOUT_MS + ); if (agisoTradeDetailTimeoutMs !== null) { - nextConfig.platforms.agiso.tradeDetail.timeoutMs = agisoTradeDetailTimeoutMs + nextConfig.platforms.agiso.tradeDetail.timeoutMs = + agisoTradeDetailTimeoutMs; } - const agisoAutoDeliveryEnabled = parseBoolean(process.env.AGISO_AUTO_DELIVERY_ENABLED) + const agisoAutoDeliveryEnabled = parseBoolean( + process.env.AGISO_AUTO_DELIVERY_ENABLED + ); if (agisoAutoDeliveryEnabled !== null) { - nextConfig.platforms.agiso.autoDelivery.enabled = agisoAutoDeliveryEnabled + nextConfig.platforms.agiso.autoDelivery.enabled = agisoAutoDeliveryEnabled; } - const agisoAutoDeliveryEndpoint = String(process.env.AGISO_AUTO_DELIVERY_ENDPOINT || '').trim() + const agisoAutoDeliveryEndpoint = String( + process.env.AGISO_AUTO_DELIVERY_ENDPOINT || "" + ).trim(); if (agisoAutoDeliveryEndpoint) { - nextConfig.platforms.agiso.autoDelivery.endpoint = agisoAutoDeliveryEndpoint + nextConfig.platforms.agiso.autoDelivery.endpoint = + agisoAutoDeliveryEndpoint; } - const agisoAutoDeliveryApiVersion = String(process.env.AGISO_AUTO_DELIVERY_API_VERSION || '').trim() + const agisoAutoDeliveryApiVersion = String( + process.env.AGISO_AUTO_DELIVERY_API_VERSION || "" + ).trim(); if (agisoAutoDeliveryApiVersion) { - nextConfig.platforms.agiso.autoDelivery.apiVersion = agisoAutoDeliveryApiVersion + nextConfig.platforms.agiso.autoDelivery.apiVersion = + agisoAutoDeliveryApiVersion; } - const agisoMessageApiVersion = String(process.env.AGISO_MESSAGE_API_VERSION || '').trim() + const agisoMessageApiVersion = String( + process.env.AGISO_MESSAGE_API_VERSION || "" + ).trim(); if (agisoMessageApiVersion) { - nextConfig.platforms.agiso.messaging.apiVersion = agisoMessageApiVersion + nextConfig.platforms.agiso.messaging.apiVersion = agisoMessageApiVersion; } - const agisoSendMessageEndpoint = String(process.env.AGISO_SEND_MESSAGE_ENDPOINT || '').trim() + const agisoSendMessageEndpoint = String( + process.env.AGISO_SEND_MESSAGE_ENDPOINT || "" + ).trim(); if (agisoSendMessageEndpoint) { - nextConfig.platforms.agiso.messaging.sendMessageEndpoint = agisoSendMessageEndpoint + nextConfig.platforms.agiso.messaging.sendMessageEndpoint = + agisoSendMessageEndpoint; } - const agisoMessagingEnabled = parseBoolean(process.env.AGISO_MESSAGING_ENABLED) + const agisoMessagingEnabled = parseBoolean( + process.env.AGISO_MESSAGING_ENABLED + ); if (agisoMessagingEnabled !== null) { - nextConfig.platforms.agiso.messaging.enabled = agisoMessagingEnabled + nextConfig.platforms.agiso.messaging.enabled = agisoMessagingEnabled; } - const ninetyoneUserId = String(process.env.NINETYONE_USER_ID || '').trim() + const ninetyoneUserId = String(process.env.NINETYONE_USER_ID || "").trim(); if (ninetyoneUserId) { - nextConfig.platforms.ninetyone.userId = ninetyoneUserId + nextConfig.platforms.ninetyone.userId = ninetyoneUserId; } - const ninetyoneSecret = String(process.env.NINETYONE_SECRET || '').trim() + const ninetyoneSecret = String(process.env.NINETYONE_SECRET || "").trim(); if (ninetyoneSecret) { - nextConfig.platforms.ninetyone.secret = ninetyoneSecret + nextConfig.platforms.ninetyone.secret = ninetyoneSecret; } - const ninetyoneVersion = String(process.env.NINETYONE_VERSION || '').trim() + const ninetyoneVersion = String(process.env.NINETYONE_VERSION || "").trim(); if (ninetyoneVersion) { - nextConfig.platforms.ninetyone.version = ninetyoneVersion + nextConfig.platforms.ninetyone.version = ninetyoneVersion; } - const ninetyoneShopId = String(process.env.NINETYONE_SHOP_ID || '').trim() + const ninetyoneShopId = String(process.env.NINETYONE_SHOP_ID || "").trim(); if (ninetyoneShopId) { - nextConfig.platforms.ninetyone.shopId = ninetyoneShopId + nextConfig.platforms.ninetyone.shopId = ninetyoneShopId; } - const ninetyoneShopName = String(process.env.NINETYONE_SHOP_NAME || '').trim() + const ninetyoneShopName = String( + process.env.NINETYONE_SHOP_NAME || "" + ).trim(); if (ninetyoneShopName) { - nextConfig.platforms.ninetyone.shopName = ninetyoneShopName + nextConfig.platforms.ninetyone.shopName = ninetyoneShopName; } - const ninetyoneTimestampToleranceSeconds = parseInteger(process.env.NINETYONE_TIMESTAMP_TOLERANCE_SECONDS) + const ninetyoneTimestampToleranceSeconds = parseInteger( + process.env.NINETYONE_TIMESTAMP_TOLERANCE_SECONDS + ); if (ninetyoneTimestampToleranceSeconds !== null) { - nextConfig.platforms.ninetyone.timestampToleranceSeconds = ninetyoneTimestampToleranceSeconds + nextConfig.platforms.ninetyone.timestampToleranceSeconds = + ninetyoneTimestampToleranceSeconds; } - const ninetyoneCardsEncoding = String(process.env.NINETYONE_CARDS_ENCODING || '').trim() + const ninetyoneCardsEncoding = String( + process.env.NINETYONE_CARDS_ENCODING || "" + ).trim(); if (ninetyoneCardsEncoding) { - nextConfig.platforms.ninetyone.cardsEncoding = ninetyoneCardsEncoding + nextConfig.platforms.ninetyone.cardsEncoding = ninetyoneCardsEncoding; } - const cloudtentaclesBaseUrl = String(process.env.CLOUDTENTACLES_BASE_URL || '').trim() + const cloudtentaclesBaseUrl = String( + process.env.CLOUDTENTACLES_BASE_URL || "" + ).trim(); if (cloudtentaclesBaseUrl) { - nextConfig.platforms.cloudtentacles.baseUrl = cloudtentaclesBaseUrl + nextConfig.platforms.cloudtentacles.baseUrl = cloudtentaclesBaseUrl; } - const cloudtentaclesTimeoutMs = parseInteger(process.env.CLOUDTENTACLES_TIMEOUT_MS) + const cloudtentaclesTimeoutMs = parseInteger( + process.env.CLOUDTENTACLES_TIMEOUT_MS + ); if (cloudtentaclesTimeoutMs !== null) { - nextConfig.platforms.cloudtentacles.timeoutMs = cloudtentaclesTimeoutMs + nextConfig.platforms.cloudtentacles.timeoutMs = cloudtentaclesTimeoutMs; } - const cloudtentaclesSendSmsPath = String(process.env.CLOUDTENTACLES_SEND_SMS_PATH || '').trim() + const cloudtentaclesSendSmsPath = String( + process.env.CLOUDTENTACLES_SEND_SMS_PATH || "" + ).trim(); if (cloudtentaclesSendSmsPath) { - nextConfig.platforms.cloudtentacles.sendSmsPath = cloudtentaclesSendSmsPath + nextConfig.platforms.cloudtentacles.sendSmsPath = cloudtentaclesSendSmsPath; } - const cloudtentaclesLoginPath = String(process.env.CLOUDTENTACLES_LOGIN_PATH || '').trim() + const cloudtentaclesLoginPath = String( + process.env.CLOUDTENTACLES_LOGIN_PATH || "" + ).trim(); if (cloudtentaclesLoginPath) { - nextConfig.platforms.cloudtentacles.loginPath = cloudtentaclesLoginPath + nextConfig.platforms.cloudtentacles.loginPath = cloudtentaclesLoginPath; } - const cloudtentaclesUserInfoPath = String(process.env.CLOUDTENTACLES_USER_INFO_PATH || '').trim() + const cloudtentaclesUserInfoPath = String( + process.env.CLOUDTENTACLES_USER_INFO_PATH || "" + ).trim(); if (cloudtentaclesUserInfoPath) { - nextConfig.platforms.cloudtentacles.userInfoPath = cloudtentaclesUserInfoPath + nextConfig.platforms.cloudtentacles.userInfoPath = + cloudtentaclesUserInfoPath; } - const cloudtentaclesAssetPath = String(process.env.CLOUDTENTACLES_ASSET_PATH || '').trim() + const cloudtentaclesAssetPath = String( + process.env.CLOUDTENTACLES_ASSET_PATH || "" + ).trim(); if (cloudtentaclesAssetPath) { - nextConfig.platforms.cloudtentacles.assetPath = cloudtentaclesAssetPath + nextConfig.platforms.cloudtentacles.assetPath = cloudtentaclesAssetPath; } - const cloudtentaclesPermissionPath = String(process.env.CLOUDTENTACLES_PERMISSION_PATH || '').trim() + const cloudtentaclesPermissionPath = String( + process.env.CLOUDTENTACLES_PERMISSION_PATH || "" + ).trim(); if (cloudtentaclesPermissionPath) { - nextConfig.platforms.cloudtentacles.permissionPath = cloudtentaclesPermissionPath + nextConfig.platforms.cloudtentacles.permissionPath = + cloudtentaclesPermissionPath; } - const cloudtentaclesCategoriesPath = String(process.env.CLOUDTENTACLES_CATEGORIES_PATH || '').trim() + const cloudtentaclesCategoriesPath = String( + process.env.CLOUDTENTACLES_CATEGORIES_PATH || "" + ).trim(); if (cloudtentaclesCategoriesPath) { - nextConfig.platforms.cloudtentacles.categoriesPath = cloudtentaclesCategoriesPath + nextConfig.platforms.cloudtentacles.categoriesPath = + cloudtentaclesCategoriesPath; } - const cloudtentaclesSkuListPath = String(process.env.CLOUDTENTACLES_SKU_LIST_PATH || '').trim() + const cloudtentaclesSkuListPath = String( + process.env.CLOUDTENTACLES_SKU_LIST_PATH || "" + ).trim(); if (cloudtentaclesSkuListPath) { - nextConfig.platforms.cloudtentacles.skuListPath = cloudtentaclesSkuListPath + nextConfig.platforms.cloudtentacles.skuListPath = cloudtentaclesSkuListPath; } - const cloudtentaclesSkuBuyPath = String(process.env.CLOUDTENTACLES_SKU_BUY_PATH || '').trim() + const cloudtentaclesSkuBuyPath = String( + process.env.CLOUDTENTACLES_SKU_BUY_PATH || "" + ).trim(); if (cloudtentaclesSkuBuyPath) { - nextConfig.platforms.cloudtentacles.skuBuyPath = cloudtentaclesSkuBuyPath + nextConfig.platforms.cloudtentacles.skuBuyPath = cloudtentaclesSkuBuyPath; } - const cloudtentaclesKnapsackPath = String(process.env.CLOUDTENTACLES_KNAPSACK_PATH || '').trim() + const cloudtentaclesKnapsackPath = String( + process.env.CLOUDTENTACLES_KNAPSACK_PATH || "" + ).trim(); if (cloudtentaclesKnapsackPath) { - nextConfig.platforms.cloudtentacles.knapsackPath = cloudtentaclesKnapsackPath + nextConfig.platforms.cloudtentacles.knapsackPath = + cloudtentaclesKnapsackPath; } - const cloudtentaclesVnListPath = String(process.env.CLOUDTENTACLES_VN_LIST_PATH || '').trim() + const cloudtentaclesVnListPath = String( + process.env.CLOUDTENTACLES_VN_LIST_PATH || "" + ).trim(); if (cloudtentaclesVnListPath) { - nextConfig.platforms.cloudtentacles.vnListPath = cloudtentaclesVnListPath + nextConfig.platforms.cloudtentacles.vnListPath = cloudtentaclesVnListPath; } - const cloudtentaclesVnAppointPath = String(process.env.CLOUDTENTACLES_VN_APPOINT_PATH || '').trim() + const cloudtentaclesVnAppointPath = String( + process.env.CLOUDTENTACLES_VN_APPOINT_PATH || "" + ).trim(); if (cloudtentaclesVnAppointPath) { - nextConfig.platforms.cloudtentacles.vnAppointPath = cloudtentaclesVnAppointPath + nextConfig.platforms.cloudtentacles.vnAppointPath = + cloudtentaclesVnAppointPath; } - const cloudtentaclesVnGenerateLoginCodePath = String(process.env.CLOUDTENTACLES_VN_GENERATE_LOGIN_CODE_PATH || '').trim() + const cloudtentaclesVnGenerateLoginCodePath = String( + process.env.CLOUDTENTACLES_VN_GENERATE_LOGIN_CODE_PATH || "" + ).trim(); if (cloudtentaclesVnGenerateLoginCodePath) { - nextConfig.platforms.cloudtentacles.vnGenerateLoginCodePath = cloudtentaclesVnGenerateLoginCodePath + nextConfig.platforms.cloudtentacles.vnGenerateLoginCodePath = + cloudtentaclesVnGenerateLoginCodePath; } - const cloudtentaclesVnVerifCodePath = String(process.env.CLOUDTENTACLES_VN_VERIF_CODE_PATH || '').trim() + const cloudtentaclesVnVerifCodePath = String( + process.env.CLOUDTENTACLES_VN_VERIF_CODE_PATH || "" + ).trim(); if (cloudtentaclesVnVerifCodePath) { - nextConfig.platforms.cloudtentacles.vnVerifCodePath = cloudtentaclesVnVerifCodePath + nextConfig.platforms.cloudtentacles.vnVerifCodePath = + cloudtentaclesVnVerifCodePath; } - const cloudtentaclesVnVerifyLoginCodePath = String(process.env.CLOUDTENTACLES_VN_VERIFY_LOGIN_CODE_PATH || '').trim() + const cloudtentaclesVnVerifyLoginCodePath = String( + process.env.CLOUDTENTACLES_VN_VERIFY_LOGIN_CODE_PATH || "" + ).trim(); if (cloudtentaclesVnVerifyLoginCodePath) { - nextConfig.platforms.cloudtentacles.vnVerifyLoginCodePath = cloudtentaclesVnVerifyLoginCodePath + nextConfig.platforms.cloudtentacles.vnVerifyLoginCodePath = + cloudtentaclesVnVerifyLoginCodePath; } - const cloudtentaclesVnBindUrlPath = String(process.env.CLOUDTENTACLES_VN_BIND_URL_PATH || '').trim() + const cloudtentaclesVnBindUrlPath = String( + process.env.CLOUDTENTACLES_VN_BIND_URL_PATH || "" + ).trim(); if (cloudtentaclesVnBindUrlPath) { - nextConfig.platforms.cloudtentacles.vnBindUrlPath = cloudtentaclesVnBindUrlPath + nextConfig.platforms.cloudtentacles.vnBindUrlPath = + cloudtentaclesVnBindUrlPath; } - const cloudtentaclesVnBindInfoPath = String(process.env.CLOUDTENTACLES_VN_BIND_INFO_PATH || '').trim() + const cloudtentaclesVnBindInfoPath = String( + process.env.CLOUDTENTACLES_VN_BIND_INFO_PATH || "" + ).trim(); if (cloudtentaclesVnBindInfoPath) { - nextConfig.platforms.cloudtentacles.vnBindInfoPath = cloudtentaclesVnBindInfoPath + nextConfig.platforms.cloudtentacles.vnBindInfoPath = + cloudtentaclesVnBindInfoPath; } - const cloudtentaclesVnBackPath = String(process.env.CLOUDTENTACLES_VN_BACK_PATH || '').trim() + const cloudtentaclesVnBackPath = String( + process.env.CLOUDTENTACLES_VN_BACK_PATH || "" + ).trim(); if (cloudtentaclesVnBackPath) { - nextConfig.platforms.cloudtentacles.vnBackPath = cloudtentaclesVnBackPath + nextConfig.platforms.cloudtentacles.vnBackPath = cloudtentaclesVnBackPath; } - const cloudtentaclesBindUrlTtlSeconds = parseInteger(process.env.CLOUDTENTACLES_BIND_URL_TTL_SECONDS) + const cloudtentaclesBindUrlTtlSeconds = parseInteger( + process.env.CLOUDTENTACLES_BIND_URL_TTL_SECONDS + ); if (cloudtentaclesBindUrlTtlSeconds !== null) { - nextConfig.platforms.cloudtentacles.bindUrlTtlSeconds = cloudtentaclesBindUrlTtlSeconds + nextConfig.platforms.cloudtentacles.bindUrlTtlSeconds = + cloudtentaclesBindUrlTtlSeconds; } - const cloudtentaclesBindUrlProbeIntervalSeconds = parseInteger(process.env.CLOUDTENTACLES_BIND_URL_PROBE_INTERVAL_SECONDS) + const cloudtentaclesBindUrlProbeIntervalSeconds = parseInteger( + process.env.CLOUDTENTACLES_BIND_URL_PROBE_INTERVAL_SECONDS + ); if (cloudtentaclesBindUrlProbeIntervalSeconds !== null) { - nextConfig.platforms.cloudtentacles.bindUrlProbeIntervalSeconds = cloudtentaclesBindUrlProbeIntervalSeconds + nextConfig.platforms.cloudtentacles.bindUrlProbeIntervalSeconds = + cloudtentaclesBindUrlProbeIntervalSeconds; } - const cloudtentaclesBindUrlProbeTimeoutMs = parseInteger(process.env.CLOUDTENTACLES_BIND_URL_PROBE_TIMEOUT_MS) + const cloudtentaclesBindUrlProbeTimeoutMs = parseInteger( + process.env.CLOUDTENTACLES_BIND_URL_PROBE_TIMEOUT_MS + ); if (cloudtentaclesBindUrlProbeTimeoutMs !== null) { - nextConfig.platforms.cloudtentacles.bindUrlProbeTimeoutMs = cloudtentaclesBindUrlProbeTimeoutMs + nextConfig.platforms.cloudtentacles.bindUrlProbeTimeoutMs = + cloudtentaclesBindUrlProbeTimeoutMs; } - const cloudtentaclesBindUrlProbeUserAgent = String(process.env.CLOUDTENTACLES_BIND_URL_PROBE_USER_AGENT || '').trim() + const cloudtentaclesBindUrlProbeUserAgent = String( + process.env.CLOUDTENTACLES_BIND_URL_PROBE_USER_AGENT || "" + ).trim(); if (cloudtentaclesBindUrlProbeUserAgent) { - nextConfig.platforms.cloudtentacles.bindUrlProbeUserAgent = cloudtentaclesBindUrlProbeUserAgent + nextConfig.platforms.cloudtentacles.bindUrlProbeUserAgent = + cloudtentaclesBindUrlProbeUserAgent; } - const cloudtentaclesBindUrlProbeEndpoint = String(process.env.CLOUDTENTACLES_BIND_URL_PROBE_ENDPOINT || '').trim() + const cloudtentaclesBindUrlProbeEndpoint = String( + process.env.CLOUDTENTACLES_BIND_URL_PROBE_ENDPOINT || "" + ).trim(); if (cloudtentaclesBindUrlProbeEndpoint) { - nextConfig.platforms.cloudtentacles.bindUrlProbeEndpoint = cloudtentaclesBindUrlProbeEndpoint + nextConfig.platforms.cloudtentacles.bindUrlProbeEndpoint = + cloudtentaclesBindUrlProbeEndpoint; } - const cloudtentaclesBindUrlProbeChartId = String(process.env.CLOUDTENTACLES_BIND_URL_PROBE_CHART_ID || '').trim() + const cloudtentaclesBindUrlProbeChartId = String( + process.env.CLOUDTENTACLES_BIND_URL_PROBE_CHART_ID || "" + ).trim(); if (cloudtentaclesBindUrlProbeChartId) { - nextConfig.platforms.cloudtentacles.bindUrlProbeChartId = cloudtentaclesBindUrlProbeChartId + nextConfig.platforms.cloudtentacles.bindUrlProbeChartId = + cloudtentaclesBindUrlProbeChartId; } - const cloudtentaclesBindUrlProbeSubChartId = String(process.env.CLOUDTENTACLES_BIND_URL_PROBE_SUB_CHART_ID || '').trim() + const cloudtentaclesBindUrlProbeSubChartId = String( + process.env.CLOUDTENTACLES_BIND_URL_PROBE_SUB_CHART_ID || "" + ).trim(); if (cloudtentaclesBindUrlProbeSubChartId) { - nextConfig.platforms.cloudtentacles.bindUrlProbeSubChartId = cloudtentaclesBindUrlProbeSubChartId + nextConfig.platforms.cloudtentacles.bindUrlProbeSubChartId = + cloudtentaclesBindUrlProbeSubChartId; } - const cloudtentaclesBindUrlProbeIdeToken = String(process.env.CLOUDTENTACLES_BIND_URL_PROBE_IDE_TOKEN || '').trim() + const cloudtentaclesBindUrlProbeIdeToken = String( + process.env.CLOUDTENTACLES_BIND_URL_PROBE_IDE_TOKEN || "" + ).trim(); if (cloudtentaclesBindUrlProbeIdeToken) { - nextConfig.platforms.cloudtentacles.bindUrlProbeIdeToken = cloudtentaclesBindUrlProbeIdeToken + nextConfig.platforms.cloudtentacles.bindUrlProbeIdeToken = + cloudtentaclesBindUrlProbeIdeToken; } - const cloudtentaclesBindUrlProbeActivityUrl = String(process.env.CLOUDTENTACLES_BIND_URL_PROBE_ACTIVITY_URL || '').trim() + const cloudtentaclesBindUrlProbeActivityUrl = String( + process.env.CLOUDTENTACLES_BIND_URL_PROBE_ACTIVITY_URL || "" + ).trim(); if (cloudtentaclesBindUrlProbeActivityUrl) { - nextConfig.platforms.cloudtentacles.bindUrlProbeActivityUrl = cloudtentaclesBindUrlProbeActivityUrl + nextConfig.platforms.cloudtentacles.bindUrlProbeActivityUrl = + cloudtentaclesBindUrlProbeActivityUrl; } - const cloudtentaclesBindUrlProbeReferer = String(process.env.CLOUDTENTACLES_BIND_URL_PROBE_REFERER || '').trim() + const cloudtentaclesBindUrlProbeReferer = String( + process.env.CLOUDTENTACLES_BIND_URL_PROBE_REFERER || "" + ).trim(); if (cloudtentaclesBindUrlProbeReferer) { - nextConfig.platforms.cloudtentacles.bindUrlProbeReferer = cloudtentaclesBindUrlProbeReferer + nextConfig.platforms.cloudtentacles.bindUrlProbeReferer = + cloudtentaclesBindUrlProbeReferer; } - const cloudtentaclesBindUrlProbeExtraCookie = String(process.env.CLOUDTENTACLES_BIND_URL_PROBE_EXTRA_COOKIE || '').trim() + const cloudtentaclesBindUrlProbeExtraCookie = String( + process.env.CLOUDTENTACLES_BIND_URL_PROBE_EXTRA_COOKIE || "" + ).trim(); if (cloudtentaclesBindUrlProbeExtraCookie) { - nextConfig.platforms.cloudtentacles.bindUrlProbeExtraCookie = cloudtentaclesBindUrlProbeExtraCookie + nextConfig.platforms.cloudtentacles.bindUrlProbeExtraCookie = + cloudtentaclesBindUrlProbeExtraCookie; } - const cloudtentaclesPublicKeyPem = String(process.env.CLOUDTENTACLES_PUBLIC_KEY_PEM || '').trim() + const cloudtentaclesPublicKeyPem = String( + process.env.CLOUDTENTACLES_PUBLIC_KEY_PEM || "" + ).trim(); if (cloudtentaclesPublicKeyPem) { - nextConfig.platforms.cloudtentacles.publicKeyPem = cloudtentaclesPublicKeyPem + nextConfig.platforms.cloudtentacles.publicKeyPem = + cloudtentaclesPublicKeyPem; } - const cloudtentaclesClientSource = String(process.env.CLOUDTENTACLES_CLIENT_SOURCE || '').trim() + const cloudtentaclesClientSource = String( + process.env.CLOUDTENTACLES_CLIENT_SOURCE || "" + ).trim(); if (cloudtentaclesClientSource) { - nextConfig.platforms.cloudtentacles.clientSource = cloudtentaclesClientSource + nextConfig.platforms.cloudtentacles.clientSource = + cloudtentaclesClientSource; } - const cloudtentaclesDeviceId = String(process.env.CLOUDTENTACLES_DEVICE_ID || '').trim() + const cloudtentaclesDeviceId = String( + process.env.CLOUDTENTACLES_DEVICE_ID || "" + ).trim(); if (cloudtentaclesDeviceId) { - nextConfig.platforms.cloudtentacles.deviceId = cloudtentaclesDeviceId + nextConfig.platforms.cloudtentacles.deviceId = cloudtentaclesDeviceId; } - const cloudtentaclesDeviceType = parseInteger(process.env.CLOUDTENTACLES_DEVICE_TYPE) + const cloudtentaclesDeviceType = parseInteger( + process.env.CLOUDTENTACLES_DEVICE_TYPE + ); if (cloudtentaclesDeviceType !== null) { - nextConfig.platforms.cloudtentacles.deviceType = cloudtentaclesDeviceType + nextConfig.platforms.cloudtentacles.deviceType = cloudtentaclesDeviceType; } - const proofMode = String(process.env.TENCENT_REDEEM_PROOF_MODE || '').trim() + const proofMode = String(process.env.TENCENT_REDEEM_PROOF_MODE || "").trim(); if (proofMode) { - nextConfig.redeem.proofMode = proofMode + nextConfig.redeem.proofMode = proofMode; } - return nextConfig + return nextConfig; } function deepMerge(baseValue, overrideValue) { if (!isPlainObject(baseValue)) { - return cloneValue(overrideValue) + return cloneValue(overrideValue); } - const result = cloneValue(baseValue) + const result = cloneValue(baseValue); if (!isPlainObject(overrideValue)) { - return result + return result; } for (const [key, value] of Object.entries(overrideValue)) { if (isPlainObject(value) && isPlainObject(result[key])) { - result[key] = deepMerge(result[key], value) - continue + result[key] = deepMerge(result[key], value); + continue; } - result[key] = cloneValue(value) + result[key] = cloneValue(value); } - return result + return result; } function cloneValue(value) { if (Array.isArray(value)) { - return value.map((item) => cloneValue(item)) + return value.map((item) => cloneValue(item)); } if (isPlainObject(value)) { - const output = {} + const output = {}; for (const [key, item] of Object.entries(value)) { - output[key] = cloneValue(item) + output[key] = cloneValue(item); } - return output + return output; } - return value + return value; } function isPlainObject(value) { - return Object.prototype.toString.call(value) === '[object Object]' + return Object.prototype.toString.call(value) === "[object Object]"; } function parseBoolean(rawValue) { - const normalized = String(rawValue || '').trim().toLowerCase() + const normalized = String(rawValue || "") + .trim() + .toLowerCase(); if (!normalized) { - return null + return null; } - if (['1', 'true', 'yes', 'on'].includes(normalized)) { - return true + if (["1", "true", "yes", "on"].includes(normalized)) { + return true; } - if (['0', 'false', 'no', 'off'].includes(normalized)) { - return false + if (["0", "false", "no", "off"].includes(normalized)) { + return false; } - return null + return null; } function parseInteger(rawValue) { - const normalized = String(rawValue || '').trim() + const normalized = String(rawValue || "").trim(); if (!normalized) { - return null + return null; } - const parsed = Number(normalized) - return Number.isFinite(parsed) ? parsed : null + const parsed = Number(normalized); + return Number.isFinite(parsed) ? parsed : null; } function parseJsonArray(rawValue) { - const normalized = String(rawValue || '').trim() + const normalized = String(rawValue || "").trim(); if (!normalized) { - return null + return null; } try { - const parsed = JSON.parse(normalized) - return Array.isArray(parsed) ? parsed : null + const parsed = JSON.parse(normalized); + return Array.isArray(parsed) ? parsed : null; } catch { - return null + return null; } } function normalizeBooleanLike(value) { - if (typeof value === 'boolean') { - return value + if (typeof value === "boolean") { + return value; } - return parseBoolean(value) + return parseBoolean(value); } diff --git a/apps/backend/src/services/session/ocr.js b/apps/backend/src/services/session/ocr.js index 52463bda..cb6f4914 100644 --- a/apps/backend/src/services/session/ocr.js +++ b/apps/backend/src/services/session/ocr.js @@ -22,14 +22,89 @@ export async function batchRecognizeTencentCaptcha(payload) { } export async function warmupLocalOcrWorker() { + const mode = resolveOcrMode() + if (mode === 'http') { + await warmupOcrViaHttp() + return + } await runOcrCommand('healthcheck', { timeoutMs: 30_000 }) } export async function closeLocalOcrWorker() { - // OCR 改为按次调用 Python 子进程,这里不再维护常驻 worker。 + // OCR 改为按次调用 Python 子进程或 HTTP 服务,这里不再维护常驻 worker。 } +// ── Mode Resolution ────────────────────────────────────────────────────────── + +function resolveOcrMode() { + if (String(runtimeConfig.ocr.baseUrl || '').trim()) { + return 'http' + } + return 'subprocess' +} + +// ── HTTP Mode ───────────────────────────────────────────────────────────────── + +async function callOcrViaHttp(action, payload, { timeoutMs }) { + const baseUrl = String(runtimeConfig.ocr.baseUrl).trim().replace(/\/+$/, '') + const url = `${baseUrl}/ocr/${action}` + + let response + try { + response = await fetch(url, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify(payload), + signal: AbortSignal.timeout(timeoutMs), + }) + } catch (err) { + if (err instanceof Error && err.name === 'TimeoutError') { + throw new Error(`OCR 请求超时(${timeoutMs}ms),请检查 OCR 服务状态`) + } + throw new Error(`OCR 服务不可用(${baseUrl}),请检查 ocr-worker 容器是否正常运行`) + } + + if (!response.ok) { + throw new Error(`OCR 服务返回错误:HTTP ${response.status}`) + } + + const result = await response.json() + if (!result || typeof result !== 'object' || Array.isArray(result)) { + throw new Error('OCR 服务返回了无效响应') + } + if (result.code !== 0) { + throw new Error(`OCR 服务返回错误:${result.msg || '未知错误'}`) + } + + return result +} + +async function warmupOcrViaHttp() { + const baseUrl = String(runtimeConfig.ocr.baseUrl).trim().replace(/\/+$/, '') + let response + try { + response = await fetch(`${baseUrl}/health`, { + signal: AbortSignal.timeout(30_000), + }) + } catch (err) { + if (err instanceof Error && err.name === 'TimeoutError') { + throw new Error(`OCR 服务健康检查超时,请检查 ${baseUrl} 是否可访问`) + } + throw new Error(`OCR 服务不可用(${baseUrl}),请检查 ocr-worker 容器是否正常运行`) + } + if (!response.ok) { + throw new Error(`OCR 服务健康检查失败:HTTP ${response.status}`) + } +} + +// ── Request Router ──────────────────────────────────────────────────────────── + async function callOcrRequest(action, payload, { timeoutMs = DEFAULT_TIMEOUT_MS } = {}) { + const mode = resolveOcrMode() + if (mode === 'http') { + return await callOcrViaHttp(action, payload, { timeoutMs }) + } + // subprocess mode const response = await runOcrCommand('request', { timeoutMs, input: JSON.stringify({ @@ -45,6 +120,8 @@ async function callOcrRequest(action, payload, { timeoutMs = DEFAULT_TIMEOUT_MS return response } +// ── Subprocess Mode ─────────────────────────────────────────────────────────── + async function runOcrCommand(command, { timeoutMs = DEFAULT_TIMEOUT_MS, input = '' } = {}) { const projectRoot = resolveOcrProjectRoot() const workerCommand = resolveWorkerCommand(projectRoot) diff --git a/apps/backend/src/types/runtime-config.js b/apps/backend/src/types/runtime-config.js index b16e3c8e..64c1f0bc 100644 --- a/apps/backend/src/types/runtime-config.js +++ b/apps/backend/src/types/runtime-config.js @@ -1,6 +1,6 @@ // @ts-check -export {} +export {}; /** * @typedef {{ @@ -46,6 +46,7 @@ export {} * } * ocr: { * projectRoot: string + * baseUrl: string * } * data: { * root: string