@xiashe/sdk 0.1.23 → 0.1.25

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 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 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());
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
- ? '虾舍已为该资源签发结构有效的支付宝 402 账单;尚未调用钱包或创建交易。'
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: 'available',
691
+ state: 'runtime_available',
628
692
  provider: 'alipay-agent-payment',
629
- message: '支付宝官方付款桥已可用;付款时将由支付宝 App 请求确认。',
693
+ message: '已找到支付宝官方钱包程序;这只表示程序可执行,尚未检查钱包授权或交易资格。',
694
+ walletStateChecked: false,
695
+ transactionCreationVerified: false,
696
+ ...(runtimeVersion ? { runtimeVersion } : {}),
630
697
  diagnostic: safeDiagnostic(stdout || stderr)
631
698
  };
632
699
  }
@@ -811,3 +878,62 @@ export async function diagnoseAlipay402Resource(input, options = {}) {
811
878
  updatedAt: state.updatedAt || null
812
879
  };
813
880
  }
881
+
882
+ /**
883
+ * Creates a deliberately redacted support summary for an already-failed
884
+ * official-wallet attempt. This never invokes the wallet, re-fetches the
885
+ * resource, or reads/prints the Payment-Needed payload. It is intended for
886
+ * the official `alipay-bot problem-feedback` flow, where a generic wallet
887
+ * trade-creation error otherwise leaves an operator with no safe facts to
888
+ * report.
889
+ */
890
+ export async function createAlipay402SupportReport(input, options = {}) {
891
+ const resourceUrl = normalizeResourceUrl(input?.resourceUrl);
892
+ const state = await readPaymentState(resourceUrl, options);
893
+ if (!state) {
894
+ return {
895
+ ok: false,
896
+ status: 'no_local_attempt',
897
+ provider: 'alipay-agent-payment',
898
+ walletInvoked: false,
899
+ message: '没有找到本地付款尝试,无法生成问题反馈材料。'
900
+ };
901
+ }
902
+
903
+ const failureCode = state.lastFailureCode || null;
904
+ const diagnosis = state.lastDiagnosis || null;
905
+ const failedBeforeConfirmation = !state.queryCredential?.value &&
906
+ ['failed', 'wallet_command_failed'].includes(state.status);
907
+ const { stdout, stderr } = await runOfficialCli(['--version'], options);
908
+ const runtimeVersion = safeRuntimeVersion(stdout, stderr) || null;
909
+ const lines = [
910
+ '[环节]:402 支付 / 官方钱包创建交易',
911
+ `[结果]:${failedBeforeConfirmation ? '未创建可确认交易,未获得 Payment-Proof' : '请以本地诊断状态为准'}`,
912
+ `[桥接诊断]:${diagnosis?.code || failureCode || 'unknown'}`,
913
+ `[官方代码]:${diagnosis?.officialCode || '未返回'}`,
914
+ `[官方运行时]:${runtimeVersion || '未知'}`,
915
+ `[发生时间]:${state.updatedAt || state.createdAt || '未知'}`,
916
+ '[已确认]:卖方资源返回字段结构有效的 402 账单;本次未生成可查询交易凭证。',
917
+ '[请协助]:返回本次 TRADE_PROGRESS_FAILED 的子码、requestId/traceId,以及交易创建被拒绝的具体校验项。'
918
+ ];
919
+ return {
920
+ ok: true,
921
+ status: 'support_report_ready',
922
+ provider: 'alipay-agent-payment',
923
+ walletInvoked: false,
924
+ report: {
925
+ category: 'ALIPAY_402_TRADE_CREATION_FAILED',
926
+ attemptId: `alipay-402:${state.resourceDigest.slice(0, 16)}`,
927
+ occurredAt: state.updatedAt || state.createdAt || null,
928
+ officialRuntimeVersion: runtimeVersion,
929
+ failureCode,
930
+ ...(diagnosis?.officialCode ? { officialCode: diagnosis.officialCode } : {}),
931
+ ...(diagnosis?.officialSubCode ? { officialSubCode: diagnosis.officialSubCode } : {}),
932
+ billShapeValidated: state.merchantResource?.billShapeValidated === true,
933
+ paymentNeededReceived: state.merchantResource?.paymentNeededReceived === true,
934
+ queryCredentialCreated: Boolean(state.queryCredential?.value),
935
+ text: lines.join('\n')
936
+ },
937
+ message: '已生成脱敏的问题反馈材料;其中不包含订单号、资源 URL、账单、Payment-Proof 或钱包凭证。'
938
+ };
939
+ }
package/index.mjs CHANGED
@@ -6,7 +6,7 @@ import path from 'node:path';
6
6
  import { ConvexHttpClient } from 'convex/browser';
7
7
  import { anyApi as api } from 'convex/server';
8
8
 
9
- export const VERSION = '0.1.23';
9
+ export const VERSION = '0.1.25';
10
10
 
11
11
  export const DEFAULTS = {
12
12
  cn: {
@@ -1365,5 +1365,6 @@ export {
1365
1365
  preflightAlipay402Resource,
1366
1366
  payAlipay402Resource,
1367
1367
  queryAlipay402Resource,
1368
- diagnoseAlipay402Resource
1368
+ diagnoseAlipay402Resource,
1369
+ createAlipay402SupportReport
1369
1370
  } from './alipayWallet.mjs';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xiashe/sdk",
3
- "version": "0.1.23",
3
+ "version": "0.1.25",
4
4
  "type": "module",
5
5
  "main": "index.mjs",
6
6
  "exports": {