继续收紧 TypeScript:ClaimIdentity 契约与 flow 出口类型
- 新增 types/claim-identity,统一 ClaimIdentity / Payload / AdminSummary - 导出 KuaishouCloudFlow、KuaishouFeifeiFlow 作为 normalize 出口 - 生产路径 JsonObject 统一从 types/json 导入,去掉 rebind as any - 前后端 claimIdentity 类型字段对齐
This commit is contained in:
@@ -34,18 +34,7 @@ export type CloudSkuLikeItem = {
|
|||||||
[key: string]: unknown
|
[key: string]: unknown
|
||||||
}
|
}
|
||||||
|
|
||||||
export type KuaishouCloudFlow = JsonObject & {
|
export type { KuaishouCloudFlow } from '../../fulfillment/kuaishou-cloud/domain.js'
|
||||||
configId: string
|
|
||||||
internalSkuCode: string
|
|
||||||
internalSkuName: string
|
|
||||||
ticket: JsonObject
|
|
||||||
binding: JsonObject
|
|
||||||
role: JsonObject
|
|
||||||
purchase: JsonObject
|
|
||||||
dispatch: JsonObject
|
|
||||||
returnNumber: JsonObject
|
|
||||||
consume: JsonObject
|
|
||||||
}
|
|
||||||
|
|
||||||
export type KuaishouCloudBindingResources = {
|
export type KuaishouCloudBindingResources = {
|
||||||
skuId: number
|
skuId: number
|
||||||
|
|||||||
@@ -1,14 +1,19 @@
|
|||||||
import { createHttpError } from '../../utils/http.js'
|
import { createHttpError } from '../../utils/http.js'
|
||||||
import { parseTaskContext } from '../../utils/task-json.js'
|
import { parseTaskContext } from '../../utils/task-json.js'
|
||||||
import { isTaskFinalStatus, normalizeTaskStatus, TASK_STATUS } from '../../domain/task-status.js'
|
import { isTaskFinalStatus, normalizeTaskStatus, TASK_STATUS } from '../../domain/task-status.js'
|
||||||
|
import type {
|
||||||
|
ClaimIdentity,
|
||||||
|
ClaimIdentityAdminSummary,
|
||||||
|
ClaimIdentityPayload,
|
||||||
|
} from '../../types/claim-identity.js'
|
||||||
import type { TaskRow } from '../../types/repository/rows.js'
|
import type { TaskRow } from '../../types/repository/rows.js'
|
||||||
import type { JsonObject } from '../../types/json.js'
|
import type { JsonObject } from '../../types/json.js'
|
||||||
|
|
||||||
export type ClaimIdentity = {
|
export type {
|
||||||
expectedUid: string
|
ClaimIdentity,
|
||||||
submittedAt: string | null
|
ClaimIdentityAdminSummary,
|
||||||
source: string
|
ClaimIdentityPayload,
|
||||||
}
|
} from '../../types/claim-identity.js'
|
||||||
|
|
||||||
const CLAIM_UID_MAX_LENGTH = 64
|
const CLAIM_UID_MAX_LENGTH = 64
|
||||||
|
|
||||||
@@ -130,18 +135,6 @@ export function assertLewanAutoFulfillmentUidReady(
|
|||||||
return expectedUid
|
return expectedUid
|
||||||
}
|
}
|
||||||
|
|
||||||
export type ClaimIdentityAdminSummary = {
|
|
||||||
expectedUid: string
|
|
||||||
submittedAt: string | null
|
|
||||||
source: string
|
|
||||||
ready: boolean
|
|
||||||
boundUid: string
|
|
||||||
boundRoleName: string
|
|
||||||
uidMatched: boolean | null
|
|
||||||
compatibilityMode: 'uid' | 'legacy_no_uid'
|
|
||||||
note: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export function buildClaimIdentityAdminSummary(
|
export function buildClaimIdentityAdminSummary(
|
||||||
context: unknown,
|
context: unknown,
|
||||||
options: { flowLike?: unknown; taskRoleId?: unknown; taskRoleName?: unknown } = {},
|
options: { flowLike?: unknown; taskRoleId?: unknown; taskRoleName?: unknown } = {},
|
||||||
@@ -261,7 +254,7 @@ export function appendUidToUrl(targetUrl: unknown, uid: unknown): string {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function buildClaimIdentityPayload(value: unknown) {
|
export function buildClaimIdentityPayload(value: unknown): ClaimIdentityPayload {
|
||||||
const identity = normalizeClaimIdentity(value)
|
const identity = normalizeClaimIdentity(value)
|
||||||
return {
|
return {
|
||||||
expectedUid: identity.expectedUid,
|
expectedUid: identity.expectedUid,
|
||||||
|
|||||||
@@ -18,7 +18,103 @@ export function isIndustryEVoucherTask(task: unknown) {
|
|||||||
return String(source.executor_key || '').trim() === 'kuaishou-industry'
|
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 source: JsonObject = value && typeof value === 'object' ? (value as JsonObject) : {}
|
||||||
const binding = asJsonObject(source.binding)
|
const binding = asJsonObject(source.binding)
|
||||||
const role = asJsonObject(source.role)
|
const role = asJsonObject(source.role)
|
||||||
|
|||||||
@@ -14,6 +14,10 @@ export {
|
|||||||
isSameKuaishouCloudRoleIdentity,
|
isSameKuaishouCloudRoleIdentity,
|
||||||
resolveKuaishouCloudBindUrlExpiresAt,
|
resolveKuaishouCloudBindUrlExpiresAt,
|
||||||
} from './domain.js'
|
} from './domain.js'
|
||||||
|
export type {
|
||||||
|
KuaishouCloudDeliveryItem,
|
||||||
|
KuaishouCloudFlow,
|
||||||
|
} from './domain.js'
|
||||||
export { resolvePersistedCloudtentaclesContextBySourceKeys } from './cloudtentacles-context.js'
|
export { resolvePersistedCloudtentaclesContextBySourceKeys } from './cloudtentacles-context.js'
|
||||||
export { ensureTaskClaimLink } from './ensure-claim-link.js'
|
export { ensureTaskClaimLink } from './ensure-claim-link.js'
|
||||||
export {
|
export {
|
||||||
|
|||||||
@@ -41,10 +41,13 @@ export async function probeKuaishouCloudTaskBindUrl(task: TaskRow, options: Json
|
|||||||
|
|
||||||
const probeIntervalMs =
|
const probeIntervalMs =
|
||||||
Number(resolveCloudtentaclesConfig().bindUrlProbeIntervalSeconds || 30) * 1000
|
Number(resolveCloudtentaclesConfig().bindUrlProbeIntervalSeconds || 30) * 1000
|
||||||
|
const lastProbeAt = flow.binding.bindProbeAt
|
||||||
|
? Date.parse(String(flow.binding.bindProbeAt))
|
||||||
|
: NaN
|
||||||
if (
|
if (
|
||||||
!options.force &&
|
!options.force &&
|
||||||
flow.binding.bindProbeAt &&
|
Number.isFinite(lastProbeAt) &&
|
||||||
Date.now() - Date.parse(flow.binding.bindProbeAt) < probeIntervalMs
|
Date.now() - lastProbeAt < probeIntervalMs
|
||||||
) {
|
) {
|
||||||
return {
|
return {
|
||||||
task,
|
task,
|
||||||
|
|||||||
@@ -38,14 +38,13 @@ export async function rebindKuaishouCloudTaskRole(task: TaskRow, options: JsonOb
|
|||||||
}
|
}
|
||||||
|
|
||||||
const normalizedStatus = normalizeTaskStatus(task.task_status)
|
const normalizedStatus = normalizeTaskStatus(task.task_status)
|
||||||
if (
|
const rebindAllowedStatuses = new Set<string>([
|
||||||
![
|
TASK_STATUS.WAITING_BINDING,
|
||||||
TASK_STATUS.WAITING_BINDING,
|
TASK_STATUS.ROLE_CONFIRMED,
|
||||||
TASK_STATUS.ROLE_CONFIRMED,
|
TASK_STATUS.MANUAL_REVIEW,
|
||||||
TASK_STATUS.MANUAL_REVIEW,
|
TASK_STATUS.RETRY_PENDING,
|
||||||
TASK_STATUS.RETRY_PENDING,
|
])
|
||||||
].includes(normalizedStatus as any)
|
if (!rebindAllowedStatuses.has(normalizedStatus)) {
|
||||||
) {
|
|
||||||
throw createHttpError('当前任务状态不可换绑角色', {
|
throw createHttpError('当前任务状态不可换绑角色', {
|
||||||
statusCode: 409,
|
statusCode: 409,
|
||||||
errorCode: 'kuaishou_cloud_rebind_not_allowed',
|
errorCode: 'kuaishou_cloud_rebind_not_allowed',
|
||||||
|
|||||||
@@ -6,9 +6,9 @@ import { getCloudtentaclesBindInfo } from '../../platforms/cloudtentacles/virtua
|
|||||||
import {
|
import {
|
||||||
hasKuaishouCloudDefaultRoleSnapshot,
|
hasKuaishouCloudDefaultRoleSnapshot,
|
||||||
isSameKuaishouCloudRoleIdentity,
|
isSameKuaishouCloudRoleIdentity,
|
||||||
normalizeKuaishouCloudFlow,
|
|
||||||
normalizeKuaishouCloudRoleInfo,
|
normalizeKuaishouCloudRoleInfo,
|
||||||
type JsonObject,
|
type JsonObject,
|
||||||
|
type KuaishouCloudFlow,
|
||||||
} from './domain.js'
|
} from './domain.js'
|
||||||
|
|
||||||
export type KuaishouCloudDefaultRoleSnapshot = {
|
export type KuaishouCloudDefaultRoleSnapshot = {
|
||||||
@@ -79,7 +79,7 @@ export function buildRoleStateFromCurrentInfo({
|
|||||||
now,
|
now,
|
||||||
emptyMessage,
|
emptyMessage,
|
||||||
}: {
|
}: {
|
||||||
flow: ReturnType<typeof normalizeKuaishouCloudFlow>
|
flow: KuaishouCloudFlow
|
||||||
roleInfo: { name: string; rid: string; rawInfo?: unknown }
|
roleInfo: { name: string; rid: string; rawInfo?: unknown }
|
||||||
now: string
|
now: string
|
||||||
emptyMessage: string
|
emptyMessage: string
|
||||||
|
|||||||
@@ -207,7 +207,28 @@ export async function syncKuaishouFeifeiTaskStatus(task: TaskRow) {
|
|||||||
return updatedTask || task
|
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)
|
const source = value && typeof value === 'object' && !Array.isArray(value)
|
||||||
? value as JsonObject
|
? value as JsonObject
|
||||||
: {}
|
: {}
|
||||||
@@ -270,7 +291,7 @@ export function resolveKuaishouFeifeiH5UrlWithTaskUid(
|
|||||||
}
|
}
|
||||||
|
|
||||||
function mergeKuaishouFeifeiOrder(
|
function mergeKuaishouFeifeiOrder(
|
||||||
flow: ReturnType<typeof normalizeKuaishouFeifeiFlow>,
|
flow: KuaishouFeifeiFlow,
|
||||||
order: Awaited<ReturnType<typeof createKuaishouFeifeiOrder>>,
|
order: Awaited<ReturnType<typeof createKuaishouFeifeiOrder>>,
|
||||||
patch: {
|
patch: {
|
||||||
platformOrderNo?: string
|
platformOrderNo?: string
|
||||||
@@ -299,7 +320,7 @@ function mergeKuaishouFeifeiOrder(
|
|||||||
}
|
}
|
||||||
|
|
||||||
function resolveKuaishouFeifeiDirectClaimUrl(
|
function resolveKuaishouFeifeiDirectClaimUrl(
|
||||||
flow: ReturnType<typeof normalizeKuaishouFeifeiFlow>,
|
flow: KuaishouFeifeiFlow,
|
||||||
) {
|
) {
|
||||||
const h5ClaimUrl = flow.h5.rechargeUrl || flow.h5.entryUrl
|
const h5ClaimUrl = flow.h5.rechargeUrl || flow.h5.entryUrl
|
||||||
if (h5ClaimUrl) {
|
if (h5ClaimUrl) {
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import { getFulfillmentProfileByKey } from '../../repositories/fulfillment-profile-repo.js'
|
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 type { OrderItemRow, OrderRow } from '../../types/repository/rows.js'
|
||||||
import {
|
import {
|
||||||
FULFILLMENT_EXECUTOR_KEYS,
|
FULFILLMENT_EXECUTOR_KEYS,
|
||||||
@@ -6,8 +7,6 @@ import {
|
|||||||
isKuaishouFeifeiExecutor,
|
isKuaishouFeifeiExecutor,
|
||||||
} from './executors/types.js'
|
} from './executors/types.js'
|
||||||
|
|
||||||
type JsonObject = Record<string, unknown>
|
|
||||||
|
|
||||||
export type FulfillmentBindingLike = {
|
export type FulfillmentBindingLike = {
|
||||||
id: number
|
id: number
|
||||||
profile_id?: number
|
profile_id?: number
|
||||||
|
|||||||
@@ -7,10 +7,9 @@ import {
|
|||||||
saveAppConfigEntry,
|
saveAppConfigEntry,
|
||||||
} from '../config/app-config-store.js'
|
} from '../config/app-config-store.js'
|
||||||
import { normalizeCloudtentaclesMatchName } from '../order/cloudtentacles-match-utils.js'
|
import { normalizeCloudtentaclesMatchName } from '../order/cloudtentacles-match-utils.js'
|
||||||
|
import type { JsonObject } from '../../types/json.js'
|
||||||
import { FULFILLMENT_EXECUTOR_KEYS } from './executors/types.js'
|
import { FULFILLMENT_EXECUTOR_KEYS } from './executors/types.js'
|
||||||
|
|
||||||
type JsonObject = Record<string, unknown>
|
|
||||||
|
|
||||||
export type FulfillmentRoutingRuleMatchType = 'exact' | 'contains'
|
export type FulfillmentRoutingRuleMatchType = 'exact' | 'contains'
|
||||||
|
|
||||||
export type FulfillmentRoutingExecutorConfig = {
|
export type FulfillmentRoutingExecutorConfig = {
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
|
import type { JsonObject } from '../../types/json.js'
|
||||||
import { createHttpError } from '../../utils/http.js'
|
import { createHttpError } from '../../utils/http.js'
|
||||||
|
|
||||||
const DEFAULT_TIMEOUT_MS = 10000
|
const DEFAULT_TIMEOUT_MS = 10000
|
||||||
|
|
||||||
type JsonObject = Record<string, unknown>
|
|
||||||
type BarkSendInput = {
|
type BarkSendInput = {
|
||||||
serverUrl?: string
|
serverUrl?: string
|
||||||
recipient?: {
|
recipient?: {
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
|
import type { JsonObject } from '../../types/json.js'
|
||||||
import { logWarn } from '../../utils/logger.js'
|
import { logWarn } from '../../utils/logger.js'
|
||||||
import { sendInternalNotification } from './notification-service.js'
|
import { sendInternalNotification } from './notification-service.js'
|
||||||
|
|
||||||
const DEFAULT_COOLDOWN_MS = 10 * 60 * 1000
|
const DEFAULT_COOLDOWN_MS = 10 * 60 * 1000
|
||||||
const notificationCooldownMap = new Map<string, number>()
|
const notificationCooldownMap = new Map<string, number>()
|
||||||
|
|
||||||
type JsonObject = Record<string, unknown>
|
|
||||||
type InternalNotificationPayload = {
|
type InternalNotificationPayload = {
|
||||||
title: string
|
title: string
|
||||||
body?: string
|
body?: string
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import http from 'node:http'
|
import http from 'node:http'
|
||||||
import https from 'node:https'
|
import https from 'node:https'
|
||||||
|
|
||||||
|
import type { JsonObject } from '../../types/json.js'
|
||||||
import { createHttpError } from '../../utils/http.js'
|
import { createHttpError } from '../../utils/http.js'
|
||||||
|
|
||||||
const DEFAULT_WPUSH_ENDPOINT = 'https://api.wpush.cn/api/v1/send'
|
const DEFAULT_WPUSH_ENDPOINT = 'https://api.wpush.cn/api/v1/send'
|
||||||
const DEFAULT_TIMEOUT_MS = 10000
|
const DEFAULT_TIMEOUT_MS = 10000
|
||||||
|
|
||||||
type JsonObject = Record<string, unknown>
|
|
||||||
type NodeHttpResponse = {
|
type NodeHttpResponse = {
|
||||||
ok: boolean
|
ok: boolean
|
||||||
status: number
|
status: number
|
||||||
|
|||||||
@@ -1,20 +1,11 @@
|
|||||||
|
import type { ClaimIdentityAdminSummary } from '../claim-identity.js'
|
||||||
import type { JsonObject } from '../json.js'
|
import type { JsonObject } from '../json.js'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 后台任务详情 API 返回形状(与前端 AdminTaskDetail 对齐的后端契约)。
|
* 后台任务详情 API 返回形状(与前端 AdminTaskDetail 对齐的后端契约)。
|
||||||
* 深层履约字段仍用 JsonObject,避免一次改完所有 mapper。
|
* 深层履约字段仍用 JsonObject,避免一次改完所有 mapper。
|
||||||
*/
|
*/
|
||||||
export type AdminClaimIdentitySummary = {
|
export type AdminClaimIdentitySummary = ClaimIdentityAdminSummary
|
||||||
expectedUid: string
|
|
||||||
submittedAt: string | null
|
|
||||||
source: string
|
|
||||||
ready: boolean
|
|
||||||
boundUid: string
|
|
||||||
boundRoleName: string
|
|
||||||
uidMatched: boolean | null
|
|
||||||
compatibilityMode: 'uid' | 'legacy_no_uid'
|
|
||||||
note: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export type AdminTaskDetailView = {
|
export type AdminTaskDetailView = {
|
||||||
task: JsonObject
|
task: JsonObject
|
||||||
|
|||||||
@@ -0,0 +1,32 @@
|
|||||||
|
/**
|
||||||
|
* 领取页 UID 身份与后台摘要的共享类型(纯数据契约,无运行时依赖)。
|
||||||
|
*/
|
||||||
|
|
||||||
|
export type ClaimIdentity = {
|
||||||
|
expectedUid: string
|
||||||
|
submittedAt: string | null
|
||||||
|
source: string
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 领取页 / claim API 返回的 UID 身份(含 ready) */
|
||||||
|
export type ClaimIdentityPayload = ClaimIdentity & {
|
||||||
|
ready: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 后台任务详情中的 UID 兼容摘要 */
|
||||||
|
export type ClaimIdentityAdminSummary = ClaimIdentityPayload & {
|
||||||
|
boundUid: string
|
||||||
|
boundRoleName: string
|
||||||
|
uidMatched: boolean | null
|
||||||
|
compatibilityMode: 'uid' | 'legacy_no_uid'
|
||||||
|
note: string
|
||||||
|
}
|
||||||
|
|
||||||
|
/** context_json 中 claimIdentity 的宽松写入形态(兼容历史 uid 字段) */
|
||||||
|
export type ClaimIdentityContext = {
|
||||||
|
expectedUid?: string
|
||||||
|
submittedAt?: string | null
|
||||||
|
source?: string
|
||||||
|
/** @deprecated 历史字段,normalize 时映射到 expectedUid */
|
||||||
|
uid?: string
|
||||||
|
}
|
||||||
@@ -1,18 +1,16 @@
|
|||||||
|
import type { ClaimIdentityContext } from './claim-identity.js'
|
||||||
import type { JsonObject } from './json.js'
|
import type { JsonObject } from './json.js'
|
||||||
|
|
||||||
|
export type { ClaimIdentityContext }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 履约任务 context_json 的已知字段。
|
* 履约任务 context_json 的已知字段。
|
||||||
* 未建模扩展仍可通过索引访问(JsonObject)。
|
* 未建模扩展仍可通过索引访问(JsonObject)。
|
||||||
|
* kuaishouCloudFulfillment / kuaishouFeifei 在 normalize 出口有具名类型;
|
||||||
|
* 此处保留 JsonObject 以兼容未 normalize 的原始落库形态。
|
||||||
*/
|
*/
|
||||||
export type ClaimIdentityContext = {
|
|
||||||
expectedUid?: string
|
|
||||||
submittedAt?: string | null
|
|
||||||
source?: string
|
|
||||||
uid?: string
|
|
||||||
}
|
|
||||||
|
|
||||||
export type TaskContext = JsonObject & {
|
export type TaskContext = JsonObject & {
|
||||||
claimIdentity?: ClaimIdentityContext | JsonObject
|
claimIdentity?: ClaimIdentityContext
|
||||||
kuaishouCloudFulfillment?: JsonObject
|
kuaishouCloudFulfillment?: JsonObject
|
||||||
kuaishouFeifei?: JsonObject
|
kuaishouFeifei?: JsonObject
|
||||||
kuaishouIndustryVoucher?: JsonObject
|
kuaishouIndustryVoucher?: JsonObject
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
|
import type { JsonObject } from '../types/json.js'
|
||||||
import { createHttpError } from './http.js'
|
import { createHttpError } from './http.js'
|
||||||
|
|
||||||
const LARGE_INTEGER_PATTERN = /(:\s*)(-?\d{16,})(\s*[,}\]])/g
|
const LARGE_INTEGER_PATTERN = /(:\s*)(-?\d{16,})(\s*[,}\]])/g
|
||||||
|
|
||||||
type JsonObject = Record<string, unknown>
|
|
||||||
|
|
||||||
type ParseJsonObjectOptions = {
|
type ParseJsonObjectOptions = {
|
||||||
preserveLargeIntegers?: boolean
|
preserveLargeIntegers?: boolean
|
||||||
throwOnError?: boolean
|
throwOnError?: boolean
|
||||||
|
|||||||
@@ -58,6 +58,19 @@ export interface AdminTaskActionResponse {
|
|||||||
token?: string
|
token?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** 与后端 ClaimIdentityAdminSummary / AdminClaimIdentitySummary 对齐 */
|
||||||
|
export interface AdminClaimIdentitySummary {
|
||||||
|
expectedUid: string
|
||||||
|
submittedAt: string | null
|
||||||
|
source: string
|
||||||
|
ready: boolean
|
||||||
|
boundUid: string
|
||||||
|
boundRoleName: string
|
||||||
|
uidMatched: boolean | null
|
||||||
|
compatibilityMode: 'uid' | 'legacy_no_uid'
|
||||||
|
note: string
|
||||||
|
}
|
||||||
|
|
||||||
export interface AdminTaskDetail {
|
export interface AdminTaskDetail {
|
||||||
task: AdminTaskListItem
|
task: AdminTaskListItem
|
||||||
order: null | {
|
order: null | {
|
||||||
@@ -105,17 +118,7 @@ export interface AdminTaskDetail {
|
|||||||
resultMessage: string
|
resultMessage: string
|
||||||
}>
|
}>
|
||||||
}
|
}
|
||||||
claimIdentity: null | {
|
claimIdentity: AdminClaimIdentitySummary | null
|
||||||
expectedUid: string
|
|
||||||
submittedAt: string | null
|
|
||||||
source: string
|
|
||||||
ready: boolean
|
|
||||||
boundUid: string
|
|
||||||
boundRoleName: string
|
|
||||||
uidMatched: boolean | null
|
|
||||||
compatibilityMode: 'uid' | 'legacy_no_uid'
|
|
||||||
note: string
|
|
||||||
}
|
|
||||||
kuaishouCloudFulfillment: null | {
|
kuaishouCloudFulfillment: null | {
|
||||||
flowType: string
|
flowType: string
|
||||||
configId: string
|
configId: string
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ export type ClaimTokenStatus = 'active' | 'used' | 'expired' | 'revoked' | (stri
|
|||||||
|
|
||||||
export type ClaimTaskStatus = KnownTaskStatus | (string & {})
|
export type ClaimTaskStatus = KnownTaskStatus | (string & {})
|
||||||
|
|
||||||
|
/** 与后端 ClaimIdentityPayload 对齐 */
|
||||||
export interface ClaimIdentityInfo {
|
export interface ClaimIdentityInfo {
|
||||||
expectedUid: string
|
expectedUid: string
|
||||||
submittedAt: string | null
|
submittedAt: string | null
|
||||||
|
|||||||
@@ -7,10 +7,13 @@
|
|||||||
- `JsonObject`:中心定义(当前值仍为 any 以兼容深层 context 访问)
|
- `JsonObject`:中心定义(当前值仍为 any 以兼容深层 context 访问)
|
||||||
- `StrictJson` / `StrictJsonObject`:新代码可用的 unknown 严格形态
|
- `StrictJson` / `StrictJsonObject`:新代码可用的 unknown 严格形态
|
||||||
- `asJsonObject` / `isPlainObject` 工具
|
- `asJsonObject` / `isPlainObject` 工具
|
||||||
3. **去掉约 60 处本地** `type JsonObject = Record<string, any>`
|
3. **去掉生产路径本地** `type JsonObject = …`(统一从 `types/json` 导入;scripts 可保留本地别名)
|
||||||
4. **TaskContext**:`types/task-context.ts`,`parseTaskContext` 返回 `TaskContext`
|
4. **TaskContext**:`types/task-context.ts`,`parseTaskContext` 返回 `TaskContext`
|
||||||
5. **Admin 任务详情契约**:`types/admin/task-detail.ts`,`getAdminTaskDetail(): Promise<AdminTaskDetailView>`
|
5. **ClaimIdentity 契约**:`types/claim-identity.ts`(`ClaimIdentity` / `ClaimIdentityPayload` / `ClaimIdentityAdminSummary`)
|
||||||
6. **测试 fixture**:`delivery-task-service.test.ts` 减少 `as any`
|
6. **Admin 任务详情契约**:`types/admin/task-detail.ts`,`getAdminTaskDetail(): Promise<AdminTaskDetailView>`
|
||||||
|
7. **normalize 出口具名类型**:`KuaishouCloudFlow`、`KuaishouFeifeiFlow`
|
||||||
|
8. **前后端 claimIdentity 字段对齐**:前端 `ClaimIdentityInfo` / `AdminClaimIdentitySummary`
|
||||||
|
9. **测试 fixture**:`delivery-task-service.test.ts` 减少 `as any`;生产路径去掉 `as any` 状态列表
|
||||||
|
|
||||||
## 未做完(后续)
|
## 未做完(后续)
|
||||||
|
|
||||||
@@ -18,6 +21,7 @@
|
|||||||
- 前后端共享类型包 / OpenAPI
|
- 前后端共享类型包 / OpenAPI
|
||||||
- 前端对齐 `noUncheckedIndexedAccess`
|
- 前端对齐 `noUncheckedIndexedAccess`
|
||||||
- 全量测试 fixture 工厂化
|
- 全量测试 fixture 工厂化
|
||||||
|
- scripts 本地 JsonObject 别名可按需迁入中心类型
|
||||||
|
|
||||||
## 约定
|
## 约定
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user