增加行业凭证后台 token 配置

This commit is contained in:
yml2213
2026-07-07 23:00:24 +08:00
parent f6cbd7993f
commit 81bfd8b078
24 changed files with 1315 additions and 32 deletions
@@ -0,0 +1,172 @@
import { maskSecret } from '../../../utils/masking.js'
import {
getKuaishouIndustrySourceConfig,
getKuaishouIndustrySourceFilePath,
saveKuaishouIndustrySourceConfig,
type KuaishouIndustrySourceConfig,
} from '../../platforms/kuaishou-industry/source-config-service.js'
import { refreshKuaishouIndustryAccessToken } from '../../platforms/kuaishou-industry/token-service.js'
type JsonObject = Record<string, any>
const SECRET_FIELDS = [
'appSecret',
'signSecret',
'messageSecret',
'accessToken',
'refreshToken',
] as const
export function getAdminKuaishouIndustrySourceConfig() {
const config = getKuaishouIndustrySourceConfig()
return {
filePath: getKuaishouIndustrySourceFilePath(),
source: mapAdminKuaishouIndustrySourceConfig(config),
}
}
export function updateAdminKuaishouIndustrySourceConfig(payload: JsonObject = {}) {
const current = getKuaishouIndustrySourceConfig()
const saved = saveKuaishouIndustrySourceConfig({
...current,
enabled: hasPayloadField(payload, 'enabled') ? payload.enabled !== false : current.enabled !== false,
sendCallbackEnabled: hasPayloadField(payload, 'sendCallbackEnabled')
? payload.sendCallbackEnabled === true
: current.sendCallbackEnabled === true,
baseUrl: readConfigString(payload, 'baseUrl', current.baseUrl),
authBaseUrl: readConfigString(payload, 'authBaseUrl', current.authBaseUrl),
appKey: readConfigString(payload, 'appKey', current.appKey, { allowBlank: true }),
sellerId: readConfigString(payload, 'sellerId', current.sellerId, { allowBlank: true }),
provider: readConfigString(payload, 'provider', current.provider),
platform: readConfigString(payload, 'platform', current.platform),
shopId: readConfigString(payload, 'shopId', current.shopId),
shopName: readConfigString(payload, 'shopName', current.shopName),
version: readConfigString(payload, 'version', current.version),
accessTokenExpiresAt: readConfigString(payload, 'accessTokenExpiresAt', current.accessTokenExpiresAt, { allowBlank: true }),
refreshTokenExpiresAt: readConfigString(payload, 'refreshTokenExpiresAt', current.refreshTokenExpiresAt, { allowBlank: true }),
...resolveSecretPatch(payload, current),
})
return {
filePath: getKuaishouIndustrySourceFilePath(),
source: mapAdminKuaishouIndustrySourceConfig(saved),
}
}
export async function refreshAdminKuaishouIndustryAccessToken() {
const result = await refreshKuaishouIndustryAccessToken()
return {
filePath: getKuaishouIndustrySourceFilePath(),
refreshed: result.refreshed,
source: mapAdminKuaishouIndustrySourceConfig(result.config),
}
}
function mapAdminKuaishouIndustrySourceConfig(config: KuaishouIndustrySourceConfig) {
const accessTokenStatus = resolveAccessTokenStatus(config)
return {
enabled: config.enabled !== false,
sendCallbackEnabled: config.sendCallbackEnabled === true,
baseUrl: config.baseUrl,
authBaseUrl: config.authBaseUrl,
appKey: config.appKey,
appSecret: '',
appSecretMasked: maskSecret(config.appSecret),
hasAppSecret: Boolean(config.appSecret),
signSecret: '',
signSecretMasked: maskSecret(config.signSecret),
hasSignSecret: Boolean(config.signSecret),
messageSecret: '',
messageSecretMasked: maskSecret(config.messageSecret),
hasMessageSecret: Boolean(config.messageSecret),
accessToken: '',
accessTokenMasked: maskSecret(config.accessToken),
hasAccessToken: Boolean(config.accessToken),
refreshToken: '',
refreshTokenMasked: maskSecret(config.refreshToken),
hasRefreshToken: Boolean(config.refreshToken),
accessTokenExpiresAt: config.accessTokenExpiresAt,
refreshTokenExpiresAt: config.refreshTokenExpiresAt,
accessTokenStatus: accessTokenStatus.status,
accessTokenExpiresInSeconds: accessTokenStatus.expiresInSeconds,
sellerId: config.sellerId,
provider: config.provider,
platform: config.platform,
shopId: config.shopId,
shopName: config.shopName,
version: config.version,
lastRefreshedAt: config.lastRefreshedAt,
lastRefreshError: config.lastRefreshError,
}
}
function resolveSecretPatch(
payload: JsonObject,
current: KuaishouIndustrySourceConfig,
): Partial<KuaishouIndustrySourceConfig> {
const patch: Partial<KuaishouIndustrySourceConfig> = {}
for (const field of SECRET_FIELDS) {
const text = String(payload[field] || '').trim()
patch[field] = text || current[field]
}
return patch
}
function resolveAccessTokenStatus(config: KuaishouIndustrySourceConfig) {
if (!config.accessToken) {
return {
status: 'missing',
expiresInSeconds: null,
}
}
const expiresAt = Date.parse(config.accessTokenExpiresAt || '')
if (!Number.isFinite(expiresAt)) {
return {
status: 'unknown',
expiresInSeconds: null,
}
}
const expiresInSeconds = Math.floor((expiresAt - Date.now()) / 1000)
if (expiresInSeconds <= 0) {
return {
status: 'expired',
expiresInSeconds,
}
}
if (expiresInSeconds <= 30 * 60) {
return {
status: 'expiring',
expiresInSeconds,
}
}
return {
status: 'valid',
expiresInSeconds,
}
}
function readConfigString(
payload: JsonObject,
field: string,
fallback: string,
options: { allowBlank?: boolean } = {},
): string {
if (!hasPayloadField(payload, field)) {
return fallback
}
const text = String(payload[field] || '').trim()
return text || (options.allowBlank ? '' : fallback)
}
function hasPayloadField(payload: JsonObject, field: string): boolean {
return Object.prototype.hasOwnProperty.call(payload, field)
}