@xiashe/sdk 0.1.17 → 0.1.18
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 +91 -3
- package/index.mjs +1 -1
- package/package.json +1 -1
package/alipayWallet.mjs
CHANGED
|
@@ -12,6 +12,13 @@ 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
|
+
]);
|
|
15
22
|
|
|
16
23
|
export class AlipayWalletError extends Error {
|
|
17
24
|
constructor(code, message, options = {}) {
|
|
@@ -230,6 +237,81 @@ function walletFailureCode(stdout, stderr, exitCode) {
|
|
|
230
237
|
return Number.isInteger(exitCode) && exitCode !== 0 ? 'official_cli_nonzero_exit' : 'official_cli_unclassified';
|
|
231
238
|
}
|
|
232
239
|
|
|
240
|
+
/**
|
|
241
|
+
* The official wallet can return useful machine error codes alongside protocol
|
|
242
|
+
* material. Expose only a small allow-list: arbitrary vendor output can carry
|
|
243
|
+
* credentials, URLs, trade identifiers, or PayGuard internals.
|
|
244
|
+
*/
|
|
245
|
+
function safeOfficialFailureCode(stdout, stderr) {
|
|
246
|
+
const output = `${stdout}\n${stderr}`;
|
|
247
|
+
const candidate = output.match(/(?:"(?:errorCode|code)"|\b(?:errorCode|code)\b)\s*[:=]\s*["']?([A-Z][A-Z0-9_]{2,80})/i)?.[1]?.toUpperCase() || '';
|
|
248
|
+
return SAFE_OFFICIAL_FAILURE_CODES.has(candidate) ? candidate : null;
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
function paymentFailureDiagnosis(failureCode, stdout, stderr) {
|
|
252
|
+
const officialCode = safeOfficialFailureCode(stdout, stderr);
|
|
253
|
+
const base = {
|
|
254
|
+
code: failureCode,
|
|
255
|
+
stage: 'official_wallet_trade_creation',
|
|
256
|
+
nextStep: '不要重复付款;保留诊断代码和本次 attemptId 以便定位。'
|
|
257
|
+
};
|
|
258
|
+
if (failureCode === 'payment_needed_rejected') {
|
|
259
|
+
return {
|
|
260
|
+
...base,
|
|
261
|
+
stage: 'alipay_bill_validation',
|
|
262
|
+
nextStep: '核对支付宝平台中该 APPID 的应用公钥、service_id、收款方 2088 seller_id 和线上接入状态;修复后必须创建新订单再测试。',
|
|
263
|
+
...(officialCode ? { officialCode } : {})
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
if (failureCode === 'wallet_runtime_not_supported') {
|
|
267
|
+
return {
|
|
268
|
+
...base,
|
|
269
|
+
stage: 'agent_runtime_identity',
|
|
270
|
+
nextStep: '当前运行时没有通过支付宝 Agent 身份校验;请换用已被官方钱包识别并已授权的本地 Agent 运行时。',
|
|
271
|
+
...(officialCode ? { officialCode } : {})
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
if (failureCode === 'buyer_identity_rejected') {
|
|
275
|
+
return {
|
|
276
|
+
...base,
|
|
277
|
+
stage: 'buyer_identity_validation',
|
|
278
|
+
nextStep: '支付宝钱包的买家身份未通过校验;完成钱包授权后,用同一受支持运行时创建新订单。',
|
|
279
|
+
...(officialCode ? { officialCode } : {})
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
if (failureCode === 'wallet_not_ready') {
|
|
283
|
+
return {
|
|
284
|
+
...base,
|
|
285
|
+
stage: 'wallet_authorization',
|
|
286
|
+
nextStep: '支付宝钱包未完成授权或未启用;先完成官方钱包授权,再创建新订单。',
|
|
287
|
+
...(officialCode ? { officialCode } : {})
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
if (failureCode === 'wallet_network_error') {
|
|
291
|
+
return {
|
|
292
|
+
...base,
|
|
293
|
+
stage: 'wallet_network',
|
|
294
|
+
nextStep: '钱包或网络请求没有完成;先检查网络,再创建新订单。',
|
|
295
|
+
...(officialCode ? { officialCode } : {})
|
|
296
|
+
};
|
|
297
|
+
}
|
|
298
|
+
return {
|
|
299
|
+
...base,
|
|
300
|
+
...(officialCode ? { officialCode } : {})
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
function paymentFailureUserVisible(diagnosis) {
|
|
305
|
+
const lines = [
|
|
306
|
+
'支付宝付款未创建可确认交易。',
|
|
307
|
+
`诊断代码:${diagnosis.code}`,
|
|
308
|
+
`失败阶段:${diagnosis.stage}`,
|
|
309
|
+
...(diagnosis.officialCode ? [`官方返回代码:${diagnosis.officialCode}`] : []),
|
|
310
|
+
`下一步:${diagnosis.nextStep}`
|
|
311
|
+
];
|
|
312
|
+
return lines.join('\n');
|
|
313
|
+
}
|
|
314
|
+
|
|
233
315
|
function paymentMessage(status) {
|
|
234
316
|
if (status === 'completed') return '支付宝钱包显示本次付款已完成;正在由服务端确认权益。';
|
|
235
317
|
if (status === 'pending_confirmation') return '支付宝已发起本次付款确认;请打开支付宝 App 完成确认,然后运行 status。';
|
|
@@ -285,6 +367,7 @@ function publicPaymentResult(state, status, diagnostic, options = {}) {
|
|
|
285
367
|
const commandFailed = options.commandFailed === true;
|
|
286
368
|
const failureCode = options.failureCode || 'official_cli_nonzero_exit';
|
|
287
369
|
const failed = status === 'failed' || status === 'wallet_command_failed';
|
|
370
|
+
const diagnosis = failed ? options.diagnosis : null;
|
|
288
371
|
return {
|
|
289
372
|
ok: !failed,
|
|
290
373
|
status,
|
|
@@ -293,7 +376,8 @@ function publicPaymentResult(state, status, diagnostic, options = {}) {
|
|
|
293
376
|
walletInvoked: true,
|
|
294
377
|
message: failed ? paymentFailureMessage(failureCode) : paymentMessage(status),
|
|
295
378
|
diagnostic,
|
|
296
|
-
...(
|
|
379
|
+
...(failed && diagnosis ? { userVisible: paymentFailureUserVisible(diagnosis), diagnosis } : {}),
|
|
380
|
+
...(!failed && options.userVisible ? { userVisible: options.userVisible } : {}),
|
|
297
381
|
...(options.officialMedia ? { officialMedia: options.officialMedia } : {}),
|
|
298
382
|
...(status === 'pending_confirmation'
|
|
299
383
|
? { confirmation: { source: 'official_alipay_wallet', surface: 'app_or_official_media', required: true } }
|
|
@@ -392,9 +476,11 @@ export async function payAlipay402Resource(input, options = {}) {
|
|
|
392
476
|
await writePaymentState(state, options);
|
|
393
477
|
if (status === 'completed') await rm(paths.paymentNeededPath, { force: true });
|
|
394
478
|
const failed = commandFailed || status === 'failed';
|
|
479
|
+
const failureCode = failed ? walletFailureCode(walletInvocation.stdout, walletInvocation.stderr, walletInvocation.exitCode) : undefined;
|
|
395
480
|
return publicPaymentResult(state, status, result.diagnostic, {
|
|
396
481
|
commandFailed: failed,
|
|
397
|
-
failureCode
|
|
482
|
+
failureCode,
|
|
483
|
+
diagnosis: failed ? paymentFailureDiagnosis(failureCode, walletInvocation.stdout, walletInvocation.stderr) : undefined,
|
|
398
484
|
userVisible: ['pending_confirmation', 'completed'].includes(status)
|
|
399
485
|
? userVisibleWalletOutput(walletInvocation.stdout, walletInvocation.stderr)
|
|
400
486
|
: null,
|
|
@@ -440,9 +526,11 @@ export async function queryAlipay402Resource(input, options = {}) {
|
|
|
440
526
|
await rm(paymentNeededPath, { force: true });
|
|
441
527
|
}
|
|
442
528
|
const failed = commandFailed || status === 'failed';
|
|
529
|
+
const failureCode = failed ? walletFailureCode(walletInvocation.stdout, walletInvocation.stderr, walletInvocation.exitCode) : undefined;
|
|
443
530
|
return publicPaymentResult(state, status, result.diagnostic, {
|
|
444
531
|
commandFailed: failed,
|
|
445
|
-
failureCode
|
|
532
|
+
failureCode,
|
|
533
|
+
diagnosis: failed ? paymentFailureDiagnosis(failureCode, walletInvocation.stdout, walletInvocation.stderr) : undefined,
|
|
446
534
|
userVisible: ['pending_confirmation', 'completed'].includes(status)
|
|
447
535
|
? userVisibleWalletOutput(walletInvocation.stdout, walletInvocation.stderr)
|
|
448
536
|
: null,
|
package/index.mjs
CHANGED