@qntx/spark 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 +201 -0
- package/NOTICE +6 -0
- package/README.md +59 -2
- package/dist/bolt11-DsNTTS_O.d.mts +52 -0
- package/dist/crypto.d.mts +3 -0
- package/dist/crypto.mjs +9 -0
- package/dist/errors-5xLkExNL.mjs +67 -0
- package/dist/index-B_g3vHnT.d.mts +820 -0
- package/dist/index-D1fBaHTa.d.mts +55 -0
- package/dist/index-DUSx3L3J.d.mts +69 -0
- package/dist/index.d.mts +115 -0
- package/dist/index.mjs +7322 -0
- package/dist/lightning-address-CRULmi9v.d.mts +106 -0
- package/dist/lightning-address-CZrb8x4p.mjs +92 -0
- package/dist/lnurl-kcdXU75g.mjs +729 -0
- package/dist/lnurl.d.mts +258 -0
- package/dist/lnurl.mjs +1 -0
- package/dist/server.d.mts +158 -0
- package/dist/server.mjs +373 -0
- package/dist/signer.d.mts +72 -0
- package/dist/signer.mjs +1024 -0
- package/dist/text-DC_Vptn6.mjs +303 -0
- package/dist/token-DmojVTWi.mjs +2122 -0
- package/dist/types-jBCznYd6.d.mts +322 -0
- package/package.json +98 -4
package/dist/lnurl.d.mts
ADDED
|
@@ -0,0 +1,258 @@
|
|
|
1
|
+
import { n as SparkNetwork, t as LightningAddressStatement } from "./lightning-address-CRULmi9v.mjs";
|
|
2
|
+
import { t as Bolt11Invoice } from "./bolt11-DsNTTS_O.mjs";
|
|
3
|
+
//#region src/lnurl/auth.d.ts
|
|
4
|
+
type LnurlAuthAction = "register" | "login" | "link" | "auth";
|
|
5
|
+
type LnurlAuthRequest = {
|
|
6
|
+
readonly tag: "login";
|
|
7
|
+
/** The full service URL to GET in the second step, normalized. */
|
|
8
|
+
readonly url: string;
|
|
9
|
+
/** The 32-byte challenge, lowercase hex. */
|
|
10
|
+
readonly k1: string;
|
|
11
|
+
readonly action?: LnurlAuthAction | undefined;
|
|
12
|
+
/** The service's lowercase hostname — shown to the user on login. */
|
|
13
|
+
readonly domain: string;
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Parses an LNURL-auth URL (the decoded form of a `lnurl1…` string or a bare https/onion URL).
|
|
17
|
+
* Requires `tag=login` and a 64-hex `k1` query parameter; `action` must be one of the LUD-04 enum
|
|
18
|
+
* values when present.
|
|
19
|
+
*/
|
|
20
|
+
export declare function parseLnurlAuth(url: string): LnurlAuthRequest;
|
|
21
|
+
/**
|
|
22
|
+
* The signing shape the auth flow needs — a structural subset of `LnurlAuthSigner` (the lnurl layer
|
|
23
|
+
* must not import the signer implementation).
|
|
24
|
+
*/
|
|
25
|
+
type LnurlAuthSigning = {
|
|
26
|
+
readonly sign: (request: {
|
|
27
|
+
readonly domain: string;
|
|
28
|
+
readonly k1: Uint8Array;
|
|
29
|
+
}) => Promise<{
|
|
30
|
+
readonly linkingKey: Uint8Array;
|
|
31
|
+
readonly signature: Uint8Array;
|
|
32
|
+
}>;
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* LUD-04 step 3: signs the `k1` challenge with the domain's linking key and GETs the service URL
|
|
36
|
+
* with `sig` and `key` appended. The k1 challenge and the signature never appear in error
|
|
37
|
+
* messages.
|
|
38
|
+
*/
|
|
39
|
+
export declare function submitLnurlAuth(request: LnurlAuthRequest, options: {
|
|
40
|
+
readonly fetch: typeof globalThis.fetch;
|
|
41
|
+
readonly signer: LnurlAuthSigning;
|
|
42
|
+
}): Promise<void>;
|
|
43
|
+
//#endregion
|
|
44
|
+
//#region src/lnurl/codec.d.ts
|
|
45
|
+
/** LUD-01 §HTTPS or Onion: clearnet https, or http only for a `.onion` host. */
|
|
46
|
+
export declare function checkLnurlUrl(url: string): void;
|
|
47
|
+
/**
|
|
48
|
+
* Decodes a bech32 `lnurl1…` string into the normalized URL it wraps (LUD-01). Accepts upper- or
|
|
49
|
+
* lowercase (never mixed) and an optional `lightning:` scheme prefix.
|
|
50
|
+
*/
|
|
51
|
+
export declare function decodeLnurl(text: string): string;
|
|
52
|
+
/** Bech32-encodes an https/onion URL into a lowercase `lnurl1…` string (LUD-01). */
|
|
53
|
+
export declare function encodeLnurl(url: string): string;
|
|
54
|
+
/**
|
|
55
|
+
* LUD-16 `<username>@<domain>` → the well-known pay endpoint. `@<domain>` resolves to the default
|
|
56
|
+
* identifier `_`. An `.onion` domain yields http, a clearnet domain https. Usernames are lowercased
|
|
57
|
+
* and must match `a-z0-9-_.` plus `+` for service tags; ports, userinfo and paths are rejected.
|
|
58
|
+
*/
|
|
59
|
+
export declare function lightningAddressUrl(address: string): string;
|
|
60
|
+
//#endregion
|
|
61
|
+
//#region src/lnurl/http.d.ts
|
|
62
|
+
type JsonObject = Record<string, unknown>;
|
|
63
|
+
/**
|
|
64
|
+
* One GET against an LNURL endpoint with the injected fetch. HTTP failures and the protocol-level
|
|
65
|
+
* `{"status": "ERROR", "reason"}` envelope map onto the SSP client's error vocabulary; error
|
|
66
|
+
* messages never echo request URLs — withdraw callbacks carry the ephemeral `k1`, which authorizes
|
|
67
|
+
* a payout.
|
|
68
|
+
*/
|
|
69
|
+
export declare function lnurlGetJson(url: string, fetch: typeof globalThis.fetch): Promise<JsonObject>;
|
|
70
|
+
/**
|
|
71
|
+
* One JSON request with a body (POST/DELETE) against an LNURL endpoint. Same error vocabulary as
|
|
72
|
+
* {@link lnurlGetJson}; a 2xx response with an empty body returns `undefined`, and request bodies
|
|
73
|
+
* never echo into error messages — the server's response text is sanitized before it is embedded.
|
|
74
|
+
*/
|
|
75
|
+
export declare function lnurlSendJson(url: string, fetch: typeof globalThis.fetch, options: {
|
|
76
|
+
readonly method: string;
|
|
77
|
+
readonly body: JsonObject;
|
|
78
|
+
/** Whole-round-trip bound; defaults to {@link LNURL_REQUEST_TIMEOUT_MS}. */
|
|
79
|
+
readonly timeoutMs?: number;
|
|
80
|
+
}): Promise<JsonObject | undefined>;
|
|
81
|
+
//#endregion
|
|
82
|
+
//#region src/lnurl/success-action.d.ts
|
|
83
|
+
type LnurlSuccessAction = {
|
|
84
|
+
readonly tag: "message";
|
|
85
|
+
readonly message: string;
|
|
86
|
+
} | {
|
|
87
|
+
readonly tag: "url";
|
|
88
|
+
readonly description: string;
|
|
89
|
+
readonly url: string;
|
|
90
|
+
} | {
|
|
91
|
+
readonly tag: "aes";
|
|
92
|
+
readonly description: string;
|
|
93
|
+
readonly ciphertext: string;
|
|
94
|
+
readonly iv: string;
|
|
95
|
+
};
|
|
96
|
+
/**
|
|
97
|
+
* Parses a `successAction` object (LUD-09). `callbackHost` is the payRequest callback's hostname:
|
|
98
|
+
* `url` actions must stay on that domain. Unknown tags are rejected — a wallet that cannot show the
|
|
99
|
+
* action must not proceed (LUD-09).
|
|
100
|
+
*/
|
|
101
|
+
export declare function parseSuccessAction(value: unknown, callbackHost: string): LnurlSuccessAction;
|
|
102
|
+
/**
|
|
103
|
+
* LUD-10: decrypts an `aes` successAction with the payment preimage — AES-256-CBC, the preimage is
|
|
104
|
+
* the key, `iv` is base64 of 16 bytes, `ciphertext` base64 of at most 4 KiB, PKCS#7 padding, UTF-8
|
|
105
|
+
* plaintext.
|
|
106
|
+
*/
|
|
107
|
+
export declare function decryptSuccessAction(action: Extract<LnurlSuccessAction, {
|
|
108
|
+
readonly tag: "aes";
|
|
109
|
+
}>, preimage: Uint8Array): string;
|
|
110
|
+
//#endregion
|
|
111
|
+
//#region src/lnurl/pay.d.ts
|
|
112
|
+
type LnurlPayRequest = {
|
|
113
|
+
readonly tag: "payRequest";
|
|
114
|
+
/** Second-callback URL from the service. */
|
|
115
|
+
readonly callback: string;
|
|
116
|
+
readonly minSendableMsat: number;
|
|
117
|
+
readonly maxSendableMsat: number;
|
|
118
|
+
/** Raw metadata JSON string — hashed verbatim into the invoice's `h` field. */
|
|
119
|
+
readonly metadata: string;
|
|
120
|
+
/** The metadata's single `text/plain` entry (LUD-06, mandatory). */
|
|
121
|
+
readonly description: string;
|
|
122
|
+
/** Max comment characters the service accepts (LUD-12); 0 = unsupported. */
|
|
123
|
+
readonly commentAllowed: number;
|
|
124
|
+
/** NIP-57 zaps: the service accepts a signed `nostr` zap-request event. */
|
|
125
|
+
readonly allowsNostr: boolean;
|
|
126
|
+
/** 32-byte x-only nostr pubkey; present exactly when `allowsNostr`. */
|
|
127
|
+
readonly nostrPubkey?: Uint8Array | undefined;
|
|
128
|
+
};
|
|
129
|
+
export declare function parseLnurlPayRequest(body: JsonObject): LnurlPayRequest;
|
|
130
|
+
type LnurlInvoice = {
|
|
131
|
+
/** The service's BOLT-11 payment request string. */
|
|
132
|
+
readonly invoice: string;
|
|
133
|
+
readonly decoded: Bolt11Invoice;
|
|
134
|
+
readonly successAction?: LnurlSuccessAction | undefined;
|
|
135
|
+
};
|
|
136
|
+
/**
|
|
137
|
+
* LUD-06 second callback: requests the invoice for `amountMsat`, then verifies it against the
|
|
138
|
+
* request — exact amount, invoice network, and a `h` description-hash over the raw metadata (or
|
|
139
|
+
* over the zap-request event alone for a nostr zap, NIP-57).
|
|
140
|
+
*/
|
|
141
|
+
export declare function requestInvoice(request: LnurlPayRequest, options: {
|
|
142
|
+
readonly fetch: typeof globalThis.fetch;
|
|
143
|
+
readonly network: SparkNetwork;
|
|
144
|
+
readonly amountMsat: number;
|
|
145
|
+
readonly comment?: string;
|
|
146
|
+
readonly zapRequest?: string;
|
|
147
|
+
}): Promise<LnurlInvoice>;
|
|
148
|
+
//#endregion
|
|
149
|
+
//#region src/lnurl/withdraw.d.ts
|
|
150
|
+
type LnurlWithdrawRequest = {
|
|
151
|
+
readonly tag: "withdrawRequest";
|
|
152
|
+
/** Second-callback URL accepting `k1` and `pr` query params. */
|
|
153
|
+
readonly callback: string;
|
|
154
|
+
/** Ephemeral service challenge echoed back verbatim on the callback. */
|
|
155
|
+
readonly k1: string;
|
|
156
|
+
readonly defaultDescription: string;
|
|
157
|
+
readonly minWithdrawableMsat: number;
|
|
158
|
+
readonly maxWithdrawableMsat: number;
|
|
159
|
+
};
|
|
160
|
+
export declare function parseLnurlWithdrawRequest(body: JsonObject): LnurlWithdrawRequest;
|
|
161
|
+
/**
|
|
162
|
+
* LUD-03 step 5: submits the wallet's BOLT-11 `invoice` for payment. The service pays
|
|
163
|
+
* asynchronously; a `{"status": "OK"}` body means it accepted — errors surface as
|
|
164
|
+
* `SparkRequestError` (`lnurl_error` / `http_*`).
|
|
165
|
+
*/
|
|
166
|
+
export declare function submitWithdraw(request: LnurlWithdrawRequest, options: {
|
|
167
|
+
readonly fetch: typeof globalThis.fetch;
|
|
168
|
+
readonly invoice: string;
|
|
169
|
+
}): Promise<void>;
|
|
170
|
+
//#endregion
|
|
171
|
+
//#region src/lnurl/fetch.d.ts
|
|
172
|
+
type LnurlResolved = LnurlPayRequest | LnurlWithdrawRequest | LnurlAuthRequest;
|
|
173
|
+
/**
|
|
174
|
+
* Resolves an `lnurl1…` string, a lightning address (`user@domain`, LUD-16) or a bare https/onion
|
|
175
|
+
* URL into a typed LNURL service request. A `tag=login` query is a LUD-04 auth challenge carried
|
|
176
|
+
* inside the LNURL itself and returns without fetching; otherwise the endpoint is fetched and only
|
|
177
|
+
* the interactive `payRequest` (LUD-06) and `withdrawRequest` (LUD-03) tags are supported.
|
|
178
|
+
*/
|
|
179
|
+
export declare function resolveLnurl(input: string, options: {
|
|
180
|
+
readonly fetch: typeof globalThis.fetch;
|
|
181
|
+
}): Promise<LnurlResolved>;
|
|
182
|
+
//#endregion
|
|
183
|
+
//#region src/lnurl/lightning-address.d.ts
|
|
184
|
+
/**
|
|
185
|
+
* The signing shape the registration helpers need — a structural subset of `SparkSigner` (the lnurl
|
|
186
|
+
* layer must not import the signer implementation).
|
|
187
|
+
*/
|
|
188
|
+
type LightningAddressSigning = {
|
|
189
|
+
readonly identityPublicKey: () => Promise<Uint8Array>;
|
|
190
|
+
readonly signIdentity: (statement: LightningAddressStatement) => Promise<Uint8Array>;
|
|
191
|
+
};
|
|
192
|
+
type RegisterLightningAddressBody = {
|
|
193
|
+
readonly username: string;
|
|
194
|
+
readonly signature: string;
|
|
195
|
+
readonly timestamp: number;
|
|
196
|
+
readonly description: string;
|
|
197
|
+
};
|
|
198
|
+
type UnregisterLightningAddressBody = {
|
|
199
|
+
readonly username: string;
|
|
200
|
+
readonly signature: string;
|
|
201
|
+
readonly timestamp: number;
|
|
202
|
+
};
|
|
203
|
+
type LightningAddressRegistration = {
|
|
204
|
+
readonly lnurl: string;
|
|
205
|
+
readonly lightningAddress: string;
|
|
206
|
+
};
|
|
207
|
+
/**
|
|
208
|
+
* Builds the register request body the signed statement commits to — lowercased domain and
|
|
209
|
+
* username, fresh timestamp — and signs it. Split from {@link registerLightningAddress} so the same
|
|
210
|
+
* bytes can be handed to a server handler in tests without HTTP.
|
|
211
|
+
*/
|
|
212
|
+
export declare function lightningAddressRegisterBody(options: {
|
|
213
|
+
readonly domain: string;
|
|
214
|
+
readonly username: string;
|
|
215
|
+
readonly description: string;
|
|
216
|
+
readonly signer: LightningAddressSigning;
|
|
217
|
+
readonly now?: (() => number) | undefined;
|
|
218
|
+
}): Promise<{
|
|
219
|
+
readonly pubkeyHex: string;
|
|
220
|
+
readonly body: RegisterLightningAddressBody;
|
|
221
|
+
}>;
|
|
222
|
+
/** The unregister counterpart of {@link lightningAddressRegisterBody}. */
|
|
223
|
+
export declare function lightningAddressUnregisterBody(options: {
|
|
224
|
+
readonly domain: string;
|
|
225
|
+
readonly username: string;
|
|
226
|
+
readonly signer: LightningAddressSigning;
|
|
227
|
+
readonly now?: (() => number) | undefined;
|
|
228
|
+
}): Promise<{
|
|
229
|
+
readonly pubkeyHex: string;
|
|
230
|
+
readonly body: UnregisterLightningAddressBody;
|
|
231
|
+
}>;
|
|
232
|
+
/**
|
|
233
|
+
* Claims `username` on the Lightning Address server at `serverUrl`: signs the register statement
|
|
234
|
+
* and POSTs it to `/lnurlpay/{pubkey}`. `serverUrl` must be https or an `.onion` http URL.
|
|
235
|
+
*/
|
|
236
|
+
export declare function registerLightningAddress(options: {
|
|
237
|
+
readonly fetch: typeof globalThis.fetch;
|
|
238
|
+
readonly serverUrl: string;
|
|
239
|
+
readonly domain: string;
|
|
240
|
+
readonly username: string;
|
|
241
|
+
readonly description: string;
|
|
242
|
+
readonly signer: LightningAddressSigning;
|
|
243
|
+
readonly now?: (() => number) | undefined;
|
|
244
|
+
}): Promise<LightningAddressRegistration>;
|
|
245
|
+
/**
|
|
246
|
+
* Gives up `username` on the server: signs the unregister statement and DELETEs
|
|
247
|
+
* `/lnurlpay/{pubkey}`.
|
|
248
|
+
*/
|
|
249
|
+
export declare function unregisterLightningAddress(options: {
|
|
250
|
+
readonly fetch: typeof globalThis.fetch;
|
|
251
|
+
readonly serverUrl: string;
|
|
252
|
+
readonly domain: string;
|
|
253
|
+
readonly username: string;
|
|
254
|
+
readonly signer: LightningAddressSigning;
|
|
255
|
+
readonly now?: (() => number) | undefined;
|
|
256
|
+
}): Promise<void>;
|
|
257
|
+
//#endregion
|
|
258
|
+
export type { JsonObject, LightningAddressRegistration, LightningAddressSigning, LnurlAuthAction, LnurlAuthRequest, LnurlAuthSigning, LnurlInvoice, LnurlPayRequest, LnurlResolved, LnurlSuccessAction, LnurlWithdrawRequest, RegisterLightningAddressBody, UnregisterLightningAddressBody };
|
package/dist/lnurl.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { f as checkLnurlUrl, p as decodeLnurl, u as decryptSuccessAction, m as encodeLnurl, t as lightningAddressRegisterBody, n as lightningAddressUnregisterBody, h as lightningAddressUrl, y as lnurlGetJson, b as lnurlSendJson, g as parseLnurlAuth, c as parseLnurlPayRequest, o as parseLnurlWithdrawRequest, d as parseSuccessAction, r as registerLightningAddress, l as requestInvoice, a as resolveLnurl, _ as submitLnurlAuth, s as submitWithdraw, i as unregisterLightningAddress } from "./lnurl-kcdXU75g.mjs";
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { n as SparkClient } from "./index-B_g3vHnT.mjs";
|
|
2
|
+
//#region src/server/store.d.ts
|
|
3
|
+
type LightningAddressUser = {
|
|
4
|
+
/** Lowercase LUD-16 local-part. */
|
|
5
|
+
readonly name: string;
|
|
6
|
+
/** The owner's compressed secp256k1 identity public key, lowercase hex. */
|
|
7
|
+
readonly pubkeyHex: string;
|
|
8
|
+
/** The registration description — verbatim into the payRequest `text/plain` metadata. */
|
|
9
|
+
readonly description: string;
|
|
10
|
+
};
|
|
11
|
+
type LightningAddressInvoice = {
|
|
12
|
+
/** Lowercase hex payment hash of the BOLT-11 invoice. */
|
|
13
|
+
readonly paymentHash: string;
|
|
14
|
+
/** The SSP lightning-receive request id — the settlement status is polled through it. */
|
|
15
|
+
readonly requestId: string;
|
|
16
|
+
/** The registered name the invoice was issued to. */
|
|
17
|
+
readonly name: string;
|
|
18
|
+
/** The payee's compressed identity public key, lowercase hex. */
|
|
19
|
+
readonly pubkeyHex: string;
|
|
20
|
+
/** The encoded BOLT-11 invoice handed to the payer. */
|
|
21
|
+
readonly invoice: string;
|
|
22
|
+
readonly expiresAtMs: number;
|
|
23
|
+
/** Last `settlePending` status check — the pending queue is served least-recently-checked first. */
|
|
24
|
+
readonly lastCheckedAtMs?: number;
|
|
25
|
+
/** The raw zap-request event JSON (NIP-57), when the payer sent one. */
|
|
26
|
+
readonly zapRequest?: string;
|
|
27
|
+
readonly comment?: string;
|
|
28
|
+
/** Lowercase hex settled preimage — present only once settled. */
|
|
29
|
+
readonly preimageHex?: string;
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* The persistence the server handlers need. A pubkey holds at most one name: registering a new name
|
|
33
|
+
* releases the old one.
|
|
34
|
+
*/
|
|
35
|
+
type LightningAddressStore = {
|
|
36
|
+
readonly userByName: (name: string) => Promise<LightningAddressUser | undefined>;
|
|
37
|
+
readonly userByPublicKey: (pubkeyHex: string) => Promise<LightningAddressUser | undefined>;
|
|
38
|
+
/** Registered name count — one row per name, and each pubkey holds at most one. */
|
|
39
|
+
readonly countUsers: () => Promise<number>;
|
|
40
|
+
/**
|
|
41
|
+
* Registers `user.name` for `user.pubkeyHex`. Returns `false` when another pubkey already holds
|
|
42
|
+
* the name; otherwise removes the pubkey's previous name and stores the record.
|
|
43
|
+
*/
|
|
44
|
+
readonly putUser: (user: LightningAddressUser) => Promise<boolean>;
|
|
45
|
+
/** Removes the name only when it is still held by `pubkeyHex`. */
|
|
46
|
+
readonly deleteUser: (pubkeyHex: string, name: string) => Promise<boolean>;
|
|
47
|
+
/**
|
|
48
|
+
* Claims a signed statement for replay protection: `false` when the hash was already claimed,
|
|
49
|
+
* else records it with `expiresAtMs` (after which the record may be dropped) and returns `true`.
|
|
50
|
+
*/
|
|
51
|
+
readonly claimStatement: (hashHex: string, expiresAtMs: number) => Promise<boolean>;
|
|
52
|
+
readonly putInvoice: (invoice: LightningAddressInvoice) => Promise<void>;
|
|
53
|
+
readonly invoiceByPaymentHash: (hashHex: string) => Promise<LightningAddressInvoice | undefined>;
|
|
54
|
+
/**
|
|
55
|
+
* Unsettled invoices whose expiry has not passed at `nowMs` — at most `limit`, ordered
|
|
56
|
+
* least-recently-checked first so a bounded `settlePending` round rotates fairly.
|
|
57
|
+
*/
|
|
58
|
+
readonly pendingInvoices: (nowMs: number, limit: number) => Promise<ReadonlyArray<LightningAddressInvoice>>;
|
|
59
|
+
/** Records that `hashHex` was status-checked at `nowMs`; feeds the {@link pendingInvoices} order. */
|
|
60
|
+
readonly markChecked: (hashHex: string, nowMs: number) => Promise<void>;
|
|
61
|
+
/** Unsettled, unexpired invoice count at `nowMs` — scoped to `pubkeyHex` when given. */
|
|
62
|
+
readonly countPendingInvoices: (nowMs: number, pubkeyHex?: string) => Promise<number>;
|
|
63
|
+
/**
|
|
64
|
+
* Deletes expired unsettled invoices and settled invoices whose expiry passed more than
|
|
65
|
+
* `settledRetentionMs` ago. Returns the number of rows removed.
|
|
66
|
+
*/
|
|
67
|
+
readonly pruneInvoices: (nowMs: number, settledRetentionMs: number) => Promise<number>;
|
|
68
|
+
readonly settleInvoice: (hashHex: string, preimageHex: string) => Promise<LightningAddressInvoice | undefined>;
|
|
69
|
+
};
|
|
70
|
+
/**
|
|
71
|
+
* In-memory {@link LightningAddressStore} — a reference implementation and the test store. `now` is
|
|
72
|
+
* injectable so statement claims can prune expired entries deterministically.
|
|
73
|
+
*/
|
|
74
|
+
export declare function createMemoryLightningAddressStore(now?: () => number): LightningAddressStore;
|
|
75
|
+
//#endregion
|
|
76
|
+
//#region src/server/index.d.ts
|
|
77
|
+
export type LightningAddressResult = {
|
|
78
|
+
readonly status: number;
|
|
79
|
+
readonly body: unknown;
|
|
80
|
+
};
|
|
81
|
+
/** NIP-57 zap support: the receipt key plus the app's own zap-request validation. */
|
|
82
|
+
export type LightningAddressZapConfig = {
|
|
83
|
+
/** The receipt signer's 32-byte x-only public key, lowercase hex — the `nostrPubkey` payers see. */
|
|
84
|
+
readonly receiptPublicKey: string;
|
|
85
|
+
/**
|
|
86
|
+
* Validates a raw zap-request event JSON for `amountMsat`; throwing rejects the invoice. The
|
|
87
|
+
* registered user record holds no nostr key, so the request's `p` tag (the nostr pubkey the
|
|
88
|
+
* receipt attributes the zap to) cannot be bound to the payee — same behavior as Breez.
|
|
89
|
+
*/
|
|
90
|
+
readonly validateRequest: (json: string, amountMsat: number) => void;
|
|
91
|
+
};
|
|
92
|
+
/** The wallet the server creates invoices through — a `SparkClient` or its lightning slice. */
|
|
93
|
+
export type LightningAddressServerClient = Pick<SparkClient, "lightning">;
|
|
94
|
+
export type LightningAddressServer = {
|
|
95
|
+
/** `POST /lnurlpay/{pubkey}` — signed statement claims a name. */
|
|
96
|
+
readonly register: (pubkeyHex: string, body: unknown) => Promise<LightningAddressResult>;
|
|
97
|
+
/** `DELETE /lnurlpay/{pubkey}` — signed statement gives the held name up. */
|
|
98
|
+
readonly unregister: (pubkeyHex: string, body: unknown) => Promise<LightningAddressResult>;
|
|
99
|
+
/** `GET /.well-known/lnurlp/{name}` (or `/lnurlp/{name}`) — the LUD-06 payRequest. */
|
|
100
|
+
readonly payRequest: (name: string) => Promise<LightningAddressResult>;
|
|
101
|
+
/** `GET /lnurlp/{name}/invoice?amount=&comment=&nostr=` — the LUD-06 callback. */
|
|
102
|
+
readonly invoice: (name: string, params: {
|
|
103
|
+
readonly amount: unknown;
|
|
104
|
+
readonly comment?: string;
|
|
105
|
+
readonly nostr?: string;
|
|
106
|
+
}) => Promise<LightningAddressResult>;
|
|
107
|
+
/** `GET /lnurlp/verify/{paymentHash}` — LUD-21 payment status. */
|
|
108
|
+
readonly verify: (paymentHashHex: string) => Promise<LightningAddressResult>;
|
|
109
|
+
/**
|
|
110
|
+
* Polls `client.lightning.receiveStatus` for a bounded batch of pending invoices —
|
|
111
|
+
* least-recently-checked first — and settles the ones whose verified preimage arrived. Returns
|
|
112
|
+
* the records settled this round so the app can publish zap receipts or webhooks.
|
|
113
|
+
*/
|
|
114
|
+
readonly settlePending: () => Promise<ReadonlyArray<LightningAddressInvoice>>;
|
|
115
|
+
};
|
|
116
|
+
/**
|
|
117
|
+
* Creates the Lightning Address handlers for one `domain`. The registration LNURL handed out is the
|
|
118
|
+
* LUD-01 bech32 encoding of `https://{domain}/lnurlp/{name}` (not the `lnurlp://` LUD-17 scheme) —
|
|
119
|
+
* every LUD-16 wallet resolves the bare address without scheme support.
|
|
120
|
+
*/
|
|
121
|
+
export declare function createLightningAddressServer(options: {
|
|
122
|
+
readonly client: LightningAddressServerClient;
|
|
123
|
+
/** The served hostname — validated, lowercased, and signed into every registration message. */
|
|
124
|
+
readonly domain: string;
|
|
125
|
+
readonly store: LightningAddressStore;
|
|
126
|
+
readonly minSendableMsat: number;
|
|
127
|
+
readonly maxSendableMsat: number;
|
|
128
|
+
/** Longest payer comment accepted (LUD-12 `commentAllowed`). */
|
|
129
|
+
readonly commentAllowed: number;
|
|
130
|
+
/** BOLT-11 expiry requested for every issued invoice; default {@link DEFAULT_INVOICE_EXPIRY_SECS}. */
|
|
131
|
+
readonly invoiceExpirySecs?: number;
|
|
132
|
+
/**
|
|
133
|
+
* Pending (unsettled, unexpired) invoices one payee may hold — an unauthenticated callback is a
|
|
134
|
+
* write, so without a cap a name's quota is a free database row each. Default 100. The cap is a
|
|
135
|
+
* storage bound, not abuse protection: anyone can fill one name's quota with unpaid invoices for
|
|
136
|
+
* up to `invoiceExpirySecs`, temporarily blocking that name's payments — operators should add
|
|
137
|
+
* per-IP rate limiting at the reverse proxy.
|
|
138
|
+
*/
|
|
139
|
+
readonly maxPendingInvoicesPerUser?: number;
|
|
140
|
+
/** Pending invoices the whole server holds; default 10_000. */
|
|
141
|
+
readonly maxPendingInvoices?: number;
|
|
142
|
+
/**
|
|
143
|
+
* Registered names the whole server holds; default 100_000. A pubkey re-registering a new name is
|
|
144
|
+
* never blocked by the cap. This is a storage bound, not abuse protection: registration needs a
|
|
145
|
+
* valid signature but pubkeys are free to generate — put per-IP rate limiting on the register
|
|
146
|
+
* route at the reverse proxy.
|
|
147
|
+
*/
|
|
148
|
+
readonly maxUsers?: number;
|
|
149
|
+
/**
|
|
150
|
+
* Invoices status-checked per `settlePending` round, least-recently-checked first so a backlog
|
|
151
|
+
* rotates fairly instead of starving the tail. Default {@link DEFAULT_SETTLE_BATCH}.
|
|
152
|
+
*/
|
|
153
|
+
readonly settleBatch?: number;
|
|
154
|
+
readonly zap?: LightningAddressZapConfig | undefined;
|
|
155
|
+
readonly now?: (() => number) | undefined;
|
|
156
|
+
}): LightningAddressServer;
|
|
157
|
+
//#endregion
|
|
158
|
+
export type { LightningAddressInvoice, LightningAddressStore, LightningAddressUser };
|