moltspay 0.8.0 → 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.
- package/.env.example +10 -0
- package/dist/cli/index.js +207 -98
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/index.mjs +226 -111
- package/dist/cli/index.mjs.map +1 -1
- package/dist/index.js +321 -211
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +338 -228
- package/dist/index.mjs.map +1 -1
- package/dist/server/index.d.mts +23 -11
- package/dist/server/index.d.ts +23 -11
- package/dist/server/index.js +213 -153
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +211 -154
- package/dist/server/index.mjs.map +1 -1
- package/package.json +3 -1
package/.env.example
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# MoltsPay Server Configuration
|
|
2
|
+
# Copy to ~/.moltspay/.env or ./.env and fill in values
|
|
3
|
+
|
|
4
|
+
# Network: true = Base mainnet, false = Base Sepolia testnet
|
|
5
|
+
USE_MAINNET=true
|
|
6
|
+
|
|
7
|
+
# CDP API Credentials (required for mainnet)
|
|
8
|
+
# Get from: https://portal.cdp.coinbase.com/
|
|
9
|
+
CDP_API_KEY_ID=
|
|
10
|
+
CDP_API_KEY_SECRET=
|
package/dist/cli/index.js
CHANGED
|
@@ -367,38 +367,96 @@ var MoltsPayClient = class {
|
|
|
367
367
|
// src/server/index.ts
|
|
368
368
|
var import_fs2 = require("fs");
|
|
369
369
|
var import_http = require("http");
|
|
370
|
-
var
|
|
370
|
+
var path = __toESM(require("path"));
|
|
371
371
|
var X402_VERSION2 = 2;
|
|
372
372
|
var PAYMENT_REQUIRED_HEADER2 = "x-payment-required";
|
|
373
373
|
var PAYMENT_HEADER2 = "x-payment";
|
|
374
|
+
var PAYMENT_RESPONSE_HEADER = "x-payment-response";
|
|
375
|
+
var FACILITATOR_TESTNET = "https://www.x402.org/facilitator";
|
|
376
|
+
var FACILITATOR_MAINNET = "https://api.cdp.coinbase.com/platform/v2/x402";
|
|
377
|
+
function loadEnvFiles() {
|
|
378
|
+
try {
|
|
379
|
+
const dotenv = require("dotenv");
|
|
380
|
+
const envPaths = [
|
|
381
|
+
path.join(process.cwd(), ".env"),
|
|
382
|
+
path.join(process.env.HOME || "", ".moltspay", ".env")
|
|
383
|
+
];
|
|
384
|
+
for (const envPath of envPaths) {
|
|
385
|
+
if ((0, import_fs2.existsSync)(envPath)) {
|
|
386
|
+
dotenv.config({ path: envPath });
|
|
387
|
+
console.log(`[MoltsPay] Loaded config from ${envPath}`);
|
|
388
|
+
break;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
} catch {
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
function getCDPConfig() {
|
|
395
|
+
loadEnvFiles();
|
|
396
|
+
return {
|
|
397
|
+
useMainnet: process.env.USE_MAINNET?.toLowerCase() === "true",
|
|
398
|
+
apiKeyId: process.env.CDP_API_KEY_ID,
|
|
399
|
+
apiKeySecret: process.env.CDP_API_KEY_SECRET
|
|
400
|
+
};
|
|
401
|
+
}
|
|
402
|
+
async function getCDPAuthHeaders(method, urlPath, body) {
|
|
403
|
+
const config = getCDPConfig();
|
|
404
|
+
if (!config.apiKeyId || !config.apiKeySecret) {
|
|
405
|
+
throw new Error("CDP_API_KEY_ID and CDP_API_KEY_SECRET required for mainnet");
|
|
406
|
+
}
|
|
407
|
+
try {
|
|
408
|
+
const { getAuthHeaders } = await import("@coinbase/cdp-sdk/auth");
|
|
409
|
+
const headers = await getAuthHeaders({
|
|
410
|
+
apiKeyId: config.apiKeyId,
|
|
411
|
+
apiKeySecret: config.apiKeySecret,
|
|
412
|
+
requestMethod: method,
|
|
413
|
+
requestHost: "api.cdp.coinbase.com",
|
|
414
|
+
requestPath: urlPath,
|
|
415
|
+
requestBody: body
|
|
416
|
+
});
|
|
417
|
+
return headers;
|
|
418
|
+
} catch (err) {
|
|
419
|
+
console.error("[MoltsPay] Failed to generate CDP auth headers:", err.message);
|
|
420
|
+
throw err;
|
|
421
|
+
}
|
|
422
|
+
}
|
|
374
423
|
var MoltsPayServer = class {
|
|
375
424
|
manifest;
|
|
376
425
|
skills = /* @__PURE__ */ new Map();
|
|
377
426
|
options;
|
|
378
|
-
|
|
379
|
-
|
|
427
|
+
cdpConfig;
|
|
428
|
+
facilitatorUrl;
|
|
429
|
+
networkId;
|
|
380
430
|
constructor(servicesPath, options = {}) {
|
|
431
|
+
this.cdpConfig = getCDPConfig();
|
|
381
432
|
const content = (0, import_fs2.readFileSync)(servicesPath, "utf-8");
|
|
382
433
|
this.manifest = JSON.parse(content);
|
|
383
434
|
this.options = {
|
|
384
435
|
port: options.port || 3e3,
|
|
385
|
-
host: options.host || "0.0.0.0"
|
|
386
|
-
privateKey: options.privateKey || process.env.MOLTSPAY_PRIVATE_KEY
|
|
436
|
+
host: options.host || "0.0.0.0"
|
|
387
437
|
};
|
|
388
|
-
if (this.
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
this.wallet = new import_ethers2.ethers.Wallet(this.options.privateKey, this.provider);
|
|
393
|
-
console.log(`[MoltsPay] Payment wallet: ${this.wallet.address}`);
|
|
394
|
-
} catch (err) {
|
|
395
|
-
console.warn("[MoltsPay] Warning: Could not initialize wallet for payment claims");
|
|
438
|
+
if (this.cdpConfig.useMainnet) {
|
|
439
|
+
if (!this.cdpConfig.apiKeyId || !this.cdpConfig.apiKeySecret) {
|
|
440
|
+
console.warn("[MoltsPay] WARNING: USE_MAINNET=true but CDP keys not set!");
|
|
441
|
+
console.warn("[MoltsPay] Set CDP_API_KEY_ID and CDP_API_KEY_SECRET in ~/.moltspay/.env");
|
|
396
442
|
}
|
|
443
|
+
this.facilitatorUrl = FACILITATOR_MAINNET;
|
|
444
|
+
this.networkId = "eip155:8453";
|
|
445
|
+
} else {
|
|
446
|
+
this.facilitatorUrl = options.facilitatorUrl || FACILITATOR_TESTNET;
|
|
447
|
+
this.networkId = "eip155:84532";
|
|
397
448
|
}
|
|
449
|
+
const networkName = this.cdpConfig.useMainnet ? "Base mainnet" : "Base Sepolia (testnet)";
|
|
450
|
+
const facilitatorName = this.cdpConfig.useMainnet ? "CDP" : "x402.org";
|
|
398
451
|
console.log(`[MoltsPay] Loaded ${this.manifest.services.length} services from ${servicesPath}`);
|
|
399
452
|
console.log(`[MoltsPay] Provider: ${this.manifest.provider.name}`);
|
|
400
453
|
console.log(`[MoltsPay] Receive wallet: ${this.manifest.provider.wallet}`);
|
|
401
|
-
console.log(`[MoltsPay]
|
|
454
|
+
console.log(`[MoltsPay] Network: ${this.networkId} (${networkName})`);
|
|
455
|
+
console.log(`[MoltsPay] Facilitator: ${facilitatorName} (${this.facilitatorUrl})`);
|
|
456
|
+
if (this.cdpConfig.useMainnet && this.cdpConfig.apiKeyId) {
|
|
457
|
+
console.log(`[MoltsPay] CDP API Key: ${this.cdpConfig.apiKeyId.slice(0, 8)}...`);
|
|
458
|
+
}
|
|
459
|
+
console.log(`[MoltsPay] Protocol: x402 (gasless for both client AND server)`);
|
|
402
460
|
}
|
|
403
461
|
/**
|
|
404
462
|
* Register a skill handler for a service
|
|
@@ -408,48 +466,45 @@ var MoltsPayServer = class {
|
|
|
408
466
|
if (!config) {
|
|
409
467
|
throw new Error(`Service '${serviceId}' not found in manifest`);
|
|
410
468
|
}
|
|
411
|
-
this.skills.set(serviceId, {
|
|
412
|
-
id: serviceId,
|
|
413
|
-
config,
|
|
414
|
-
handler
|
|
415
|
-
});
|
|
416
|
-
console.log(`[MoltsPay] Registered skill: ${serviceId} ($${config.price} ${config.currency})`);
|
|
469
|
+
this.skills.set(serviceId, { id: serviceId, config, handler });
|
|
417
470
|
return this;
|
|
418
471
|
}
|
|
419
472
|
/**
|
|
420
|
-
* Start
|
|
473
|
+
* Start HTTP server
|
|
421
474
|
*/
|
|
422
475
|
listen(port) {
|
|
423
|
-
const p = port || this.options.port;
|
|
476
|
+
const p = port || this.options.port || 3e3;
|
|
477
|
+
const host = this.options.host || "0.0.0.0";
|
|
424
478
|
const server = (0, import_http.createServer)((req, res) => this.handleRequest(req, res));
|
|
425
|
-
server.listen(p,
|
|
426
|
-
console.log(`[MoltsPay] Server listening on http://${
|
|
479
|
+
server.listen(p, host, () => {
|
|
480
|
+
console.log(`[MoltsPay] Server listening on http://${host}:${p}`);
|
|
427
481
|
console.log(`[MoltsPay] Endpoints:`);
|
|
428
482
|
console.log(` GET /services - List available services`);
|
|
429
483
|
console.log(` POST /execute - Execute service (x402 payment)`);
|
|
430
484
|
});
|
|
431
485
|
}
|
|
486
|
+
/**
|
|
487
|
+
* Handle incoming request
|
|
488
|
+
*/
|
|
432
489
|
async handleRequest(req, res) {
|
|
433
|
-
const url = new URL(req.url || "/", `http://${req.headers.host}`);
|
|
434
|
-
const path = url.pathname;
|
|
435
|
-
const method = req.method || "GET";
|
|
436
490
|
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
437
491
|
res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
|
|
438
492
|
res.setHeader("Access-Control-Allow-Headers", "Content-Type, X-Payment");
|
|
439
493
|
res.setHeader("Access-Control-Expose-Headers", "X-Payment-Required, X-Payment-Response");
|
|
440
|
-
if (method === "OPTIONS") {
|
|
494
|
+
if (req.method === "OPTIONS") {
|
|
441
495
|
res.writeHead(204);
|
|
442
496
|
res.end();
|
|
443
497
|
return;
|
|
444
498
|
}
|
|
445
499
|
try {
|
|
446
|
-
|
|
500
|
+
const url = new URL(req.url || "/", `http://${req.headers.host}`);
|
|
501
|
+
if (url.pathname === "/services" && req.method === "GET") {
|
|
447
502
|
return this.handleGetServices(res);
|
|
448
503
|
}
|
|
449
|
-
if (
|
|
504
|
+
if (url.pathname === "/execute" && req.method === "POST") {
|
|
450
505
|
const body = await this.readBody(req);
|
|
451
506
|
const paymentHeader = req.headers[PAYMENT_HEADER2];
|
|
452
|
-
return this.handleExecute(body, paymentHeader, res);
|
|
507
|
+
return await this.handleExecute(body, paymentHeader, res);
|
|
453
508
|
}
|
|
454
509
|
this.sendJson(res, 404, { error: "Not found" });
|
|
455
510
|
} catch (err) {
|
|
@@ -461,7 +516,6 @@ var MoltsPayServer = class {
|
|
|
461
516
|
* GET /services - List available services
|
|
462
517
|
*/
|
|
463
518
|
handleGetServices(res) {
|
|
464
|
-
const chain = getChain(this.manifest.provider.chain);
|
|
465
519
|
const services = this.manifest.services.map((s) => ({
|
|
466
520
|
id: s.id,
|
|
467
521
|
name: s.name,
|
|
@@ -477,15 +531,15 @@ var MoltsPayServer = class {
|
|
|
477
531
|
services,
|
|
478
532
|
x402: {
|
|
479
533
|
version: X402_VERSION2,
|
|
480
|
-
network:
|
|
481
|
-
schemes: ["exact"]
|
|
534
|
+
network: this.networkId,
|
|
535
|
+
schemes: ["exact"],
|
|
536
|
+
facilitator: this.cdpConfig.useMainnet ? "cdp" : "x402.org",
|
|
537
|
+
mainnet: this.cdpConfig.useMainnet
|
|
482
538
|
}
|
|
483
539
|
});
|
|
484
540
|
}
|
|
485
541
|
/**
|
|
486
542
|
* POST /execute - Execute service with x402 payment
|
|
487
|
-
* Body: { service: string, params: object }
|
|
488
|
-
* Header: X-Payment (optional - if missing, returns 402)
|
|
489
543
|
*/
|
|
490
544
|
async handleExecute(body, paymentHeader, res) {
|
|
491
545
|
const { service, params } = body;
|
|
@@ -515,6 +569,11 @@ var MoltsPayServer = class {
|
|
|
515
569
|
if (!validation.valid) {
|
|
516
570
|
return this.sendJson(res, 402, { error: validation.error });
|
|
517
571
|
}
|
|
572
|
+
console.log(`[MoltsPay] Verifying payment with facilitator...`);
|
|
573
|
+
const verifyResult = await this.verifyWithFacilitator(payment, skill.config);
|
|
574
|
+
if (!verifyResult.valid) {
|
|
575
|
+
return this.sendJson(res, 402, { error: `Payment verification failed: ${verifyResult.error}` });
|
|
576
|
+
}
|
|
518
577
|
console.log(`[MoltsPay] Executing skill: ${service}`);
|
|
519
578
|
let result;
|
|
520
579
|
try {
|
|
@@ -526,32 +585,46 @@ var MoltsPayServer = class {
|
|
|
526
585
|
message: err.message
|
|
527
586
|
});
|
|
528
587
|
}
|
|
529
|
-
console.log(`[MoltsPay] Skill succeeded,
|
|
530
|
-
let
|
|
588
|
+
console.log(`[MoltsPay] Skill succeeded, settling payment...`);
|
|
589
|
+
let settlement = null;
|
|
531
590
|
try {
|
|
532
|
-
|
|
533
|
-
console.log(`[MoltsPay] Payment
|
|
591
|
+
settlement = await this.settleWithFacilitator(payment, skill.config);
|
|
592
|
+
console.log(`[MoltsPay] Payment settled: ${settlement.transaction || "pending"}`);
|
|
534
593
|
} catch (err) {
|
|
535
|
-
console.error("[MoltsPay]
|
|
594
|
+
console.error("[MoltsPay] Settlement failed:", err.message);
|
|
595
|
+
}
|
|
596
|
+
const responseHeaders = {};
|
|
597
|
+
if (settlement) {
|
|
598
|
+
const responsePayload = {
|
|
599
|
+
success: true,
|
|
600
|
+
transaction: settlement.transaction,
|
|
601
|
+
network: payment.network
|
|
602
|
+
};
|
|
603
|
+
responseHeaders[PAYMENT_RESPONSE_HEADER] = Buffer.from(
|
|
604
|
+
JSON.stringify(responsePayload)
|
|
605
|
+
).toString("base64");
|
|
536
606
|
}
|
|
537
607
|
this.sendJson(res, 200, {
|
|
538
608
|
success: true,
|
|
539
609
|
result,
|
|
540
|
-
payment:
|
|
541
|
-
});
|
|
610
|
+
payment: settlement ? { transaction: settlement.transaction, status: "settled" } : { status: "pending" }
|
|
611
|
+
}, responseHeaders);
|
|
542
612
|
}
|
|
543
613
|
/**
|
|
544
614
|
* Return 402 with x402 payment requirements
|
|
545
615
|
*/
|
|
546
616
|
sendPaymentRequired(config, res) {
|
|
547
|
-
const chain = getChain(this.manifest.provider.chain);
|
|
548
617
|
const amountInUnits = Math.floor(config.price * 1e6).toString();
|
|
549
618
|
const requirements = [{
|
|
550
619
|
scheme: "exact",
|
|
551
|
-
network:
|
|
620
|
+
network: this.networkId,
|
|
552
621
|
maxAmountRequired: amountInUnits,
|
|
553
622
|
resource: this.manifest.provider.wallet,
|
|
554
|
-
description: `${config.name} - $${config.price} ${config.currency}
|
|
623
|
+
description: `${config.name} - $${config.price} ${config.currency}`,
|
|
624
|
+
extra: JSON.stringify({
|
|
625
|
+
facilitator: this.cdpConfig.useMainnet ? "cdp" : "x402.org",
|
|
626
|
+
mainnet: this.cdpConfig.useMainnet
|
|
627
|
+
})
|
|
555
628
|
}];
|
|
556
629
|
const encoded = Buffer.from(JSON.stringify(requirements)).toString("base64");
|
|
557
630
|
res.writeHead(402, {
|
|
@@ -565,7 +638,7 @@ var MoltsPayServer = class {
|
|
|
565
638
|
}, null, 2));
|
|
566
639
|
}
|
|
567
640
|
/**
|
|
568
|
-
*
|
|
641
|
+
* Basic payment validation
|
|
569
642
|
*/
|
|
570
643
|
validatePayment(payment, config) {
|
|
571
644
|
if (payment.x402Version !== X402_VERSION2) {
|
|
@@ -574,56 +647,89 @@ var MoltsPayServer = class {
|
|
|
574
647
|
if (payment.scheme !== "exact") {
|
|
575
648
|
return { valid: false, error: `Unsupported scheme: ${payment.scheme}` };
|
|
576
649
|
}
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
if (payment.network !== expectedNetwork) {
|
|
580
|
-
return { valid: false, error: `Network mismatch: expected ${expectedNetwork}` };
|
|
581
|
-
}
|
|
582
|
-
const auth = payment.payload.authorization;
|
|
583
|
-
if (auth.to.toLowerCase() !== this.manifest.provider.wallet.toLowerCase()) {
|
|
584
|
-
return { valid: false, error: "Payment recipient mismatch" };
|
|
585
|
-
}
|
|
586
|
-
const amount = Number(auth.value) / 1e6;
|
|
587
|
-
if (amount < config.price) {
|
|
588
|
-
return { valid: false, error: `Insufficient amount: $${amount} < $${config.price}` };
|
|
589
|
-
}
|
|
590
|
-
const now = Math.floor(Date.now() / 1e3);
|
|
591
|
-
if (Number(auth.validBefore) < now) {
|
|
592
|
-
return { valid: false, error: "Payment authorization expired" };
|
|
593
|
-
}
|
|
594
|
-
if (Number(auth.validAfter) > now) {
|
|
595
|
-
return { valid: false, error: "Payment authorization not yet valid" };
|
|
650
|
+
if (payment.network !== this.networkId) {
|
|
651
|
+
return { valid: false, error: `Network mismatch: expected ${this.networkId}, got ${payment.network}` };
|
|
596
652
|
}
|
|
597
653
|
return { valid: true };
|
|
598
654
|
}
|
|
599
655
|
/**
|
|
600
|
-
*
|
|
656
|
+
* Verify payment with facilitator (testnet or CDP)
|
|
601
657
|
*/
|
|
602
|
-
async
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
658
|
+
async verifyWithFacilitator(payment, config) {
|
|
659
|
+
try {
|
|
660
|
+
const amountInUnits = Math.floor(config.price * 1e6).toString();
|
|
661
|
+
const requirements = {
|
|
662
|
+
scheme: "exact",
|
|
663
|
+
network: this.networkId,
|
|
664
|
+
maxAmountRequired: amountInUnits,
|
|
665
|
+
resource: this.manifest.provider.wallet,
|
|
666
|
+
payTo: this.manifest.provider.wallet
|
|
667
|
+
};
|
|
668
|
+
const requestBody = {
|
|
669
|
+
paymentPayload: payment,
|
|
670
|
+
paymentRequirements: requirements
|
|
671
|
+
};
|
|
672
|
+
let headers = { "Content-Type": "application/json" };
|
|
673
|
+
if (this.cdpConfig.useMainnet) {
|
|
674
|
+
const authHeaders = await getCDPAuthHeaders(
|
|
675
|
+
"POST",
|
|
676
|
+
"/platform/v2/x402/verify",
|
|
677
|
+
requestBody
|
|
678
|
+
);
|
|
679
|
+
headers = { ...headers, ...authHeaders };
|
|
680
|
+
}
|
|
681
|
+
const response = await fetch(`${this.facilitatorUrl}/verify`, {
|
|
682
|
+
method: "POST",
|
|
683
|
+
headers,
|
|
684
|
+
body: JSON.stringify(requestBody)
|
|
685
|
+
});
|
|
686
|
+
const result = await response.json();
|
|
687
|
+
if (!response.ok || !result.isValid) {
|
|
688
|
+
return { valid: false, error: result.invalidReason || result.error || "Verification failed" };
|
|
689
|
+
}
|
|
690
|
+
return { valid: true };
|
|
691
|
+
} catch (err) {
|
|
692
|
+
return { valid: false, error: `Facilitator error: ${err.message}` };
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
/**
|
|
696
|
+
* Settle payment with facilitator (execute on-chain transfer)
|
|
697
|
+
*/
|
|
698
|
+
async settleWithFacilitator(payment, config) {
|
|
699
|
+
const amountInUnits = Math.floor(config.price * 1e6).toString();
|
|
700
|
+
const requirements = {
|
|
701
|
+
scheme: "exact",
|
|
702
|
+
network: this.networkId,
|
|
703
|
+
maxAmountRequired: amountInUnits,
|
|
704
|
+
resource: this.manifest.provider.wallet,
|
|
705
|
+
payTo: this.manifest.provider.wallet
|
|
706
|
+
};
|
|
707
|
+
const requestBody = {
|
|
708
|
+
paymentPayload: payment,
|
|
709
|
+
paymentRequirements: requirements
|
|
710
|
+
};
|
|
711
|
+
let headers = { "Content-Type": "application/json" };
|
|
712
|
+
if (this.cdpConfig.useMainnet) {
|
|
713
|
+
const authHeaders = await getCDPAuthHeaders(
|
|
714
|
+
"POST",
|
|
715
|
+
"/platform/v2/x402/settle",
|
|
716
|
+
requestBody
|
|
717
|
+
);
|
|
718
|
+
headers = { ...headers, ...authHeaders };
|
|
719
|
+
}
|
|
720
|
+
const response = await fetch(`${this.facilitatorUrl}/settle`, {
|
|
721
|
+
method: "POST",
|
|
722
|
+
headers,
|
|
723
|
+
body: JSON.stringify(requestBody)
|
|
724
|
+
});
|
|
725
|
+
const result = await response.json();
|
|
726
|
+
if (!response.ok || !result.success) {
|
|
727
|
+
throw new Error(result.error || result.errorReason || "Settlement failed");
|
|
728
|
+
}
|
|
729
|
+
return {
|
|
730
|
+
transaction: result.transaction,
|
|
731
|
+
status: result.status || "settled"
|
|
732
|
+
};
|
|
627
733
|
}
|
|
628
734
|
async readBody(req) {
|
|
629
735
|
return new Promise((resolve2, reject) => {
|
|
@@ -639,8 +745,12 @@ var MoltsPayServer = class {
|
|
|
639
745
|
req.on("error", reject);
|
|
640
746
|
});
|
|
641
747
|
}
|
|
642
|
-
sendJson(res, status, data) {
|
|
643
|
-
|
|
748
|
+
sendJson(res, status, data, extraHeaders) {
|
|
749
|
+
const headers = { "Content-Type": "application/json" };
|
|
750
|
+
if (extraHeaders) {
|
|
751
|
+
Object.assign(headers, extraHeaders);
|
|
752
|
+
}
|
|
753
|
+
res.writeHead(status, headers);
|
|
644
754
|
res.end(JSON.stringify(data, null, 2));
|
|
645
755
|
}
|
|
646
756
|
};
|
|
@@ -801,7 +911,7 @@ program.command("services <url>").description("List services from a provider").o
|
|
|
801
911
|
console.error("\u274C Error:", err.message);
|
|
802
912
|
}
|
|
803
913
|
});
|
|
804
|
-
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("--
|
|
914
|
+
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) => {
|
|
805
915
|
const manifestPath = (0, import_path2.resolve)(manifest);
|
|
806
916
|
if (!(0, import_fs3.existsSync)(manifestPath)) {
|
|
807
917
|
console.error(`\u274C Manifest not found: ${manifestPath}`);
|
|
@@ -809,16 +919,15 @@ program.command("start <manifest>").description("Start MoltsPay server from serv
|
|
|
809
919
|
}
|
|
810
920
|
const port = parseInt(options.port, 10);
|
|
811
921
|
const host = options.host;
|
|
812
|
-
const
|
|
922
|
+
const facilitatorUrl = options.facilitator;
|
|
813
923
|
console.log(`
|
|
814
924
|
\u{1F680} Starting MoltsPay Server (x402 protocol)
|
|
815
925
|
`);
|
|
816
926
|
console.log(` Manifest: ${manifestPath}`);
|
|
817
927
|
console.log(` Port: ${port}`);
|
|
818
|
-
console.log(` Payment claims: ${privateKey ? "enabled" : "disabled (no private key)"}`);
|
|
819
928
|
console.log("");
|
|
820
929
|
try {
|
|
821
|
-
const server = new MoltsPayServer(manifestPath, { port, host,
|
|
930
|
+
const server = new MoltsPayServer(manifestPath, { port, host, facilitatorUrl });
|
|
822
931
|
const manifestContent = await import("fs").then(
|
|
823
932
|
(fs) => JSON.parse(fs.readFileSync(manifestPath, "utf-8"))
|
|
824
933
|
);
|