@xiashe/sdk 0.1.23 → 0.1.24
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 +75 -8
- package/index.mjs +1 -1
- package/package.json +1 -1
package/alipayWallet.mjs
CHANGED
|
@@ -41,6 +41,8 @@ const SAFE_OFFICIAL_FAILURE_CODES = new Set([
|
|
|
41
41
|
'SELLER_ID_EMPTY',
|
|
42
42
|
'TRADE_STATUS_INVALID'
|
|
43
43
|
]);
|
|
44
|
+
const SAFE_OFFICIAL_FIELD_VALUE = /^[A-Za-z][A-Za-z0-9_.:-]{2,127}$/;
|
|
45
|
+
const SAFE_OFFICIAL_ERROR_MESSAGE = /^(?!.*(?:https?:\/\/|payment[-_ ]?needed|payment[-_ ]?proof|seller_signature|authorization\s*:|runtimeToken|client[_ -]?session|(?:access|refresh)[_-]?token|credential|\b[A-Za-z0-9_-]{80,}\b)).{1,240}$/i;
|
|
44
46
|
|
|
45
47
|
const OFFICIAL_ERROR_DIAGNOSES = {
|
|
46
48
|
PAYMENT_NEEDED_REJECTED: {
|
|
@@ -142,6 +144,52 @@ function safeDiagnostic(value) {
|
|
|
142
144
|
return SENSITIVE_OUTPUT.test(text) ? 'protocol_payload_processed' : 'official_wallet_response_received';
|
|
143
145
|
}
|
|
144
146
|
|
|
147
|
+
function explicitJsonString(output, fields) {
|
|
148
|
+
for (const field of fields) {
|
|
149
|
+
const match = output.match(new RegExp(`"${field}"\\s*:\\s*("(?:\\\\.|[^"\\\\])*")`, 'i'));
|
|
150
|
+
if (!match) continue;
|
|
151
|
+
try {
|
|
152
|
+
const value = JSON.parse(match[1]);
|
|
153
|
+
if (typeof value === 'string') return value;
|
|
154
|
+
} catch {
|
|
155
|
+
// Do not fall back to arbitrary vendor text: it can carry protocol data.
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return null;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* The official client may include Payment-Needed, Payment-Proof, credentials,
|
|
163
|
+
* or mutable diagnostic text. Persist only explicit, bounded support fields.
|
|
164
|
+
*/
|
|
165
|
+
function safeOfficialDiagnostic(stdout, stderr) {
|
|
166
|
+
const output = `${stdout}\n${stderr}`;
|
|
167
|
+
const pick = (fields) => {
|
|
168
|
+
const value = explicitJsonString(output, fields);
|
|
169
|
+
return value && SAFE_OFFICIAL_FIELD_VALUE.test(value) ? value : null;
|
|
170
|
+
};
|
|
171
|
+
const code = pick(['errorCode', 'error_code', 'previous_error', 'code']);
|
|
172
|
+
const message = explicitJsonString(output, ['errorMsg', 'subMsg', 'error_message', 'message']);
|
|
173
|
+
return {
|
|
174
|
+
code,
|
|
175
|
+
subCode: pick(['subCode', 'sub_code']),
|
|
176
|
+
requestId: pick(['requestId', 'request_id']),
|
|
177
|
+
traceId: pick(['traceId', 'trace_id']),
|
|
178
|
+
// For known downstream codes, our normalized recovery text is safer and
|
|
179
|
+
// more useful than arbitrary vendor prose. TRADE_PROGRESS_FAILED is the
|
|
180
|
+
// one generic wallet-creation code where the official short message adds
|
|
181
|
+
// context without exposing protocol material.
|
|
182
|
+
...(code?.toUpperCase() === 'TRADE_PROGRESS_FAILED' && message && SAFE_OFFICIAL_ERROR_MESSAGE.test(message.trim())
|
|
183
|
+
? { message: safeText(message, 240) }
|
|
184
|
+
: {})
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function safeRuntimeVersion(stdout, stderr) {
|
|
189
|
+
const match = `${stdout}\n${stderr}`.match(/\balipay-bot(?:-cli)?\s+v?(\d+\.\d+\.\d+(?:[-+][A-Za-z0-9.-]+)?)/i);
|
|
190
|
+
return match?.[1] || null;
|
|
191
|
+
}
|
|
192
|
+
|
|
145
193
|
function normalizeResourceUrl(value) {
|
|
146
194
|
let url;
|
|
147
195
|
try {
|
|
@@ -340,10 +388,10 @@ function walletFailureCode(stdout, stderr, exitCode) {
|
|
|
340
388
|
* credentials, URLs, trade identifiers, or PayGuard internals.
|
|
341
389
|
*/
|
|
342
390
|
function safeOfficialFailureCode(stdout, stderr) {
|
|
343
|
-
const
|
|
344
|
-
const candidates = [
|
|
345
|
-
|
|
346
|
-
|
|
391
|
+
const official = safeOfficialDiagnostic(stdout, stderr);
|
|
392
|
+
const candidates = [official.code, official.subCode]
|
|
393
|
+
.filter(Boolean)
|
|
394
|
+
.map((candidate) => candidate.toUpperCase());
|
|
347
395
|
return candidates.find((candidate) => SAFE_OFFICIAL_FAILURE_CODES.has(candidate)) || null;
|
|
348
396
|
}
|
|
349
397
|
|
|
@@ -358,12 +406,17 @@ function safeMerchantDiagnosticCode(stdout, stderr) {
|
|
|
358
406
|
}
|
|
359
407
|
|
|
360
408
|
function paymentFailureDiagnosis(failureCode, stdout, stderr) {
|
|
409
|
+
const official = safeOfficialDiagnostic(stdout, stderr);
|
|
361
410
|
const officialCode = safeOfficialFailureCode(stdout, stderr);
|
|
362
411
|
const merchantDiagnostic = safeMerchantDiagnosticCode(stdout, stderr);
|
|
363
412
|
const base = {
|
|
364
413
|
code: failureCode,
|
|
365
414
|
stage: 'official_wallet_trade_creation',
|
|
366
|
-
nextStep: '不要重复付款;保留诊断代码和本次 attemptId 以便定位。'
|
|
415
|
+
nextStep: '不要重复付款;保留诊断代码和本次 attemptId 以便定位。',
|
|
416
|
+
...(official.subCode ? { officialSubCode: official.subCode } : {}),
|
|
417
|
+
...(official.requestId ? { officialRequestId: official.requestId } : {}),
|
|
418
|
+
...(official.traceId ? { officialTraceId: official.traceId } : {}),
|
|
419
|
+
...(official.message ? { officialMessage: official.message } : {})
|
|
367
420
|
};
|
|
368
421
|
if (officialCode && OFFICIAL_ERROR_DIAGNOSES[officialCode]) {
|
|
369
422
|
return {
|
|
@@ -435,6 +488,10 @@ function paymentFailureUserVisible(diagnosis) {
|
|
|
435
488
|
`诊断代码:${diagnosis.code}`,
|
|
436
489
|
`失败阶段:${diagnosis.stage}`,
|
|
437
490
|
...(diagnosis.officialCode ? [`官方返回代码:${diagnosis.officialCode}`] : []),
|
|
491
|
+
...(diagnosis.officialSubCode ? [`官方子码:${diagnosis.officialSubCode}`] : []),
|
|
492
|
+
...(diagnosis.officialMessage ? [`官方消息:${diagnosis.officialMessage}`] : []),
|
|
493
|
+
...(diagnosis.officialRequestId ? [`官方请求标识:${diagnosis.officialRequestId}`] : []),
|
|
494
|
+
...(diagnosis.officialTraceId ? [`官方追踪标识:${diagnosis.officialTraceId}`] : []),
|
|
438
495
|
...(diagnosis.merchantDiagnostic ? [`商家验证诊断:${diagnosis.merchantDiagnostic}`] : []),
|
|
439
496
|
`下一步:${diagnosis.nextStep}`
|
|
440
497
|
];
|
|
@@ -576,8 +633,14 @@ export async function preflightAlipay402Resource(input, options = {}) {
|
|
|
576
633
|
walletInvoked: false,
|
|
577
634
|
resourceStatus: resource.responseStatus,
|
|
578
635
|
message: validation.ok
|
|
579
|
-
? '
|
|
636
|
+
? '虾舍已为该资源签发字段结构有效的支付宝 402 账单;尚未调用钱包或创建交易,且未验证支付宝端服务状态、已登记公钥或账单签名。'
|
|
580
637
|
: '虾舍资源返回了 402,但账单结构不符合支付宝 AI收要求;未调用钱包。',
|
|
638
|
+
validationScope: {
|
|
639
|
+
billFields: true,
|
|
640
|
+
sellerSignatureVerifiedByAlipay: false,
|
|
641
|
+
merchantServiceVerifiedByAlipay: false,
|
|
642
|
+
transactionCreationVerified: false
|
|
643
|
+
},
|
|
581
644
|
checks: validation.checks
|
|
582
645
|
};
|
|
583
646
|
}
|
|
@@ -622,11 +685,15 @@ export async function checkAlipayWallet(options = {}) {
|
|
|
622
685
|
/** Checks that the official buyer CLI is present, without querying wallet state. */
|
|
623
686
|
export async function getAlipayWalletBridgeInfo(options = {}) {
|
|
624
687
|
const { stdout, stderr } = await runOfficialCli(['--version'], options);
|
|
688
|
+
const runtimeVersion = safeRuntimeVersion(stdout, stderr);
|
|
625
689
|
return {
|
|
626
690
|
ok: true,
|
|
627
|
-
state: '
|
|
691
|
+
state: 'runtime_available',
|
|
628
692
|
provider: 'alipay-agent-payment',
|
|
629
|
-
message: '
|
|
693
|
+
message: '已找到支付宝官方钱包程序;这只表示程序可执行,尚未检查钱包授权或交易资格。',
|
|
694
|
+
walletStateChecked: false,
|
|
695
|
+
transactionCreationVerified: false,
|
|
696
|
+
...(runtimeVersion ? { runtimeVersion } : {}),
|
|
630
697
|
diagnostic: safeDiagnostic(stdout || stderr)
|
|
631
698
|
};
|
|
632
699
|
}
|
package/index.mjs
CHANGED