继续收紧 TypeScript:ClaimIdentity 契约与 flow 出口类型

- 新增 types/claim-identity,统一 ClaimIdentity / Payload / AdminSummary
- 导出 KuaishouCloudFlow、KuaishouFeifeiFlow 作为 normalize 出口
- 生产路径 JsonObject 统一从 types/json 导入,去掉 rebind as any
- 前后端 claimIdentity 类型字段对齐
This commit is contained in:
yml2213
2026-07-10 15:56:25 +08:00
parent 8bcd9bbd81
commit 042574dea3
20 changed files with 219 additions and 88 deletions
@@ -18,7 +18,103 @@ export function isIndustryEVoucherTask(task: unknown) {
return String(source.executor_key || '').trim() === 'kuaishou-industry'
}
export function normalizeKuaishouCloudFlow(value: unknown) {
export type KuaishouCloudDeliveryItem = {
cloudSkuId: number
cloudSkuName: string
quantity: number
}
/** normalizeKuaishouCloudFlow 出口类型(履约主路径应经此 normalize) */
export type KuaishouCloudFlow = {
configId: string
internalSkuCode: string
internalSkuName: string
deliveryItems: KuaishouCloudDeliveryItem[]
ticket: {
code: string
status: string
capturedAt: unknown
capturedBy: unknown
verifiedAt: unknown
oid: string
formToken: string
leftCount: number
goodsTitle: string
}
binding: {
prepareStatus: string
cloudSourceKeys: string[]
resolvedSourceKey: string
skuId: number
skuName: string
vnKey: string
vnId: number
vnPhone: string
bindUrl: string
bindPreparedAt: unknown
bindExpiresAt: unknown
bindProbeAt: unknown
bindProbeStatus: string
bindProbeMessage: string
roleName: string
roleId: string
}
role: {
status: string
name: string
rid: string
refreshedAt: unknown
errorMessage: string
rawInfo: unknown
defaultName: string
defaultRid: string
defaultCapturedAt: unknown
defaultCaptureStatus: string
defaultErrorMessage: string
isDefaultRole: boolean
}
purchase: {
autoBuyEnabled: boolean
minAssetReserve: number
usedKnapsack: boolean
purchaseTriggered: boolean
assetBefore: number
assetAfter: number
purchaseAt: unknown
items: unknown[]
}
dispatch: {
status: string
dispatchAt: unknown
dispatchBy: unknown
sendType: number
note: string
items: unknown[]
}
returnNumber: {
status: string
returnedAt: unknown
returnedBy: unknown
autoReturnEnabled: boolean
}
consume: {
status: string
shopId: string
shopName: string
autoConsumeEnabled: boolean
consumedAt: unknown
errorMessage: string
}
rebind: {
currentAttempt: number
history: unknown[]
}
notes: string
/** 未建模扩展(mock 等)仍可落库 */
[key: string]: unknown
}
export function normalizeKuaishouCloudFlow(value: unknown): KuaishouCloudFlow {
const source: JsonObject = value && typeof value === 'object' ? (value as JsonObject) : {}
const binding = asJsonObject(source.binding)
const role = asJsonObject(source.role)
@@ -14,6 +14,10 @@ export {
isSameKuaishouCloudRoleIdentity,
resolveKuaishouCloudBindUrlExpiresAt,
} from './domain.js'
export type {
KuaishouCloudDeliveryItem,
KuaishouCloudFlow,
} from './domain.js'
export { resolvePersistedCloudtentaclesContextBySourceKeys } from './cloudtentacles-context.js'
export { ensureTaskClaimLink } from './ensure-claim-link.js'
export {
@@ -41,10 +41,13 @@ export async function probeKuaishouCloudTaskBindUrl(task: TaskRow, options: Json
const probeIntervalMs =
Number(resolveCloudtentaclesConfig().bindUrlProbeIntervalSeconds || 30) * 1000
const lastProbeAt = flow.binding.bindProbeAt
? Date.parse(String(flow.binding.bindProbeAt))
: NaN
if (
!options.force &&
flow.binding.bindProbeAt &&
Date.now() - Date.parse(flow.binding.bindProbeAt) < probeIntervalMs
Number.isFinite(lastProbeAt) &&
Date.now() - lastProbeAt < probeIntervalMs
) {
return {
task,
@@ -38,14 +38,13 @@ export async function rebindKuaishouCloudTaskRole(task: TaskRow, options: JsonOb
}
const normalizedStatus = normalizeTaskStatus(task.task_status)
if (
![
TASK_STATUS.WAITING_BINDING,
TASK_STATUS.ROLE_CONFIRMED,
TASK_STATUS.MANUAL_REVIEW,
TASK_STATUS.RETRY_PENDING,
].includes(normalizedStatus as any)
) {
const rebindAllowedStatuses = new Set<string>([
TASK_STATUS.WAITING_BINDING,
TASK_STATUS.ROLE_CONFIRMED,
TASK_STATUS.MANUAL_REVIEW,
TASK_STATUS.RETRY_PENDING,
])
if (!rebindAllowedStatuses.has(normalizedStatus)) {
throw createHttpError('当前任务状态不可换绑角色', {
statusCode: 409,
errorCode: 'kuaishou_cloud_rebind_not_allowed',
@@ -6,9 +6,9 @@ import { getCloudtentaclesBindInfo } from '../../platforms/cloudtentacles/virtua
import {
hasKuaishouCloudDefaultRoleSnapshot,
isSameKuaishouCloudRoleIdentity,
normalizeKuaishouCloudFlow,
normalizeKuaishouCloudRoleInfo,
type JsonObject,
type KuaishouCloudFlow,
} from './domain.js'
export type KuaishouCloudDefaultRoleSnapshot = {
@@ -79,7 +79,7 @@ export function buildRoleStateFromCurrentInfo({
now,
emptyMessage,
}: {
flow: ReturnType<typeof normalizeKuaishouCloudFlow>
flow: KuaishouCloudFlow
roleInfo: { name: string; rid: string; rawInfo?: unknown }
now: string
emptyMessage: string
@@ -207,7 +207,28 @@ export async function syncKuaishouFeifeiTaskStatus(task: TaskRow) {
return updatedTask || task
}
export function normalizeKuaishouFeifeiFlow(value: unknown) {
/** normalizeKuaishouFeifeiFlow 出口类型 */
export type KuaishouFeifeiFlow = {
flowType: 'kuaishou_feifei'
productCode: string
productName: string
platformOrderNo: string
orderNo: string
rechargeStatus: number
rechargeStatusLabel: string
rechargeResultMessage: string
claimUrl: string
consumeStatus: string
shortLink: ReturnType<typeof normalizeShortLinkPayload>
h5: {
entryUrl: string
rechargeUrl: string
}
lastSyncedAt: unknown
raw: unknown
}
export function normalizeKuaishouFeifeiFlow(value: unknown): KuaishouFeifeiFlow {
const source = value && typeof value === 'object' && !Array.isArray(value)
? value as JsonObject
: {}
@@ -270,7 +291,7 @@ export function resolveKuaishouFeifeiH5UrlWithTaskUid(
}
function mergeKuaishouFeifeiOrder(
flow: ReturnType<typeof normalizeKuaishouFeifeiFlow>,
flow: KuaishouFeifeiFlow,
order: Awaited<ReturnType<typeof createKuaishouFeifeiOrder>>,
patch: {
platformOrderNo?: string
@@ -299,7 +320,7 @@ function mergeKuaishouFeifeiOrder(
}
function resolveKuaishouFeifeiDirectClaimUrl(
flow: ReturnType<typeof normalizeKuaishouFeifeiFlow>,
flow: KuaishouFeifeiFlow,
) {
const h5ClaimUrl = flow.h5.rechargeUrl || flow.h5.entryUrl
if (h5ClaimUrl) {
@@ -1,4 +1,5 @@
import { getFulfillmentProfileByKey } from '../../repositories/fulfillment-profile-repo.js'
import type { JsonObject } from '../../types/json.js'
import type { OrderItemRow, OrderRow } from '../../types/repository/rows.js'
import {
FULFILLMENT_EXECUTOR_KEYS,
@@ -6,8 +7,6 @@ import {
isKuaishouFeifeiExecutor,
} from './executors/types.js'
type JsonObject = Record<string, unknown>
export type FulfillmentBindingLike = {
id: number
profile_id?: number
@@ -7,10 +7,9 @@ import {
saveAppConfigEntry,
} from '../config/app-config-store.js'
import { normalizeCloudtentaclesMatchName } from '../order/cloudtentacles-match-utils.js'
import type { JsonObject } from '../../types/json.js'
import { FULFILLMENT_EXECUTOR_KEYS } from './executors/types.js'
type JsonObject = Record<string, unknown>
export type FulfillmentRoutingRuleMatchType = 'exact' | 'contains'
export type FulfillmentRoutingExecutorConfig = {