mrmainspring 0.1.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.
Files changed (79) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +47 -0
  3. package/dist/audit/service.d.ts +7 -0
  4. package/dist/audit/service.js +98 -0
  5. package/dist/audit/store.d.ts +7 -0
  6. package/dist/audit/store.js +37 -0
  7. package/dist/audit/supabase-store.d.ts +9 -0
  8. package/dist/audit/supabase-store.js +22 -0
  9. package/dist/audit/types.d.ts +31 -0
  10. package/dist/audit/types.js +1 -0
  11. package/dist/casper/anchorClient.d.ts +99 -0
  12. package/dist/casper/anchorClient.js +412 -0
  13. package/dist/config.d.ts +51 -0
  14. package/dist/config.js +215 -0
  15. package/dist/env-file.d.ts +1 -0
  16. package/dist/env-file.js +51 -0
  17. package/dist/grimoire/service.d.ts +13 -0
  18. package/dist/grimoire/service.js +199 -0
  19. package/dist/grimoire/store.d.ts +10 -0
  20. package/dist/grimoire/store.js +64 -0
  21. package/dist/grimoire/supabase-store.d.ts +13 -0
  22. package/dist/grimoire/supabase-store.js +50 -0
  23. package/dist/grimoire/types.d.ts +60 -0
  24. package/dist/grimoire/types.js +1 -0
  25. package/dist/index.d.ts +2 -0
  26. package/dist/index.js +17 -0
  27. package/dist/mcp/auditTools.d.ts +3 -0
  28. package/dist/mcp/auditTools.js +13 -0
  29. package/dist/mcp/grimoireTools.d.ts +3 -0
  30. package/dist/mcp/grimoireTools.js +91 -0
  31. package/dist/mcp/jsonResult.d.ts +2 -0
  32. package/dist/mcp/jsonResult.js +10 -0
  33. package/dist/mcp/memoryTools.d.ts +3 -0
  34. package/dist/mcp/memoryTools.js +73 -0
  35. package/dist/mcp/paymentTools.d.ts +3 -0
  36. package/dist/mcp/paymentTools.js +33 -0
  37. package/dist/memory/canonical.d.ts +4 -0
  38. package/dist/memory/canonical.js +49 -0
  39. package/dist/memory/hash.d.ts +1 -0
  40. package/dist/memory/hash.js +4 -0
  41. package/dist/memory/service.d.ts +37 -0
  42. package/dist/memory/service.js +175 -0
  43. package/dist/memory/store.d.ts +8 -0
  44. package/dist/memory/store.js +49 -0
  45. package/dist/memory/supabase-store.d.ts +10 -0
  46. package/dist/memory/supabase-store.js +30 -0
  47. package/dist/memory/types.d.ts +56 -0
  48. package/dist/memory/types.js +7 -0
  49. package/dist/payments/service.d.ts +26 -0
  50. package/dist/payments/service.js +613 -0
  51. package/dist/payments/store.d.ts +10 -0
  52. package/dist/payments/store.js +64 -0
  53. package/dist/payments/supabase-store.d.ts +13 -0
  54. package/dist/payments/supabase-store.js +51 -0
  55. package/dist/payments/types.d.ts +101 -0
  56. package/dist/payments/types.js +1 -0
  57. package/dist/server.d.ts +5 -0
  58. package/dist/server.js +68 -0
  59. package/dist/storage/json-file-store.d.ts +17 -0
  60. package/dist/storage/json-file-store.js +87 -0
  61. package/dist/storage/store-factory.d.ts +12 -0
  62. package/dist/storage/store-factory.js +26 -0
  63. package/dist/storage/supabase-rest.d.ts +26 -0
  64. package/dist/storage/supabase-rest.js +85 -0
  65. package/dist/x402/client.d.ts +44 -0
  66. package/dist/x402/client.js +95 -0
  67. package/dist/x402/facilitator.d.ts +84 -0
  68. package/dist/x402/facilitator.js +800 -0
  69. package/dist/x402/readiness.d.ts +55 -0
  70. package/dist/x402/readiness.js +433 -0
  71. package/dist/x402/redaction.d.ts +1 -0
  72. package/dist/x402/redaction.js +30 -0
  73. package/dist/x402/resource.d.ts +69 -0
  74. package/dist/x402/resource.js +325 -0
  75. package/dist/x402/settlement.d.ts +176 -0
  76. package/dist/x402/settlement.js +1210 -0
  77. package/dist/x402/signer.d.ts +71 -0
  78. package/dist/x402/signer.js +616 -0
  79. package/package.json +61 -0
@@ -0,0 +1,1210 @@
1
+ import { spawn } from "node:child_process";
2
+ import { extractCasperTransactionHash } from "../casper/anchorClient.js";
3
+ import { canonicalizeJson, toJsonObject, toJsonValue } from "../memory/canonical.js";
4
+ import { sha256Hex } from "../memory/hash.js";
5
+ import { redactX402Value } from "./redaction.js";
6
+ import { validateX402PaymentPayload, verifyX402SettlementResponse } from "./readiness.js";
7
+ export class DisabledX402SettlementProvider {
8
+ blocker;
9
+ constructor(blocker = "x402_settlement_disabled") {
10
+ this.blocker = blocker;
11
+ }
12
+ async settle(input) {
13
+ return {
14
+ status: "unavailable",
15
+ blocker: this.blocker,
16
+ signed_payload_hash: null,
17
+ response_status: null,
18
+ casper_transaction_hash: null,
19
+ receipt_json: settlementReceiptJson({
20
+ status: "settlement_unavailable",
21
+ blocker: this.blocker,
22
+ payment_id: input.payment_id,
23
+ selected_requirement_hash: input.selected_requirement_hash,
24
+ facilitator_url: input.facilitator_url
25
+ })
26
+ };
27
+ }
28
+ }
29
+ export class DisabledX402SigningProvider {
30
+ async sign() {
31
+ return {
32
+ signed: false,
33
+ blocker: "x402_signing_provider_not_configured"
34
+ };
35
+ }
36
+ }
37
+ export class HttpX402SigningProvider {
38
+ config;
39
+ constructor(config) {
40
+ this.config = config;
41
+ }
42
+ async sign(input) {
43
+ if (!this.config.signerUrl) {
44
+ return {
45
+ signed: false,
46
+ blocker: "x402_signing_provider_not_configured"
47
+ };
48
+ }
49
+ let response;
50
+ try {
51
+ response = await postSignerJson(this.config, {
52
+ payment_id: input.payment_id,
53
+ facilitator_url: input.facilitator_url,
54
+ method: input.method,
55
+ url: input.url,
56
+ selected_requirement: input.selected_requirement,
57
+ selected_requirement_hash: input.selected_requirement_hash,
58
+ policy_hash: input.policy_hash
59
+ });
60
+ }
61
+ catch {
62
+ return {
63
+ signed: false,
64
+ blocker: "x402_signer_request_failed"
65
+ };
66
+ }
67
+ const text = await response.text();
68
+ if (!response.ok) {
69
+ return {
70
+ signed: false,
71
+ blocker: "x402_signer_request_failed"
72
+ };
73
+ }
74
+ const body = parseJsonOrRaw(text);
75
+ const signedPayload = extractSignedPayload(body);
76
+ if (!signedPayload) {
77
+ return {
78
+ signed: false,
79
+ blocker: "x402_signer_response_invalid"
80
+ };
81
+ }
82
+ const payloadApproval = validateX402PaymentPayload(signedPayload, input.selected_requirement_hash, {
83
+ now: this.config.now?.() ?? new Date(),
84
+ maxValiditySeconds: this.config.maxValiditySeconds ?? null
85
+ });
86
+ if (!payloadApproval.approved) {
87
+ return {
88
+ signed: false,
89
+ blocker: "x402_signer_response_invalid"
90
+ };
91
+ }
92
+ return {
93
+ signed: true,
94
+ signed_payload: signedPayload,
95
+ signed_payload_hash: createSignedPayloadHash(signedPayload)
96
+ };
97
+ }
98
+ }
99
+ export class CasperCliX402SettlementProvider {
100
+ signer;
101
+ config;
102
+ commandRunner;
103
+ constructor(signer, config, commandRunner = runCasperCommand) {
104
+ this.signer = signer;
105
+ this.config = config;
106
+ this.commandRunner = commandRunner;
107
+ }
108
+ async settle(input) {
109
+ const config = validateX402CasperCliSettlementConfig(this.config);
110
+ if (!config) {
111
+ return {
112
+ status: "unavailable",
113
+ blocker: "x402_casper_settlement_not_configured",
114
+ signed_payload_hash: null,
115
+ response_status: null,
116
+ casper_transaction_hash: null,
117
+ receipt_json: settlementReceiptJson({
118
+ status: "settlement_unavailable",
119
+ blocker: "x402_casper_settlement_not_configured",
120
+ payment_id: input.payment_id,
121
+ selected_requirement_hash: input.selected_requirement_hash,
122
+ facilitator_url: input.facilitator_url
123
+ })
124
+ };
125
+ }
126
+ if (!config.submissionEnabled) {
127
+ return {
128
+ status: "unavailable",
129
+ blocker: "x402_casper_transaction_submission_disabled",
130
+ signed_payload_hash: null,
131
+ response_status: null,
132
+ casper_transaction_hash: null,
133
+ receipt_json: settlementReceiptJson({
134
+ status: "settlement_unavailable",
135
+ blocker: "x402_casper_transaction_submission_disabled",
136
+ payment_id: input.payment_id,
137
+ selected_requirement_hash: input.selected_requirement_hash,
138
+ facilitator_url: input.facilitator_url
139
+ })
140
+ };
141
+ }
142
+ const signed = await this.signer.sign(input);
143
+ if (!signed.signed) {
144
+ return {
145
+ status: "unavailable",
146
+ blocker: signed.blocker,
147
+ signed_payload_hash: null,
148
+ response_status: null,
149
+ casper_transaction_hash: null,
150
+ receipt_json: settlementReceiptJson({
151
+ status: "settlement_unavailable",
152
+ blocker: signed.blocker,
153
+ payment_id: input.payment_id,
154
+ selected_requirement_hash: input.selected_requirement_hash,
155
+ facilitator_url: input.facilitator_url
156
+ })
157
+ };
158
+ }
159
+ const payloadApproval = validateX402PaymentPayload(signed.signed_payload, input.selected_requirement_hash, {
160
+ now: config.now?.() ?? new Date(),
161
+ maxValiditySeconds: config.maxValiditySeconds ?? null
162
+ });
163
+ if (!payloadApproval.approved) {
164
+ return casperSettlementFailedOutcome({
165
+ input,
166
+ blocker: "x402_casper_payment_payload_invalid",
167
+ signedPayloadHash: signed.signed_payload_hash,
168
+ transactionHash: null,
169
+ receipt: {
170
+ status: "casper_payment_payload_invalid",
171
+ reason: payloadApproval.reason
172
+ }
173
+ });
174
+ }
175
+ const payment = extractCasperSettlementPayment(signed.signed_payload, input.selected_requirement, input.selected_requirement_hash, config);
176
+ if (!payment) {
177
+ return casperSettlementFailedOutcome({
178
+ input,
179
+ blocker: "x402_casper_payment_payload_invalid",
180
+ signedPayloadHash: signed.signed_payload_hash,
181
+ transactionHash: null,
182
+ receipt: {
183
+ status: "casper_payment_payload_invalid"
184
+ }
185
+ });
186
+ }
187
+ const invocation = buildCasperX402SettlementCommand(config, payment);
188
+ let putResult;
189
+ try {
190
+ putResult = await this.commandRunner(invocation.command, invocation.args);
191
+ }
192
+ catch {
193
+ return casperSettlementFailedOutcome({
194
+ input,
195
+ blocker: "x402_casper_transaction_submission_failed",
196
+ signedPayloadHash: signed.signed_payload_hash,
197
+ transactionHash: null,
198
+ receipt: {
199
+ status: "casper_transaction_submission_failed",
200
+ command: commandReceipt(invocation)
201
+ }
202
+ });
203
+ }
204
+ if (putResult.exitCode !== 0) {
205
+ return casperSettlementFailedOutcome({
206
+ input,
207
+ blocker: "x402_casper_transaction_submission_failed",
208
+ signedPayloadHash: signed.signed_payload_hash,
209
+ transactionHash: null,
210
+ receipt: {
211
+ status: "casper_transaction_submission_failed",
212
+ command: commandReceipt(invocation),
213
+ result: commandResultReceipt(putResult)
214
+ }
215
+ });
216
+ }
217
+ const transactionHash = extractCasperTransactionHash(putResult);
218
+ if (!transactionHash) {
219
+ return casperSettlementFailedOutcome({
220
+ input,
221
+ blocker: "x402_casper_transaction_hash_missing",
222
+ signedPayloadHash: signed.signed_payload_hash,
223
+ transactionHash: null,
224
+ receipt: {
225
+ status: "casper_transaction_hash_missing",
226
+ command: commandReceipt(invocation),
227
+ result: commandResultReceipt(putResult)
228
+ }
229
+ });
230
+ }
231
+ const execution = await this.waitForExecution(config, transactionHash);
232
+ if (execution.status === "lookup_failed") {
233
+ return casperSettlementFailedOutcome({
234
+ input,
235
+ blocker: "x402_casper_transaction_lookup_failed",
236
+ signedPayloadHash: signed.signed_payload_hash,
237
+ transactionHash,
238
+ receipt: {
239
+ status: "casper_transaction_lookup_failed",
240
+ transactionHash,
241
+ result: commandResultReceipt(execution.result)
242
+ }
243
+ });
244
+ }
245
+ if (execution.status === "not_executed") {
246
+ return casperSettlementFailedOutcome({
247
+ input,
248
+ blocker: "x402_casper_transaction_execution_unavailable",
249
+ signedPayloadHash: signed.signed_payload_hash,
250
+ transactionHash,
251
+ receipt: {
252
+ status: "casper_transaction_execution_unavailable",
253
+ transactionHash,
254
+ receipt: execution.receipt
255
+ }
256
+ });
257
+ }
258
+ if (execution.status === "failed") {
259
+ return casperSettlementFailedOutcome({
260
+ input,
261
+ blocker: "x402_casper_transaction_execution_failed",
262
+ signedPayloadHash: signed.signed_payload_hash,
263
+ transactionHash,
264
+ receipt: {
265
+ status: "casper_transaction_execution_failed",
266
+ transactionHash,
267
+ error_message: execution.errorMessage,
268
+ receipt: execution.receipt
269
+ }
270
+ });
271
+ }
272
+ return {
273
+ status: "settled",
274
+ signed_payload_hash: signed.signed_payload_hash,
275
+ response_status: 200,
276
+ casper_transaction_hash: transactionHash,
277
+ receipt_json: settlementReceiptJson({
278
+ success: true,
279
+ status: "settled",
280
+ transactionHash,
281
+ transaction: transactionHash,
282
+ network: payment.network,
283
+ asset: settlementAssetReceipt(payment),
284
+ amount: payment.amount,
285
+ payer: settlementPayerReceipt(payment, signed.signed_payload),
286
+ payTo: settlementPayeeReceipt(payment),
287
+ payment_id: input.payment_id,
288
+ selected_requirement_hash: input.selected_requirement_hash,
289
+ nonce_hash: sha256Hex(payment.nonce),
290
+ execution: execution.receipt
291
+ })
292
+ };
293
+ }
294
+ async waitForExecution(config, transactionHash) {
295
+ const timeoutMs = config.confirmationTimeoutMs ?? 120_000;
296
+ const pollIntervalMs = config.confirmationPollIntervalMs ?? 2_000;
297
+ const deadline = Date.now() + timeoutMs;
298
+ for (;;) {
299
+ const invocation = buildCasperGetTransactionCommand(config, transactionHash);
300
+ let result;
301
+ try {
302
+ result = await this.commandRunner(invocation.command, invocation.args);
303
+ }
304
+ catch {
305
+ return {
306
+ status: "lookup_failed",
307
+ result: { exitCode: 1, stdout: "", stderr: "casper-client get-transaction failed" }
308
+ };
309
+ }
310
+ if (result.exitCode !== 0) {
311
+ return { status: "lookup_failed", result };
312
+ }
313
+ const execution = verifyCasperTransactionExecution(result);
314
+ if (execution.status !== "not_executed") {
315
+ return execution;
316
+ }
317
+ if (Date.now() >= deadline) {
318
+ return execution;
319
+ }
320
+ await delay(Math.min(pollIntervalMs, Math.max(0, deadline - Date.now())));
321
+ }
322
+ }
323
+ }
324
+ export class FacilitatorX402SettlementProvider {
325
+ signer;
326
+ postJson;
327
+ config;
328
+ constructor(signer, postJson = postJsonWithFetch, config = {}) {
329
+ this.signer = signer;
330
+ this.postJson = postJson;
331
+ this.config = config;
332
+ }
333
+ async settle(input) {
334
+ const signed = await this.signer.sign(input);
335
+ if (!signed.signed) {
336
+ return {
337
+ status: "unavailable",
338
+ blocker: signed.blocker,
339
+ signed_payload_hash: null,
340
+ response_status: null,
341
+ casper_transaction_hash: null,
342
+ receipt_json: settlementReceiptJson({
343
+ status: "settlement_unavailable",
344
+ blocker: signed.blocker,
345
+ payment_id: input.payment_id,
346
+ selected_requirement_hash: input.selected_requirement_hash,
347
+ facilitator_url: input.facilitator_url
348
+ })
349
+ };
350
+ }
351
+ const payloadApproval = validateX402PaymentPayload(signed.signed_payload, input.selected_requirement_hash, {
352
+ now: this.config.now?.() ?? new Date(),
353
+ maxValiditySeconds: this.config.maxValiditySeconds ?? null
354
+ });
355
+ if (!payloadApproval.approved) {
356
+ return signerPayloadInvalidOutcome(input);
357
+ }
358
+ const verify = await this.postJson(facilitatorEndpoint(input.facilitator_url, "verify"), {
359
+ paymentPayload: signed.signed_payload,
360
+ paymentRequirements: input.selected_requirement
361
+ });
362
+ const verifyObject = tryJsonObject(verify.body);
363
+ if (!verifyObject) {
364
+ return {
365
+ status: "failed",
366
+ blocker: "x402_facilitator_verify_failed",
367
+ signed_payload_hash: signed.signed_payload_hash,
368
+ response_status: verify.status,
369
+ casper_transaction_hash: null,
370
+ receipt_json: settlementReceiptJson({
371
+ status: "verify_failed",
372
+ payment_id: input.payment_id,
373
+ selected_requirement_hash: input.selected_requirement_hash,
374
+ facilitator_url: input.facilitator_url,
375
+ verify_response: verify.body
376
+ })
377
+ };
378
+ }
379
+ const verifyAccepted = verify.status >= 200 &&
380
+ verify.status < 300 &&
381
+ (verifyObject.valid === true || verifyObject.success === true);
382
+ if (!verifyAccepted) {
383
+ return {
384
+ status: "failed",
385
+ blocker: "x402_facilitator_verify_failed",
386
+ signed_payload_hash: signed.signed_payload_hash,
387
+ response_status: verify.status,
388
+ casper_transaction_hash: null,
389
+ receipt_json: settlementReceiptJson({
390
+ status: "verify_failed",
391
+ payment_id: input.payment_id,
392
+ selected_requirement_hash: input.selected_requirement_hash,
393
+ facilitator_url: input.facilitator_url,
394
+ verify_response: verifyObject
395
+ })
396
+ };
397
+ }
398
+ const settle = await this.postJson(facilitatorEndpoint(input.facilitator_url, "settle"), {
399
+ paymentPayload: signed.signed_payload,
400
+ paymentRequirements: input.selected_requirement
401
+ });
402
+ const settlement = verifyX402SettlementResponse(settle.body, {
403
+ selectedRequirement: input.selected_requirement,
404
+ signedPayload: signed.signed_payload
405
+ });
406
+ if (!settlement.settled) {
407
+ return {
408
+ status: "failed",
409
+ blocker: settle.status >= 200 && settle.status < 300
410
+ ? "x402_facilitator_settlement_not_verified"
411
+ : "x402_facilitator_settle_failed",
412
+ signed_payload_hash: signed.signed_payload_hash,
413
+ response_status: settle.status,
414
+ casper_transaction_hash: null,
415
+ receipt_json: settlement.receipt_json ??
416
+ settlementReceiptJson({
417
+ status: "settle_failed",
418
+ payment_id: input.payment_id,
419
+ selected_requirement_hash: input.selected_requirement_hash,
420
+ facilitator_url: input.facilitator_url,
421
+ settle_response: settle.body
422
+ })
423
+ };
424
+ }
425
+ return {
426
+ status: "settled",
427
+ signed_payload_hash: signed.signed_payload_hash,
428
+ response_status: settle.status,
429
+ casper_transaction_hash: settlement.transaction_hash,
430
+ receipt_json: settlement.receipt_json
431
+ };
432
+ }
433
+ }
434
+ export class ResourceRetryX402SettlementProvider {
435
+ signer;
436
+ resourceFetch;
437
+ paymentHeaderName;
438
+ now;
439
+ maxValiditySeconds;
440
+ constructor(signer, resourceFetch = fetchPaidResource, config = {}) {
441
+ this.signer = signer;
442
+ this.resourceFetch = resourceFetch;
443
+ this.paymentHeaderName = config.paymentHeaderName ?? "PAYMENT-SIGNATURE";
444
+ this.now = config.now ?? (() => new Date());
445
+ this.maxValiditySeconds = config.maxValiditySeconds ?? null;
446
+ }
447
+ async settle(input) {
448
+ const signed = await this.signer.sign(input);
449
+ if (!signed.signed) {
450
+ return {
451
+ status: "unavailable",
452
+ blocker: signed.blocker,
453
+ signed_payload_hash: null,
454
+ response_status: null,
455
+ casper_transaction_hash: null,
456
+ receipt_json: settlementReceiptJson({
457
+ status: "settlement_unavailable",
458
+ blocker: signed.blocker,
459
+ payment_id: input.payment_id,
460
+ selected_requirement_hash: input.selected_requirement_hash,
461
+ facilitator_url: input.facilitator_url
462
+ })
463
+ };
464
+ }
465
+ const payloadApproval = validateX402PaymentPayload(signed.signed_payload, input.selected_requirement_hash, {
466
+ now: this.now(),
467
+ maxValiditySeconds: this.maxValiditySeconds
468
+ });
469
+ if (!payloadApproval.approved) {
470
+ return signerPayloadInvalidOutcome(input);
471
+ }
472
+ const paymentHeader = encodePaymentHeader(signed.signed_payload);
473
+ let paidResponse;
474
+ try {
475
+ paidResponse = await this.resourceFetch(input.url, {
476
+ method: input.method,
477
+ headers: {
478
+ [this.paymentHeaderName]: paymentHeader
479
+ }
480
+ });
481
+ }
482
+ catch {
483
+ return {
484
+ status: "failed",
485
+ blocker: "x402_paid_resource_fetch_failed",
486
+ signed_payload_hash: signed.signed_payload_hash,
487
+ response_status: null,
488
+ casper_transaction_hash: null,
489
+ receipt_json: settlementReceiptJson({
490
+ status: "paid_resource_fetch_failed",
491
+ payment_id: input.payment_id,
492
+ selected_requirement_hash: input.selected_requirement_hash,
493
+ facilitator_url: input.facilitator_url
494
+ })
495
+ };
496
+ }
497
+ const paymentResponse = parsePaymentResponseHeader(paidResponse.headers);
498
+ const settlement = verifyX402SettlementResponse(paymentResponse, {
499
+ selectedRequirement: input.selected_requirement,
500
+ signedPayload: signed.signed_payload
501
+ });
502
+ const bodyHash = sha256Hex(paidResponse.bodyText);
503
+ if (!paidResponseOk(paidResponse.status)) {
504
+ return {
505
+ status: "failed",
506
+ blocker: paidResponse.status === 402
507
+ ? "x402_paid_resource_still_requires_payment"
508
+ : "x402_paid_resource_fetch_failed",
509
+ signed_payload_hash: signed.signed_payload_hash,
510
+ response_status: paidResponse.status,
511
+ casper_transaction_hash: null,
512
+ receipt_json: settlementReceiptJson({
513
+ status: "paid_resource_failed",
514
+ payment_id: input.payment_id,
515
+ selected_requirement_hash: input.selected_requirement_hash,
516
+ facilitator_url: input.facilitator_url,
517
+ resource_response_status: paidResponse.status,
518
+ resource_response_hash: bodyHash,
519
+ payment_response: paymentResponse
520
+ })
521
+ };
522
+ }
523
+ if (!settlement.settled) {
524
+ return {
525
+ status: "failed",
526
+ blocker: "x402_paid_resource_settlement_not_verified",
527
+ signed_payload_hash: signed.signed_payload_hash,
528
+ response_status: paidResponse.status,
529
+ casper_transaction_hash: null,
530
+ receipt_json: settlementReceiptJson({
531
+ status: "paid_resource_settlement_not_verified",
532
+ reason: settlement.reason,
533
+ payment_id: input.payment_id,
534
+ selected_requirement_hash: input.selected_requirement_hash,
535
+ facilitator_url: input.facilitator_url,
536
+ resource_response_status: paidResponse.status,
537
+ resource_response_hash: bodyHash,
538
+ payment_response: paymentResponse
539
+ })
540
+ };
541
+ }
542
+ return {
543
+ status: "settled",
544
+ signed_payload_hash: signed.signed_payload_hash,
545
+ response_status: paidResponse.status,
546
+ casper_transaction_hash: settlement.transaction_hash,
547
+ receipt_json: settlementReceiptJson({
548
+ status: "settled",
549
+ payment_id: input.payment_id,
550
+ selected_requirement_hash: input.selected_requirement_hash,
551
+ facilitator_url: input.facilitator_url,
552
+ resource_response_status: paidResponse.status,
553
+ resource_response_hash: bodyHash,
554
+ payment_response: JSON.parse(settlement.receipt_json)
555
+ })
556
+ };
557
+ }
558
+ }
559
+ export function createSignedPayloadHash(payload) {
560
+ return sha256Hex(canonicalizeJson(payload));
561
+ }
562
+ export function validateX402CasperCliSettlementConfig(config) {
563
+ if (!config.rpcUrl || !config.accountKeyPath) {
564
+ return null;
565
+ }
566
+ return {
567
+ ...config,
568
+ rpcUrl: config.rpcUrl,
569
+ accountKeyPath: config.accountKeyPath
570
+ };
571
+ }
572
+ export function buildCasperX402SettlementCommand(config, payment) {
573
+ if (payment.settlementKind === "native-transfer") {
574
+ return wrapCasperX402Command(config, [
575
+ "put-transaction",
576
+ "transfer",
577
+ "--node-address",
578
+ config.rpcUrl,
579
+ "--chain-name",
580
+ config.networkName,
581
+ "--secret-key",
582
+ config.accountKeyPath,
583
+ "--target",
584
+ payment.target,
585
+ "--transfer-amount",
586
+ payment.amount,
587
+ "--gas-price-tolerance",
588
+ config.gasPriceTolerance,
589
+ "--pricing-mode",
590
+ config.pricingMode,
591
+ "--payment-amount",
592
+ config.paymentAmountMotes,
593
+ "--standard-payment",
594
+ "true"
595
+ ]);
596
+ }
597
+ return wrapCasperX402Command(config, [
598
+ "put-transaction",
599
+ "package",
600
+ "--node-address",
601
+ config.rpcUrl,
602
+ "--chain-name",
603
+ config.networkName,
604
+ "--contract-package-hash",
605
+ `hash-${payment.assetPackageHash}`,
606
+ "--session-entry-point",
607
+ "transfer_with_authorization",
608
+ "--gas-price-tolerance",
609
+ config.gasPriceTolerance,
610
+ "--pricing-mode",
611
+ config.pricingMode,
612
+ "--payment-amount",
613
+ config.paymentAmountMotes,
614
+ "--standard-payment",
615
+ "true",
616
+ "--secret-key",
617
+ config.accountKeyPath,
618
+ "--session-arg",
619
+ sessionArg("from", "key", accountKeyArg(payment.from)),
620
+ "--session-arg",
621
+ sessionArg("to", "key", accountKeyArg(payment.to)),
622
+ "--session-arg",
623
+ sessionArg("amount", "u256", payment.amount),
624
+ "--session-arg",
625
+ sessionArg("valid_after", "i64", payment.validAfter),
626
+ "--session-arg",
627
+ sessionArg("valid_before", "i64", payment.validBefore),
628
+ "--session-arg",
629
+ sessionArg("nonce", "byte_array", payment.nonce),
630
+ "--session-arg",
631
+ sessionArg("public_key", "public_key", payment.publicKey),
632
+ "--session-arg",
633
+ sessionArg("signature", "byte_array", payment.signature)
634
+ ]);
635
+ }
636
+ export function buildCasperGetTransactionCommand(config, transactionHash) {
637
+ return wrapCasperX402Command(config, [
638
+ "get-transaction",
639
+ "--node-address",
640
+ config.rpcUrl,
641
+ transactionHash
642
+ ]);
643
+ }
644
+ export function verifyCasperTransactionExecution(result) {
645
+ const parsed = parseCasperClientOutput(result.stdout) ?? parseCasperClientOutput(result.stderr);
646
+ const receipt = parsed ?? { raw: [result.stdout, result.stderr].filter(Boolean).join("\n") };
647
+ const executionInfo = findExecutionInfo(receipt);
648
+ if (!executionInfo) {
649
+ return {
650
+ status: "not_executed",
651
+ receipt
652
+ };
653
+ }
654
+ const errorMessage = findExecutionErrorMessage(executionInfo);
655
+ if (errorMessage) {
656
+ return {
657
+ status: "failed",
658
+ errorMessage,
659
+ receipt
660
+ };
661
+ }
662
+ return {
663
+ status: "success",
664
+ receipt
665
+ };
666
+ }
667
+ function casperSettlementFailedOutcome(failure) {
668
+ return {
669
+ status: "failed",
670
+ blocker: failure.blocker,
671
+ signed_payload_hash: failure.signedPayloadHash,
672
+ response_status: null,
673
+ casper_transaction_hash: failure.transactionHash,
674
+ receipt_json: settlementReceiptJson({
675
+ payment_id: failure.input.payment_id,
676
+ selected_requirement_hash: failure.input.selected_requirement_hash,
677
+ facilitator_url: failure.input.facilitator_url,
678
+ ...(asRecord(failure.receipt) ?? {})
679
+ })
680
+ };
681
+ }
682
+ function signerPayloadInvalidOutcome(input) {
683
+ return {
684
+ status: "unavailable",
685
+ blocker: "x402_signer_response_invalid",
686
+ signed_payload_hash: null,
687
+ response_status: null,
688
+ casper_transaction_hash: null,
689
+ receipt_json: settlementReceiptJson({
690
+ status: "settlement_unavailable",
691
+ blocker: "x402_signer_response_invalid",
692
+ payment_id: input.payment_id,
693
+ selected_requirement_hash: input.selected_requirement_hash,
694
+ facilitator_url: input.facilitator_url
695
+ })
696
+ };
697
+ }
698
+ function extractCasperSettlementPayment(signedPayload, selectedRequirement, selectedRequirementHash, config) {
699
+ const root = asRecord(signedPayload);
700
+ if (!root) {
701
+ return null;
702
+ }
703
+ const paymentPayload = asRecord(root.payload) ?? root;
704
+ const authorization = asRecord(paymentPayload.authorization) ?? asRecord(root.authorization);
705
+ if (!authorization) {
706
+ return null;
707
+ }
708
+ const acceptedRequirement = asRecord(root.accepted);
709
+ const scheme = firstString(root, ["scheme"]) ?? firstString(acceptedRequirement, ["scheme"]);
710
+ if (scheme !== "exact") {
711
+ return null;
712
+ }
713
+ const network = firstString(root, ["network"]) ??
714
+ firstString(acceptedRequirement, ["network"]) ??
715
+ firstString(selectedRequirement, ["network", "networkId", "network_id", "caip2_chain_id"]);
716
+ if (!network || !networkMatches(network, config.caip2ChainId)) {
717
+ return null;
718
+ }
719
+ const requirementNetwork = firstString(selectedRequirement, [
720
+ "network",
721
+ "networkId",
722
+ "network_id",
723
+ "caip2_chain_id"
724
+ ]);
725
+ if (requirementNetwork && !networkMatches(network, requirementNetwork)) {
726
+ return null;
727
+ }
728
+ const payloadRequirementHash = firstString(root, [
729
+ "selectedRequirementHash",
730
+ "selected_requirement_hash"
731
+ ]);
732
+ if (payloadRequirementHash !== selectedRequirementHash) {
733
+ return null;
734
+ }
735
+ const requirementAmount = firstString(selectedRequirement, [
736
+ "amount",
737
+ "maxAmountRequired",
738
+ "max_amount_required"
739
+ ]);
740
+ if (!requirementAmount || !isUnsignedIntegerString(requirementAmount)) {
741
+ return null;
742
+ }
743
+ const assetValue = firstString(selectedRequirement, [
744
+ "asset",
745
+ "assetId",
746
+ "asset_id",
747
+ "assetPackage",
748
+ "asset_package"
749
+ ]);
750
+ const nonce = normalizeHex(firstString(authorization, ["nonce"]) ?? firstString(root, ["nonce"]), 64);
751
+ if (!nonce) {
752
+ return null;
753
+ }
754
+ if (assetValue?.toLowerCase() === "casper-native-cspr") {
755
+ const target = normalizeCasperTransferTarget(firstString(selectedRequirement, ["payTo", "pay_to", "payee", "recipient"]));
756
+ if (!target) {
757
+ return null;
758
+ }
759
+ return {
760
+ settlementKind: "native-transfer",
761
+ scheme: "exact",
762
+ network,
763
+ assetId: "casper-native-cspr",
764
+ target,
765
+ amount: requirementAmount,
766
+ nonce
767
+ };
768
+ }
769
+ const assetPackageHash = normalizeCasperPackageHash(assetValue);
770
+ if (!assetPackageHash) {
771
+ return null;
772
+ }
773
+ const from = normalizeCasperAccountAddress(firstString(authorization, ["from"]));
774
+ const to = normalizeCasperAccountAddress(firstString(authorization, ["to"]));
775
+ const amount = firstString(authorization, ["value", "amount"]);
776
+ const validAfter = unixSecondsString(firstString(authorization, ["validAfter", "valid_after"]));
777
+ const validBefore = unixSecondsString(firstString(authorization, ["validBefore", "valid_before"]));
778
+ const publicKey = normalizePublicKey(firstString(paymentPayload, ["publicKey", "public_key"]) ??
779
+ firstString(authorization, ["publicKey", "public_key"]));
780
+ const signature = normalizeHex(firstString(paymentPayload, ["signature"]) ?? firstString(authorization, ["signature"]), 130);
781
+ if (!from ||
782
+ !to ||
783
+ !amount ||
784
+ !isUnsignedIntegerString(amount) ||
785
+ !validAfter ||
786
+ !validBefore ||
787
+ !nonce ||
788
+ !publicKey ||
789
+ !signature) {
790
+ return null;
791
+ }
792
+ if (BigInt(validBefore) <= BigInt(validAfter)) {
793
+ return null;
794
+ }
795
+ const nowSeconds = BigInt(Math.floor((config.now?.() ?? new Date()).getTime() / 1000));
796
+ if (BigInt(validAfter) > nowSeconds) {
797
+ return null;
798
+ }
799
+ if (BigInt(validBefore) <= nowSeconds) {
800
+ return null;
801
+ }
802
+ const payer = normalizeCasperAccountAddress(firstString(root, ["payer", "payerAccount", "payer_account"]));
803
+ if (payer && payer !== from) {
804
+ return null;
805
+ }
806
+ if (requirementAmount && requirementAmount !== amount) {
807
+ return null;
808
+ }
809
+ const requirementPayTo = normalizeCasperAccountAddress(firstString(selectedRequirement, ["payTo", "pay_to", "payee", "recipient"]));
810
+ if (requirementPayTo && requirementPayTo !== to) {
811
+ return null;
812
+ }
813
+ return {
814
+ settlementKind: "cep18-transfer-with-authorization",
815
+ scheme: "exact",
816
+ network,
817
+ assetPackageHash,
818
+ from,
819
+ to,
820
+ amount,
821
+ validAfter,
822
+ validBefore,
823
+ nonce,
824
+ publicKey,
825
+ signature
826
+ };
827
+ }
828
+ function runCasperCommand(command, args) {
829
+ return new Promise((resolve, reject) => {
830
+ const child = spawn(command, args, {
831
+ shell: false,
832
+ windowsHide: true
833
+ });
834
+ let stdout = "";
835
+ let stderr = "";
836
+ child.stdout.setEncoding("utf8");
837
+ child.stderr.setEncoding("utf8");
838
+ child.stdout.on("data", (chunk) => {
839
+ stdout += chunk;
840
+ });
841
+ child.stderr.on("data", (chunk) => {
842
+ stderr += chunk;
843
+ });
844
+ child.on("error", reject);
845
+ child.on("close", (code) => {
846
+ resolve({
847
+ exitCode: code ?? 1,
848
+ stdout,
849
+ stderr
850
+ });
851
+ });
852
+ });
853
+ }
854
+ function wrapCasperX402Command(config, args) {
855
+ if (!config.clientWslDistro) {
856
+ return {
857
+ command: config.clientBin,
858
+ args
859
+ };
860
+ }
861
+ return {
862
+ command: "wsl",
863
+ args: ["-d", config.clientWslDistro, "--", config.clientBin, ...args]
864
+ };
865
+ }
866
+ function sessionArg(name, type, value) {
867
+ return `${name}:${type}='${value}'`;
868
+ }
869
+ function accountKeyArg(value) {
870
+ const normalized = normalizeCasperAccountAddress(value);
871
+ if (!normalized) {
872
+ throw new Error("Invalid Casper account address");
873
+ }
874
+ return `account-hash-${normalized.slice(2)}`;
875
+ }
876
+ function commandReceipt(invocation) {
877
+ return {
878
+ command: invocation.command,
879
+ args: invocation.args.map((arg, index) => redactCommandArg(arg, invocation.args[index - 1] ?? null))
880
+ };
881
+ }
882
+ function redactCommandArg(arg, previousArg) {
883
+ if (previousArg === "--secret-key") {
884
+ return "<redacted>";
885
+ }
886
+ if (previousArg !== "--session-arg") {
887
+ return arg;
888
+ }
889
+ const sessionArgMatch = arg.match(/^([^:]+):([^=]+)='(.*)'$/);
890
+ if (!sessionArgMatch) {
891
+ return arg;
892
+ }
893
+ const [, name, type, value] = sessionArgMatch;
894
+ if (!name || !type) {
895
+ return arg;
896
+ }
897
+ if (/signature|public_key|private_key|secret|authorization|nonce/i.test(name)) {
898
+ return `${name}:${type}='<redacted:${sha256Hex(value ?? "")}>'`;
899
+ }
900
+ return arg;
901
+ }
902
+ function commandResultReceipt(result) {
903
+ return {
904
+ exit_code: result.exitCode,
905
+ stdout_hash: result.stdout ? sha256Hex(result.stdout) : null,
906
+ stderr_hash: result.stderr ? sha256Hex(result.stderr) : null,
907
+ stdout_bytes: Buffer.byteLength(result.stdout, "utf8"),
908
+ stderr_bytes: Buffer.byteLength(result.stderr, "utf8")
909
+ };
910
+ }
911
+ function parseCasperClientOutput(output) {
912
+ const trimmed = output.trim();
913
+ if (!trimmed) {
914
+ return null;
915
+ }
916
+ for (const candidate of [trimmed, jsonObjectSlice(trimmed)]) {
917
+ if (!candidate) {
918
+ continue;
919
+ }
920
+ try {
921
+ return JSON.parse(candidate);
922
+ }
923
+ catch {
924
+ continue;
925
+ }
926
+ }
927
+ return null;
928
+ }
929
+ function jsonObjectSlice(output) {
930
+ const firstBrace = output.indexOf("{");
931
+ const lastBrace = output.lastIndexOf("}");
932
+ if (firstBrace === -1 || lastBrace === -1 || lastBrace <= firstBrace) {
933
+ return null;
934
+ }
935
+ return output.slice(firstBrace, lastBrace + 1);
936
+ }
937
+ function findExecutionInfo(value) {
938
+ if (!value || typeof value !== "object") {
939
+ return null;
940
+ }
941
+ const record = value;
942
+ for (const key of ["execution_info", "execution_results"]) {
943
+ const executionInfo = record[key];
944
+ if (Array.isArray(executionInfo)) {
945
+ if (executionInfo.length > 0) {
946
+ return executionInfo;
947
+ }
948
+ continue;
949
+ }
950
+ if (executionInfo && typeof executionInfo === "object") {
951
+ return executionInfo;
952
+ }
953
+ }
954
+ for (const nested of Object.values(record)) {
955
+ const executionInfo = findExecutionInfo(nested);
956
+ if (executionInfo) {
957
+ return executionInfo;
958
+ }
959
+ }
960
+ return null;
961
+ }
962
+ function findExecutionErrorMessage(value) {
963
+ if (!value || typeof value !== "object") {
964
+ return null;
965
+ }
966
+ if (Array.isArray(value)) {
967
+ for (const item of value) {
968
+ const errorMessage = findExecutionErrorMessage(item);
969
+ if (errorMessage) {
970
+ return errorMessage;
971
+ }
972
+ }
973
+ return null;
974
+ }
975
+ const record = value;
976
+ const direct = record.error_message;
977
+ if (typeof direct === "string" && direct.trim()) {
978
+ return direct.trim();
979
+ }
980
+ const failure = record.Failure ?? record.failure;
981
+ if (failure) {
982
+ return typeof failure === "string" ? failure : JSON.stringify(failure);
983
+ }
984
+ for (const nested of Object.values(record)) {
985
+ const errorMessage = findExecutionErrorMessage(nested);
986
+ if (errorMessage) {
987
+ return errorMessage;
988
+ }
989
+ }
990
+ return null;
991
+ }
992
+ function firstString(record, keys) {
993
+ if (!record) {
994
+ return null;
995
+ }
996
+ for (const key of keys) {
997
+ const value = record[key];
998
+ if (typeof value === "string" && value.trim()) {
999
+ return value.trim();
1000
+ }
1001
+ }
1002
+ return null;
1003
+ }
1004
+ function asRecord(value) {
1005
+ return value && typeof value === "object" && !Array.isArray(value)
1006
+ ? value
1007
+ : null;
1008
+ }
1009
+ function normalizeCasperPackageHash(value) {
1010
+ const normalized = value?.toLowerCase().replace(/^(hash-|package-)/, "");
1011
+ return normalized && /^[a-f0-9]{64}$/.test(normalized) ? normalized : null;
1012
+ }
1013
+ function normalizeCasperAccountAddress(value) {
1014
+ const normalized = value?.toLowerCase();
1015
+ if (!normalized) {
1016
+ return null;
1017
+ }
1018
+ const accountHash = normalized.match(/^account-hash-([a-f0-9]{64})$/);
1019
+ if (accountHash) {
1020
+ return `00${accountHash[1]}`;
1021
+ }
1022
+ return /^(00|01)[a-f0-9]{64}$/.test(normalized) ? normalized : null;
1023
+ }
1024
+ function normalizeHex(value, length) {
1025
+ const normalized = value?.toLowerCase().replace(/^0x/, "");
1026
+ return normalized && new RegExp(`^[a-f0-9]{${length}}$`).test(normalized)
1027
+ ? normalized
1028
+ : null;
1029
+ }
1030
+ function normalizePublicKey(value) {
1031
+ const normalized = value?.toLowerCase().replace(/^0x/, "");
1032
+ if (!normalized || !/^(01|02)[a-f0-9]+$/.test(normalized)) {
1033
+ return null;
1034
+ }
1035
+ return normalized.length === 66 || normalized.length === 68 ? normalized : null;
1036
+ }
1037
+ function normalizeCasperTransferTarget(value) {
1038
+ const publicKey = normalizePublicKey(value);
1039
+ if (publicKey) {
1040
+ return publicKey;
1041
+ }
1042
+ const accountAddress = normalizeCasperAccountAddress(value);
1043
+ return accountAddress ? `account-hash-${accountAddress.slice(2)}` : null;
1044
+ }
1045
+ function settlementAssetReceipt(payment) {
1046
+ return payment.settlementKind === "native-transfer"
1047
+ ? payment.assetId
1048
+ : payment.assetPackageHash;
1049
+ }
1050
+ function settlementPayeeReceipt(payment) {
1051
+ return payment.settlementKind === "native-transfer" ? payment.target : payment.to;
1052
+ }
1053
+ function settlementPayerReceipt(payment, signedPayload) {
1054
+ if (payment.settlementKind !== "native-transfer") {
1055
+ return payment.from;
1056
+ }
1057
+ return firstString(signedPayload, ["payer", "payerAccount", "payer_account"]);
1058
+ }
1059
+ function unixSecondsString(value) {
1060
+ if (!value) {
1061
+ return null;
1062
+ }
1063
+ if (isUnsignedIntegerString(value)) {
1064
+ return value;
1065
+ }
1066
+ const timestampMs = Date.parse(value);
1067
+ if (!Number.isFinite(timestampMs)) {
1068
+ return null;
1069
+ }
1070
+ return String(Math.floor(timestampMs / 1000));
1071
+ }
1072
+ function isUnsignedIntegerString(value) {
1073
+ return /^(0|[1-9]\d*)$/.test(value);
1074
+ }
1075
+ function networkMatches(left, right) {
1076
+ const normalizedLeft = left.toLowerCase();
1077
+ const normalizedRight = right.toLowerCase();
1078
+ if (normalizedLeft === normalizedRight) {
1079
+ return true;
1080
+ }
1081
+ const leftSuffix = normalizedLeft.split(":").at(-1);
1082
+ const rightSuffix = normalizedRight.split(":").at(-1);
1083
+ return Boolean(leftSuffix && rightSuffix && leftSuffix === rightSuffix);
1084
+ }
1085
+ function delay(ms) {
1086
+ return new Promise((resolve) => setTimeout(resolve, ms));
1087
+ }
1088
+ function facilitatorEndpoint(facilitatorUrl, path) {
1089
+ if (!facilitatorUrl) {
1090
+ throw new Error("X402_FACILITATOR_URL is required for facilitator settlement");
1091
+ }
1092
+ return new URL(path, ensureTrailingSlash(facilitatorUrl)).toString();
1093
+ }
1094
+ function ensureTrailingSlash(value) {
1095
+ return value.endsWith("/") ? value : `${value}/`;
1096
+ }
1097
+ function settlementReceiptJson(value) {
1098
+ return JSON.stringify(redactX402Value(toJsonValue(value, "x402_settlement_receipt")));
1099
+ }
1100
+ async function postSignerJson(config, body) {
1101
+ const controller = new AbortController();
1102
+ const timeout = setTimeout(() => controller.abort(), config.timeoutMs ?? 10_000);
1103
+ try {
1104
+ const headers = {
1105
+ "content-type": "application/json"
1106
+ };
1107
+ if (config.authToken) {
1108
+ headers.authorization = `Bearer ${config.authToken}`;
1109
+ }
1110
+ return await fetch(config.signerUrl, {
1111
+ method: "POST",
1112
+ headers,
1113
+ body: JSON.stringify(body),
1114
+ signal: controller.signal
1115
+ });
1116
+ }
1117
+ finally {
1118
+ clearTimeout(timeout);
1119
+ }
1120
+ }
1121
+ function extractSignedPayload(value) {
1122
+ const response = tryJsonObject(value);
1123
+ if (!response) {
1124
+ return null;
1125
+ }
1126
+ for (const key of [
1127
+ "signed_payload",
1128
+ "signedPayload",
1129
+ "paymentPayload",
1130
+ "payment_payload"
1131
+ ]) {
1132
+ const candidate = response[key];
1133
+ if (candidate && typeof candidate === "object" && !Array.isArray(candidate)) {
1134
+ return toJsonObject(candidate, key);
1135
+ }
1136
+ }
1137
+ return null;
1138
+ }
1139
+ function encodePaymentHeader(payload) {
1140
+ return Buffer.from(JSON.stringify(payload), "utf8").toString("base64");
1141
+ }
1142
+ async function fetchPaidResource(url, init) {
1143
+ const response = await fetch(url, {
1144
+ method: init.method,
1145
+ headers: init.headers
1146
+ });
1147
+ return {
1148
+ status: response.status,
1149
+ headers: response.headers,
1150
+ bodyText: await response.text()
1151
+ };
1152
+ }
1153
+ function parsePaymentResponseHeader(headers) {
1154
+ for (const name of ["PAYMENT-RESPONSE", "X-PAYMENT-RESPONSE"]) {
1155
+ const header = headers.get(name);
1156
+ if (!header) {
1157
+ continue;
1158
+ }
1159
+ return parsePaymentResponseHeaderValue(header);
1160
+ }
1161
+ return null;
1162
+ }
1163
+ function parsePaymentResponseHeaderValue(value) {
1164
+ const trimmed = value.trim();
1165
+ for (const candidate of [
1166
+ () => Buffer.from(trimmed, "base64").toString("utf8"),
1167
+ () => trimmed
1168
+ ]) {
1169
+ try {
1170
+ return JSON.parse(candidate());
1171
+ }
1172
+ catch {
1173
+ continue;
1174
+ }
1175
+ }
1176
+ return { raw: trimmed };
1177
+ }
1178
+ function paidResponseOk(status) {
1179
+ return status >= 200 && status < 300;
1180
+ }
1181
+ async function postJsonWithFetch(url, body) {
1182
+ const response = await fetch(url, {
1183
+ method: "POST",
1184
+ headers: {
1185
+ "content-type": "application/json"
1186
+ },
1187
+ body: JSON.stringify(body)
1188
+ });
1189
+ const text = await response.text();
1190
+ return {
1191
+ status: response.status,
1192
+ body: text ? parseJsonOrRaw(text) : {}
1193
+ };
1194
+ }
1195
+ function tryJsonObject(value) {
1196
+ try {
1197
+ return toJsonObject(value, "x402_response");
1198
+ }
1199
+ catch {
1200
+ return null;
1201
+ }
1202
+ }
1203
+ function parseJsonOrRaw(text) {
1204
+ try {
1205
+ return JSON.parse(text);
1206
+ }
1207
+ catch {
1208
+ return { raw: text };
1209
+ }
1210
+ }