xytara 3.1.13 → 3.1.15

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 (68) hide show
  1. package/.env.example +38 -4
  2. package/BSV_TERANODE_PLATFORM_DISCONTINUITY_RUNBOOK.md +126 -126
  3. package/REAL_PAYMENT_SETUP.md +14 -7
  4. package/RELEASE_NOTES.md +9 -4
  5. package/fixtures/catalog.js +22 -0
  6. package/lib/a2a_rpc.js +287 -280
  7. package/lib/account_auth.js +585 -585
  8. package/lib/agent_identity.js +162 -162
  9. package/lib/asyncapi_contract.js +3 -3
  10. package/lib/bolt_adapter.js +187 -187
  11. package/lib/bolt_payment_front.js +224 -224
  12. package/lib/buyer_event_log.js +215 -0
  13. package/lib/buyer_safety_policy.js +132 -0
  14. package/lib/checkout_processor_adapter.js +217 -217
  15. package/lib/command_flow.js +911 -722
  16. package/lib/commerce_artifacts.js +591 -591
  17. package/lib/commerce_bridge.js +274 -274
  18. package/lib/commerce_cases.js +399 -399
  19. package/lib/commerce_client.js +7694 -7694
  20. package/lib/commerce_quotes.js +29 -0
  21. package/lib/commerce_runtime.js +322 -322
  22. package/lib/execution_dedupe.js +86 -86
  23. package/lib/external_credit_bridge.js +142 -142
  24. package/lib/http_transport.js +99 -81
  25. package/lib/l402_adapter.js +241 -241
  26. package/lib/l402_payment_front.js +265 -265
  27. package/lib/mpp_adapter.js +237 -237
  28. package/lib/openapi_contract.js +4 -0
  29. package/lib/payment_config.js +257 -253
  30. package/lib/payment_verification.js +357 -357
  31. package/lib/provider_payout_execution.js +155 -155
  32. package/lib/provider_registry.js +852 -842
  33. package/lib/rate_limiter.js +81 -81
  34. package/lib/runtime_state_store.js +495 -369
  35. package/lib/settlement_bsv_live.js +600 -600
  36. package/lib/settlement_bsv_teranode.js +117 -117
  37. package/lib/stripe_mpp_payment_front.js +258 -258
  38. package/lib/x402_facilitator.js +198 -191
  39. package/lib/x402_lane_contract.js +5 -3
  40. package/lib/x402_settlement_recovery.js +175 -0
  41. package/package.json +9 -3
  42. package/scripts/buyer_events_daily_report.js +79 -0
  43. package/scripts/state_backup_offsite.js +196 -0
  44. package/scripts/verify_a2a_rpc.js +131 -105
  45. package/scripts/verify_agent_identity.js +153 -153
  46. package/scripts/verify_all.js +1 -1
  47. package/scripts/verify_bolt_adapter.js +128 -128
  48. package/scripts/verify_buyer_event_log.js +123 -0
  49. package/scripts/verify_buyer_safety.js +141 -0
  50. package/scripts/verify_cdp_facilitator.js +110 -110
  51. package/scripts/verify_checkout_processor.js +109 -109
  52. package/scripts/verify_commerce_bridge.js +177 -177
  53. package/scripts/verify_execution_dedupe.js +189 -189
  54. package/scripts/verify_execution_surfacing.js +76 -76
  55. package/scripts/verify_final_activation.js +191 -191
  56. package/scripts/verify_l402_adapter.js +86 -86
  57. package/scripts/verify_lifecycle_spend_binding.js +88 -0
  58. package/scripts/verify_mpp_adapter.js +128 -128
  59. package/scripts/verify_production_readiness.js +268 -268
  60. package/scripts/verify_rate_limiter.js +52 -52
  61. package/scripts/verify_refund_credit.js +106 -106
  62. package/scripts/verify_release_candidate.js +81 -81
  63. package/scripts/verify_runtime_state_guard.js +117 -0
  64. package/scripts/verify_service.js +15421 -15421
  65. package/scripts/verify_verify_execute_settle.js +209 -208
  66. package/scripts/verify_x402_facilitator.js +307 -286
  67. package/scripts/verify_x402_settlement_recovery.js +153 -0
  68. package/server.js +12242 -11974
@@ -1,265 +1,265 @@
1
- "use strict";
2
-
3
- const crypto = require("crypto");
4
- const l402Adapter = require("./l402_adapter");
5
-
6
- function normalizeString(value) {
7
- return typeof value === "string" ? value.trim() : "";
8
- }
9
-
10
- function safeEqualHex(left, right) {
11
- const a = Buffer.from(String(left || ""), "hex");
12
- const b = Buffer.from(String(right || ""), "hex");
13
- if (a.length === 0 || b.length === 0 || a.length !== b.length) return false;
14
- return crypto.timingSafeEqual(a, b);
15
- }
16
-
17
- function decodeBase64UrlJson(value) {
18
- try {
19
- return JSON.parse(Buffer.from(String(value || ""), "base64url").toString("utf8"));
20
- } catch (_) {
21
- return null;
22
- }
23
- }
24
-
25
- function loadL402FrontConfig() {
26
- const sharedSecret = normalizeString(process.env.XYTARA_L402_SHARED_SECRET);
27
- return {
28
- enabled: String(process.env.XYTARA_L402_ENABLED || (sharedSecret ? "true" : "false")).trim().toLowerCase() !== "false",
29
- shared_secret: sharedSecret || null,
30
- max_age_seconds: Math.max(30, Number(process.env.XYTARA_L402_MAX_AGE_SECONDS || 300) || 300),
31
- required_headers: ["authorization"],
32
- auth_scheme: "L402",
33
- token_shape: "base64url_json_with_macaroon_and_hmac_signed_payload"
34
- };
35
- }
36
-
37
- function parseL402Authorization(headers) {
38
- const authorization = headers && typeof headers.authorization === "string"
39
- ? headers.authorization.trim()
40
- : "";
41
- const match = authorization.match(/^L402\s+(.+)$/i);
42
- if (!match) return null;
43
- const decoded = decodeBase64UrlJson(match[1]);
44
- if (!decoded || typeof decoded !== "object") return null;
45
- return {
46
- wallet_id: decoded.wallet_id || decoded.gateway_id || "l402_gateway",
47
- encoded: decoded.payload || null,
48
- signature: decoded.signature || null,
49
- macaroon: decoded.macaroon || null,
50
- invoice_id: decoded.invoice_id || null,
51
- preimage_hash: decoded.preimage_hash || null,
52
- scheme: "l402"
53
- };
54
- }
55
-
56
- function verifyL402PaymentPayload(paymentPayload, quote, walletId, maxAgeSeconds) {
57
- if (!paymentPayload || typeof paymentPayload !== "object") {
58
- return { ok: false, reason: "l402_payload_invalid" };
59
- }
60
- if (!paymentPayload.quote_id || paymentPayload.quote_id !== quote.quote_id) {
61
- return { ok: false, reason: "l402_quote_mismatch" };
62
- }
63
- if (paymentPayload.amount_minor !== quote.amount_minor) {
64
- return { ok: false, reason: "l402_amount_mismatch" };
65
- }
66
- if (paymentPayload.currency !== quote.currency) {
67
- return { ok: false, reason: "l402_currency_mismatch" };
68
- }
69
- if (paymentPayload.account_id && paymentPayload.account_id !== quote.account_id) {
70
- return { ok: false, reason: "l402_account_mismatch" };
71
- }
72
- if (walletId && paymentPayload.wallet_id && paymentPayload.wallet_id !== walletId) {
73
- return { ok: false, reason: "l402_wallet_mismatch" };
74
- }
75
- if (!paymentPayload.nonce || typeof paymentPayload.nonce !== "string") {
76
- return { ok: false, reason: "l402_nonce_missing" };
77
- }
78
- if (!paymentPayload.issued_at_iso || Number.isNaN(Date.parse(paymentPayload.issued_at_iso))) {
79
- return { ok: false, reason: "l402_issued_at_invalid" };
80
- }
81
- const ageSeconds = Math.max(0, Math.floor((Date.now() - Date.parse(paymentPayload.issued_at_iso)) / 1000));
82
- if (ageSeconds > maxAgeSeconds) {
83
- return { ok: false, reason: "l402_token_expired" };
84
- }
85
- if (!normalizeString(paymentPayload.macaroon_id || paymentPayload.macaroon)) {
86
- return { ok: false, reason: "l402_macaroon_missing" };
87
- }
88
- if (!normalizeString(paymentPayload.invoice_id || paymentPayload.invoice_reference)) {
89
- return { ok: false, reason: "l402_invoice_reference_missing" };
90
- }
91
- return { ok: true, age_seconds: ageSeconds };
92
- }
93
-
94
- function verifyL402AccessToken(headers, quote, state) {
95
- // Real Lightning (L402) path: when a Lightning provider is configured, verify
96
- // the standard "L402 <macaroon>:<preimage>" authorization cryptographically
97
- // (HMAC-bound macaroon + sha256(preimage) === payment_hash) with single-use
98
- // replay protection via the runtime nonce set. Otherwise fall through to the
99
- // existing gateway-signed token scheme below (unchanged).
100
- const lightningConfig = l402Adapter.loadL402Config();
101
- if (l402Adapter.isConfigured(lightningConfig)) {
102
- const authorization = headers && typeof headers.authorization === "string" ? headers.authorization : "";
103
- const result = l402Adapter.verifyL402Authorization(lightningConfig, authorization);
104
- if (!result.ok) {
105
- return { ok: false, status: result.reason === "l402_authorization_malformed" ? 402 : 403, reason: result.reason };
106
- }
107
- if (state && state.acceptedPaymentNonces && state.acceptedPaymentNonces.has(result.payment_hash)) {
108
- return { ok: false, status: 403, reason: "l402_preimage_replayed" };
109
- }
110
- return {
111
- ok: true,
112
- verification_mode: "l402_lightning",
113
- wallet_id: "l402",
114
- payment_payload: {
115
- nonce: result.payment_hash,
116
- payment_hash: result.payment_hash,
117
- preimage: result.preimage,
118
- quote_id: quote && quote.quote_id,
119
- issued_at_iso: new Date().toISOString()
120
- },
121
- l402: { payment_hash: result.payment_hash, preimage: result.preimage }
122
- };
123
- }
124
-
125
- const config = loadL402FrontConfig();
126
- if (!config.enabled) {
127
- return {
128
- ok: false,
129
- status: 503,
130
- reason: "l402_not_enabled"
131
- };
132
- }
133
- if (!config.shared_secret) {
134
- return {
135
- ok: false,
136
- status: 503,
137
- reason: "l402_shared_secret_missing"
138
- };
139
- }
140
- const payment = parseL402Authorization(headers || {});
141
- if (!payment || !payment.encoded || !payment.signature || !payment.macaroon) {
142
- return {
143
- ok: false,
144
- status: 402,
145
- reason: "l402_headers_incomplete"
146
- };
147
- }
148
- const expectedSignature = crypto.createHmac("sha256", config.shared_secret).update(payment.encoded).digest("hex");
149
- if (!safeEqualHex(expectedSignature, payment.signature)) {
150
- return {
151
- ok: false,
152
- status: 403,
153
- reason: "l402_signature_invalid"
154
- };
155
- }
156
- const payload = decodeBase64UrlJson(payment.encoded);
157
- const validation = verifyL402PaymentPayload(payload, quote, payment.wallet_id, config.max_age_seconds);
158
- if (!validation.ok) {
159
- return {
160
- ok: false,
161
- status: 403,
162
- reason: validation.reason
163
- };
164
- }
165
- return {
166
- ok: true,
167
- verification_mode: "l402_gateway_signed",
168
- wallet_id: payment.wallet_id,
169
- payment_payload: payload,
170
- age_seconds: validation.age_seconds,
171
- l402: {
172
- macaroon: payment.macaroon,
173
- invoice_id: payment.invoice_id || payload.invoice_id || null,
174
- preimage_hash: payment.preimage_hash || payload.preimage_hash || null
175
- }
176
- };
177
- }
178
-
179
- function buildL402SecuritySummary() {
180
- const config = loadL402FrontConfig();
181
- const blockers = [];
182
- if (config.enabled && !config.shared_secret) blockers.push("l402_shared_secret_missing");
183
- return {
184
- ok: true,
185
- category: "machine-commerce-l402-security-summary",
186
- summary_version: "xytara-l402-security-summary-v1",
187
- enabled: config.enabled,
188
- shared_secret_configured: Boolean(config.shared_secret),
189
- max_age_seconds: config.max_age_seconds,
190
- auth_scheme: config.auth_scheme,
191
- token_shape: config.token_shape,
192
- ready: config.enabled && blockers.length === 0,
193
- blockers,
194
- linked_surfaces: {
195
- l402_lane_ref: "/v1/l402",
196
- commands_execute_ref: "/l402/commands/execute",
197
- mcp_invoke_ref: "/l402/mcp/tools/invoke"
198
- }
199
- };
200
- }
201
-
202
- async function buildL402ChallengePayload(quote) {
203
- // Real Lightning (L402) challenge: when a Lightning provider is configured,
204
- // issue a real bolt11 invoice + an HMAC-bound macaroon and advertise the
205
- // standard L402 WWW-Authenticate value. Otherwise return the existing
206
- // token-shape descriptor (unchanged).
207
- const lightningConfig = l402Adapter.loadL402Config();
208
- if (l402Adapter.isConfigured(lightningConfig)) {
209
- const invoice = await l402Adapter.createLightningInvoice(lightningConfig, {
210
- amountSats: lightningConfig.priceSats,
211
- memo: quote && quote.quote_id ? `naxytra ${quote.quote_id}` : "naxytra L402"
212
- });
213
- if (!invoice.ok) {
214
- return {
215
- ok: false,
216
- payment_required: {
217
- scheme: "l402",
218
- quote,
219
- error: invoice.reason,
220
- operator_requirements: { auth_scheme: "L402", security_ref: "/v1/l402/security" }
221
- }
222
- };
223
- }
224
- const macaroon = l402Adapter.issueL402Macaroon(lightningConfig, {
225
- payment_hash: invoice.payment_hash,
226
- amountSats: lightningConfig.priceSats
227
- });
228
- return {
229
- ok: false,
230
- payment_required: {
231
- scheme: "l402",
232
- quote,
233
- invoice: invoice.payment_request,
234
- payment_hash: invoice.payment_hash,
235
- macaroon,
236
- www_authenticate: l402Adapter.buildWwwAuthenticate(macaroon, invoice.payment_request),
237
- operator_requirements: {
238
- auth_scheme: "L402",
239
- token_shape: "authorization_header_L402_macaroon_colon_preimage",
240
- security_ref: "/v1/l402/security"
241
- }
242
- }
243
- };
244
- }
245
- return {
246
- ok: false,
247
- payment_required: {
248
- scheme: "l402",
249
- quote,
250
- operator_requirements: {
251
- auth_scheme: "L402",
252
- token_shape: "base64url_json_with_macaroon_and_hmac_signed_payload",
253
- security_ref: "/v1/l402/security"
254
- }
255
- }
256
- };
257
- }
258
-
259
- module.exports = {
260
- buildL402ChallengePayload,
261
- buildL402SecuritySummary,
262
- loadL402FrontConfig,
263
- parseL402Authorization,
264
- verifyL402AccessToken
265
- };
1
+ "use strict";
2
+
3
+ const crypto = require("crypto");
4
+ const l402Adapter = require("./l402_adapter");
5
+
6
+ function normalizeString(value) {
7
+ return typeof value === "string" ? value.trim() : "";
8
+ }
9
+
10
+ function safeEqualHex(left, right) {
11
+ const a = Buffer.from(String(left || ""), "hex");
12
+ const b = Buffer.from(String(right || ""), "hex");
13
+ if (a.length === 0 || b.length === 0 || a.length !== b.length) return false;
14
+ return crypto.timingSafeEqual(a, b);
15
+ }
16
+
17
+ function decodeBase64UrlJson(value) {
18
+ try {
19
+ return JSON.parse(Buffer.from(String(value || ""), "base64url").toString("utf8"));
20
+ } catch (_) {
21
+ return null;
22
+ }
23
+ }
24
+
25
+ function loadL402FrontConfig() {
26
+ const sharedSecret = normalizeString(process.env.XYTARA_L402_SHARED_SECRET);
27
+ return {
28
+ enabled: String(process.env.XYTARA_L402_ENABLED || (sharedSecret ? "true" : "false")).trim().toLowerCase() !== "false",
29
+ shared_secret: sharedSecret || null,
30
+ max_age_seconds: Math.max(30, Number(process.env.XYTARA_L402_MAX_AGE_SECONDS || 300) || 300),
31
+ required_headers: ["authorization"],
32
+ auth_scheme: "L402",
33
+ token_shape: "base64url_json_with_macaroon_and_hmac_signed_payload"
34
+ };
35
+ }
36
+
37
+ function parseL402Authorization(headers) {
38
+ const authorization = headers && typeof headers.authorization === "string"
39
+ ? headers.authorization.trim()
40
+ : "";
41
+ const match = authorization.match(/^L402\s+(.+)$/i);
42
+ if (!match) return null;
43
+ const decoded = decodeBase64UrlJson(match[1]);
44
+ if (!decoded || typeof decoded !== "object") return null;
45
+ return {
46
+ wallet_id: decoded.wallet_id || decoded.gateway_id || "l402_gateway",
47
+ encoded: decoded.payload || null,
48
+ signature: decoded.signature || null,
49
+ macaroon: decoded.macaroon || null,
50
+ invoice_id: decoded.invoice_id || null,
51
+ preimage_hash: decoded.preimage_hash || null,
52
+ scheme: "l402"
53
+ };
54
+ }
55
+
56
+ function verifyL402PaymentPayload(paymentPayload, quote, walletId, maxAgeSeconds) {
57
+ if (!paymentPayload || typeof paymentPayload !== "object") {
58
+ return { ok: false, reason: "l402_payload_invalid" };
59
+ }
60
+ if (!paymentPayload.quote_id || paymentPayload.quote_id !== quote.quote_id) {
61
+ return { ok: false, reason: "l402_quote_mismatch" };
62
+ }
63
+ if (paymentPayload.amount_minor !== quote.amount_minor) {
64
+ return { ok: false, reason: "l402_amount_mismatch" };
65
+ }
66
+ if (paymentPayload.currency !== quote.currency) {
67
+ return { ok: false, reason: "l402_currency_mismatch" };
68
+ }
69
+ if (paymentPayload.account_id && paymentPayload.account_id !== quote.account_id) {
70
+ return { ok: false, reason: "l402_account_mismatch" };
71
+ }
72
+ if (walletId && paymentPayload.wallet_id && paymentPayload.wallet_id !== walletId) {
73
+ return { ok: false, reason: "l402_wallet_mismatch" };
74
+ }
75
+ if (!paymentPayload.nonce || typeof paymentPayload.nonce !== "string") {
76
+ return { ok: false, reason: "l402_nonce_missing" };
77
+ }
78
+ if (!paymentPayload.issued_at_iso || Number.isNaN(Date.parse(paymentPayload.issued_at_iso))) {
79
+ return { ok: false, reason: "l402_issued_at_invalid" };
80
+ }
81
+ const ageSeconds = Math.max(0, Math.floor((Date.now() - Date.parse(paymentPayload.issued_at_iso)) / 1000));
82
+ if (ageSeconds > maxAgeSeconds) {
83
+ return { ok: false, reason: "l402_token_expired" };
84
+ }
85
+ if (!normalizeString(paymentPayload.macaroon_id || paymentPayload.macaroon)) {
86
+ return { ok: false, reason: "l402_macaroon_missing" };
87
+ }
88
+ if (!normalizeString(paymentPayload.invoice_id || paymentPayload.invoice_reference)) {
89
+ return { ok: false, reason: "l402_invoice_reference_missing" };
90
+ }
91
+ return { ok: true, age_seconds: ageSeconds };
92
+ }
93
+
94
+ function verifyL402AccessToken(headers, quote, state) {
95
+ // Real Lightning (L402) path: when a Lightning provider is configured, verify
96
+ // the standard "L402 <macaroon>:<preimage>" authorization cryptographically
97
+ // (HMAC-bound macaroon + sha256(preimage) === payment_hash) with single-use
98
+ // replay protection via the runtime nonce set. Otherwise fall through to the
99
+ // existing gateway-signed token scheme below (unchanged).
100
+ const lightningConfig = l402Adapter.loadL402Config();
101
+ if (l402Adapter.isConfigured(lightningConfig)) {
102
+ const authorization = headers && typeof headers.authorization === "string" ? headers.authorization : "";
103
+ const result = l402Adapter.verifyL402Authorization(lightningConfig, authorization);
104
+ if (!result.ok) {
105
+ return { ok: false, status: result.reason === "l402_authorization_malformed" ? 402 : 403, reason: result.reason };
106
+ }
107
+ if (state && state.acceptedPaymentNonces && state.acceptedPaymentNonces.has(result.payment_hash)) {
108
+ return { ok: false, status: 403, reason: "l402_preimage_replayed" };
109
+ }
110
+ return {
111
+ ok: true,
112
+ verification_mode: "l402_lightning",
113
+ wallet_id: "l402",
114
+ payment_payload: {
115
+ nonce: result.payment_hash,
116
+ payment_hash: result.payment_hash,
117
+ preimage: result.preimage,
118
+ quote_id: quote && quote.quote_id,
119
+ issued_at_iso: new Date().toISOString()
120
+ },
121
+ l402: { payment_hash: result.payment_hash, preimage: result.preimage }
122
+ };
123
+ }
124
+
125
+ const config = loadL402FrontConfig();
126
+ if (!config.enabled) {
127
+ return {
128
+ ok: false,
129
+ status: 503,
130
+ reason: "l402_not_enabled"
131
+ };
132
+ }
133
+ if (!config.shared_secret) {
134
+ return {
135
+ ok: false,
136
+ status: 503,
137
+ reason: "l402_shared_secret_missing"
138
+ };
139
+ }
140
+ const payment = parseL402Authorization(headers || {});
141
+ if (!payment || !payment.encoded || !payment.signature || !payment.macaroon) {
142
+ return {
143
+ ok: false,
144
+ status: 402,
145
+ reason: "l402_headers_incomplete"
146
+ };
147
+ }
148
+ const expectedSignature = crypto.createHmac("sha256", config.shared_secret).update(payment.encoded).digest("hex");
149
+ if (!safeEqualHex(expectedSignature, payment.signature)) {
150
+ return {
151
+ ok: false,
152
+ status: 403,
153
+ reason: "l402_signature_invalid"
154
+ };
155
+ }
156
+ const payload = decodeBase64UrlJson(payment.encoded);
157
+ const validation = verifyL402PaymentPayload(payload, quote, payment.wallet_id, config.max_age_seconds);
158
+ if (!validation.ok) {
159
+ return {
160
+ ok: false,
161
+ status: 403,
162
+ reason: validation.reason
163
+ };
164
+ }
165
+ return {
166
+ ok: true,
167
+ verification_mode: "l402_gateway_signed",
168
+ wallet_id: payment.wallet_id,
169
+ payment_payload: payload,
170
+ age_seconds: validation.age_seconds,
171
+ l402: {
172
+ macaroon: payment.macaroon,
173
+ invoice_id: payment.invoice_id || payload.invoice_id || null,
174
+ preimage_hash: payment.preimage_hash || payload.preimage_hash || null
175
+ }
176
+ };
177
+ }
178
+
179
+ function buildL402SecuritySummary() {
180
+ const config = loadL402FrontConfig();
181
+ const blockers = [];
182
+ if (config.enabled && !config.shared_secret) blockers.push("l402_shared_secret_missing");
183
+ return {
184
+ ok: true,
185
+ category: "machine-commerce-l402-security-summary",
186
+ summary_version: "xytara-l402-security-summary-v1",
187
+ enabled: config.enabled,
188
+ shared_secret_configured: Boolean(config.shared_secret),
189
+ max_age_seconds: config.max_age_seconds,
190
+ auth_scheme: config.auth_scheme,
191
+ token_shape: config.token_shape,
192
+ ready: config.enabled && blockers.length === 0,
193
+ blockers,
194
+ linked_surfaces: {
195
+ l402_lane_ref: "/v1/l402",
196
+ commands_execute_ref: "/l402/commands/execute",
197
+ mcp_invoke_ref: "/l402/mcp/tools/invoke"
198
+ }
199
+ };
200
+ }
201
+
202
+ async function buildL402ChallengePayload(quote) {
203
+ // Real Lightning (L402) challenge: when a Lightning provider is configured,
204
+ // issue a real bolt11 invoice + an HMAC-bound macaroon and advertise the
205
+ // standard L402 WWW-Authenticate value. Otherwise return the existing
206
+ // token-shape descriptor (unchanged).
207
+ const lightningConfig = l402Adapter.loadL402Config();
208
+ if (l402Adapter.isConfigured(lightningConfig)) {
209
+ const invoice = await l402Adapter.createLightningInvoice(lightningConfig, {
210
+ amountSats: lightningConfig.priceSats,
211
+ memo: quote && quote.quote_id ? `naxytra ${quote.quote_id}` : "naxytra L402"
212
+ });
213
+ if (!invoice.ok) {
214
+ return {
215
+ ok: false,
216
+ payment_required: {
217
+ scheme: "l402",
218
+ quote,
219
+ error: invoice.reason,
220
+ operator_requirements: { auth_scheme: "L402", security_ref: "/v1/l402/security" }
221
+ }
222
+ };
223
+ }
224
+ const macaroon = l402Adapter.issueL402Macaroon(lightningConfig, {
225
+ payment_hash: invoice.payment_hash,
226
+ amountSats: lightningConfig.priceSats
227
+ });
228
+ return {
229
+ ok: false,
230
+ payment_required: {
231
+ scheme: "l402",
232
+ quote,
233
+ invoice: invoice.payment_request,
234
+ payment_hash: invoice.payment_hash,
235
+ macaroon,
236
+ www_authenticate: l402Adapter.buildWwwAuthenticate(macaroon, invoice.payment_request),
237
+ operator_requirements: {
238
+ auth_scheme: "L402",
239
+ token_shape: "authorization_header_L402_macaroon_colon_preimage",
240
+ security_ref: "/v1/l402/security"
241
+ }
242
+ }
243
+ };
244
+ }
245
+ return {
246
+ ok: false,
247
+ payment_required: {
248
+ scheme: "l402",
249
+ quote,
250
+ operator_requirements: {
251
+ auth_scheme: "L402",
252
+ token_shape: "base64url_json_with_macaroon_and_hmac_signed_payload",
253
+ security_ref: "/v1/l402/security"
254
+ }
255
+ }
256
+ };
257
+ }
258
+
259
+ module.exports = {
260
+ buildL402ChallengePayload,
261
+ buildL402SecuritySummary,
262
+ loadL402FrontConfig,
263
+ parseL402Authorization,
264
+ verifyL402AccessToken
265
+ };