moltspay 0.8.1 → 0.8.2

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.
@@ -1,10 +1,16 @@
1
1
  #!/usr/bin/env node
2
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
3
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
4
+ }) : x)(function(x) {
5
+ if (typeof require !== "undefined") return require.apply(this, arguments);
6
+ throw Error('Dynamic require of "' + x + '" is not supported');
7
+ });
2
8
 
3
9
  // src/cli/index.ts
4
10
  import { Command } from "commander";
5
11
  import { homedir as homedir2 } from "os";
6
- import { join as join2, dirname, resolve } from "path";
7
- import { existsSync as existsSync2, writeFileSync as writeFileSync2, readFileSync as readFileSync3, unlinkSync, mkdirSync as mkdirSync2 } from "fs";
12
+ import { join as join3, dirname, resolve } from "path";
13
+ import { existsSync as existsSync3, writeFileSync as writeFileSync2, readFileSync as readFileSync3, unlinkSync, mkdirSync as mkdirSync2 } from "fs";
8
14
  import { spawn } from "child_process";
9
15
 
10
16
  // src/client/index.ts
@@ -342,30 +348,97 @@ var MoltsPayClient = class {
342
348
  };
343
349
 
344
350
  // src/server/index.ts
345
- import { readFileSync as readFileSync2 } from "fs";
351
+ import { readFileSync as readFileSync2, existsSync as existsSync2 } from "fs";
346
352
  import { createServer } from "http";
353
+ import * as path from "path";
347
354
  var X402_VERSION2 = 2;
348
355
  var PAYMENT_REQUIRED_HEADER2 = "x-payment-required";
349
356
  var PAYMENT_HEADER2 = "x-payment";
350
357
  var PAYMENT_RESPONSE_HEADER = "x-payment-response";
351
- var DEFAULT_FACILITATOR_URL = "https://x402.org/facilitator";
358
+ var FACILITATOR_TESTNET = "https://www.x402.org/facilitator";
359
+ var FACILITATOR_MAINNET = "https://api.cdp.coinbase.com/platform/v2/x402";
360
+ function loadEnvFiles() {
361
+ try {
362
+ const dotenv = __require("dotenv");
363
+ const envPaths = [
364
+ path.join(process.cwd(), ".env"),
365
+ path.join(process.env.HOME || "", ".moltspay", ".env")
366
+ ];
367
+ for (const envPath of envPaths) {
368
+ if (existsSync2(envPath)) {
369
+ dotenv.config({ path: envPath });
370
+ console.log(`[MoltsPay] Loaded config from ${envPath}`);
371
+ break;
372
+ }
373
+ }
374
+ } catch {
375
+ }
376
+ }
377
+ function getCDPConfig() {
378
+ loadEnvFiles();
379
+ return {
380
+ useMainnet: process.env.USE_MAINNET?.toLowerCase() === "true",
381
+ apiKeyId: process.env.CDP_API_KEY_ID,
382
+ apiKeySecret: process.env.CDP_API_KEY_SECRET
383
+ };
384
+ }
385
+ async function getCDPAuthHeaders(method, urlPath, body) {
386
+ const config = getCDPConfig();
387
+ if (!config.apiKeyId || !config.apiKeySecret) {
388
+ throw new Error("CDP_API_KEY_ID and CDP_API_KEY_SECRET required for mainnet");
389
+ }
390
+ try {
391
+ const { getAuthHeaders } = await import("@coinbase/cdp-sdk/auth");
392
+ const headers = await getAuthHeaders({
393
+ apiKeyId: config.apiKeyId,
394
+ apiKeySecret: config.apiKeySecret,
395
+ requestMethod: method,
396
+ requestHost: "api.cdp.coinbase.com",
397
+ requestPath: urlPath,
398
+ requestBody: body
399
+ });
400
+ return headers;
401
+ } catch (err) {
402
+ console.error("[MoltsPay] Failed to generate CDP auth headers:", err.message);
403
+ throw err;
404
+ }
405
+ }
352
406
  var MoltsPayServer = class {
353
407
  manifest;
354
408
  skills = /* @__PURE__ */ new Map();
355
409
  options;
410
+ cdpConfig;
356
411
  facilitatorUrl;
412
+ networkId;
357
413
  constructor(servicesPath, options = {}) {
414
+ this.cdpConfig = getCDPConfig();
358
415
  const content = readFileSync2(servicesPath, "utf-8");
359
416
  this.manifest = JSON.parse(content);
360
417
  this.options = {
361
418
  port: options.port || 3e3,
362
419
  host: options.host || "0.0.0.0"
363
420
  };
364
- this.facilitatorUrl = options.facilitatorUrl || DEFAULT_FACILITATOR_URL;
421
+ if (this.cdpConfig.useMainnet) {
422
+ if (!this.cdpConfig.apiKeyId || !this.cdpConfig.apiKeySecret) {
423
+ console.warn("[MoltsPay] WARNING: USE_MAINNET=true but CDP keys not set!");
424
+ console.warn("[MoltsPay] Set CDP_API_KEY_ID and CDP_API_KEY_SECRET in ~/.moltspay/.env");
425
+ }
426
+ this.facilitatorUrl = FACILITATOR_MAINNET;
427
+ this.networkId = "eip155:8453";
428
+ } else {
429
+ this.facilitatorUrl = options.facilitatorUrl || FACILITATOR_TESTNET;
430
+ this.networkId = "eip155:84532";
431
+ }
432
+ const networkName = this.cdpConfig.useMainnet ? "Base mainnet" : "Base Sepolia (testnet)";
433
+ const facilitatorName = this.cdpConfig.useMainnet ? "CDP" : "x402.org";
365
434
  console.log(`[MoltsPay] Loaded ${this.manifest.services.length} services from ${servicesPath}`);
366
435
  console.log(`[MoltsPay] Provider: ${this.manifest.provider.name}`);
367
436
  console.log(`[MoltsPay] Receive wallet: ${this.manifest.provider.wallet}`);
368
- console.log(`[MoltsPay] Facilitator: ${this.facilitatorUrl}`);
437
+ console.log(`[MoltsPay] Network: ${this.networkId} (${networkName})`);
438
+ console.log(`[MoltsPay] Facilitator: ${facilitatorName} (${this.facilitatorUrl})`);
439
+ if (this.cdpConfig.useMainnet && this.cdpConfig.apiKeyId) {
440
+ console.log(`[MoltsPay] CDP API Key: ${this.cdpConfig.apiKeyId.slice(0, 8)}...`);
441
+ }
369
442
  console.log(`[MoltsPay] Protocol: x402 (gasless for both client AND server)`);
370
443
  }
371
444
  /**
@@ -426,7 +499,6 @@ var MoltsPayServer = class {
426
499
  * GET /services - List available services
427
500
  */
428
501
  handleGetServices(res) {
429
- const chain = getChain(this.manifest.provider.chain);
430
502
  const services = this.manifest.services.map((s) => ({
431
503
  id: s.id,
432
504
  name: s.name,
@@ -442,16 +514,15 @@ var MoltsPayServer = class {
442
514
  services,
443
515
  x402: {
444
516
  version: X402_VERSION2,
445
- network: `eip155:${chain.chainId}`,
517
+ network: this.networkId,
446
518
  schemes: ["exact"],
447
- facilitator: this.facilitatorUrl
519
+ facilitator: this.cdpConfig.useMainnet ? "cdp" : "x402.org",
520
+ mainnet: this.cdpConfig.useMainnet
448
521
  }
449
522
  });
450
523
  }
451
524
  /**
452
525
  * POST /execute - Execute service with x402 payment
453
- * Body: { service: string, params: object }
454
- * Header: X-Payment (optional - if missing, returns 402)
455
526
  */
456
527
  async handleExecute(body, paymentHeader, res) {
457
528
  const { service, params } = body;
@@ -526,16 +597,17 @@ var MoltsPayServer = class {
526
597
  * Return 402 with x402 payment requirements
527
598
  */
528
599
  sendPaymentRequired(config, res) {
529
- const chain = getChain(this.manifest.provider.chain);
530
600
  const amountInUnits = Math.floor(config.price * 1e6).toString();
531
601
  const requirements = [{
532
602
  scheme: "exact",
533
- network: `eip155:${chain.chainId}`,
603
+ network: this.networkId,
534
604
  maxAmountRequired: amountInUnits,
535
605
  resource: this.manifest.provider.wallet,
536
606
  description: `${config.name} - $${config.price} ${config.currency}`,
537
- // Include facilitator info for client
538
- extra: JSON.stringify({ facilitator: this.facilitatorUrl })
607
+ extra: JSON.stringify({
608
+ facilitator: this.cdpConfig.useMainnet ? "cdp" : "x402.org",
609
+ mainnet: this.cdpConfig.useMainnet
610
+ })
539
611
  }];
540
612
  const encoded = Buffer.from(JSON.stringify(requirements)).toString("base64");
541
613
  res.writeHead(402, {
@@ -549,7 +621,7 @@ var MoltsPayServer = class {
549
621
  }, null, 2));
550
622
  }
551
623
  /**
552
- * Basic payment validation (before calling facilitator)
624
+ * Basic payment validation
553
625
  */
554
626
  validatePayment(payment, config) {
555
627
  if (payment.x402Version !== X402_VERSION2) {
@@ -558,37 +630,45 @@ var MoltsPayServer = class {
558
630
  if (payment.scheme !== "exact") {
559
631
  return { valid: false, error: `Unsupported scheme: ${payment.scheme}` };
560
632
  }
561
- const chain = getChain(this.manifest.provider.chain);
562
- const expectedNetwork = `eip155:${chain.chainId}`;
563
- if (payment.network !== expectedNetwork) {
564
- return { valid: false, error: `Network mismatch: expected ${expectedNetwork}` };
633
+ if (payment.network !== this.networkId) {
634
+ return { valid: false, error: `Network mismatch: expected ${this.networkId}, got ${payment.network}` };
565
635
  }
566
636
  return { valid: true };
567
637
  }
568
638
  /**
569
- * Verify payment with facilitator
639
+ * Verify payment with facilitator (testnet or CDP)
570
640
  */
571
641
  async verifyWithFacilitator(payment, config) {
572
642
  try {
573
- const chain = getChain(this.manifest.provider.chain);
574
643
  const amountInUnits = Math.floor(config.price * 1e6).toString();
575
644
  const requirements = {
576
645
  scheme: "exact",
577
- network: `eip155:${chain.chainId}`,
646
+ network: this.networkId,
578
647
  maxAmountRequired: amountInUnits,
579
- resource: this.manifest.provider.wallet
648
+ resource: this.manifest.provider.wallet,
649
+ payTo: this.manifest.provider.wallet
650
+ };
651
+ const requestBody = {
652
+ paymentPayload: payment,
653
+ paymentRequirements: requirements
580
654
  };
655
+ let headers = { "Content-Type": "application/json" };
656
+ if (this.cdpConfig.useMainnet) {
657
+ const authHeaders = await getCDPAuthHeaders(
658
+ "POST",
659
+ "/platform/v2/x402/verify",
660
+ requestBody
661
+ );
662
+ headers = { ...headers, ...authHeaders };
663
+ }
581
664
  const response = await fetch(`${this.facilitatorUrl}/verify`, {
582
665
  method: "POST",
583
- headers: { "Content-Type": "application/json" },
584
- body: JSON.stringify({
585
- paymentPayload: payment,
586
- paymentRequirements: requirements
587
- })
666
+ headers,
667
+ body: JSON.stringify(requestBody)
588
668
  });
589
669
  const result = await response.json();
590
670
  if (!response.ok || !result.isValid) {
591
- return { valid: false, error: result.invalidReason || "Verification failed" };
671
+ return { valid: false, error: result.invalidReason || result.error || "Verification failed" };
592
672
  }
593
673
  return { valid: true };
594
674
  } catch (err) {
@@ -599,25 +679,35 @@ var MoltsPayServer = class {
599
679
  * Settle payment with facilitator (execute on-chain transfer)
600
680
  */
601
681
  async settleWithFacilitator(payment, config) {
602
- const chain = getChain(this.manifest.provider.chain);
603
682
  const amountInUnits = Math.floor(config.price * 1e6).toString();
604
683
  const requirements = {
605
684
  scheme: "exact",
606
- network: `eip155:${chain.chainId}`,
685
+ network: this.networkId,
607
686
  maxAmountRequired: amountInUnits,
608
- resource: this.manifest.provider.wallet
687
+ resource: this.manifest.provider.wallet,
688
+ payTo: this.manifest.provider.wallet
609
689
  };
690
+ const requestBody = {
691
+ paymentPayload: payment,
692
+ paymentRequirements: requirements
693
+ };
694
+ let headers = { "Content-Type": "application/json" };
695
+ if (this.cdpConfig.useMainnet) {
696
+ const authHeaders = await getCDPAuthHeaders(
697
+ "POST",
698
+ "/platform/v2/x402/settle",
699
+ requestBody
700
+ );
701
+ headers = { ...headers, ...authHeaders };
702
+ }
610
703
  const response = await fetch(`${this.facilitatorUrl}/settle`, {
611
704
  method: "POST",
612
- headers: { "Content-Type": "application/json" },
613
- body: JSON.stringify({
614
- paymentPayload: payment,
615
- paymentRequirements: requirements
616
- })
705
+ headers,
706
+ body: JSON.stringify(requestBody)
617
707
  });
618
708
  const result = await response.json();
619
- if (!response.ok) {
620
- throw new Error(result.error || "Settlement failed");
709
+ if (!response.ok || !result.success) {
710
+ throw new Error(result.error || result.errorReason || "Settlement failed");
621
711
  }
622
712
  return {
623
713
  transaction: result.transaction,
@@ -651,9 +741,9 @@ var MoltsPayServer = class {
651
741
  // src/cli/index.ts
652
742
  import * as readline from "readline";
653
743
  var program = new Command();
654
- var DEFAULT_CONFIG_DIR = join2(homedir2(), ".moltspay");
655
- var PID_FILE = join2(DEFAULT_CONFIG_DIR, "server.pid");
656
- if (!existsSync2(DEFAULT_CONFIG_DIR)) {
744
+ var DEFAULT_CONFIG_DIR = join3(homedir2(), ".moltspay");
745
+ var PID_FILE = join3(DEFAULT_CONFIG_DIR, "server.pid");
746
+ if (!existsSync3(DEFAULT_CONFIG_DIR)) {
657
747
  mkdirSync2(DEFAULT_CONFIG_DIR, { recursive: true });
658
748
  }
659
749
  function prompt(question) {
@@ -671,7 +761,7 @@ function prompt(question) {
671
761
  program.name("moltspay").description("MoltsPay - Payment infrastructure for AI Agents").version("1.0.0");
672
762
  program.command("init").description("Initialize MoltsPay client (create wallet, set limits)").option("--chain <chain>", "Blockchain to use", "base").option("--max-per-tx <amount>", "Max amount per transaction").option("--max-per-day <amount>", "Max amount per day").option("--config-dir <dir>", "Config directory", DEFAULT_CONFIG_DIR).action(async (options) => {
673
763
  console.log("\n\u{1F510} MoltsPay Client Setup\n");
674
- if (existsSync2(join2(options.configDir, "wallet.json"))) {
764
+ if (existsSync3(join3(options.configDir, "wallet.json"))) {
675
765
  console.log('\u26A0\uFE0F Already initialized. Use "moltspay config" to update settings.');
676
766
  console.log(` Config dir: ${options.configDir}`);
677
767
  return;
@@ -698,7 +788,7 @@ program.command("init").description("Initialize MoltsPay client (create wallet,
698
788
  console.log(`
699
789
  \u{1F4C1} Config saved to: ${result.configDir}`);
700
790
  console.log(`
701
- \u26A0\uFE0F IMPORTANT: Back up ${join2(result.configDir, "wallet.json")}`);
791
+ \u26A0\uFE0F IMPORTANT: Back up ${join3(result.configDir, "wallet.json")}`);
702
792
  console.log(` This file contains your private key!
703
793
  `);
704
794
  console.log(`\u{1F4B0} Fund your wallet with USDC on ${chain} to start using services.
@@ -806,7 +896,7 @@ program.command("services <url>").description("List services from a provider").o
806
896
  });
807
897
  program.command("start <manifest>").description("Start MoltsPay server from services manifest").option("-p, --port <port>", "Port to listen on", "3000").option("--host <host>", "Host to bind", "0.0.0.0").option("--facilitator <url>", "x402 facilitator URL (default: https://x402.org/facilitator)").action(async (manifest, options) => {
808
898
  const manifestPath = resolve(manifest);
809
- if (!existsSync2(manifestPath)) {
899
+ if (!existsSync3(manifestPath)) {
810
900
  console.error(`\u274C Manifest not found: ${manifestPath}`);
811
901
  process.exit(1);
812
902
  }
@@ -870,7 +960,7 @@ program.command("start <manifest>").description("Start MoltsPay server from serv
870
960
  server.listen(port);
871
961
  const cleanup = () => {
872
962
  try {
873
- if (existsSync2(PID_FILE)) {
963
+ if (existsSync3(PID_FILE)) {
874
964
  unlinkSync(PID_FILE);
875
965
  }
876
966
  } catch {
@@ -893,7 +983,7 @@ program.command("start <manifest>").description("Start MoltsPay server from serv
893
983
  }
894
984
  });
895
985
  program.command("stop").description("Stop the running MoltsPay server").action(async () => {
896
- if (!existsSync2(PID_FILE)) {
986
+ if (!existsSync3(PID_FILE)) {
897
987
  console.log("\u274C No running server found (no PID file)");
898
988
  process.exit(1);
899
989
  }
@@ -923,7 +1013,7 @@ program.command("stop").description("Stop the running MoltsPay server").action(a
923
1013
  process.kill(pid, "SIGKILL");
924
1014
  } catch {
925
1015
  }
926
- if (existsSync2(PID_FILE)) {
1016
+ if (existsSync3(PID_FILE)) {
927
1017
  unlinkSync(PID_FILE);
928
1018
  }
929
1019
  console.log("\u2705 Server stopped\n");
@@ -954,7 +1044,7 @@ program.command("pay <server> <service> [params]").description("Pay for a servic
954
1044
  params.image_url = imagePath;
955
1045
  } else {
956
1046
  const filePath = resolve(imagePath);
957
- if (!existsSync2(filePath)) {
1047
+ if (!existsSync3(filePath)) {
958
1048
  console.error(`\u274C Image file not found: ${filePath}`);
959
1049
  process.exit(1);
960
1050
  }