@nodana/phoenixd-mpp-sdk 0.0.0-stage → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Nodana
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/NOTICE ADDED
@@ -0,0 +1,27 @@
1
+ The Lightning charge wire schema in src/Methods.ts is adapted from:
2
+ https://github.com/buildonspark/lightning-mpp-sdk
3
+ Copyright (c) 2026 Lightspark Group, Inc.
4
+
5
+ The upstream licence follows:
6
+
7
+ MIT License
8
+
9
+ Copyright (c) 2026 Lightspark Group, Inc.
10
+
11
+ Permission is hereby granted, free of charge, to any person obtaining a copy
12
+ of this software and associated documentation files (the "Software"), to deal
13
+ in the Software without restriction, including without limitation the rights
14
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15
+ copies of the Software, and to permit persons to whom the Software is
16
+ furnished to do so, subject to the following conditions:
17
+
18
+ The above copyright notice and this permission notice shall be included in all
19
+ copies or substantial portions of the Software.
20
+
21
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,148 @@
1
- # Temporary Holding Version
1
+ # Phoenixd MPP SDK
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Accept or send Lightning payments for API requests using the Machine Payments Protocol (MPP) and a Phoenixd node. This package supplies the Phoenixd payment method for `mppx`; `@nodana/phoenixd-ts` connects it to your node.
4
+
5
+ Use Node.js 22.12 or later. The package provides TypeScript declarations and ESM and CommonJS exports.
6
+
7
+ ## Install
8
+
9
+ Install the adapter and its dependencies:
10
+
11
+ ```sh
12
+ npm install @nodana/phoenixd-mpp-sdk @nodana/phoenixd-ts mppx
13
+ ```
14
+
15
+ ## Accept payment for a request
16
+
17
+ Configure `PHOENIXD_URL`, `PHOENIXD_PASSWORD` and `MPP_SECRET_KEY` in your service's environment. Use your node's HTTPS endpoint and set `PHOENIXD_PASSWORD` to its restricted password (`http-password-limited-access`). The receiving adapter only creates and decodes invoices; it does not need permission to send payments. Generate a signing secret with `openssl rand -hex 32` and save it in your service's secret configuration. Keep the same secret across instances and restarts.
18
+
19
+ ```ts
20
+ import { Phoenixd } from "@nodana/phoenixd-ts";
21
+ import { Mppx, phoenixd } from "@nodana/phoenixd-mpp-sdk/server";
22
+
23
+ const node = new Phoenixd(
24
+ process.env.PHOENIXD_URL!,
25
+ process.env.PHOENIXD_PASSWORD!,
26
+ { timeoutMs: 15_000 },
27
+ );
28
+ const payments = Mppx.create({
29
+ methods: [phoenixd.charge({ client: node })],
30
+ secretKey: process.env.MPP_SECRET_KEY!,
31
+ });
32
+
33
+ export async function handler(request: Request): Promise<Response> {
34
+ const payment = await payments.charge({
35
+ amount: "100",
36
+ description: "Paid API query",
37
+ })(request);
38
+
39
+ if (payment.status === 402) return payment.challenge;
40
+
41
+ // Run your query or tool only after payment is accepted.
42
+ return payment.withReceipt(Response.json({ answer: "Your paid result" }));
43
+ }
44
+ ```
45
+
46
+ Mount the handler at your paid endpoint. `amount: '100'` charges 100 satoshis. An unpaid request receives a payment challenge; a paid request receives your result and a receipt.
47
+
48
+ ## Choose payment storage
49
+
50
+ The adapter uses in-memory storage by default, suitable for development. For deployed services, use Redis so every server instance shares payment state. The adapter handles the checks; you supply a connected Redis client.
51
+
52
+ Install the Redis client if your application does not already use it:
53
+
54
+ ```sh
55
+ npm install redis
56
+ ```
57
+
58
+ ```ts
59
+ import { createClient } from "redis";
60
+ import { redisStore } from "@nodana/phoenixd-mpp-sdk/server";
61
+
62
+ const redis = createClient({ url: process.env.REDIS_URL! });
63
+ redis.on("error", () => console.error("Redis connection error"));
64
+ await redis.connect();
65
+
66
+ const payments = Mppx.create({
67
+ methods: [phoenixd.charge({ client: node, store: redisStore(redis) })],
68
+ secretKey: process.env.MPP_SECRET_KEY!,
69
+ });
70
+ ```
71
+
72
+ Reuse your existing connected client if you have one. Use the same persistent Redis service and signing secret across your server instances. Expired payment records are removed automatically.
73
+
74
+ If several services share Redis, choose a namespace with `redisStore(redis, { keyPrefix: 'my-api' })` and use it consistently across that service's instances.
75
+
76
+ ## Pay for a request
77
+
78
+ Run the payer in a backend or a trusted Node.js application with its own funded Phoenixd node. Set its `PHOENIXD_PASSWORD` to the full-access password (`http-password`), since paying invoices requires spending permission. `maxAmountSat` is required and limits the invoice amount for each challenge; routing fees are additional.
79
+
80
+ ```ts
81
+ import { Phoenixd } from "@nodana/phoenixd-ts";
82
+ import { Mppx, phoenixd } from "@nodana/phoenixd-mpp-sdk/client";
83
+
84
+ const node = new Phoenixd(
85
+ process.env.PHOENIXD_URL!,
86
+ process.env.PHOENIXD_PASSWORD!,
87
+ { timeoutMs: 15_000 },
88
+ );
89
+ const payments = Mppx.create({
90
+ methods: [phoenixd.charge({ client: node, maxAmountSat: 100 })],
91
+ polyfill: false,
92
+ });
93
+
94
+ const response = await payments.fetch("https://api.example.com/query");
95
+ if (!response.ok) throw new Error(`API request failed: ${response.status}`);
96
+ console.log(await response.json());
97
+ ```
98
+
99
+ `payments.fetch` pays a supported challenge within the limit and retries the request. Choose a limit appropriate for the API you are calling. Keep Phoenixd credentials in your backend; they allow spending from the node. Use HTTPS for paid endpoints.
100
+
101
+ ## Configure a charge
102
+
103
+ | Option | Server | Client |
104
+ | ---------------------- | ---------------------------------------------------------------------- | -------------------------------------------------------------- |
105
+ | `client` | Configured Phoenixd client for creating and decoding invoices | Configured client for decoding, paying and looking up payments |
106
+ | `store` | `redisStore(redis)` for shared state; defaults to process-local memory | — |
107
+ | `invoiceExpirySeconds` | Invoice lifetime; defaults to 3600 seconds | — |
108
+ | `network` | Optional expected invoice network | Expected network; defaults to `mainnet` |
109
+ | `maxAmountSat` | — | Required maximum invoice amount per challenge |
110
+
111
+ Set the challenge expiry on the handler when needed:
112
+
113
+ ```ts
114
+ const payment = await payments.charge({
115
+ amount: "100",
116
+ expires: new Date(Date.now() + 60_000),
117
+ })(request);
118
+ ```
119
+
120
+ The challenge expires no later than its invoice. Use `network: 'regtest'` on both payment methods when testing with regtest nodes.
121
+
122
+ ## Troubleshoot
123
+
124
+ Probe an endpoint without paying:
125
+
126
+ ```sh
127
+ curl -i https://api.example.com/query
128
+ ```
129
+
130
+ Expect HTTP `402` and a `WWW-Authenticate: Payment` header. Server failures creating invoices or accessing storage must be caught by your application's error handling; respond with a service error and keep the paid result behind the payment check.
131
+
132
+ Client errors expose a `code` through `PhoenixdPaymentError`, exported from the client entry point:
133
+
134
+ | Code | Action |
135
+ | ----------------- | ----------------------------------------------------------------------------------- |
136
+ | `amount_limit` | Check the endpoint's price and your configured limit. |
137
+ | `invalid_invoice` | Check the invoice amount, expiry and network. Request a fresh challenge if expired. |
138
+ | `payment_failed` | Check your node balance and outgoing payment history. |
139
+ | `payment_unknown` | Check outgoing payment history before trying again; the payment may have succeeded. |
140
+
141
+ If a paid request is rejected, check that you retried the same URL, method and body before expiry. A credential authorises one request. Check that all server instances use the same signing secret and storage.
142
+
143
+ ## Reference
144
+
145
+ - [MPP overview](https://mpp.dev/overview)
146
+ - [mppx SDK](https://mpp.dev/sdk/typescript)
147
+ - [Phoenixd HTTP API](https://phoenix.acinq.co/server/api)
148
+ - [Development and storage integration](docs/development.md)
@@ -0,0 +1,45 @@
1
+ // src/shared.ts
2
+ import { createHash } from "crypto";
3
+ function satoshis(amount) {
4
+ if (!/^[1-9][0-9]*$/.test(amount))
5
+ throw new TypeError("amount must be a positive integer string in satoshis");
6
+ const value = Number(amount);
7
+ if (!Number.isSafeInteger(value * 1e3))
8
+ throw new TypeError(
9
+ "amount exceeds the safely representable millisatoshi range"
10
+ );
11
+ return value;
12
+ }
13
+ function paymentHash(preimage) {
14
+ if (!/^[0-9a-f]{64}$/.test(preimage))
15
+ throw new TypeError("Invalid payment preimage");
16
+ return createHash("sha256").update(Buffer.from(preimage, "hex")).digest("hex");
17
+ }
18
+ function invoiceDetails(invoice, request, expected) {
19
+ if (request.currency !== "sat" || invoice.amount !== satoshis(request.amount) * 1e3)
20
+ throw new TypeError("Invoice amount does not match the requested satoshis");
21
+ if (!/^[0-9a-f]{64}$/.test(invoice.paymentHash))
22
+ throw new TypeError("Invoice has an invalid payment hash");
23
+ const network = invoice.chain;
24
+ if (network !== "mainnet" && network !== "regtest" && network !== "signet")
25
+ throw new TypeError("Invoice uses an unsupported Lightning network");
26
+ if (expected !== void 0 && network !== expected)
27
+ throw new TypeError(
28
+ "Invoice network does not match the configured network"
29
+ );
30
+ const expiresAt = (invoice.timestampSeconds + (invoice.expirySeconds ?? 3600)) * 1e3;
31
+ if (!Number.isSafeInteger(expiresAt) || expiresAt <= Date.now())
32
+ throw new TypeError("Invoice is expired or has an invalid expiry");
33
+ return { paymentHash: invoice.paymentHash, network, expiresAt };
34
+ }
35
+ async function bodyHash(request) {
36
+ return createHash("sha256").update(Buffer.from(await request.clone().arrayBuffer())).digest("hex");
37
+ }
38
+
39
+ export {
40
+ satoshis,
41
+ paymentHash,
42
+ invoiceDetails,
43
+ bodyHash
44
+ };
45
+ //# sourceMappingURL=chunk-7BE7G2UI.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/shared.ts"],"sourcesContent":["import { createHash } from \"node:crypto\";\nimport type { DecodedInvoice } from \"@nodana/phoenixd-ts\";\nimport type { ChargeRequest, LightningNetwork } from \"./Methods\";\n\nexport function satoshis(amount: string): number {\n if (!/^[1-9][0-9]*$/.test(amount))\n throw new TypeError(\"amount must be a positive integer string in satoshis\");\n\n const value = Number(amount);\n\n if (!Number.isSafeInteger(value * 1000))\n throw new TypeError(\n \"amount exceeds the safely representable millisatoshi range\",\n );\n\n return value;\n}\n\nexport function paymentHash(preimage: string): string {\n if (!/^[0-9a-f]{64}$/.test(preimage))\n throw new TypeError(\"Invalid payment preimage\");\n\n return createHash(\"sha256\")\n .update(Buffer.from(preimage, \"hex\"))\n .digest(\"hex\");\n}\n\nexport function invoiceDetails(\n invoice: DecodedInvoice,\n request: Pick<ChargeRequest, \"amount\" | \"currency\">,\n expected?: LightningNetwork,\n): { paymentHash: string; network: LightningNetwork; expiresAt: number } {\n if (\n request.currency !== \"sat\" ||\n invoice.amount !== satoshis(request.amount) * 1000\n )\n throw new TypeError(\"Invoice amount does not match the requested satoshis\");\n\n if (!/^[0-9a-f]{64}$/.test(invoice.paymentHash))\n throw new TypeError(\"Invoice has an invalid payment hash\");\n\n const network = invoice.chain;\n\n if (network !== \"mainnet\" && network !== \"regtest\" && network !== \"signet\")\n throw new TypeError(\"Invoice uses an unsupported Lightning network\");\n\n if (expected !== undefined && network !== expected)\n throw new TypeError(\n \"Invoice network does not match the configured network\",\n );\n\n const expiresAt =\n (invoice.timestampSeconds + (invoice.expirySeconds ?? 3600)) * 1000;\n\n if (!Number.isSafeInteger(expiresAt) || expiresAt <= Date.now())\n throw new TypeError(\"Invoice is expired or has an invalid expiry\");\n\n return { paymentHash: invoice.paymentHash, network, expiresAt };\n}\n\nexport async function bodyHash(request: Request): Promise<string> {\n // Clone preserves the body for the application handler.\n return createHash(\"sha256\")\n .update(Buffer.from(await request.clone().arrayBuffer()))\n .digest(\"hex\");\n}\n"],"mappings":";AAAA,SAAS,kBAAkB;AAIpB,SAAS,SAAS,QAAwB;AAC/C,MAAI,CAAC,gBAAgB,KAAK,MAAM;AAC9B,UAAM,IAAI,UAAU,sDAAsD;AAE5E,QAAM,QAAQ,OAAO,MAAM;AAE3B,MAAI,CAAC,OAAO,cAAc,QAAQ,GAAI;AACpC,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAEF,SAAO;AACT;AAEO,SAAS,YAAY,UAA0B;AACpD,MAAI,CAAC,iBAAiB,KAAK,QAAQ;AACjC,UAAM,IAAI,UAAU,0BAA0B;AAEhD,SAAO,WAAW,QAAQ,EACvB,OAAO,OAAO,KAAK,UAAU,KAAK,CAAC,EACnC,OAAO,KAAK;AACjB;AAEO,SAAS,eACd,SACA,SACA,UACuE;AACvE,MACE,QAAQ,aAAa,SACrB,QAAQ,WAAW,SAAS,QAAQ,MAAM,IAAI;AAE9C,UAAM,IAAI,UAAU,sDAAsD;AAE5E,MAAI,CAAC,iBAAiB,KAAK,QAAQ,WAAW;AAC5C,UAAM,IAAI,UAAU,qCAAqC;AAE3D,QAAM,UAAU,QAAQ;AAExB,MAAI,YAAY,aAAa,YAAY,aAAa,YAAY;AAChE,UAAM,IAAI,UAAU,+CAA+C;AAErE,MAAI,aAAa,UAAa,YAAY;AACxC,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAEF,QAAM,aACH,QAAQ,oBAAoB,QAAQ,iBAAiB,SAAS;AAEjE,MAAI,CAAC,OAAO,cAAc,SAAS,KAAK,aAAa,KAAK,IAAI;AAC5D,UAAM,IAAI,UAAU,6CAA6C;AAEnE,SAAO,EAAE,aAAa,QAAQ,aAAa,SAAS,UAAU;AAChE;AAEA,eAAsB,SAAS,SAAmC;AAEhE,SAAO,WAAW,QAAQ,EACvB,OAAO,OAAO,KAAK,MAAM,QAAQ,MAAM,EAAE,YAAY,CAAC,CAAC,EACvD,OAAO,KAAK;AACjB;","names":[]}
@@ -0,0 +1,67 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __export = (target, all) => {
3
+ for (var name in all)
4
+ __defProp(target, name, { get: all[name], enumerable: true });
5
+ };
6
+
7
+ // src/Methods.ts
8
+ var Methods_exports = {};
9
+ __export(Methods_exports, {
10
+ charge: () => charge
11
+ });
12
+ import { Method, z } from "mppx";
13
+ var charge = Method.from({
14
+ name: "lightning",
15
+ intent: "charge",
16
+ schema: {
17
+ credential: {
18
+ payload: z.object({
19
+ preimage: z.string().check(z.regex(/^[0-9a-f]{64}$/))
20
+ })
21
+ },
22
+ request: z.object({
23
+ amount: z.string().check(z.regex(/^[1-9][0-9]*$/)),
24
+ currency: z.literal("sat"),
25
+ description: z.optional(z.string()),
26
+ methodDetails: z.object({
27
+ invoice: z.string(),
28
+ paymentHash: z.optional(z.string().check(z.regex(/^[0-9a-f]{64}$/))),
29
+ network: z.optional(z.enum(["mainnet", "regtest", "signet"]))
30
+ })
31
+ })
32
+ }
33
+ });
34
+
35
+ // src/errors.ts
36
+ import { Errors } from "mppx";
37
+ var ChargeError = class extends Errors.PaymentError {
38
+ constructor(code, message) {
39
+ super(message);
40
+ this.code = code;
41
+ const problem = code === "store_unavailable" || code === "invalid_invoice" ? "internal-payment-error" : code === "invoice_expired" ? "payment-expired" : code === "invalid_preimage" || code === "already_consumed" ? "verification-failed" : "invalid-challenge";
42
+ this.type = `https://paymentauth.org/problems/${problem}`;
43
+ this.status = code === "store_unavailable" ? 503 : code === "invalid_invoice" ? 502 : 402;
44
+ }
45
+ code;
46
+ name = "ChargeError";
47
+ title = "Lightning payment rejected";
48
+ type;
49
+ status;
50
+ };
51
+ var PhoenixdPaymentError = class extends Error {
52
+ constructor(code, message) {
53
+ super(message);
54
+ this.code = code;
55
+ }
56
+ code;
57
+ name = "PhoenixdPaymentError";
58
+ };
59
+
60
+ export {
61
+ __export,
62
+ charge,
63
+ Methods_exports,
64
+ ChargeError,
65
+ PhoenixdPaymentError
66
+ };
67
+ //# sourceMappingURL=chunk-EQRLZHAJ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/Methods.ts","../src/errors.ts"],"sourcesContent":["// Lightning wire schema adapted from buildonspark/lightning-mpp-sdk (MIT).\n// Copyright (c) 2026 Lightspark Group, Inc. See NOTICE.\nimport { Method, z } from \"mppx\";\n\nexport const charge = Method.from({\n name: \"lightning\",\n intent: \"charge\",\n schema: {\n credential: {\n payload: z.object({\n preimage: z.string().check(z.regex(/^[0-9a-f]{64}$/)),\n }),\n },\n request: z.object({\n amount: z.string().check(z.regex(/^[1-9][0-9]*$/)),\n currency: z.literal(\"sat\"),\n description: z.optional(z.string()),\n methodDetails: z.object({\n invoice: z.string(),\n paymentHash: z.optional(z.string().check(z.regex(/^[0-9a-f]{64}$/))),\n network: z.optional(z.enum([\"mainnet\", \"regtest\", \"signet\"])),\n }),\n }),\n },\n});\n\nexport type ChargeRequest = z.output<typeof charge.schema.request>;\n\nexport type LightningNetwork = NonNullable<\n ChargeRequest[\"methodDetails\"][\"network\"]\n>;\n","import { Errors } from \"mppx\";\n\nexport type ChargeErrorCode =\n | \"unknown_challenge\"\n | \"invalid_challenge\"\n | \"invalid_preimage\"\n | \"invoice_expired\"\n | \"already_consumed\"\n | \"invalid_invoice\"\n | \"store_unavailable\";\n\nexport class ChargeError extends Errors.PaymentError {\n readonly name = \"ChargeError\";\n readonly title = \"Lightning payment rejected\";\n readonly type: string;\n override readonly status: number;\n\n constructor(\n public readonly code: ChargeErrorCode,\n message: string,\n ) {\n super(message);\n\n const problem =\n code === \"store_unavailable\" || code === \"invalid_invoice\"\n ? \"internal-payment-error\"\n : code === \"invoice_expired\"\n ? \"payment-expired\"\n : code === \"invalid_preimage\" || code === \"already_consumed\"\n ? \"verification-failed\"\n : \"invalid-challenge\";\n\n this.type = `https://paymentauth.org/problems/${problem}`;\n this.status =\n code === \"store_unavailable\"\n ? 503\n : code === \"invalid_invoice\"\n ? 502\n : 402;\n }\n}\n\nexport type ClientErrorCode =\n \"invalid_invoice\" | \"amount_limit\" | \"payment_failed\" | \"payment_unknown\";\n\nexport class PhoenixdPaymentError extends Error {\n readonly name = \"PhoenixdPaymentError\";\n\n constructor(\n public readonly code: ClientErrorCode,\n message: string,\n ) {\n super(message);\n }\n}\n"],"mappings":";;;;;;;AAAA;AAAA;AAAA;AAAA;AAEA,SAAS,QAAQ,SAAS;AAEnB,IAAM,SAAS,OAAO,KAAK;AAAA,EAChC,MAAM;AAAA,EACN,QAAQ;AAAA,EACR,QAAQ;AAAA,IACN,YAAY;AAAA,MACV,SAAS,EAAE,OAAO;AAAA,QAChB,UAAU,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAAA,MACtD,CAAC;AAAA,IACH;AAAA,IACA,SAAS,EAAE,OAAO;AAAA,MAChB,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,eAAe,CAAC;AAAA,MACjD,UAAU,EAAE,QAAQ,KAAK;AAAA,MACzB,aAAa,EAAE,SAAS,EAAE,OAAO,CAAC;AAAA,MAClC,eAAe,EAAE,OAAO;AAAA,QACtB,SAAS,EAAE,OAAO;AAAA,QAClB,aAAa,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC,CAAC;AAAA,QACnE,SAAS,EAAE,SAAS,EAAE,KAAK,CAAC,WAAW,WAAW,QAAQ,CAAC,CAAC;AAAA,MAC9D,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AACF,CAAC;;;ACxBD,SAAS,cAAc;AAWhB,IAAM,cAAN,cAA0B,OAAO,aAAa;AAAA,EAMnD,YACkB,MAChB,SACA;AACA,UAAM,OAAO;AAHG;AAKhB,UAAM,UACJ,SAAS,uBAAuB,SAAS,oBACrC,2BACA,SAAS,oBACP,oBACA,SAAS,sBAAsB,SAAS,qBACtC,wBACA;AAEV,SAAK,OAAO,oCAAoC,OAAO;AACvD,SAAK,SACH,SAAS,sBACL,MACA,SAAS,oBACP,MACA;AAAA,EACV;AAAA,EArBkB;AAAA,EANT,OAAO;AAAA,EACP,QAAQ;AAAA,EACR;AAAA,EACS;AAyBpB;AAKO,IAAM,uBAAN,cAAmC,MAAM;AAAA,EAG9C,YACkB,MAChB,SACA;AACA,UAAM,OAAO;AAHG;AAAA,EAIlB;AAAA,EAJkB;AAAA,EAHT,OAAO;AAQlB;","names":[]}
@@ -0,0 +1,244 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/client/index.ts
21
+ var client_exports = {};
22
+ __export(client_exports, {
23
+ Mppx: () => import_client.Mppx,
24
+ PhoenixdPaymentError: () => PhoenixdPaymentError,
25
+ charge: () => charge2,
26
+ phoenixd: () => methods_exports
27
+ });
28
+ module.exports = __toCommonJS(client_exports);
29
+ var import_client = require("mppx/client");
30
+
31
+ // src/client/methods.ts
32
+ var methods_exports = {};
33
+ __export(methods_exports, {
34
+ charge: () => charge2
35
+ });
36
+
37
+ // src/client/charge.ts
38
+ var import_mppx3 = require("mppx");
39
+
40
+ // src/Methods.ts
41
+ var import_mppx = require("mppx");
42
+ var charge = import_mppx.Method.from({
43
+ name: "lightning",
44
+ intent: "charge",
45
+ schema: {
46
+ credential: {
47
+ payload: import_mppx.z.object({
48
+ preimage: import_mppx.z.string().check(import_mppx.z.regex(/^[0-9a-f]{64}$/))
49
+ })
50
+ },
51
+ request: import_mppx.z.object({
52
+ amount: import_mppx.z.string().check(import_mppx.z.regex(/^[1-9][0-9]*$/)),
53
+ currency: import_mppx.z.literal("sat"),
54
+ description: import_mppx.z.optional(import_mppx.z.string()),
55
+ methodDetails: import_mppx.z.object({
56
+ invoice: import_mppx.z.string(),
57
+ paymentHash: import_mppx.z.optional(import_mppx.z.string().check(import_mppx.z.regex(/^[0-9a-f]{64}$/))),
58
+ network: import_mppx.z.optional(import_mppx.z.enum(["mainnet", "regtest", "signet"]))
59
+ })
60
+ })
61
+ }
62
+ });
63
+
64
+ // src/errors.ts
65
+ var import_mppx2 = require("mppx");
66
+ var ChargeError = class extends import_mppx2.Errors.PaymentError {
67
+ constructor(code, message) {
68
+ super(message);
69
+ this.code = code;
70
+ const problem = code === "store_unavailable" || code === "invalid_invoice" ? "internal-payment-error" : code === "invoice_expired" ? "payment-expired" : code === "invalid_preimage" || code === "already_consumed" ? "verification-failed" : "invalid-challenge";
71
+ this.type = `https://paymentauth.org/problems/${problem}`;
72
+ this.status = code === "store_unavailable" ? 503 : code === "invalid_invoice" ? 502 : 402;
73
+ }
74
+ code;
75
+ name = "ChargeError";
76
+ title = "Lightning payment rejected";
77
+ type;
78
+ status;
79
+ };
80
+ var PhoenixdPaymentError = class extends Error {
81
+ constructor(code, message) {
82
+ super(message);
83
+ this.code = code;
84
+ }
85
+ code;
86
+ name = "PhoenixdPaymentError";
87
+ };
88
+
89
+ // src/shared.ts
90
+ var import_node_crypto = require("crypto");
91
+ function satoshis(amount) {
92
+ if (!/^[1-9][0-9]*$/.test(amount))
93
+ throw new TypeError("amount must be a positive integer string in satoshis");
94
+ const value = Number(amount);
95
+ if (!Number.isSafeInteger(value * 1e3))
96
+ throw new TypeError(
97
+ "amount exceeds the safely representable millisatoshi range"
98
+ );
99
+ return value;
100
+ }
101
+ function paymentHash(preimage) {
102
+ if (!/^[0-9a-f]{64}$/.test(preimage))
103
+ throw new TypeError("Invalid payment preimage");
104
+ return (0, import_node_crypto.createHash)("sha256").update(Buffer.from(preimage, "hex")).digest("hex");
105
+ }
106
+ function invoiceDetails(invoice, request, expected) {
107
+ if (request.currency !== "sat" || invoice.amount !== satoshis(request.amount) * 1e3)
108
+ throw new TypeError("Invoice amount does not match the requested satoshis");
109
+ if (!/^[0-9a-f]{64}$/.test(invoice.paymentHash))
110
+ throw new TypeError("Invoice has an invalid payment hash");
111
+ const network = invoice.chain;
112
+ if (network !== "mainnet" && network !== "regtest" && network !== "signet")
113
+ throw new TypeError("Invoice uses an unsupported Lightning network");
114
+ if (expected !== void 0 && network !== expected)
115
+ throw new TypeError(
116
+ "Invoice network does not match the configured network"
117
+ );
118
+ const expiresAt = (invoice.timestampSeconds + (invoice.expirySeconds ?? 3600)) * 1e3;
119
+ if (!Number.isSafeInteger(expiresAt) || expiresAt <= Date.now())
120
+ throw new TypeError("Invoice is expired or has an invalid expiry");
121
+ return { paymentHash: invoice.paymentHash, network, expiresAt };
122
+ }
123
+
124
+ // src/client/charge.ts
125
+ function charge2({
126
+ client,
127
+ maxAmountSat,
128
+ network = "mainnet"
129
+ }) {
130
+ if (!Number.isSafeInteger(maxAmountSat) || maxAmountSat < 1)
131
+ throw new TypeError("maxAmountSat must be a positive integer");
132
+ const pending = /* @__PURE__ */ new Map();
133
+ const verifiedProof = (preimage, hash) => {
134
+ let actual;
135
+ try {
136
+ actual = paymentHash(preimage);
137
+ } catch {
138
+ throw new PhoenixdPaymentError(
139
+ "payment_unknown",
140
+ "Phoenixd returned an invalid payment proof"
141
+ );
142
+ }
143
+ if (actual !== hash)
144
+ throw new PhoenixdPaymentError(
145
+ "payment_unknown",
146
+ "Phoenixd returned a payment proof that does not match the invoice"
147
+ );
148
+ return preimage;
149
+ };
150
+ async function pay(invoice, hash) {
151
+ const existing = await client.getOutgoingPaymentByHash(hash);
152
+ if (existing?.isPaid) {
153
+ if (!existing.preimage)
154
+ throw new PhoenixdPaymentError(
155
+ "payment_unknown",
156
+ "The invoice is paid but its proof is unavailable; check outgoing payment history"
157
+ );
158
+ return verifiedProof(existing.preimage, hash);
159
+ }
160
+ if (existing && existing.completedAt == null)
161
+ throw new PhoenixdPaymentError(
162
+ "payment_unknown",
163
+ "A payment for this invoice is already pending; check outgoing payment history"
164
+ );
165
+ let result;
166
+ try {
167
+ result = await client.payInvoice({ invoice });
168
+ } catch {
169
+ try {
170
+ const payment = await client.getOutgoingPaymentByHash(hash);
171
+ if (payment?.isPaid && payment.preimage)
172
+ return verifiedProof(payment.preimage, hash);
173
+ } catch {
174
+ }
175
+ throw new PhoenixdPaymentError(
176
+ "payment_unknown",
177
+ "The payment outcome is unknown; check outgoing payment history before retrying"
178
+ );
179
+ }
180
+ if (result.type === "payment_failed")
181
+ throw new PhoenixdPaymentError(
182
+ "payment_failed",
183
+ "Phoenixd rejected the payment"
184
+ );
185
+ if (result.paymentHash !== hash)
186
+ throw new PhoenixdPaymentError(
187
+ "payment_unknown",
188
+ "Phoenixd returned a different payment hash"
189
+ );
190
+ return verifiedProof(result.paymentPreimage, hash);
191
+ }
192
+ return import_mppx3.Method.toClient(charge, {
193
+ async createCredential({ challenge }) {
194
+ const request = charge.schema.request.parse(challenge.request);
195
+ let details;
196
+ try {
197
+ details = invoiceDetails(
198
+ await client.decodeInvoice({
199
+ invoice: request.methodDetails.invoice
200
+ }),
201
+ request,
202
+ network
203
+ );
204
+ if (request.methodDetails.paymentHash !== void 0 && request.methodDetails.paymentHash !== details.paymentHash)
205
+ throw new TypeError("Challenge payment hash does not match invoice");
206
+ if (request.methodDetails.network !== void 0 && request.methodDetails.network !== details.network)
207
+ throw new TypeError("Challenge network does not match invoice");
208
+ if (challenge.expires !== void 0 && Date.parse(challenge.expires) <= Date.now())
209
+ throw new TypeError("The challenge is expired");
210
+ } catch {
211
+ throw new PhoenixdPaymentError(
212
+ "invalid_invoice",
213
+ "The challenge contains an invalid, expired or mismatched invoice"
214
+ );
215
+ }
216
+ if (Number(request.amount) > maxAmountSat)
217
+ throw new PhoenixdPaymentError(
218
+ "amount_limit",
219
+ "The requested payment exceeds maxAmountSat"
220
+ );
221
+ let promise = pending.get(details.paymentHash);
222
+ if (!promise) {
223
+ promise = pay(request.methodDetails.invoice, details.paymentHash);
224
+ pending.set(details.paymentHash, promise);
225
+ }
226
+ let preimage;
227
+ try {
228
+ preimage = await promise;
229
+ } finally {
230
+ if (pending.get(details.paymentHash) === promise)
231
+ pending.delete(details.paymentHash);
232
+ }
233
+ return import_mppx3.Credential.serialize({ challenge, payload: { preimage } });
234
+ }
235
+ });
236
+ }
237
+ // Annotate the CommonJS export names for ESM import in node:
238
+ 0 && (module.exports = {
239
+ Mppx,
240
+ PhoenixdPaymentError,
241
+ charge,
242
+ phoenixd
243
+ });
244
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/client/index.ts","../../src/client/methods.ts","../../src/client/charge.ts","../../src/Methods.ts","../../src/errors.ts","../../src/shared.ts"],"sourcesContent":["export { Mppx } from \"mppx/client\";\nexport * as phoenixd from \"./methods\";\nexport { charge } from \"./charge\";\nexport type { ChargeOptions, ClientChargeMethod } from \"./charge\";\nexport { PhoenixdPaymentError } from \"../errors\";\n","export { charge } from \"./charge\";\n","import { Credential, Method } from \"mppx\";\nimport type { PhoenixdClient, PaymentResult } from \"@nodana/phoenixd-ts\";\nimport * as Methods from \"../Methods\";\nimport { PhoenixdPaymentError } from \"../errors\";\nimport { invoiceDetails, paymentHash } from \"../shared\";\n\nexport interface ChargeOptions {\n client: Pick<\n PhoenixdClient,\n \"decodeInvoice\" | \"payInvoice\" | \"getOutgoingPaymentByHash\"\n >;\n /** Maximum payment amount per challenge, in satoshis. */\n maxAmountSat: number;\n /** Expected invoice network. Defaults to mainnet. */\n network?: Methods.LightningNetwork;\n}\n\nexport type ClientChargeMethod = Method.Client<typeof Methods.charge>;\n\nexport function charge({\n client,\n maxAmountSat,\n network = \"mainnet\",\n}: ChargeOptions): ClientChargeMethod {\n if (!Number.isSafeInteger(maxAmountSat) || maxAmountSat < 1)\n throw new TypeError(\"maxAmountSat must be a positive integer\");\n\n const pending = new Map<string, Promise<string>>();\n\n const verifiedProof = (preimage: string, hash: string) => {\n let actual: string;\n\n try {\n actual = paymentHash(preimage);\n } catch {\n throw new PhoenixdPaymentError(\n \"payment_unknown\",\n \"Phoenixd returned an invalid payment proof\",\n );\n }\n\n if (actual !== hash)\n throw new PhoenixdPaymentError(\n \"payment_unknown\",\n \"Phoenixd returned a payment proof that does not match the invoice\",\n );\n\n return preimage;\n };\n\n async function pay(invoice: string, hash: string): Promise<string> {\n // Check history before sending, including after a previous uncertain result.\n const existing = await client.getOutgoingPaymentByHash(hash);\n\n if (existing?.isPaid) {\n if (!existing.preimage)\n throw new PhoenixdPaymentError(\n \"payment_unknown\",\n \"The invoice is paid but its proof is unavailable; check outgoing payment history\",\n );\n\n return verifiedProof(existing.preimage, hash);\n }\n\n if (existing && existing.completedAt == null)\n throw new PhoenixdPaymentError(\n \"payment_unknown\",\n \"A payment for this invoice is already pending; check outgoing payment history\",\n );\n\n let result: PaymentResult;\n\n try {\n result = await client.payInvoice({ invoice });\n } catch {\n try {\n const payment = await client.getOutgoingPaymentByHash(hash);\n\n if (payment?.isPaid && payment.preimage)\n return verifiedProof(payment.preimage, hash);\n } catch {\n /* The payment outcome remains unknown. */\n }\n\n throw new PhoenixdPaymentError(\n \"payment_unknown\",\n \"The payment outcome is unknown; check outgoing payment history before retrying\",\n );\n }\n\n if (result.type === \"payment_failed\")\n throw new PhoenixdPaymentError(\n \"payment_failed\",\n \"Phoenixd rejected the payment\",\n );\n\n if (result.paymentHash !== hash)\n throw new PhoenixdPaymentError(\n \"payment_unknown\",\n \"Phoenixd returned a different payment hash\",\n );\n\n return verifiedProof(result.paymentPreimage, hash);\n }\n\n return Method.toClient(Methods.charge, {\n async createCredential({ challenge }) {\n const request = Methods.charge.schema.request.parse(challenge.request);\n let details: ReturnType<typeof invoiceDetails>;\n\n try {\n details = invoiceDetails(\n await client.decodeInvoice({\n invoice: request.methodDetails.invoice,\n }),\n request,\n network,\n );\n\n if (\n request.methodDetails.paymentHash !== undefined &&\n request.methodDetails.paymentHash !== details.paymentHash\n )\n throw new TypeError(\"Challenge payment hash does not match invoice\");\n\n if (\n request.methodDetails.network !== undefined &&\n request.methodDetails.network !== details.network\n )\n throw new TypeError(\"Challenge network does not match invoice\");\n\n if (\n challenge.expires !== undefined &&\n Date.parse(challenge.expires) <= Date.now()\n )\n throw new TypeError(\"The challenge is expired\");\n } catch {\n throw new PhoenixdPaymentError(\n \"invalid_invoice\",\n \"The challenge contains an invalid, expired or mismatched invoice\",\n );\n }\n\n if (Number(request.amount) > maxAmountSat)\n throw new PhoenixdPaymentError(\n \"amount_limit\",\n \"The requested payment exceeds maxAmountSat\",\n );\n\n let promise = pending.get(details.paymentHash);\n\n if (!promise) {\n promise = pay(request.methodDetails.invoice, details.paymentHash);\n pending.set(details.paymentHash, promise);\n }\n\n let preimage: string;\n\n try {\n preimage = await promise;\n } finally {\n if (pending.get(details.paymentHash) === promise)\n pending.delete(details.paymentHash);\n }\n\n return Credential.serialize({ challenge, payload: { preimage } });\n },\n });\n}\n","// Lightning wire schema adapted from buildonspark/lightning-mpp-sdk (MIT).\n// Copyright (c) 2026 Lightspark Group, Inc. See NOTICE.\nimport { Method, z } from \"mppx\";\n\nexport const charge = Method.from({\n name: \"lightning\",\n intent: \"charge\",\n schema: {\n credential: {\n payload: z.object({\n preimage: z.string().check(z.regex(/^[0-9a-f]{64}$/)),\n }),\n },\n request: z.object({\n amount: z.string().check(z.regex(/^[1-9][0-9]*$/)),\n currency: z.literal(\"sat\"),\n description: z.optional(z.string()),\n methodDetails: z.object({\n invoice: z.string(),\n paymentHash: z.optional(z.string().check(z.regex(/^[0-9a-f]{64}$/))),\n network: z.optional(z.enum([\"mainnet\", \"regtest\", \"signet\"])),\n }),\n }),\n },\n});\n\nexport type ChargeRequest = z.output<typeof charge.schema.request>;\n\nexport type LightningNetwork = NonNullable<\n ChargeRequest[\"methodDetails\"][\"network\"]\n>;\n","import { Errors } from \"mppx\";\n\nexport type ChargeErrorCode =\n | \"unknown_challenge\"\n | \"invalid_challenge\"\n | \"invalid_preimage\"\n | \"invoice_expired\"\n | \"already_consumed\"\n | \"invalid_invoice\"\n | \"store_unavailable\";\n\nexport class ChargeError extends Errors.PaymentError {\n readonly name = \"ChargeError\";\n readonly title = \"Lightning payment rejected\";\n readonly type: string;\n override readonly status: number;\n\n constructor(\n public readonly code: ChargeErrorCode,\n message: string,\n ) {\n super(message);\n\n const problem =\n code === \"store_unavailable\" || code === \"invalid_invoice\"\n ? \"internal-payment-error\"\n : code === \"invoice_expired\"\n ? \"payment-expired\"\n : code === \"invalid_preimage\" || code === \"already_consumed\"\n ? \"verification-failed\"\n : \"invalid-challenge\";\n\n this.type = `https://paymentauth.org/problems/${problem}`;\n this.status =\n code === \"store_unavailable\"\n ? 503\n : code === \"invalid_invoice\"\n ? 502\n : 402;\n }\n}\n\nexport type ClientErrorCode =\n \"invalid_invoice\" | \"amount_limit\" | \"payment_failed\" | \"payment_unknown\";\n\nexport class PhoenixdPaymentError extends Error {\n readonly name = \"PhoenixdPaymentError\";\n\n constructor(\n public readonly code: ClientErrorCode,\n message: string,\n ) {\n super(message);\n }\n}\n","import { createHash } from \"node:crypto\";\nimport type { DecodedInvoice } from \"@nodana/phoenixd-ts\";\nimport type { ChargeRequest, LightningNetwork } from \"./Methods\";\n\nexport function satoshis(amount: string): number {\n if (!/^[1-9][0-9]*$/.test(amount))\n throw new TypeError(\"amount must be a positive integer string in satoshis\");\n\n const value = Number(amount);\n\n if (!Number.isSafeInteger(value * 1000))\n throw new TypeError(\n \"amount exceeds the safely representable millisatoshi range\",\n );\n\n return value;\n}\n\nexport function paymentHash(preimage: string): string {\n if (!/^[0-9a-f]{64}$/.test(preimage))\n throw new TypeError(\"Invalid payment preimage\");\n\n return createHash(\"sha256\")\n .update(Buffer.from(preimage, \"hex\"))\n .digest(\"hex\");\n}\n\nexport function invoiceDetails(\n invoice: DecodedInvoice,\n request: Pick<ChargeRequest, \"amount\" | \"currency\">,\n expected?: LightningNetwork,\n): { paymentHash: string; network: LightningNetwork; expiresAt: number } {\n if (\n request.currency !== \"sat\" ||\n invoice.amount !== satoshis(request.amount) * 1000\n )\n throw new TypeError(\"Invoice amount does not match the requested satoshis\");\n\n if (!/^[0-9a-f]{64}$/.test(invoice.paymentHash))\n throw new TypeError(\"Invoice has an invalid payment hash\");\n\n const network = invoice.chain;\n\n if (network !== \"mainnet\" && network !== \"regtest\" && network !== \"signet\")\n throw new TypeError(\"Invoice uses an unsupported Lightning network\");\n\n if (expected !== undefined && network !== expected)\n throw new TypeError(\n \"Invoice network does not match the configured network\",\n );\n\n const expiresAt =\n (invoice.timestampSeconds + (invoice.expirySeconds ?? 3600)) * 1000;\n\n if (!Number.isSafeInteger(expiresAt) || expiresAt <= Date.now())\n throw new TypeError(\"Invoice is expired or has an invalid expiry\");\n\n return { paymentHash: invoice.paymentHash, network, expiresAt };\n}\n\nexport async function bodyHash(request: Request): Promise<string> {\n // Clone preserves the body for the application handler.\n return createHash(\"sha256\")\n .update(Buffer.from(await request.clone().arrayBuffer()))\n .digest(\"hex\");\n}\n"],"mappings":"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","names":["charge","charge","import_mppx","import_mppx","charge"]}
@@ -0,0 +1,22 @@
1
+ export { Mppx } from 'mppx/client';
2
+ import { Method } from 'mppx';
3
+ import { PhoenixdClient } from '@nodana/phoenixd-ts';
4
+ import { L as LightningNetwork, c as charge$1 } from '../index-3V4vmG3I.cjs';
5
+ export { P as PhoenixdPaymentError } from '../index-3V4vmG3I.cjs';
6
+
7
+ interface ChargeOptions {
8
+ client: Pick<PhoenixdClient, "decodeInvoice" | "payInvoice" | "getOutgoingPaymentByHash">;
9
+ /** Maximum payment amount per challenge, in satoshis. */
10
+ maxAmountSat: number;
11
+ /** Expected invoice network. Defaults to mainnet. */
12
+ network?: LightningNetwork;
13
+ }
14
+ type ClientChargeMethod = Method.Client<typeof charge$1>;
15
+ declare function charge({ client, maxAmountSat, network, }: ChargeOptions): ClientChargeMethod;
16
+
17
+ declare const methods_charge: typeof charge;
18
+ declare namespace methods {
19
+ export { methods_charge as charge };
20
+ }
21
+
22
+ export { type ChargeOptions, type ClientChargeMethod, charge, methods as phoenixd };
@@ -0,0 +1,22 @@
1
+ export { Mppx } from 'mppx/client';
2
+ import { Method } from 'mppx';
3
+ import { PhoenixdClient } from '@nodana/phoenixd-ts';
4
+ import { L as LightningNetwork, c as charge$1 } from '../index-3V4vmG3I.js';
5
+ export { P as PhoenixdPaymentError } from '../index-3V4vmG3I.js';
6
+
7
+ interface ChargeOptions {
8
+ client: Pick<PhoenixdClient, "decodeInvoice" | "payInvoice" | "getOutgoingPaymentByHash">;
9
+ /** Maximum payment amount per challenge, in satoshis. */
10
+ maxAmountSat: number;
11
+ /** Expected invoice network. Defaults to mainnet. */
12
+ network?: LightningNetwork;
13
+ }
14
+ type ClientChargeMethod = Method.Client<typeof charge$1>;
15
+ declare function charge({ client, maxAmountSat, network, }: ChargeOptions): ClientChargeMethod;
16
+
17
+ declare const methods_charge: typeof charge;
18
+ declare namespace methods {
19
+ export { methods_charge as charge };
20
+ }
21
+
22
+ export { type ChargeOptions, type ClientChargeMethod, charge, methods as phoenixd };