后端迁移平台配置底座

This commit is contained in:
yml
2026-05-21 16:04:09 +08:00
parent ed659ea232
commit 38b0bf8ba5
5 changed files with 56 additions and 57 deletions
@@ -1,6 +1,6 @@
// @ts-check
type JsonObject = Record<string, any>
export function pickFirstNonEmpty(values) {
export function pickFirstNonEmpty(values: unknown[]) {
for (const value of values) {
const normalized = String(value || "").trim();
if (normalized) {
@@ -11,31 +11,23 @@ export function pickFirstNonEmpty(values) {
return "";
}
export function isPlainObject(value) {
export function isPlainObject(value: unknown): value is JsonObject {
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
}
export function resolveKuaishouEticketAdminContext(payload = {}, options = {}) {
const savedSource = /** @type {Record<string, unknown>} */ (
options.savedSource || {}
);
export function resolveKuaishouEticketAdminContext(payload: JsonObject = {}, options: JsonObject = {}) {
const savedSource = options.savedSource || {};
const findShopConfig =
/** @type {(shopId: string, source: Record<string, unknown>) => unknown} */ (
options.findShopConfig || (() => null)
);
(options.findShopConfig || (() => null)) as (shopId: string, source: JsonObject) => unknown;
const getFirstAvailableShop =
/** @type {(source: Record<string, unknown>) => unknown} */ (
options.getFirstAvailableShop || (() => null)
);
(options.getFirstAvailableShop || (() => null)) as (source: JsonObject) => unknown;
const defaultBaseUrl = String(
options.defaultBaseUrl || "https://s.kwaixiaodian.com"
).trim();
const requestedShopId = String(payload.shopId || "").trim();
const configuredShop = /** @type {Record<string, unknown> | null} */ (
requestedShopId
const configuredShop = (requestedShopId
? findShopConfig(requestedShopId, savedSource)
: getFirstAvailableShop(savedSource)
);
: getFirstAvailableShop(savedSource)) as JsonObject | null;
return {
baseUrl: pickFirstNonEmpty([
@@ -52,18 +44,14 @@ export function resolveKuaishouEticketAdminContext(payload = {}, options = {}) {
import { getCloudtentaclesSourceByKey } from "../../platforms/cloudtentacles/source-config-service.js";
import { getCloudtentaclesSessionStateByKey } from "../../platforms/cloudtentacles/session-state-service.js";
export function resolveCloudtentaclesAdminContext(payload = {}, options = {}) {
export function resolveCloudtentaclesAdminContext(payload: JsonObject = {}, options: JsonObject = {}) {
const sourceKey = String(
payload.sourceKey || options.sourceKey || "default"
).trim();
const savedSource = /** @type {Record<string, unknown>} */ (
options.savedSource || getCloudtentaclesSourceByKey(sourceKey) || {}
);
const persistedSession = /** @type {Record<string, unknown>} */ (
options.persistedSession ||
const savedSource = options.savedSource || getCloudtentaclesSourceByKey(sourceKey) || {};
const persistedSession = options.persistedSession ||
getCloudtentaclesSessionStateByKey(sourceKey) ||
{}
);
{};
const defaultBaseUrl = String(
options.defaultBaseUrl || "https://123.207.217.176"
).trim();
@@ -89,8 +77,8 @@ export function resolveCloudtentaclesAdminContext(payload = {}, options = {}) {
}
export function hasCloudtentaclesCredentialContextChanged(
current = {},
next = {}
current: JsonObject = {},
next: JsonObject = {}
) {
return (
String(current.baseUrl || "").trim() !==
@@ -1,9 +1,9 @@
// @ts-check
import { normalizeAgisoMessageTemplate } from '../../platforms/agiso/xianyu/message-service.js'
import { maskSecret } from './mappers.js'
export function mapAdminAgisoMessagingDefaults(defaults = {}) {
type JsonObject = Record<string, any>
export function mapAdminAgisoMessagingDefaults(defaults: JsonObject = {}) {
return {
messageTemplate: normalizeAgisoMessageTemplate(String(defaults.messageTemplate || '').trim()),
autoDeliveryMessageTemplate: normalizeAgisoMessageTemplate(
@@ -12,7 +12,7 @@ export function mapAdminAgisoMessagingDefaults(defaults = {}) {
}
}
export function mapAdminAgisoShopConfigItem(shopId, config = {}) {
export function mapAdminAgisoShopConfigItem(shopId: unknown, config: JsonObject = {}) {
return {
shopId,
shopName: String(config.shopName || '').trim(),
@@ -29,7 +29,7 @@ export function mapAdminAgisoShopConfigItem(shopId, config = {}) {
}
}
export function applyOptionalStringField(target, key, source) {
export function applyOptionalStringField(target: JsonObject, key: string, source: JsonObject) {
if (!source || typeof source[key] !== 'string') {
return
}
@@ -43,7 +43,7 @@ export function applyOptionalStringField(target, key, source) {
delete target[key]
}
export function mapAdminFulfillmentBindingConfigItem(item) {
export function mapAdminFulfillmentBindingConfigItem(item: JsonObject) {
const match = item?.match || {}
return {
provider: String(item?.provider || '').trim(),
@@ -65,7 +65,7 @@ export function mapAdminFulfillmentBindingConfigItem(item) {
}
}
export function matchesObservedProduct(binding, observed) {
export function matchesObservedProduct(binding: JsonObject, observed: JsonObject) {
const provider = String(binding?.provider || '').trim()
const platform = String(binding?.platform || '').trim()
const shopId = String(binding?.shopId || '').trim()
@@ -93,11 +93,11 @@ export function matchesObservedProduct(binding, observed) {
)
}
export function findMatchingObservedBinding(bindings, observed) {
export function findMatchingObservedBinding(bindings: JsonObject[], observed: JsonObject) {
return (Array.isArray(bindings) ? bindings : []).find((binding) => matchesObservedProduct(binding, observed)) || null
}
export function mapAdminObservedProductItem(item, bindings = []) {
export function mapAdminObservedProductItem(item: JsonObject, bindings: JsonObject[] = []) {
const matchedBinding = findMatchingObservedBinding(bindings, item)
return {
@@ -1,6 +1,6 @@
// @ts-check
type JsonObject = Record<string, any>
export function maskSecret(value) {
export function maskSecret(value: unknown) {
const normalized = String(value || "").trim();
if (!normalized) {
return "";
@@ -13,7 +13,7 @@ export function maskSecret(value) {
return `${normalized.slice(0, 6)}****${normalized.slice(-6)}`;
}
export function maskPhone(value) {
export function maskPhone(value: unknown) {
const normalized = String(value || "").trim();
if (!normalized) {
return "";
@@ -26,7 +26,7 @@ export function maskPhone(value) {
return `${normalized.slice(0, 3)}****${normalized.slice(-4)}`;
}
export function mapAdminKuaishouEticketShopItem(item = {}) {
export function mapAdminKuaishouEticketShopItem(item: JsonObject = {}) {
return {
shopId: String(item.shopId || "").trim(),
kshopName: String(item.kshopName || "").trim(),
@@ -38,7 +38,7 @@ export function mapAdminKuaishouEticketShopItem(item = {}) {
};
}
export function mapAdminKuaishouEticketSourceConfig(config = {}, shops = []) {
export function mapAdminKuaishouEticketSourceConfig(config: JsonObject = {}, shops: JsonObject[] = []) {
return {
enabled: config.enabled !== false,
baseUrl: String(config.baseUrl || "").trim(),
@@ -46,7 +46,7 @@ export function mapAdminKuaishouEticketSourceConfig(config = {}, shops = []) {
};
}
export function mapAdminCloudtentaclesSourceConfig(config = {}) {
export function mapAdminCloudtentaclesSourceConfig(config: JsonObject = {}) {
return {
key: String(config.key || "").trim(),
label: String(config.label || "").trim(),
@@ -60,7 +60,7 @@ export function mapAdminCloudtentaclesSourceConfig(config = {}) {
};
}
export function mapAdminCloudtentaclesSession(session = {}) {
export function mapAdminCloudtentaclesSession(session: JsonObject = {}) {
return {
token: String(session.token || "").trim(),
tokenMasked: maskSecret(session.token),
@@ -74,7 +74,7 @@ export function mapAdminCloudtentaclesSession(session = {}) {
};
}
export function mapAdminKuaishouCloudFulfillmentItem(item = {}) {
export function mapAdminKuaishouCloudFulfillmentItem(item: JsonObject = {}) {
return {
id: String(item.id || "").trim(),
enabled: item.enabled !== false,
@@ -103,7 +103,7 @@ export function mapAdminKuaishouCloudFulfillmentItem(item = {}) {
};
}
export function mapAdminKuaishouCloudFulfillmentSource(config = {}) {
export function mapAdminKuaishouCloudFulfillmentSource(config: JsonObject = {}) {
return {
enabled: config.enabled !== false,
items: (Array.isArray(config.items) ? config.items : []).map((item) =>
@@ -1,10 +1,10 @@
// @ts-check
import { createHttpError } from '../../../utils/http.js'
import { normalizeProductName } from '../../order/product-match-service.js'
import { isPlainObject } from './context.js'
export function assertAdminFulfillmentBindingsInput(bindings) {
type JsonObject = Record<string, any>
export function assertAdminFulfillmentBindingsInput(bindings: unknown) {
if (Array.isArray(bindings)) {
return
}
@@ -16,8 +16,8 @@ export function assertAdminFulfillmentBindingsInput(bindings) {
}
export function normalizeAdminFulfillmentBindingItem(
rawBinding,
options = {},
rawBinding: unknown,
options: JsonObject = {},
) {
const index = Number(options.index || 0)
if (!isPlainObject(rawBinding)) {
@@ -87,16 +87,16 @@ export function buildAdminFulfillmentBindingUniqueKey(binding) {
}
export async function validateAdminFulfillmentBindingConfigs(
bindings,
options = {},
bindings: JsonObject[],
options: JsonObject = {},
) {
assertAdminFulfillmentBindingsInput(bindings)
const getFulfillmentProfileByKey = /** @type {(profileKey: string) => Promise<unknown>} */ (
const getFulfillmentProfileByKey = (
options.getFulfillmentProfileByKey || (async () => null)
)
) as (profileKey: string) => Promise<unknown>
const seenKeys = new Set()
const normalizedBindings = []
const normalizedBindings: JsonObject[] = []
for (const [index, rawBinding] of bindings.entries()) {
const normalized = normalizeAdminFulfillmentBindingItem(rawBinding, { index })
+11
View File
@@ -578,6 +578,17 @@
- `npm run typecheck`
- `npm run build`
- `npm test` 共 139 个用例通过
135. 后台平台配置底座模块迁移到 `.ts`
- `src/services/admin/platform-config/context.ts`
- `src/services/admin/platform-config/domain.ts`
- `src/services/admin/platform-config/mappers.ts`
- `src/services/admin/platform-config/validation.ts`
136. 后台平台配置上下文解析、展示映射、敏感信息脱敏、履约绑定校验与重复规则检测已进入 TS 编译链路;动态配置对象补齐通用类型,`isPlainObject` 改为类型守卫
137. Docker 内验证通过:
- `src/services/admin/platform-config/context.test.js``domain.test.js``mappers.test.js``validation.test.js` 共 23 个用例通过
- `npm run typecheck`
- `npm run build`
- `npm test` 共 139 个用例通过
## 下一步建议