偿还 lewan 工程债:模块拆分、默认角色降级与短链收口

将 kuaishou-cloud 大入口拆为 prepare/rebind/probe/refresh 等模块;默认角色仅作诊断;补充兑换状态单测;短链明确只读兼容历史链接。
This commit is contained in:
yml2213
2026-07-10 14:01:29 +08:00
parent c70c3ff6a5
commit d6b0e45c7b
15 changed files with 1508 additions and 1190 deletions
@@ -0,0 +1,97 @@
import assert from 'node:assert/strict'
import test from 'node:test'
import {
TASK_STATUS,
canRedeemKuaishouCloudClaimStatus,
canTaskTransition,
normalizeTaskStatus,
} from '../../domain/task-status.js'
import {
assertBoundUidMatchesExpected,
assertClaimExpectedUidReady,
isClaimUidMatched,
} from './claim-identity.js'
/**
* 一键兑换前置:waiting_binding + UID 匹配 → 可升到 role_confirmed → redeeming
*/
function canPromoteWaitingBindingToRedeem(options: {
status: unknown
expectedUid: string
boundUid: string
}) {
const status = normalizeTaskStatus(options.status)
if (!canRedeemKuaishouCloudClaimStatus(status)) {
return { ok: false, reason: 'status_not_redeemable' as const }
}
if (!options.expectedUid) {
return { ok: false, reason: 'uid_missing' as const }
}
if (!isClaimUidMatched(options.expectedUid, options.boundUid)) {
return { ok: false, reason: 'uid_mismatch' as const }
}
if (status === TASK_STATUS.WAITING_BINDING) {
if (!canTaskTransition(TASK_STATUS.WAITING_BINDING, TASK_STATUS.ROLE_CONFIRMED)) {
return { ok: false, reason: 'cannot_promote' as const }
}
}
if (!canTaskTransition(TASK_STATUS.ROLE_CONFIRMED, TASK_STATUS.REDEEMING)) {
return { ok: false, reason: 'cannot_redeem' as const }
}
return { ok: true as const, reason: 'ok' as const }
}
test('waiting_binding + uid 匹配可一键兑换', () => {
const result = canPromoteWaitingBindingToRedeem({
status: TASK_STATUS.WAITING_BINDING,
expectedUid: '10001',
boundUid: '10001',
})
assert.deepEqual(result, { ok: true, reason: 'ok' })
})
test('waiting_binding + uid 不一致不可兑换', () => {
const result = canPromoteWaitingBindingToRedeem({
status: TASK_STATUS.WAITING_BINDING,
expectedUid: '10001',
boundUid: '99999',
})
assert.equal(result.ok, false)
assert.equal(result.reason, 'uid_mismatch')
})
test('link_generated 状态不可直接 redeem', () => {
const result = canPromoteWaitingBindingToRedeem({
status: TASK_STATUS.LINK_GENERATED,
expectedUid: '10001',
boundUid: '10001',
})
assert.equal(result.ok, false)
assert.equal(result.reason, 'status_not_redeemable')
})
test('assertBoundUidMatchesExpected 在不匹配时抛错', () => {
assert.throws(
() =>
assertBoundUidMatchesExpected(
{
context_json: JSON.stringify({
claimIdentity: { expectedUid: '10001' },
}),
},
{
binding: { roleId: '999', roleName: 'x', vnPhone: '1' },
role: { rid: '999', name: 'x' },
},
),
/不一致/,
)
})
test('assertClaimExpectedUidReady 要求 claimIdentity', () => {
assert.throws(
() => assertClaimExpectedUidReady({ context_json: '{}' }),
/填写游戏 UID/,
)
})
@@ -36,7 +36,8 @@ export async function syncKuaishouCloudRoleInfo(task: TaskRow) {
source: 'claim_page_polling',
actor: { source: 'system' },
recordEvent: false,
forceProbe: flow.role.isDefaultRole === true,
// 轮询阶段始终允许探测绑链,默认角色仅作诊断
forceProbe: true,
})
return result.task || task
} catch {