@xiashe/sdk 0.1.26 → 0.1.28
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 +49 -9
- package/index.mjs +26 -13
- package/package.json +1 -1
package/alipayWallet.mjs
CHANGED
|
@@ -321,9 +321,18 @@ function walletStateFromOutput(stdout, stderr) {
|
|
|
321
321
|
}
|
|
322
322
|
|
|
323
323
|
function queryCredentialFromOutput(output) {
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
324
|
+
// The official wallet has used both camelCase and snake_case JSON fields.
|
|
325
|
+
// Match either spelling without forwarding the raw wallet output.
|
|
326
|
+
const tradeNo = output.match(/(?:["']?trade[\s_-]*no["']?|交易(?:流水)?号)\s*["::=]\s*["']?([A-Za-z0-9._-]{8,128})/i)?.[1] || null;
|
|
327
|
+
const outShakeNo = output.match(/(?:["']?out[\s_-]*shake[\s_-]*no["']?|外部(?:摇一摇)?编号)\s*["::=]\s*["']?([A-Za-z0-9_-]{8,128})/i)?.[1] || null;
|
|
328
|
+
// An outShakeNo is the preferred 402 status-query credential, but only its
|
|
329
|
+
// documented 32-character AI Pay form may select that query path.
|
|
330
|
+
const validOutShakeNo = outShakeNo && outShakeNo.length === 32 && outShakeNo.slice(10, 14) === '8282';
|
|
331
|
+
return validOutShakeNo
|
|
332
|
+
? { type: 'out_shake_no', value: outShakeNo }
|
|
333
|
+
: tradeNo
|
|
334
|
+
? { type: 'trade_no', value: tradeNo }
|
|
335
|
+
: null;
|
|
327
336
|
}
|
|
328
337
|
|
|
329
338
|
function paymentStatusFromOutput(stdout, stderr) {
|
|
@@ -476,6 +485,14 @@ function paymentFailureDiagnosis(failureCode, stdout, stderr) {
|
|
|
476
485
|
...(officialCode ? { officialCode } : {})
|
|
477
486
|
};
|
|
478
487
|
}
|
|
488
|
+
if (failureCode === 'wallet_query_credential_missing') {
|
|
489
|
+
return {
|
|
490
|
+
...base,
|
|
491
|
+
stage: 'official_wallet_query_credential',
|
|
492
|
+
nextStep: '支付宝钱包没有返回可继续查询的交易凭据。不要继续付款或重复付款;如支付宝已显示扣款,请由商户按交易号对账并提交问题反馈。',
|
|
493
|
+
...(officialCode ? { officialCode } : {})
|
|
494
|
+
};
|
|
495
|
+
}
|
|
479
496
|
return {
|
|
480
497
|
...base,
|
|
481
498
|
...(officialCode ? { officialCode } : {})
|
|
@@ -484,7 +501,9 @@ function paymentFailureDiagnosis(failureCode, stdout, stderr) {
|
|
|
484
501
|
|
|
485
502
|
function paymentFailureUserVisible(diagnosis) {
|
|
486
503
|
const lines = [
|
|
487
|
-
'
|
|
504
|
+
diagnosis.code === 'wallet_query_credential_missing'
|
|
505
|
+
? '支付宝钱包未返回可继续查询的交易凭据,当前付款状态无法确认。'
|
|
506
|
+
: '支付宝付款未创建可确认交易。',
|
|
488
507
|
`诊断代码:${diagnosis.code}`,
|
|
489
508
|
`失败阶段:${diagnosis.stage}`,
|
|
490
509
|
...(diagnosis.officialCode ? [`官方返回代码:${diagnosis.officialCode}`] : []),
|
|
@@ -506,6 +525,9 @@ function paymentMessage(status) {
|
|
|
506
525
|
}
|
|
507
526
|
|
|
508
527
|
function paymentFailureMessage(failureCode) {
|
|
528
|
+
if (failureCode === 'wallet_query_credential_missing') {
|
|
529
|
+
return '支付宝钱包返回待确认,但未返回可继续查询的交易凭据。无法确认是否已付款,因此不会授予付费 Skill 权益;请勿再次付款。';
|
|
530
|
+
}
|
|
509
531
|
if (failureCode === 'wallet_trade_progress_failed') {
|
|
510
532
|
return '支付宝钱包未能创建可确认的交易;未授予付费 Skill 权益。官方钱包没有给出可归因的原因,不能据此判断为 Agent 不受支持、账单签名错误或已扣款;请勿重复付款。';
|
|
511
533
|
}
|
|
@@ -762,22 +784,31 @@ export async function payAlipay402Resource(input, options = {}) {
|
|
|
762
784
|
], options);
|
|
763
785
|
const result = paymentStatusFromOutput(walletInvocation.stdout, walletInvocation.stderr);
|
|
764
786
|
const commandFailed = walletInvocation.exitCode !== 0 && result.status === 'unknown';
|
|
765
|
-
const
|
|
787
|
+
const missingQueryCredential = result.status === 'pending_confirmation' && !result.credential;
|
|
788
|
+
const status = commandFailed
|
|
789
|
+
? 'wallet_command_failed'
|
|
790
|
+
: missingQueryCredential
|
|
791
|
+
? 'failed'
|
|
792
|
+
: result.status;
|
|
766
793
|
const failed = commandFailed || status === 'failed';
|
|
794
|
+
const failureCode = missingQueryCredential
|
|
795
|
+
? 'wallet_query_credential_missing'
|
|
796
|
+
: failed
|
|
797
|
+
? walletFailureCode(walletInvocation.stdout, walletInvocation.stderr, walletInvocation.exitCode)
|
|
798
|
+
: undefined;
|
|
767
799
|
const officialMedia = ['pending_confirmation', 'completed'].includes(status)
|
|
768
800
|
? await officialWalletMedia(walletInvocation.stdout, walletInvocation.stderr)
|
|
769
801
|
: null;
|
|
770
802
|
state.status = status;
|
|
771
803
|
state.queryCredential = result.credential;
|
|
772
|
-
state.lastFailureCode =
|
|
804
|
+
state.lastFailureCode = failureCode ?? null;
|
|
773
805
|
state.lastDiagnosis = failed
|
|
774
|
-
? paymentFailureDiagnosis(
|
|
806
|
+
? paymentFailureDiagnosis(failureCode, walletInvocation.stdout, walletInvocation.stderr)
|
|
775
807
|
: null;
|
|
776
808
|
state.lastWalletDiagnostic = result.diagnostic;
|
|
777
809
|
state.updatedAt = new Date().toISOString();
|
|
778
810
|
await writePaymentState(state, options);
|
|
779
811
|
if (status === 'completed') await rm(paths.paymentNeededPath, { force: true });
|
|
780
|
-
const failureCode = failed ? state.lastFailureCode : undefined;
|
|
781
812
|
return publicPaymentResult(state, status, result.diagnostic, {
|
|
782
813
|
commandFailed: failed,
|
|
783
814
|
failureCode,
|
|
@@ -883,7 +914,16 @@ export async function diagnoseAlipay402Resource(input, options = {}) {
|
|
|
883
914
|
// optional command after a failed payment.
|
|
884
915
|
if (state.lastFailureCode === 'wallet_trade_progress_failed') {
|
|
885
916
|
const support = await createAlipay402SupportReport({ resourceUrl }, options);
|
|
886
|
-
if (support.ok && support.report)
|
|
917
|
+
if (support.ok && support.report) {
|
|
918
|
+
result.supportReport = support.report;
|
|
919
|
+
// Some Agents intentionally present only `userVisible` from a bridge
|
|
920
|
+
// result. Put the already-redacted support text there as well so the
|
|
921
|
+
// only useful evidence from this generic upstream error is not silently
|
|
922
|
+
// dropped by a client-side response mapper.
|
|
923
|
+
result.userVisible = [result.userVisible, '', '支付宝支持诊断:', support.report.text]
|
|
924
|
+
.filter((line) => typeof line === 'string' && line.length > 0)
|
|
925
|
+
.join('\n');
|
|
926
|
+
}
|
|
887
927
|
}
|
|
888
928
|
return result;
|
|
889
929
|
}
|
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.
|
|
9
|
+
export const VERSION = '0.1.27';
|
|
10
10
|
|
|
11
11
|
export const DEFAULTS = {
|
|
12
12
|
cn: {
|
|
@@ -22,6 +22,7 @@ export const DEFAULTS = {
|
|
|
22
22
|
market: 'intl',
|
|
23
23
|
locale: 'en',
|
|
24
24
|
convexUrl: 'https://adept-porcupine-970.convex.cloud',
|
|
25
|
+
// agentpie.app is the production Worker gateway for public and Agent APIs.
|
|
25
26
|
actionsUrl: 'https://agentpie.app',
|
|
26
27
|
mcpUrl: 'https://agentpie.app/mcp/xiashe',
|
|
27
28
|
agentClaimUrl: 'https://agentpie.app/agent-gateway/claim',
|
|
@@ -409,8 +410,8 @@ export class XiasheClient {
|
|
|
409
410
|
return this.mutation(api.auth.signInWithPassword, { email, password });
|
|
410
411
|
}
|
|
411
412
|
|
|
412
|
-
async registerWithPassword(email, password, displayName = '') {
|
|
413
|
-
return this.mutation(api.auth.registerWithPassword, { email, password, displayName });
|
|
413
|
+
async registerWithPassword(email, password, displayName = '', verificationCode = '') {
|
|
414
|
+
return this.mutation(api.auth.registerWithPassword, { email, password, displayName, verificationCode });
|
|
414
415
|
}
|
|
415
416
|
|
|
416
417
|
async requestEmailCode(email, mode = 'login') {
|
|
@@ -421,6 +422,19 @@ export class XiasheClient {
|
|
|
421
422
|
return this.mutation(api.auth.verifyEmailCode, { email, code, mode, displayName });
|
|
422
423
|
}
|
|
423
424
|
|
|
425
|
+
/**
|
|
426
|
+
* Creates the same short-lived, creator-scoped connection code that the
|
|
427
|
+
* dashboard's “Add Skill” flow uses. This intentionally requires an
|
|
428
|
+
* authenticated local AgentPie session; it is not a publish bypass.
|
|
429
|
+
*/
|
|
430
|
+
async issueCreatorSkillClaimCode({ label = '' } = {}) {
|
|
431
|
+
const normalizedLabel = String(label || '').trim().slice(0, 320);
|
|
432
|
+
return this.mutation(
|
|
433
|
+
api.creatorSkillRegistry.issueClaimCode,
|
|
434
|
+
this.authArgs(normalizedLabel ? { label: normalizedLabel } : {})
|
|
435
|
+
);
|
|
436
|
+
}
|
|
437
|
+
|
|
424
438
|
async whoami() {
|
|
425
439
|
return this.query(api.users.getById, this.authArgs({ userId: this.profile.session.userId }));
|
|
426
440
|
}
|
|
@@ -734,8 +748,8 @@ export class XiasheClient {
|
|
|
734
748
|
}
|
|
735
749
|
|
|
736
750
|
async verifyCreatorAlipayAppConfig(creatorAlipayAppId, options = {}) {
|
|
737
|
-
return this.
|
|
738
|
-
api.marketplaceBilling.
|
|
751
|
+
return this.action(
|
|
752
|
+
api.marketplaceBilling.verifyCreatorAlipayAppConfigAsync,
|
|
739
753
|
this.authArgs({
|
|
740
754
|
creatorAlipayAppId,
|
|
741
755
|
uploadedToAlipay: options.uploadedToAlipay !== false
|
|
@@ -843,7 +857,7 @@ export class XiasheClient {
|
|
|
843
857
|
}
|
|
844
858
|
|
|
845
859
|
alipayAiCollectPaymentResourceUrl(orderIdOrUrl, options = {}) {
|
|
846
|
-
const value = String(orderIdOrUrl || options.
|
|
860
|
+
const value = String(orderIdOrUrl || options.paymentResourceUrl || '').trim();
|
|
847
861
|
if (!value) {
|
|
848
862
|
throw new XiasheError('Missing Alipay AI Collect order id or payment resource URL.', {
|
|
849
863
|
code: 'ALIPAY_AI_COLLECT_RESOURCE_REQUIRED'
|
|
@@ -852,13 +866,12 @@ export class XiasheClient {
|
|
|
852
866
|
if (/^https?:\/\//i.test(value)) {
|
|
853
867
|
return value;
|
|
854
868
|
}
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
}
|
|
861
|
-
return `${actionsUrl}/payment/alipay-ai-collect?orderId=${encodeURIComponent(value)}`;
|
|
869
|
+
// Resource URLs are registered and signed per Skill. An order id alone
|
|
870
|
+
// cannot safely reconstruct one: doing so would silently return to the
|
|
871
|
+
// retired merchant-wide /payment/alipay-ai-collect route.
|
|
872
|
+
throw new XiasheError('Use the paymentResourceUrl returned by checkout; an order id alone is not a payment resource URL.', {
|
|
873
|
+
code: 'ALIPAY_AI_COLLECT_RESOURCE_URL_REQUIRED'
|
|
874
|
+
});
|
|
862
875
|
}
|
|
863
876
|
|
|
864
877
|
async getAlipayAiCollectPaymentNeeded(orderIdOrUrl, options = {}) {
|