@openreceive/http 0.2.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 +21 -0
- package/README.md +57 -0
- package/dist/adapter-surface-BtXnvW2q.d.ts +722 -0
- package/dist/adapter-surface.d.ts +3 -0
- package/dist/adapter-surface.js +20 -0
- package/dist/chunk-5S24YV7E.js +2228 -0
- package/dist/index.d.ts +411 -0
- package/dist/index.js +74 -0
- package/package.json +59 -0
|
@@ -0,0 +1,722 @@
|
|
|
1
|
+
import { Checkout, SwapData, NodeSettlementActionHook, CreateCheckoutAmount, NodeSettlementActionInput, OpenReceive } from '@openreceive/node';
|
|
2
|
+
import { ErrorBody, ErrorCode, TransactionSettlementStatus, PaymentDetails } from '@openreceive/core';
|
|
3
|
+
|
|
4
|
+
type AuthorizeAction = "checkout.prepare" | "checkout.create" | "payment.check" | "swap.quote" | "swap.create" | "swap.read" | "swap.refund";
|
|
5
|
+
/**
|
|
6
|
+
* Copied from the payer's JSON body before any host lookup. `reference` is on
|
|
7
|
+
* every order-scoped route; `paymentHash` is also set on `payment.check`,
|
|
8
|
+
* `swap.read`, and `swap.refund`. Either value identifies a row — it does not
|
|
9
|
+
* prove this caller owns it.
|
|
10
|
+
*/
|
|
11
|
+
interface AuthorizeResource {
|
|
12
|
+
reference?: string;
|
|
13
|
+
paymentHash?: string;
|
|
14
|
+
}
|
|
15
|
+
interface AuthorizeContext {
|
|
16
|
+
readonly action: AuthorizeAction;
|
|
17
|
+
readonly request: Request;
|
|
18
|
+
readonly resource: AuthorizeResource;
|
|
19
|
+
/**
|
|
20
|
+
* The untouched framework-native request (Express req, Fastify request), when
|
|
21
|
+
* an adapter provides one. Use it for middleware-attached state like
|
|
22
|
+
* req.session. Same `authorize` callback as `request`; this is not a second
|
|
23
|
+
* signature.
|
|
24
|
+
*/
|
|
25
|
+
readonly native?: unknown;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* One callback, one argument. Return `true` to allow, `false` for 403.
|
|
29
|
+
* May be sync or async. Destructure whichever fields of `context` you need —
|
|
30
|
+
* they are always present except `native`, which adapters fill in.
|
|
31
|
+
*/
|
|
32
|
+
type Authorize = (context: AuthorizeContext) => boolean | Promise<boolean>;
|
|
33
|
+
type RateLimit = Authorize;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* A control-flow error the handler maps to a JSON error response. Carries the HTTP status, a
|
|
37
|
+
* shared error code, and an optional `retryable` hint / `details` object.
|
|
38
|
+
*/
|
|
39
|
+
declare class HttpError extends Error {
|
|
40
|
+
readonly status: number;
|
|
41
|
+
readonly code: ErrorCode;
|
|
42
|
+
readonly retryable?: boolean;
|
|
43
|
+
readonly details?: Record<string, unknown>;
|
|
44
|
+
/** Emitted as a `Retry-After` header so clients can back off with a hint. */
|
|
45
|
+
readonly retryAfterSeconds?: number;
|
|
46
|
+
constructor(status: number, code: ErrorCode, message: string, options?: {
|
|
47
|
+
readonly retryable?: boolean;
|
|
48
|
+
readonly details?: Record<string, unknown>;
|
|
49
|
+
readonly retryAfterSeconds?: number;
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
/** Shape a service error carries: a numeric status and an OpenReceive error body. */
|
|
53
|
+
interface ServiceErrorShape {
|
|
54
|
+
readonly status: number;
|
|
55
|
+
readonly body: ErrorBody;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Duck-type an ServiceError (from @openreceive/node) without importing the class, so the
|
|
59
|
+
* handler stays runtime-agnostic and never breaks on cross-module `instanceof` identity mismatches
|
|
60
|
+
* (source vs. built dist, or two copies of @openreceive/node).
|
|
61
|
+
*/
|
|
62
|
+
declare function isServiceErrorShape(error: unknown): error is ServiceErrorShape;
|
|
63
|
+
/**
|
|
64
|
+
* Host-route control-flow error with the same `{ status, body }` shape as
|
|
65
|
+
* {@link ServiceError}. Use for cart/validation failures on app routes
|
|
66
|
+
* (for example the host's `/orders` route) so framework helpers can map them.
|
|
67
|
+
*/
|
|
68
|
+
declare class HostError extends Error {
|
|
69
|
+
readonly status: number;
|
|
70
|
+
readonly body: ErrorBody;
|
|
71
|
+
constructor(status: number, body: ErrorBody);
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Convenience factory for a host validation error (default 400 INVALID_REQUEST).
|
|
75
|
+
*
|
|
76
|
+
* `retryable` rides along only when it CONTRADICTS the code's own default —
|
|
77
|
+
* spelling out `retryable: false` on a CONFLICT restates what the shared error
|
|
78
|
+
* contract already says, and it was the one field that made the JS engine's
|
|
79
|
+
* conflict bodies differ from the Ruby engine's.
|
|
80
|
+
*/
|
|
81
|
+
declare function hostError(message: string, status?: number, code?: ErrorCode): HostError;
|
|
82
|
+
/**
|
|
83
|
+
* Map a thrown host/service error to `{ status, body }` for app routes outside the
|
|
84
|
+
* mounted OpenReceive handler. Returns `null` when the value is not a known shape
|
|
85
|
+
* (caller should rethrow / pass to `next(error)`).
|
|
86
|
+
*/
|
|
87
|
+
declare function mapHostRouteError(error: unknown): {
|
|
88
|
+
readonly status: number;
|
|
89
|
+
readonly body: ErrorBody;
|
|
90
|
+
} | null;
|
|
91
|
+
/** Generate a per-response request id used in both the body and the `X-Request-Id` header. */
|
|
92
|
+
declare function createRequestId(): string;
|
|
93
|
+
/**
|
|
94
|
+
* Serialize a value as a snake_case JSON response with the shared content-type and request-id header.
|
|
95
|
+
* `extraHeaders` are appended (not set) — used for `Retry-After` on 429s. Note for adapters:
|
|
96
|
+
* multi-value headers other than the ones used here would need per-framework handling
|
|
97
|
+
* (Express folds repeated `Set-Cookie` appends); the handler deliberately emits none.
|
|
98
|
+
*/
|
|
99
|
+
declare function jsonResponse(status: number, body: unknown, requestId: string, extraHeaders?: Iterable<readonly [string, string]>): Response;
|
|
100
|
+
/**
|
|
101
|
+
* Map any thrown value to a JSON error response with a code from the shared enum. Service errors keep
|
|
102
|
+
* their status/body (with `request_id` ensured); handler errors map to their status; anything else is
|
|
103
|
+
* a generic 500 INTERNAL so internal messages never leak.
|
|
104
|
+
*/
|
|
105
|
+
declare function errorResponse(error: unknown, requestId: string): Response;
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Seconds past an attempt's expiry during which reconciliation still scans for a
|
|
109
|
+
* settlement before closing the attempt. Covers clock skew and wallets that
|
|
110
|
+
* accept a payment moments after nominal invoice expiry.
|
|
111
|
+
*/
|
|
112
|
+
declare const OPENRECEIVE_ATTEMPT_EXPIRY_GRACE_SECONDS: 900;
|
|
113
|
+
/**
|
|
114
|
+
* Lifecycle of one payment attempt: {@link TransactionSettlementStatus} plus
|
|
115
|
+
* `attention`. `pending` attempts participate in reconciliation; every other
|
|
116
|
+
* status is terminal for reconciliation purposes. `attention` marks rows an
|
|
117
|
+
* operator must review before the attempt moves on: the wallet still
|
|
118
|
+
* explicitly reports an in-flight transaction state long after invoice expiry.
|
|
119
|
+
*/
|
|
120
|
+
type AttemptStatus = TransactionSettlementStatus | "attention";
|
|
121
|
+
/**
|
|
122
|
+
* The minimal row OpenReceive needs for one invoice or swap attempt.
|
|
123
|
+
* An order may have many of these records. `swapData` must remain server-only.
|
|
124
|
+
*/
|
|
125
|
+
interface PaymentRecord {
|
|
126
|
+
readonly reference: string;
|
|
127
|
+
readonly paymentHash: string;
|
|
128
|
+
readonly status: AttemptStatus;
|
|
129
|
+
/** Optional operator-facing detail for the current status (e.g. "superseded"). */
|
|
130
|
+
readonly statusReason?: string | null;
|
|
131
|
+
readonly paidAt: number | null;
|
|
132
|
+
/** Unix timestamp after which these payer instructions must not be reused. */
|
|
133
|
+
readonly expiresAt: number;
|
|
134
|
+
/** Unix timestamp used only to choose deterministically between historical attempts. */
|
|
135
|
+
readonly createdAt: number;
|
|
136
|
+
/** Safe, replayable payer response. Contains no wallet or provider credentials. */
|
|
137
|
+
readonly checkout: Checkout;
|
|
138
|
+
readonly swapData?: SwapData | null;
|
|
139
|
+
}
|
|
140
|
+
interface PaymentInsert {
|
|
141
|
+
readonly reference: string;
|
|
142
|
+
readonly paymentHash: string;
|
|
143
|
+
readonly expiresAt: number;
|
|
144
|
+
readonly createdAt: number;
|
|
145
|
+
readonly checkout: Checkout;
|
|
146
|
+
readonly swapData?: SwapData;
|
|
147
|
+
/** Client IP captured at invoice creation, when the adapter could attribute one. */
|
|
148
|
+
readonly clientIp?: string;
|
|
149
|
+
}
|
|
150
|
+
/** One pending attempt the reconciler should include in its next wallet scan. */
|
|
151
|
+
interface ReconcilableAttempt {
|
|
152
|
+
readonly paymentHash: string;
|
|
153
|
+
/** Exact NIP-47 invoice creation time returned by make_invoice. */
|
|
154
|
+
readonly createdAt: number;
|
|
155
|
+
/** Unix timestamp after which the attempt can be closed once a scan confirms no settlement. */
|
|
156
|
+
readonly expiresAt: number;
|
|
157
|
+
}
|
|
158
|
+
/** A terminal (non-settled) state transition observed by reconciliation. */
|
|
159
|
+
interface ReconciliationTransition {
|
|
160
|
+
readonly paymentHash: string;
|
|
161
|
+
readonly status: Exclude<AttemptStatus, "pending" | "settled">;
|
|
162
|
+
/** Unix timestamp of the wallet scan that justified this transition. */
|
|
163
|
+
readonly observedAt: number;
|
|
164
|
+
/** Operator-facing reason, e.g. "wallet_reported_expired" or "not_found_after_expiry". */
|
|
165
|
+
readonly reason: string;
|
|
166
|
+
}
|
|
167
|
+
/** One observed wallet settlement, as handed to the repository to record. */
|
|
168
|
+
interface SettlementRecord {
|
|
169
|
+
readonly paymentHash: string;
|
|
170
|
+
/** Unix timestamp the wallet reports (or the scan observed) the payment at. */
|
|
171
|
+
readonly paidAt: number;
|
|
172
|
+
readonly details?: PaymentDetails;
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Persistence boundary for payment attempts. Most applications use the
|
|
176
|
+
* library-provided SQL repository (`createSqlPayments`); implementing
|
|
177
|
+
* this interface directly is the advanced escape hatch.
|
|
178
|
+
*
|
|
179
|
+
* `commitAttempt` must serialize concurrent creates for one order, reject a
|
|
180
|
+
* settled order or a reusable live attempt on the same rail/asset, supersede a
|
|
181
|
+
* near-expiry same-rail attempt, and commit before it returns. Other rails may
|
|
182
|
+
* remain live so the payer can switch methods. The HTTP handler withholds payer
|
|
183
|
+
* instructions when this method throws.
|
|
184
|
+
*
|
|
185
|
+
* `recordReconciliation` must apply the transition only while the row is still
|
|
186
|
+
* `pending` — it must never overwrite a settled attempt.
|
|
187
|
+
*
|
|
188
|
+
* `recordSettlement` is the write-once settlement claim: the library calls it
|
|
189
|
+
* for every observed settlement and runs the host's own handler only when the
|
|
190
|
+
* call reports the claim won, so a redelivered settlement fulfills once.
|
|
191
|
+
*/
|
|
192
|
+
interface PaymentRepository {
|
|
193
|
+
listForReference(reference: string): Promise<readonly PaymentRecord[]>;
|
|
194
|
+
/**
|
|
195
|
+
* The oldest `pending` attempts, terminal rows excluded. A repository with a
|
|
196
|
+
* large backlog should return an oldest-first batch (the built-in SQL one
|
|
197
|
+
* caps each pass at OPENRECEIVE_RECONCILE_BATCH_SIZE); the remainder is
|
|
198
|
+
* covered by later passes.
|
|
199
|
+
*/
|
|
200
|
+
listReconcilableAttempts(): Promise<readonly ReconcilableAttempt[]>;
|
|
201
|
+
/**
|
|
202
|
+
* The `pending` attempt for one payment hash, or undefined when the hash is
|
|
203
|
+
* unknown or already terminal. Direct settlement from an NWC notification
|
|
204
|
+
* needs a by-hash answer: `listReconcilableAttempts` is an oldest-first
|
|
205
|
+
* batch, so a notified attempt behind a backlog would look unknown. A
|
|
206
|
+
* repository that omits this falls back to batch membership, which delays
|
|
207
|
+
* notified settlements past a batch-sized backlog.
|
|
208
|
+
*/
|
|
209
|
+
findPendingAttempt?(paymentHash: string): Promise<ReconcilableAttempt | undefined>;
|
|
210
|
+
commitAttempt(input: CheckoutCreatedInput): void | Promise<void>;
|
|
211
|
+
recordReconciliation(transition: ReconciliationTransition): void | Promise<void>;
|
|
212
|
+
/**
|
|
213
|
+
* Claim the order's first settlement for this attempt and persist it.
|
|
214
|
+
* Returns true only for the call that won the claim — the attempt was still
|
|
215
|
+
* unsettled AND no sibling attempt on the order had settled. Later calls for
|
|
216
|
+
* the same or a sibling attempt must record the settlement (a genuine second
|
|
217
|
+
* payment is not discarded) and return false. A settled attempt is never
|
|
218
|
+
* overwritten, and an unknown payment hash is a no-op returning false.
|
|
219
|
+
*/
|
|
220
|
+
recordSettlement(settlement: SettlementRecord): boolean | Promise<boolean>;
|
|
221
|
+
/**
|
|
222
|
+
* Count attempt rows recorded for this client IP at or after `sinceUnixSeconds`.
|
|
223
|
+
* Backs the handler's opt-in `rateLimiting` option; when a custom repository
|
|
224
|
+
* omits it, enabling `rateLimiting` fails at construction (there is no
|
|
225
|
+
* in-memory fallback — use a custom `rateLimitHook` instead).
|
|
226
|
+
*/
|
|
227
|
+
countAttemptsFromIp?(clientIp: string, sinceUnixSeconds: number): number | Promise<number>;
|
|
228
|
+
/**
|
|
229
|
+
* Claim the durable global reconcile gate: return true when this caller may
|
|
230
|
+
* run a wallet scan now, false when another worker scanned within
|
|
231
|
+
* `intervalSeconds` (`gate_busy`). The claim MUST be a durable compare-and-set
|
|
232
|
+
* shared by every process on the host database (the built-in SQL repository
|
|
233
|
+
* uses the `openreceive_meta` key/value/rev table) — process-local memory
|
|
234
|
+
* cannot coordinate multiple workers and must never back this. Backs the
|
|
235
|
+
* handler's default opportunistic reconcile; when a custom repository omits
|
|
236
|
+
* it, construction throws unless `opportunisticReconcile: false` — the
|
|
237
|
+
* default settlement path never degrades silently.
|
|
238
|
+
*/
|
|
239
|
+
claimReconcileGate?(input: {
|
|
240
|
+
readonly now: number;
|
|
241
|
+
readonly intervalSeconds: number;
|
|
242
|
+
}): boolean | Promise<boolean>;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Runs one SQL statement and returns SELECT rows (`[]` otherwise). The SQL
|
|
247
|
+
* arrives written for the adapter's own dialect — `?` placeholders on sqlite,
|
|
248
|
+
* `$1`-style on postgres — so pass it to the driver verbatim. Nothing rewrites
|
|
249
|
+
* it: a `?` inside a string literal, a comment, or a postgres JSON operator
|
|
250
|
+
* (`data ? 'field'`) must survive untouched.
|
|
251
|
+
*/
|
|
252
|
+
type SqlQuery = (sql: string, params?: readonly unknown[]) => Promise<readonly Record<string, unknown>[]>;
|
|
253
|
+
interface SqlClient {
|
|
254
|
+
readonly query: SqlQuery;
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* The escape-hatch database boundary: a dialect, a query function, and a
|
|
258
|
+
* transaction wrapper. The built-in bindings cover `pg` pools/clients and
|
|
259
|
+
* SQLite (`node:sqlite` or better-sqlite3) without adding dependencies.
|
|
260
|
+
*/
|
|
261
|
+
interface SqlAdapter extends SqlClient {
|
|
262
|
+
readonly dialect: "postgres" | "sqlite";
|
|
263
|
+
transaction<T>(run: (tx: SqlClient) => Promise<T>): Promise<T>;
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* Structural view of a `pg` Pool or Client. A Pool's `connect()` checks out a
|
|
267
|
+
* per-transaction client; a Client's `connect()` opens its one socket and
|
|
268
|
+
* resolves nothing, so it must be called at most once. A handle with only
|
|
269
|
+
* `query` is treated as a single connection and transactions serialize on it.
|
|
270
|
+
*/
|
|
271
|
+
interface PgLike {
|
|
272
|
+
query(sql: string, params?: unknown[]): Promise<{
|
|
273
|
+
rows: Record<string, unknown>[];
|
|
274
|
+
}>;
|
|
275
|
+
connect?(): Promise<unknown>;
|
|
276
|
+
}
|
|
277
|
+
/** Structural view of `node:sqlite` DatabaseSync or a better-sqlite3 Database. */
|
|
278
|
+
interface SqliteLike {
|
|
279
|
+
prepare(sql: string): {
|
|
280
|
+
all(...params: unknown[]): unknown[];
|
|
281
|
+
run(...params: unknown[]): unknown;
|
|
282
|
+
};
|
|
283
|
+
exec(sql: string): void;
|
|
284
|
+
}
|
|
285
|
+
/** Any database handle `createSqlPayments` accepts. */
|
|
286
|
+
type SqlDatabase = SqlAdapter | PgLike | SqliteLike;
|
|
287
|
+
|
|
288
|
+
/**
|
|
289
|
+
* Oldest-first page size for one reconciliation pass. A backlog of pending
|
|
290
|
+
* attempts is drained over several passes instead of loading every row (and
|
|
291
|
+
* scanning every invoice's window) in one unbounded query.
|
|
292
|
+
*/
|
|
293
|
+
declare const OPENRECEIVE_RECONCILE_BATCH_SIZE: 200;
|
|
294
|
+
interface SqlPaymentsOptions {
|
|
295
|
+
/** Payment attempts table name. Default `openreceive_payments`. */
|
|
296
|
+
readonly tableName?: string;
|
|
297
|
+
/** Durable reconcile-gate key/value table name. Default `openreceive_meta`. */
|
|
298
|
+
readonly metaTableName?: string;
|
|
299
|
+
readonly clock?: () => number;
|
|
300
|
+
}
|
|
301
|
+
/** Settlement context passed to the host's `onPaid` in library-persistence mode. */
|
|
302
|
+
interface PaymentSettlement {
|
|
303
|
+
readonly reference: string;
|
|
304
|
+
readonly paymentHash: string;
|
|
305
|
+
readonly paidAt: number;
|
|
306
|
+
readonly details?: PaymentDetails;
|
|
307
|
+
/**
|
|
308
|
+
* Runs statements inside the settlement transaction. Use it to update the
|
|
309
|
+
* host order or insert a transactional outbox row. Write the placeholders
|
|
310
|
+
* your database uses (`?` on sqlite, `$1`-style on postgres) — this SQL is
|
|
311
|
+
* yours and reaches the driver exactly as written.
|
|
312
|
+
*
|
|
313
|
+
* OpenReceive already guarantees this hook fires at most once per reference
|
|
314
|
+
* across its own settlement paths. It cannot see fulfillment triggered
|
|
315
|
+
* anywhere else, though —
|
|
316
|
+
* an admin action, a second processor, a replayed job — so if any of those
|
|
317
|
+
* exist, guard the transition here rather than assuming exclusivity:
|
|
318
|
+
*
|
|
319
|
+
* ```sql
|
|
320
|
+
* UPDATE orders SET state = 'paid'
|
|
321
|
+
* WHERE id = $1 AND state = 'awaiting_payment' RETURNING id
|
|
322
|
+
* ```
|
|
323
|
+
*
|
|
324
|
+
* An empty result means someone else already fulfilled it; return without
|
|
325
|
+
* shipping. `fulfillmentNote` in `@openreceive/core` is the full
|
|
326
|
+
* version, and is what the scaffold writes into every generated file.
|
|
327
|
+
*/
|
|
328
|
+
readonly query: SqlQuery;
|
|
329
|
+
}
|
|
330
|
+
type PaymentSettlementHook = (settlement: PaymentSettlement) => void | Promise<void>;
|
|
331
|
+
interface SqlPaymentRepository extends PaymentRepository {
|
|
332
|
+
/**
|
|
333
|
+
* Replay-safe settlement transaction: set the attempt's `paid_at`/`settled`
|
|
334
|
+
* status once, and run `fulfill` inside the same transaction only for the
|
|
335
|
+
* order's first settled attempt. A later sibling settlement is recorded with
|
|
336
|
+
* reason `duplicate_settlement` and never fulfills again. Returns whether
|
|
337
|
+
* this call won the order's first-settlement claim (and therefore ran
|
|
338
|
+
* `fulfill`).
|
|
339
|
+
*/
|
|
340
|
+
markPaidOnce(input: {
|
|
341
|
+
paymentHash: string;
|
|
342
|
+
paidAt: number;
|
|
343
|
+
details?: PaymentDetails;
|
|
344
|
+
}, fulfill: PaymentSettlementHook): Promise<boolean>;
|
|
345
|
+
}
|
|
346
|
+
/**
|
|
347
|
+
* The canonical payment-attempts DDL, rendered as one executable script. The
|
|
348
|
+
* statements themselves live in `@openreceive/core`
|
|
349
|
+
* (`paymentsDdlStatements`) so this helper and the scaffold CLI's
|
|
350
|
+
* ORM migrations can never drift from each other.
|
|
351
|
+
*/
|
|
352
|
+
declare function paymentsSchemaSql(dialect: "postgres" | "sqlite", tableName?: string, metaTableName?: string): string;
|
|
353
|
+
/**
|
|
354
|
+
* Library-owned payment-attempt repository over the host application's existing
|
|
355
|
+
* database. Owns the commit locking, settlement write-once, and reconciliation
|
|
356
|
+
* state transitions so host applications never implement them.
|
|
357
|
+
*/
|
|
358
|
+
declare function createSqlPayments(db: SqlDatabase, options?: SqlPaymentsOptions): SqlPaymentRepository;
|
|
359
|
+
|
|
360
|
+
interface CreateOpenReceiveHostBaseOptions {
|
|
361
|
+
/**
|
|
362
|
+
* The trusted price for a reference, or `null` when there is nothing to
|
|
363
|
+
* pay for (the request is answered 404). Called only where a price is
|
|
364
|
+
* minted or quoted; the payer never sends an amount.
|
|
365
|
+
*/
|
|
366
|
+
readonly amountFor: (reference: string, context: ResolveCheckoutContext) => CreateCheckoutAmount | null | Promise<CreateCheckoutAmount | null>;
|
|
367
|
+
readonly clock?: () => number;
|
|
368
|
+
}
|
|
369
|
+
/**
|
|
370
|
+
* Default mode: OpenReceive owns the payment-attempt rows in the host
|
|
371
|
+
* application's existing database. `onPaid` runs inside the settlement
|
|
372
|
+
* transaction for the first settled attempt for a reference only.
|
|
373
|
+
*/
|
|
374
|
+
interface CreateHostDbOptions extends CreateOpenReceiveHostBaseOptions {
|
|
375
|
+
readonly db: SqlDatabase;
|
|
376
|
+
/** Payment attempts table name. Default `openreceive_payments`. */
|
|
377
|
+
readonly tableName?: string;
|
|
378
|
+
readonly onPaid: PaymentSettlementHook;
|
|
379
|
+
readonly payments?: never;
|
|
380
|
+
}
|
|
381
|
+
/**
|
|
382
|
+
* Settlement context passed to repository-mode `onPaid`: the raw core
|
|
383
|
+
* settlement event (`paymentHash`, `paidAt`, `details`). Unlike db-mode's
|
|
384
|
+
* {@link PaymentSettlement} it carries no `reference` and no
|
|
385
|
+
* transactional `query` — the custom repository owns that mapping.
|
|
386
|
+
*/
|
|
387
|
+
type SettlementEvent = NodeSettlementActionInput;
|
|
388
|
+
type SettlementEventHook = (settlement: SettlementEvent) => void | Promise<void>;
|
|
389
|
+
/**
|
|
390
|
+
* Advanced escape hatch: the host implements the full
|
|
391
|
+
* `PaymentRepository` contract, including commit locking, write-once
|
|
392
|
+
* settlement, and reconciliation transitions.
|
|
393
|
+
*
|
|
394
|
+
* The settlement hook is `onPaid` in this mode too, but its context type
|
|
395
|
+
* differs from db mode: it receives the raw {@link SettlementEvent}
|
|
396
|
+
* (`paymentHash`, `paidAt`, `details`), with no `reference` and no transactional
|
|
397
|
+
* `query` — unlike db-mode `onPaid`, which runs inside the library's settlement
|
|
398
|
+
* transaction. Write-once is still the library's: repository-mode `onPaid`
|
|
399
|
+
* runs only for the settlement whose `payments.recordSettlement` claim was
|
|
400
|
+
* won, so a redelivered settlement never fulfills twice.
|
|
401
|
+
*/
|
|
402
|
+
interface CreateHostRepositoryOptions extends CreateOpenReceiveHostBaseOptions {
|
|
403
|
+
readonly payments: PaymentRepository;
|
|
404
|
+
/** Host settlement handler; runs once, for the winning first-settlement claim. */
|
|
405
|
+
readonly onPaid: SettlementEventHook;
|
|
406
|
+
readonly db?: never;
|
|
407
|
+
readonly tableName?: never;
|
|
408
|
+
}
|
|
409
|
+
type CreateHostOptions = CreateHostDbOptions | CreateHostRepositoryOptions;
|
|
410
|
+
interface Host {
|
|
411
|
+
readonly resolveCheckout: ResolveCheckoutHook;
|
|
412
|
+
readonly onCheckoutCreated: CheckoutCreatedHook;
|
|
413
|
+
readonly onPaid: NodeSettlementActionHook;
|
|
414
|
+
readonly payments: PaymentRepository;
|
|
415
|
+
}
|
|
416
|
+
/**
|
|
417
|
+
* Build the mounted-route host integration around the host's price hook and
|
|
418
|
+
* either the host database handle (`db`, default) or a custom payment
|
|
419
|
+
* repository (`payments`, advanced). Attempt selection, commit locking,
|
|
420
|
+
* settlement write-once, and reconciliation transitions are library-owned in
|
|
421
|
+
* `db` mode.
|
|
422
|
+
*/
|
|
423
|
+
declare function createHost(options: CreateHostOptions): Host;
|
|
424
|
+
|
|
425
|
+
interface IpRateLimitConfig {
|
|
426
|
+
/** Maximum invoice creations per IP per rolling hour. Default 60. */
|
|
427
|
+
readonly limitPerHour?: number;
|
|
428
|
+
/** Optional additional cap per rolling 24 hours. Unset = hourly cap only. */
|
|
429
|
+
readonly limitPerDay?: number;
|
|
430
|
+
/** Payer-facing message on the 429 response. */
|
|
431
|
+
readonly message?: string;
|
|
432
|
+
/**
|
|
433
|
+
* Actions to throttle. Default: both invoice-minting actions. Only
|
|
434
|
+
* `checkout.create` and `swap.create` are accepted — attempt-row counting counts
|
|
435
|
+
* mints, so a throttle on any other action could never trigger. Police other
|
|
436
|
+
* actions with a custom `rateLimitHook` instead.
|
|
437
|
+
*/
|
|
438
|
+
readonly actions?: readonly AuthorizeAction[];
|
|
439
|
+
/**
|
|
440
|
+
* Client IP extractor. The default reads `native.ip` (Express/Fastify request).
|
|
441
|
+
* Returning undefined allows the request — the limiter fails open rather than
|
|
442
|
+
* blocking payers the host cannot attribute, and warns once per limiter so an
|
|
443
|
+
* adapter that never supplies an IP is visible.
|
|
444
|
+
*/
|
|
445
|
+
readonly ip?: (context: AuthorizeContext) => string | undefined;
|
|
446
|
+
/**
|
|
447
|
+
* Count invoice attempts for this IP at or after `sinceUnixSeconds`. The handler
|
|
448
|
+
* wires this to the payment repository's `countAttemptsFromIp` automatically.
|
|
449
|
+
* Required: without a counter, construction throws — there is no ephemeral
|
|
450
|
+
* in-process fallback.
|
|
451
|
+
*/
|
|
452
|
+
readonly countAttemptsFromIp?: (clientIp: string, sinceUnixSeconds: number) => number | Promise<number>;
|
|
453
|
+
/** Clock in unix seconds; override in tests. */
|
|
454
|
+
readonly now?: () => number;
|
|
455
|
+
}
|
|
456
|
+
/**
|
|
457
|
+
* Build the per-IP invoice rate limit behind the handler's `rateLimiting` option.
|
|
458
|
+
* Hosts composing their own policy can call this directly and pass the result as
|
|
459
|
+
* `rateLimitHook`. Over-limit requests fail with `429 RATE_LIMITED` and a retryable,
|
|
460
|
+
* payer-facing message; requests with no attributable IP are always allowed.
|
|
461
|
+
* Fails closed at construction when no `countAttemptsFromIp` counter is supplied.
|
|
462
|
+
*/
|
|
463
|
+
declare function createIpRateLimit(config?: IpRateLimitConfig): RateLimit;
|
|
464
|
+
/**
|
|
465
|
+
* The `rateLimiting` slice of the handler options an adapter passes on when the
|
|
466
|
+
* host opted into a trusted forwarded IP header. Shared by @openreceive/express,
|
|
467
|
+
* /fastify and /next so the three adapters cannot drift on a security control.
|
|
468
|
+
*
|
|
469
|
+
* `trustProxyIpHeader` is `true` for `x-forwarded-for`, or the name of another
|
|
470
|
+
* header YOUR reverse proxy sets; the extracted first hop becomes the limiter's
|
|
471
|
+
* `ip` unless the host supplied its own extractor.
|
|
472
|
+
*
|
|
473
|
+
* `requireIpSource` names the adapter for adapters whose native request carries
|
|
474
|
+
* NO socket IP (Next: a web Request has none). Those must fail loud at
|
|
475
|
+
* construction rather than build a limiter that can never attribute a request;
|
|
476
|
+
* adapters that do have a socket-IP fallback (Express/Fastify `req.ip`) leave it
|
|
477
|
+
* unset and simply keep the default limiter when no header is trusted.
|
|
478
|
+
*/
|
|
479
|
+
declare function createProxyRateLimitingConfig(rateLimiting: boolean | IpRateLimitConfig | undefined, trustProxyIpHeader: boolean | string | undefined, options?: {
|
|
480
|
+
readonly requireIpSource?: string;
|
|
481
|
+
}): {
|
|
482
|
+
readonly rateLimiting?: boolean | IpRateLimitConfig;
|
|
483
|
+
};
|
|
484
|
+
/**
|
|
485
|
+
* Client IP the adapter attributed to this request: `native.ip` (Express/Fastify).
|
|
486
|
+
* Undefined when no adapter IP is available — callers must treat that as
|
|
487
|
+
* "unattributable", never as an error.
|
|
488
|
+
*/
|
|
489
|
+
declare function resolveClientIp(context: Pick<AuthorizeContext, "native">): string | undefined;
|
|
490
|
+
|
|
491
|
+
interface CheckoutCreatedInput {
|
|
492
|
+
readonly reference: string;
|
|
493
|
+
readonly paymentHash: string;
|
|
494
|
+
readonly checkout: Checkout;
|
|
495
|
+
/** Sensitive server-only provider state. Persist it on the payment attempt; never send it to a browser. */
|
|
496
|
+
readonly swapData?: SwapData;
|
|
497
|
+
/**
|
|
498
|
+
* Client IP the adapter attributed to this request, stored on the attempt row.
|
|
499
|
+
* Backs the opt-in `rateLimiting` option; absent when no IP was attributable.
|
|
500
|
+
*/
|
|
501
|
+
readonly clientIp?: string;
|
|
502
|
+
}
|
|
503
|
+
type CheckoutCreatedHook = (input: CheckoutCreatedInput) => void | Promise<void>;
|
|
504
|
+
interface ResolveCheckoutContext {
|
|
505
|
+
readonly action: AuthorizeAction;
|
|
506
|
+
readonly request: Request;
|
|
507
|
+
readonly reference: string;
|
|
508
|
+
readonly payInAsset?: string;
|
|
509
|
+
/** Untrusted payer input. Use it only to locate/recompute host-owned data. */
|
|
510
|
+
readonly input: Readonly<Record<string, unknown>>;
|
|
511
|
+
}
|
|
512
|
+
interface ResolvedHostCheckout {
|
|
513
|
+
/**
|
|
514
|
+
* Host-owned price. Payer input is never an amount authority. Required for
|
|
515
|
+
* prepare/create/quote actions; status and refund actions on a committed
|
|
516
|
+
* attempt never need (or wait for) host pricing.
|
|
517
|
+
*/
|
|
518
|
+
readonly amount?: CreateCheckoutAmount;
|
|
519
|
+
/** Return the selected host payment attempt's hash to reuse or inspect its checkout. */
|
|
520
|
+
readonly paymentHash?: string;
|
|
521
|
+
/** Host-persisted safe checkout snapshot used for retry without a wallet read. */
|
|
522
|
+
readonly checkout?: Checkout;
|
|
523
|
+
/** Server-only structured provider state loaded from the host database. */
|
|
524
|
+
readonly swapData?: SwapData;
|
|
525
|
+
/**
|
|
526
|
+
* The selected attempt's stored status and settlement time, when the
|
|
527
|
+
* resolver read them. `payments/check` serves this on the row path
|
|
528
|
+
* (`gate_busy`, a hash outside the pending set, reconcile disabled) instead
|
|
529
|
+
* of re-reading the rows the resolver listed moments earlier in the same
|
|
530
|
+
* request — that route is the highest-frequency one there is. A custom
|
|
531
|
+
* `resolveCheckout` may omit it; the row is then re-read.
|
|
532
|
+
*/
|
|
533
|
+
readonly attemptStatus?: {
|
|
534
|
+
readonly status: AttemptStatus;
|
|
535
|
+
readonly paidAt: number | null;
|
|
536
|
+
};
|
|
537
|
+
}
|
|
538
|
+
type ResolveCheckoutHook = (context: ResolveCheckoutContext) => ResolvedHostCheckout | Promise<ResolvedHostCheckout>;
|
|
539
|
+
interface CreateHttpHandlerOptions {
|
|
540
|
+
readonly service: OpenReceive;
|
|
541
|
+
/** Host authentication and authorization policy. OpenReceive never inspects host sessions. */
|
|
542
|
+
readonly authorize: Authorize;
|
|
543
|
+
/** Host authentication-independent payment integration returned by createHost. */
|
|
544
|
+
readonly host: Host;
|
|
545
|
+
readonly rateLimitHook?: RateLimit;
|
|
546
|
+
/**
|
|
547
|
+
* Built-in per-IP invoice rate limiting. OFF by default: shared-IP deployments
|
|
548
|
+
* (point-of-sale terminals, kiosks, NAT'd venues) mint many invoices from one
|
|
549
|
+
* address and must never be blocked by an accidental default. Recommended for
|
|
550
|
+
* public web shops: `rateLimiting: true` caps invoice creation at 60 per IP per
|
|
551
|
+
* rolling hour, counted from `openreceive_payments` rows by `client_ip` — limits
|
|
552
|
+
* survive restarts and span instances sharing the database. Requires a repository
|
|
553
|
+
* that can count (the built-in SQL repository does); construction throws otherwise
|
|
554
|
+
* rather than degrading to per-process memory. Applies only when a new attempt
|
|
555
|
+
* would be minted — reuse of a committed attempt is never throttled — and fails
|
|
556
|
+
* open per-request when no client IP is attributable. Pass a config object to
|
|
557
|
+
* tune limits or the payer-facing message. Mutually exclusive with a custom
|
|
558
|
+
* `rateLimitHook`.
|
|
559
|
+
*/
|
|
560
|
+
readonly rateLimiting?: boolean | IpRateLimitConfig;
|
|
561
|
+
/**
|
|
562
|
+
* Opportunistic settlement discovery, ON by default: every mounted payment
|
|
563
|
+
* route first runs one durably gated reconcile pass when payment attempts
|
|
564
|
+
* are pending, so abandoned checkouts settle on any later OpenReceive call
|
|
565
|
+
* with no long-running process. Unauthenticated `GET /rates` never triggers
|
|
566
|
+
* it — crawlers and health checks must not consume the wallet-scan budget.
|
|
567
|
+
* The durable `openreceive_meta` gate (min 2s, stretched by invoice age) is
|
|
568
|
+
* shared by every worker on the host database, so rapid calls collapse to
|
|
569
|
+
* one real wallet scan per interval; `payments/check` serves the requested
|
|
570
|
+
* hash from that same pass — one gate claim per request, never a second
|
|
571
|
+
* per-invoice wallet walk. Requires `payments.claimReconcileGate` (the
|
|
572
|
+
* built-in SQL repository has it); construction throws otherwise rather
|
|
573
|
+
* than degrading silently. A dedicated notifications worker claims the same
|
|
574
|
+
* gate, so running both never double-scans. Pass `false` to disable or
|
|
575
|
+
* `{ minIntervalSeconds }` to tune.
|
|
576
|
+
*/
|
|
577
|
+
readonly opportunisticReconcile?: boolean | {
|
|
578
|
+
readonly minIntervalSeconds?: number;
|
|
579
|
+
};
|
|
580
|
+
/**
|
|
581
|
+
* Clock override (unix seconds) for every time-dependent decision the
|
|
582
|
+
* handler makes: the opportunistic reconcile gate AND the `payments/check`
|
|
583
|
+
* payment-methods cache TTL. A test that overrides it to control the gate
|
|
584
|
+
* also controls that cache — which is the point (one clock, one handler),
|
|
585
|
+
* but worth knowing before a frozen clock keeps a warmed catalog forever.
|
|
586
|
+
*/
|
|
587
|
+
readonly clock?: () => number;
|
|
588
|
+
readonly prefix?: string;
|
|
589
|
+
}
|
|
590
|
+
interface HttpHandler {
|
|
591
|
+
(request: Request, extras?: {
|
|
592
|
+
native?: unknown;
|
|
593
|
+
}): Promise<Response>;
|
|
594
|
+
readonly prefix: string;
|
|
595
|
+
handle(request: Request, extras?: {
|
|
596
|
+
native?: unknown;
|
|
597
|
+
}): Promise<Response>;
|
|
598
|
+
}
|
|
599
|
+
declare function createHttpHandler(options: CreateHttpHandlerOptions): HttpHandler;
|
|
600
|
+
|
|
601
|
+
interface NotificationListener {
|
|
602
|
+
/** Unsubscribe from wallet notifications and wait for any in-flight pass. */
|
|
603
|
+
stop(): Promise<void> | void;
|
|
604
|
+
}
|
|
605
|
+
/**
|
|
606
|
+
* Opt-in NWC-02 notification listener. Notifications are authenticated wallet
|
|
607
|
+
* data: a `payment_received` payload that satisfies the settlement rule
|
|
608
|
+
* (`settled_at` or a settled transaction state — never a preimage alone) and
|
|
609
|
+
* matches a pending attempt settles that attempt directly through
|
|
610
|
+
* `host.onPaid`, with no redundant wallet scan for that invoice. Anything less
|
|
611
|
+
* — no payload, no finality signal, or an unknown/not-pending hash — wakes one
|
|
612
|
+
* reconcile pass instead, claimed through the durable scan gate so listeners,
|
|
613
|
+
* workers, and the request path share one wallet-scan budget. Bursts coalesce:
|
|
614
|
+
* while a pass runs, at most one follow-up pass is queued. Errors go to
|
|
615
|
+
* `onError` (default: a sanitized console.warn); a direct-settlement failure
|
|
616
|
+
* also falls back to a scan so the safety net covers it. The polling
|
|
617
|
+
* reconciler remains the safety net for
|
|
618
|
+
* notifications missed while offline. Direct settlement assumes the NWC client
|
|
619
|
+
* binds notification decryption to the connection's wallet pubkey (the bundled
|
|
620
|
+
* SDK does).
|
|
621
|
+
*/
|
|
622
|
+
declare function startNotificationListener(input: {
|
|
623
|
+
readonly service: OpenReceive;
|
|
624
|
+
readonly host: Host;
|
|
625
|
+
readonly overlapSeconds?: number;
|
|
626
|
+
readonly onError?: (error: unknown) => void;
|
|
627
|
+
}): Promise<NotificationListener>;
|
|
628
|
+
interface NotificationWorker {
|
|
629
|
+
/** Unsubscribe, stop the periodic pass, and wait for in-flight work. */
|
|
630
|
+
stop(): Promise<void>;
|
|
631
|
+
/** Resolves after `stop()` once the periodic loop has drained. */
|
|
632
|
+
readonly done: Promise<void>;
|
|
633
|
+
}
|
|
634
|
+
/**
|
|
635
|
+
* The OPTIONAL case-2 worker: one separate long-lived process that both
|
|
636
|
+
* listens for NWC-02 `payment_received` notifications AND runs the same
|
|
637
|
+
* one-pass reconcile on an interval — the safety net for notifications missed
|
|
638
|
+
* while this worker was down. The web process never does this; its default is
|
|
639
|
+
* request-path opportunistic reconcile. Every pass — worker or web — claims
|
|
640
|
+
* the same durable scan gate, so running both never double-scans the wallet.
|
|
641
|
+
* A wallet without notification support degrades to the periodic pass alone
|
|
642
|
+
* (reported via `onError`).
|
|
643
|
+
*
|
|
644
|
+
* There is no host-aware CLI for this: wire it from a small host script that
|
|
645
|
+
* owns `service` and `host` (see the scaffold wiring guide).
|
|
646
|
+
*/
|
|
647
|
+
declare function startNotificationWorker(input: {
|
|
648
|
+
readonly service: OpenReceive;
|
|
649
|
+
readonly host: Host;
|
|
650
|
+
/** Periodic safety-net pass interval. Default 15 seconds. */
|
|
651
|
+
readonly pollIntervalMs?: number;
|
|
652
|
+
readonly overlapSeconds?: number;
|
|
653
|
+
readonly onError?: (error: unknown) => void;
|
|
654
|
+
}): Promise<NotificationWorker>;
|
|
655
|
+
|
|
656
|
+
/**
|
|
657
|
+
* The one-factory happy path (T1): three callbacks plus a db handle. The stack
|
|
658
|
+
* builds the service, host, and handler in one call — the composed
|
|
659
|
+
* `{ service, host, ... }` form and every individual piece stay exported for
|
|
660
|
+
* tests and custom repositories.
|
|
661
|
+
*
|
|
662
|
+
* The stack starts NO background process: settlement of abandoned checkouts
|
|
663
|
+
* happens opportunistically when any later OpenReceive call wins the durable
|
|
664
|
+
* reconcile gate (the handler's default `opportunisticReconcile`). Hosts that
|
|
665
|
+
* want push notifications or a poll loop run the optional worker —
|
|
666
|
+
* `startNotificationWorker` — in a separate process.
|
|
667
|
+
*/
|
|
668
|
+
/**
|
|
669
|
+
* The wallet the stack talks to: a receive-only NWC connection string — the
|
|
670
|
+
* stack builds and owns the client, and `close()` closes it — or a prebuilt
|
|
671
|
+
* (or promised) service for custom options, whose lifecycle stays yours.
|
|
672
|
+
*/
|
|
673
|
+
type StackWallet = {
|
|
674
|
+
readonly nwc: string;
|
|
675
|
+
readonly service?: never;
|
|
676
|
+
} | {
|
|
677
|
+
readonly service: OpenReceive | Promise<OpenReceive>;
|
|
678
|
+
readonly nwc?: never;
|
|
679
|
+
};
|
|
680
|
+
/**
|
|
681
|
+
* Where attempts live, which decides what `onPaid` receives. With the host
|
|
682
|
+
* database handle (`db`, the default mode) it is the per-reference
|
|
683
|
+
* `PaymentSettlement`, with `reference` and the transactional `query`;
|
|
684
|
+
* with a custom repository (`payments`, advanced) it is the raw
|
|
685
|
+
* `SettlementEvent`. The branch carries the hook's type, so the
|
|
686
|
+
* wrong signature is a type error rather than a runtime surprise.
|
|
687
|
+
*/
|
|
688
|
+
type StackStorage = Pick<CreateHostDbOptions, "db" | "tableName" | "onPaid" | "payments"> | Pick<CreateHostRepositoryOptions, "payments" | "onPaid" | "db" | "tableName">;
|
|
689
|
+
interface CreateStackOptions extends Omit<CreateHttpHandlerOptions, "service" | "host">, Omit<CreateHostDbOptions, "db" | "tableName" | "onPaid" | "payments"> {
|
|
690
|
+
readonly wallet: StackWallet;
|
|
691
|
+
readonly storage: StackStorage;
|
|
692
|
+
/**
|
|
693
|
+
* Where the one boot-failure line goes. Boot happens before any service
|
|
694
|
+
* exists, so this is the only sink @openreceive/http can offer; it defaults
|
|
695
|
+
* to `console.error`. The message only ever carries `error.message` — a
|
|
696
|
+
* boot-time wallet error object carries a raw cause that has passed through
|
|
697
|
+
* none of the redaction the service wires for every other line.
|
|
698
|
+
*/
|
|
699
|
+
readonly onBootFailure?: (message: string) => void;
|
|
700
|
+
}
|
|
701
|
+
interface Stack {
|
|
702
|
+
/**
|
|
703
|
+
* Handler that boots lazily: the first request (and `ready`) awaits service
|
|
704
|
+
* construction. Boot failures surface on `ready` and on every request.
|
|
705
|
+
*/
|
|
706
|
+
readonly handler: HttpHandler;
|
|
707
|
+
/** Resolves when the service and handler are up. */
|
|
708
|
+
readonly ready: Promise<void>;
|
|
709
|
+
/** Closes the service if the stack created it. */
|
|
710
|
+
close(): Promise<void>;
|
|
711
|
+
}
|
|
712
|
+
declare function createStack(options: CreateStackOptions): Stack;
|
|
713
|
+
/**
|
|
714
|
+
* True when adapter options are the flat all-in-one form (no prebuilt `host`).
|
|
715
|
+
* The composed form always carries `host`; the flat form carries the host
|
|
716
|
+
* hooks directly. Composed options that merely forgot `host` (e.g.
|
|
717
|
+
* `{ service, authorize }`) throw the missing-host error instead of entering
|
|
718
|
+
* the all-in-one path and blaming the caller for omitting nwc/db/onPaid.
|
|
719
|
+
*/
|
|
720
|
+
declare function isStackOptions(options: CreateHttpHandlerOptions | CreateStackOptions): options is CreateStackOptions;
|
|
721
|
+
|
|
722
|
+
export { hostError as $, type AttemptStatus as A, type SettlementEventHook as B, type CheckoutCreatedHook as C, type SettlementRecord as D, type SqlClient as E, type SqlDatabase as F, type SqlPaymentRepository as G, type Host as H, type IpRateLimitConfig as I, type SqlPaymentsOptions as J, type SqlQuery as K, type Stack as L, type StackStorage as M, type NotificationListener as N, OPENRECEIVE_ATTEMPT_EXPIRY_GRACE_SECONDS as O, type PaymentInsert as P, type StackWallet as Q, type ReconcilableAttempt as R, type SqlAdapter as S, createHost as T, createHttpHandler as U, createIpRateLimit as V, createProxyRateLimitingConfig as W, createRequestId as X, createSqlPayments as Y, createStack as Z, errorResponse as _, type Authorize as a, isServiceErrorShape as a0, isStackOptions as a1, jsonResponse as a2, mapHostRouteError as a3, paymentsSchemaSql as a4, resolveClientIp as a5, startNotificationListener as a6, startNotificationWorker as a7, type AuthorizeAction as b, type AuthorizeContext as c, type AuthorizeResource as d, type CheckoutCreatedInput as e, type CreateHostDbOptions as f, type CreateHostOptions as g, type CreateHostRepositoryOptions as h, type CreateHttpHandlerOptions as i, type CreateStackOptions as j, HostError as k, HttpError as l, type HttpHandler as m, type NotificationWorker as n, OPENRECEIVE_RECONCILE_BATCH_SIZE as o, type PaymentRecord as p, type PaymentRepository as q, type PaymentSettlement as r, type PaymentSettlementHook as s, type RateLimit as t, type ReconciliationTransition as u, type ResolveCheckoutContext as v, type ResolveCheckoutHook as w, type ResolvedHostCheckout as x, type ServiceErrorShape as y, type SettlementEvent as z };
|