@xiashe/sdk 0.1.17 → 0.1.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/alipayWallet.mjs +265 -5
- package/index.mjs +1 -1
- package/package.json +1 -1
package/alipayWallet.mjs
CHANGED
|
@@ -12,6 +12,110 @@ const SENSITIVE_USER_OUTPUT = /payment[-_ ]?proof|payment[-_ ]?needed|seller_sig
|
|
|
12
12
|
const DEFAULT_STATE_DIR = path.join(os.homedir(), '.xiashe', 'alipay-402');
|
|
13
13
|
const OFFICIAL_MEDIA_EXTENSIONS = new Set(['.png', '.jpg', '.jpeg', '.webp']);
|
|
14
14
|
const MAX_OFFICIAL_MEDIA_BYTES = 8 * 1024 * 1024;
|
|
15
|
+
const SAFE_OFFICIAL_FAILURE_CODES = new Set([
|
|
16
|
+
'TRADE_PROGRESS_FAILED',
|
|
17
|
+
'PAYMENT_NEEDED_REJECTED',
|
|
18
|
+
'SYSTEM_ERROR',
|
|
19
|
+
'BUYER_IDENTITY_REJECTED',
|
|
20
|
+
'WALLET_NOT_READY',
|
|
21
|
+
// AI收 payment.verify business errors. These can be returned after the
|
|
22
|
+
// wallet has paid and retries the protected resource with Payment-Proof.
|
|
23
|
+
'INVALID_PARAMETER',
|
|
24
|
+
'CLIENT_SESSION_IS_EMPTY',
|
|
25
|
+
'PAYMENT_PROOF_AGENT_MISMATCH',
|
|
26
|
+
'PAYMENT_PROOF_BUYER_MISMATCH',
|
|
27
|
+
'PAYMENT_PROOF_EMPTY',
|
|
28
|
+
'PAYMENT_PROOF_ID_MISMATCH',
|
|
29
|
+
'PAYMENT_PROOF_INVALID',
|
|
30
|
+
'PAYMENT_PROOF_NOT_FOUND',
|
|
31
|
+
'PAYMENT_PROOF_STATUS_INVALID',
|
|
32
|
+
'PAYMENT_PROOF_TRADE_NO_MISMATCH',
|
|
33
|
+
'TRADE_NOT_FOUND',
|
|
34
|
+
'TRADE_NO_EMPTY',
|
|
35
|
+
'TRADE_NO_INVALID',
|
|
36
|
+
'TRADE_STATUS_CLOSED',
|
|
37
|
+
'TRADE_STATUS_UNPAID',
|
|
38
|
+
// AI收 fulfillment.confirm business errors. These do not revoke a
|
|
39
|
+
// delivered entitlement, but do need an operator-visible diagnosis.
|
|
40
|
+
'SELLER_IDENTITY_MISMATCH',
|
|
41
|
+
'SELLER_ID_EMPTY',
|
|
42
|
+
'TRADE_STATUS_INVALID'
|
|
43
|
+
]);
|
|
44
|
+
|
|
45
|
+
const OFFICIAL_ERROR_DIAGNOSES = {
|
|
46
|
+
PAYMENT_NEEDED_REJECTED: {
|
|
47
|
+
stage: 'alipay_bill_validation',
|
|
48
|
+
nextStep: '核对支付宝平台中该 APPID 的应用公钥、service_id、收款方 2088 seller_id 和线上接入状态;修复后必须创建新订单再测试。'
|
|
49
|
+
},
|
|
50
|
+
CLIENT_SESSION_IS_EMPTY: {
|
|
51
|
+
stage: 'merchant_payment_proof_verification',
|
|
52
|
+
nextStep: '买方 CLI 未传回有效 client_session;升级官方支付宝支付组件后,用新订单重新发起付款。'
|
|
53
|
+
},
|
|
54
|
+
PAYMENT_PROOF_AGENT_MISMATCH: {
|
|
55
|
+
stage: 'merchant_payment_proof_verification',
|
|
56
|
+
nextStep: '支付凭证与当前 Agent 商户身份不一致;确认付款与重试使用同一官方钱包运行时后,以新订单重试。'
|
|
57
|
+
},
|
|
58
|
+
PAYMENT_PROOF_BUYER_MISMATCH: {
|
|
59
|
+
stage: 'merchant_payment_proof_verification',
|
|
60
|
+
nextStep: '支付买家与凭证买家不一致;不要复用凭证,请在同一支付宝买家身份下重新发起付款。'
|
|
61
|
+
},
|
|
62
|
+
PAYMENT_PROOF_ID_MISMATCH: {
|
|
63
|
+
stage: 'merchant_payment_proof_verification',
|
|
64
|
+
nextStep: 'Payment-Proof 中的卖家身份与本 Skill 配置不一致;核对 APPID、2088 seller_id 和 service_id。'
|
|
65
|
+
},
|
|
66
|
+
PAYMENT_PROOF_EMPTY: {
|
|
67
|
+
stage: 'merchant_payment_proof_verification',
|
|
68
|
+
nextStep: '官方钱包没有返回支付凭证;请停止,不要手工补造凭证,并用受支持运行时重新发起。'
|
|
69
|
+
},
|
|
70
|
+
PAYMENT_PROOF_INVALID: {
|
|
71
|
+
stage: 'merchant_payment_proof_verification',
|
|
72
|
+
nextStep: '支付宝返回的支付凭证格式无效;请使用最新官方买方组件,并创建新订单重试。'
|
|
73
|
+
},
|
|
74
|
+
PAYMENT_PROOF_NOT_FOUND: {
|
|
75
|
+
stage: 'merchant_payment_proof_verification',
|
|
76
|
+
nextStep: '支付凭证不存在或已过期;不要重复提交旧凭证,创建新订单后重新付款。'
|
|
77
|
+
},
|
|
78
|
+
PAYMENT_PROOF_STATUS_INVALID: {
|
|
79
|
+
stage: 'merchant_payment_proof_verification',
|
|
80
|
+
nextStep: '支付凭证已失效或已被使用;请创建新订单重新付款。'
|
|
81
|
+
},
|
|
82
|
+
PAYMENT_PROOF_TRADE_NO_MISMATCH: {
|
|
83
|
+
stage: 'merchant_payment_proof_verification',
|
|
84
|
+
nextStep: '支付凭证与交易号不匹配;不要重放该凭证,创建新订单后重新付款。'
|
|
85
|
+
},
|
|
86
|
+
TRADE_NOT_FOUND: {
|
|
87
|
+
stage: 'merchant_payment_proof_verification',
|
|
88
|
+
nextStep: '支付宝找不到该交易;先查询官方钱包本地状态,未创建交易时用新订单重新发起。'
|
|
89
|
+
},
|
|
90
|
+
TRADE_NO_EMPTY: {
|
|
91
|
+
stage: 'merchant_payment_proof_verification',
|
|
92
|
+
nextStep: '官方钱包未返回交易号;当前交易不可继续,请创建新订单重新发起。'
|
|
93
|
+
},
|
|
94
|
+
TRADE_NO_INVALID: {
|
|
95
|
+
stage: 'merchant_payment_proof_verification',
|
|
96
|
+
nextStep: '官方钱包返回的交易号格式无效;升级官方买方组件后以新订单重试。'
|
|
97
|
+
},
|
|
98
|
+
TRADE_STATUS_CLOSED: {
|
|
99
|
+
stage: 'merchant_payment_proof_verification',
|
|
100
|
+
nextStep: '该交易已关闭;不要重试旧订单,请创建新订单重新付款。'
|
|
101
|
+
},
|
|
102
|
+
TRADE_STATUS_UNPAID: {
|
|
103
|
+
stage: 'merchant_payment_proof_verification',
|
|
104
|
+
nextStep: '交易尚未完成付款;如本地有查询凭证则运行 status,否则创建新订单重新发起。'
|
|
105
|
+
},
|
|
106
|
+
SELLER_IDENTITY_MISMATCH: {
|
|
107
|
+
stage: 'merchant_fulfillment_confirmation',
|
|
108
|
+
nextStep: '已交付的 Skill 权益不会撤销;运营方应核对卖家 APPID、2088 seller_id 与交易卖方身份。'
|
|
109
|
+
},
|
|
110
|
+
SELLER_ID_EMPTY: {
|
|
111
|
+
stage: 'merchant_fulfillment_confirmation',
|
|
112
|
+
nextStep: '已交付的 Skill 权益不会撤销;运营方应检查商户应用签名与卖家身份配置。'
|
|
113
|
+
},
|
|
114
|
+
TRADE_STATUS_INVALID: {
|
|
115
|
+
stage: 'merchant_fulfillment_confirmation',
|
|
116
|
+
nextStep: '已交付的 Skill 权益不会撤销;运营方应查询支付宝交易状态后处理履约回执。'
|
|
117
|
+
}
|
|
118
|
+
};
|
|
15
119
|
|
|
16
120
|
export class AlipayWalletError extends Error {
|
|
17
121
|
constructor(code, message, options = {}) {
|
|
@@ -230,6 +334,113 @@ function walletFailureCode(stdout, stderr, exitCode) {
|
|
|
230
334
|
return Number.isInteger(exitCode) && exitCode !== 0 ? 'official_cli_nonzero_exit' : 'official_cli_unclassified';
|
|
231
335
|
}
|
|
232
336
|
|
|
337
|
+
/**
|
|
338
|
+
* The official wallet can return useful machine error codes alongside protocol
|
|
339
|
+
* material. Expose only a small allow-list: arbitrary vendor output can carry
|
|
340
|
+
* credentials, URLs, trade identifiers, or PayGuard internals.
|
|
341
|
+
*/
|
|
342
|
+
function safeOfficialFailureCode(stdout, stderr) {
|
|
343
|
+
const output = `${stdout}\n${stderr}`;
|
|
344
|
+
const candidates = [
|
|
345
|
+
...output.matchAll(/(?:"(?:errorCode|code|sub_code|previous_error)"|\b(?:errorCode|code|sub_code|previous_error)\b)\s*[:=]\s*["']?([A-Z][A-Z0-9_]{2,80})/ig)
|
|
346
|
+
].map((match) => match[1].toUpperCase());
|
|
347
|
+
return candidates.find((candidate) => SAFE_OFFICIAL_FAILURE_CODES.has(candidate)) || null;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
/** Codes generated by XiaShe from the signed merchant verification response. */
|
|
351
|
+
function safeMerchantDiagnosticCode(stdout, stderr) {
|
|
352
|
+
const output = `${stdout}\n${stderr}`;
|
|
353
|
+
const candidates = [...output.matchAll(/\b(ALIPAY_(?:VERIFY|FULFILLMENT)_[A-Z0-9_]{2,180})\b/g)]
|
|
354
|
+
.map((match) => match[1]);
|
|
355
|
+
return candidates.find((candidate) =>
|
|
356
|
+
/^ALIPAY_(?:VERIFY|FULFILLMENT)_(?:PAYMENT_PROOF_INACTIVE|(?:SYSTEM_ERROR|INVALID_PARAMETER|CLIENT_SESSION_IS_EMPTY|PAYMENT_PROOF_AGENT_MISMATCH|PAYMENT_PROOF_BUYER_MISMATCH|PAYMENT_PROOF_EMPTY|PAYMENT_PROOF_ID_MISMATCH|PAYMENT_PROOF_INVALID|PAYMENT_PROOF_NOT_FOUND|PAYMENT_PROOF_STATUS_INVALID|PAYMENT_PROOF_TRADE_NO_MISMATCH|SELLER_IDENTITY_MISMATCH|SELLER_ID_EMPTY|TRADE_NOT_FOUND|TRADE_NO_EMPTY|TRADE_NO_INVALID|TRADE_STATUS_CLOSED|TRADE_STATUS_UNPAID|TRADE_STATUS_INVALID)|GATEWAY_(?:20000|20001|40001|40002|40003|40004|40005|40006)(?:_[A-Z0-9_]{2,100})?)$/.test(candidate)
|
|
357
|
+
) || null;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
function paymentFailureDiagnosis(failureCode, stdout, stderr) {
|
|
361
|
+
const officialCode = safeOfficialFailureCode(stdout, stderr);
|
|
362
|
+
const merchantDiagnostic = safeMerchantDiagnosticCode(stdout, stderr);
|
|
363
|
+
const base = {
|
|
364
|
+
code: failureCode,
|
|
365
|
+
stage: 'official_wallet_trade_creation',
|
|
366
|
+
nextStep: '不要重复付款;保留诊断代码和本次 attemptId 以便定位。'
|
|
367
|
+
};
|
|
368
|
+
if (officialCode && OFFICIAL_ERROR_DIAGNOSES[officialCode]) {
|
|
369
|
+
return {
|
|
370
|
+
...base,
|
|
371
|
+
...OFFICIAL_ERROR_DIAGNOSES[officialCode],
|
|
372
|
+
officialCode
|
|
373
|
+
};
|
|
374
|
+
}
|
|
375
|
+
if (merchantDiagnostic) {
|
|
376
|
+
const fulfillment = merchantDiagnostic.startsWith('ALIPAY_FULFILLMENT_');
|
|
377
|
+
return {
|
|
378
|
+
...base,
|
|
379
|
+
stage: fulfillment ? 'merchant_fulfillment_confirmation' : 'merchant_payment_proof_verification',
|
|
380
|
+
merchantDiagnostic,
|
|
381
|
+
nextStep: fulfillment
|
|
382
|
+
? 'Skill 权益已交付;运营方应按商家验证诊断处理履约回执,买家无需重复付款。'
|
|
383
|
+
: '商家已返回支付宝验凭证诊断;不要手工补造凭证,按诊断修复后创建新订单重新付款。'
|
|
384
|
+
};
|
|
385
|
+
}
|
|
386
|
+
if (failureCode === 'payment_needed_rejected') {
|
|
387
|
+
return {
|
|
388
|
+
...base,
|
|
389
|
+
stage: 'alipay_bill_validation',
|
|
390
|
+
nextStep: '核对支付宝平台中该 APPID 的应用公钥、service_id、收款方 2088 seller_id 和线上接入状态;修复后必须创建新订单再测试。',
|
|
391
|
+
...(officialCode ? { officialCode } : {})
|
|
392
|
+
};
|
|
393
|
+
}
|
|
394
|
+
if (failureCode === 'wallet_runtime_not_supported') {
|
|
395
|
+
return {
|
|
396
|
+
...base,
|
|
397
|
+
stage: 'agent_runtime_identity',
|
|
398
|
+
nextStep: '当前运行时没有通过支付宝 Agent 身份校验;请换用已被官方钱包识别并已授权的本地 Agent 运行时。',
|
|
399
|
+
...(officialCode ? { officialCode } : {})
|
|
400
|
+
};
|
|
401
|
+
}
|
|
402
|
+
if (failureCode === 'buyer_identity_rejected') {
|
|
403
|
+
return {
|
|
404
|
+
...base,
|
|
405
|
+
stage: 'buyer_identity_validation',
|
|
406
|
+
nextStep: '支付宝钱包的买家身份未通过校验;完成钱包授权后,用同一受支持运行时创建新订单。',
|
|
407
|
+
...(officialCode ? { officialCode } : {})
|
|
408
|
+
};
|
|
409
|
+
}
|
|
410
|
+
if (failureCode === 'wallet_not_ready') {
|
|
411
|
+
return {
|
|
412
|
+
...base,
|
|
413
|
+
stage: 'wallet_authorization',
|
|
414
|
+
nextStep: '支付宝钱包未完成授权或未启用;先完成官方钱包授权,再创建新订单。',
|
|
415
|
+
...(officialCode ? { officialCode } : {})
|
|
416
|
+
};
|
|
417
|
+
}
|
|
418
|
+
if (failureCode === 'wallet_network_error') {
|
|
419
|
+
return {
|
|
420
|
+
...base,
|
|
421
|
+
stage: 'wallet_network',
|
|
422
|
+
nextStep: '钱包或网络请求没有完成;先检查网络,再创建新订单。',
|
|
423
|
+
...(officialCode ? { officialCode } : {})
|
|
424
|
+
};
|
|
425
|
+
}
|
|
426
|
+
return {
|
|
427
|
+
...base,
|
|
428
|
+
...(officialCode ? { officialCode } : {})
|
|
429
|
+
};
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
function paymentFailureUserVisible(diagnosis) {
|
|
433
|
+
const lines = [
|
|
434
|
+
'支付宝付款未创建可确认交易。',
|
|
435
|
+
`诊断代码:${diagnosis.code}`,
|
|
436
|
+
`失败阶段:${diagnosis.stage}`,
|
|
437
|
+
...(diagnosis.officialCode ? [`官方返回代码:${diagnosis.officialCode}`] : []),
|
|
438
|
+
...(diagnosis.merchantDiagnostic ? [`商家验证诊断:${diagnosis.merchantDiagnostic}`] : []),
|
|
439
|
+
`下一步:${diagnosis.nextStep}`
|
|
440
|
+
];
|
|
441
|
+
return lines.join('\n');
|
|
442
|
+
}
|
|
443
|
+
|
|
233
444
|
function paymentMessage(status) {
|
|
234
445
|
if (status === 'completed') return '支付宝钱包显示本次付款已完成;正在由服务端确认权益。';
|
|
235
446
|
if (status === 'pending_confirmation') return '支付宝已发起本次付款确认;请打开支付宝 App 完成确认,然后运行 status。';
|
|
@@ -285,6 +496,7 @@ function publicPaymentResult(state, status, diagnostic, options = {}) {
|
|
|
285
496
|
const commandFailed = options.commandFailed === true;
|
|
286
497
|
const failureCode = options.failureCode || 'official_cli_nonzero_exit';
|
|
287
498
|
const failed = status === 'failed' || status === 'wallet_command_failed';
|
|
499
|
+
const diagnosis = failed ? options.diagnosis : null;
|
|
288
500
|
return {
|
|
289
501
|
ok: !failed,
|
|
290
502
|
status,
|
|
@@ -293,7 +505,8 @@ function publicPaymentResult(state, status, diagnostic, options = {}) {
|
|
|
293
505
|
walletInvoked: true,
|
|
294
506
|
message: failed ? paymentFailureMessage(failureCode) : paymentMessage(status),
|
|
295
507
|
diagnostic,
|
|
296
|
-
...(
|
|
508
|
+
...(failed && diagnosis ? { userVisible: paymentFailureUserVisible(diagnosis), diagnosis } : {}),
|
|
509
|
+
...(!failed && options.userVisible ? { userVisible: options.userVisible } : {}),
|
|
297
510
|
...(options.officialMedia ? { officialMedia: options.officialMedia } : {}),
|
|
298
511
|
...(status === 'pending_confirmation'
|
|
299
512
|
? { confirmation: { source: 'official_alipay_wallet', surface: 'app_or_official_media', required: true } }
|
|
@@ -383,18 +596,25 @@ export async function payAlipay402Resource(input, options = {}) {
|
|
|
383
596
|
const result = paymentStatusFromOutput(walletInvocation.stdout, walletInvocation.stderr);
|
|
384
597
|
const commandFailed = walletInvocation.exitCode !== 0 && result.status === 'unknown';
|
|
385
598
|
const status = commandFailed ? 'wallet_command_failed' : result.status;
|
|
599
|
+
const failed = commandFailed || status === 'failed';
|
|
386
600
|
const officialMedia = ['pending_confirmation', 'completed'].includes(status)
|
|
387
601
|
? await officialWalletMedia(walletInvocation.stdout, walletInvocation.stderr)
|
|
388
602
|
: null;
|
|
389
603
|
state.status = status;
|
|
390
604
|
state.queryCredential = result.credential;
|
|
605
|
+
state.lastFailureCode = failed ? walletFailureCode(walletInvocation.stdout, walletInvocation.stderr, walletInvocation.exitCode) : null;
|
|
606
|
+
state.lastDiagnosis = failed
|
|
607
|
+
? paymentFailureDiagnosis(state.lastFailureCode, walletInvocation.stdout, walletInvocation.stderr)
|
|
608
|
+
: null;
|
|
609
|
+
state.lastWalletDiagnostic = result.diagnostic;
|
|
391
610
|
state.updatedAt = new Date().toISOString();
|
|
392
611
|
await writePaymentState(state, options);
|
|
393
612
|
if (status === 'completed') await rm(paths.paymentNeededPath, { force: true });
|
|
394
|
-
const
|
|
613
|
+
const failureCode = failed ? state.lastFailureCode : undefined;
|
|
395
614
|
return publicPaymentResult(state, status, result.diagnostic, {
|
|
396
615
|
commandFailed: failed,
|
|
397
|
-
failureCode
|
|
616
|
+
failureCode,
|
|
617
|
+
diagnosis: failed ? paymentFailureDiagnosis(failureCode, walletInvocation.stdout, walletInvocation.stderr) : undefined,
|
|
398
618
|
userVisible: ['pending_confirmation', 'completed'].includes(status)
|
|
399
619
|
? userVisibleWalletOutput(walletInvocation.stdout, walletInvocation.stderr)
|
|
400
620
|
: null,
|
|
@@ -428,24 +648,64 @@ export async function queryAlipay402Resource(input, options = {}) {
|
|
|
428
648
|
const result = paymentStatusFromOutput(walletInvocation.stdout, walletInvocation.stderr);
|
|
429
649
|
const commandFailed = walletInvocation.exitCode !== 0 && result.status === 'unknown';
|
|
430
650
|
const status = commandFailed ? 'wallet_command_failed' : result.status;
|
|
651
|
+
const failed = commandFailed || status === 'failed';
|
|
431
652
|
const officialMedia = ['pending_confirmation', 'completed'].includes(status)
|
|
432
653
|
? await officialWalletMedia(walletInvocation.stdout, walletInvocation.stderr)
|
|
433
654
|
: null;
|
|
434
655
|
state.status = status;
|
|
435
656
|
state.queryCredential = result.credential || state.queryCredential;
|
|
657
|
+
state.lastFailureCode = failed ? walletFailureCode(walletInvocation.stdout, walletInvocation.stderr, walletInvocation.exitCode) : null;
|
|
658
|
+
state.lastDiagnosis = failed
|
|
659
|
+
? paymentFailureDiagnosis(state.lastFailureCode, walletInvocation.stdout, walletInvocation.stderr)
|
|
660
|
+
: null;
|
|
661
|
+
state.lastWalletDiagnostic = result.diagnostic;
|
|
436
662
|
state.updatedAt = new Date().toISOString();
|
|
437
663
|
await writePaymentState(state, options);
|
|
438
664
|
if (status === 'completed') {
|
|
439
665
|
const { paymentNeededPath } = statePaths(resourceUrl, options);
|
|
440
666
|
await rm(paymentNeededPath, { force: true });
|
|
441
667
|
}
|
|
442
|
-
const
|
|
668
|
+
const failureCode = failed ? state.lastFailureCode : undefined;
|
|
443
669
|
return publicPaymentResult(state, status, result.diagnostic, {
|
|
444
670
|
commandFailed: failed,
|
|
445
|
-
failureCode
|
|
671
|
+
failureCode,
|
|
672
|
+
diagnosis: failed ? paymentFailureDiagnosis(failureCode, walletInvocation.stdout, walletInvocation.stderr) : undefined,
|
|
446
673
|
userVisible: ['pending_confirmation', 'completed'].includes(status)
|
|
447
674
|
? userVisibleWalletOutput(walletInvocation.stdout, walletInvocation.stderr)
|
|
448
675
|
: null,
|
|
449
676
|
officialMedia
|
|
450
677
|
});
|
|
451
678
|
}
|
|
679
|
+
|
|
680
|
+
/**
|
|
681
|
+
* Read-only support output. It never invokes the wallet, replays a 402
|
|
682
|
+
* request, exposes a query credential, or returns the private protocol file.
|
|
683
|
+
*/
|
|
684
|
+
export async function diagnoseAlipay402Resource(input, options = {}) {
|
|
685
|
+
const resourceUrl = normalizeResourceUrl(input?.resourceUrl);
|
|
686
|
+
const state = await readPaymentState(resourceUrl, options);
|
|
687
|
+
if (!state) {
|
|
688
|
+
return {
|
|
689
|
+
ok: false,
|
|
690
|
+
status: 'no_local_attempt',
|
|
691
|
+
provider: 'alipay-agent-payment',
|
|
692
|
+
walletInvoked: false,
|
|
693
|
+
message: '没有找到本地付款尝试;请不要因此重复付款。'
|
|
694
|
+
};
|
|
695
|
+
}
|
|
696
|
+
return {
|
|
697
|
+
ok: state.status !== 'failed' && state.status !== 'wallet_command_failed',
|
|
698
|
+
status: state.status || 'unknown',
|
|
699
|
+
provider: 'alipay-agent-payment',
|
|
700
|
+
attemptId: `alipay-402:${state.resourceDigest.slice(0, 16)}`,
|
|
701
|
+
walletInvoked: state.status !== 'started',
|
|
702
|
+
queryAvailable: Boolean(state.queryCredential?.value),
|
|
703
|
+
diagnostic: state.lastWalletDiagnostic || 'payment_state_recorded',
|
|
704
|
+
...(state.lastFailureCode ? { failureCode: state.lastFailureCode } : {}),
|
|
705
|
+
...(state.lastDiagnosis ? {
|
|
706
|
+
diagnosis: state.lastDiagnosis,
|
|
707
|
+
userVisible: paymentFailureUserVisible(state.lastDiagnosis)
|
|
708
|
+
} : {}),
|
|
709
|
+
updatedAt: state.updatedAt || null
|
|
710
|
+
};
|
|
711
|
+
}
|
package/index.mjs
CHANGED