@lunora/payment 1.0.0-alpha.10 → 1.0.0-alpha.100
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.md +6 -0
- package/README.md +5 -2
- package/dist/index.d.mts +365 -528
- package/dist/index.d.ts +365 -528
- package/dist/index.mjs +1 -16
- package/dist/packem_shared/LunoraPaymentError-BSxyhWgu.mjs +1 -0
- package/dist/packem_shared/MemoryPaymentStore-Cu9J-zf9.mjs +1 -0
- package/dist/packem_shared/PAYMENT_TERMINAL_STATES-DVerjPR6.mjs +1 -0
- package/dist/packem_shared/adapter.d-Cpy8g96b.d.mts +443 -0
- package/dist/packem_shared/adapter.d-Cpy8g96b.d.ts +443 -0
- package/dist/packem_shared/addMoney-B4ufWAnD.mjs +1 -0
- package/dist/packem_shared/applyWebhookAction-daHKTG_Q.mjs +1 -0
- package/dist/packem_shared/constantTimeEqual-ggrwGvRa.mjs +1 -0
- package/dist/packem_shared/createAdapterRegistry-DyCsry1Q.mjs +1 -0
- package/dist/packem_shared/createDatabasePaymentStore-CVrAhWjP.mjs +1 -0
- package/dist/packem_shared/createPayment-Dmh6IWLZ.mjs +1 -0
- package/dist/packem_shared/entitlementsForReference-Bq-9UUL8.mjs +1 -0
- package/dist/packem_shared/idempotencyKey-BjxjMMna.mjs +1 -0
- package/dist/packem_shared/json-BJJPJVYj.mjs +1 -0
- package/dist/packem_shared/lunoraDatabaseToPaymentDatabase-5WkBd3aZ.mjs +1 -0
- package/dist/packem_shared/not-supported-Cl0brzhn.mjs +1 -0
- package/dist/packem_shared/observability-BteZ2dJS.mjs +1 -0
- package/dist/packem_shared/paymentTables-Be-_11ux.mjs +1 -0
- package/dist/packem_shared/reconcile-Cm45pURT.mjs +1 -0
- package/dist/packem_shared/subscription-event-C8GiQSFM.mjs +1 -0
- package/dist/providers/autumn-features.d.mts +129 -0
- package/dist/providers/autumn-features.d.ts +129 -0
- package/dist/providers/autumn-features.mjs +1 -0
- package/dist/providers/autumn.d.mts +28 -0
- package/dist/providers/autumn.d.ts +28 -0
- package/dist/providers/autumn.mjs +1 -0
- package/dist/providers/creem.d.mts +26 -0
- package/dist/providers/creem.d.ts +26 -0
- package/dist/providers/creem.mjs +1 -0
- package/dist/providers/dodopayments.d.mts +30 -0
- package/dist/providers/dodopayments.d.ts +30 -0
- package/dist/providers/dodopayments.mjs +1 -0
- package/dist/providers/polar.d.mts +31 -0
- package/dist/providers/polar.d.ts +31 -0
- package/dist/providers/polar.mjs +1 -0
- package/dist/providers/stripe.d.mts +32 -0
- package/dist/providers/stripe.d.ts +32 -0
- package/dist/providers/stripe.mjs +1 -0
- package/package.json +45 -4
- package/dist/packem_shared/LunoraPaymentError-B3hEzXSs.mjs +0 -22
- package/dist/packem_shared/MemoryPaymentStore-DvgdWa3C.mjs +0 -72
- package/dist/packem_shared/PAYMENT_TERMINAL_STATES-DrxV0clv.mjs +0 -26
- package/dist/packem_shared/addMoney-bCcs1nyw.mjs +0 -60
- package/dist/packem_shared/applyWebhookAction-DpAqf3Lw.mjs +0 -177
- package/dist/packem_shared/constantTimeEqual-CfY0jYcL.mjs +0 -95
- package/dist/packem_shared/createAdapterRegistry-BuDHFCBc.mjs +0 -24
- package/dist/packem_shared/createDatabasePaymentStore-bYB_HUE6.mjs +0 -172
- package/dist/packem_shared/createPayment-BccfPGyw.mjs +0 -190
- package/dist/packem_shared/createPolarAdapter-BJtVGSlF.mjs +0 -217
- package/dist/packem_shared/createStripeAdapter-D40MVBXg.mjs +0 -270
- package/dist/packem_shared/entitlementsForReference-CzZGXPoZ.mjs +0 -51
- package/dist/packem_shared/idempotencyKey-BFzDCA7g.mjs +0 -3
- package/dist/packem_shared/json-Db337f36.mjs +0 -6
- package/dist/packem_shared/lunoraDatabaseToPaymentDatabase-RlKX3Kcd.mjs +0 -29
- package/dist/packem_shared/observability-CvhJ205g.mjs +0 -11
- package/dist/packem_shared/paymentTables-DccHwWr_.mjs +0 -127
- package/dist/packem_shared/reconcile-CI1ukJF9.mjs +0 -73
package/dist/index.d.mts
CHANGED
|
@@ -1,327 +1,79 @@
|
|
|
1
|
+
import { a as ProviderId, C as Customer, b as PaymentSession, S as Subscription, U as UsageEvent, W as WebhookActionType, A as ApplyResult, P as PaymentAdapter, c as AttachInput, d as CheckoutResult, e as CancelSubscriptionOptions, f as CaptureInput, g as CheckInput, h as CheckResult, i as CheckoutInput, F as FeatureBalance, R as RefundInput, T as TrackInput, j as TrackResult, k as CurrencyCode, M as Money, l as PaymentState, m as SubscriptionState, n as WebhookAction } from "./packem_shared/adapter.d-Cpy8g96b.mjs";
|
|
2
|
+
export { type o as AdapterRegistry, type p as CustomerRef, type q as PortalInput, type r as ProviderCapabilities, type s as RefundAmountKind, type t as ReportUsageInput, type u as SubscriptionPatch, type v as WebhookHeaders, type w as WebhookInput, x as createAdapterRegistry } from "./packem_shared/adapter.d-Cpy8g96b.mjs";
|
|
3
|
+
import { LunoraError } from '@lunora/errors';
|
|
1
4
|
import { TableDefinition } from '@lunora/server';
|
|
2
5
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
|
|
6
|
-
* provider-agnostic vocabulary every adapter normalizes onto.
|
|
7
|
-
*/
|
|
8
|
-
/** ISO-4217 currency code (uppercase, 3 letters). Not enumerated — provider coverage varies. */
|
|
9
|
-
type CurrencyCode = string;
|
|
10
|
-
/**
|
|
11
|
-
* Money as integer minor units + currency. Always carry the two together.
|
|
12
|
-
*
|
|
13
|
-
* `minorUnits` is a `bigint`, which is **not** JSON-serializable — cross the RPC/wire boundary
|
|
14
|
-
* with the `toMoneyJSON` / `fromMoneyJSON` helpers (see `./money`).
|
|
15
|
-
*/
|
|
16
|
-
interface Money {
|
|
17
|
-
readonly currency: CurrencyCode;
|
|
18
|
-
readonly minorUnits: bigint;
|
|
19
|
-
}
|
|
20
|
-
/** Stable provider identifier (Medusa-style). Scoped to what Convex ships: Stripe + Polar. */
|
|
21
|
-
type ProviderId = "polar" | "stripe";
|
|
22
|
-
/** What a provider can do — encoded in types so tax/UX assumptions aren't tribal knowledge. */
|
|
23
|
-
interface ProviderCapabilities {
|
|
24
|
-
/** True for Polar / Lemon Squeezy / Paddle; false for Stripe (PSP). Drives tax/invoice ownership. */
|
|
25
|
-
readonly merchantOfRecord: boolean;
|
|
26
|
-
/** Native hosted customer/billing portal. */
|
|
27
|
-
readonly portal: boolean;
|
|
28
|
-
/** Usage-based / metered billing. */
|
|
29
|
-
readonly usageMetering: boolean;
|
|
30
|
-
}
|
|
31
|
-
/** Lifecycle state of a one-time payment session. */
|
|
32
|
-
type PaymentState = "authorized" | "canceled" | "captured" | "failed" | "initiated" | "partially_refunded" | "refunded";
|
|
33
|
-
/** Lifecycle state of a subscription. */
|
|
34
|
-
type SubscriptionState = "active" | "canceled" | "past_due" | "paused" | "trialing";
|
|
35
|
-
interface Customer {
|
|
36
|
-
readonly createdAt: number;
|
|
37
|
-
readonly email?: string;
|
|
38
|
-
/** Provider-side customer id. */
|
|
39
|
-
readonly id: string;
|
|
40
|
-
readonly provider: ProviderId;
|
|
41
|
-
/** App-side owner the customer belongs to (user / org / workspace). Opaque to this package. */
|
|
42
|
-
readonly referenceId: string;
|
|
43
|
-
}
|
|
44
|
-
interface PaymentSession {
|
|
45
|
-
readonly amount: Money;
|
|
46
|
-
readonly capturedAmount: Money;
|
|
47
|
-
readonly createdAt: number;
|
|
48
|
-
/** Provider-side payment / intent / session id. */
|
|
49
|
-
readonly id: string;
|
|
50
|
-
readonly provider: ProviderId;
|
|
51
|
-
readonly referenceId: string;
|
|
52
|
-
readonly refundedAmount: Money;
|
|
53
|
-
readonly state: PaymentState;
|
|
54
|
-
readonly updatedAt: number;
|
|
55
|
-
}
|
|
56
|
-
interface Subscription {
|
|
57
|
-
readonly cancelAtPeriodEnd: boolean;
|
|
58
|
-
readonly createdAt: number;
|
|
59
|
-
readonly currentPeriodEnd?: number;
|
|
60
|
-
/** Start of the current billing period — the window `check` sums metered usage over. */
|
|
61
|
-
readonly currentPeriodStart?: number;
|
|
62
|
-
readonly id: string;
|
|
63
|
-
readonly priceId: string;
|
|
64
|
-
readonly provider: ProviderId;
|
|
65
|
-
readonly quantity: number;
|
|
66
|
-
readonly referenceId: string;
|
|
67
|
-
readonly state: SubscriptionState;
|
|
68
|
-
readonly updatedAt: number;
|
|
69
|
-
}
|
|
70
|
-
interface CustomerRef {
|
|
71
|
-
readonly email?: string;
|
|
72
|
-
readonly metadata?: Record<string, string>;
|
|
73
|
-
readonly referenceId: string;
|
|
74
|
-
}
|
|
75
|
-
interface CheckoutInput {
|
|
76
|
-
readonly cancelUrl: string;
|
|
77
|
-
/** Existing provider customer id, if known. */
|
|
78
|
-
readonly customerId?: string;
|
|
79
|
-
/** Outbound idempotency key for the provider call; auto-derived when omitted. */
|
|
80
|
-
readonly idempotencyKey?: string;
|
|
81
|
-
readonly metadata?: Record<string, string>;
|
|
82
|
-
readonly mode: "payment" | "subscription";
|
|
83
|
-
readonly priceId: string;
|
|
84
|
-
readonly quantity?: number;
|
|
85
|
-
readonly referenceId: string;
|
|
86
|
-
readonly successUrl: string;
|
|
87
|
-
}
|
|
88
|
-
interface CheckoutResult {
|
|
89
|
-
readonly id: string;
|
|
90
|
-
readonly provider: ProviderId;
|
|
91
|
-
readonly url: string;
|
|
92
|
-
}
|
|
93
|
-
/**
|
|
94
|
-
* `attach` input — subscribe a reference to a plan. A thin, plan-oriented skin over
|
|
95
|
-
* {@link CheckoutInput}: `mode` defaults to `"subscription"` (the common case), so callers pass
|
|
96
|
-
* just `{ referenceId, priceId, successUrl, cancelUrl }`.
|
|
97
|
-
*/
|
|
98
|
-
interface AttachInput extends Omit<CheckoutInput, "mode"> {
|
|
99
|
-
readonly mode?: CheckoutInput["mode"];
|
|
100
|
-
}
|
|
101
|
-
interface PortalInput {
|
|
102
|
-
readonly customerId: string;
|
|
103
|
-
readonly returnUrl: string;
|
|
104
|
-
}
|
|
105
|
-
/** A single durable usage record — one metered event for a `(referenceId, featureId)` pair. */
|
|
106
|
-
interface UsageEvent {
|
|
107
|
-
readonly createdAt: number;
|
|
108
|
-
readonly featureId: string;
|
|
109
|
-
/** Caller-stable dedupe key — recording the same key twice is a no-op (exactly-once `track`). */
|
|
110
|
-
readonly idempotencyKey: string;
|
|
111
|
-
readonly provider: ProviderId;
|
|
112
|
-
readonly quantity: number;
|
|
113
|
-
readonly referenceId: string;
|
|
114
|
-
/** Whether the event was successfully forwarded to the provider's metering API. */
|
|
115
|
-
readonly reportedToProvider: boolean;
|
|
116
|
-
}
|
|
117
|
-
/** `track` input — record metered usage for a reference's feature. */
|
|
118
|
-
interface TrackInput {
|
|
119
|
-
readonly featureId: string;
|
|
120
|
-
/** Caller-supplied dedupe key; a fresh one is generated when omitted (so each call records). */
|
|
121
|
-
readonly idempotencyKey?: string;
|
|
122
|
-
/** `"add"` (default) increments usage by `quantity`; `"set"` reconciles the period total to `quantity`. */
|
|
123
|
-
readonly mode?: "add" | "set";
|
|
124
|
-
/** Usage amount to add, or the absolute period total when `mode` is `"set"` (defaults to `1`). */
|
|
125
|
-
readonly quantity?: number;
|
|
126
|
-
readonly referenceId: string;
|
|
127
|
-
}
|
|
128
|
-
/** Result of a `track` call. */
|
|
129
|
-
interface TrackResult {
|
|
130
|
-
/** True when this call inserted a new usage event; false when deduplicated by idempotency key. */
|
|
131
|
-
readonly recorded: boolean;
|
|
132
|
-
/** True when the event was forwarded to the provider's metering API. */
|
|
133
|
-
readonly reportedToProvider: boolean;
|
|
134
|
-
}
|
|
135
|
-
/**
|
|
136
|
-
* `check` input — is a reference allowed something right now? Pass `featureId` to check a feature
|
|
137
|
-
* grant/allowance, or `priceId` to check active access to a product (one of the two is required).
|
|
138
|
-
*/
|
|
139
|
-
interface CheckInput {
|
|
140
|
-
/** Feature to check a grant/allowance for. Provide this **or** `priceId`. */
|
|
141
|
-
readonly featureId?: string;
|
|
142
|
-
/** Provider price/product id to check active access for. Provide this **or** `featureId`. */
|
|
143
|
-
readonly priceId?: string;
|
|
144
|
-
/** Units the caller intends to consume; the check passes only when this many remain (default `1`). */
|
|
145
|
-
readonly quantity?: number;
|
|
146
|
-
readonly referenceId: string;
|
|
147
|
-
}
|
|
148
|
-
/** Result of a `check` call. */
|
|
149
|
-
interface CheckResult {
|
|
150
|
-
/** Whether the reference may consume `quantity` units of the feature right now. */
|
|
151
|
-
readonly allowed: boolean;
|
|
152
|
-
/** Remaining units this period (`limit - used`), for metered features only. */
|
|
153
|
-
readonly balance?: number;
|
|
154
|
-
/** The plan-granted cap, for metered features only. */
|
|
155
|
-
readonly limit?: number;
|
|
156
|
-
/** True for a boolean feature granted without a numeric cap. */
|
|
157
|
-
readonly unlimited: boolean;
|
|
158
|
-
/** Usage consumed this period, for metered features only. */
|
|
159
|
-
readonly used?: number;
|
|
160
|
-
}
|
|
161
|
-
/** One feature's resolved allowance for a reference — a {@link CheckResult} tagged with its feature. */
|
|
162
|
-
interface FeatureBalance extends CheckResult {
|
|
163
|
-
readonly featureId: string;
|
|
164
|
-
}
|
|
165
|
-
/** Input the adapter forwards to the provider's metering API (Stripe Meter Events / Polar ingestion). */
|
|
166
|
-
interface ReportUsageInput {
|
|
167
|
-
/** Provider customer id, when known (Stripe meter events key on it). */
|
|
168
|
-
readonly customerId?: string;
|
|
169
|
-
readonly featureId: string;
|
|
170
|
-
readonly idempotencyKey: string;
|
|
171
|
-
readonly quantity: number;
|
|
172
|
-
readonly referenceId: string;
|
|
173
|
-
/** Event time in epoch ms; defaults to now at the provider. */
|
|
174
|
-
readonly timestamp?: number;
|
|
175
|
-
}
|
|
176
|
-
interface CaptureInput {
|
|
177
|
-
/** Partial capture amount; full capture when omitted. */
|
|
178
|
-
readonly amount?: Money;
|
|
179
|
-
readonly idempotencyKey?: string;
|
|
180
|
-
readonly sessionId: string;
|
|
181
|
-
}
|
|
182
|
-
interface RefundInput {
|
|
183
|
-
/** Partial refund amount; full refund when omitted. */
|
|
184
|
-
readonly amount?: Money;
|
|
185
|
-
readonly idempotencyKey?: string;
|
|
186
|
-
readonly reason?: string;
|
|
187
|
-
readonly sessionId: string;
|
|
188
|
-
}
|
|
189
|
-
interface CancelSubscriptionOptions {
|
|
190
|
-
/** Cancel at period end instead of immediately. */
|
|
191
|
-
readonly atPeriodEnd?: boolean;
|
|
192
|
-
readonly idempotencyKey?: string;
|
|
193
|
-
}
|
|
194
|
-
interface SubscriptionPatch {
|
|
195
|
-
readonly priceId?: string;
|
|
196
|
-
readonly quantity?: number;
|
|
197
|
-
}
|
|
198
|
-
/** Normalized webhook outcome — the *core state transition* a provider event implies. */
|
|
199
|
-
type WebhookActionType = "payment.authorized" | "payment.captured" | "payment.failed" | "payment.refunded" | "subscription.active" | "subscription.canceled" | "subscription.past_due" | "subscription.paused" | "subscription.updated" | "unhandled";
|
|
200
|
-
/**
|
|
201
|
-
* How a refund action's {@link WebhookAction.amount} should be interpreted by the sync layer.
|
|
202
|
-
*
|
|
203
|
-
* `"delta"` is an incremental amount added to the running refunded total (Polar `refund.created`,
|
|
204
|
-
* and the historical default), so multiple events accumulate. `"absolute"` is the provider's
|
|
205
|
-
* cumulative refunded-to-date total (Stripe `charge.refunded` carries `amount_refunded`, which
|
|
206
|
-
* already sums all prior partial refunds); the sync layer sets the refunded total to this value
|
|
207
|
-
* rather than adding, so repeated partial-refund events do not over-count.
|
|
208
|
-
*
|
|
209
|
-
* Omitted means `"delta"`, preserving the original behavior for callers that predate this field.
|
|
210
|
-
*/
|
|
211
|
-
type RefundAmountKind = "absolute" | "delta";
|
|
212
|
-
interface WebhookAction {
|
|
213
|
-
readonly amount?: Money;
|
|
214
|
-
/**
|
|
215
|
-
* Interpretation of {@link WebhookAction.amount} for refund actions (`payment.refunded`).
|
|
216
|
-
* Defaults to `"delta"` when omitted. Ignored for non-refund actions.
|
|
217
|
-
*/
|
|
218
|
-
readonly amountKind?: RefundAmountKind;
|
|
219
|
-
readonly cancelAtPeriodEnd?: boolean;
|
|
220
|
-
readonly currentPeriodEnd?: number;
|
|
221
|
-
readonly currentPeriodStart?: number;
|
|
222
|
-
readonly customerId?: string;
|
|
223
|
-
/** Provider event id — the inbound idempotency key. */
|
|
224
|
-
readonly eventId: string;
|
|
225
|
-
readonly priceId?: string;
|
|
226
|
-
readonly provider: ProviderId;
|
|
227
|
-
readonly quantity?: number;
|
|
228
|
-
/** Raw provider event, retained for the events log / debugging. */
|
|
229
|
-
readonly raw?: unknown;
|
|
230
|
-
readonly referenceId?: string;
|
|
231
|
-
readonly sessionId?: string;
|
|
232
|
-
readonly subscriptionId?: string;
|
|
233
|
-
readonly type: WebhookActionType;
|
|
234
|
-
}
|
|
235
|
-
/** Result of applying a webhook action to the store. */
|
|
236
|
-
interface ApplyResult {
|
|
237
|
-
readonly applied: boolean;
|
|
238
|
-
readonly reason?: "duplicate" | "illegal_transition" | "invalid_refund_amount" | "ok" | "unhandled";
|
|
239
|
-
}
|
|
240
|
-
/** A read-only header bag; the platform `Headers` object satisfies it. */
|
|
241
|
-
interface WebhookHeaders {
|
|
242
|
-
get: (name: string) => null | string;
|
|
243
|
-
}
|
|
244
|
-
interface WebhookInput {
|
|
245
|
-
/** Request headers (signature schemes read provider-specific headers from here). */
|
|
246
|
-
readonly headers: WebhookHeaders;
|
|
247
|
-
/** Raw request body, exactly as received (required for signature verification). */
|
|
248
|
-
readonly payload: string;
|
|
249
|
-
}
|
|
250
|
-
/**
|
|
251
|
-
* A stateless translator between the provider API and Lunora's normalized vocabulary.
|
|
252
|
-
*
|
|
253
|
-
* Adapters never own state — they make provider calls and normalize provider events into a
|
|
254
|
-
* `WebhookAction`. All durable state lives in the payment store.
|
|
255
|
-
*/
|
|
256
|
-
interface PaymentAdapter {
|
|
257
|
-
cancelPayment: (sessionId: string, options?: {
|
|
258
|
-
idempotencyKey?: string;
|
|
259
|
-
}) => Promise<PaymentSession>;
|
|
260
|
-
cancelSubscription: (subscriptionId: string, options?: CancelSubscriptionOptions) => Promise<Subscription>;
|
|
261
|
-
readonly capabilities: ProviderCapabilities;
|
|
262
|
-
capturePayment: (input: CaptureInput) => Promise<PaymentSession>;
|
|
263
|
-
createCheckout: (input: CheckoutInput) => Promise<CheckoutResult>;
|
|
264
|
-
createPortalSession: (input: PortalInput) => Promise<{
|
|
265
|
-
url: string;
|
|
266
|
-
}>;
|
|
267
|
-
getOrCreateCustomer: (ref: CustomerRef) => Promise<Customer>;
|
|
268
|
-
/** Fetch the provider's current truth for a payment session — the basis for reconciliation. */
|
|
269
|
-
getPaymentStatus: (sessionId: string) => Promise<PaymentSession>;
|
|
270
|
-
/** Fetch the provider's current truth for a subscription — the basis for reconciliation. */
|
|
271
|
-
getSubscriptionStatus: (subscriptionId: string) => Promise<Subscription>;
|
|
272
|
-
/** Stable provider identifier (Medusa-style). */
|
|
273
|
-
readonly identifier: ProviderId;
|
|
274
|
-
/** Verify the signature over the raw body, then normalize the event. Throws on invalid signature. */
|
|
275
|
-
parseWebhook: (input: WebhookInput) => Promise<WebhookAction>;
|
|
276
|
-
refundPayment: (input: RefundInput) => Promise<PaymentSession>;
|
|
277
|
-
/**
|
|
278
|
-
* Forward metered usage to the provider's billing API. Optional — present only on providers
|
|
279
|
-
* whose `capabilities.usageMetering` is `true` and that expose an ingestion endpoint. When
|
|
280
|
-
* absent, `track` still records usage durably and `check` enforces limits locally.
|
|
281
|
-
*/
|
|
282
|
-
reportUsage?: (input: ReportUsageInput) => Promise<void>;
|
|
283
|
-
resumeSubscription: (subscriptionId: string) => Promise<Subscription>;
|
|
284
|
-
updateSubscription: (subscriptionId: string, patch: SubscriptionPatch) => Promise<Subscription>;
|
|
285
|
-
}
|
|
286
|
-
/** Registry of adapters keyed by provider id — supports dual-register during provider migration. */
|
|
287
|
-
interface AdapterRegistry {
|
|
288
|
-
all: () => PaymentAdapter[];
|
|
289
|
-
get: (provider: ProviderId) => PaymentAdapter;
|
|
290
|
-
has: (provider: ProviderId) => boolean;
|
|
291
|
-
}
|
|
292
|
-
declare const createAdapterRegistry: (adapters: ReadonlyArray<PaymentAdapter>) => AdapterRegistry;
|
|
6
|
+
* `PaymentStore` is part of the experimental `@lunora/payment` API and may change without a major version bump.
|
|
7
|
+
* @experimental
|
|
8
|
+
*/
|
|
293
9
|
interface PaymentStore {
|
|
294
10
|
getCustomerByReference: (provider: ProviderId, referenceId: string) => Promise<Customer | undefined>;
|
|
295
11
|
getPaymentSession: (provider: ProviderId, id: string) => Promise<PaymentSession | undefined>;
|
|
296
12
|
getSubscription: (provider: ProviderId, id: string) => Promise<Subscription | undefined>;
|
|
297
13
|
listSubscriptionsByReference: (referenceId: string) => Promise<Subscription[]>;
|
|
298
14
|
/**
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
15
|
+
* Usage events that still owe an upstream forward, oldest first, at most `limit`.
|
|
16
|
+
*
|
|
17
|
+
* "Owes a forward" is narrower than `reportedToProvider === false`: only an
|
|
18
|
+
* ADDITIVE event with a positive `quantity` qualifies. A `"set"` event's
|
|
19
|
+
* upstream delta was measured against the period total at the moment it was
|
|
20
|
+
* recorded and is not recoverable afterwards, and a non-positive quantity was
|
|
21
|
+
* never sent, so neither is a retry candidate — returning them would make the
|
|
22
|
+
* sweep re-send the same rows forever (or double-count on an additive meter).
|
|
23
|
+
*
|
|
24
|
+
* Read by `reconcile` to retry a forward the provider rejected transiently;
|
|
25
|
+
* without it a single 5xx loses that metered unit upstream for good, which for
|
|
26
|
+
* a provider that owns entitlements under-bills and over-entitles the customer.
|
|
27
|
+
*/
|
|
28
|
+
listUnreportedUsage: (provider: ProviderId, limit: number) => Promise<UsageEvent[]>;
|
|
29
|
+
/**
|
|
30
|
+
* Claims a provider event id for processing. Resolves `true` the first time an event is seen
|
|
31
|
+
* and `false` for a duplicate — the inbound-idempotency primitive.
|
|
32
|
+
*/
|
|
302
33
|
markEventProcessed: (provider: ProviderId, eventId: string) => Promise<boolean>;
|
|
303
34
|
/** Flag a recorded usage event as forwarded to the provider's metering API. */
|
|
304
35
|
markUsageReported: (provider: ProviderId, idempotencyKey: string) => Promise<void>;
|
|
305
36
|
/**
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
37
|
+
* Append a usage event. Resolves `true` when newly recorded and `false` when its
|
|
38
|
+
* `idempotencyKey` was already seen — the exactly-once primitive behind `track`.
|
|
39
|
+
*/
|
|
309
40
|
recordUsage: (event: UsageEvent) => Promise<boolean>;
|
|
310
41
|
/**
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
42
|
+
* Release a previously-claimed event id (see {@link PaymentStore.markEventProcessed}) so a
|
|
43
|
+
* provider retry can re-process it. Called only when applying the claimed event *throws* (a
|
|
44
|
+
* genuine store-write failure): the atomic insert-claim guards concurrent duplicates, but a
|
|
45
|
+
* claim that outlives a failed apply would dedupe the retry and lose the effect — so the claim
|
|
46
|
+
* is rolled back on failure. A no-op if the id was never claimed.
|
|
47
|
+
*/
|
|
317
48
|
releaseEvent: (provider: ProviderId, eventId: string) => Promise<void>;
|
|
318
|
-
/**
|
|
49
|
+
/**
|
|
50
|
+
* The period total for a `(referenceId, featureId)` pair since `since` (epoch ms).
|
|
51
|
+
*
|
|
52
|
+
* NOT a plain sum: events are folded in `createdAt` order (ties broken by
|
|
53
|
+
* `idempotencyKey`, so every store agrees on the same order for events stamped
|
|
54
|
+
* in the same millisecond). An `"add"` event increments the running total; a
|
|
55
|
+
* `"set"` event RESETS it to that event's `quantity`, discarding everything
|
|
56
|
+
* earlier in the period. Use {@link foldUsage} so the two implementations
|
|
57
|
+
* cannot drift.
|
|
58
|
+
*
|
|
59
|
+
* This fold is what lets `track({ mode: "set" })` be append-only. Reconciling by
|
|
60
|
+
* writing `target - current` instead would be a read-modify-write across two
|
|
61
|
+
* un-transacted store calls: two interleaved `set`s would both read the same
|
|
62
|
+
* total, both append a delta, and leave the period over- or under-counted —
|
|
63
|
+
* inflating `balance = limit - used`. Here a concurrent pair simply resolves
|
|
64
|
+
* last-writer-wins, and a replayed `set` is idempotent by construction.
|
|
65
|
+
*/
|
|
319
66
|
sumUsage: (referenceId: string, featureId: string, since: number) => Promise<number>;
|
|
67
|
+
/** Period usage totals for many features in one read — the batch form of {@link PaymentStore.sumUsage}. */
|
|
68
|
+
sumUsageByFeature: (referenceId: string, featureIds: ReadonlyArray<string>, since: number) => Promise<ReadonlyMap<string, number>>;
|
|
320
69
|
upsertCustomer: (customer: Customer) => Promise<void>;
|
|
321
70
|
upsertPaymentSession: (session: PaymentSession) => Promise<void>;
|
|
322
71
|
upsertSubscription: (subscription: Subscription) => Promise<void>;
|
|
323
72
|
}
|
|
324
|
-
/**
|
|
73
|
+
/**
|
|
74
|
+
* In-memory {@link PaymentStore} for tests and local development. Not durable.
|
|
75
|
+
* @experimental
|
|
76
|
+
*/
|
|
325
77
|
declare class MemoryPaymentStore implements PaymentStore {
|
|
326
78
|
private readonly customers;
|
|
327
79
|
private readonly processedEvents;
|
|
@@ -332,15 +84,21 @@ declare class MemoryPaymentStore implements PaymentStore {
|
|
|
332
84
|
getPaymentSession(provider: ProviderId, id: string): Promise<PaymentSession | undefined>;
|
|
333
85
|
getSubscription(provider: ProviderId, id: string): Promise<Subscription | undefined>;
|
|
334
86
|
listSubscriptionsByReference(referenceId: string): Promise<Subscription[]>;
|
|
87
|
+
listUnreportedUsage(provider: ProviderId, limit: number): Promise<UsageEvent[]>;
|
|
335
88
|
markEventProcessed(provider: ProviderId, eventId: string): Promise<boolean>;
|
|
336
89
|
releaseEvent(provider: ProviderId, eventId: string): Promise<void>;
|
|
337
90
|
markUsageReported(provider: ProviderId, idempotencyKey: string): Promise<void>;
|
|
338
91
|
recordUsage(event: UsageEvent): Promise<boolean>;
|
|
339
92
|
sumUsage(referenceId: string, featureId: string, since: number): Promise<number>;
|
|
93
|
+
sumUsageByFeature(referenceId: string, featureIds: ReadonlyArray<string>, since: number): Promise<ReadonlyMap<string, number>>;
|
|
340
94
|
upsertCustomer(customer: Customer): Promise<void>;
|
|
341
95
|
upsertPaymentSession(session: PaymentSession): Promise<void>;
|
|
342
96
|
upsertSubscription(subscription: Subscription): Promise<void>;
|
|
343
97
|
}
|
|
98
|
+
/**
|
|
99
|
+
* `PlanDefinition` is part of the experimental `@lunora/payment` API and may change without a major version bump.
|
|
100
|
+
* @experimental
|
|
101
|
+
*/
|
|
344
102
|
interface PlanDefinition {
|
|
345
103
|
/** Feature flags this plan grants. */
|
|
346
104
|
readonly features?: ReadonlyArray<string>;
|
|
@@ -349,10 +107,18 @@ interface PlanDefinition {
|
|
|
349
107
|
/** Provider price/product ids that grant this plan. */
|
|
350
108
|
readonly priceIds: ReadonlyArray<string>;
|
|
351
109
|
}
|
|
110
|
+
/**
|
|
111
|
+
* `EntitlementsConfig` is part of the experimental `@lunora/payment` API and may change without a major version bump.
|
|
112
|
+
* @experimental
|
|
113
|
+
*/
|
|
352
114
|
interface EntitlementsConfig {
|
|
353
115
|
/** Plan name → definition. */
|
|
354
116
|
readonly plans: Record<string, PlanDefinition>;
|
|
355
117
|
}
|
|
118
|
+
/**
|
|
119
|
+
* `Entitlements` is part of the experimental `@lunora/payment` API and may change without a major version bump.
|
|
120
|
+
* @experimental
|
|
121
|
+
*/
|
|
356
122
|
interface Entitlements {
|
|
357
123
|
readonly features: ReadonlySet<string>;
|
|
358
124
|
/** True when an active subscription grants `feature`. */
|
|
@@ -363,19 +129,36 @@ interface Entitlements {
|
|
|
363
129
|
readonly plans: ReadonlyArray<string>;
|
|
364
130
|
}
|
|
365
131
|
/**
|
|
366
|
-
* Start of the window `check` sums metered usage over: the most recent billing-period start among
|
|
367
|
-
* a reference's active subscriptions. `0` (count all-time) when no active subscription reports one
|
|
368
|
-
* — limits still bind, they just never reset until the provider sends a period.
|
|
369
|
-
|
|
132
|
+
* Start of the window `check` sums metered usage over: the most recent billing-period start among
|
|
133
|
+
* a reference's active subscriptions. `0` (count all-time) when no active subscription reports one
|
|
134
|
+
* — limits still bind, they just never reset until the provider sends a period.
|
|
135
|
+
* @experimental
|
|
136
|
+
*/
|
|
370
137
|
declare const usagePeriodStart: (subscriptions: ReadonlyArray<Subscription>) => number;
|
|
371
|
-
/**
|
|
138
|
+
/**
|
|
139
|
+
* Every feature name a config can grant — the union of `features` flags and `limits` keys across all plans, sorted.
|
|
140
|
+
* @experimental
|
|
141
|
+
*/
|
|
372
142
|
declare const featureNames: (config: EntitlementsConfig) => string[];
|
|
373
|
-
/**
|
|
143
|
+
/**
|
|
144
|
+
* Whether the reference holds an entitling (active/trialing) subscription on `priceId` — the basis of a product `check`.
|
|
145
|
+
* @experimental
|
|
146
|
+
*/
|
|
374
147
|
declare const hasActivePrice: (subscriptions: ReadonlyArray<Subscription>, priceId: string) => boolean;
|
|
375
|
-
/**
|
|
148
|
+
/**
|
|
149
|
+
* Derive {@link Entitlements} from a reference's subscriptions. Pure — the basis of `check`.
|
|
150
|
+
* @experimental
|
|
151
|
+
*/
|
|
376
152
|
declare const resolveEntitlements: (config: EntitlementsConfig, subscriptions: ReadonlyArray<Subscription>) => Entitlements;
|
|
377
|
-
/**
|
|
153
|
+
/**
|
|
154
|
+
* Convenience: resolve entitlements straight from the store for a reference.
|
|
155
|
+
* @experimental
|
|
156
|
+
*/
|
|
378
157
|
declare const entitlementsForReference: (store: PaymentStore, config: EntitlementsConfig, referenceId: string) => Promise<Entitlements>;
|
|
158
|
+
/**
|
|
159
|
+
* `PaymentEvent` is part of the experimental `@lunora/payment` API and may change without a major version bump.
|
|
160
|
+
* @experimental
|
|
161
|
+
*/
|
|
379
162
|
type PaymentEvent = {
|
|
380
163
|
action: WebhookActionType;
|
|
381
164
|
eventId: string;
|
|
@@ -420,15 +203,26 @@ type PaymentEvent = {
|
|
|
420
203
|
referenceId: string;
|
|
421
204
|
type: "usage.report_failed";
|
|
422
205
|
};
|
|
206
|
+
/**
|
|
207
|
+
* `PaymentObserver` is part of the experimental `@lunora/payment` API and may change without a major version bump.
|
|
208
|
+
* @experimental
|
|
209
|
+
*/
|
|
423
210
|
type PaymentObserver = (event: PaymentEvent) => void;
|
|
424
|
-
/**
|
|
211
|
+
/**
|
|
212
|
+
* Returns whether the current caller may act on `referenceId`. Throwing is also treated as denial.
|
|
213
|
+
* @experimental
|
|
214
|
+
*/
|
|
425
215
|
type AuthorizeReference = (referenceId: string) => boolean | Promise<boolean>;
|
|
216
|
+
/**
|
|
217
|
+
* `CreatePaymentOptions` is part of the experimental `@lunora/payment` API and may change without a major version bump.
|
|
218
|
+
* @experimental
|
|
219
|
+
*/
|
|
426
220
|
interface CreatePaymentOptions {
|
|
427
221
|
readonly adapter: PaymentAdapter;
|
|
428
222
|
/**
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
223
|
+
* Per-caller authorization for every mutation. Return `false` to reject with 403. Omit only
|
|
224
|
+
* for trusted server-internal callers (e.g. the reconciliation sweep).
|
|
225
|
+
*/
|
|
432
226
|
readonly authorize?: AuthorizeReference;
|
|
433
227
|
/** Plan → features/limits map. Required for `check`; omit if you don't gate features. */
|
|
434
228
|
readonly entitlements?: EntitlementsConfig;
|
|
@@ -436,73 +230,151 @@ interface CreatePaymentOptions {
|
|
|
436
230
|
readonly observability?: PaymentObserver;
|
|
437
231
|
readonly store: PaymentStore;
|
|
438
232
|
}
|
|
233
|
+
/**
|
|
234
|
+
* `LunoraPayment` is part of the experimental `@lunora/payment` API and may change without a major version bump.
|
|
235
|
+
* @experimental
|
|
236
|
+
*/
|
|
439
237
|
interface LunoraPayment {
|
|
440
238
|
readonly adapter: PaymentAdapter;
|
|
441
239
|
/**
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
240
|
+
* Subscribe a reference to a plan — a plan-oriented alias of {@link LunoraPayment.createCheckout}
|
|
241
|
+
* with `mode` defaulting to `"subscription"`. Returns a hosted-checkout URL to redirect to.
|
|
242
|
+
*/
|
|
445
243
|
attach: (input: AttachInput) => Promise<CheckoutResult>;
|
|
244
|
+
/** Cancel the caller's own uncaptured payment (authorized, derived idempotency key, store synced). */
|
|
245
|
+
cancelPayment: (sessionId: string, options?: {
|
|
246
|
+
idempotencyKey?: string;
|
|
247
|
+
}) => Promise<PaymentSession>;
|
|
446
248
|
cancelSubscription: (subscriptionId: string, options?: CancelSubscriptionOptions) => Promise<Subscription>;
|
|
249
|
+
/** Capture the caller's own authorized payment (authorized, derived idempotency key, store synced). */
|
|
250
|
+
capturePayment: (input: CaptureInput) => Promise<PaymentSession>;
|
|
447
251
|
/**
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
252
|
+
* Is a reference allowed something right now? Pass `featureId` to check a grant/allowance (boolean
|
|
253
|
+
* features check plan grants; metered features subtract usage tracked this period) or `priceId` to
|
|
254
|
+
* check active access to a product. The feature path requires `entitlements` to be configured.
|
|
255
|
+
*/
|
|
452
256
|
check: (input: CheckInput) => Promise<CheckResult>;
|
|
453
257
|
createCheckout: (input: CheckoutInput) => Promise<CheckoutResult>;
|
|
454
258
|
/** Open the provider billing portal for the caller's own customer (derived from the store). */
|
|
455
259
|
createPortalSession: (referenceId: string, returnUrl: string) => Promise<{
|
|
456
260
|
url: string;
|
|
457
261
|
}>;
|
|
458
|
-
/**
|
|
262
|
+
/**
|
|
263
|
+
* Verify + normalize + apply a provider webhook. 200 once verified, even on a no-op — except an
|
|
264
|
+
* event whose target row doesn't exist yet, which returns 500 so the provider redelivers it once.
|
|
265
|
+
*/
|
|
459
266
|
handleWebhook: (request: Request) => Promise<Response>;
|
|
460
267
|
/** Resolve every configured feature's allowance for a reference in one call. Requires `entitlements`. */
|
|
461
268
|
listBalances: (referenceId: string) => Promise<FeatureBalance[]>;
|
|
462
269
|
listSubscriptions: (referenceId: string) => Promise<Subscription[]>;
|
|
270
|
+
/** Refund the caller's own captured payment (authorized, derived idempotency key, store synced). */
|
|
271
|
+
refundPayment: (input: RefundInput) => Promise<PaymentSession>;
|
|
463
272
|
readonly store: PaymentStore;
|
|
464
273
|
/**
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
274
|
+
* Record metered usage for a reference's feature — durably (exactly-once by idempotency key) and,
|
|
275
|
+
* when the provider supports it, forwarded to its metering API. Best-effort upstream: a reporting
|
|
276
|
+
* failure is observed, never thrown, and the local ledger that `check` reads is always updated.
|
|
277
|
+
*/
|
|
469
278
|
track: (input: TrackInput) => Promise<TrackResult>;
|
|
470
279
|
}
|
|
280
|
+
/**
|
|
281
|
+
* `createPayment` is part of the experimental `@lunora/payment` API and may change without a major version bump.
|
|
282
|
+
* @experimental
|
|
283
|
+
*/
|
|
471
284
|
declare const createPayment: (options: CreatePaymentOptions) => LunoraPayment;
|
|
472
|
-
/**
|
|
285
|
+
/**
|
|
286
|
+
* A stored row, carrying Lunora's document id.
|
|
287
|
+
* @experimental
|
|
288
|
+
*/
|
|
473
289
|
interface PaymentRow extends Record<string, unknown> {
|
|
474
290
|
readonly _id: string;
|
|
475
291
|
}
|
|
476
|
-
/**
|
|
292
|
+
/**
|
|
293
|
+
* Bounded-read arguments for {@link PaymentDatabase.findMany}, mirroring what
|
|
294
|
+
* Lunora's `ctx.db.findMany` already accepts. `where` stays equality-only — these
|
|
295
|
+
* are the knobs that let a caller bound the number of rows FETCHED rather than
|
|
296
|
+
* fetching everything and slicing afterwards.
|
|
297
|
+
* @experimental
|
|
298
|
+
*/
|
|
299
|
+
interface PaymentPageArgs {
|
|
300
|
+
/** Keyset cursor from a previous page's {@link PaymentPage.cursor}. */
|
|
301
|
+
cursor?: string;
|
|
302
|
+
/** Maximum rows to FETCH. Omit to read every match. */
|
|
303
|
+
limit?: number;
|
|
304
|
+
/** Sort keys, pushed down to the store so the keyset cursor is well-defined. */
|
|
305
|
+
orderBy?: Record<string, "asc" | "desc">[];
|
|
306
|
+
}
|
|
307
|
+
/**
|
|
308
|
+
* One page of rows plus the cursor that continues it.
|
|
309
|
+
* @experimental
|
|
310
|
+
*/
|
|
311
|
+
interface PaymentPage {
|
|
312
|
+
/** Cursor for the next page, or `undefined` when this was the last one. */
|
|
313
|
+
readonly cursor: string | undefined;
|
|
314
|
+
readonly rows: PaymentRow[];
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* Minimal write/read surface this store needs; `ctx.db` satisfies it structurally.
|
|
318
|
+
* @experimental
|
|
319
|
+
*/
|
|
477
320
|
interface PaymentDatabase {
|
|
478
321
|
delete: (id: string) => Promise<void>;
|
|
479
322
|
findFirst: (table: string, where: Record<string, unknown>) => Promise<PaymentRow | null>;
|
|
480
|
-
|
|
323
|
+
/**
|
|
324
|
+
* Equality-only `where`, with optional order/limit/cursor pushed DOWN to the
|
|
325
|
+
* store (see {@link PaymentPageArgs}). Omitting `page` reads every match — do
|
|
326
|
+
* that only where the match set is inherently small (one reference's rows).
|
|
327
|
+
*/
|
|
328
|
+
findMany: (table: string, where: Record<string, unknown>, page?: PaymentPageArgs) => Promise<PaymentPage>;
|
|
481
329
|
insert: (table: string, document: Record<string, unknown>) => Promise<string>;
|
|
482
330
|
patch: (id: string, patch: Record<string, unknown>) => Promise<void>;
|
|
483
331
|
}
|
|
332
|
+
/**
|
|
333
|
+
* `createDatabasePaymentStore` is part of the experimental `@lunora/payment` API and may change without a major version bump.
|
|
334
|
+
* @experimental
|
|
335
|
+
*/
|
|
484
336
|
declare const createDatabasePaymentStore: (database: PaymentDatabase) => PaymentStore;
|
|
485
|
-
/**
|
|
337
|
+
/**
|
|
338
|
+
* Structural subset of Lunora's `ctx.db` (the `findFirst`/`findMany(tableName, { where })` form).
|
|
339
|
+
*
|
|
340
|
+
* `findMany` models the order/limit/cursor knobs too — {@link PaymentDatabase}
|
|
341
|
+
* pushes them down so a sweep over a large match set reads bounded chunks
|
|
342
|
+
* instead of materialising the lot. `continueCursor` is REQUIRED here (`ctx.db`
|
|
343
|
+
* always returns it): a double that omitted it would page exactly once and then
|
|
344
|
+
* silently report the rest of the table as absent.
|
|
345
|
+
* @experimental
|
|
346
|
+
*/
|
|
486
347
|
interface LunoraDatabaseLike {
|
|
487
348
|
delete: (id: string) => Promise<void>;
|
|
488
349
|
findFirst: (table: string, args?: {
|
|
489
350
|
where?: Record<string, unknown>;
|
|
490
351
|
}) => Promise<Record<string, unknown> | null>;
|
|
491
352
|
findMany: (table: string, args?: {
|
|
353
|
+
cursor?: string;
|
|
354
|
+
limit?: number;
|
|
355
|
+
orderBy?: Record<string, "asc" | "desc">[];
|
|
492
356
|
where?: Record<string, unknown>;
|
|
493
357
|
}) => Promise<{
|
|
358
|
+
continueCursor: null | string;
|
|
494
359
|
page: Record<string, unknown>[];
|
|
495
360
|
}>;
|
|
496
361
|
insert: (table: string, document: Record<string, unknown>) => Promise<string>;
|
|
497
362
|
patch: (id: string, patch: Record<string, unknown>) => Promise<void>;
|
|
498
363
|
}
|
|
499
|
-
/**
|
|
364
|
+
/**
|
|
365
|
+
* Structural subset of a Lunora function context used to build payments.
|
|
366
|
+
* @experimental
|
|
367
|
+
*/
|
|
500
368
|
interface PaymentContextLike {
|
|
501
369
|
auth?: {
|
|
502
370
|
userId?: null | string;
|
|
503
371
|
};
|
|
504
372
|
db: LunoraDatabaseLike;
|
|
505
373
|
}
|
|
374
|
+
/**
|
|
375
|
+
* `PaymentsFromContextOptions` is part of the experimental `@lunora/payment` API and may change without a major version bump.
|
|
376
|
+
* @experimental
|
|
377
|
+
*/
|
|
506
378
|
interface PaymentsFromContextOptions {
|
|
507
379
|
readonly adapter: PaymentAdapter;
|
|
508
380
|
/** Override the default "caller owns the referenceId" authorization. */
|
|
@@ -512,190 +384,90 @@ interface PaymentsFromContextOptions {
|
|
|
512
384
|
/** Optional telemetry sink, forwarded to the facade. */
|
|
513
385
|
readonly observability?: PaymentObserver;
|
|
514
386
|
}
|
|
515
|
-
/**
|
|
387
|
+
/**
|
|
388
|
+
* Adapt a Lunora `ctx.db` to the {@link PaymentDatabase} port the store writes through.
|
|
389
|
+
* @experimental
|
|
390
|
+
*/
|
|
516
391
|
declare const lunoraDatabaseToPaymentDatabase: (database: LunoraDatabaseLike) => PaymentDatabase;
|
|
392
|
+
/**
|
|
393
|
+
* `paymentsFromContext` is part of the experimental `@lunora/payment` API and may change without a major version bump.
|
|
394
|
+
* @experimental
|
|
395
|
+
*/
|
|
517
396
|
declare const paymentsFromContext: (context: PaymentContextLike, options: PaymentsFromContextOptions) => LunoraPayment;
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
397
|
+
/**
|
|
398
|
+
* `PaymentErrorCode` is part of the experimental `@lunora/payment` API and may change without a major version bump.
|
|
399
|
+
* @experimental
|
|
400
|
+
*/
|
|
401
|
+
type PaymentErrorCode = "CONFIG_INVALID" | "CURRENCY_MISMATCH" | "FORBIDDEN" | "INVALID_TRANSITION" | "NOT_FOUND" | "PROVIDER_ERROR" | "VALIDATION_ERROR" | "WEBHOOK_EVENT_ID_MISSING" | "WEBHOOK_SIGNATURE_INVALID" | "WEBHOOK_TIMESTAMP_INVALID";
|
|
402
|
+
/**
|
|
403
|
+
* Typed error for all `@lunora/payment` failures. A `LunoraError` subclass; `status` maps onto an HTTP response.
|
|
404
|
+
* @experimental
|
|
405
|
+
*/
|
|
406
|
+
declare class LunoraPaymentError extends LunoraError {
|
|
521
407
|
readonly code: PaymentErrorCode;
|
|
522
|
-
readonly status: number;
|
|
523
408
|
constructor(code: PaymentErrorCode, message: string);
|
|
524
409
|
}
|
|
525
410
|
/**
|
|
526
|
-
*
|
|
527
|
-
*
|
|
528
|
-
|
|
529
|
-
* a Worker retry can never double-charge. Distinct from inbound webhook dedupe (keyed on the
|
|
530
|
-
* provider event id).
|
|
531
|
-
*/
|
|
532
|
-
/** Build a deterministic idempotency key from an operation name and stable parts. */
|
|
411
|
+
* Build a deterministic idempotency key from an operation name and stable parts.
|
|
412
|
+
* @experimental
|
|
413
|
+
*/
|
|
533
414
|
declare const idempotencyKey: (operation: string, ...parts: ReadonlyArray<number | string>) => string;
|
|
534
|
-
/**
|
|
415
|
+
/**
|
|
416
|
+
* True when the currency has no minor unit (e.g. JPY).
|
|
417
|
+
*/
|
|
535
418
|
declare const isZeroDecimalCurrency: (currency: CurrencyCode) => boolean;
|
|
536
|
-
/**
|
|
419
|
+
/**
|
|
420
|
+
* Construct money. Currency is normalized to uppercase; never use floats for amounts.
|
|
421
|
+
*/
|
|
537
422
|
declare const money: (minorUnits: bigint | number, currency: CurrencyCode) => Money;
|
|
423
|
+
/**
|
|
424
|
+
* Zero in the given currency.
|
|
425
|
+
*/
|
|
538
426
|
declare const zeroMoney: (currency: CurrencyCode) => Money;
|
|
539
|
-
/**
|
|
427
|
+
/**
|
|
428
|
+
* Localized currency string for display (e.g. `$19.99`). For UI only — never for arithmetic.
|
|
429
|
+
*/
|
|
540
430
|
declare const formatMoney: (value: Money, locale?: string) => string;
|
|
431
|
+
/**
|
|
432
|
+
* Sum of two same-currency amounts. Throws `CURRENCY_MISMATCH` otherwise.
|
|
433
|
+
*/
|
|
541
434
|
declare const addMoney: (a: Money, b: Money) => Money;
|
|
435
|
+
/**
|
|
436
|
+
* Difference of two same-currency amounts. Throws `CURRENCY_MISMATCH` otherwise.
|
|
437
|
+
*/
|
|
542
438
|
declare const subtractMoney: (a: Money, b: Money) => Money;
|
|
543
|
-
/**
|
|
439
|
+
/**
|
|
440
|
+
* Compares two same-currency amounts, returning -1, 0, or 1.
|
|
441
|
+
*/
|
|
544
442
|
declare const compareMoney: (a: Money, b: Money) => -1 | 0 | 1;
|
|
545
443
|
/**
|
|
546
|
-
* Split an amount across integer ratios, distributing the remainder to the smallest unit so the
|
|
547
|
-
* parts always sum back to the original. The basis for seat/proration math.
|
|
548
|
-
*/
|
|
444
|
+
* Split an amount across integer ratios, distributing the remainder to the smallest unit so the
|
|
445
|
+
* parts always sum back to the original. The basis for seat/proration math.
|
|
446
|
+
*/
|
|
549
447
|
declare const allocateMoney: (amount: Money, ratios: ReadonlyArray<bigint>) => Money[];
|
|
448
|
+
/**
|
|
449
|
+
* True when the amount is exactly zero minor units.
|
|
450
|
+
*/
|
|
550
451
|
declare const isZeroMoney: (a: Money) => boolean;
|
|
551
|
-
/**
|
|
452
|
+
/**
|
|
453
|
+
* JSON-safe wire form of money (bigint encoded as a decimal string).
|
|
454
|
+
*/
|
|
552
455
|
interface MoneyJSON {
|
|
553
456
|
readonly currency: CurrencyCode;
|
|
554
457
|
readonly minorUnits: string;
|
|
555
458
|
}
|
|
459
|
+
/**
|
|
460
|
+
* Encode money for the wire — `minorUnits` becomes a decimal string.
|
|
461
|
+
*/
|
|
556
462
|
declare const toMoneyJSON: (m: Money) => MoneyJSON;
|
|
463
|
+
/**
|
|
464
|
+
* Decode the wire form back to a `bigint`-backed {@link Money}.
|
|
465
|
+
*/
|
|
557
466
|
declare const fromMoneyJSON: (json: MoneyJSON) => Money;
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
readonly customerId?: null | string;
|
|
563
|
-
readonly id: string;
|
|
564
|
-
readonly metadata?: Record<string, string>;
|
|
565
|
-
readonly productId?: string;
|
|
566
|
-
readonly status: string;
|
|
567
|
-
}
|
|
568
|
-
interface PolarOrderLike {
|
|
569
|
-
readonly amount?: number;
|
|
570
|
-
readonly currency?: string;
|
|
571
|
-
readonly id: string;
|
|
572
|
-
readonly status: string;
|
|
573
|
-
readonly totalAmount?: number;
|
|
574
|
-
}
|
|
575
|
-
interface PolarClientLike {
|
|
576
|
-
readonly checkouts: {
|
|
577
|
-
create: (parameters: Record<string, unknown>) => Promise<{
|
|
578
|
-
id: string;
|
|
579
|
-
url: string;
|
|
580
|
-
}>;
|
|
581
|
-
};
|
|
582
|
-
readonly customers: {
|
|
583
|
-
create: (parameters: Record<string, unknown>) => Promise<{
|
|
584
|
-
email: null | string;
|
|
585
|
-
id: string;
|
|
586
|
-
}>;
|
|
587
|
-
};
|
|
588
|
-
readonly customerSessions: {
|
|
589
|
-
create: (parameters: Record<string, unknown>) => Promise<{
|
|
590
|
-
customerPortalUrl: string;
|
|
591
|
-
}>;
|
|
592
|
-
};
|
|
593
|
-
readonly events: {
|
|
594
|
-
ingest: (parameters: Record<string, unknown>) => Promise<{
|
|
595
|
-
inserted?: number;
|
|
596
|
-
}>;
|
|
597
|
-
};
|
|
598
|
-
readonly orders: {
|
|
599
|
-
get: (parameters: Record<string, unknown>) => Promise<PolarOrderLike>;
|
|
600
|
-
};
|
|
601
|
-
readonly refunds: {
|
|
602
|
-
create: (parameters: Record<string, unknown>) => Promise<{
|
|
603
|
-
id: string;
|
|
604
|
-
}>;
|
|
605
|
-
};
|
|
606
|
-
readonly subscriptions: {
|
|
607
|
-
get: (parameters: Record<string, unknown>) => Promise<PolarSubscriptionLike>;
|
|
608
|
-
revoke: (parameters: Record<string, unknown>) => Promise<PolarSubscriptionLike>;
|
|
609
|
-
update: (parameters: Record<string, unknown>) => Promise<PolarSubscriptionLike>;
|
|
610
|
-
};
|
|
611
|
-
}
|
|
612
|
-
interface PolarAdapterOptions {
|
|
613
|
-
readonly client: PolarClientLike;
|
|
614
|
-
readonly webhookSecret: string;
|
|
615
|
-
readonly webhookToleranceSeconds?: number;
|
|
616
|
-
}
|
|
617
|
-
declare const createPolarAdapter: (options: PolarAdapterOptions) => PaymentAdapter;
|
|
618
|
-
interface StripeRequestOptions {
|
|
619
|
-
readonly idempotencyKey?: string;
|
|
620
|
-
}
|
|
621
|
-
interface StripePaymentIntentLike {
|
|
622
|
-
readonly amount: number;
|
|
623
|
-
readonly amount_received?: number;
|
|
624
|
-
readonly currency: string;
|
|
625
|
-
readonly customer?: null | string;
|
|
626
|
-
readonly id: string;
|
|
627
|
-
readonly metadata?: Record<string, string>;
|
|
628
|
-
readonly status: string;
|
|
629
|
-
}
|
|
630
|
-
interface StripeSubscriptionLike {
|
|
631
|
-
readonly cancel_at_period_end?: boolean;
|
|
632
|
-
readonly current_period_end?: number;
|
|
633
|
-
readonly current_period_start?: number;
|
|
634
|
-
readonly customer?: null | string;
|
|
635
|
-
readonly id: string;
|
|
636
|
-
readonly items?: {
|
|
637
|
-
data: ReadonlyArray<{
|
|
638
|
-
price?: {
|
|
639
|
-
id?: string;
|
|
640
|
-
};
|
|
641
|
-
quantity?: number;
|
|
642
|
-
}>;
|
|
643
|
-
};
|
|
644
|
-
readonly metadata?: Record<string, string>;
|
|
645
|
-
readonly status: string;
|
|
646
|
-
}
|
|
647
|
-
/** The subset of the Stripe SDK surface this adapter calls. A real `Stripe` instance satisfies it. */
|
|
648
|
-
interface StripeClientLike {
|
|
649
|
-
readonly billing: {
|
|
650
|
-
meterEvents: {
|
|
651
|
-
create: (parameters: Record<string, unknown>, options?: StripeRequestOptions) => Promise<{
|
|
652
|
-
identifier?: string;
|
|
653
|
-
}>;
|
|
654
|
-
};
|
|
655
|
-
};
|
|
656
|
-
readonly billingPortal: {
|
|
657
|
-
sessions: {
|
|
658
|
-
create: (parameters: Record<string, unknown>) => Promise<{
|
|
659
|
-
url: string;
|
|
660
|
-
}>;
|
|
661
|
-
};
|
|
662
|
-
};
|
|
663
|
-
readonly checkout: {
|
|
664
|
-
sessions: {
|
|
665
|
-
create: (parameters: Record<string, unknown>, options?: StripeRequestOptions) => Promise<{
|
|
666
|
-
id: string;
|
|
667
|
-
url: null | string;
|
|
668
|
-
}>;
|
|
669
|
-
};
|
|
670
|
-
};
|
|
671
|
-
readonly customers: {
|
|
672
|
-
create: (parameters: Record<string, unknown>, options?: StripeRequestOptions) => Promise<{
|
|
673
|
-
email: null | string;
|
|
674
|
-
id: string;
|
|
675
|
-
}>;
|
|
676
|
-
};
|
|
677
|
-
readonly paymentIntents: {
|
|
678
|
-
cancel: (id: string, parameters?: Record<string, unknown>, options?: StripeRequestOptions) => Promise<StripePaymentIntentLike>;
|
|
679
|
-
capture: (id: string, parameters?: Record<string, unknown>, options?: StripeRequestOptions) => Promise<StripePaymentIntentLike>;
|
|
680
|
-
retrieve: (id: string) => Promise<StripePaymentIntentLike>;
|
|
681
|
-
};
|
|
682
|
-
readonly refunds: {
|
|
683
|
-
create: (parameters: Record<string, unknown>, options?: StripeRequestOptions) => Promise<{
|
|
684
|
-
id: string;
|
|
685
|
-
}>;
|
|
686
|
-
};
|
|
687
|
-
readonly subscriptions: {
|
|
688
|
-
cancel: (id: string, parameters?: Record<string, unknown>, options?: StripeRequestOptions) => Promise<StripeSubscriptionLike>;
|
|
689
|
-
retrieve: (id: string) => Promise<StripeSubscriptionLike>;
|
|
690
|
-
update: (id: string, parameters: Record<string, unknown>, options?: StripeRequestOptions) => Promise<StripeSubscriptionLike>;
|
|
691
|
-
};
|
|
692
|
-
}
|
|
693
|
-
interface StripeAdapterOptions {
|
|
694
|
-
readonly client: StripeClientLike;
|
|
695
|
-
readonly webhookSecret: string;
|
|
696
|
-
readonly webhookToleranceSeconds?: number;
|
|
697
|
-
}
|
|
698
|
-
declare const createStripeAdapter: (options: StripeAdapterOptions) => PaymentAdapter;
|
|
467
|
+
/**
|
|
468
|
+
* `ReconcileInput` is part of the experimental `@lunora/payment` API and may change without a major version bump.
|
|
469
|
+
* @experimental
|
|
470
|
+
*/
|
|
699
471
|
interface ReconcileInput {
|
|
700
472
|
readonly adapter: PaymentAdapter;
|
|
701
473
|
/** Optional telemetry sink — fired per drifted row and once on completion. */
|
|
@@ -703,56 +475,107 @@ interface ReconcileInput {
|
|
|
703
475
|
readonly paymentSessionIds?: ReadonlyArray<string>;
|
|
704
476
|
readonly store: PaymentStore;
|
|
705
477
|
readonly subscriptionIds?: ReadonlyArray<string>;
|
|
478
|
+
/**
|
|
479
|
+
* How many unreported usage events to retry forwarding upstream this sweep
|
|
480
|
+
* (oldest first). Default {@link DEFAULT_USAGE_REPORT_LIMIT}; `0` skips the
|
|
481
|
+
* usage sweep entirely. Ignored by an adapter that does not meter usage.
|
|
482
|
+
*/
|
|
483
|
+
readonly usageReportLimit?: number;
|
|
706
484
|
}
|
|
485
|
+
/**
|
|
486
|
+
* `ReconcileResult` is part of the experimental `@lunora/payment` API and may change without a major version bump.
|
|
487
|
+
* @experimental
|
|
488
|
+
*/
|
|
707
489
|
interface ReconcileResult {
|
|
708
490
|
readonly checkedPayments: number;
|
|
709
491
|
readonly checkedSubscriptions: number;
|
|
492
|
+
readonly checkedUsage: number;
|
|
710
493
|
readonly failedPayments: number;
|
|
711
494
|
readonly failedSubscriptions: number;
|
|
495
|
+
/** Usage events whose retried forward failed again — still pending for the next sweep. */
|
|
496
|
+
readonly failedUsage: number;
|
|
712
497
|
readonly updatedPayments: number;
|
|
713
498
|
readonly updatedSubscriptions: number;
|
|
499
|
+
/** Usage events successfully forwarded upstream on this sweep. */
|
|
500
|
+
readonly updatedUsage: number;
|
|
714
501
|
}
|
|
502
|
+
/**
|
|
503
|
+
* `reconcile` is part of the experimental `@lunora/payment` API and may change without a major version bump.
|
|
504
|
+
* @experimental
|
|
505
|
+
*/
|
|
715
506
|
declare const reconcile: (input: ReconcileInput) => Promise<ReconcileResult>;
|
|
507
|
+
/**
|
|
508
|
+
* The canonical column reference for the payment tables — a value to READ (in a test, a migration
|
|
509
|
+
* check, or your editor), not one to spread. `defineSchema({ ...paymentTables })` does NOT work:
|
|
510
|
+
* codegen discovers tables by parsing your `lunora/schema.ts` AST and cannot resolve a
|
|
511
|
+
* cross-package spread, so declare the same columns inline there (see the module docstring).
|
|
512
|
+
*
|
|
513
|
+
* `paymentTables` is part of the experimental `@lunora/payment` API and may change without a major version bump.
|
|
514
|
+
* @experimental
|
|
515
|
+
*/
|
|
716
516
|
declare const paymentTables: Record<string, TableDefinition>;
|
|
717
|
-
/**
|
|
517
|
+
/**
|
|
518
|
+
* Action that may advance a payment session.
|
|
519
|
+
* @experimental
|
|
520
|
+
*/
|
|
718
521
|
type PaymentAction = "authorize" | "cancel" | "capture" | "fail" | "partial_refund" | "refund";
|
|
719
|
-
/**
|
|
522
|
+
/**
|
|
523
|
+
* Action that may advance a subscription.
|
|
524
|
+
* @experimental
|
|
525
|
+
*/
|
|
720
526
|
type SubscriptionAction = "activate" | "cancel" | "mark_past_due" | "pause" | "renew" | "resume";
|
|
527
|
+
/**
|
|
528
|
+
* `PAYMENT_TERMINAL_STATES` is part of the experimental `@lunora/payment` API and may change without a major version bump.
|
|
529
|
+
* @experimental
|
|
530
|
+
*/
|
|
721
531
|
declare const PAYMENT_TERMINAL_STATES: ReadonlySet<PaymentState>;
|
|
532
|
+
/**
|
|
533
|
+
* `SUBSCRIPTION_TERMINAL_STATES` is part of the experimental `@lunora/payment` API and may change without a major version bump.
|
|
534
|
+
* @experimental
|
|
535
|
+
*/
|
|
722
536
|
declare const SUBSCRIPTION_TERMINAL_STATES: ReadonlySet<SubscriptionState>;
|
|
723
|
-
/**
|
|
537
|
+
/**
|
|
538
|
+
* Next payment state for an action, or `undefined` if the transition is illegal from `from`.
|
|
539
|
+
* @experimental
|
|
540
|
+
*/
|
|
724
541
|
declare const nextPaymentState: (from: PaymentState, action: PaymentAction) => PaymentState | undefined;
|
|
542
|
+
/**
|
|
543
|
+
* `canTransitionPayment` is part of the experimental `@lunora/payment` API and may change without a major version bump.
|
|
544
|
+
* @experimental
|
|
545
|
+
*/
|
|
725
546
|
declare const canTransitionPayment: (from: PaymentState, action: PaymentAction) => boolean;
|
|
726
|
-
/**
|
|
547
|
+
/**
|
|
548
|
+
* Next subscription state for an action, or `undefined` if the transition is illegal from `from`.
|
|
549
|
+
* @experimental
|
|
550
|
+
*/
|
|
727
551
|
declare const nextSubscriptionState: (from: SubscriptionState, action: SubscriptionAction) => SubscriptionState | undefined;
|
|
552
|
+
/**
|
|
553
|
+
* `canTransitionSubscription` is part of the experimental `@lunora/payment` API and may change without a major version bump.
|
|
554
|
+
* @experimental
|
|
555
|
+
*/
|
|
728
556
|
declare const canTransitionSubscription: (from: SubscriptionState, action: SubscriptionAction) => boolean;
|
|
557
|
+
/**
|
|
558
|
+
* `applyWebhookAction` is part of the experimental `@lunora/payment` API and may change without a major version bump.
|
|
559
|
+
* @experimental
|
|
560
|
+
*/
|
|
729
561
|
declare const applyWebhookAction: (store: PaymentStore, action: WebhookAction, observer?: PaymentObserver) => Promise<ApplyResult>;
|
|
730
|
-
/**
|
|
562
|
+
/**
|
|
563
|
+
* Constant-time string comparison to avoid leaking byte positions via timing.
|
|
564
|
+
*
|
|
565
|
+
* Re-exported from `shared/constant-time-equal` rather than defined here. The
|
|
566
|
+
* copy that used to live at this spot returned early on a length mismatch, so
|
|
567
|
+
* an attacker learned the expected signature's LENGTH from the response time —
|
|
568
|
+
* the exact divergence that shared file was created to stop, and which it
|
|
569
|
+
* records having already fixed once in the relay hub. It also compared by code
|
|
570
|
+
* POINT, making timing depend on surrogate boundaries; the canonical one
|
|
571
|
+
* compares per UTF-16 code unit.
|
|
572
|
+
*/
|
|
731
573
|
declare const constantTimeEqual: (a: string, b: string) => boolean;
|
|
732
|
-
declare const hmacSha256Hex: (secret: string, payload: string) => Promise<string>;
|
|
733
|
-
interface StripeSignatureParts {
|
|
734
|
-
readonly signatures: string[];
|
|
735
|
-
readonly timestamp: number;
|
|
736
|
-
}
|
|
737
|
-
/** Parse a Stripe-style `t=...,v1=...,v1=...` signature header. */
|
|
738
|
-
declare const parseStripeSignatureHeader: (header: string) => StripeSignatureParts;
|
|
739
|
-
interface VerifyStripeSignatureInput {
|
|
740
|
-
/** Injectable clock (ms since epoch) for tests. */
|
|
741
|
-
readonly now?: number;
|
|
742
|
-
/** Raw request body, exactly as received. */
|
|
743
|
-
readonly payload: string;
|
|
744
|
-
readonly secret: string;
|
|
745
|
-
/** The `Stripe-Signature` header value. */
|
|
746
|
-
readonly signatureHeader: string;
|
|
747
|
-
/** Whole-second tolerance for the signed timestamp (default 300). */
|
|
748
|
-
readonly toleranceSeconds?: number;
|
|
749
|
-
}
|
|
750
574
|
/**
|
|
751
|
-
*
|
|
752
|
-
*
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
declare const verifyStripeSignature: (input: VerifyStripeSignatureInput) => Promise<void>;
|
|
575
|
+
* Hex-encoded `HMAC_SHA256(secret, payload)` — the primitive behind the hex-scheme
|
|
576
|
+
* webhook verifiers.
|
|
577
|
+
*/
|
|
578
|
+
declare const hmacSha256Hex: (secret: string, payload: string) => Promise<string>;
|
|
756
579
|
interface VerifyStandardWebhookInput {
|
|
757
580
|
/** Injectable clock (ms since epoch) for tests. */
|
|
758
581
|
readonly now?: number;
|
|
@@ -764,15 +587,29 @@ interface VerifyStandardWebhookInput {
|
|
|
764
587
|
readonly toleranceSeconds?: number;
|
|
765
588
|
/** `webhook-id` header. */
|
|
766
589
|
readonly webhookId: string;
|
|
767
|
-
/** `webhook-signature` header — space-separated `v1
|
|
590
|
+
/** `webhook-signature` header — space-separated `v1,<base64>` entries. */
|
|
768
591
|
readonly webhookSignature: string;
|
|
769
592
|
/** `webhook-timestamp` header — unix seconds as a string. */
|
|
770
593
|
readonly webhookTimestamp: string;
|
|
771
594
|
}
|
|
772
595
|
/**
|
|
773
|
-
* Verify a Standard Webhooks signature (the scheme Polar and svix use):
|
|
774
|
-
* `base64(HMAC_SHA256(key, "{id}.{timestamp}.{payload}"))` compared against the header's `v1`
|
|
775
|
-
* entries, with a replay-window check. Throws a {@link LunoraPaymentError} on any failure.
|
|
776
|
-
*/
|
|
596
|
+
* Verify a Standard Webhooks signature (the scheme Polar and svix use):
|
|
597
|
+
* `base64(HMAC_SHA256(key, "{id}.{timestamp}.{payload}"))` compared against the header's `v1`
|
|
598
|
+
* entries, with a replay-window check. Throws a {@link LunoraPaymentError} on any failure.
|
|
599
|
+
*/
|
|
777
600
|
declare const verifyStandardWebhook: (input: VerifyStandardWebhookInput) => Promise<void>;
|
|
778
|
-
|
|
601
|
+
interface VerifyCreemSignatureInput {
|
|
602
|
+
/** Raw request body, exactly as received. */
|
|
603
|
+
readonly payload: string;
|
|
604
|
+
/** Creem webhook signing secret. */
|
|
605
|
+
readonly secret: string;
|
|
606
|
+
/** The `creem-signature` header value. */
|
|
607
|
+
readonly signature: string;
|
|
608
|
+
}
|
|
609
|
+
/**
|
|
610
|
+
* Verify a Creem webhook signature: `hex(HMAC_SHA256(secret, rawBody))` compared against the
|
|
611
|
+
* `creem-signature` header. Creem's scheme signs the raw body with no timestamp, so there is no
|
|
612
|
+
* replay-window check. Throws a {@link LunoraPaymentError} on any failure.
|
|
613
|
+
*/
|
|
614
|
+
declare const verifyCreemSignature: (input: VerifyCreemSignatureInput) => Promise<void>;
|
|
615
|
+
export { type ApplyResult, type AttachInput, type AuthorizeReference, type CancelSubscriptionOptions, type CaptureInput, type CheckInput, type CheckResult, type CheckoutInput, type CheckoutResult, type CreatePaymentOptions, type CurrencyCode, type Customer, type Entitlements, type EntitlementsConfig, type FeatureBalance, type LunoraDatabaseLike, type LunoraPayment, LunoraPaymentError, MemoryPaymentStore, type Money, type MoneyJSON, PAYMENT_TERMINAL_STATES, type PaymentAction, type PaymentAdapter, type PaymentContextLike, type PaymentDatabase, type PaymentErrorCode, type PaymentEvent, type PaymentObserver, type PaymentPage, type PaymentPageArgs, type PaymentRow, type PaymentSession, type PaymentState, type PaymentStore, type PaymentsFromContextOptions, type PlanDefinition, type ProviderId, type ReconcileInput, type ReconcileResult, type RefundInput, SUBSCRIPTION_TERMINAL_STATES, type Subscription, type SubscriptionAction, type SubscriptionState, type TrackInput, type TrackResult, type UsageEvent, type VerifyCreemSignatureInput, type VerifyStandardWebhookInput, type WebhookAction, type WebhookActionType, addMoney, allocateMoney, applyWebhookAction, canTransitionPayment, canTransitionSubscription, compareMoney, constantTimeEqual, createDatabasePaymentStore, createPayment, entitlementsForReference, featureNames, formatMoney, fromMoneyJSON, hasActivePrice, hmacSha256Hex, idempotencyKey, isZeroDecimalCurrency, isZeroMoney, lunoraDatabaseToPaymentDatabase, money, nextPaymentState, nextSubscriptionState, paymentTables, paymentsFromContext, reconcile, resolveEntitlements, subtractMoney, toMoneyJSON, usagePeriodStart, verifyCreemSignature, verifyStandardWebhook, zeroMoney };
|