moltspay 1.4.0 → 1.5.0
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/.env.example +14 -0
- package/README.md +185 -93
- package/dist/cli/index.js +69 -33
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/index.mjs +69 -33
- package/dist/cli/index.mjs.map +1 -1
- package/dist/client/index.d.mts +3 -0
- package/dist/client/index.d.ts +3 -0
- package/dist/client/index.js +46 -26
- package/dist/client/index.js.map +1 -1
- package/dist/client/index.mjs +46 -26
- package/dist/client/index.mjs.map +1 -1
- package/dist/index.js +50 -28
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +50 -28
- package/dist/index.mjs.map +1 -1
- package/dist/mcp/index.d.mts +1 -0
- package/dist/mcp/index.d.ts +1 -0
- package/dist/mcp/index.js +1498 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/mcp/index.mjs +1492 -0
- package/dist/mcp/index.mjs.map +1 -0
- package/dist/server/index.js +4 -2
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +4 -2
- package/dist/server/index.mjs.map +1 -1
- package/package.json +12 -4
package/dist/client/index.d.mts
CHANGED
|
@@ -38,6 +38,7 @@ interface ServiceInfo {
|
|
|
38
38
|
output: Record<string, any>;
|
|
39
39
|
available: boolean;
|
|
40
40
|
provider?: ProviderInfo;
|
|
41
|
+
endpoint?: string;
|
|
41
42
|
}
|
|
42
43
|
interface ProviderInfo {
|
|
43
44
|
name: string;
|
|
@@ -81,6 +82,8 @@ interface PayOptions {
|
|
|
81
82
|
autoSelect?: boolean;
|
|
82
83
|
/** Chain to pay on */
|
|
83
84
|
chain?: 'base' | 'polygon' | 'base_sepolia' | 'tempo_moderato' | 'bnb' | 'bnb_testnet' | 'solana' | 'solana_devnet';
|
|
85
|
+
/** Send raw data at top level instead of wrapped in { params } */
|
|
86
|
+
rawData?: boolean;
|
|
84
87
|
}
|
|
85
88
|
declare class MoltsPayClient {
|
|
86
89
|
private configDir;
|
package/dist/client/index.d.ts
CHANGED
|
@@ -38,6 +38,7 @@ interface ServiceInfo {
|
|
|
38
38
|
output: Record<string, any>;
|
|
39
39
|
available: boolean;
|
|
40
40
|
provider?: ProviderInfo;
|
|
41
|
+
endpoint?: string;
|
|
41
42
|
}
|
|
42
43
|
interface ProviderInfo {
|
|
43
44
|
name: string;
|
|
@@ -81,6 +82,8 @@ interface PayOptions {
|
|
|
81
82
|
autoSelect?: boolean;
|
|
82
83
|
/** Chain to pay on */
|
|
83
84
|
chain?: 'base' | 'polygon' | 'base_sepolia' | 'tempo_moderato' | 'bnb' | 'bnb_testnet' | 'solana' | 'solana_devnet';
|
|
85
|
+
/** Send raw data at top level instead of wrapped in { params } */
|
|
86
|
+
rawData?: boolean;
|
|
84
87
|
}
|
|
85
88
|
declare class MoltsPayClient {
|
|
86
89
|
private configDir;
|
package/dist/client/index.js
CHANGED
|
@@ -422,11 +422,26 @@ var MoltsPayClient = class {
|
|
|
422
422
|
throw new Error("Client not initialized. Run: npx moltspay init");
|
|
423
423
|
}
|
|
424
424
|
console.log(`[MoltsPay] Requesting service: ${service}`);
|
|
425
|
-
|
|
425
|
+
let executeUrl = `${serverUrl}/execute`;
|
|
426
|
+
try {
|
|
427
|
+
const services = await this.getServices(serverUrl);
|
|
428
|
+
const svc = services.services?.find((s) => s.id === service);
|
|
429
|
+
if (svc?.endpoint) {
|
|
430
|
+
executeUrl = `${serverUrl}${svc.endpoint}`;
|
|
431
|
+
console.log(`[MoltsPay] Using service endpoint: ${svc.endpoint}`);
|
|
432
|
+
}
|
|
433
|
+
} catch {
|
|
434
|
+
}
|
|
435
|
+
let requestBody;
|
|
436
|
+
if (options.rawData) {
|
|
437
|
+
requestBody = { service, ...params };
|
|
438
|
+
} else {
|
|
439
|
+
requestBody = { service, params };
|
|
440
|
+
}
|
|
426
441
|
if (options.chain) {
|
|
427
442
|
requestBody.chain = options.chain;
|
|
428
443
|
}
|
|
429
|
-
const initialRes = await fetch(
|
|
444
|
+
const initialRes = await fetch(executeUrl, {
|
|
430
445
|
method: "POST",
|
|
431
446
|
headers: { "Content-Type": "application/json" },
|
|
432
447
|
body: JSON.stringify(requestBody)
|
|
@@ -442,7 +457,7 @@ var MoltsPayClient = class {
|
|
|
442
457
|
const paymentRequiredHeader = initialRes.headers.get(PAYMENT_REQUIRED_HEADER);
|
|
443
458
|
if (wwwAuthHeader && wwwAuthHeader.toLowerCase().includes("payment")) {
|
|
444
459
|
console.log("[MoltsPay] Detected MPP protocol, using Tempo flow...");
|
|
445
|
-
return await this.handleMPPPayment(
|
|
460
|
+
return await this.handleMPPPayment(executeUrl, service, params, wwwAuthHeader, options);
|
|
446
461
|
}
|
|
447
462
|
if (!paymentRequiredHeader) {
|
|
448
463
|
throw new Error("Missing payment header (x-payment-required or www-authenticate)");
|
|
@@ -503,7 +518,7 @@ Please specify: --chain <chain_name>`
|
|
|
503
518
|
if (!req2) {
|
|
504
519
|
throw new Error(`Failed to find payment requirement for ${selectedChain}`);
|
|
505
520
|
}
|
|
506
|
-
return await this.handleSolanaPayment(
|
|
521
|
+
return await this.handleSolanaPayment(executeUrl, service, params, req2, solanaChain, options);
|
|
507
522
|
}
|
|
508
523
|
const chainName = selectedChain;
|
|
509
524
|
const chain = getChain(chainName);
|
|
@@ -550,14 +565,14 @@ Please specify: --chain <chain_name>`
|
|
|
550
565
|
if (!bnbSpender) {
|
|
551
566
|
throw new Error("Server did not provide bnbSpender address. Server may not support BNB payments.");
|
|
552
567
|
}
|
|
553
|
-
return await this.handleBNBPayment(
|
|
568
|
+
return await this.handleBNBPayment(executeUrl, service, params, {
|
|
554
569
|
to: payTo2,
|
|
555
570
|
amount,
|
|
556
571
|
token,
|
|
557
572
|
chainName,
|
|
558
573
|
chain,
|
|
559
574
|
spender: bnbSpender
|
|
560
|
-
});
|
|
575
|
+
}, options);
|
|
561
576
|
}
|
|
562
577
|
const payTo = req.payTo || req.resource;
|
|
563
578
|
if (!payTo) {
|
|
@@ -588,11 +603,11 @@ Please specify: --chain <chain_name>`
|
|
|
588
603
|
};
|
|
589
604
|
const paymentHeader = Buffer.from(JSON.stringify(payload)).toString("base64");
|
|
590
605
|
console.log(`[MoltsPay] Sending request with payment...`);
|
|
591
|
-
const paidRequestBody = { service, params };
|
|
606
|
+
const paidRequestBody = options.rawData ? { service, ...params } : { service, params };
|
|
592
607
|
if (options.chain) {
|
|
593
608
|
paidRequestBody.chain = options.chain;
|
|
594
609
|
}
|
|
595
|
-
const paidRes = await fetch(
|
|
610
|
+
const paidRes = await fetch(executeUrl, {
|
|
596
611
|
method: "POST",
|
|
597
612
|
headers: {
|
|
598
613
|
"Content-Type": "application/json",
|
|
@@ -606,13 +621,13 @@ Please specify: --chain <chain_name>`
|
|
|
606
621
|
}
|
|
607
622
|
this.recordSpending(amount);
|
|
608
623
|
console.log(`[MoltsPay] Success! Payment: ${result.payment?.status || "claimed"}`);
|
|
609
|
-
return result.result;
|
|
624
|
+
return result.result || result;
|
|
610
625
|
}
|
|
611
626
|
/**
|
|
612
627
|
* Handle MPP (Machine Payments Protocol) payment flow
|
|
613
628
|
* Called when pay() detects WWW-Authenticate header in 402 response
|
|
614
629
|
*/
|
|
615
|
-
async handleMPPPayment(
|
|
630
|
+
async handleMPPPayment(executeUrl, service, params, wwwAuthHeader, options = {}) {
|
|
616
631
|
const { privateKeyToAccount } = await import("viem/accounts");
|
|
617
632
|
const { createWalletClient, createPublicClient, http } = await import("viem");
|
|
618
633
|
const { tempoModerato } = await import("viem/chains");
|
|
@@ -673,13 +688,14 @@ Please specify: --chain <chain_name>`
|
|
|
673
688
|
source: `did:pkh:eip155:${chainId}:${account.address}`
|
|
674
689
|
};
|
|
675
690
|
const credentialB64 = Buffer.from(JSON.stringify(credential)).toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
676
|
-
const
|
|
691
|
+
const retryBody = options.rawData ? { service, ...params, chain: "tempo_moderato" } : { service, params, chain: "tempo_moderato" };
|
|
692
|
+
const paidRes = await fetch(executeUrl, {
|
|
677
693
|
method: "POST",
|
|
678
694
|
headers: {
|
|
679
695
|
"Content-Type": "application/json",
|
|
680
696
|
"Authorization": `Payment ${credentialB64}`
|
|
681
697
|
},
|
|
682
|
-
body: JSON.stringify(
|
|
698
|
+
body: JSON.stringify(retryBody)
|
|
683
699
|
});
|
|
684
700
|
const result = await paidRes.json();
|
|
685
701
|
if (!paidRes.ok) {
|
|
@@ -699,7 +715,7 @@ Please specify: --chain <chain_name>`
|
|
|
699
715
|
* 4. Server executes service
|
|
700
716
|
* 5. Server calls transferFrom if successful (pay-for-success)
|
|
701
717
|
*/
|
|
702
|
-
async handleBNBPayment(
|
|
718
|
+
async handleBNBPayment(executeUrl, service, params, paymentDetails, options = {}) {
|
|
703
719
|
const { to, amount, token, chainName, chain, spender } = paymentDetails;
|
|
704
720
|
const tokenConfig = chain.tokens[token];
|
|
705
721
|
const provider = new import_ethers.ethers.JsonRpcProvider(chain.rpc);
|
|
@@ -795,13 +811,14 @@ Run: npx moltspay approve --chain ${chainName} --spender ${spender}`
|
|
|
795
811
|
};
|
|
796
812
|
const paymentHeader = Buffer.from(JSON.stringify(payload)).toString("base64");
|
|
797
813
|
console.log(`[MoltsPay] Sending BNB payment request...`);
|
|
798
|
-
const
|
|
814
|
+
const bnbRequestBody = options.rawData ? { service, ...params, chain: chainName } : { service, params, chain: chainName };
|
|
815
|
+
const paidRes = await fetch(executeUrl, {
|
|
799
816
|
method: "POST",
|
|
800
817
|
headers: {
|
|
801
818
|
"Content-Type": "application/json",
|
|
802
819
|
"X-Payment": paymentHeader
|
|
803
820
|
},
|
|
804
|
-
body: JSON.stringify(
|
|
821
|
+
body: JSON.stringify(bnbRequestBody)
|
|
805
822
|
});
|
|
806
823
|
const result = await paidRes.json();
|
|
807
824
|
if (!paidRes.ok) {
|
|
@@ -818,7 +835,7 @@ Run: npx moltspay approve --chain ${chainName} --spender ${spender}`
|
|
|
818
835
|
* 1. Client creates and signs a transfer transaction
|
|
819
836
|
* 2. Server submits the transaction after service completes
|
|
820
837
|
*/
|
|
821
|
-
async handleSolanaPayment(
|
|
838
|
+
async handleSolanaPayment(executeUrl, service, params, requirements, chain, options = {}) {
|
|
822
839
|
const solanaWallet = loadSolanaWallet(this.configDir);
|
|
823
840
|
if (!solanaWallet) {
|
|
824
841
|
throw new Error("No Solana wallet found. Run: npx moltspay init --chain solana_devnet");
|
|
@@ -871,13 +888,14 @@ Run: npx moltspay approve --chain ${chainName} --spender ${spender}`
|
|
|
871
888
|
}
|
|
872
889
|
};
|
|
873
890
|
const paymentHeader = Buffer.from(JSON.stringify(payload)).toString("base64");
|
|
874
|
-
const
|
|
891
|
+
const solanaRequestBody = options.rawData ? { service, ...params, chain } : { service, params, chain };
|
|
892
|
+
const paidRes = await fetch(executeUrl, {
|
|
875
893
|
method: "POST",
|
|
876
894
|
headers: {
|
|
877
895
|
"Content-Type": "application/json",
|
|
878
896
|
"X-Payment": paymentHeader
|
|
879
897
|
},
|
|
880
|
-
body: JSON.stringify(
|
|
898
|
+
body: JSON.stringify(solanaRequestBody)
|
|
881
899
|
});
|
|
882
900
|
const result = await paidRes.json();
|
|
883
901
|
if (!paidRes.ok) {
|
|
@@ -1022,15 +1040,17 @@ Run: npx moltspay approve --chain ${chainName} --spender ${spender}`
|
|
|
1022
1040
|
loadWallet() {
|
|
1023
1041
|
const walletPath = (0, import_path2.join)(this.configDir, "wallet.json");
|
|
1024
1042
|
if ((0, import_fs2.existsSync)(walletPath)) {
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1043
|
+
if (process.platform !== "win32") {
|
|
1044
|
+
try {
|
|
1045
|
+
const stats = (0, import_fs2.statSync)(walletPath);
|
|
1046
|
+
const mode = stats.mode & 511;
|
|
1047
|
+
if (mode !== 384) {
|
|
1048
|
+
console.warn(`[MoltsPay] WARNING: wallet.json has insecure permissions (${mode.toString(8)})`);
|
|
1049
|
+
console.warn(`[MoltsPay] Fixing permissions to 0600...`);
|
|
1050
|
+
(0, import_fs2.chmodSync)(walletPath, 384);
|
|
1051
|
+
}
|
|
1052
|
+
} catch {
|
|
1032
1053
|
}
|
|
1033
|
-
} catch (err) {
|
|
1034
1054
|
}
|
|
1035
1055
|
const content = (0, import_fs2.readFileSync)(walletPath, "utf-8");
|
|
1036
1056
|
return JSON.parse(content);
|