[Snow Team] Merge ocr-node's work

This commit is contained in:
yml
2026-05-19 23:10:39 +08:00
4 changed files with 437 additions and 216 deletions
+1
View File
@@ -20,6 +20,7 @@ module.exports = {
ocr: { ocr: {
projectRoot: path.resolve(__dirname, '../subservices/ocr-worker'), projectRoot: path.resolve(__dirname, '../subservices/ocr-worker'),
baseUrl: '',
}, },
data: { data: {
+356 -214
View File
@@ -1,544 +1,686 @@
// @ts-check // @ts-check
import fs from 'node:fs' import fs from "node:fs";
import path from 'node:path' import path from "node:path";
import process from 'node:process' import process from "node:process";
import { createRequire } from 'node:module' import { createRequire } from "node:module";
import { fileURLToPath } from 'node:url' import { fileURLToPath } from "node:url";
/** @typedef {import('../types/runtime-config.js').RuntimeConfig} RuntimeConfig */ /** @typedef {import('../types/runtime-config.js').RuntimeConfig} RuntimeConfig */
const require = createRequire(import.meta.url) const require = createRequire(import.meta.url);
const CURRENT_DIR = path.dirname(fileURLToPath(import.meta.url)) const CURRENT_DIR = path.dirname(fileURLToPath(import.meta.url));
export const PROJECT_ROOT = path.resolve(CURRENT_DIR, '../..') export const PROJECT_ROOT = path.resolve(CURRENT_DIR, "../..");
const WORKSPACE_ROOT = path.resolve(PROJECT_ROOT, '../..') const WORKSPACE_ROOT = path.resolve(PROJECT_ROOT, "../..");
const CONFIG_ROOT = path.join(PROJECT_ROOT, 'config') const CONFIG_ROOT = path.join(PROJECT_ROOT, "config");
loadEnvFiles([ loadEnvFiles([
path.join(WORKSPACE_ROOT, '.env'), path.join(WORKSPACE_ROOT, ".env"),
path.join(PROJECT_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) { function loadConfig(configPath) {
if (!fs.existsSync(configPath)) { if (!fs.existsSync(configPath)) {
return {} return {};
} }
const loaded = require(configPath) const loaded = require(configPath);
return isPlainObject(loaded) ? loaded : {} return isPlainObject(loaded) ? loaded : {};
} }
function loadEnvFiles(filePaths) { function loadEnvFiles(filePaths) {
for (const filePath of filePaths) { for (const filePath of filePaths) {
loadEnvFile(filePath) loadEnvFile(filePath);
} }
} }
function loadEnvFile(filePath) { function loadEnvFile(filePath) {
if (!fs.existsSync(filePath)) { if (!fs.existsSync(filePath)) {
return return;
} }
const rawText = fs.readFileSync(filePath, 'utf8') const rawText = fs.readFileSync(filePath, "utf8");
const lines = rawText.split(/\r?\n/) const lines = rawText.split(/\r?\n/);
for (const rawLine of lines) { for (const rawLine of lines) {
const line = rawLine.trim() const line = rawLine.trim();
if (!line || line.startsWith('#')) { if (!line || line.startsWith("#")) {
continue continue;
} }
const separatorIndex = line.indexOf('=') const separatorIndex = line.indexOf("=");
if (separatorIndex <= 0) { 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) { 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) { function parseEnvValue(rawValue) {
const value = String(rawValue || '').trim() const value = String(rawValue || "").trim();
if (!value) { if (!value) {
return '' return "";
} }
const quote = value[0] const quote = value[0];
if ((quote === '"' || quote === "'") && value.endsWith(quote)) { if ((quote === '"' || quote === "'") && value.endsWith(quote)) {
return value.slice(1, -1) return value.slice(1, -1);
} }
return value return value;
} }
function applyEnvOverrides(baseConfig) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { if (claimBaseUrl) {
nextConfig.orders.claimBaseUrl = claimBaseUrl nextConfig.orders.claimBaseUrl = claimBaseUrl;
} else { } else {
const appBaseUrl = String(process.env.APP_BASE_URL || '').trim() const appBaseUrl = String(process.env.APP_BASE_URL || "").trim();
if (appBaseUrl) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { 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) { if (proofMode) {
nextConfig.redeem.proofMode = proofMode nextConfig.redeem.proofMode = proofMode;
} }
return nextConfig return nextConfig;
} }
function deepMerge(baseValue, overrideValue) { function deepMerge(baseValue, overrideValue) {
if (!isPlainObject(baseValue)) { if (!isPlainObject(baseValue)) {
return cloneValue(overrideValue) return cloneValue(overrideValue);
} }
const result = cloneValue(baseValue) const result = cloneValue(baseValue);
if (!isPlainObject(overrideValue)) { if (!isPlainObject(overrideValue)) {
return result return result;
} }
for (const [key, value] of Object.entries(overrideValue)) { for (const [key, value] of Object.entries(overrideValue)) {
if (isPlainObject(value) && isPlainObject(result[key])) { if (isPlainObject(value) && isPlainObject(result[key])) {
result[key] = deepMerge(result[key], value) result[key] = deepMerge(result[key], value);
continue continue;
} }
result[key] = cloneValue(value) result[key] = cloneValue(value);
} }
return result return result;
} }
function cloneValue(value) { function cloneValue(value) {
if (Array.isArray(value)) { if (Array.isArray(value)) {
return value.map((item) => cloneValue(item)) return value.map((item) => cloneValue(item));
} }
if (isPlainObject(value)) { if (isPlainObject(value)) {
const output = {} const output = {};
for (const [key, item] of Object.entries(value)) { 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) { function isPlainObject(value) {
return Object.prototype.toString.call(value) === '[object Object]' return Object.prototype.toString.call(value) === "[object Object]";
} }
function parseBoolean(rawValue) { function parseBoolean(rawValue) {
const normalized = String(rawValue || '').trim().toLowerCase() const normalized = String(rawValue || "")
.trim()
.toLowerCase();
if (!normalized) { if (!normalized) {
return null return null;
} }
if (['1', 'true', 'yes', 'on'].includes(normalized)) { if (["1", "true", "yes", "on"].includes(normalized)) {
return true return true;
} }
if (['0', 'false', 'no', 'off'].includes(normalized)) { if (["0", "false", "no", "off"].includes(normalized)) {
return false return false;
} }
return null return null;
} }
function parseInteger(rawValue) { function parseInteger(rawValue) {
const normalized = String(rawValue || '').trim() const normalized = String(rawValue || "").trim();
if (!normalized) { if (!normalized) {
return null return null;
} }
const parsed = Number(normalized) const parsed = Number(normalized);
return Number.isFinite(parsed) ? parsed : null return Number.isFinite(parsed) ? parsed : null;
} }
function parseJsonArray(rawValue) { function parseJsonArray(rawValue) {
const normalized = String(rawValue || '').trim() const normalized = String(rawValue || "").trim();
if (!normalized) { if (!normalized) {
return null return null;
} }
try { try {
const parsed = JSON.parse(normalized) const parsed = JSON.parse(normalized);
return Array.isArray(parsed) ? parsed : null return Array.isArray(parsed) ? parsed : null;
} catch { } catch {
return null return null;
} }
} }
function normalizeBooleanLike(value) { function normalizeBooleanLike(value) {
if (typeof value === 'boolean') { if (typeof value === "boolean") {
return value return value;
} }
return parseBoolean(value) return parseBoolean(value);
} }
+78 -1
View File
@@ -22,14 +22,89 @@ export async function batchRecognizeTencentCaptcha(payload) {
} }
export async function warmupLocalOcrWorker() { export async function warmupLocalOcrWorker() {
const mode = resolveOcrMode()
if (mode === 'http') {
await warmupOcrViaHttp()
return
}
await runOcrCommand('healthcheck', { timeoutMs: 30_000 }) await runOcrCommand('healthcheck', { timeoutMs: 30_000 })
} }
export async function closeLocalOcrWorker() { 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 } = {}) { 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', { const response = await runOcrCommand('request', {
timeoutMs, timeoutMs,
input: JSON.stringify({ input: JSON.stringify({
@@ -45,6 +120,8 @@ async function callOcrRequest(action, payload, { timeoutMs = DEFAULT_TIMEOUT_MS
return response return response
} }
// ── Subprocess Mode ───────────────────────────────────────────────────────────
async function runOcrCommand(command, { timeoutMs = DEFAULT_TIMEOUT_MS, input = '' } = {}) { async function runOcrCommand(command, { timeoutMs = DEFAULT_TIMEOUT_MS, input = '' } = {}) {
const projectRoot = resolveOcrProjectRoot() const projectRoot = resolveOcrProjectRoot()
const workerCommand = resolveWorkerCommand(projectRoot) const workerCommand = resolveWorkerCommand(projectRoot)
+2 -1
View File
@@ -1,6 +1,6 @@
// @ts-check // @ts-check
export {} export {};
/** /**
* @typedef {{ * @typedef {{
@@ -46,6 +46,7 @@ export {}
* } * }
* ocr: { * ocr: {
* projectRoot: string * projectRoot: string
* baseUrl: string
* } * }
* data: { * data: {
* root: string * root: string