配置改为数据库存储

将运行时 JSON 配置迁入 app_config_entries,启动时从文件导入并删除源文件。
This commit is contained in:
yml2213
2026-07-10 09:14:12 +08:00
parent ce01c2aa34
commit 3642ad8aec
20 changed files with 577 additions and 251 deletions
@@ -1,7 +1,11 @@
import path from 'node:path'
import { APP_CONFIG_KEYS } from '../../../config/app-config-keys.js'
import { PROJECT_ROOT, runtimeConfig } from '../../../config/runtime.js'
import { readJsonFile, writeJsonFile } from '../../../utils/json-file-store.js'
import {
readAppConfigEntry,
saveAppConfigEntry,
} from '../../config/app-config-store.js'
const KUAISHOU_INDUSTRY_SOURCE_FILE_PATH = path.join(PROJECT_ROOT, 'data', 'kuaishou-industry-source.json')
const DEFAULT_CALLBACK_BASE_URL = 'https://openapi.kwaixiaodian.com'
@@ -62,24 +66,26 @@ export function getKuaishouIndustrySourceFilePath(): string {
}
export function getKuaishouIndustrySourceConfig(): KuaishouIndustrySourceConfig {
return readJsonFile(
KUAISHOU_INDUSTRY_SOURCE_FILE_PATH,
createDefaultKuaishouIndustrySourceConfig,
normalizeKuaishouIndustrySourceConfig,
)
return readAppConfigEntry({
configKey: APP_CONFIG_KEYS.kuaishouIndustrySource,
legacyFilePath: KUAISHOU_INDUSTRY_SOURCE_FILE_PATH,
fallback: createDefaultKuaishouIndustrySourceConfig,
normalize: normalizeKuaishouIndustrySourceConfig,
})
}
export function saveKuaishouIndustrySourceConfig(rawValue: unknown): KuaishouIndustrySourceConfig {
return writeJsonFile(
KUAISHOU_INDUSTRY_SOURCE_FILE_PATH,
rawValue,
normalizeKuaishouIndustrySourceConfig,
)
export function saveKuaishouIndustrySourceConfig(rawValue: unknown): Promise<KuaishouIndustrySourceConfig> {
return saveAppConfigEntry({
configKey: APP_CONFIG_KEYS.kuaishouIndustrySource,
legacyFilePath: KUAISHOU_INDUSTRY_SOURCE_FILE_PATH,
value: rawValue,
normalize: normalizeKuaishouIndustrySourceConfig,
})
}
export function patchKuaishouIndustrySourceConfig(
patch: Partial<KuaishouIndustrySourceConfig>,
): KuaishouIndustrySourceConfig {
): Promise<KuaishouIndustrySourceConfig> {
return saveKuaishouIndustrySourceConfig({
...getKuaishouIndustrySourceConfig(),
...patch,
@@ -108,7 +114,7 @@ export function findKuaishouIndustryShopConfig(
export function patchKuaishouIndustryShopConfig(
sellerId: unknown,
patch: Partial<KuaishouIndustryShopConfig>,
): KuaishouIndustrySourceConfig {
): Promise<KuaishouIndustrySourceConfig> {
const source = getKuaishouIndustrySourceConfig()
const normalizedSellerId = String(patch.sellerId || sellerId || '').trim()
const existing = findKuaishouIndustryShopConfig(normalizedSellerId, source)
@@ -119,7 +125,7 @@ export function patchKuaishouIndustryShopConfig(
})
if (!nextShop) {
return source
return Promise.resolve(source)
}
const shops = listKuaishouIndustryShopConfigs(source)
@@ -131,7 +137,7 @@ export function patchKuaishouIndustryShopConfig(
})
}
function normalizeKuaishouIndustrySourceConfig(rawValue: unknown): KuaishouIndustrySourceConfig {
export function normalizeKuaishouIndustrySourceConfig(rawValue: unknown): KuaishouIndustrySourceConfig {
const fallback = createDefaultKuaishouIndustrySourceConfig()
const source = isPlainObject(rawValue) ? rawValue : {}
const shops = normalizeKuaishouIndustryShopList(source)
@@ -76,7 +76,7 @@ export async function refreshKuaishouIndustryAccessToken(
failureMessage: '快手 accessToken 刷新失败',
errorCode: 'kuaishou_industry_access_token_refresh_failed',
})
const saved = saveTokenPayload(tokenPayload, config, shop)
const saved = await saveTokenPayload(tokenPayload, config, shop)
logInfo('[kuaishou-industry/token]', 'accessToken 刷新成功', {
durationMs: Date.now() - startedAt,
@@ -94,10 +94,10 @@ export async function refreshKuaishouIndustryAccessToken(
}
} catch (error) {
const message = error instanceof Error ? error.message : String(error)
patchKuaishouIndustryShopConfig(shop.sellerId, {
await patchKuaishouIndustryShopConfig(shop.sellerId, {
lastRefreshError: message,
})
patchKuaishouIndustrySourceConfig({
await patchKuaishouIndustrySourceConfig({
lastRefreshError: message,
})
logWarn('[kuaishou-industry/token]', 'accessToken 刷新失败', resolveRefreshErrorDetail(error))
@@ -133,7 +133,7 @@ export async function exchangeKuaishouIndustryAuthorizationCode(
failureMessage: '快手授权码换取 accessToken 失败',
errorCode: 'kuaishou_industry_authorization_code_exchange_failed',
})
const saved = saveTokenPayload(tokenPayload, config, {
const saved = await saveTokenPayload(tokenPayload, config, {
...createEmptyShopConfig(),
sellerId: String(options.sellerId || '').trim(),
shopId: String(options.sellerId || '').trim(),
@@ -157,7 +157,7 @@ export async function exchangeKuaishouIndustryAuthorizationCode(
}
} catch (error) {
const message = error instanceof Error ? error.message : String(error)
patchKuaishouIndustrySourceConfig({
await patchKuaishouIndustrySourceConfig({
lastRefreshError: message,
})
logWarn('[kuaishou-industry/token]', '授权码换取 accessToken 失败', resolveRefreshErrorDetail(error))
@@ -314,7 +314,7 @@ async function requestKuaishouIndustryToken({
if (!response.ok || !isTokenResponseSuccess(json) || !tokenPayload.accessToken) {
const message = resolveTokenErrorMessage(json, response.status, failureMessage)
patchKuaishouIndustrySourceConfig({
await patchKuaishouIndustrySourceConfig({
lastRefreshError: message,
})
throw createHttpError(message, {
@@ -326,7 +326,7 @@ async function requestKuaishouIndustryToken({
return tokenPayload
}
function saveTokenPayload(
async function saveTokenPayload(
tokenPayload: ReturnType<typeof normalizeTokenResponse>,
config: KuaishouIndustrySourceConfig,
shop: KuaishouIndustryShopConfig,
@@ -340,7 +340,7 @@ function saveTokenPayload(
}
const nextRefreshToken = tokenPayload.refreshToken || shop.refreshToken
const savedConfig = patchKuaishouIndustryShopConfig(nextSellerId, {
const savedConfig = await patchKuaishouIndustryShopConfig(nextSellerId, {
...shop,
enabled: shop.enabled !== false,
sellerId: nextSellerId,