@contextvm/sdk 0.3.1 → 0.4.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 (97) hide show
  1. package/dist/esm/core/utils/utils.d.ts +11 -0
  2. package/dist/esm/core/utils/utils.d.ts.map +1 -1
  3. package/dist/esm/core/utils/utils.js +15 -0
  4. package/dist/esm/core/utils/utils.js.map +1 -1
  5. package/dist/esm/gateway/index.d.ts +10 -8
  6. package/dist/esm/gateway/index.d.ts.map +1 -1
  7. package/dist/esm/gateway/index.js +29 -12
  8. package/dist/esm/gateway/index.js.map +1 -1
  9. package/dist/esm/index.d.ts +1 -0
  10. package/dist/esm/index.d.ts.map +1 -1
  11. package/dist/esm/index.js +1 -0
  12. package/dist/esm/index.js.map +1 -1
  13. package/dist/esm/payments/cap-tags.d.ts +13 -0
  14. package/dist/esm/payments/cap-tags.d.ts.map +1 -0
  15. package/dist/esm/payments/cap-tags.js +38 -0
  16. package/dist/esm/payments/cap-tags.js.map +1 -0
  17. package/dist/esm/payments/client-payments.d.ts +10 -0
  18. package/dist/esm/payments/client-payments.d.ts.map +1 -0
  19. package/dist/esm/payments/client-payments.js +108 -0
  20. package/dist/esm/payments/client-payments.js.map +1 -0
  21. package/dist/esm/payments/fake-payment-handler.d.ts +19 -0
  22. package/dist/esm/payments/fake-payment-handler.d.ts.map +1 -0
  23. package/dist/esm/payments/fake-payment-handler.js +16 -0
  24. package/dist/esm/payments/fake-payment-handler.js.map +1 -0
  25. package/dist/esm/payments/fake-payment-processor.d.ts +34 -0
  26. package/dist/esm/payments/fake-payment-processor.d.ts.map +1 -0
  27. package/dist/esm/payments/fake-payment-processor.js +29 -0
  28. package/dist/esm/payments/fake-payment-processor.js.map +1 -0
  29. package/dist/esm/payments/handlers/ln-bolt11-lnbits-payment-handler.d.ts +24 -0
  30. package/dist/esm/payments/handlers/ln-bolt11-lnbits-payment-handler.d.ts.map +1 -0
  31. package/dist/esm/payments/handlers/ln-bolt11-lnbits-payment-handler.js +44 -0
  32. package/dist/esm/payments/handlers/ln-bolt11-lnbits-payment-handler.js.map +1 -0
  33. package/dist/esm/payments/handlers/ln-bolt11-nwc-payment-handler.d.ts +20 -0
  34. package/dist/esm/payments/handlers/ln-bolt11-nwc-payment-handler.d.ts.map +1 -0
  35. package/dist/esm/payments/handlers/ln-bolt11-nwc-payment-handler.js +36 -0
  36. package/dist/esm/payments/handlers/ln-bolt11-nwc-payment-handler.js.map +1 -0
  37. package/dist/esm/payments/index.d.ts +17 -0
  38. package/dist/esm/payments/index.d.ts.map +1 -0
  39. package/dist/esm/payments/index.js +17 -0
  40. package/dist/esm/payments/index.js.map +1 -0
  41. package/dist/esm/payments/nip47/connection.d.ts +9 -0
  42. package/dist/esm/payments/nip47/connection.d.ts.map +1 -0
  43. package/dist/esm/payments/nip47/connection.js +34 -0
  44. package/dist/esm/payments/nip47/connection.js.map +1 -0
  45. package/dist/esm/payments/nip47/nwc-client.d.ts +38 -0
  46. package/dist/esm/payments/nip47/nwc-client.d.ts.map +1 -0
  47. package/dist/esm/payments/nip47/nwc-client.js +144 -0
  48. package/dist/esm/payments/nip47/nwc-client.js.map +1 -0
  49. package/dist/esm/payments/nip47/types.d.ts +54 -0
  50. package/dist/esm/payments/nip47/types.d.ts.map +1 -0
  51. package/dist/esm/payments/nip47/types.js +2 -0
  52. package/dist/esm/payments/nip47/types.js.map +1 -0
  53. package/dist/esm/payments/nip47/utils.d.ts +7 -0
  54. package/dist/esm/payments/nip47/utils.d.ts.map +1 -0
  55. package/dist/esm/payments/nip47/utils.js +9 -0
  56. package/dist/esm/payments/nip47/utils.js.map +1 -0
  57. package/dist/esm/payments/pmi-tags.d.ts +8 -0
  58. package/dist/esm/payments/pmi-tags.d.ts.map +1 -0
  59. package/dist/esm/payments/pmi-tags.js +9 -0
  60. package/dist/esm/payments/pmi-tags.js.map +1 -0
  61. package/dist/esm/payments/pmis.d.ts +7 -0
  62. package/dist/esm/payments/pmis.d.ts.map +1 -0
  63. package/dist/esm/payments/pmis.js +7 -0
  64. package/dist/esm/payments/pmis.js.map +1 -0
  65. package/dist/esm/payments/processors/ln-bolt11-lnbits-payment-processor.d.ts +50 -0
  66. package/dist/esm/payments/processors/ln-bolt11-lnbits-payment-processor.d.ts.map +1 -0
  67. package/dist/esm/payments/processors/ln-bolt11-lnbits-payment-processor.js +133 -0
  68. package/dist/esm/payments/processors/ln-bolt11-lnbits-payment-processor.js.map +1 -0
  69. package/dist/esm/payments/processors/ln-bolt11-nwc-payment-processor.d.ts +41 -0
  70. package/dist/esm/payments/processors/ln-bolt11-nwc-payment-processor.d.ts.map +1 -0
  71. package/dist/esm/payments/processors/ln-bolt11-nwc-payment-processor.js +129 -0
  72. package/dist/esm/payments/processors/ln-bolt11-nwc-payment-processor.js.map +1 -0
  73. package/dist/esm/payments/server-payments.d.ts +32 -0
  74. package/dist/esm/payments/server-payments.d.ts.map +1 -0
  75. package/dist/esm/payments/server-payments.js +199 -0
  76. package/dist/esm/payments/server-payments.js.map +1 -0
  77. package/dist/esm/payments/server-transport-payments.d.ts +7 -0
  78. package/dist/esm/payments/server-transport-payments.d.ts.map +1 -0
  79. package/dist/esm/payments/server-transport-payments.js +14 -0
  80. package/dist/esm/payments/server-transport-payments.js.map +1 -0
  81. package/dist/esm/payments/types.d.ts +174 -0
  82. package/dist/esm/payments/types.d.ts.map +1 -0
  83. package/dist/esm/payments/types.js +5 -0
  84. package/dist/esm/payments/types.js.map +1 -0
  85. package/dist/esm/transport/nostr-client-transport.d.ts +12 -0
  86. package/dist/esm/transport/nostr-client-transport.d.ts.map +1 -1
  87. package/dist/esm/transport/nostr-client-transport.js +49 -18
  88. package/dist/esm/transport/nostr-client-transport.js.map +1 -1
  89. package/dist/esm/transport/nostr-server/announcement-manager.d.ts +18 -0
  90. package/dist/esm/transport/nostr-server/announcement-manager.d.ts.map +1 -1
  91. package/dist/esm/transport/nostr-server/announcement-manager.js +40 -5
  92. package/dist/esm/transport/nostr-server/announcement-manager.js.map +1 -1
  93. package/dist/esm/transport/nostr-server-transport.d.ts +30 -0
  94. package/dist/esm/transport/nostr-server-transport.d.ts.map +1 -1
  95. package/dist/esm/transport/nostr-server-transport.js +64 -4
  96. package/dist/esm/transport/nostr-server-transport.js.map +1 -1
  97. package/package.json +1 -1
@@ -0,0 +1,133 @@
1
+ import { PMI_BITCOIN_LIGHTNING_BOLT11 } from '../pmis.js';
2
+ import { createLogger } from '../../core/utils/logger.js';
3
+ import { sleep } from '../../core/utils/utils.js';
4
+ /**
5
+ * CEP-8 server payment processor for PMI `bitcoin-lightning-bolt11` backed by LNbits REST API.
6
+ *
7
+ * Creates BOLT11 invoices via the LNbits `/api/v1/payments` endpoint and polls
8
+ * for settlement using the same API.
9
+ */
10
+ export class LnBolt11LnbitsPaymentProcessor {
11
+ constructor(options) {
12
+ var _a, _b, _c;
13
+ this.pmi = PMI_BITCOIN_LIGHTNING_BOLT11;
14
+ this.lnbitsUrl = options.lnbitsUrl.replace(/\/+$/, '');
15
+ this.lnbitsApiKey = options.lnbitsApiKey;
16
+ this.lnbitsBasicAuth = options.lnbitsBasicAuth;
17
+ this.ttlSeconds = (_a = options.ttlSeconds) !== null && _a !== void 0 ? _a : 300;
18
+ this.invoiceExpirySeconds = (_b = options.invoiceExpirySeconds) !== null && _b !== void 0 ? _b : this.ttlSeconds;
19
+ this.pollIntervalMs = (_c = options.pollIntervalMs) !== null && _c !== void 0 ? _c : 1500;
20
+ this.logger = createLogger('payments/lnbits-processor');
21
+ }
22
+ buildHeaders() {
23
+ const headers = {
24
+ 'Content-Type': 'application/json',
25
+ 'X-Api-Key': this.lnbitsApiKey,
26
+ };
27
+ if (this.lnbitsBasicAuth) {
28
+ const encoded = Buffer.from(this.lnbitsBasicAuth).toString('base64');
29
+ headers['Authorization'] = `Basic ${encoded}`;
30
+ }
31
+ return headers;
32
+ }
33
+ async createPaymentRequired(params) {
34
+ var _a;
35
+ const body = JSON.stringify({
36
+ out: false,
37
+ amount: params.amount,
38
+ memo: (_a = params.description) !== null && _a !== void 0 ? _a : `CVM payment: ${params.requestEventId.slice(0, 8)}`,
39
+ expiry: this.invoiceExpirySeconds,
40
+ });
41
+ const response = await fetch(`${this.lnbitsUrl}/api/v1/payments`, {
42
+ method: 'POST',
43
+ headers: this.buildHeaders(),
44
+ body,
45
+ });
46
+ if (!response.ok) {
47
+ const text = await response.text();
48
+ throw new Error(`LNbits create invoice failed: ${response.status} ${text}`);
49
+ }
50
+ const result = (await response.json());
51
+ if (!result.payment_request) {
52
+ throw new Error('LNbits returned no payment_request');
53
+ }
54
+ this.logger.debug('Invoice created', {
55
+ requestEventId: params.requestEventId,
56
+ paymentHash: result.payment_hash,
57
+ amount: params.amount,
58
+ });
59
+ return {
60
+ amount: params.amount,
61
+ pay_req: result.payment_request,
62
+ description: params.description,
63
+ pmi: this.pmi,
64
+ ttl: this.ttlSeconds,
65
+ };
66
+ }
67
+ async verifyPayment(params) {
68
+ var _a;
69
+ // We need the payment hash to check status. Derive it from the invoice
70
+ // by first looking it up via the decoded invoice endpoint, or by checking
71
+ // all recent payments. The simplest approach: decode the bolt11 to get the hash.
72
+ const paymentHash = await this.getPaymentHashFromInvoice(params.pay_req);
73
+ while (true) {
74
+ if ((_a = params.abortSignal) === null || _a === void 0 ? void 0 : _a.aborted) {
75
+ throw new Error('verifyPayment aborted');
76
+ }
77
+ const response = await fetch(`${this.lnbitsUrl}/api/v1/payments/${paymentHash}`, {
78
+ method: 'GET',
79
+ headers: this.buildHeaders(),
80
+ });
81
+ if (response.ok) {
82
+ const result = (await response.json());
83
+ this.logger.debug('Payment check', {
84
+ requestEventId: params.requestEventId,
85
+ paymentHash,
86
+ paid: result.paid,
87
+ });
88
+ if (result.paid) {
89
+ return { _meta: { payment_hash: paymentHash } };
90
+ }
91
+ }
92
+ else {
93
+ this.logger.debug('Payment check request failed', {
94
+ status: response.status,
95
+ paymentHash,
96
+ });
97
+ }
98
+ await sleep(this.pollIntervalMs);
99
+ }
100
+ }
101
+ /**
102
+ * Extract payment hash from a BOLT11 invoice by checking it against LNbits.
103
+ * LNbits returns the payment_hash when creating an invoice, but verifyPayment
104
+ * only receives pay_req. We decode it via LNbits decode endpoint.
105
+ */
106
+ async getPaymentHashFromInvoice(bolt11) {
107
+ const response = await fetch(`${this.lnbitsUrl}/api/v1/payments/decode`, {
108
+ method: 'POST',
109
+ headers: this.buildHeaders(),
110
+ body: JSON.stringify({ data: bolt11 }),
111
+ });
112
+ if (response.ok) {
113
+ const decoded = (await response.json());
114
+ if (decoded.payment_hash) {
115
+ return decoded.payment_hash;
116
+ }
117
+ }
118
+ // Fallback: search recent payments for matching bolt11
119
+ const paymentsResponse = await fetch(`${this.lnbitsUrl}/api/v1/payments?limit=50`, {
120
+ method: 'GET',
121
+ headers: this.buildHeaders(),
122
+ });
123
+ if (paymentsResponse.ok) {
124
+ const payments = (await paymentsResponse.json());
125
+ const match = payments.find((p) => p.bolt11 === bolt11);
126
+ if (match) {
127
+ return match.payment_hash;
128
+ }
129
+ }
130
+ throw new Error('Could not resolve payment hash from invoice');
131
+ }
132
+ }
133
+ //# sourceMappingURL=ln-bolt11-lnbits-payment-processor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ln-bolt11-lnbits-payment-processor.js","sourceRoot":"","sources":["../../../../src/payments/processors/ln-bolt11-lnbits-payment-processor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ import type { RelayHandler } from '../../core/interfaces.js';
2
+ import type { PaymentProcessor, PaymentProcessorCreateParams, PaymentProcessorVerifyParams } from '../types.js';
3
+ export interface LnBolt11NwcPaymentProcessorOptions {
4
+ /** NIP-47 `nostr+walletconnect://...` connection string. */
5
+ nwcConnectionString: string;
6
+ /** Optional relay handler to reuse; defaults to an ApplesauceRelayPool built from the connection relays. */
7
+ relayHandler?: RelayHandler;
8
+ /** Fallback TTL in seconds if wallet does not provide expires_at. @default 300 */
9
+ ttlSeconds?: number;
10
+ /** `make_invoice.expiry` in seconds. @default ttlSeconds */
11
+ invoiceExpirySeconds?: number;
12
+ /** Poll interval for `lookup_invoice`. @default 1500 */
13
+ pollIntervalMs?: number;
14
+ /** Per-request response timeout. @default 60_000 */
15
+ responseTimeoutMs?: number;
16
+ }
17
+ /**
18
+ * CEP-8 server payment processor for PMI `bitcoin-lightning-bolt11` backed by NIP-47 (NWC).
19
+ */
20
+ export declare class LnBolt11NwcPaymentProcessor implements PaymentProcessor {
21
+ readonly pmi: "bitcoin-lightning-bolt11";
22
+ private readonly nwc;
23
+ private readonly ttlSeconds;
24
+ private readonly invoiceExpirySeconds;
25
+ private readonly pollIntervalMs;
26
+ private readonly logger;
27
+ constructor(options: LnBolt11NwcPaymentProcessorOptions);
28
+ private isSettledInvoice;
29
+ private getReceiptFromInvoiceResult;
30
+ createPaymentRequired(params: PaymentProcessorCreateParams): Promise<{
31
+ amount: number;
32
+ pay_req: string;
33
+ description?: string;
34
+ pmi: string;
35
+ ttl?: number;
36
+ }>;
37
+ verifyPayment(params: PaymentProcessorVerifyParams): Promise<{
38
+ _meta?: Record<string, unknown>;
39
+ }>;
40
+ }
41
+ //# sourceMappingURL=ln-bolt11-nwc-payment-processor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ln-bolt11-nwc-payment-processor.d.ts","sourceRoot":"","sources":["../../../../src/payments/processors/ln-bolt11-nwc-payment-processor.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,KAAK,EACV,gBAAgB,EAChB,4BAA4B,EAC5B,4BAA4B,EAC7B,MAAM,aAAa,CAAC;AAUrB,MAAM,WAAW,kCAAkC;IACjD,4DAA4D;IAC5D,mBAAmB,EAAE,MAAM,CAAC;IAC5B,4GAA4G;IAC5G,YAAY,CAAC,EAAE,YAAY,CAAC;IAE5B,kFAAkF;IAClF,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,4DAA4D;IAC5D,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,wDAAwD;IACxD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,oDAAoD;IACpD,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED;;GAEG;AACH,qBAAa,2BAA4B,YAAW,gBAAgB;IAClE,SAAgB,GAAG,6BAAgC;IAEnD,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAY;IAChC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;IACpC,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAS;IAC9C,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAS;IACxC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;gBAEb,OAAO,EAAE,kCAAkC;IAiB9D,OAAO,CAAC,gBAAgB;IAWxB,OAAO,CAAC,2BAA2B;IAqBtB,qBAAqB,CAChC,MAAM,EAAE,4BAA4B,GACnC,OAAO,CAAC;QACT,MAAM,EAAE,MAAM,CAAC;QACf,OAAO,EAAE,MAAM,CAAC;QAChB,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,GAAG,EAAE,MAAM,CAAC;QACZ,GAAG,CAAC,EAAE,MAAM,CAAC;KACd,CAAC;IAoCW,aAAa,CACxB,MAAM,EAAE,4BAA4B,GACnC,OAAO,CAAC;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,CAAC;CAoDhD"}
@@ -0,0 +1,129 @@
1
+ import { PMI_BITCOIN_LIGHTNING_BOLT11 } from '../pmis.js';
2
+ import { parseNwcConnectionString } from '../nip47/connection.js';
3
+ import { NwcClient } from '../nip47/nwc-client.js';
4
+ import { ApplesauceRelayPool } from '../../relay/applesauce-relay-pool.js';
5
+ import { createLogger } from '../../core/utils/logger.js';
6
+ import { sleep } from '../../core/utils/utils.js';
7
+ import { satsToMsats } from '../nip47/utils.js';
8
+ /**
9
+ * CEP-8 server payment processor for PMI `bitcoin-lightning-bolt11` backed by NIP-47 (NWC).
10
+ */
11
+ export class LnBolt11NwcPaymentProcessor {
12
+ constructor(options) {
13
+ var _a, _b, _c, _d;
14
+ this.pmi = PMI_BITCOIN_LIGHTNING_BOLT11;
15
+ const connection = parseNwcConnectionString(options.nwcConnectionString);
16
+ const relayHandler = (_a = options.relayHandler) !== null && _a !== void 0 ? _a : new ApplesauceRelayPool([...connection.relays]);
17
+ this.nwc = new NwcClient({
18
+ relayHandler,
19
+ connection,
20
+ responseTimeoutMs: options.responseTimeoutMs,
21
+ });
22
+ this.ttlSeconds = (_b = options.ttlSeconds) !== null && _b !== void 0 ? _b : 300;
23
+ this.invoiceExpirySeconds = (_c = options.invoiceExpirySeconds) !== null && _c !== void 0 ? _c : this.ttlSeconds;
24
+ this.pollIntervalMs = (_d = options.pollIntervalMs) !== null && _d !== void 0 ? _d : 1500;
25
+ this.logger = createLogger('payments/nwc-processor');
26
+ }
27
+ isSettledInvoice(result) {
28
+ // Wallets vary: some set `state`, some only set `settled_at`, some include `preimage`.
29
+ // Treat any of these signals as settlement.
30
+ if (!result)
31
+ return false;
32
+ if (result.state === 'settled')
33
+ return true;
34
+ if (typeof result.settled_at === 'number')
35
+ return true;
36
+ if (typeof result.preimage === 'string' && result.preimage.length > 0)
37
+ return true;
38
+ return false;
39
+ }
40
+ getReceiptFromInvoiceResult(params) {
41
+ const { result, requestEventId } = params;
42
+ // Prefer stable identifiers; avoid leaking preimage.
43
+ if (typeof (result === null || result === void 0 ? void 0 : result.payment_hash) === 'string' &&
44
+ result.payment_hash.length > 0) {
45
+ return result.payment_hash;
46
+ }
47
+ // Some wallets do not provide `payment_hash` on lookup results. Still produce a stable
48
+ // settlement identifier string for correlation.
49
+ const settledAt = typeof (result === null || result === void 0 ? void 0 : result.settled_at) === 'number' ? result.settled_at : undefined;
50
+ return `settled:${requestEventId}${settledAt ? `:${settledAt}` : ''}`;
51
+ }
52
+ async createPaymentRequired(params) {
53
+ var _a;
54
+ const request = {
55
+ amount: satsToMsats(params.amount),
56
+ description: params.description,
57
+ expiry: this.invoiceExpirySeconds,
58
+ };
59
+ const response = await this.nwc.request({
60
+ method: 'make_invoice',
61
+ resultType: 'make_invoice',
62
+ request: { method: 'make_invoice', params: request },
63
+ });
64
+ if (response.error) {
65
+ throw new Error(`NWC make_invoice failed: ${response.error.code} (${response.error.message})`);
66
+ }
67
+ const invoice = (_a = response.result) === null || _a === void 0 ? void 0 : _a.invoice;
68
+ if (!invoice) {
69
+ throw new Error('NWC make_invoice returned no invoice');
70
+ }
71
+ // Keep TTL simple and predictable. Some providers return non-standard `expires_at`.
72
+ const ttl = this.ttlSeconds;
73
+ return {
74
+ amount: params.amount,
75
+ pay_req: invoice,
76
+ description: params.description,
77
+ pmi: this.pmi,
78
+ ttl,
79
+ };
80
+ }
81
+ async verifyPayment(params) {
82
+ var _a;
83
+ // Note: server-payments middleware already bounds overall time by the `ttl` it emitted.
84
+ // We still keep this loop tight and predictable.
85
+ while (true) {
86
+ if ((_a = params.abortSignal) === null || _a === void 0 ? void 0 : _a.aborted) {
87
+ throw new Error('verifyPayment aborted');
88
+ }
89
+ const response = await this.nwc.request({
90
+ method: 'lookup_invoice',
91
+ resultType: 'lookup_invoice',
92
+ request: {
93
+ method: 'lookup_invoice',
94
+ params: { invoice: params.pay_req },
95
+ },
96
+ });
97
+ if (response.error) {
98
+ // NOT_FOUND can happen if the wallet is lagging; treat as pending.
99
+ if (response.error.code !== 'NOT_FOUND') {
100
+ throw new Error(`NWC lookup_invoice failed: ${response.error.code} (${response.error.message})`);
101
+ }
102
+ }
103
+ else {
104
+ const result = response.result;
105
+ this.logger.debug('lookup_invoice result', {
106
+ requestEventId: params.requestEventId,
107
+ state: result === null || result === void 0 ? void 0 : result.state,
108
+ hasPreimage: Boolean(result === null || result === void 0 ? void 0 : result.preimage),
109
+ hasSettledAt: typeof (result === null || result === void 0 ? void 0 : result.settled_at) === 'number',
110
+ hasPaymentHash: Boolean(result === null || result === void 0 ? void 0 : result.payment_hash),
111
+ });
112
+ if (this.isSettledInvoice(result)) {
113
+ // Prefer payment_hash as a stable identifier (avoid exposing preimages).
114
+ const paymentHash = this.getReceiptFromInvoiceResult({
115
+ result,
116
+ requestEventId: params.requestEventId,
117
+ });
118
+ return { _meta: { payment_hash: paymentHash } };
119
+ }
120
+ const state = result === null || result === void 0 ? void 0 : result.state;
121
+ if (state === 'expired' || state === 'failed') {
122
+ throw new Error(`Invoice ${state}`);
123
+ }
124
+ }
125
+ await sleep(this.pollIntervalMs);
126
+ }
127
+ }
128
+ }
129
+ //# sourceMappingURL=ln-bolt11-nwc-payment-processor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ln-bolt11-nwc-payment-processor.js","sourceRoot":"","sources":["../../../../src/payments/processors/ln-bolt11-nwc-payment-processor.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ import { CorrelatedNotificationSender, PaymentProcessor, PricedCapability, ResolvePriceFn, ServerMiddlewareFn } from './types.js';
2
+ export interface ServerPaymentsOptions {
3
+ processors: readonly PaymentProcessor[];
4
+ pricedCapabilities: readonly PricedCapability[];
5
+ /** Optional dynamic pricing callback used to compute a per-request quote. */
6
+ resolvePrice?: ResolvePriceFn;
7
+ /**
8
+ * Maximum time to keep a request in pending-payment state.
9
+ *
10
+ * Note: if the payment request includes a CEP-8 `ttl` (seconds), the effective
11
+ * verification timeout will be derived from that TTL. This option is primarily
12
+ * a memory/DoS guardrail.
13
+ *
14
+ * @default 300_000
15
+ */
16
+ paymentTtlMs?: number;
17
+ /**
18
+ * Maximum number of concurrent pending-payment request ids to track.
19
+ *
20
+ * This is a DoS/memory-safety guardrail.
21
+ * @default 1000
22
+ */
23
+ maxPendingPayments?: number;
24
+ }
25
+ /**
26
+ * Creates a server-side middleware that gates priced requests until payment is verified.
27
+ */
28
+ export declare function createServerPaymentsMiddleware(params: {
29
+ sender: CorrelatedNotificationSender;
30
+ options: ServerPaymentsOptions;
31
+ }): ServerMiddlewareFn;
32
+ //# sourceMappingURL=server-payments.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server-payments.d.ts","sourceRoot":"","sources":["../../../src/payments/server-payments.ts"],"names":[],"mappings":"AACA,OAAO,EACL,4BAA4B,EAE5B,gBAAgB,EAGhB,gBAAgB,EAGhB,cAAc,EACd,kBAAkB,EAEnB,MAAM,YAAY,CAAC;AAIpB,MAAM,WAAW,qBAAqB;IACpC,UAAU,EAAE,SAAS,gBAAgB,EAAE,CAAC;IACxC,kBAAkB,EAAE,SAAS,gBAAgB,EAAE,CAAC;IAEhD,6EAA6E;IAC7E,YAAY,CAAC,EAAE,cAAc,CAAC;IAC9B;;;;;;;;OAQG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB;;;;;OAKG;IACH,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAuHD;;GAEG;AACH,wBAAgB,8BAA8B,CAAC,MAAM,EAAE;IACrD,MAAM,EAAE,4BAA4B,CAAC;IACrC,OAAO,EAAE,qBAAqB,CAAC;CAChC,GAAG,kBAAkB,CA6JrB"}
@@ -0,0 +1,199 @@
1
+ import { isJsonRpcRequest, } from './types.js';
2
+ import { LruCache } from '../core/utils/lru-cache.js';
3
+ import { withTimeout } from '../core/utils/utils.js';
4
+ function purgeExpiredPending(params) {
5
+ let checked = 0;
6
+ for (const [key, value] of params.pending.entries()) {
7
+ if (checked >= params.maxToCheck) {
8
+ break;
9
+ }
10
+ checked += 1;
11
+ if (value.expiresAtMs <= params.nowMs) {
12
+ params.pending.delete(key);
13
+ }
14
+ }
15
+ }
16
+ function getVerificationTimeoutMs(params) {
17
+ // CEP-8 TTL is in seconds. If TTL is absent, default is 5 minutes.
18
+ const ttlSeconds = params.ttlSeconds;
19
+ if (ttlSeconds === undefined) {
20
+ return 5 * 60 * 1000;
21
+ }
22
+ if (!Number.isFinite(ttlSeconds) || ttlSeconds <= 0) {
23
+ return 5 * 60 * 1000;
24
+ }
25
+ return Math.floor(ttlSeconds * 1000);
26
+ }
27
+ function matchPricedCapability(message, priced) {
28
+ const capabilityName = getCapabilityNameForPricing(message);
29
+ return priced.find((p) => {
30
+ if (p.method !== message.method)
31
+ return false;
32
+ if (p.name === undefined)
33
+ return true;
34
+ return p.name === capabilityName;
35
+ });
36
+ }
37
+ function getCapabilityNameForPricing(message) {
38
+ const params = message.params;
39
+ switch (message.method) {
40
+ case 'tools/call': {
41
+ const name = params === null || params === void 0 ? void 0 : params.name;
42
+ return typeof name === 'string' ? name : undefined;
43
+ }
44
+ case 'prompts/get': {
45
+ const name = params === null || params === void 0 ? void 0 : params.name;
46
+ return typeof name === 'string' ? name : undefined;
47
+ }
48
+ case 'resources/read': {
49
+ const uri = params === null || params === void 0 ? void 0 : params.uri;
50
+ return typeof uri === 'string' ? uri : undefined;
51
+ }
52
+ default:
53
+ return undefined;
54
+ }
55
+ }
56
+ function createPaymentRequiredNotification(params) {
57
+ return {
58
+ jsonrpc: '2.0',
59
+ method: 'notifications/payment_required',
60
+ params,
61
+ };
62
+ }
63
+ function createPaymentAcceptedNotification(params) {
64
+ return {
65
+ jsonrpc: '2.0',
66
+ method: 'notifications/payment_accepted',
67
+ params,
68
+ };
69
+ }
70
+ function createPaymentRejectedNotification(params) {
71
+ return {
72
+ jsonrpc: '2.0',
73
+ method: 'notifications/payment_rejected',
74
+ params,
75
+ };
76
+ }
77
+ function isResolvePriceRejection(quote) {
78
+ return 'reject' in quote && quote.reject;
79
+ }
80
+ /**
81
+ * Creates a server-side middleware that gates priced requests until payment is verified.
82
+ */
83
+ export function createServerPaymentsMiddleware(params) {
84
+ var _a, _b;
85
+ const { sender, options } = params;
86
+ const processorsByPmi = new Map(options.processors.map((p) => [p.pmi, p]));
87
+ const paymentTtlMs = (_a = options.paymentTtlMs) !== null && _a !== void 0 ? _a : 300000;
88
+ const pending = new LruCache((_b = options.maxPendingPayments) !== null && _b !== void 0 ? _b : 1000);
89
+ return async (message, ctx, forward) => {
90
+ // Only gate requests. Never interfere with notifications.
91
+ if (!isJsonRpcRequest(message)) {
92
+ await forward(message);
93
+ return;
94
+ }
95
+ const priced = matchPricedCapability(message, options.pricedCapabilities);
96
+ if (!priced) {
97
+ await forward(message);
98
+ return;
99
+ }
100
+ const requestEventId = String(message.id);
101
+ const now = Date.now();
102
+ // Opportunistic cleanup so one-shot spam doesn't accumulate until reuse.
103
+ purgeExpiredPending({ pending, nowMs: now, maxToCheck: 25 });
104
+ const existing = pending.get(requestEventId);
105
+ if (existing && existing.expiresAtMs > now) {
106
+ // Duplicate request event id: await the in-flight work deterministically.
107
+ // This avoids double-charge races and avoids black-holing duplicates.
108
+ await existing.inFlight;
109
+ return;
110
+ }
111
+ // IMPORTANT: set pending state synchronously before any await to make idempotency atomic.
112
+ const inFlight = (async () => {
113
+ var _a, _b, _c;
114
+ const clientPmis = ctx.clientPmis;
115
+ const chosenPmi = clientPmis
116
+ ? clientPmis.find((pmi) => processorsByPmi.has(pmi))
117
+ : undefined;
118
+ const chosenProcessor = chosenPmi
119
+ ? processorsByPmi.get(chosenPmi)
120
+ : options.processors[0];
121
+ if (!chosenProcessor) {
122
+ throw new Error('No payment processors configured');
123
+ }
124
+ const processor = (_a = processorsByPmi.get(chosenProcessor.pmi)) !== null && _a !== void 0 ? _a : chosenProcessor;
125
+ const quote = options.resolvePrice
126
+ ? await options.resolvePrice({
127
+ capability: priced,
128
+ request: message,
129
+ clientPubkey: ctx.clientPubkey,
130
+ requestEventId,
131
+ })
132
+ : { amount: priced.amount, description: priced.description };
133
+ // Handle rejection: emit payment_rejected and do not forward.
134
+ if (isResolvePriceRejection(quote)) {
135
+ const rejectedNotification = createPaymentRejectedNotification({
136
+ pmi: processor.pmi,
137
+ amount: priced.amount,
138
+ message: quote.message,
139
+ });
140
+ await sender.sendNotification(ctx.clientPubkey, rejectedNotification, requestEventId);
141
+ }
142
+ else {
143
+ const resolvedQuote = quote;
144
+ const paymentRequired = await processor.createPaymentRequired({
145
+ amount: resolvedQuote.amount,
146
+ description: resolvedQuote.description,
147
+ requestEventId,
148
+ clientPubkey: ctx.clientPubkey,
149
+ });
150
+ const mergedMeta = resolvedQuote.meta === undefined &&
151
+ paymentRequired._meta === undefined
152
+ ? undefined
153
+ : {
154
+ ...((_b = paymentRequired._meta) !== null && _b !== void 0 ? _b : {}),
155
+ ...((_c = resolvedQuote.meta) !== null && _c !== void 0 ? _c : {}),
156
+ };
157
+ const requiredNotification = createPaymentRequiredNotification({
158
+ amount: paymentRequired.amount,
159
+ pay_req: paymentRequired.pay_req,
160
+ pmi: paymentRequired.pmi,
161
+ description: paymentRequired.description,
162
+ ttl: paymentRequired.ttl,
163
+ _meta: mergedMeta,
164
+ });
165
+ await sender.sendNotification(ctx.clientPubkey, requiredNotification, requestEventId);
166
+ const verifyTimeoutMs = getVerificationTimeoutMs({
167
+ ttlSeconds: paymentRequired.ttl,
168
+ });
169
+ const effectiveTimeoutMs = Math.min(verifyTimeoutMs, paymentTtlMs);
170
+ const controller = new AbortController();
171
+ const verified = await withTimeout(processor.verifyPayment({
172
+ pay_req: paymentRequired.pay_req,
173
+ requestEventId,
174
+ clientPubkey: ctx.clientPubkey,
175
+ abortSignal: controller.signal,
176
+ }), effectiveTimeoutMs, 'verifyPayment timed out').finally(() => controller.abort());
177
+ const acceptedNotification = createPaymentAcceptedNotification({
178
+ amount: paymentRequired.amount,
179
+ pmi: paymentRequired.pmi,
180
+ _meta: verified._meta,
181
+ });
182
+ await sender.sendNotification(ctx.clientPubkey, acceptedNotification, requestEventId);
183
+ await forward(message);
184
+ }
185
+ })();
186
+ const state = {
187
+ expiresAtMs: now + paymentTtlMs,
188
+ inFlight,
189
+ };
190
+ pending.set(requestEventId, state);
191
+ try {
192
+ await inFlight;
193
+ }
194
+ finally {
195
+ pending.delete(requestEventId);
196
+ }
197
+ };
198
+ }
199
+ //# sourceMappingURL=server-payments.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server-payments.js","sourceRoot":"","sources":["../../../src/payments/server-payments.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import type { NostrServerTransport } from '../transport/nostr-server-transport.js';
2
+ import type { ServerPaymentsOptions } from './server-payments.js';
3
+ /**
4
+ * Attaches CEP-8 payments gating to a NostrServerTransport.
5
+ */
6
+ export declare function withServerPayments(transport: NostrServerTransport, options: ServerPaymentsOptions): NostrServerTransport;
7
+ //# sourceMappingURL=server-transport-payments.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server-transport-payments.d.ts","sourceRoot":"","sources":["../../../src/payments/server-transport-payments.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,wCAAwC,CAAC;AACnF,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAKlE;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,SAAS,EAAE,oBAAoB,EAC/B,OAAO,EAAE,qBAAqB,GAC7B,oBAAoB,CAatB"}
@@ -0,0 +1,14 @@
1
+ import { createCapTagsFromPricedCapabilities } from './cap-tags.js';
2
+ import { createPmiTagsFromProcessors } from './pmi-tags.js';
3
+ import { createServerPaymentsMiddleware } from './server-payments.js';
4
+ /**
5
+ * Attaches CEP-8 payments gating to a NostrServerTransport.
6
+ */
7
+ export function withServerPayments(transport, options) {
8
+ // CEP-8 discovery tags: advertise supported PMIs + reference pricing on announcement/list events.
9
+ transport.setAnnouncementExtraTags(createPmiTagsFromProcessors(options.processors));
10
+ transport.setAnnouncementPricingTags(createCapTagsFromPricedCapabilities(options.pricedCapabilities));
11
+ transport.addInboundMiddleware(createServerPaymentsMiddleware({ sender: transport, options }));
12
+ return transport;
13
+ }
14
+ //# sourceMappingURL=server-transport-payments.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server-transport-payments.js","sourceRoot":"","sources":["../../../src/payments/server-transport-payments.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,mCAAmC,EAAE,MAAM,eAAe,CAAC;AACpE,OAAO,EAAE,2BAA2B,EAAE,MAAM,eAAe,CAAC;AAC5D,OAAO,EAAE,8BAA8B,EAAE,MAAM,sBAAsB,CAAC;AAEtE;;GAEG;AACH,MAAM,UAAU,kBAAkB,CAChC,SAA+B,EAC/B,OAA8B;IAE9B,kGAAkG;IAClG,SAAS,CAAC,wBAAwB,CAChC,2BAA2B,CAAC,OAAO,CAAC,UAAU,CAAC,CAChD,CAAC;IACF,SAAS,CAAC,0BAA0B,CAClC,mCAAmC,CAAC,OAAO,CAAC,kBAAkB,CAAC,CAChE,CAAC;IAEF,SAAS,CAAC,oBAAoB,CAC5B,8BAA8B,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,CAC/D,CAAC;IACF,OAAO,SAAS,CAAC;AACnB,CAAC"}