@voltro/plugin-billing 0.85.0 → 0.87.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +5987 -0
- package/README.md +435 -0
- package/THIRD-PARTY-NOTICES.md +864 -253
- package/dist/catalog.js +471 -0
- package/dist/checkoutStore.js +165 -0
- package/dist/closeStore.js +125 -0
- package/dist/custodyInventory.js +155 -0
- package/dist/customerStore.js +259 -0
- package/dist/dunning.js +209 -0
- package/dist/economy.d.ts +30 -0
- package/dist/economy.js +266 -0
- package/dist/entitlement.js +41 -0
- package/dist/eventDelivery.js +72 -0
- package/dist/flushClaim.js +20 -0
- package/dist/index.d.ts +669 -65
- package/dist/index.js +243 -2803
- package/dist/invoiceHistory.js +91 -0
- package/dist/invoiceHistoryJournal.js +476 -0
- package/dist/invoiceHistoryProgress.js +235 -0
- package/dist/invoiceHistoryWork.js +363 -0
- package/dist/invoiceSnapshot.js +66 -0
- package/dist/invoiceStore.js +133 -0
- package/dist/metering.js +74 -0
- package/dist/plans.js +24 -0
- package/dist/providerIdentity.js +24 -0
- package/dist/providers.js +338 -0
- package/dist/provision.js +153 -0
- package/dist/service.js +1116 -0
- package/dist/stores.js +260 -0
- package/dist/stripeClient.js +53 -0
- package/dist/stripeIdentity.js +56 -0
- package/dist/stripeInvoiceHistory.js +67 -0
- package/dist/stripeInvoiceSnapshot.js +86 -0
- package/dist/stripeProvider.js +479 -0
- package/dist/stripeRest.js +52 -0
- package/dist/stripeVerifiedEvent.js +29 -0
- package/dist/table.js +77 -0
- package/dist/types.d.ts +298 -27
- package/dist/usageEvents.js +65 -0
- package/dist/webhook.js +38 -0
- package/package.json +17 -7
package/dist/index.d.ts
CHANGED
|
@@ -3,6 +3,8 @@ import { Context } from 'effect';
|
|
|
3
3
|
import { DataStore } from '@voltro/database';
|
|
4
4
|
import { default as default_2 } from 'stripe';
|
|
5
5
|
import { Effect } from 'effect';
|
|
6
|
+
import { IdempotencyClaim } from '@voltro/protocol';
|
|
7
|
+
import { IdempotencyStore } from '@voltro/protocol';
|
|
6
8
|
import { IncomingRequest } from '@voltro/plugin-webhooks';
|
|
7
9
|
import { IncomingResponse } from '@voltro/plugin-webhooks';
|
|
8
10
|
import { IncomingWebhookDescriptor } from '@voltro/plugin-webhooks';
|
|
@@ -26,16 +28,45 @@ export declare const assertBillingProductionReady: (input: {
|
|
|
26
28
|
readonly redirectOrigins: ReadonlyArray<string> | undefined;
|
|
27
29
|
}) => void;
|
|
28
30
|
|
|
31
|
+
export declare const BILLING_CHECKOUT_OPERATIONS_TABLE = "_voltro_billing_checkout_operations";
|
|
32
|
+
|
|
33
|
+
export declare const BILLING_CLOSE_OPERATIONS_TABLE = "_voltro_billing_close_operations";
|
|
34
|
+
|
|
35
|
+
/** Tenant-addressable native inputs, including retained tables. Global delivery
|
|
36
|
+
* receipts, provider history and the application's own records need separate
|
|
37
|
+
* inventory; this roster does not assert their absence or financial completion. */
|
|
38
|
+
export declare const BILLING_CUSTODY_INVENTORY_TABLES: ReadonlyArray<string>;
|
|
39
|
+
|
|
40
|
+
export declare const BILLING_CUSTOMER_ACCOUNTS_TABLE = "_voltro_billing_customer_accounts";
|
|
41
|
+
|
|
42
|
+
export declare const BILLING_CUSTOMER_CUSTODY_TABLE = "_voltro_billing_customer_custody";
|
|
43
|
+
|
|
29
44
|
export declare const BILLING_CUSTOMERS_TABLE = "_voltro_billing_customers";
|
|
30
45
|
|
|
31
46
|
export declare const BILLING_DUNNING_NOTICES_TABLE = "_voltro_billing_dunning_notices";
|
|
32
47
|
|
|
33
48
|
export declare const BILLING_FLUSH_CLAIMS_TABLE = "_voltro_billing_flush_claims";
|
|
34
49
|
|
|
50
|
+
export declare const BILLING_INVOICE_HISTORY_DISPATCH_TABLE = "_voltro_billing_invoice_history_dispatch";
|
|
51
|
+
|
|
52
|
+
export declare const BILLING_INVOICE_HISTORY_PAGES_TABLE = "_voltro_billing_invoice_history_pages";
|
|
53
|
+
|
|
54
|
+
export declare const BILLING_INVOICE_HISTORY_REFERENCES_TABLE = "_voltro_billing_invoice_history_references";
|
|
55
|
+
|
|
56
|
+
export declare const BILLING_INVOICE_HISTORY_SCAN_ACCOUNTS_TABLE = "_voltro_billing_invoice_history_scan_accounts";
|
|
57
|
+
|
|
58
|
+
export declare const BILLING_INVOICE_HISTORY_WALKS_TABLE = "_voltro_billing_invoice_history_walks";
|
|
59
|
+
|
|
60
|
+
export declare const BILLING_INVOICE_HISTORY_WORK_TABLE = "_voltro_billing_invoice_history_work";
|
|
61
|
+
|
|
62
|
+
export declare const BILLING_INVOICE_OBSERVATIONS_TABLE = "_voltro_billing_account_invoices";
|
|
63
|
+
|
|
35
64
|
export declare const BILLING_INVOICES_TABLE = "_voltro_billing_invoices";
|
|
36
65
|
|
|
37
66
|
export declare const BILLING_SUBSCRIPTIONS_TABLE = "_voltro_billing_subscriptions";
|
|
38
67
|
|
|
68
|
+
export declare const BILLING_USAGE_EVENTS_TABLE = "_voltro_billing_usage_events";
|
|
69
|
+
|
|
39
70
|
export declare const BILLING_USAGE_TABLE = "_voltro_billing_usage";
|
|
40
71
|
|
|
41
72
|
/** The webhook id + the path the doc + plugin mount at. */
|
|
@@ -51,6 +82,35 @@ export declare const BILLING_WEBHOOK_PATH = "/billing/webhook";
|
|
|
51
82
|
*/
|
|
52
83
|
export declare type BillingAction = 'checkout' | 'change' | 'resume' | 'portal' | 'cancel';
|
|
53
84
|
|
|
85
|
+
export declare const billingCheckoutOperationsTable: BillingTable;
|
|
86
|
+
|
|
87
|
+
export declare interface BillingCloseOperation {
|
|
88
|
+
readonly id: string;
|
|
89
|
+
readonly tenantId: string;
|
|
90
|
+
readonly provider: string;
|
|
91
|
+
readonly scope: string;
|
|
92
|
+
readonly providerSubscriptionId: string | null;
|
|
93
|
+
readonly cancelAt: Date | null;
|
|
94
|
+
readonly createdAt: Date;
|
|
95
|
+
readonly usageSealed: number;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export declare const billingCloseOperationsTable: BillingTable;
|
|
99
|
+
|
|
100
|
+
export declare interface BillingCloseStore {
|
|
101
|
+
readonly sealUsage: (tenantId: string) => Effect.Effect<BillingCloseOperation, BillingError>;
|
|
102
|
+
readonly getAccount: (tenantId: string) => Effect.Effect<BillingCloseOperation | null, BillingError>;
|
|
103
|
+
readonly reserveAccount: (tenantId: string, provider: string, createdAt: Date) => Effect.Effect<BillingCloseOperation, BillingError>;
|
|
104
|
+
readonly getSubscription: (tenantId: string, providerSubscriptionId: string) => Effect.Effect<BillingCloseOperation | null, BillingError>;
|
|
105
|
+
readonly reserveSubscription: (input: {
|
|
106
|
+
readonly tenantId: string;
|
|
107
|
+
readonly provider: string;
|
|
108
|
+
readonly providerSubscriptionId: string;
|
|
109
|
+
readonly cancelAt: Date;
|
|
110
|
+
readonly createdAt: Date;
|
|
111
|
+
}) => Effect.Effect<BillingCloseOperation, BillingError>;
|
|
112
|
+
}
|
|
113
|
+
|
|
54
114
|
/**
|
|
55
115
|
* The shape every handler executor receives carries the resolved subject
|
|
56
116
|
* under `ctx.request.subject` (mirrors `@voltro/plugin-rbac`'s
|
|
@@ -62,9 +122,55 @@ export declare interface BillingContext {
|
|
|
62
122
|
};
|
|
63
123
|
}
|
|
64
124
|
|
|
125
|
+
export declare interface BillingCustodyInventory {
|
|
126
|
+
readonly format: 'voltro.billing-custody-inventory.v1';
|
|
127
|
+
readonly tenantId: string;
|
|
128
|
+
readonly digest: string;
|
|
129
|
+
readonly tables: ReadonlyArray<BillingCustodyInventoryTable>;
|
|
130
|
+
/** Diagnostic local time, excluded from the content digest. */
|
|
131
|
+
readonly observedAt: Date;
|
|
132
|
+
/** Two equal native read sweeps are observations, not a writer-stop proof,
|
|
133
|
+
* an atomic provider snapshot, an approval or original account authority. */
|
|
134
|
+
readonly purpose: 'review-only';
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export declare interface BillingCustodyInventoryOptions {
|
|
138
|
+
readonly tenantId: string;
|
|
139
|
+
/** Defaults to 200; bounded to 1..500. */
|
|
140
|
+
readonly pageSize?: number;
|
|
141
|
+
/** Defaults to 5,000; bounded to 1..50,000 per table. Exceeding this limit
|
|
142
|
+
* fails the whole inventory rather than returning a truncated manifest. */
|
|
143
|
+
readonly maxRowsPerTable?: number;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export declare interface BillingCustodyInventoryRow {
|
|
147
|
+
readonly id: string;
|
|
148
|
+
/** Hash of every returned native field, not just the displayed references. */
|
|
149
|
+
readonly digest: string;
|
|
150
|
+
/** Existing native identifiers only; never a proposed customer/tenant mapping. */
|
|
151
|
+
readonly references: Readonly<Record<string, string>>;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
export declare interface BillingCustodyInventoryTable {
|
|
155
|
+
readonly tableName: string;
|
|
156
|
+
readonly rowCount: number;
|
|
157
|
+
readonly digest: string;
|
|
158
|
+
readonly rows: ReadonlyArray<BillingCustodyInventoryRow>;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
export declare const billingCustomerAccountsTable: BillingTable;
|
|
162
|
+
|
|
163
|
+
export declare const billingCustomerCustodyTable: BillingTable;
|
|
164
|
+
|
|
65
165
|
/** tenant ↔ provider customer link. */
|
|
66
166
|
export declare const billingCustomersTable: BillingTable;
|
|
67
167
|
|
|
168
|
+
/** Optional native receipt binding for standalone webhook mounts. */
|
|
169
|
+
export declare interface BillingDeliveryReceipts {
|
|
170
|
+
readonly scope: string;
|
|
171
|
+
readonly store: () => IdempotencyStore;
|
|
172
|
+
}
|
|
173
|
+
|
|
68
174
|
/**
|
|
69
175
|
* The sent-notice ledger. One row per `(tenant, episode, step)` — and the
|
|
70
176
|
* UNIQUE over exactly those three is the send gate, not a report: a notice is
|
|
@@ -103,7 +209,7 @@ declare const BillingError_base: Schema.Class<BillingError, Schema.TaggedStruct<
|
|
|
103
209
|
}>, YieldableError>;
|
|
104
210
|
|
|
105
211
|
/**
|
|
106
|
-
* The
|
|
212
|
+
* The tenant-resolved event union dispatched after `BillingService.applyEvent` accepts an event
|
|
107
213
|
* from a verified, decoded provider webhook payload. `BillingService`
|
|
108
214
|
* applies these to the DB rows — switching provider swaps the adapter;
|
|
109
215
|
* the service + rows + entitlement engine are unchanged.
|
|
@@ -156,15 +262,51 @@ export declare type BillingEvent = {
|
|
|
156
262
|
readonly occurredAt: Date | null;
|
|
157
263
|
};
|
|
158
264
|
|
|
265
|
+
/** Per-event side effect, run AFTER the row is updated. */
|
|
266
|
+
export declare interface BillingEventDeliveryContext extends ProviderAccountIdentity {
|
|
267
|
+
readonly provider: string;
|
|
268
|
+
readonly providerEventId: string;
|
|
269
|
+
readonly receiptScope: string;
|
|
270
|
+
}
|
|
271
|
+
|
|
159
272
|
/** The event tag union — handy for `onEvent` keys. */
|
|
160
273
|
export declare type BillingEventTag = BillingEvent['_tag'];
|
|
161
274
|
|
|
162
275
|
/** One row per flush window — `windowKey` UNIQUE makes the INSERT the gate. */
|
|
163
276
|
export declare const billingFlushClaimsTable: TableLike;
|
|
164
277
|
|
|
165
|
-
|
|
278
|
+
export declare const billingInvoiceHistoryDispatchTable: BillingTable;
|
|
279
|
+
|
|
280
|
+
export declare const billingInvoiceHistoryPagesTable: BillingTable;
|
|
281
|
+
|
|
282
|
+
export declare const billingInvoiceHistoryReferencesTable: BillingTable;
|
|
283
|
+
|
|
284
|
+
export declare const billingInvoiceHistoryScanAccountsTable: BillingTable;
|
|
285
|
+
|
|
286
|
+
export declare const billingInvoiceHistoryWalksTable: BillingTable;
|
|
287
|
+
|
|
288
|
+
export declare const billingInvoiceHistoryWorkTable: BillingTable;
|
|
289
|
+
|
|
290
|
+
export declare const billingInvoiceObservationsTable: BillingTable;
|
|
291
|
+
|
|
292
|
+
/** Retained invoice-event history; current writes use billingInvoiceObservationsTable. */
|
|
166
293
|
export declare const billingInvoicesTable: BillingTable;
|
|
167
294
|
|
|
295
|
+
export declare type BillingInvoiceTrigger = BillingInvoiceTriggerFields & ({
|
|
296
|
+
readonly _tag: 'invoicePaid';
|
|
297
|
+
} | {
|
|
298
|
+
readonly _tag: 'invoicePaymentFailed';
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
/** Verified provider invoice trigger. Tenant metadata is never ownership evidence. */
|
|
302
|
+
declare interface BillingInvoiceTriggerFields {
|
|
303
|
+
readonly providerCustomerId: string;
|
|
304
|
+
readonly providerInvoiceId: string;
|
|
305
|
+
readonly amountMinor: number;
|
|
306
|
+
readonly currency: string;
|
|
307
|
+
readonly occurredAt: Date | null;
|
|
308
|
+
}
|
|
309
|
+
|
|
168
310
|
export declare const billingPlugin: (options?: BillingPluginOptions) => VoltroPlugin;
|
|
169
311
|
|
|
170
312
|
export declare interface BillingPluginOptions {
|
|
@@ -275,17 +417,14 @@ export declare interface BillingPluginOptions {
|
|
|
275
417
|
readonly name?: string;
|
|
276
418
|
}
|
|
277
419
|
|
|
278
|
-
/**
|
|
279
|
-
* Dumb adapter over a billing provider. Holds NO policy — checkout/portal
|
|
280
|
-
* URL minting, usage push, and pure payload→event mapping only. The
|
|
281
|
-
* `BillingService` wraps it with the entitlement engine, the DB rows, and
|
|
282
|
-
* transient retry.
|
|
283
|
-
*
|
|
284
|
-
* `normalizeEvent` receives a payload whose signature was ALREADY verified
|
|
285
|
-
* by @voltro/plugin-webhooks' mounter — this is pure mapping, never a
|
|
286
|
-
* second signature check.
|
|
287
|
-
*/
|
|
288
420
|
export declare interface BillingProvider {
|
|
421
|
+
/** Required by account-qualified custody consumers; absence is unsupported, not fallback authority. */
|
|
422
|
+
readonly fetchAccountIdentity?: () => Effect.Effect<ProviderAccountIdentity, BillingError>;
|
|
423
|
+
/** Must reject a different account/mode before reading customer data. A 404 is not positive deletion evidence. */
|
|
424
|
+
readonly fetchCustomerSnapshot?: (input: {
|
|
425
|
+
readonly account: ProviderAccountIdentity;
|
|
426
|
+
readonly providerCustomerId: string;
|
|
427
|
+
}) => Effect.Effect<ProviderCustomerSnapshot, BillingError>;
|
|
289
428
|
readonly name: string;
|
|
290
429
|
/** Whether the provider supports server-pushed metered usage. Stripe
|
|
291
430
|
* does (subscription-item usage records); a flat-plan provider may not.
|
|
@@ -296,9 +435,13 @@ export declare interface BillingProvider {
|
|
|
296
435
|
* meters map events to a customer by id, so an unlinked tenant's usage
|
|
297
436
|
* stays pending instead of being sent unattributable. */
|
|
298
437
|
readonly usageRequiresCustomer?: boolean;
|
|
299
|
-
readonly createCheckoutSession: (input: CheckoutInput) => Effect.Effect<
|
|
300
|
-
|
|
301
|
-
|
|
438
|
+
readonly createCheckoutSession: (input: CheckoutInput) => Effect.Effect<CheckoutSessionReceipt, BillingError>;
|
|
439
|
+
/** Read positive evidence for one exact persisted checkout intent. */
|
|
440
|
+
readonly findCheckoutSession: (input: {
|
|
441
|
+
readonly tenantId: string;
|
|
442
|
+
readonly providerCustomerId?: string;
|
|
443
|
+
readonly operationId: string;
|
|
444
|
+
}) => Effect.Effect<CheckoutSessionLookup, BillingError>;
|
|
302
445
|
readonly createPortalSession: (input: PortalInput) => Effect.Effect<{
|
|
303
446
|
url: string;
|
|
304
447
|
}, BillingError>;
|
|
@@ -330,6 +473,10 @@ export declare interface BillingProvider {
|
|
|
330
473
|
* matters — the subscription's status right now does. Returns null when the
|
|
331
474
|
* provider does not know the id.
|
|
332
475
|
*/
|
|
476
|
+
/** Direct customer-qualified observation, including terminal subscriptions.
|
|
477
|
+
* Null is absence, never proof of cancellation. Required for retired-customer
|
|
478
|
+
* reconciliation and for subscriptions absent from the live listing. */
|
|
479
|
+
readonly fetchSubscriptionSnapshot?: (providerSubscriptionId: string) => Effect.Effect<ProviderSubscriptionSnapshot | null, BillingError>;
|
|
333
480
|
readonly fetchSubscription: (providerSubscriptionId: string) => Effect.Effect<ProviderSubscriptionState | null, BillingError>;
|
|
334
481
|
/**
|
|
335
482
|
* Every live (not yet ended) subscription at the provider, optionally for
|
|
@@ -339,12 +486,19 @@ export declare interface BillingProvider {
|
|
|
339
486
|
readonly listSubscriptions: (input: {
|
|
340
487
|
readonly providerCustomerId?: string;
|
|
341
488
|
}) => Effect.Effect<ReadonlyArray<ProviderSubscriptionSnapshot>, BillingError>;
|
|
342
|
-
/**
|
|
343
|
-
*
|
|
489
|
+
/** Quote the provider-clock settlement deadline after final usage dispatch.
|
|
490
|
+
* Persist it before requesting account-close cancellation. */
|
|
491
|
+
readonly prepareSubscriptionClose: (providerSubscriptionId: string) => Effect.Effect<{
|
|
492
|
+
readonly cancelAt: Date;
|
|
493
|
+
}, BillingError>;
|
|
344
494
|
readonly cancelSubscription: (input: {
|
|
345
495
|
readonly providerSubscriptionId: string;
|
|
346
|
-
|
|
347
|
-
|
|
496
|
+
} & ({
|
|
497
|
+
readonly mode: 'periodEnd';
|
|
498
|
+
} | {
|
|
499
|
+
readonly mode: 'close';
|
|
500
|
+
readonly closeOperation: SubscriptionCloseOperation;
|
|
501
|
+
})) => Effect.Effect<ProviderSubscriptionState, BillingError>;
|
|
348
502
|
/** Undo a period-end cancellation that has not taken effect yet. */
|
|
349
503
|
readonly resumeSubscription: (providerSubscriptionId: string) => Effect.Effect<ProviderSubscriptionState, BillingError>;
|
|
350
504
|
/**
|
|
@@ -361,6 +515,7 @@ export declare interface BillingProvider {
|
|
|
361
515
|
* can be paid. Returns how many were expired. */
|
|
362
516
|
readonly expireOpenCheckouts: (input: {
|
|
363
517
|
readonly providerCustomerId: string;
|
|
518
|
+
readonly exceptOperationId?: string;
|
|
364
519
|
}) => Effect.Effect<number, BillingError>;
|
|
365
520
|
/** Add prices the subscription is missing (metered items), without
|
|
366
521
|
* proration. Prices already present are left alone. */
|
|
@@ -374,12 +529,22 @@ export declare interface BillingProvider {
|
|
|
374
529
|
* the app keeps its own. Optional: a provider may model no customer email.
|
|
375
530
|
*/
|
|
376
531
|
readonly customerEmail?: (providerCustomerId: string) => Effect.Effect<string | null, BillingError>;
|
|
377
|
-
/**
|
|
378
|
-
*
|
|
532
|
+
/** Bounded recent invoice preview, not complete history. Provider-hosted
|
|
533
|
+
* links remain theirs; use listInvoiceHistory for explicit cursor traversal. */
|
|
379
534
|
readonly listInvoices: (input: {
|
|
380
535
|
readonly providerCustomerId: string;
|
|
381
536
|
readonly limit?: number;
|
|
382
537
|
}) => Effect.Effect<ReadonlyArray<InvoiceRecord>, BillingError>;
|
|
538
|
+
/** Explicit bounded history pages, including draft and terminal statuses.
|
|
539
|
+
* Cursor exhaustion describes this traversal, not a stable global snapshot.
|
|
540
|
+
* Unsupported adapters must fail; the latest-preview list is no fallback. */
|
|
541
|
+
readonly listInvoiceHistory?: (input: ProviderInvoiceHistoryInput) => Effect.Effect<ProviderInvoiceHistoryPage, BillingError>;
|
|
542
|
+
/** Read one finalized invoice with every line, after confirming its customer.
|
|
543
|
+
* Absence means this provider cannot supply detailed invoice evidence. */
|
|
544
|
+
readonly fetchInvoiceSnapshot?: (input: {
|
|
545
|
+
readonly providerCustomerId: string;
|
|
546
|
+
readonly providerInvoiceId: string;
|
|
547
|
+
}) => Effect.Effect<ProviderInvoiceSnapshot, BillingError>;
|
|
383
548
|
/**
|
|
384
549
|
* Verify a webhook signature and decode the payload, using the provider's
|
|
385
550
|
* OWN verification. Returns `null` when this provider does not do its own
|
|
@@ -390,10 +555,10 @@ export declare interface BillingProvider {
|
|
|
390
555
|
readonly signatureHeader: string;
|
|
391
556
|
readonly secret: string;
|
|
392
557
|
}) => Effect.Effect<unknown, BillingError>;
|
|
393
|
-
/** Map a verified, decoded webhook payload to a `
|
|
558
|
+
/** Map a verified, decoded webhook payload to a `BillingProviderEvent`, or
|
|
394
559
|
* `null` for an event type this provider doesn't model (handler
|
|
395
560
|
* no-ops, still 200). */
|
|
396
|
-
readonly normalizeEvent: (raw: unknown) => Effect.Effect<
|
|
561
|
+
readonly normalizeEvent: (raw: unknown) => Effect.Effect<BillingProviderEvent | null, BillingError>;
|
|
397
562
|
/**
|
|
398
563
|
* Who and when a verified payload is about: the provider customer it names
|
|
399
564
|
* and when the provider created it. The webhook syncs that customer from a
|
|
@@ -410,11 +575,22 @@ export declare interface BillingProvider {
|
|
|
410
575
|
* it keeps them (Stripe: 30 days) — what an outage of the endpoint left
|
|
411
576
|
* behind. Optional: a provider without it has no catch-up.
|
|
412
577
|
*/
|
|
413
|
-
readonly listUndeliveredEvents?: (
|
|
578
|
+
readonly listUndeliveredEvents?: (input: {
|
|
579
|
+
readonly cursor: string | null;
|
|
580
|
+
readonly limit: number;
|
|
581
|
+
}) => Effect.Effect<UndeliveredEventPage, BillingError>;
|
|
414
582
|
}
|
|
415
583
|
|
|
584
|
+
/** Invoice ownership is resolved from native customer links before dispatch. */
|
|
585
|
+
export declare type BillingProviderEvent = Exclude<BillingEvent, {
|
|
586
|
+
readonly _tag: 'invoicePaid' | 'invoicePaymentFailed';
|
|
587
|
+
}> | BillingInvoiceTrigger;
|
|
588
|
+
|
|
416
589
|
export declare type BillingProviderName = 'stripe' | 'mock';
|
|
417
590
|
|
|
591
|
+
/** Retained unqualified observations are not adopted by the current writer. */
|
|
592
|
+
export declare const billingRetainedInvoiceObservationsTable: BillingTable;
|
|
593
|
+
|
|
418
594
|
/** The billing service Tag — `const billing = yield* BillingService`. */
|
|
419
595
|
export declare class BillingService extends BillingService_base {
|
|
420
596
|
}
|
|
@@ -521,6 +697,8 @@ export declare interface BillingServiceShape {
|
|
|
521
697
|
readonly consumeEntitlement: (tenantId: string, key: string, cost: number) => Effect.Effect<void, BillingError | EntitlementExceeded>;
|
|
522
698
|
/** Record metered usage locally; flushed to the provider in batches. */
|
|
523
699
|
readonly reportUsage: (tenantId: string, key: string, qty: number) => Effect.Effect<void, BillingError>;
|
|
700
|
+
/** Atomically retain an occurrence receipt and increment its original UTC month. */
|
|
701
|
+
readonly reportUsageEvent: (event: MeteredUsageEvent) => Effect.Effect<void, BillingError>;
|
|
524
702
|
/** Flush all pending local usage counters to the provider. */
|
|
525
703
|
readonly flushUsage: () => Effect.Effect<void, BillingError>;
|
|
526
704
|
/** What a plan/seat change WOULD cost, from the provider's own invoice
|
|
@@ -530,8 +708,27 @@ export declare interface BillingServiceShape {
|
|
|
530
708
|
readonly plan?: PlanId;
|
|
531
709
|
readonly quantity?: number;
|
|
532
710
|
}) => Effect.Effect<SubscriptionChange, BillingError>;
|
|
533
|
-
/**
|
|
711
|
+
/** Bounded recent provider invoice preview for this tenant, not history coverage. */
|
|
534
712
|
readonly invoices: (tenantId: string) => Effect.Effect<ReadonlyArray<InvoiceRecord>, BillingError>;
|
|
713
|
+
/** Read history for an exact current or retained customer owned by the tenant.
|
|
714
|
+
* Does not create custody or persist observations. The caller authorizes access. */
|
|
715
|
+
readonly invoiceHistory: (tenantId: string, providerCustomerId: string, options?: {
|
|
716
|
+
readonly cursor?: ProviderInvoiceHistoryCursor;
|
|
717
|
+
readonly limit?: number;
|
|
718
|
+
}) => Effect.Effect<ProviderInvoiceHistoryPage, BillingError>;
|
|
719
|
+
/** Fresh detailed provider evidence for this tenant's current linked customer.
|
|
720
|
+
* This read neither grants entitlements nor replaces native reconciliation. */
|
|
721
|
+
readonly invoiceSnapshot: (tenantId: string, providerInvoiceId: string) => Effect.Effect<ProviderInvoiceSnapshot, BillingError>;
|
|
722
|
+
/** Persist and read back a complete owned observation. A lost revision race
|
|
723
|
+
* repeats the provider read; event payloads never replace provider evidence. */
|
|
724
|
+
readonly reconcileInvoice: (tenantId: string, providerInvoiceId: string, expectedCustomerId?: string) => Effect.Effect<InvoiceObservation, BillingError>;
|
|
725
|
+
/** One bounded durable account/customer pass. Counts are work observations,
|
|
726
|
+
* not global, payment or historical financial completion. */
|
|
727
|
+
readonly reconcileInvoiceHistory: () => Effect.Effect<InvoiceHistoryPassResult, BillingError>;
|
|
728
|
+
/** Process one retained owned history reference with fresh provider/native
|
|
729
|
+
* reads and a fenced durable result. Open/draft/error work stays pending;
|
|
730
|
+
* an observed result is not settlement or historical entitlement coverage. */
|
|
731
|
+
readonly processInvoiceHistoryReference: (tenantId: string, providerCustomerId: string, referenceId: string) => Effect.Effect<InvoiceHistoryReferenceResult, BillingError>;
|
|
535
732
|
/** Mint a provider-hosted checkout URL for `plan`. */
|
|
536
733
|
readonly startCheckout: (input: {
|
|
537
734
|
readonly tenantId: string;
|
|
@@ -540,6 +737,9 @@ export declare interface BillingServiceShape {
|
|
|
540
737
|
readonly cancelUrl: string;
|
|
541
738
|
/** Seats to buy up front. Omit for 1. */
|
|
542
739
|
readonly quantity?: number;
|
|
740
|
+
/** Server-call authority check repeated after waits, before provider work.
|
|
741
|
+
* Native RPC routes supply their current declared-guard check. */
|
|
742
|
+
readonly authorize?: () => Effect.Effect<void, BillingError>;
|
|
543
743
|
}) => Effect.Effect<{
|
|
544
744
|
url: string;
|
|
545
745
|
}, BillingError>;
|
|
@@ -589,8 +789,8 @@ export declare interface BillingServiceShape {
|
|
|
589
789
|
* load. Every call that changes what a tenant pays already runs it first.
|
|
590
790
|
*/
|
|
591
791
|
readonly syncTenant: (tenantId: string) => Effect.Effect<Subscription | null, BillingError>;
|
|
592
|
-
/** Apply a
|
|
593
|
-
readonly applyEvent: (event:
|
|
792
|
+
/** Apply a verified provider trigger and return its native tenant-resolved event. */
|
|
793
|
+
readonly applyEvent: (event: BillingProviderEvent) => Effect.Effect<BillingEvent, BillingError>;
|
|
594
794
|
/**
|
|
595
795
|
* Change the tenant's plan mid-cycle. Computes a TIME-BASED prorated
|
|
596
796
|
* settlement on the amount difference for the unused remainder of the
|
|
@@ -610,9 +810,14 @@ export declare interface BillingServiceShape {
|
|
|
610
810
|
}
|
|
611
811
|
|
|
612
812
|
export declare interface BillingStores {
|
|
813
|
+
readonly closures: BillingCloseStore;
|
|
814
|
+
readonly checkouts: CheckoutOperationStore;
|
|
613
815
|
readonly customers: CustomerStore;
|
|
614
816
|
readonly subscriptions: SubscriptionStore;
|
|
615
817
|
readonly invoices: InvoiceStore;
|
|
818
|
+
readonly historyJournal: InvoiceHistoryJournal;
|
|
819
|
+
readonly historyWork: InvoiceHistoryWorkStore;
|
|
820
|
+
readonly historyProgress: InvoiceHistoryProgressStore;
|
|
616
821
|
readonly usage: UsageStore;
|
|
617
822
|
/** The dunning sent-notice ledger — the send gate, not a report. */
|
|
618
823
|
readonly dunningNotices: DunningNoticeStore;
|
|
@@ -634,6 +839,8 @@ export declare interface BillingTable extends TableLike {
|
|
|
634
839
|
|
|
635
840
|
export declare const billingTables: () => ReadonlyArray<BillingTable>;
|
|
636
841
|
|
|
842
|
+
export declare const billingUsageEventsTable: BillingTable;
|
|
843
|
+
|
|
637
844
|
/** Per-tenant metered counters driving the entitlement engine. */
|
|
638
845
|
export declare const billingUsageTable: BillingTable;
|
|
639
846
|
|
|
@@ -648,6 +855,8 @@ declare interface BillingWebhookOptions {
|
|
|
648
855
|
readonly provider: BillingProvider;
|
|
649
856
|
readonly service: BillingServiceShape;
|
|
650
857
|
readonly onEvent?: OnEventMap;
|
|
858
|
+
/** Shared native receipt binding; standalone mounts otherwise retain process memory only. */
|
|
859
|
+
readonly receipts?: BillingDeliveryReceipts;
|
|
651
860
|
/** The signing secret. It is BOTH the secret the mount's generic HMAC check
|
|
652
861
|
* verifies with AND the one the provider's own verifier (Stripe's
|
|
653
862
|
* `constructEvent`) uses. Null → the mount answers 503: an unverifiable
|
|
@@ -717,6 +926,12 @@ export declare type CatalogFinding = {
|
|
|
717
926
|
|
|
718
927
|
export declare interface CheckoutInput {
|
|
719
928
|
readonly tenantId: string;
|
|
929
|
+
/** Identity of one logical checkout request. Providers that support request
|
|
930
|
+
* idempotency must forward it unchanged across transport retries. The
|
|
931
|
+
* caller owns persistence and must not reuse it for different parameters. */
|
|
932
|
+
readonly idempotencyKey?: string;
|
|
933
|
+
/** Fixed deadline of a persisted intent; providers enforce it on creation. */
|
|
934
|
+
readonly expiresAt?: Date;
|
|
720
935
|
/** Provider price id to subscribe to. */
|
|
721
936
|
readonly priceId: string;
|
|
722
937
|
/** Usage-based prices added next to `priceId` (no quantity). */
|
|
@@ -737,6 +952,65 @@ export declare interface CheckoutInput {
|
|
|
737
952
|
readonly trialDays?: number;
|
|
738
953
|
}
|
|
739
954
|
|
|
955
|
+
export declare interface CheckoutOperation {
|
|
956
|
+
readonly id: string;
|
|
957
|
+
readonly tenantId: string;
|
|
958
|
+
readonly provider: string;
|
|
959
|
+
readonly requestDigest: string;
|
|
960
|
+
readonly plan: string;
|
|
961
|
+
readonly quantity: number;
|
|
962
|
+
readonly providerCustomerId: string | null;
|
|
963
|
+
readonly providerSessionId: string | null;
|
|
964
|
+
readonly phase: CheckoutPhase;
|
|
965
|
+
readonly revision: number;
|
|
966
|
+
readonly active: number | null;
|
|
967
|
+
readonly slot: string;
|
|
968
|
+
readonly createdAt: Date;
|
|
969
|
+
readonly expiresAt: Date;
|
|
970
|
+
readonly updatedAt: Date;
|
|
971
|
+
}
|
|
972
|
+
|
|
973
|
+
export declare interface CheckoutOperationStore {
|
|
974
|
+
readonly reserve: (input: CheckoutReservation) => Effect.Effect<CheckoutOperation, BillingError>;
|
|
975
|
+
readonly getActive: (tenantId: string) => Effect.Effect<CheckoutOperation | null, BillingError>;
|
|
976
|
+
readonly patch: (operationId: string, patch: {
|
|
977
|
+
readonly phase?: CheckoutPhase;
|
|
978
|
+
readonly providerCustomerId?: string;
|
|
979
|
+
readonly providerSessionId?: string;
|
|
980
|
+
}) => Effect.Effect<CheckoutOperation, BillingError>;
|
|
981
|
+
}
|
|
982
|
+
|
|
983
|
+
export declare type CheckoutPhase = 'preparing' | 'creating' | 'ready' | 'completed' | 'expired' | 'retired';
|
|
984
|
+
|
|
985
|
+
export declare type CheckoutReservation = Pick<CheckoutOperation, 'tenantId' | 'provider' | 'requestDigest' | 'plan' | 'quantity' | 'createdAt' | 'expiresAt'>;
|
|
986
|
+
|
|
987
|
+
export declare interface CheckoutSessionLookup {
|
|
988
|
+
readonly receipt: CheckoutSessionReceipt | null;
|
|
989
|
+
/** Provider-clock evidence, never the application host's clock. */
|
|
990
|
+
readonly observedAt: Date | null;
|
|
991
|
+
}
|
|
992
|
+
|
|
993
|
+
/**
|
|
994
|
+
* Dumb adapter over a billing provider. Holds NO policy — checkout/portal
|
|
995
|
+
* URL minting, usage push, and pure payload→event mapping only. The
|
|
996
|
+
* `BillingService` wraps it with the entitlement engine, the DB rows, and
|
|
997
|
+
* transient retry.
|
|
998
|
+
*
|
|
999
|
+
* `normalizeEvent` receives a payload whose signature was ALREADY verified
|
|
1000
|
+
* by @voltro/plugin-webhooks' mounter — this is pure mapping, never a
|
|
1001
|
+
* second signature check.
|
|
1002
|
+
*/
|
|
1003
|
+
export declare interface CheckoutSessionReceipt {
|
|
1004
|
+
readonly id: string;
|
|
1005
|
+
readonly operationId: string | null;
|
|
1006
|
+
readonly tenantId: string | null;
|
|
1007
|
+
readonly providerCustomerId: string | null;
|
|
1008
|
+
readonly providerSubscriptionId: string | null;
|
|
1009
|
+
readonly status: 'open' | 'complete' | 'expired';
|
|
1010
|
+
readonly url: string | null;
|
|
1011
|
+
readonly expiresAt: Date;
|
|
1012
|
+
}
|
|
1013
|
+
|
|
740
1014
|
/**
|
|
741
1015
|
* Try to claim the flush window. INSERT-wins: the first replica's row is the
|
|
742
1016
|
* winner; a racing replica's `insertIgnore` returns that same row, so it sees a
|
|
@@ -749,29 +1023,68 @@ export declare const claimFlushWindow: (store: DataStore, windowKey: string, rep
|
|
|
749
1023
|
/** What `closeAccount` did at the provider. */
|
|
750
1024
|
export declare interface CloseAccountResult {
|
|
751
1025
|
readonly tenantId: string;
|
|
752
|
-
/** Provider subscriptions
|
|
1026
|
+
/** Provider subscriptions positively confirmed canceled. A scheduled close remains pending. */
|
|
753
1027
|
readonly canceled: ReadonlyArray<string>;
|
|
754
1028
|
}
|
|
755
1029
|
|
|
756
|
-
declare interface
|
|
1030
|
+
export declare interface CustomerBinding extends CustomerScope {
|
|
757
1031
|
readonly tenantId: string;
|
|
758
|
-
readonly provider: string;
|
|
759
1032
|
readonly providerCustomerId: string;
|
|
760
1033
|
}
|
|
761
1034
|
|
|
1035
|
+
export declare interface CustomerCustodyInventoryPage {
|
|
1036
|
+
readonly customers: ReadonlyArray<CustomerRecord>;
|
|
1037
|
+
/** Read continuation only; not global or financial completion. */
|
|
1038
|
+
readonly nextCustodyId: string | null;
|
|
1039
|
+
}
|
|
1040
|
+
|
|
1041
|
+
declare interface CustomerRecord extends CustomerBinding {
|
|
1042
|
+
readonly id: string;
|
|
1043
|
+
readonly retiredAt: Date | null;
|
|
1044
|
+
}
|
|
1045
|
+
|
|
1046
|
+
export declare interface CustomerScope {
|
|
1047
|
+
readonly provider: string;
|
|
1048
|
+
readonly account: ProviderAccountIdentity;
|
|
1049
|
+
}
|
|
1050
|
+
|
|
762
1051
|
export declare interface CustomerStore {
|
|
763
|
-
|
|
1052
|
+
/** Immutable financial namespace intent, separate from customer ownership. */
|
|
1053
|
+
readonly accountForTenant: (tenantId: string) => Effect.Effect<CustomerScope | null, BillingError>;
|
|
1054
|
+
readonly assertAccount: (tenantId: string, scope: CustomerScope) => Effect.Effect<boolean, BillingError>;
|
|
1055
|
+
readonly reserveAccount: (tenantId: string, scope: CustomerScope) => Effect.Effect<void, BillingError>;
|
|
1056
|
+
/** Never overwrites ownership or resurrects a retired customer. */
|
|
1057
|
+
readonly bind: (binding: CustomerBinding, snapshot: ProviderCustomerSnapshot) => Effect.Effect<CustomerRecord, BillingError>;
|
|
764
1058
|
readonly getByTenant: (tenantId: string) => Effect.Effect<CustomerRecord | null, BillingError>;
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
readonly list: () => Effect.Effect<ReadonlyArray<CustomerRecord>, BillingError>;
|
|
768
|
-
/**
|
|
769
|
-
*
|
|
770
|
-
readonly
|
|
1059
|
+
/** Includes retained retired ownership, within this exact provider account/mode. */
|
|
1060
|
+
readonly getByProviderCustomerId: (providerCustomerId: string, scope: CustomerScope) => Effect.Effect<CustomerRecord | null, BillingError>;
|
|
1061
|
+
readonly list: (scope: CustomerScope) => Effect.Effect<ReadonlyArray<CustomerRecord>, BillingError>;
|
|
1062
|
+
/** Bounded exact-account inventory including retained retired customers.
|
|
1063
|
+
* Restart at the head in later passes to discover newly inserted custody. */
|
|
1064
|
+
readonly inventory: (scope: CustomerScope, input?: {
|
|
1065
|
+
readonly afterCustodyId?: string;
|
|
1066
|
+
readonly limit?: number;
|
|
1067
|
+
}) => Effect.Effect<CustomerCustodyInventoryPage, BillingError>;
|
|
1068
|
+
/** Only positive provider deletion retires this exact customer; history is retained. */
|
|
1069
|
+
readonly retire: (scope: CustomerScope, snapshot: ProviderCustomerSnapshot) => Effect.Effect<CustomerRecord | null, BillingError>;
|
|
771
1070
|
}
|
|
772
1071
|
|
|
1072
|
+
export declare const dataStoreBillingCloseStore: (store: DataStore) => BillingCloseStore;
|
|
1073
|
+
|
|
1074
|
+
export declare const dataStoreCheckoutOperationStore: (store: DataStore) => CheckoutOperationStore;
|
|
1075
|
+
|
|
773
1076
|
export declare const dataStoreDunningNoticeStore: (store: DataStore) => DunningNoticeStore;
|
|
774
1077
|
|
|
1078
|
+
export declare const dataStoreInvoiceHistoryJournal: (store: DataStore) => InvoiceHistoryJournal;
|
|
1079
|
+
|
|
1080
|
+
/** Traversal hints never qualify an invoice or own its execution. Native journal,
|
|
1081
|
+
* custody and work claims remain authoritative; every update is revision fenced. */
|
|
1082
|
+
export declare const dataStoreInvoiceHistoryProgressStore: (store: DataStore) => InvoiceHistoryProgressStore;
|
|
1083
|
+
|
|
1084
|
+
/** Per-reference results live in this native table, not the expiring Framework
|
|
1085
|
+
* receipt. Receipt ownership and the business acknowledgement commit together. */
|
|
1086
|
+
export declare const dataStoreInvoiceHistoryWorkStore: (store: DataStore) => InvoiceHistoryWorkStore;
|
|
1087
|
+
|
|
775
1088
|
export declare const dataStoreStores: (store: DataStore) => BillingStores;
|
|
776
1089
|
|
|
777
1090
|
/**
|
|
@@ -1092,6 +1405,184 @@ export declare const formEncode: (params: Readonly<Record<string, unknown>>) =>
|
|
|
1092
1405
|
/** When the grace for an episode runs out. */
|
|
1093
1406
|
export declare const graceEndOf: (pastDueSince: Date, graceHours: number) => Date;
|
|
1094
1407
|
|
|
1408
|
+
/** Trusted operator/server utility. The caller authorizes tenant access and
|
|
1409
|
+
* supplies a root DataStore, outside any application transaction. It deliberately
|
|
1410
|
+
* uses integrity reads, explicit tenant predicates and all deletion/expiry scopes.
|
|
1411
|
+
* No provider call, customer binding, account reservation or native write occurs.
|
|
1412
|
+
* A custom store without integrityQuery is unsupported; query is no fallback. */
|
|
1413
|
+
export declare const inspectBillingCustody: (store: DataStore, input: BillingCustodyInventoryOptions) => Effect.Effect<BillingCustodyInventory, BillingError>;
|
|
1414
|
+
|
|
1415
|
+
/** Immutable native ownership of one provider invoice, not payment authority. */
|
|
1416
|
+
export declare interface InvoiceBinding extends ProviderAccountIdentity {
|
|
1417
|
+
readonly tenantId: string;
|
|
1418
|
+
readonly provider: string;
|
|
1419
|
+
readonly providerCustomerId: string;
|
|
1420
|
+
readonly providerInvoiceId: string;
|
|
1421
|
+
}
|
|
1422
|
+
|
|
1423
|
+
export declare interface InvoiceHistoryAccountProgress extends CustomerScope {
|
|
1424
|
+
readonly id: string;
|
|
1425
|
+
readonly revision: number;
|
|
1426
|
+
readonly afterCustodyId: string | null;
|
|
1427
|
+
readonly updatedAt: Date;
|
|
1428
|
+
}
|
|
1429
|
+
|
|
1430
|
+
export declare interface InvoiceHistoryCustomerProgress extends InvoiceHistoryDispatchPosition {
|
|
1431
|
+
readonly id: string;
|
|
1432
|
+
readonly revision: number;
|
|
1433
|
+
readonly owner: CustomerRecord;
|
|
1434
|
+
readonly updatedAt: Date;
|
|
1435
|
+
}
|
|
1436
|
+
|
|
1437
|
+
export declare interface InvoiceHistoryDispatchPosition {
|
|
1438
|
+
readonly walkId: string | null;
|
|
1439
|
+
readonly cursors: Readonly<Record<InvoiceHistoryWorkLane, string | null>>;
|
|
1440
|
+
}
|
|
1441
|
+
|
|
1442
|
+
export declare interface InvoiceHistoryJournal {
|
|
1443
|
+
readonly begin: (owner: CustomerRecord) => Effect.Effect<InvoiceHistoryWalk, BillingError>;
|
|
1444
|
+
readonly read: (owner: CustomerRecord) => Effect.Effect<InvoiceHistoryWalk | null, BillingError>;
|
|
1445
|
+
/** Null means a stale checkpoint with no committed change. Discard that
|
|
1446
|
+
* offered page and reread both native checkpoint and provider page. */
|
|
1447
|
+
readonly commitPage: (expected: InvoiceHistoryWalk, page: ProviderInvoiceHistoryPage) => Effect.Effect<InvoiceHistoryWalk | null, BillingError>;
|
|
1448
|
+
/** Retain every old page/reference when a cursor is lost or a new head is scanned. */
|
|
1449
|
+
readonly restart: (expected: InvoiceHistoryWalk) => Effect.Effect<InvoiceHistoryWalk | null, BillingError>;
|
|
1450
|
+
readonly reference: (owner: CustomerRecord, referenceId: string) => Effect.Effect<InvoiceHistoryJournalReference | null, BillingError>;
|
|
1451
|
+
readonly references: (owner: CustomerRecord, input?: {
|
|
1452
|
+
readonly afterReferenceId?: string;
|
|
1453
|
+
readonly limit?: number;
|
|
1454
|
+
}) => Effect.Effect<InvoiceHistoryReferencePage, BillingError>;
|
|
1455
|
+
}
|
|
1456
|
+
|
|
1457
|
+
export declare interface InvoiceHistoryJournalOwner extends CustomerBinding {
|
|
1458
|
+
readonly custodyId: string;
|
|
1459
|
+
}
|
|
1460
|
+
|
|
1461
|
+
export declare interface InvoiceHistoryJournalReference extends InvoiceHistoryJournalOwner {
|
|
1462
|
+
readonly id: string;
|
|
1463
|
+
readonly walkId: string;
|
|
1464
|
+
readonly round: number;
|
|
1465
|
+
readonly pageId: string;
|
|
1466
|
+
readonly pageOrdinal: number;
|
|
1467
|
+
readonly position: number;
|
|
1468
|
+
readonly providerInvoiceId: string;
|
|
1469
|
+
readonly discoveryStatus: ProviderInvoiceHistoryEntry['status'];
|
|
1470
|
+
readonly providerCreatedAt: Date;
|
|
1471
|
+
}
|
|
1472
|
+
|
|
1473
|
+
export declare interface InvoiceHistoryPassResult {
|
|
1474
|
+
readonly kind: 'idle' | 'advanced' | 'contended';
|
|
1475
|
+
readonly customerCustodyId: string | null;
|
|
1476
|
+
readonly admittedPages: number;
|
|
1477
|
+
readonly observed: number;
|
|
1478
|
+
readonly deferred: number;
|
|
1479
|
+
readonly busy: number;
|
|
1480
|
+
readonly unconfirmed: number;
|
|
1481
|
+
}
|
|
1482
|
+
|
|
1483
|
+
export declare interface InvoiceHistoryProgressStore {
|
|
1484
|
+
readonly account: (scope: CustomerScope, now: Date) => Effect.Effect<InvoiceHistoryAccountProgress, BillingError>;
|
|
1485
|
+
readonly advanceAccount: (expected: InvoiceHistoryAccountProgress, afterCustodyId: string | null, now: Date) => Effect.Effect<InvoiceHistoryAccountProgress | null, BillingError>;
|
|
1486
|
+
readonly customer: (owner: CustomerRecord, now: Date) => Effect.Effect<InvoiceHistoryCustomerProgress, BillingError>;
|
|
1487
|
+
readonly advanceCustomer: (expected: InvoiceHistoryCustomerProgress, next: InvoiceHistoryDispatchPosition, now: Date) => Effect.Effect<InvoiceHistoryCustomerProgress | null, BillingError>;
|
|
1488
|
+
}
|
|
1489
|
+
|
|
1490
|
+
export declare interface InvoiceHistoryReferencePage {
|
|
1491
|
+
readonly references: ReadonlyArray<InvoiceHistoryJournalReference>;
|
|
1492
|
+
readonly nextReferenceId: string | null;
|
|
1493
|
+
/** This read's admitted-page bound, never a global completion receipt. */
|
|
1494
|
+
readonly watermarkPageOrdinal: number;
|
|
1495
|
+
readonly walkRevision: number;
|
|
1496
|
+
}
|
|
1497
|
+
|
|
1498
|
+
export declare interface InvoiceHistoryReferenceResult {
|
|
1499
|
+
readonly kind: 'observed' | 'deferred' | 'busy';
|
|
1500
|
+
readonly work: InvoiceHistoryWork;
|
|
1501
|
+
}
|
|
1502
|
+
|
|
1503
|
+
export declare interface InvoiceHistoryWalk extends InvoiceHistoryJournalOwner {
|
|
1504
|
+
readonly id: string;
|
|
1505
|
+
readonly revision: number;
|
|
1506
|
+
readonly round: number;
|
|
1507
|
+
/** Monotonic across rounds; restarting never renumbers admitted pages. */
|
|
1508
|
+
readonly pageOrdinal: number;
|
|
1509
|
+
readonly cursor: ProviderInvoiceHistoryCursor | null;
|
|
1510
|
+
/** Provider enumeration ended, not processing or financial completion. */
|
|
1511
|
+
readonly exhausted: boolean;
|
|
1512
|
+
}
|
|
1513
|
+
|
|
1514
|
+
export declare interface InvoiceHistoryWork extends InvoiceHistoryJournalOwner {
|
|
1515
|
+
readonly id: string;
|
|
1516
|
+
readonly walkId: string;
|
|
1517
|
+
readonly referenceId: string;
|
|
1518
|
+
readonly providerInvoiceId: string;
|
|
1519
|
+
readonly revision: number;
|
|
1520
|
+
/** Logical attempts and acquired execution identities survive restarts. */
|
|
1521
|
+
readonly attempt: number;
|
|
1522
|
+
readonly executions: number;
|
|
1523
|
+
readonly state: 'queued' | 'working' | 'retry' | 'deferred' | 'observed';
|
|
1524
|
+
readonly activeClaimId: string | null;
|
|
1525
|
+
readonly nextAttemptAt: Date;
|
|
1526
|
+
readonly lastOutcome: 'unconfirmed' | 'open' | 'observed';
|
|
1527
|
+
/** An observed native version, never a payment or entitlement receipt. */
|
|
1528
|
+
readonly observationId: string | null;
|
|
1529
|
+
readonly observationRevision: number | null;
|
|
1530
|
+
readonly updatedAt: Date;
|
|
1531
|
+
}
|
|
1532
|
+
|
|
1533
|
+
export declare type InvoiceHistoryWorkAcquisition = {
|
|
1534
|
+
readonly kind: 'claimed';
|
|
1535
|
+
readonly work: InvoiceHistoryWork;
|
|
1536
|
+
readonly attempt: InvoiceHistoryWorkAttempt;
|
|
1537
|
+
} | {
|
|
1538
|
+
readonly kind: 'busy' | 'observed';
|
|
1539
|
+
readonly work: InvoiceHistoryWork;
|
|
1540
|
+
};
|
|
1541
|
+
|
|
1542
|
+
export declare interface InvoiceHistoryWorkAttempt {
|
|
1543
|
+
readonly work: InvoiceHistoryWork;
|
|
1544
|
+
readonly claim: IdempotencyClaim;
|
|
1545
|
+
}
|
|
1546
|
+
|
|
1547
|
+
export declare interface InvoiceHistoryWorkCursor {
|
|
1548
|
+
readonly lane: InvoiceHistoryWorkLane;
|
|
1549
|
+
readonly walkId: string;
|
|
1550
|
+
readonly afterId: string;
|
|
1551
|
+
}
|
|
1552
|
+
|
|
1553
|
+
export declare type InvoiceHistoryWorkLane = 'unprepared' | 'ready' | 'working';
|
|
1554
|
+
|
|
1555
|
+
export declare interface InvoiceHistoryWorkPage {
|
|
1556
|
+
readonly entries: ReadonlyArray<{
|
|
1557
|
+
readonly reference: InvoiceHistoryJournalReference;
|
|
1558
|
+
readonly work: InvoiceHistoryWork | null;
|
|
1559
|
+
}>;
|
|
1560
|
+
/** Read pagination only; null never establishes global/financial completion. */
|
|
1561
|
+
readonly nextCursor: InvoiceHistoryWorkCursor | null;
|
|
1562
|
+
readonly walkRevision: number;
|
|
1563
|
+
}
|
|
1564
|
+
|
|
1565
|
+
export declare interface InvoiceHistoryWorkStore {
|
|
1566
|
+
/** Independent bounded lanes keep new references separate from due retries
|
|
1567
|
+
* and claimed executions. Selection grants no execution ownership. */
|
|
1568
|
+
readonly pending: (owner: CustomerRecord, lane: InvoiceHistoryWorkLane, now: Date, input?: {
|
|
1569
|
+
readonly limit?: number;
|
|
1570
|
+
readonly cursor?: InvoiceHistoryWorkCursor;
|
|
1571
|
+
}) => Effect.Effect<InvoiceHistoryWorkPage, BillingError>;
|
|
1572
|
+
readonly claim: (owner: CustomerRecord, referenceId: string, now: Date) => Effect.Effect<InvoiceHistoryWorkAcquisition, BillingError>;
|
|
1573
|
+
readonly observed: (owner: CustomerRecord, attempt: InvoiceHistoryWorkAttempt, observation: InvoiceObservation, now: Date) => Effect.Effect<InvoiceHistoryWork | null, BillingError>;
|
|
1574
|
+
readonly failed: (owner: CustomerRecord, attempt: InvoiceHistoryWorkAttempt, now: Date) => Effect.Effect<InvoiceHistoryWork | null, BillingError>;
|
|
1575
|
+
/** Uses the shared Framework heartbeat. Stopping never proves SDK work stopped. */
|
|
1576
|
+
readonly hold: (attempt: InvoiceHistoryWorkAttempt, now?: () => number) => () => void;
|
|
1577
|
+
}
|
|
1578
|
+
|
|
1579
|
+
export declare interface InvoiceObservation extends InvoiceBinding {
|
|
1580
|
+
readonly id: string;
|
|
1581
|
+
readonly identityKey: string;
|
|
1582
|
+
readonly revision: number;
|
|
1583
|
+
readonly snapshot: ProviderInvoiceSnapshot;
|
|
1584
|
+
}
|
|
1585
|
+
|
|
1095
1586
|
declare interface InvoiceRecord {
|
|
1096
1587
|
readonly providerInvoiceId: string;
|
|
1097
1588
|
readonly amountMinor: number;
|
|
@@ -1103,28 +1594,12 @@ declare interface InvoiceRecord {
|
|
|
1103
1594
|
readonly pdfUrl: string | null;
|
|
1104
1595
|
}
|
|
1105
1596
|
|
|
1106
|
-
declare interface InvoiceRecord_2 {
|
|
1107
|
-
readonly tenantId: string;
|
|
1108
|
-
readonly provider: string;
|
|
1109
|
-
readonly providerInvoiceId: string;
|
|
1110
|
-
readonly amountMinor: number;
|
|
1111
|
-
readonly currency: string;
|
|
1112
|
-
/** 'paid' | 'open' | 'uncollectible' | 'void'. */
|
|
1113
|
-
readonly status: string;
|
|
1114
|
-
/** Provider-event timestamp this `status` came from; null when undated. */
|
|
1115
|
-
readonly statusEventAt: Date | null;
|
|
1116
|
-
}
|
|
1117
|
-
|
|
1118
1597
|
export declare interface InvoiceStore {
|
|
1119
|
-
/**
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
*
|
|
1123
|
-
|
|
1124
|
-
* unordered delivery.
|
|
1125
|
-
*/
|
|
1126
|
-
readonly upsert: (invoice: InvoiceRecord_2) => Effect.Effect<void, BillingError>;
|
|
1127
|
-
readonly listByTenant: (tenantId: string) => Effect.Effect<ReadonlyArray<InvoiceRecord_2>, BillingError>;
|
|
1598
|
+
/** Read the revision before a provider observation, without reserving unproven ownership. */
|
|
1599
|
+
readonly get: (binding: InvoiceBinding) => Effect.Effect<InvoiceObservation | null, BillingError>;
|
|
1600
|
+
/** Insert only if absent, or compare the previously read revision. False requires
|
|
1601
|
+
* another native AND provider read; never retry a captured payload alone. */
|
|
1602
|
+
readonly complete: (binding: InvoiceBinding, expected: InvoiceObservation | null, snapshot: ProviderInvoiceSnapshot) => Effect.Effect<boolean, BillingError>;
|
|
1128
1603
|
}
|
|
1129
1604
|
|
|
1130
1605
|
/** Is this a real deployment boot? Only an explicitly dev-like NODE_ENV is not. */
|
|
@@ -1143,6 +1618,10 @@ export declare const isStaleStatusEvent: (existing: Date | null, incoming: Date
|
|
|
1143
1618
|
*/
|
|
1144
1619
|
export declare type LockoutMode = 'hard' | 'soft';
|
|
1145
1620
|
|
|
1621
|
+
export declare const memoryBillingCloseStore: () => BillingCloseStore;
|
|
1622
|
+
|
|
1623
|
+
export declare const memoryCheckoutOperationStore: () => CheckoutOperationStore;
|
|
1624
|
+
|
|
1146
1625
|
export declare const memoryDunningNoticeStore: () => DunningNoticeStore;
|
|
1147
1626
|
|
|
1148
1627
|
export declare const memoryStores: () => BillingStores;
|
|
@@ -1150,6 +1629,15 @@ export declare const memoryStores: () => BillingStores;
|
|
|
1150
1629
|
/** Replace (or add) `NAME=value` lines; every other line is kept as it was. */
|
|
1151
1630
|
export declare const mergeEnvFile: (text: string, values: Readonly<Record<string, string>>) => string;
|
|
1152
1631
|
|
|
1632
|
+
export declare interface MeteredUsageEvent {
|
|
1633
|
+
readonly tenantId: string;
|
|
1634
|
+
readonly entitlementKey: string;
|
|
1635
|
+
readonly quantity: number;
|
|
1636
|
+
readonly occurredAt: Date;
|
|
1637
|
+
/** Stable tenant-scoped occurrence identity, reused unchanged on every retry. */
|
|
1638
|
+
readonly idempotencyKey: string;
|
|
1639
|
+
}
|
|
1640
|
+
|
|
1153
1641
|
/** `meterKey → source`. The meterKey is the entitlement/usage key reported to
|
|
1154
1642
|
* the provider (`billing.reportUsage(tenant, meterKey, qty)`). */
|
|
1155
1643
|
declare type MeteringConfig = Readonly<Record<string, MeterSource>>;
|
|
@@ -1179,11 +1667,19 @@ declare type MeterSource =
|
|
|
1179
1667
|
* In-memory provider with deterministic outputs. Checkout/portal URLs are
|
|
1180
1668
|
* stable functions of the input so tests can assert on them; usage pushes
|
|
1181
1669
|
* are recorded on `pushed` for assertion. `normalizeEvent` accepts the
|
|
1182
|
-
*
|
|
1183
|
-
* straight through)
|
|
1184
|
-
* mapping, so the same webhook path exercises the mock end-to-end.
|
|
1670
|
+
* verified `BillingProviderEvent` shape directly (the test feeds events
|
|
1671
|
+
* straight through). Invoice triggers carry providerCustomerId; an event never seeds provider state.
|
|
1185
1672
|
*/
|
|
1186
1673
|
export declare interface MockProvider extends BillingProvider {
|
|
1674
|
+
readonly fetchAccountIdentity: NonNullable<BillingProvider['fetchAccountIdentity']>;
|
|
1675
|
+
readonly fetchCustomerSnapshot: NonNullable<BillingProvider['fetchCustomerSnapshot']>;
|
|
1676
|
+
/** Independent provider state; an event or invoice is not customer evidence. */
|
|
1677
|
+
readonly setCustomerSnapshot: (snapshot: ProviderCustomerSnapshot) => void;
|
|
1678
|
+
/** Supply actual simulated provider state; webhook payloads never create this evidence. */
|
|
1679
|
+
readonly setInvoiceSnapshot: (snapshot: ProviderInvoiceSnapshot) => void;
|
|
1680
|
+
/** Independent provider history, including drafts and original creation dates.
|
|
1681
|
+
* Detailed snapshots and event payloads do not manufacture this history. */
|
|
1682
|
+
readonly setInvoiceHistory: (entries: ReadonlyArray<ProviderInvoiceHistoryEntry>) => void;
|
|
1187
1683
|
/** Recorded usage pushes — assertion surface for tests. */
|
|
1188
1684
|
readonly pushed: ReadonlyArray<UsagePush>;
|
|
1189
1685
|
/** Recorded subscription updates. The point of asserting on these is that
|
|
@@ -1232,6 +1728,9 @@ export declare interface MockProvider extends BillingProvider {
|
|
|
1232
1728
|
export declare const mockProvider: (options?: {
|
|
1233
1729
|
readonly baseUrl?: string;
|
|
1234
1730
|
readonly supportsMeteredUsage?: boolean;
|
|
1731
|
+
readonly now?: () => Date;
|
|
1732
|
+
/** Explicit stable account for controlled fixtures; otherwise this mock instance owns a fresh account. */
|
|
1733
|
+
readonly accountId?: string;
|
|
1235
1734
|
}) => MockProvider;
|
|
1236
1735
|
|
|
1237
1736
|
/** A monetary amount: integer minor units + ISO-4217 currency. */
|
|
@@ -1262,10 +1761,9 @@ declare interface MountBillingWebhookOptions extends BillingWebhookOptions {
|
|
|
1262
1761
|
* not model (the handler no-ops and still answers 200, which is what stops
|
|
1263
1762
|
* Stripe retrying an event we will never care about).
|
|
1264
1763
|
*/
|
|
1265
|
-
export declare const normalizeStripeEvent: (event: default_2.Event, resolvePrice?: (priceId: string) => string | null) =>
|
|
1764
|
+
export declare const normalizeStripeEvent: (event: default_2.Event, resolvePrice?: (priceId: string) => string | null) => BillingProviderEvent | null;
|
|
1266
1765
|
|
|
1267
|
-
|
|
1268
|
-
export declare type OnEventMap = Readonly<Record<string, (event: BillingEvent) => Effect.Effect<void, unknown>>>;
|
|
1766
|
+
export declare type OnEventMap = Readonly<Record<string, (event: BillingEvent, delivery?: BillingEventDeliveryContext) => Effect.Effect<void, unknown>>>;
|
|
1269
1767
|
|
|
1270
1768
|
/** Findings the account still differs by (after `apply`: what it could not fix). */
|
|
1271
1769
|
export declare const openFindings: (findings: ProvisionResult["findings"]) => (CatalogFinding & {
|
|
@@ -1348,6 +1846,88 @@ export declare const portalParams: (portal: StripeCatalog["portal"], env: Stripe
|
|
|
1348
1846
|
readonly priceId: string;
|
|
1349
1847
|
}>) => Record<string, unknown>;
|
|
1350
1848
|
|
|
1849
|
+
/** Provider-observed account/mode, not a configured key prefix or tenant hint. */
|
|
1850
|
+
export declare interface ProviderAccountIdentity {
|
|
1851
|
+
readonly providerAccountId: string;
|
|
1852
|
+
readonly livemode: boolean;
|
|
1853
|
+
}
|
|
1854
|
+
|
|
1855
|
+
/** A positive customer response in an explicitly expected provider namespace.
|
|
1856
|
+
* observedAt is local observation time, never provider-clock settlement evidence. */
|
|
1857
|
+
export declare interface ProviderCustomerSnapshot {
|
|
1858
|
+
readonly account: ProviderAccountIdentity;
|
|
1859
|
+
readonly providerCustomerId: string;
|
|
1860
|
+
readonly deleted: boolean;
|
|
1861
|
+
readonly observedAt: Date;
|
|
1862
|
+
}
|
|
1863
|
+
|
|
1864
|
+
/** Explicit provider namespace/customer binding; not a bearer authorization. */
|
|
1865
|
+
export declare interface ProviderInvoiceHistoryCursor extends ProviderAccountIdentity {
|
|
1866
|
+
readonly providerCustomerId: string;
|
|
1867
|
+
readonly afterInvoiceId: string;
|
|
1868
|
+
}
|
|
1869
|
+
|
|
1870
|
+
/** One history reference, not a complete invoice observation or payment proof. */
|
|
1871
|
+
export declare interface ProviderInvoiceHistoryEntry extends InvoiceRecord {
|
|
1872
|
+
readonly providerCustomerId: string;
|
|
1873
|
+
readonly livemode: boolean;
|
|
1874
|
+
readonly status: 'draft' | 'open' | 'paid' | 'uncollectible' | 'void';
|
|
1875
|
+
readonly createdAt: Date;
|
|
1876
|
+
}
|
|
1877
|
+
|
|
1878
|
+
export declare interface ProviderInvoiceHistoryInput {
|
|
1879
|
+
readonly account: ProviderAccountIdentity;
|
|
1880
|
+
readonly providerCustomerId: string;
|
|
1881
|
+
readonly cursor?: ProviderInvoiceHistoryCursor;
|
|
1882
|
+
/** 1..100; defaults to 100. Invalid values fail rather than clamp. */
|
|
1883
|
+
readonly limit?: number;
|
|
1884
|
+
}
|
|
1885
|
+
|
|
1886
|
+
export declare interface ProviderInvoiceHistoryPage {
|
|
1887
|
+
readonly account: ProviderAccountIdentity;
|
|
1888
|
+
readonly providerCustomerId: string;
|
|
1889
|
+
readonly invoices: ReadonlyArray<ProviderInvoiceHistoryEntry>;
|
|
1890
|
+
readonly nextCursor: ProviderInvoiceHistoryCursor | null;
|
|
1891
|
+
/** Local observation time, not provider-clock or financial coverage evidence. */
|
|
1892
|
+
readonly observedAt: Date;
|
|
1893
|
+
}
|
|
1894
|
+
|
|
1895
|
+
export declare interface ProviderInvoiceLineSnapshot {
|
|
1896
|
+
readonly providerLineId: string;
|
|
1897
|
+
readonly providerSubscriptionId: string | null;
|
|
1898
|
+
readonly providerSubscriptionItemId: string | null;
|
|
1899
|
+
readonly providerPriceId: string | null;
|
|
1900
|
+
readonly amountMinor: number;
|
|
1901
|
+
readonly currency: string;
|
|
1902
|
+
/** Exact provider decimal; absent precision must never be replaced by a truncated integer. */
|
|
1903
|
+
readonly quantityDecimal: string | null;
|
|
1904
|
+
/** Provider period bounds are inclusive; they are not paid-through authority. */
|
|
1905
|
+
readonly periodStart: Date;
|
|
1906
|
+
readonly periodEnd: Date;
|
|
1907
|
+
/** Null means the provider did not identify the line's origin. */
|
|
1908
|
+
readonly proration: boolean | null;
|
|
1909
|
+
}
|
|
1910
|
+
|
|
1911
|
+
/** A complete provider observation, not an entitlement or a payment receipt. */
|
|
1912
|
+
export declare interface ProviderInvoiceSnapshot {
|
|
1913
|
+
readonly providerInvoiceId: string;
|
|
1914
|
+
readonly providerCustomerId: string;
|
|
1915
|
+
readonly providerSubscriptionId: string | null;
|
|
1916
|
+
readonly providerRevisionId: string | null;
|
|
1917
|
+
readonly status: 'open' | 'paid' | 'uncollectible' | 'void';
|
|
1918
|
+
readonly livemode: boolean;
|
|
1919
|
+
readonly currency: string;
|
|
1920
|
+
readonly amountDueMinor: number;
|
|
1921
|
+
readonly amountPaidMinor: number;
|
|
1922
|
+
readonly amountRemainingMinor: number;
|
|
1923
|
+
readonly finalizedAt: Date;
|
|
1924
|
+
readonly paidAt: Date | null;
|
|
1925
|
+
/** Local read completion time, never a provider clock or entitlement deadline. */
|
|
1926
|
+
readonly observedAt: Date;
|
|
1927
|
+
/** All pages. A bounded or failed read must fail instead of returning a prefix. */
|
|
1928
|
+
readonly lines: ReadonlyArray<ProviderInvoiceLineSnapshot>;
|
|
1929
|
+
}
|
|
1930
|
+
|
|
1351
1931
|
/** What `reconcileFromProvider` found and corrected. */
|
|
1352
1932
|
export declare interface ProviderReconcileResult {
|
|
1353
1933
|
/** Subscriptions compared (provider-listed plus local rows it did not list). */
|
|
@@ -1523,6 +2103,11 @@ export declare const runStripeProvision: (catalog: StripeCatalog, argv: Readonly
|
|
|
1523
2103
|
readonly vars?: NodeJS.ProcessEnv;
|
|
1524
2104
|
}) => Promise<number>;
|
|
1525
2105
|
|
|
2106
|
+
/** The row that speaks for a tenant: a live one first, then the newest. */
|
|
2107
|
+
export declare const selectCurrentSubscription: <T extends {
|
|
2108
|
+
readonly status: string;
|
|
2109
|
+
}>(rows: ReadonlyArray<T>) => T | null;
|
|
2110
|
+
|
|
1526
2111
|
/** What only a human can settle before an environment sells. */
|
|
1527
2112
|
export declare const sellingReadiness: (input: {
|
|
1528
2113
|
readonly catalog: StripeCatalog;
|
|
@@ -1532,6 +2117,10 @@ export declare const sellingReadiness: (input: {
|
|
|
1532
2117
|
readonly activeRegistrations: ReadonlyArray<string>;
|
|
1533
2118
|
}) => ReadonlyArray<CatalogFinding>;
|
|
1534
2119
|
|
|
2120
|
+
export declare interface StoredUsageEvent extends MeteredUsageEvent {
|
|
2121
|
+
readonly period: string;
|
|
2122
|
+
}
|
|
2123
|
+
|
|
1535
2124
|
/**
|
|
1536
2125
|
* A mutable holder so `bindDataStore` can swap the stores AFTER the service
|
|
1537
2126
|
* layer is built. The service reads `holder.stores` on every call rather
|
|
@@ -1822,6 +2411,12 @@ declare interface SubscriptionChangeResult {
|
|
|
1822
2411
|
readonly currentPeriodEnd: Date | null;
|
|
1823
2412
|
}
|
|
1824
2413
|
|
|
2414
|
+
export declare interface SubscriptionCloseOperation {
|
|
2415
|
+
readonly id: string;
|
|
2416
|
+
/** Provider-clock deadline captured after final usage dispatch. */
|
|
2417
|
+
readonly cancelAt: Date;
|
|
2418
|
+
}
|
|
2419
|
+
|
|
1825
2420
|
/**
|
|
1826
2421
|
* Raised when dunning has locked a tenant out — the grace period after a
|
|
1827
2422
|
* provider-confirmed past-due has expired. Distinct from
|
|
@@ -1910,12 +2505,20 @@ declare interface SubscriptionUpdateInput {
|
|
|
1910
2505
|
}
|
|
1911
2506
|
|
|
1912
2507
|
/** An event the provider failed to deliver, reduced to what a catch-up needs. */
|
|
1913
|
-
declare interface UndeliveredEvent {
|
|
2508
|
+
export declare interface UndeliveredEvent {
|
|
1914
2509
|
readonly id: string;
|
|
2510
|
+
readonly event: BillingProviderEvent | null;
|
|
2511
|
+
/** A recognized provider event could not be normalized; retry/report it, never fall back to discovery. */
|
|
2512
|
+
readonly rejected?: true;
|
|
1915
2513
|
readonly providerCustomerId: string | null;
|
|
1916
2514
|
readonly createdAt: Date | null;
|
|
1917
2515
|
}
|
|
1918
2516
|
|
|
2517
|
+
export declare interface UndeliveredEventPage {
|
|
2518
|
+
readonly events: ReadonlyArray<UndeliveredEvent>;
|
|
2519
|
+
readonly nextCursor: string | null;
|
|
2520
|
+
}
|
|
2521
|
+
|
|
1919
2522
|
export declare interface UsagePush {
|
|
1920
2523
|
readonly tenantId: string;
|
|
1921
2524
|
readonly entitlementKey: string;
|
|
@@ -1942,6 +2545,7 @@ declare interface UsageRow {
|
|
|
1942
2545
|
}
|
|
1943
2546
|
|
|
1944
2547
|
export declare interface UsageStore {
|
|
2548
|
+
readonly recordEvent: (event: StoredUsageEvent) => Effect.Effect<void, BillingError>;
|
|
1945
2549
|
/** Current used count for `(tenant, key, period)`; 0 when no row. */
|
|
1946
2550
|
readonly used: (tenantId: string, key: string, period: string) => Effect.Effect<number, BillingError>;
|
|
1947
2551
|
/**
|