@lunora/payment 1.0.0-alpha.124 → 1.0.0-alpha.126
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/dist/index.d.mts +14 -3
- package/dist/index.d.ts +14 -3
- package/dist/index.mjs +1 -1
- package/dist/packem_shared/{PAYMENT_TERMINAL_STATES-Dxxpk_br.mjs → PAYMENT_TERMINAL_STATES-C-ICZkun.mjs} +1 -1
- package/dist/packem_shared/{adapter.d-CeLGlHv_.d.mts → adapter.d-DytKm_IF.d.mts} +25 -0
- package/dist/packem_shared/{adapter.d-CeLGlHv_.d.ts → adapter.d-DytKm_IF.d.ts} +25 -0
- package/dist/packem_shared/applyWebhookAction-CvLpZjKP.mjs +1 -0
- package/dist/packem_shared/createDatabasePaymentStore-BGcHX1uq.mjs +1 -0
- package/dist/packem_shared/createPayment-Dimez2zY.mjs +1 -0
- package/dist/packem_shared/entitlementsForReference-PMmhAOWa.mjs +1 -0
- package/dist/packem_shared/idempotencyKey-qQJLcEQX.mjs +1 -0
- package/dist/packem_shared/{lunoraDatabaseToPaymentDatabase-CZmZ5LeG.mjs → lunoraDatabaseToPaymentDatabase-CFPYSEu0.mjs} +1 -1
- package/dist/packem_shared/paymentTables-Ve_lJxAt.mjs +1 -0
- package/dist/packem_shared/reconcile-fbxX8j9k.mjs +1 -0
- package/dist/providers/autumn.d.mts +1 -1
- package/dist/providers/autumn.d.ts +1 -1
- package/dist/providers/creem.d.mts +1 -1
- package/dist/providers/creem.d.ts +1 -1
- package/dist/providers/creem.mjs +1 -1
- package/dist/providers/dodopayments.d.mts +1 -1
- package/dist/providers/dodopayments.d.ts +1 -1
- package/dist/providers/dodopayments.mjs +1 -1
- package/dist/providers/polar.d.mts +1 -1
- package/dist/providers/polar.d.ts +1 -1
- package/dist/providers/polar.mjs +1 -1
- package/dist/providers/stripe.d.mts +3 -1
- package/dist/providers/stripe.d.ts +3 -1
- package/dist/providers/stripe.mjs +1 -1
- package/package.json +3 -3
- package/dist/packem_shared/applyWebhookAction-DqM4qNr3.mjs +0 -1
- package/dist/packem_shared/createDatabasePaymentStore-DWe1Vz4V.mjs +0 -1
- package/dist/packem_shared/createPayment-Cmyk1BcJ.mjs +0 -1
- package/dist/packem_shared/entitlementsForReference-Bq-9UUL8.mjs +0 -1
- package/dist/packem_shared/idempotencyKey-DBL6bpmj.mjs +0 -1
- package/dist/packem_shared/paymentTables-Be-_11ux.mjs +0 -1
- package/dist/packem_shared/reconcile-Cm45pURT.mjs +0 -1
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
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-
|
|
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 RefundResult, type u as ReportUsageInput, type v as SubscriptionPatch, type w as WebhookHeaders, type x as WebhookInput, y as createAdapterRegistry } from "./packem_shared/adapter.d-
|
|
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-DytKm_IF.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 RefundResult, type u as ReportUsageInput, type v as SubscriptionPatch, type w as WebhookHeaders, type x as WebhookInput, y as createAdapterRegistry } from "./packem_shared/adapter.d-DytKm_IF.mjs";
|
|
3
3
|
import { LunoraError } from '@lunora/errors';
|
|
4
4
|
import { TableDefinition } from '@lunora/server';
|
|
5
5
|
/**
|
|
@@ -296,13 +296,24 @@ interface LunoraPayment {
|
|
|
296
296
|
/** Resolve every configured feature's allowance for a reference in one call. Requires `entitlements`. */
|
|
297
297
|
listBalances: (referenceId: string) => Promise<FeatureBalance[]>;
|
|
298
298
|
listSubscriptions: (referenceId: string) => Promise<Subscription[]>;
|
|
299
|
-
/**
|
|
299
|
+
/**
|
|
300
|
+
* Refund the caller's own captured payment (authorized, derived idempotency key, store synced).
|
|
301
|
+
*
|
|
302
|
+
* The derived key makes "same session, same amount, same reason" ONE operation, so a retried
|
|
303
|
+
* request cannot refund twice. Two *intentional* refunds of the same amount on one session are
|
|
304
|
+
* therefore indistinguishable from that retry: pass a distinct `RefundInput.idempotencyKey` for
|
|
305
|
+
* the second one, or the provider replays the first and the second moves no money.
|
|
306
|
+
*/
|
|
300
307
|
refundPayment: (input: RefundInput) => Promise<PaymentSession>;
|
|
301
308
|
readonly store: PaymentStore;
|
|
302
309
|
/**
|
|
303
310
|
* Record metered usage for a reference's feature — durably (exactly-once by idempotency key) and,
|
|
304
311
|
* when the provider supports it, forwarded to its metering API. Best-effort upstream: a reporting
|
|
305
312
|
* failure is observed, never thrown, and the local ledger that `check` reads is always updated.
|
|
313
|
+
*
|
|
314
|
+
* `mode: "set"` is rejected with `VALIDATION_ERROR` on a provider that meters usage: its meter is
|
|
315
|
+
* additive, so a period total is not expressible on it and a lowering set would leave the provider
|
|
316
|
+
* billing more than the local ledger holds. Use `mode: "add"` there.
|
|
306
317
|
*/
|
|
307
318
|
track: (input: TrackInput) => Promise<TrackResult>;
|
|
308
319
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
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-
|
|
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 RefundResult, type u as ReportUsageInput, type v as SubscriptionPatch, type w as WebhookHeaders, type x as WebhookInput, y as createAdapterRegistry } from "./packem_shared/adapter.d-
|
|
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-DytKm_IF.js";
|
|
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 RefundResult, type u as ReportUsageInput, type v as SubscriptionPatch, type w as WebhookHeaders, type x as WebhookInput, y as createAdapterRegistry } from "./packem_shared/adapter.d-DytKm_IF.js";
|
|
3
3
|
import { LunoraError } from '@lunora/errors';
|
|
4
4
|
import { TableDefinition } from '@lunora/server';
|
|
5
5
|
/**
|
|
@@ -296,13 +296,24 @@ interface LunoraPayment {
|
|
|
296
296
|
/** Resolve every configured feature's allowance for a reference in one call. Requires `entitlements`. */
|
|
297
297
|
listBalances: (referenceId: string) => Promise<FeatureBalance[]>;
|
|
298
298
|
listSubscriptions: (referenceId: string) => Promise<Subscription[]>;
|
|
299
|
-
/**
|
|
299
|
+
/**
|
|
300
|
+
* Refund the caller's own captured payment (authorized, derived idempotency key, store synced).
|
|
301
|
+
*
|
|
302
|
+
* The derived key makes "same session, same amount, same reason" ONE operation, so a retried
|
|
303
|
+
* request cannot refund twice. Two *intentional* refunds of the same amount on one session are
|
|
304
|
+
* therefore indistinguishable from that retry: pass a distinct `RefundInput.idempotencyKey` for
|
|
305
|
+
* the second one, or the provider replays the first and the second moves no money.
|
|
306
|
+
*/
|
|
300
307
|
refundPayment: (input: RefundInput) => Promise<PaymentSession>;
|
|
301
308
|
readonly store: PaymentStore;
|
|
302
309
|
/**
|
|
303
310
|
* Record metered usage for a reference's feature — durably (exactly-once by idempotency key) and,
|
|
304
311
|
* when the provider supports it, forwarded to its metering API. Best-effort upstream: a reporting
|
|
305
312
|
* failure is observed, never thrown, and the local ledger that `check` reads is always updated.
|
|
313
|
+
*
|
|
314
|
+
* `mode: "set"` is rejected with `VALIDATION_ERROR` on a provider that meters usage: its meter is
|
|
315
|
+
* additive, so a period total is not expressible on it and a lowering set would leave the provider
|
|
316
|
+
* billing more than the local ledger holds. Use `mode: "add"` there.
|
|
306
317
|
*/
|
|
307
318
|
track: (input: TrackInput) => Promise<TrackResult>;
|
|
308
319
|
}
|
package/dist/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{createAdapterRegistry as r}from"./packem_shared/createAdapterRegistry-DyCsry1Q.mjs";import{lunoraDatabaseToPaymentDatabase as a,paymentsFromContext as n}from"./packem_shared/lunoraDatabaseToPaymentDatabase-
|
|
1
|
+
import{createAdapterRegistry as r}from"./packem_shared/createAdapterRegistry-DyCsry1Q.mjs";import{lunoraDatabaseToPaymentDatabase as a,paymentsFromContext as n}from"./packem_shared/lunoraDatabaseToPaymentDatabase-CFPYSEu0.mjs";import{createPayment as y,webhookResponse as i}from"./packem_shared/createPayment-Dimez2zY.mjs";import{createDatabasePaymentStore as s}from"./packem_shared/createDatabasePaymentStore-BGcHX1uq.mjs";import{entitlementsForReference as c,featureNames as x,hasActivePrice as S,resolveEntitlements as l,usagePeriodStart as M}from"./packem_shared/entitlementsForReference-PMmhAOWa.mjs";import{LunoraPaymentError as u}from"./packem_shared/LunoraPaymentError-BSxyhWgu.mjs";import{idempotencyKey as b}from"./packem_shared/idempotencyKey-qQJLcEQX.mjs";import{addMoney as A,allocateMoney as E,compareMoney as N,formatMoney as h,fromMoneyJSON as R,isZeroDecimalCurrency as v,isZeroMoney as C,money as D,subtractMoney as I,toMoneyJSON as _,zeroMoney as g}from"./packem_shared/addMoney-B4ufWAnD.mjs";import{reconcile as L}from"./packem_shared/reconcile-fbxX8j9k.mjs";import{default as F}from"./packem_shared/paymentTables-Ve_lJxAt.mjs";import{PAYMENT_TERMINAL_STATES as W,SUBSCRIPTION_TERMINAL_STATES as Z,canTransitionPayment as q,canTransitionSubscription as w,nextPaymentState as z,nextSubscriptionState as B}from"./packem_shared/PAYMENT_TERMINAL_STATES-C-ICZkun.mjs";import{MemoryPaymentStore as K}from"./packem_shared/MemoryPaymentStore-CZbrrEb1.mjs";import{default as Y}from"./packem_shared/applyWebhookAction-CvLpZjKP.mjs";import{constantTimeEqual as G,hmacSha256Hex as Q,verifyCreemSignature as V,verifyStandardWebhook as X}from"./packem_shared/constantTimeEqual-ggrwGvRa.mjs";export{u as LunoraPaymentError,K as MemoryPaymentStore,W as PAYMENT_TERMINAL_STATES,Z as SUBSCRIPTION_TERMINAL_STATES,A as addMoney,E as allocateMoney,Y as applyWebhookAction,q as canTransitionPayment,w as canTransitionSubscription,N as compareMoney,G as constantTimeEqual,r as createAdapterRegistry,s as createDatabasePaymentStore,y as createPayment,c as entitlementsForReference,x as featureNames,h as formatMoney,R as fromMoneyJSON,S as hasActivePrice,Q as hmacSha256Hex,b as idempotencyKey,v as isZeroDecimalCurrency,C as isZeroMoney,a as lunoraDatabaseToPaymentDatabase,D as money,z as nextPaymentState,B as nextSubscriptionState,F as paymentTables,n as paymentsFromContext,L as reconcile,l as resolveEntitlements,I as subtractMoney,_ as toMoneyJSON,M as usagePeriodStart,V as verifyCreemSignature,X as verifyStandardWebhook,i as webhookResponse,g as zeroMoney};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
const c={authorized:{cancel:"canceled",capture:"captured",fail:"failed"},canceled:{},captured:{partial_refund:"partially_refunded",refund:"refunded"},failed:{authorize:"authorized",capture:"captured",fail:"failed"},initiated:{authorize:"authorized",cancel:"canceled",capture:"captured",fail:"failed"},partially_refunded:{partial_refund:"partially_refunded",refund:"refunded"},refunded:{refund:"refunded"}},t={active:{cancel:"canceled",mark_past_due:"past_due",pause:"paused",renew:"active"},canceled:{},past_due:{activate:"active",cancel:"canceled",pause:"paused",renew:"active"},paused:{cancel:"canceled",resume:"active"},trialing:{activate:"active",cancel:"canceled",mark_past_due:"past_due"}},r=new Set(["canceled","refunded"]),i=new Set(["canceled"]),n=(e,a)=>c[e][a],u=(e,a)=>n(e,a)!==void 0,d=(e,a)=>t[e][a],l=(e,a)=>d(e,a)!==void 0;export{r as PAYMENT_TERMINAL_STATES,i as SUBSCRIPTION_TERMINAL_STATES,u as canTransitionPayment,l as canTransitionSubscription,n as nextPaymentState,d as nextSubscriptionState};
|
|
1
|
+
const c={authorized:{cancel:"canceled",capture:"captured",fail:"failed"},canceled:{},captured:{partial_refund:"partially_refunded",refund:"refunded"},failed:{authorize:"authorized",capture:"captured",fail:"failed"},initiated:{authorize:"authorized",cancel:"canceled",capture:"captured",fail:"failed"},partially_refunded:{partial_refund:"partially_refunded",refund:"refunded"},refunded:{refund:"refunded"}},t={active:{cancel:"canceled",mark_past_due:"past_due",pause:"paused",renew:"active"},canceled:{},past_due:{activate:"active",cancel:"canceled",pause:"paused",renew:"active"},paused:{cancel:"canceled",resume:"active"},trialing:{activate:"active",cancel:"canceled",mark_past_due:"past_due",pause:"paused",renew:"active"}},r=new Set(["canceled","refunded"]),i=new Set(["canceled"]),n=(e,a)=>c[e][a],u=(e,a)=>n(e,a)!==void 0,d=(e,a)=>t[e][a],l=(e,a)=>d(e,a)!==void 0;export{r as PAYMENT_TERMINAL_STATES,i as SUBSCRIPTION_TERMINAL_STATES,u as canTransitionPayment,l as canTransitionSubscription,n as nextPaymentState,d as nextSubscriptionState};
|
|
@@ -85,7 +85,17 @@ interface Subscription {
|
|
|
85
85
|
/** Start of the current billing period — the window `check` sums metered usage over. */
|
|
86
86
|
readonly currentPeriodStart?: number;
|
|
87
87
|
readonly id: string;
|
|
88
|
+
/** The primary (first) price/product id — `priceIds[0]`. Display and single-item plan changes. */
|
|
88
89
|
readonly priceId: string;
|
|
90
|
+
/**
|
|
91
|
+
* EVERY price/product id the subscription bills, not just the primary one. A Stripe subscription
|
|
92
|
+
* can carry an add-on or a metered price alongside the base plan, and a customer paying for one is
|
|
93
|
+
* entitled to it — so entitlements test membership here (see `hasActivePrice`).
|
|
94
|
+
*
|
|
95
|
+
* Optional because the webhook path and any pre-existing stored row carry only `priceId`; absent
|
|
96
|
+
* reads as `[priceId]`, which is exactly right for the single-item case every other provider has.
|
|
97
|
+
*/
|
|
98
|
+
readonly priceIds?: ReadonlyArray<string>;
|
|
89
99
|
readonly provider: ProviderId;
|
|
90
100
|
readonly quantity: number;
|
|
91
101
|
readonly referenceId: string;
|
|
@@ -195,6 +205,11 @@ interface TrackInput {
|
|
|
195
205
|
* resets to, rather than reading the current total and appending a delta. Concurrent `"set"` calls
|
|
196
206
|
* for the same reference therefore resolve last-writer-wins instead of over- or under-counting, and
|
|
197
207
|
* a replayed `"set"` is idempotent — neither mode needs a serialized context or a per-reference lock.
|
|
208
|
+
*
|
|
209
|
+
* `"set"` reconciles the LOCAL period total only, so `track` rejects it with `VALIDATION_ERROR` on a
|
|
210
|
+
* provider that meters usage upstream: those meters are additive and cannot take a period total, and
|
|
211
|
+
* a set that LOWERS usage has no negative delta to forward — the provider would keep billing the
|
|
212
|
+
* higher figure while the local ledger holds the lower one. Use `"add"` with a metered provider.
|
|
198
213
|
*/
|
|
199
214
|
readonly mode?: "add" | "set";
|
|
200
215
|
/**
|
|
@@ -372,6 +387,16 @@ interface WebhookAction {
|
|
|
372
387
|
/** Provider event id — the inbound idempotency key. */
|
|
373
388
|
readonly eventId: string;
|
|
374
389
|
readonly priceId?: string;
|
|
390
|
+
/**
|
|
391
|
+
* EVERY price/product id the subscription bills, when the adapter could establish the whole set.
|
|
392
|
+
* `sync.ts` applies it as a WHOLESALE replacement, so it must be complete or absent — never a
|
|
393
|
+
* subset, which would silently drop prices the stored row already had.
|
|
394
|
+
*
|
|
395
|
+
* `undefined` leaves the stored set standing (see {@link Subscription.priceIds}). That is the
|
|
396
|
+
* single-price providers' case, and the fail-closed answer for a provider whose embedded item
|
|
397
|
+
* list is paginated and whose event carries only the first page.
|
|
398
|
+
*/
|
|
399
|
+
readonly priceIds?: ReadonlyArray<string>;
|
|
375
400
|
readonly provider: ProviderId;
|
|
376
401
|
readonly quantity?: number;
|
|
377
402
|
/** Raw provider event, retained for the events log / debugging. */
|
|
@@ -85,7 +85,17 @@ interface Subscription {
|
|
|
85
85
|
/** Start of the current billing period — the window `check` sums metered usage over. */
|
|
86
86
|
readonly currentPeriodStart?: number;
|
|
87
87
|
readonly id: string;
|
|
88
|
+
/** The primary (first) price/product id — `priceIds[0]`. Display and single-item plan changes. */
|
|
88
89
|
readonly priceId: string;
|
|
90
|
+
/**
|
|
91
|
+
* EVERY price/product id the subscription bills, not just the primary one. A Stripe subscription
|
|
92
|
+
* can carry an add-on or a metered price alongside the base plan, and a customer paying for one is
|
|
93
|
+
* entitled to it — so entitlements test membership here (see `hasActivePrice`).
|
|
94
|
+
*
|
|
95
|
+
* Optional because the webhook path and any pre-existing stored row carry only `priceId`; absent
|
|
96
|
+
* reads as `[priceId]`, which is exactly right for the single-item case every other provider has.
|
|
97
|
+
*/
|
|
98
|
+
readonly priceIds?: ReadonlyArray<string>;
|
|
89
99
|
readonly provider: ProviderId;
|
|
90
100
|
readonly quantity: number;
|
|
91
101
|
readonly referenceId: string;
|
|
@@ -195,6 +205,11 @@ interface TrackInput {
|
|
|
195
205
|
* resets to, rather than reading the current total and appending a delta. Concurrent `"set"` calls
|
|
196
206
|
* for the same reference therefore resolve last-writer-wins instead of over- or under-counting, and
|
|
197
207
|
* a replayed `"set"` is idempotent — neither mode needs a serialized context or a per-reference lock.
|
|
208
|
+
*
|
|
209
|
+
* `"set"` reconciles the LOCAL period total only, so `track` rejects it with `VALIDATION_ERROR` on a
|
|
210
|
+
* provider that meters usage upstream: those meters are additive and cannot take a period total, and
|
|
211
|
+
* a set that LOWERS usage has no negative delta to forward — the provider would keep billing the
|
|
212
|
+
* higher figure while the local ledger holds the lower one. Use `"add"` with a metered provider.
|
|
198
213
|
*/
|
|
199
214
|
readonly mode?: "add" | "set";
|
|
200
215
|
/**
|
|
@@ -372,6 +387,16 @@ interface WebhookAction {
|
|
|
372
387
|
/** Provider event id — the inbound idempotency key. */
|
|
373
388
|
readonly eventId: string;
|
|
374
389
|
readonly priceId?: string;
|
|
390
|
+
/**
|
|
391
|
+
* EVERY price/product id the subscription bills, when the adapter could establish the whole set.
|
|
392
|
+
* `sync.ts` applies it as a WHOLESALE replacement, so it must be complete or absent — never a
|
|
393
|
+
* subset, which would silently drop prices the stored row already had.
|
|
394
|
+
*
|
|
395
|
+
* `undefined` leaves the stored set standing (see {@link Subscription.priceIds}). That is the
|
|
396
|
+
* single-price providers' case, and the fail-closed answer for a provider whose embedded item
|
|
397
|
+
* list is paginated and whose event carries only the first page.
|
|
398
|
+
*/
|
|
399
|
+
readonly priceIds?: ReadonlyArray<string>;
|
|
375
400
|
readonly provider: ProviderId;
|
|
376
401
|
readonly quantity?: number;
|
|
377
402
|
/** Raw provider event, retained for the events log / debugging. */
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{LunoraPaymentError as P}from"./LunoraPaymentError-BSxyhWgu.mjs";import{localRefundKey as A,LOCAL_REFUND_CLAIM_TYPE as E}from"./idempotencyKey-qQJLcEQX.mjs";import{zeroMoney as o,compareMoney as l,addMoney as _}from"./addMoney-B4ufWAnD.mjs";import{n as a}from"./observability-BteZ2dJS.mjs";import{nextPaymentState as S,nextSubscriptionState as w}from"./PAYMENT_TERMINAL_STATES-C-ICZkun.mjs";const b={"payment.authorized":"authorize","payment.captured":"capture","payment.failed":"fail","payment.refunded":"refund"},h={"subscription.active":"active","subscription.canceled":"canceled","subscription.past_due":"past_due","subscription.paused":"paused"},T="orphan-retry:",R="marker.orphan_retry",k={"subscription.active":"activate","subscription.canceled":"cancel","subscription.past_due":"mark_past_due","subscription.paused":"pause"},O=(t,e)=>l(t,e)>0?t:e,Y=new Set(["authorized","initiated"]),N=async(t,e,r)=>{if(!r||!e.sessionId||!e.amount||e.amountKind==="absolute")return e;const d=A(e.sessionId,e.refundId,e.amount),n=await t.markEventProcessed(e.provider,d,E);return await t.releaseEvent(e.provider,d),n?e:{...e,amount:o(e.amount.currency)}},v=(t,e)=>{if(!e.amount||t.refundedAmount.currency!==e.amount.currency||t.capturedAmount.currency!==e.amount.currency)return;const r=e.amountKind==="absolute"?O(e.amount,t.refundedAmount):_(t.refundedAmount,e.amount);if(!(l(r,t.capturedAmount)>0))return r},M=(t,e)=>{if(!t)return"refund";const r=v(t,e);return r&&l(r,t.capturedAmount)<0?"partial_refund":"refund"},q=async(t,e,r)=>{if(!e.sessionId)return{applied:!1,reason:"unhandled"};const d=await t.getPaymentSession(e.provider,e.sessionId),n=d?.state??"initiated",u=Date.now(),s=e.amount?.currency??d?.amount.currency??"USD",c=r==="refund"?await N(t,e,d):e,p=r==="refund"?M(d,c):r,I=S(n,p);if(!I)return{applied:!1,reason:r==="refund"&&Y.has(n)?"orphaned":"illegal_transition"};const i=d??{amount:e.amount??o(s),capturedAmount:o(s),createdAt:u,id:e.sessionId,provider:e.provider,referenceId:e.referenceId??"",refundedAmount:o(s),state:n,updatedAt:u};let{capturedAmount:m,refundedAmount:y}=i;if(p==="capture"&&e.amount&&(m=e.amount),(p==="partial_refund"||p==="refund")&&c.amount){const f=v(i,c);if(!f)return{applied:!1,reason:"invalid_refund_amount"};y=f}return await t.upsertPaymentSession({...i,capturedAmount:m,referenceId:e.referenceId??i.referenceId,refundedAmount:y,state:I,updatedAt:u}),{applied:!0,reason:"ok"}},C=(t,e,r)=>{if(e==="active"){if(t==="active")return"renew";if(t==="paused")return"resume"}return k[r]},g=async(t,e)=>{if(!e.subscriptionId)return{applied:!1,reason:"unhandled"};const r=await t.getSubscription(e.provider,e.subscriptionId),d=Date.now();if(e.type==="subscription.updated")return r?(await t.upsertSubscription({...r,cancelAtPeriodEnd:e.cancelAtPeriodEnd??r.cancelAtPeriodEnd,currentPeriodEnd:e.currentPeriodEnd??r.currentPeriodEnd,currentPeriodStart:e.currentPeriodStart??r.currentPeriodStart,priceId:e.priceId??r.priceId,priceIds:e.priceIds??r.priceIds,quantity:e.quantity??r.quantity,updatedAt:d}),{applied:!0,reason:"ok"}):{applied:!1,reason:"orphaned"};const n=h[e.type];if(!n)return{applied:!1,reason:"unhandled"};if(!r)return await t.upsertSubscription({cancelAtPeriodEnd:e.cancelAtPeriodEnd??!1,createdAt:d,currentPeriodEnd:e.currentPeriodEnd,currentPeriodStart:e.currentPeriodStart??d,id:e.subscriptionId,priceId:e.priceId??"",priceIds:e.priceIds,provider:e.provider,quantity:e.quantity??1,referenceId:e.referenceId??"",state:n,updatedAt:d}),{applied:!0,reason:"ok"};const u=C(r.state,n,e.type),s=u?w(r.state,u):void 0;return s?(await t.upsertSubscription({...r,cancelAtPeriodEnd:e.cancelAtPeriodEnd??r.cancelAtPeriodEnd,currentPeriodEnd:e.currentPeriodEnd??r.currentPeriodEnd,currentPeriodStart:e.currentPeriodStart??r.currentPeriodStart,priceId:e.priceId??r.priceId,priceIds:e.priceIds??r.priceIds,quantity:e.quantity??r.quantity,state:s,updatedAt:d}),{applied:!0,reason:"ok"}):{applied:!1,reason:"illegal_transition"}},U=async(t,e,r)=>{if(e.type==="unhandled")return{applied:!1,reason:"unhandled"};if(!e.eventId?.trim())throw new P("WEBHOOK_EVENT_ID_MISSING",`webhook event id is missing or blank for provider "${e.provider}"`);if(!await t.markEventProcessed(e.provider,e.eventId,e.type))return a(r,{eventId:e.eventId,provider:e.provider,type:"webhook.duplicate"}),{applied:!1,reason:"duplicate"};const n=b[e.type];let u;try{u=n?await q(t,e,n):await g(t,e)}catch(s){throw await t.releaseEvent(e.provider,e.eventId),s}return u.reason==="orphaned"&&(await t.markEventProcessed(e.provider,`${T}${e.eventId}`,R)?await t.releaseEvent(e.provider,e.eventId):u={applied:!1,reason:"unhandled"}),a(r,{action:e.type,eventId:e.eventId,provider:e.provider,reason:u.reason,type:"webhook.applied"}),e.type==="payment.failed"?a(r,{provider:e.provider,referenceId:e.referenceId,sessionId:e.sessionId,type:"payment.failed"}):e.type==="subscription.past_due"&&a(r,{provider:e.provider,referenceId:e.referenceId,subscriptionId:e.subscriptionId,type:"subscription.past_due"}),u};export{U as default};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{money as y}from"./addMoney-B4ufWAnD.mjs";import{foldUsage as m}from"./MemoryPaymentStore-CZbrrEb1.mjs";const o=(e,n)=>typeof e[n]=="string"?e[n]:"",l=(e,n)=>typeof e[n]=="string"?e[n]:void 0,c=(e,n)=>typeof e[n]=="number"?e[n]:0,v=(e,n)=>typeof e[n]=="number"?e[n]:void 0,A=(e,n)=>e[n]===!0,S=(e,n)=>{const t=e[n];return Array.isArray(t)?t.filter(d=>typeof d=="string"):void 0},f=(e,n)=>{const t=e[n];return typeof t=="bigint"?t:typeof t=="number"||typeof t=="string"?BigInt(t):0n},P=e=>({createdAt:e.createdAt,email:e.email,provider:e.provider,providerCustomerId:e.id,referenceId:e.referenceId}),E=e=>({createdAt:c(e,"createdAt"),email:l(e,"email"),id:o(e,"providerCustomerId"),provider:o(e,"provider"),referenceId:o(e,"referenceId")}),M=e=>({amountMinor:e.amount.minorUnits,capturedMinor:e.capturedAmount.minorUnits,createdAt:e.createdAt,currency:e.amount.currency,provider:e.provider,providerSessionId:e.id,referenceId:e.referenceId,refundedMinor:e.refundedAmount.minorUnits,state:e.state,updatedAt:e.updatedAt}),T=e=>{const n=o(e,"currency");return{amount:y(f(e,"amountMinor"),n),capturedAmount:y(f(e,"capturedMinor"),n),createdAt:c(e,"createdAt"),id:o(e,"providerSessionId"),provider:o(e,"provider"),referenceId:o(e,"referenceId"),refundedAmount:y(f(e,"refundedMinor"),n),state:o(e,"state"),updatedAt:c(e,"updatedAt")}},q=e=>({cancelAtPeriodEnd:e.cancelAtPeriodEnd,createdAt:e.createdAt,currentPeriodEnd:e.currentPeriodEnd,currentPeriodStart:e.currentPeriodStart,priceId:e.priceId,priceIds:e.priceIds===void 0?void 0:[...e.priceIds],provider:e.provider,providerSubscriptionId:e.id,quantity:e.quantity,referenceId:e.referenceId,state:e.state,updatedAt:e.updatedAt}),I=e=>({cancelAtPeriodEnd:A(e,"cancelAtPeriodEnd"),createdAt:c(e,"createdAt"),currentPeriodEnd:v(e,"currentPeriodEnd"),currentPeriodStart:v(e,"currentPeriodStart"),id:o(e,"providerSubscriptionId"),priceId:o(e,"priceId"),priceIds:S(e,"priceIds"),provider:o(e,"provider"),quantity:c(e,"quantity"),referenceId:o(e,"referenceId"),state:o(e,"state"),updatedAt:c(e,"updatedAt")}),K=e=>({createdAt:c(e,"createdAt"),featureId:o(e,"featureId"),idempotencyKey:o(e,"idempotencyKey"),mode:e.mode==="set"?"set":"add",provider:o(e,"provider"),quantity:c(e,"quantity"),referenceId:o(e,"referenceId"),reportedToProvider:A(e,"reportedToProvider")}),U=e=>({createdAt:e.createdAt,featureId:e.featureId,idempotencyKey:e.idempotencyKey,...e.mode==="set"?{mode:"set"}:{},provider:e.provider,quantity:e.quantity,referenceId:e.referenceId,reportedToProvider:e.reportedToProvider}),h=e=>{const n=async(t,d,r)=>{const a=await e.findFirst(t,d);if(a){await e.patch(a._id,r);return}await e.insert(t,r)};return{getCustomerByReference:async(t,d)=>{const r=await e.findFirst("customers",{provider:t,referenceId:d});return r?E(r):void 0},getPaymentSession:async(t,d)=>{const r=await e.findFirst("paymentSessions",{provider:t,providerSessionId:d});return r?T(r):void 0},getSubscription:async(t,d)=>{const r=await e.findFirst("subscriptions",{provider:t,providerSubscriptionId:d});return r?I(r):void 0},listSubscriptionsByReference:async t=>{const{rows:d}=await e.findMany("subscriptions",{referenceId:t});return d.map(r=>I(r))},listUnreportedUsage:async(t,d)=>{const r=Math.max(0,Math.floor(d));if(r===0)return[];const a=[{createdAt:"asc"},{idempotencyKey:"asc"}],s=[];let i;do{const u=await e.findMany("usageEvents",{provider:t,reportedToProvider:!1},{cursor:i,limit:r,orderBy:a});for(const g of u.rows){const p=K(g);if(p.mode!=="set"&&p.quantity>0&&(s.push(p),s.length===r))return s}i=u.cursor}while(i!==void 0);return s},markEventProcessed:async(t,d,r)=>await e.findFirst("events",{provider:t,providerEventId:d})?!1:(await e.insert("events",{processedAt:Date.now(),provider:t,providerEventId:d,type:r}),!0),releaseEvent:async(t,d)=>{const r=await e.findFirst("events",{provider:t,providerEventId:d});r&&await e.delete(r._id)},markUsageReported:async(t,d)=>{const r=await e.findFirst("usageEvents",{idempotencyKey:d,provider:t});r&&await e.patch(r._id,{reportedToProvider:!0})},recordUsage:async t=>await e.findFirst("usageEvents",{idempotencyKey:t.idempotencyKey,provider:t.provider})?!1:(await e.insert("usageEvents",U(t)),!0),sumUsage:async(t,d,r)=>{const{rows:a}=await e.findMany("usageEvents",{featureId:d,referenceId:t}),s=a.filter(i=>c(i,"createdAt")>=r).map(i=>({createdAt:c(i,"createdAt"),idempotencyKey:typeof i.idempotencyKey=="string"?i.idempotencyKey:"",mode:i.mode==="set"?"set":"add",quantity:c(i,"quantity")}));return m(s)},sumUsageByFeature:async(t,d,r)=>{const{rows:a}=await e.findMany("usageEvents",{referenceId:t}),s=new Map(d.map(i=>[i,[]]));for(const i of a)c(i,"createdAt")<r||s.get(typeof i.featureId=="string"?i.featureId:"")?.push({createdAt:c(i,"createdAt"),idempotencyKey:typeof i.idempotencyKey=="string"?i.idempotencyKey:"",mode:i.mode==="set"?"set":"add",quantity:c(i,"quantity")});return new Map([...s].map(([i,u])=>[i,m(u)]))},upsertCustomer:async t=>n("customers",{provider:t.provider,referenceId:t.referenceId},P(t)),upsertPaymentSession:async t=>n("paymentSessions",{provider:t.provider,providerSessionId:t.id},M(t)),upsertSubscription:async t=>n("subscriptions",{provider:t.provider,providerSubscriptionId:t.id},q(t))}};export{h as createDatabasePaymentStore};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{toErrorBody as N}from"@lunora/errors";import{usagePeriodStart as g,resolveEntitlements as A,featureNames as U,hasActivePrice as _}from"./entitlementsForReference-PMmhAOWa.mjs";import{LunoraPaymentError as f}from"./LunoraPaymentError-BSxyhWgu.mjs";import{derivedIdempotencyKey as b,localRefundKey as D,LOCAL_REFUND_CLAIM_TYPE as E,idempotencyKey as k}from"./idempotencyKey-qQJLcEQX.mjs";import{subtractMoney as K,addMoney as T,compareMoney as v,isZeroMoney as B}from"./addMoney-B4ufWAnD.mjs";import{n as C}from"./observability-BteZ2dJS.mjs";import F from"./applyWebhookAction-CvLpZjKP.mjs";const y=(o,n=200,s)=>{const u=new Headers({"content-type":"application/json"});for(const[l,w]of Object.entries({}))u.set(l,w);return Response.json(o,{headers:u,status:n})};let h=0;const $=()=>{const o=Date.now();return h=o>h?o:h+1,h},O=o=>o?`${o.currency}:${String(o.minorUnits)}`:"full",q=o=>o&&"referenceId"in o?Object.fromEntries(Object.entries(o).filter(([n])=>n!=="referenceId")):o,G=o=>y({applied:o.applied},o.status),H=o=>{const{adapter:n,store:s}=o,u=async e=>{if(!o.authorize)return;let t;try{t=await o.authorize(e)}catch{throw new f("FORBIDDEN",`caller not authorized for reference "${e}"`)}if(t!==!0)throw new f("FORBIDDEN",`caller not authorized for reference "${e}"`)},l=async e=>{await u(e.referenceId);const t=q(e.metadata);let r;const a=await s.getCustomerByReference(n.identifier,e.referenceId);if(a)r=a.id;else{const d=await n.getOrCreateCustomer({email:e.email,referenceId:e.referenceId});r=d.id,await s.upsertCustomer(d)}const i=e.idempotencyKey??await b("checkout",n.identifier,e.referenceId,e.priceId,e.mode,String(e.quantity??1),e.successUrl,e.cancelUrl,t?JSON.stringify(t):"");return n.createCheckout({...e,customerId:r,idempotencyKey:i,metadata:t})},w=(e,t,r)=>{const a=e-t;return{allowed:a>=r,balance:a,limit:e,unlimited:!1,used:t}},S=async(e,t,r,a,i)=>{const d=e.limit(a);if(d!==void 0){const c=await s.sumUsage(r,a,g(t));return w(d,c,i)}return{allowed:e.has(a),unlimited:e.has(a)}},p=async e=>{const t=()=>new f("NOT_FOUND",`payment session "${e}" not found`);let r=await s.getPaymentSession(n.identifier,e);if(!r)try{r=await n.getPaymentStatus(e)}catch{throw t()}if(!r.referenceId)throw t();try{await u(r.referenceId)}catch{throw t()}return r},I=async(e,t)=>{const r={...e,...t,updatedAt:Date.now()};return await s.upsertPaymentSession(r),r};return{adapter:n,attach:async e=>l({...e,mode:e.mode??"subscription"}),cancelPayment:async(e,t)=>{const r=await p(e),a=t?.idempotencyKey??k("cancel_payment",n.identifier,e),i=await n.cancelPayment(e,{...t,idempotencyKey:a});return I(r,{state:i.state})},cancelSubscription:async(e,t)=>{const r=await s.getSubscription(n.identifier,e);if(!r)throw new f("NOT_FOUND",`subscription "${e}" not found`);try{await u(r.referenceId)}catch{throw new f("NOT_FOUND",`subscription "${e}" not found`)}const a=t?.idempotencyKey??k("cancel_subscription",n.identifier,e),i=await n.cancelSubscription(e,{...t,idempotencyKey:a}),d={...i,referenceId:r.referenceId===""?i.referenceId:r.referenceId};return await s.upsertSubscription(d),d},capturePayment:async e=>{const t=await p(e.sessionId),r=e.idempotencyKey??await b("capture_payment",n.identifier,e.sessionId,O(e.amount)),a=await n.capturePayment({...e,idempotencyKey:r});return I(t,{capturedAmount:a.capturedAmount,state:a.state})},check:async e=>{if(await u(e.referenceId),e.featureId===void 0&&e.priceId===void 0)throw new f("VALIDATION_ERROR","check() requires a featureId or priceId");if(n.checkEntitlement)return n.checkEntitlement(e);const t=await s.listSubscriptionsByReference(e.referenceId);if(e.priceId!==void 0)return{allowed:_(t,e.priceId),unlimited:!1};if(e.featureId===void 0)throw new f("VALIDATION_ERROR","check() requires a featureId or priceId");if(!o.entitlements)throw new f("CONFIG_INVALID","check() requires `entitlements` to be configured");const r=A(o.entitlements,t);return S(r,t,e.referenceId,e.featureId,e.quantity??1)},createCheckout:async e=>l(e),createPortalSession:async(e,t)=>{await u(e);const r=await s.getCustomerByReference(n.identifier,e);if(!r)throw new f("NOT_FOUND",`no customer for reference "${e}"`);return n.createPortalSession({customerId:r.id,returnUrl:t})},handleWebhook:async e=>{let t;try{const a=await e.text();t=await n.parseWebhook({headers:e.headers,payload:a})}catch(a){if(a instanceof f){const{body:i,status:d}=N(a);return y({error:i.message},d)}return y({error:"webhook error"},400)}const r=await F(s,t,o.observability);return r.reason==="orphaned"?y({applied:r.applied,reason:r.reason},500):y({applied:r.applied,reason:r.reason},200)},listBalances:async e=>{if(await u(e),n.getBalances)return n.getBalances(e);if(!o.entitlements)throw new f("CONFIG_INVALID","listBalances() requires `entitlements` to be configured");const t=await s.listSubscriptionsByReference(e),r=A(o.entitlements,t),a=U(o.entitlements),i=a.filter(c=>r.limit(c)!==void 0),d=i.length===0?new Map:await s.sumUsageByFeature(e,i,g(t));return a.map(c=>{const m=r.limit(c);return m!==void 0?{featureId:c,...w(m,d.get(c)??0,1)}:{featureId:c,allowed:r.has(c),unlimited:r.has(c)}})},listSubscriptions:async e=>(await u(e),s.listSubscriptionsByReference(e)),refundPayment:async e=>{const t=await p(e.sessionId),r=e.amount??K(t.capturedAmount,t.refundedAmount),a=T(t.refundedAmount,r);if(v(a,t.capturedAmount)>0)throw new f("VALIDATION_ERROR",`refundPayment(): refunding ${String(e.amount?.minorUnits)} would exceed the captured amount on session "${e.sessionId}"`);if(B(r))return t;const i=e.amount??(v(r,t.capturedAmount)===0?void 0:r),d=e.idempotencyKey??await b("refund_payment",n.identifier,e.sessionId,O(i),e.reason??""),c=await n.refundPayment({...e,amount:i,idempotencyKey:d});if(c.pending)return t;const m=D(e.sessionId,c.refundId,r);if(!await s.markEventProcessed(n.identifier,m,E)&&c.refundId!==void 0)return t;try{return await I(t,{refundedAmount:a,state:v(a,t.capturedAmount)<0?"partially_refunded":"refunded"})}catch(P){throw await s.releaseEvent(n.identifier,m),P}},store:s,track:async e=>{await u(e.referenceId);const t=e.quantity===void 0?1:e.quantity;if(!Number.isSafeInteger(t)||t<0)throw new f("VALIDATION_ERROR",`track(): \`quantity\` must be a non-negative safe integer (got ${String(e.quantity)})`);const r=e.idempotencyKey??crypto.randomUUID(),a=e.mode==="set";if(a&&n.capabilities.usageMetering&&n.reportUsage)throw new f("VALIDATION_ERROR",`track(): \`mode: "set"\` is not supported on "${n.identifier}", whose meter is additive — a lowering set cannot be forwarded, so the provider would over-bill against the local period total. Use \`mode: "add"\`.`);const i=a?await s.listSubscriptionsByReference(e.referenceId):void 0,d=i===void 0?0:await s.sumUsage(e.referenceId,e.featureId,g(i));if(a?t===d:t===0)return{recorded:!1,reportedToProvider:!1};const c=t;if(!await s.recordUsage({createdAt:$(),featureId:e.featureId,idempotencyKey:r,...a?{mode:"set"}:{},provider:n.identifier,quantity:t,referenceId:e.referenceId,reportedToProvider:!1}))return{recorded:!1,reportedToProvider:!1};if(c<=0||!n.capabilities.usageMetering||!n.reportUsage)return{recorded:!0,reportedToProvider:!1};try{const R=await s.getCustomerByReference(n.identifier,e.referenceId);return await n.reportUsage({customerId:R?.id,featureId:e.featureId,idempotencyKey:r,quantity:c,referenceId:e.referenceId}),await s.markUsageReported(n.identifier,r),{recorded:!0,reportedToProvider:!0}}catch{return C(o.observability,{featureId:e.featureId,provider:n.identifier,referenceId:e.referenceId,type:"usage.report_failed"}),{recorded:!0,reportedToProvider:!1}}}}};export{H as createPayment,G as webhookResponse};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const f=new Set(["active","trialing"]),u=s=>s.priceIds??[s.priceId],p=s=>{let t=0;for(const e of s)f.has(e.state)&&e.currentPeriodStart!==void 0&&(t=Math.max(t,e.currentPeriodStart));return t},S=s=>{const t=new Set;for(const e of Object.values(s.plans)){for(const a of e.features??[])t.add(a);for(const a of Object.keys(e.limits??{}))t.add(a)}return[...t].toSorted((e,a)=>e.localeCompare(a))},h=(s,t)=>s.some(e=>f.has(e.state)&&u(e).includes(t)),m=(s,t)=>{const e=new Set(t.filter(n=>f.has(n.state)).flatMap(n=>u(n))),a=[],r=new Set,c=new Map;for(const[n,i]of Object.entries(s.plans))if(i.priceIds.some(o=>e.has(o))){a.push(n);for(const o of i.features??[])r.add(o);for(const[o,l]of Object.entries(i.limits??{})){const d=c.get(o);c.set(o,d===void 0?l:Math.max(d,l))}}return{features:r,has:n=>r.has(n),limit:n=>c.get(n),plans:a}},v=async(s,t,e)=>m(t,await s.listSubscriptionsByReference(e));export{v as entitlementsForReference,S as featureNames,h as hasActivePrice,m as resolveEntitlements,p as usagePeriodStart};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
const r=new TextEncoder,c=new Set(["dodopayments","polar","stripe"]),a=async n=>[...new Uint8Array(await crypto.subtle.digest("SHA-256",r.encode(n)))].map(t=>t.toString(16).padStart(2,"0")).join(""),s=(n,...t)=>[n,...t.map(String)].join(":"),i=async(n,t,...e)=>{const o=await a(JSON.stringify([t,...e.map(String)]));return`${n}:${t}:${o}`},d=(n,t,e)=>t===void 0?`local-refund:${n}:${e.currency}:${String(e.minorUnits)}`:`local-refund:${n}:id:${t}`,y="marker.local_refund",p=n=>c.has(n);export{y as LOCAL_REFUND_CLAIM_TYPE,i as derivedIdempotencyKey,s as idempotencyKey,d as localRefundKey,p as usageForwardIsIdempotent};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{createPayment as i}from"./createPayment-
|
|
1
|
+
import{createPayment as i}from"./createPayment-Dimez2zY.mjs";import{createDatabasePaymentStore as s}from"./createDatabasePaymentStore-BGcHX1uq.mjs";const o=r=>({delete:async t=>r.delete(t),findFirst:async(t,e)=>await r.findFirst(t,{where:e}),findMany:async(t,e,a)=>{const n=await r.findMany(t,{...a,where:e});return{cursor:n.continueCursor??void 0,rows:n.page}},insert:async(t,e)=>r.insert(t,e),patch:async(t,e)=>r.patch(t,e)}),y=(r,t)=>{const e=r.auth?.userId??void 0;return i({adapter:t.adapter,authorize:t.authorize??(a=>a.trim()!==""&&e!==void 0&&a===e),entitlements:t.entitlements,observability:t.observability,store:s(o(r.db))})};export{o as lunoraDatabaseToPaymentDatabase,y as paymentsFromContext};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{defineTable as r}from"@lunora/server";import{v as e}from"@lunora/values";const n=r({createdAt:e.number(),email:e.optional(e.string()),provider:e.string(),providerCustomerId:e.string(),referenceId:e.string()}).index("by_provider_customer",["provider","providerCustomerId"],{unique:!0}).index("by_reference",["referenceId"]),i=r({cancelAtPeriodEnd:e.boolean(),createdAt:e.number(),currentPeriodEnd:e.optional(e.number()),currentPeriodStart:e.optional(e.number()),priceId:e.string(),priceIds:e.optional(e.array(e.string())),provider:e.string(),providerSubscriptionId:e.string(),quantity:e.number(),referenceId:e.string(),state:e.string(),updatedAt:e.number()}).index("by_provider_subscription",["provider","providerSubscriptionId"],{unique:!0}).index("by_reference",["referenceId"]),t=r({amountMinor:e.bigint(),capturedMinor:e.bigint(),createdAt:e.number(),currency:e.string(),provider:e.string(),providerSessionId:e.string(),referenceId:e.string(),refundedMinor:e.bigint(),state:e.string(),updatedAt:e.number()}).index("by_provider_session",["provider","providerSessionId"],{unique:!0}).index("by_reference",["referenceId"]),d=r({processedAt:e.number(),provider:e.string(),providerEventId:e.string(),type:e.string()}).index("by_provider_event",["provider","providerEventId"],{unique:!0}),o=r({createdAt:e.number(),featureId:e.string(),idempotencyKey:e.string(),mode:e.optional(e.string()),provider:e.string(),quantity:e.number(),referenceId:e.string(),reportedToProvider:e.boolean()}).index("by_idempotency",["provider","idempotencyKey"],{unique:!0}).index("by_reference_feature",["referenceId","featureId"]),p={customers:n,events:d,paymentSessions:t,subscriptions:i,usageEvents:o};export{p as default};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{usageForwardIsIdempotent as l}from"./idempotencyKey-qQJLcEQX.mjs";import{compareMoney as y}from"./addMoney-B4ufWAnD.mjs";import{n as u}from"./observability-BteZ2dJS.mjs";const I=100,f=(e,t)=>e.currency===t.currency&&y(e,t)===0,A=(e,t)=>e?.state!==t.state||e.cancelAtPeriodEnd!==t.cancelAtPeriodEnd||e.currentPeriodEnd!==t.currentPeriodEnd||e.priceId!==t.priceId||e.quantity!==t.quantity,b=(e,t)=>e?.state!==t.state||!f(e.capturedAmount,t.capturedAmount)||!f(e.refundedAmount,t.refundedAmount),p={captured:0,partially_refunded:1,refunded:2},w=(e,t)=>{if(!e)return t;const a=e.refundedAmount.currency===t.refundedAmount.currency&&y(e.refundedAmount,t.refundedAmount)>0?e.refundedAmount:t.refundedAmount,d=p[e.state],r=p[t.state],i=d!==void 0&&r!==void 0&&r<d?e.state:t.state,o=t.referenceId===""?e.referenceId:t.referenceId;return{...t,referenceId:o,refundedAmount:a,state:i}},S=(e,t)=>e===void 0||e===""?t:e,P=async(e,t,n,a)=>{const d=await e.getSubscriptionStatus(n),r=await t.getSubscription(e.identifier,n);return A(r,d)?(await t.upsertSubscription({...d,createdAt:r?.createdAt??d.createdAt,referenceId:S(r?.referenceId,d.referenceId)}),u(a,{id:n,kind:"subscription",provider:e.identifier,type:"reconcile.drift"}),!0):!1},v=async(e,t,n,a)=>{const d=await e.getPaymentStatus(n),r=await t.getPaymentSession(e.identifier,n),i=w(r,d);return b(r,i)?(await t.upsertPaymentSession({...i,createdAt:r?.createdAt??i.createdAt}),u(a,{id:n,kind:"payment",provider:e.identifier,type:"reconcile.drift"}),!0):!1},g=async(e,t,n,a)=>{const{reportUsage:d}=e;if(n<=0||d===void 0||!e.capabilities.usageMetering||!l(e.identifier))return{checked:0,failed:0,updated:0};const r=await t.listUnreportedUsage(e.identifier,n);let i=0,o=0;for(const c of r)try{const s=await t.getCustomerByReference(e.identifier,c.referenceId);await d({customerId:s?.id,featureId:c.featureId,idempotencyKey:c.idempotencyKey,quantity:c.quantity,referenceId:c.referenceId}),await t.markUsageReported(e.identifier,c.idempotencyKey),i+=1}catch{o+=1,u(a,{featureId:c.featureId,provider:e.identifier,referenceId:c.referenceId,type:"usage.report_failed"})}return{checked:r.length,failed:o,updated:i}},m=async(e,t,n,a,d)=>{const r=await Promise.allSettled(e.map(c=>n(c)));let i=0,o=0;for(const[c,s]of r.entries())s.status==="fulfilled"?s.value&&(i+=1):(o+=1,u(d,{error:s.reason,id:e[c]??"",kind:t,provider:a.identifier,type:"reconcile.error"}));return{failed:o,updated:i}},U=async e=>{const{adapter:t,observability:n,store:a}=e,d=e.subscriptionIds??[],r=e.paymentSessionIds??[],i=await m(d,"subscription",s=>P(t,a,s,n),t,n),o=await m(r,"payment",s=>v(t,a,s,n),t,n),c=await g(t,a,e.usageReportLimit??I,n);return u(n,{failedPayments:o.failed,failedSubscriptions:i.failed,provider:t.identifier,type:"reconcile.completed",updatedPayments:o.updated,updatedSubscriptions:i.updated}),{checkedPayments:r.length,checkedSubscriptions:d.length,checkedUsage:c.checked,failedPayments:o.failed,failedSubscriptions:i.failed,failedUsage:c.failed,updatedPayments:o.updated,updatedSubscriptions:i.updated,updatedUsage:c.updated}};export{U as reconcile};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { P as PaymentAdapter } from "../packem_shared/adapter.d-
|
|
1
|
+
import { P as PaymentAdapter } from "../packem_shared/adapter.d-DytKm_IF.mjs";
|
|
2
2
|
/**
|
|
3
3
|
* The `autumn-js` SDK surface the adapter uses, as a structural type — a real `Autumn` instance
|
|
4
4
|
* satisfies it without a cast. Resources/methods are `unknown` (the adapter re-types the client as
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { P as PaymentAdapter } from "../packem_shared/adapter.d-
|
|
1
|
+
import { P as PaymentAdapter } from "../packem_shared/adapter.d-DytKm_IF.js";
|
|
2
2
|
/**
|
|
3
3
|
* The `autumn-js` SDK surface the adapter uses, as a structural type — a real `Autumn` instance
|
|
4
4
|
* satisfies it without a cast. Resources/methods are `unknown` (the adapter re-types the client as
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { P as PaymentAdapter } from "../packem_shared/adapter.d-
|
|
1
|
+
import { P as PaymentAdapter } from "../packem_shared/adapter.d-DytKm_IF.mjs";
|
|
2
2
|
/**
|
|
3
3
|
* The `creem` SDK surface the adapter uses, as a structural type — a real `Creem` instance satisfies
|
|
4
4
|
* it without a cast. Resources are `unknown` (the adapter re-types the client as the real `Creem`
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { P as PaymentAdapter } from "../packem_shared/adapter.d-
|
|
1
|
+
import { P as PaymentAdapter } from "../packem_shared/adapter.d-DytKm_IF.js";
|
|
2
2
|
/**
|
|
3
3
|
* The `creem` SDK surface the adapter uses, as a structural type — a real `Creem` instance satisfies
|
|
4
4
|
* it without a cast. Resources are `unknown` (the adapter re-types the client as the real `Creem`
|
package/dist/providers/creem.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{a as o,c as u,f as m,r as c,b as p,p as f,d as v,e as w}from"../packem_shared/json-BJJPJVYj.mjs";import{money as I,zeroMoney as g}from"../packem_shared/addMoney-B4ufWAnD.mjs";import{verifyCreemSignature as A}from"../packem_shared/constantTimeEqual-ggrwGvRa.mjs";import{m as E}from"../packem_shared/not-supported-Cl0brzhn.mjs";import{s as P}from"../packem_shared/subscription-event-C8GiQSFM.mjs";const k=/already exists/iu,C={canceled:"canceled",completed:"captured",expired:"canceled",paid:"captured",partially_refunded:"partially_refunded",pending:"initiated",refunded:"refunded"},h={active:"active",canceled:"canceled",cancelled:"canceled",expired:"canceled",incomplete:"past_due",paid:"active",past_due:"past_due",paused:"paused",scheduled_cancel:"active",trialing:"trialing",unpaid:"past_due"},_=E("creem (merchant-of-record)"),i=a=>typeof a=="string"?a:c(o(a),"id"),T=a=>u(a,"checkout_url","checkoutUrl")??"",S=a=>u(a,"canceled_at","canceledAt")!==void 0||c(a,"status")==="scheduled_cancel",
|
|
1
|
+
import{a as o,c as u,f as m,r as c,b as p,p as f,d as v,e as w}from"../packem_shared/json-BJJPJVYj.mjs";import{money as I,zeroMoney as g}from"../packem_shared/addMoney-B4ufWAnD.mjs";import{verifyCreemSignature as A}from"../packem_shared/constantTimeEqual-ggrwGvRa.mjs";import{m as E}from"../packem_shared/not-supported-Cl0brzhn.mjs";import{s as P}from"../packem_shared/subscription-event-C8GiQSFM.mjs";const k=/already exists/iu,C={canceled:"canceled",completed:"captured",expired:"canceled",paid:"captured",partially_refunded:"partially_refunded",pending:"initiated",refunded:"refunded"},h={active:"active",canceled:"canceled",cancelled:"canceled",expired:"canceled",incomplete:"past_due",paid:"active",past_due:"past_due",paused:"paused",scheduled_cancel:"active",trialing:"trialing",unpaid:"past_due"},_=E("creem (merchant-of-record)"),i=a=>typeof a=="string"?a:c(o(a),"id"),T=a=>u(a,"checkout_url","checkoutUrl")??"",S=a=>u(a,"canceled_at","canceledAt")!==void 0||c(a,"status")==="scheduled_cancel",B=a=>{if(!(a instanceof Error))return!1;const{statusCode:r}=a;return typeof r=="number"&&r!==400&&r!==409?!1:k.test(a.message)},l=a=>{const r=o(a),t=Date.now(),e=c(r,"status")??"";return{cancelAtPeriodEnd:S(r),createdAt:t,currentPeriodEnd:f(u(r,"current_period_end_date","currentPeriodEndDate")),currentPeriodStart:f(u(r,"current_period_start_date","currentPeriodStartDate")),id:c(r,"id")??"",priceId:i(r.product)??"",provider:"creem",quantity:p(r,"units")??1,referenceId:m(r)??i(r.customer)??"",state:h[e]??"past_due",updatedAt:t}},D=a=>{const r=o(a),t=Date.now(),e=o(r.order),n=c(e,"currency")??c(r,"currency")??"usd",s=I(BigInt(Math.round(p(e,"amount")??p(r,"amount")??0)),n),d=C[c(e,"status")??c(r,"status")??""]??"initiated";return{amount:s,capturedAmount:d==="captured"||d==="partially_refunded"||d==="refunded"?s:g(n),createdAt:t,id:c(r,"id")??"",provider:"creem",referenceId:m(r)??"",refundedAmount:d==="refunded"?s:g(n),state:d,updatedAt:t}},M=(a,r,t)=>{const e={eventId:a,provider:"creem",raw:{object:t,type:r}},n=o(t.order),s=c(n,"currency")??c(t,"currency")??"usd";switch(r){case"checkout.completed":{const d=p(n,"amount")??p(t,"amount");return{...e,amount:d===void 0?void 0:I(BigInt(Math.round(d)),s),customerId:i(t.customer),referenceId:m(t),sessionId:c(t,"id"),subscriptionId:i(t.subscription),type:"payment.captured"}}case"refund.created":{if(c(t,"status")!=="succeeded")return{...e,type:"unhandled"};const d=w(t,"refund_amount","refundAmount","amount")??p(n,"amount"),y=u(t,"refund_currency","refundCurrency")??s;return{...e,amount:d===void 0?void 0:I(BigInt(Math.round(d)),y),referenceId:m(t),refundId:c(t,"id"),sessionId:i(t.checkout)??i(t.transaction)??i(t.subscription)??i(t.order)??c(t,"id"),type:"payment.refunded"}}case"subscription.active":case"subscription.canceled":case"subscription.expired":case"subscription.paid":case"subscription.past_due":case"subscription.paused":case"subscription.scheduled_cancel":case"subscription.trialing":case"subscription.unpaid":case"subscription.update":{const d=r==="subscription.scheduled_cancel"?"scheduled_cancel":c(t,"status");return{...e,cancelAtPeriodEnd:v(t,"cancel_at_period_end")??S(t),currentPeriodEnd:f(u(t,"current_period_end_date","currentPeriodEndDate")),currentPeriodStart:f(u(t,"current_period_start_date","currentPeriodStartDate")),customerId:i(t.customer),priceId:i(t.product),referenceId:m(t)??i(t.customer),subscriptionId:c(t,"id"),type:P(h[d??""]??"past_due")}}default:return{...e,type:"unhandled"}}},O=a=>{const{webhookSecret:r}=a,t=a.client;return{cancelPayment:()=>_("manual payment cancellation"),cancelSubscription:async(e,n)=>l(await t.subscriptions.cancel(e,{mode:n?.atPeriodEnd===!0?"scheduled":"immediate"})),capabilities:{merchantOfRecord:!0,portal:!0,usageMetering:!1},capturePayment:e=>_("manual capture"),createCheckout:async e=>{const n=await t.checkouts.create({customer:e.customerId?{id:e.customerId}:void 0,metadata:{...e.metadata,referenceId:e.referenceId},productId:e.priceId,requestId:e.idempotencyKey,successUrl:e.successUrl,units:e.quantity});return{id:c(n,"id")??"",provider:"creem",url:T(n)}},createPortalSession:async e=>{const n=await t.customers.generateBillingLinks({customerId:e.customerId});return{url:u(n,"customer_portal_link","customerPortalLink")??""}},getOrCreateCustomer:async e=>{const n=s=>({createdAt:Date.now(),email:c(s,"email")??e.email,id:c(s,"id")??"",provider:"creem",referenceId:e.referenceId});try{return n(o(await t.customers.create({email:e.email??"",metadata:{...e.metadata,referenceId:e.referenceId},name:e.metadata?.name??e.referenceId})))}catch(s){if(e.email!==void 0&&B(s)){const d=o(await t.customers.retrieve(void 0,e.email));if(m(d)!==e.referenceId)throw new Error(`Creem customer for email "${e.email}" already belongs to a different reference; refusing to bind it to "${e.referenceId}".`,{cause:s});return n(d)}throw s}},getPaymentStatus:async e=>D(await t.checkouts.retrieve(e)),getSubscriptionStatus:async e=>l(await t.subscriptions.get(e)),identifier:"creem",parseWebhook:async({headers:e,payload:n})=>{await A({payload:n,secret:r,signature:e.get("creem-signature")??""});const s=o(JSON.parse(n));return M(u(s,"id","event_id","eventId")??"",u(s,"eventType","type")??"",o(s.object))},refundPayment:()=>_("programmatic refunds"),resumeSubscription:async e=>l(await t.subscriptions.resume(e)),updateSubscription:async(e,n)=>n.priceId?l(await t.subscriptions.upgrade(e,{productId:n.priceId,updateBehavior:"proration-charge-immediately"})):l(await t.subscriptions.get(e))}};export{O as createCreemAdapter};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { P as PaymentAdapter } from "../packem_shared/adapter.d-
|
|
1
|
+
import { P as PaymentAdapter } from "../packem_shared/adapter.d-DytKm_IF.mjs";
|
|
2
2
|
/**
|
|
3
3
|
* The `dodopayments` SDK surface the adapter uses, as a structural type — a real `DodoPayments`
|
|
4
4
|
* instance satisfies it without a cast. Resources are `unknown` (the adapter re-types the client as
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { P as PaymentAdapter } from "../packem_shared/adapter.d-
|
|
1
|
+
import { P as PaymentAdapter } from "../packem_shared/adapter.d-DytKm_IF.js";
|
|
2
2
|
/**
|
|
3
3
|
* The `dodopayments` SDK surface the adapter uses, as a structural type — a real `DodoPayments`
|
|
4
4
|
* instance satisfies it without a cast. Resources are `unknown` (the adapter re-types the client as
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{LunoraPaymentError as
|
|
1
|
+
import{LunoraPaymentError as w}from"../packem_shared/LunoraPaymentError-BSxyhWgu.mjs";import{idempotencyKey as S}from"../packem_shared/idempotencyKey-qQJLcEQX.mjs";import{a as i,b as c,r as n,f as p,p as f,d as v}from"../packem_shared/json-BJJPJVYj.mjs";import{money as m,zeroMoney as b}from"../packem_shared/addMoney-B4ufWAnD.mjs";import{verifyStandardWebhook as h}from"../packem_shared/constantTimeEqual-ggrwGvRa.mjs";import{m as A}from"../packem_shared/not-supported-Cl0brzhn.mjs";import{s as P}from"../packem_shared/subscription-event-C8GiQSFM.mjs";const q={cancelled:"canceled",failed:"failed",partially_captured:"captured",partially_captured_and_capturable:"captured",processing:"initiated",requires_capture:"authorized",requires_confirmation:"initiated",requires_customer_action:"authorized",requires_merchant_action:"authorized",requires_payment_method:"initiated",succeeded:"captured"},g={active:"active",cancelled:"canceled",expired:"canceled",failed:"past_due",on_hold:"past_due",paused:"paused",pending:"past_due"},I=A("dodopayments (merchant-of-record)"),k=/^-?\d+$/,E=(d,a)=>{const t=d[a];return typeof t=="number"?Number.isFinite(t)?BigInt(Math.round(t)):void 0:typeof t=="string"&&k.test(t)?BigInt(t):void 0},y=d=>n(i(d.customer),"customer_id")??n(d,"customer_id"),_=d=>{const a=i(d),t=Date.now(),e=n(a,"status")??"";return{cancelAtPeriodEnd:v(a,"cancel_at_next_billing_date")??!1,createdAt:t,currentPeriodEnd:f(n(a,"next_billing_date")),currentPeriodStart:f(n(a,"previous_billing_date")),id:n(a,"subscription_id")??"",priceId:n(a,"product_id")??"",provider:"dodopayments",quantity:c(a,"quantity")??1,referenceId:p(a)??y(a)??"",state:g[e]??"past_due",updatedAt:t}},O=d=>{const{refunds:a}=d;if(!Array.isArray(a))return 0n;let t=0n;for(const e of a){const r=i(e),s=c(r,"amount");n(r,"status")==="succeeded"&&s!==void 0&&(t+=BigInt(Math.round(s)))}return t},D=d=>{const a=i(d),t=Date.now(),e=n(a,"currency")??"usd",r=m(BigInt(Math.round(c(a,"total_amount")??0)),e),s=q[n(a,"status")??""]??"initiated",o=s==="captured"?r:b(e),u=O(a);let l=s;return s==="captured"&&u>0n&&(l=u>=o.minorUnits?"refunded":"partially_refunded"),{amount:r,capturedAmount:o,createdAt:t,id:n(a,"payment_id")??"",provider:"dodopayments",referenceId:p(a)??"",refundedAmount:m(u,e),state:l,updatedAt:t}},T=(d,a,t)=>{const e={eventId:d,provider:"dodopayments",raw:{object:t,type:a}},r=n(t,"currency")??"usd";switch(a){case"dispute.lost":case"refund.succeeded":{const s=E(t,"amount");return{...e,amount:s===void 0?void 0:m(s,r),referenceId:p(t),refundId:n(t,"refund_id")??n(t,"dispute_id"),sessionId:n(t,"payment_id"),type:"payment.refunded"}}case"payment.cancelled":case"payment.failed":return{...e,referenceId:p(t),sessionId:n(t,"payment_id"),type:"payment.failed"};case"payment.succeeded":return{...e,amount:m(BigInt(Math.round(c(t,"total_amount")??0)),r),customerId:y(t),referenceId:p(t),sessionId:n(t,"payment_id"),subscriptionId:n(t,"subscription_id"),type:"payment.captured"};case"subscription.active":case"subscription.cancelled":case"subscription.expired":case"subscription.failed":case"subscription.on_hold":case"subscription.paused":case"subscription.plan_changed":case"subscription.renewed":case"subscription.updated":{const s=a==="subscription.paused"?"paused":n(t,"status");return{...e,cancelAtPeriodEnd:v(t,"cancel_at_next_billing_date"),currentPeriodEnd:f(n(t,"next_billing_date")),currentPeriodStart:f(n(t,"previous_billing_date")),customerId:y(t),priceId:n(t,"product_id"),quantity:c(t,"quantity"),referenceId:p(t)??y(t),subscriptionId:n(t,"subscription_id"),type:P(g[s??""]??"past_due")}}default:return{...e,type:"unhandled"}}},C=d=>{const{webhookSecret:a}=d,t=d.client;return{cancelPayment:()=>I("manual payment cancellation"),cancelSubscription:async(e,r)=>{const s=r?.atPeriodEnd?{cancel_at_next_billing_date:!0}:{status:"cancelled"};return _(await t.subscriptions.update(e,s))},capabilities:{merchantOfRecord:!0,portal:!0,usageMetering:!0},capturePayment:e=>I("manual capture"),createCheckout:async e=>{const r=i(await t.checkoutSessions.create({customer:e.customerId?{customer_id:e.customerId}:void 0,metadata:{...e.metadata,referenceId:e.referenceId},product_cart:[{product_id:e.priceId,quantity:e.quantity??1}],return_url:e.successUrl}));return{id:n(r,"session_id")??"",provider:"dodopayments",url:n(r,"checkout_url")??""}},createPortalSession:async e=>{const r=i(await t.customers.customerPortal.create(e.customerId,{return_url:e.returnUrl}));return{url:n(r,"link")??n(r,"url")??""}},getOrCreateCustomer:async e=>{const r=i(await t.customers.create({email:e.email??"",name:e.metadata?.name??e.referenceId},{idempotencyKey:S("customer","dodopayments",e.referenceId)}));return{createdAt:Date.now(),email:n(r,"email")??e.email,id:n(r,"customer_id")??"",provider:"dodopayments",referenceId:e.referenceId}},getPaymentStatus:async e=>D(await t.payments.retrieve(e)),getSubscriptionStatus:async e=>_(await t.subscriptions.retrieve(e)),identifier:"dodopayments",parseWebhook:async({headers:e,payload:r})=>{const s=e.get("webhook-id")??"";await h({payload:r,secret:a,toleranceSeconds:d.webhookToleranceSeconds,webhookId:s,webhookSignature:e.get("webhook-signature")??"",webhookTimestamp:e.get("webhook-timestamp")??""});const o=i(JSON.parse(r));return T(s,n(o,"type")??"",i(o.data))},refundPayment:async e=>{if(e.amount!==void 0)throw new w("PROVIDER_ERROR","dodopayments refunds a payment in full; partial refunds require line items and aren't supported here");const r=i(await t.refunds.create({payment_id:e.sessionId,reason:e.reason})),s=n(r,"currency")??"usd",o=m(BigInt(Math.round(c(r,"amount")??0)),s),u=n(r,"status")==="succeeded",l=u?"refunded":"captured";return{amount:o,capturedAmount:o,createdAt:Date.now(),id:e.sessionId,pending:!u,provider:"dodopayments",referenceId:"",refundedAmount:o,refundId:n(r,"refund_id"),state:l,updatedAt:Date.now()}},reportUsage:async e=>{await t.usageEvents.ingest({events:[{customer_id:e.customerId??e.referenceId,event_id:e.idempotencyKey,event_name:e.featureId,metadata:{value:e.quantity},timestamp:e.timestamp===void 0?void 0:new Date(e.timestamp).toISOString()}]})},resumeSubscription:async e=>{const r=await t.subscriptions.update(e,{cancel_at_next_billing_date:!1});return _(r)},updateSubscription:async(e,r)=>{if(r.priceId!==void 0||r.quantity!==void 0){const s=i(r.priceId!==void 0&&r.quantity!==void 0?void 0:await t.subscriptions.retrieve(e));await t.subscriptions.changePlan(e,{product_id:r.priceId??n(s,"product_id")??"",proration_billing_mode:"prorated_immediately",quantity:r.quantity??c(s,"quantity")??1})}return _(await t.subscriptions.retrieve(e))}}};export{C as createDodoPaymentsAdapter};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { P as PaymentAdapter } from "../packem_shared/adapter.d-
|
|
1
|
+
import { P as PaymentAdapter } from "../packem_shared/adapter.d-DytKm_IF.mjs";
|
|
2
2
|
/**
|
|
3
3
|
* The `@polar-sh/sdk` surface the adapter uses, as a structural type — a real `Polar` instance
|
|
4
4
|
* satisfies it without a cast. Resources are `unknown` (the adapter re-types the client as the real
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { P as PaymentAdapter } from "../packem_shared/adapter.d-
|
|
1
|
+
import { P as PaymentAdapter } from "../packem_shared/adapter.d-DytKm_IF.js";
|
|
2
2
|
/**
|
|
3
3
|
* The `@polar-sh/sdk` surface the adapter uses, as a structural type — a real `Polar` instance
|
|
4
4
|
* satisfies it without a cast. Resources are `unknown` (the adapter re-types the client as the real
|
package/dist/providers/polar.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{a as
|
|
1
|
+
import{a as f,r as n,f as p,d as A,p as I,b as c}from"../packem_shared/json-BJJPJVYj.mjs";import{money as m,zeroMoney as _}from"../packem_shared/addMoney-B4ufWAnD.mjs";import{verifyStandardWebhook as v}from"../packem_shared/constantTimeEqual-ggrwGvRa.mjs";import{m as b}from"../packem_shared/not-supported-Cl0brzhn.mjs";import{s as h}from"../packem_shared/subscription-event-C8GiQSFM.mjs";const w=s=>s instanceof Date?s.getTime():I(typeof s=="string"?s:void 0),g={draft:"initiated",paid:"captured",partially_refunded:"partially_refunded",pending:"initiated",refunded:"refunded",void:"canceled"},P={active:"active",canceled:"canceled",incomplete:"past_due",incomplete_expired:"canceled",past_due:"past_due",trialing:"trialing",unpaid:"past_due"},S=b("polar (merchant-of-record)"),l=s=>{const a=f(s),r=Date.now();return{cancelAtPeriodEnd:A(a,"cancelAtPeriodEnd")??!1,createdAt:r,currentPeriodEnd:w(a.currentPeriodEnd),currentPeriodStart:w(a.currentPeriodStart),id:n(a,"id")??"",priceId:n(a,"productId")??"",provider:"polar",quantity:1,referenceId:p(a)??"",state:P[n(a,"status")??""]??"past_due",updatedAt:r}},k=s=>{const a=f(s),r=Date.now(),e=n(a,"currency")??"usd",t=m(BigInt(Math.round(c(a,"totalAmount")??c(a,"amount")??0)),e),d=g[n(a,"status")??""]??"initiated",o=d==="captured"||d==="partially_refunded"||d==="refunded",i=c(a,"refundedAmount")??c(a,"refunded_amount"),u=d==="refunded"?t:_(e);return{amount:t,capturedAmount:o?t:_(e),createdAt:r,id:n(a,"id")??"",provider:"polar",referenceId:p(a)??"",refundedAmount:i===void 0?u:m(BigInt(Math.round(i)),e),state:d,updatedAt:r}},E=(s,a,r)=>{const e={eventId:s,provider:"polar",raw:{object:r,type:a}},t=n(r,"currency")??"usd";switch(a){case"order.created":case"order.paid":return a==="order.created"&&g[n(r,"status")??""]!=="captured"?{...e,type:"unhandled"}:{...e,amount:m(c(r,"total_amount")??c(r,"amount")??0,t),customerId:n(r,"customer_id"),referenceId:p(r),sessionId:n(r,"id"),subscriptionId:n(r,"subscription_id"),type:"payment.captured"};case"refund.created":case"refund.updated":return n(r,"status")!=="succeeded"?{...e,type:"unhandled"}:{...e,amount:m(c(r,"amount")??0,t),referenceId:p(r),refundId:n(r,"id"),sessionId:n(r,"order_id")??n(r,"id"),type:"payment.refunded"};case"subscription.active":case"subscription.canceled":case"subscription.created":case"subscription.revoked":case"subscription.uncanceled":case"subscription.updated":{const d=a==="subscription.revoked"?"subscription.canceled":h(P[n(r,"status")??""]??"past_due");return{...e,cancelAtPeriodEnd:A(r,"cancel_at_period_end"),currentPeriodEnd:I(n(r,"current_period_end")),currentPeriodStart:I(n(r,"current_period_start")),customerId:n(r,"customer_id"),priceId:n(r,"product_id"),referenceId:p(r),subscriptionId:n(r,"id"),type:d}}default:return{...e,type:"unhandled"}}},B=s=>{const{webhookSecret:a}=s,r=s.client;return{cancelPayment:()=>S("manual payment cancellation"),cancelSubscription:async(e,t)=>{const d=t?.atPeriodEnd?await r.subscriptions.update({id:e,subscriptionUpdate:{cancelAtPeriodEnd:!0}}):await r.subscriptions.revoke({id:e});return l(d)},capabilities:{merchantOfRecord:!0,portal:!0,usageMetering:!0},capturePayment:e=>S("manual capture"),createCheckout:async e=>{const t=await r.checkouts.create({customerEmail:e.customerId?void 0:e.email,customerId:e.customerId,externalCustomerId:e.referenceId,metadata:{...e.metadata,referenceId:e.referenceId},products:[e.priceId],returnUrl:e.cancelUrl,successUrl:e.successUrl});return{id:t.id,provider:"polar",url:t.url}},createPortalSession:async e=>({url:(await r.customerSessions.create({customerId:e.customerId})).customerPortalUrl}),getOrCreateCustomer:async e=>{const t=await r.customers.create({email:e.email??"",externalId:e.referenceId,metadata:{...e.metadata,referenceId:e.referenceId},type:"individual"});return{createdAt:Date.now(),email:t.email??void 0,id:t.id,provider:"polar",referenceId:e.referenceId}},getPaymentStatus:async e=>k(await r.orders.get({id:e})),getSubscriptionStatus:async e=>l(await r.subscriptions.get({id:e})),identifier:"polar",parseWebhook:async({headers:e,payload:t})=>{const d=e.get("webhook-id")??"";await v({payload:t,secret:a,toleranceSeconds:s.webhookToleranceSeconds,webhookId:d,webhookSignature:e.get("webhook-signature")??"",webhookTimestamp:e.get("webhook-timestamp")??""});const o=f(JSON.parse(t));return E(d,n(o,"type")??"",f(o.data))},refundPayment:async e=>{const t=e.amount?void 0:await r.orders.get({id:e.sessionId}),d=e.amount?.currency??t?.currency??"usd",o=e.amount?Number(e.amount.minorUnits):t?.totalAmount??0,i=await r.refunds.create({amount:o,orderId:e.sessionId,reason:e.reason??"customer_request"}),u=e.amount??m(BigInt(Math.round(o)),d),y=i.status==="succeeded";return{amount:u,capturedAmount:u,createdAt:Date.now(),id:e.sessionId,pending:!y,provider:"polar",referenceId:"",refundedAmount:u,refundId:i.id,state:y?"refunded":"captured",updatedAt:Date.now()}},reportUsage:async e=>{await r.events.ingest({events:[{externalCustomerId:e.referenceId,externalId:e.idempotencyKey,metadata:{value:e.quantity},name:e.featureId,timestamp:e.timestamp===void 0?void 0:new Date(e.timestamp)}]})},resumeSubscription:async e=>{const t=await r.subscriptions.update({id:e,subscriptionUpdate:{cancelAtPeriodEnd:!1}});return l(t)},updateSubscription:async(e,t)=>{const d=await r.subscriptions.update({id:e,subscriptionUpdate:t.priceId?{productId:t.priceId}:{}});return l(d)}}};export{B as createPolarAdapter};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { P as PaymentAdapter } from "../packem_shared/adapter.d-
|
|
1
|
+
import { P as PaymentAdapter } from "../packem_shared/adapter.d-DytKm_IF.mjs";
|
|
2
2
|
/**
|
|
3
3
|
* The Stripe SDK surface the adapter uses, as a structural type — a real `Stripe` instance satisfies
|
|
4
4
|
* it without a cast. Resources are `unknown` here (the adapter re-types the client as the real
|
|
@@ -12,6 +12,8 @@ interface StripeClientLike {
|
|
|
12
12
|
readonly customers: unknown;
|
|
13
13
|
readonly paymentIntents: unknown;
|
|
14
14
|
readonly refunds: unknown;
|
|
15
|
+
/** Only reached when a subscription's embedded `items` list is paginated — see `itemsComplete`. */
|
|
16
|
+
readonly subscriptionItems: unknown;
|
|
15
17
|
readonly subscriptions: unknown;
|
|
16
18
|
readonly webhooks: unknown;
|
|
17
19
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { P as PaymentAdapter } from "../packem_shared/adapter.d-
|
|
1
|
+
import { P as PaymentAdapter } from "../packem_shared/adapter.d-DytKm_IF.js";
|
|
2
2
|
/**
|
|
3
3
|
* The Stripe SDK surface the adapter uses, as a structural type — a real `Stripe` instance satisfies
|
|
4
4
|
* it without a cast. Resources are `unknown` here (the adapter re-types the client as the real
|
|
@@ -12,6 +12,8 @@ interface StripeClientLike {
|
|
|
12
12
|
readonly customers: unknown;
|
|
13
13
|
readonly paymentIntents: unknown;
|
|
14
14
|
readonly refunds: unknown;
|
|
15
|
+
/** Only reached when a subscription's embedded `items` list is paginated — see `itemsComplete`. */
|
|
16
|
+
readonly subscriptionItems: unknown;
|
|
15
17
|
readonly subscriptions: unknown;
|
|
16
18
|
readonly webhooks: unknown;
|
|
17
19
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{LunoraPaymentError as
|
|
1
|
+
import{LunoraPaymentError as T}from"../packem_shared/LunoraPaymentError-BSxyhWgu.mjs";import{idempotencyKey as f}from"../packem_shared/idempotencyKey-qQJLcEQX.mjs";import{a as c,r as i,d as v,b as u}from"../packem_shared/json-BJJPJVYj.mjs";import{compareMoney as q,money as y,zeroMoney as h}from"../packem_shared/addMoney-B4ufWAnD.mjs";import{assertWebhookSecret as M}from"../packem_shared/constantTimeEqual-ggrwGvRa.mjs";import{s as k}from"../packem_shared/subscription-event-C8GiQSFM.mjs";const B={canceled:"canceled",processing:"authorized",requires_action:"authorized",requires_capture:"authorized",requires_confirmation:"initiated",requires_payment_method:"initiated",succeeded:"captured"},w={active:"active",canceled:"canceled",incomplete:"past_due",incomplete_expired:"canceled",past_due:"past_due",paused:"paused",trialing:"trialing",unpaid:"past_due"},o=r=>i(c(r.metadata),"referenceId")??i(r,"client_reference_id"),S=r=>{const s=c(r.items);return Array.isArray(s.data)?s.data:[]},I=r=>c(S(r)[0]),g=r=>i(c(I(r).price),"id"),U=r=>{const s=[];for(const t of S(r)){const e=i(c(c(t).price),"id");e!==void 0&&e!==""&&s.push(e)}return s},N=r=>v(c(r.items),"has_more")!==!0,A=r=>N(r)?U(r):void 0,K=r=>u(I(r),"quantity"),P=r=>{const s=u(I(r),"current_period_end")??u(r,"current_period_end");return s===void 0?void 0:s*1e3},E=r=>{const s=u(I(r),"current_period_start")??u(r,"current_period_start");return s===void 0?void 0:s*1e3},_=r=>{const s=c(r),t=i(s,"currency")??"usd",e=u(s,"amount")??0,n=y(BigInt(Math.round(e)),t),a=B[i(s,"status")??""]??"initiated",d=Date.now();return{amount:n,capturedAmount:a==="captured"?y(BigInt(Math.round(u(s,"amount_received")??e)),t):h(t),createdAt:d,id:i(s,"id")??"",provider:"stripe",referenceId:o(s)??"",refundedAmount:h(t),state:a,updatedAt:d}},l=r=>{const s=c(r),t=Date.now();return{cancelAtPeriodEnd:v(s,"cancel_at_period_end")??!1,createdAt:t,currentPeriodEnd:P(s),currentPeriodStart:E(s),id:i(s,"id")??"",priceId:g(s)??"",priceIds:A(s),provider:"stripe",quantity:K(s)??1,referenceId:o(s)??"",state:w[i(s,"status")??""]??"past_due",updatedAt:t}},R=({base:r,currency:s,object:t})=>{const e=i(t,"payment_status"),n=e==="paid"||e==="no_payment_required";if(i(t,"mode")==="subscription")return{...r,customerId:i(t,"customer"),referenceId:o(t),subscriptionId:i(t,"subscription"),type:n?"subscription.active":"subscription.updated"};const a=i(t,"payment_intent");if(a===void 0&&e!=="no_payment_required")return{...r,type:"unhandled"};const d=u(t,"amount_total");return{...r,amount:d===void 0?void 0:y(BigInt(Math.round(d)),s),customerId:i(t,"customer"),referenceId:o(t),sessionId:a??i(t,"id"),type:n?"payment.captured":"payment.authorized"}},z=({base:r,currency:s,object:t})=>i(t,"status")!=="lost"?{...r,type:"unhandled"}:{...r,amount:y(BigInt(Math.round(u(t,"amount")??0)),s),referenceId:o(t),refundId:i(t,"id"),sessionId:i(t,"payment_intent"),type:"payment.refunded"},C=(r,s,t)=>{const e={eventId:r,provider:"stripe",raw:{object:t,type:s}},n=i(t,"currency")??"usd",a={base:e,currency:n,object:t};switch(s){case"charge.dispute.closed":return z(a);case"charge.refunded":return{...e,amount:y(BigInt(Math.round(u(t,"amount_refunded")??0)),n),amountKind:"absolute",referenceId:o(t),sessionId:i(t,"payment_intent")??i(t,"id"),type:"payment.refunded"};case"checkout.session.async_payment_failed":return i(t,"mode")==="subscription"?{...e,customerId:i(t,"customer"),referenceId:o(t),subscriptionId:i(t,"subscription"),type:"subscription.past_due"}:{...e,referenceId:o(t),sessionId:i(t,"payment_intent")??i(t,"id"),type:"payment.failed"};case"checkout.session.async_payment_succeeded":case"checkout.session.completed":return R(a);case"customer.subscription.created":case"customer.subscription.updated":return{...e,cancelAtPeriodEnd:v(t,"cancel_at_period_end"),currentPeriodEnd:P(t),currentPeriodStart:E(t),customerId:i(t,"customer"),priceId:g(t),priceIds:A(t),quantity:K(t),referenceId:o(t),subscriptionId:i(t,"id"),type:k(w[i(t,"status")??""]??"past_due")};case"customer.subscription.deleted":return{...e,referenceId:o(t),subscriptionId:i(t,"id"),type:"subscription.canceled"};case"payment_intent.amount_capturable_updated":return{...e,amount:y(BigInt(Math.round(u(t,"amount")??0)),n),referenceId:o(t),sessionId:i(t,"id"),type:"payment.authorized"};case"payment_intent.payment_failed":return{...e,referenceId:o(t),sessionId:i(t,"id"),type:"payment.failed"};case"payment_intent.succeeded":return{...e,amount:y(BigInt(Math.round(u(t,"amount_received")??u(t,"amount")??0)),n),customerId:i(t,"customer"),referenceId:o(t),sessionId:i(t,"id"),type:"payment.captured"};default:return{...e,type:"unhandled"}}},L=r=>{const{webhookSecret:s}=r,t=r.client;return{cancelPayment:async(e,n)=>{const a=await t.paymentIntents.cancel(e,void 0,{idempotencyKey:n?.idempotencyKey});return _(a)},cancelSubscription:async(e,n)=>{const a=n?.atPeriodEnd?await t.subscriptions.update(e,{cancel_at_period_end:!0},{idempotencyKey:n.idempotencyKey}):await t.subscriptions.cancel(e,void 0,{idempotencyKey:n?.idempotencyKey});return l(a)},capabilities:{merchantOfRecord:!1,portal:!0,usageMetering:!0},capturePayment:async e=>{const n=await t.paymentIntents.capture(e.sessionId,e.amount?{amount_to_capture:Number(e.amount.minorUnits)}:void 0,{idempotencyKey:e.idempotencyKey});return _(n)},createCheckout:async e=>{const n=await t.checkout.sessions.create({cancel_url:e.cancelUrl,client_reference_id:e.referenceId,customer:e.customerId,line_items:[{price:e.priceId,quantity:e.quantity??1}],metadata:{...e.metadata,referenceId:e.referenceId},mode:e.mode,subscription_data:e.mode==="subscription"?{metadata:{referenceId:e.referenceId}}:void 0,success_url:e.successUrl},{idempotencyKey:e.idempotencyKey});return{id:n.id,provider:"stripe",url:n.url??""}},createPortalSession:async e=>({url:(await t.billingPortal.sessions.create({customer:e.customerId,return_url:e.returnUrl})).url}),getOrCreateCustomer:async e=>{const n=await t.customers.create({email:e.email,metadata:{...e.metadata,referenceId:e.referenceId}},{idempotencyKey:f("customer","stripe",e.referenceId)});return{createdAt:Date.now(),email:n.email??void 0,id:n.id,provider:"stripe",referenceId:e.referenceId}},getPaymentStatus:async e=>_(await t.paymentIntents.retrieve(e)),getSubscriptionStatus:async e=>{const n=await t.subscriptions.retrieve(e),a=l(n);if(a.priceIds!==void 0)return a;const d=[];for await(const p of t.subscriptionItems.list({limit:100,subscription:e})){const m=i(c(c(p).price),"id");m!==void 0&&m!==""&&d.push(m)}return{...a,priceIds:d}},identifier:"stripe",parseWebhook:async({headers:e,payload:n})=>{M(s);const a=e.get("stripe-signature")??"";let d;try{d=await t.webhooks.constructEventAsync(n,a,s,r.webhookToleranceSeconds)}catch(m){throw new T("WEBHOOK_SIGNATURE_INVALID",m instanceof Error?m.message:"invalid webhook signature")}const p=c(c(d.data).object);return C(d.id,d.type,p)},refundPayment:async e=>{const n=await t.refunds.create({amount:e.amount?Number(e.amount.minorUnits):void 0,payment_intent:e.sessionId,reason:e.reason},{idempotencyKey:e.idempotencyKey}),a=await t.paymentIntents.retrieve(e.sessionId),d=_(a),p=e.amount??d.capturedAmount,m=e.amount!==void 0&&q(e.amount,d.capturedAmount)<0;return{...d,refundedAmount:p,refundId:n.id,state:m?"partially_refunded":"refunded"}},reportUsage:async e=>{await t.billing.meterEvents.create({event_name:e.featureId,identifier:e.idempotencyKey,payload:{stripe_customer_id:e.customerId??"",value:String(e.quantity)},timestamp:e.timestamp===void 0?void 0:Math.floor(e.timestamp/1e3)},{idempotencyKey:e.idempotencyKey})},resumeSubscription:async(e,n)=>{const a=await t.subscriptions.update(e,{cancel_at_period_end:!1},{idempotencyKey:n?.idempotencyKey??f("resume_subscription","stripe",e)});return l(a)},updateSubscription:async(e,n)=>{const a={};if(n.priceId!==void 0||n.quantity!==void 0){const p=await t.subscriptions.retrieve(e);a.items=[{id:p.items.data[0]?.id,price:n.priceId,quantity:n.quantity}]}const d=await t.subscriptions.update(e,a,{idempotencyKey:n.idempotencyKey??f("update_subscription","stripe",e,n.priceId??"",n.quantity??"")});return l(d)}}};export{L as createStripeAdapter};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lunora/payment",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.126",
|
|
4
4
|
"description": "Provider-agnostic payments for Lunora: Stripe-first adapter, webhook sync, and subscription/payment state machine",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"billing",
|
|
@@ -72,8 +72,8 @@
|
|
|
72
72
|
},
|
|
73
73
|
"dependencies": {
|
|
74
74
|
"@lunora/errors": "1.0.0-alpha.36",
|
|
75
|
-
"@lunora/server": "1.0.0-alpha.
|
|
76
|
-
"@lunora/values": "1.0.0-alpha.
|
|
75
|
+
"@lunora/server": "1.0.0-alpha.124",
|
|
76
|
+
"@lunora/values": "1.0.0-alpha.46",
|
|
77
77
|
"dinero.js": "2.0.2"
|
|
78
78
|
},
|
|
79
79
|
"peerDependencies": {
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{LunoraPaymentError as P}from"./LunoraPaymentError-BSxyhWgu.mjs";import{localRefundKey as A,LOCAL_REFUND_CLAIM_TYPE as E}from"./idempotencyKey-DBL6bpmj.mjs";import{zeroMoney as o,compareMoney as l,addMoney as _}from"./addMoney-B4ufWAnD.mjs";import{n as i}from"./observability-BteZ2dJS.mjs";import{nextPaymentState as S,nextSubscriptionState as w}from"./PAYMENT_TERMINAL_STATES-Dxxpk_br.mjs";const b={"payment.authorized":"authorize","payment.captured":"capture","payment.failed":"fail","payment.refunded":"refund"},h={"subscription.active":"active","subscription.canceled":"canceled","subscription.past_due":"past_due","subscription.paused":"paused"},T="orphan-retry:",R="marker.orphan_retry",k={"subscription.active":"activate","subscription.canceled":"cancel","subscription.past_due":"mark_past_due","subscription.paused":"pause"},O=(t,e)=>l(t,e)>0?t:e,Y=new Set(["authorized","initiated"]),N=async(t,e,r)=>{if(!r||!e.sessionId||!e.amount||e.amountKind==="absolute")return e;const n=A(e.sessionId,e.refundId,e.amount),d=await t.markEventProcessed(e.provider,n,E);return await t.releaseEvent(e.provider,n),d?e:{...e,amount:o(e.amount.currency)}},I=(t,e)=>{if(!e.amount||t.refundedAmount.currency!==e.amount.currency||t.capturedAmount.currency!==e.amount.currency)return;const r=e.amountKind==="absolute"?O(e.amount,t.refundedAmount):_(t.refundedAmount,e.amount);if(!(l(r,t.capturedAmount)>0))return r},M=(t,e)=>{if(!t)return"refund";const r=I(t,e);return r&&l(r,t.capturedAmount)<0?"partial_refund":"refund"},q=async(t,e,r)=>{if(!e.sessionId)return{applied:!1,reason:"unhandled"};const n=await t.getPaymentSession(e.provider,e.sessionId),d=n?.state??"initiated",u=Date.now(),s=e.amount?.currency??n?.amount.currency??"USD",c=r==="refund"?await N(t,e,n):e,a=r==="refund"?M(n,c):r,m=S(d,a);if(!m)return{applied:!1,reason:r==="refund"&&Y.has(d)?"orphaned":"illegal_transition"};const p=n??{amount:e.amount??o(s),capturedAmount:o(s),createdAt:u,id:e.sessionId,provider:e.provider,referenceId:e.referenceId??"",refundedAmount:o(s),state:d,updatedAt:u};let{capturedAmount:y,refundedAmount:v}=p;if(a==="capture"&&e.amount&&(y=e.amount),(a==="partial_refund"||a==="refund")&&c.amount){const f=I(p,c);if(!f)return{applied:!1,reason:"invalid_refund_amount"};v=f}return await t.upsertPaymentSession({...p,capturedAmount:y,referenceId:e.referenceId??p.referenceId,refundedAmount:v,state:m,updatedAt:u}),{applied:!0,reason:"ok"}},C=(t,e,r)=>{if(e==="active"){if(t==="active")return"renew";if(t==="paused")return"resume"}return k[r]},g=async(t,e)=>{if(!e.subscriptionId)return{applied:!1,reason:"unhandled"};const r=await t.getSubscription(e.provider,e.subscriptionId),n=Date.now();if(e.type==="subscription.updated")return r?(await t.upsertSubscription({...r,cancelAtPeriodEnd:e.cancelAtPeriodEnd??r.cancelAtPeriodEnd,currentPeriodEnd:e.currentPeriodEnd??r.currentPeriodEnd,currentPeriodStart:e.currentPeriodStart??r.currentPeriodStart,priceId:e.priceId??r.priceId,quantity:e.quantity??r.quantity,updatedAt:n}),{applied:!0,reason:"ok"}):{applied:!1,reason:"orphaned"};const d=h[e.type];if(!d)return{applied:!1,reason:"unhandled"};if(!r)return await t.upsertSubscription({cancelAtPeriodEnd:e.cancelAtPeriodEnd??!1,createdAt:n,currentPeriodEnd:e.currentPeriodEnd,currentPeriodStart:e.currentPeriodStart??n,id:e.subscriptionId,priceId:e.priceId??"",provider:e.provider,quantity:e.quantity??1,referenceId:e.referenceId??"",state:d,updatedAt:n}),{applied:!0,reason:"ok"};const u=C(r.state,d,e.type),s=u?w(r.state,u):void 0;return s?(await t.upsertSubscription({...r,cancelAtPeriodEnd:e.cancelAtPeriodEnd??r.cancelAtPeriodEnd,currentPeriodEnd:e.currentPeriodEnd??r.currentPeriodEnd,currentPeriodStart:e.currentPeriodStart??r.currentPeriodStart,priceId:e.priceId??r.priceId,quantity:e.quantity??r.quantity,state:s,updatedAt:n}),{applied:!0,reason:"ok"}):{applied:!1,reason:"illegal_transition"}},U=async(t,e,r)=>{if(e.type==="unhandled")return{applied:!1,reason:"unhandled"};if(!e.eventId?.trim())throw new P("WEBHOOK_EVENT_ID_MISSING",`webhook event id is missing or blank for provider "${e.provider}"`);if(!await t.markEventProcessed(e.provider,e.eventId,e.type))return i(r,{eventId:e.eventId,provider:e.provider,type:"webhook.duplicate"}),{applied:!1,reason:"duplicate"};const d=b[e.type];let u;try{u=d?await q(t,e,d):await g(t,e)}catch(s){throw await t.releaseEvent(e.provider,e.eventId),s}return u.reason==="orphaned"&&(await t.markEventProcessed(e.provider,`${T}${e.eventId}`,R)?await t.releaseEvent(e.provider,e.eventId):u={applied:!1,reason:"unhandled"}),i(r,{action:e.type,eventId:e.eventId,provider:e.provider,reason:u.reason,type:"webhook.applied"}),e.type==="payment.failed"?i(r,{provider:e.provider,referenceId:e.referenceId,sessionId:e.sessionId,type:"payment.failed"}):e.type==="subscription.past_due"&&i(r,{provider:e.provider,referenceId:e.referenceId,subscriptionId:e.subscriptionId,type:"subscription.past_due"}),u};export{U as default};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{money as y}from"./addMoney-B4ufWAnD.mjs";import{foldUsage as m}from"./MemoryPaymentStore-CZbrrEb1.mjs";const o=(e,d)=>typeof e[d]=="string"?e[d]:"",l=(e,d)=>typeof e[d]=="string"?e[d]:void 0,c=(e,d)=>typeof e[d]=="number"?e[d]:0,v=(e,d)=>typeof e[d]=="number"?e[d]:void 0,A=(e,d)=>e[d]===!0,f=(e,d)=>{const t=e[d];return typeof t=="bigint"?t:typeof t=="number"||typeof t=="string"?BigInt(t):0n},S=e=>({createdAt:e.createdAt,email:e.email,provider:e.provider,providerCustomerId:e.id,referenceId:e.referenceId}),P=e=>({createdAt:c(e,"createdAt"),email:l(e,"email"),id:o(e,"providerCustomerId"),provider:o(e,"provider"),referenceId:o(e,"referenceId")}),E=e=>({amountMinor:e.amount.minorUnits,capturedMinor:e.capturedAmount.minorUnits,createdAt:e.createdAt,currency:e.amount.currency,provider:e.provider,providerSessionId:e.id,referenceId:e.referenceId,refundedMinor:e.refundedAmount.minorUnits,state:e.state,updatedAt:e.updatedAt}),M=e=>{const d=o(e,"currency");return{amount:y(f(e,"amountMinor"),d),capturedAmount:y(f(e,"capturedMinor"),d),createdAt:c(e,"createdAt"),id:o(e,"providerSessionId"),provider:o(e,"provider"),referenceId:o(e,"referenceId"),refundedAmount:y(f(e,"refundedMinor"),d),state:o(e,"state"),updatedAt:c(e,"updatedAt")}},T=e=>({cancelAtPeriodEnd:e.cancelAtPeriodEnd,createdAt:e.createdAt,currentPeriodEnd:e.currentPeriodEnd,currentPeriodStart:e.currentPeriodStart,priceId:e.priceId,provider:e.provider,providerSubscriptionId:e.id,quantity:e.quantity,referenceId:e.referenceId,state:e.state,updatedAt:e.updatedAt}),I=e=>({cancelAtPeriodEnd:A(e,"cancelAtPeriodEnd"),createdAt:c(e,"createdAt"),currentPeriodEnd:v(e,"currentPeriodEnd"),currentPeriodStart:v(e,"currentPeriodStart"),id:o(e,"providerSubscriptionId"),priceId:o(e,"priceId"),provider:o(e,"provider"),quantity:c(e,"quantity"),referenceId:o(e,"referenceId"),state:o(e,"state"),updatedAt:c(e,"updatedAt")}),q=e=>({createdAt:c(e,"createdAt"),featureId:o(e,"featureId"),idempotencyKey:o(e,"idempotencyKey"),mode:e.mode==="set"?"set":"add",provider:o(e,"provider"),quantity:c(e,"quantity"),referenceId:o(e,"referenceId"),reportedToProvider:A(e,"reportedToProvider")}),K=e=>({createdAt:e.createdAt,featureId:e.featureId,idempotencyKey:e.idempotencyKey,...e.mode==="set"?{mode:"set"}:{},provider:e.provider,quantity:e.quantity,referenceId:e.referenceId,reportedToProvider:e.reportedToProvider}),F=e=>{const d=async(t,i,r)=>{const a=await e.findFirst(t,i);if(a){await e.patch(a._id,r);return}await e.insert(t,r)};return{getCustomerByReference:async(t,i)=>{const r=await e.findFirst("customers",{provider:t,referenceId:i});return r?P(r):void 0},getPaymentSession:async(t,i)=>{const r=await e.findFirst("paymentSessions",{provider:t,providerSessionId:i});return r?M(r):void 0},getSubscription:async(t,i)=>{const r=await e.findFirst("subscriptions",{provider:t,providerSubscriptionId:i});return r?I(r):void 0},listSubscriptionsByReference:async t=>{const{rows:i}=await e.findMany("subscriptions",{referenceId:t});return i.map(r=>I(r))},listUnreportedUsage:async(t,i)=>{const r=Math.max(0,Math.floor(i));if(r===0)return[];const a=[{createdAt:"asc"},{idempotencyKey:"asc"}],s=[];let n;do{const u=await e.findMany("usageEvents",{provider:t,reportedToProvider:!1},{cursor:n,limit:r,orderBy:a});for(const g of u.rows){const p=q(g);if(p.mode!=="set"&&p.quantity>0&&(s.push(p),s.length===r))return s}n=u.cursor}while(n!==void 0);return s},markEventProcessed:async(t,i,r)=>await e.findFirst("events",{provider:t,providerEventId:i})?!1:(await e.insert("events",{processedAt:Date.now(),provider:t,providerEventId:i,type:r}),!0),releaseEvent:async(t,i)=>{const r=await e.findFirst("events",{provider:t,providerEventId:i});r&&await e.delete(r._id)},markUsageReported:async(t,i)=>{const r=await e.findFirst("usageEvents",{idempotencyKey:i,provider:t});r&&await e.patch(r._id,{reportedToProvider:!0})},recordUsage:async t=>await e.findFirst("usageEvents",{idempotencyKey:t.idempotencyKey,provider:t.provider})?!1:(await e.insert("usageEvents",K(t)),!0),sumUsage:async(t,i,r)=>{const{rows:a}=await e.findMany("usageEvents",{featureId:i,referenceId:t}),s=a.filter(n=>c(n,"createdAt")>=r).map(n=>({createdAt:c(n,"createdAt"),idempotencyKey:typeof n.idempotencyKey=="string"?n.idempotencyKey:"",mode:n.mode==="set"?"set":"add",quantity:c(n,"quantity")}));return m(s)},sumUsageByFeature:async(t,i,r)=>{const{rows:a}=await e.findMany("usageEvents",{referenceId:t}),s=new Map(i.map(n=>[n,[]]));for(const n of a)c(n,"createdAt")<r||s.get(typeof n.featureId=="string"?n.featureId:"")?.push({createdAt:c(n,"createdAt"),idempotencyKey:typeof n.idempotencyKey=="string"?n.idempotencyKey:"",mode:n.mode==="set"?"set":"add",quantity:c(n,"quantity")});return new Map([...s].map(([n,u])=>[n,m(u)]))},upsertCustomer:async t=>d("customers",{provider:t.provider,referenceId:t.referenceId},S(t)),upsertPaymentSession:async t=>d("paymentSessions",{provider:t.provider,providerSessionId:t.id},E(t)),upsertSubscription:async t=>d("subscriptions",{provider:t.provider,providerSubscriptionId:t.id},T(t))}};export{F as createDatabasePaymentStore};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{toErrorBody as P}from"@lunora/errors";import{usagePeriodStart as b,resolveEntitlements as A,featureNames as N,hasActivePrice as U}from"./entitlementsForReference-Bq-9UUL8.mjs";import{LunoraPaymentError as f}from"./LunoraPaymentError-BSxyhWgu.mjs";import{derivedIdempotencyKey as v,localRefundKey as _,LOCAL_REFUND_CLAIM_TYPE as D,idempotencyKey as k}from"./idempotencyKey-DBL6bpmj.mjs";import{subtractMoney as E,addMoney as K,compareMoney as R,isZeroMoney as B}from"./addMoney-B4ufWAnD.mjs";import{n as T}from"./observability-BteZ2dJS.mjs";import C from"./applyWebhookAction-DqM4qNr3.mjs";const y=(o,n=200,s)=>{const m=new Headers({"content-type":"application/json"});for(const[l,w]of Object.entries({}))m.set(l,w);return Response.json(o,{headers:m,status:n})};let h=0;const F=()=>{const o=Date.now();return h=o>h?o:h+1,h},S=o=>o?`${o.currency}:${String(o.minorUnits)}`:"full",q=o=>o&&"referenceId"in o?Object.fromEntries(Object.entries(o).filter(([n])=>n!=="referenceId")):o,W=o=>y({applied:o.applied},o.status),G=o=>{const{adapter:n,store:s}=o,m=async e=>{if(!o.authorize)return;let t;try{t=await o.authorize(e)}catch{throw new f("FORBIDDEN",`caller not authorized for reference "${e}"`)}if(t!==!0)throw new f("FORBIDDEN",`caller not authorized for reference "${e}"`)},l=async e=>{await m(e.referenceId);const t=q(e.metadata);let r;const a=await s.getCustomerByReference(n.identifier,e.referenceId);if(a)r=a.id;else{const d=await n.getOrCreateCustomer({email:e.email,referenceId:e.referenceId});r=d.id,await s.upsertCustomer(d)}const i=e.idempotencyKey??await v("checkout",n.identifier,e.referenceId,e.priceId,e.mode,String(e.quantity??1),e.successUrl,e.cancelUrl,t?JSON.stringify(t):"");return n.createCheckout({...e,customerId:r,idempotencyKey:i,metadata:t})},w=(e,t,r)=>{const a=e-t;return{allowed:a>=r,balance:a,limit:e,unlimited:!1,used:t}},O=async(e,t,r,a,i)=>{const d=e.limit(a);if(d!==void 0){const c=await s.sumUsage(r,a,b(t));return w(d,c,i)}return{allowed:e.has(a),unlimited:e.has(a)}},p=async e=>{const t=()=>new f("NOT_FOUND",`payment session "${e}" not found`);let r=await s.getPaymentSession(n.identifier,e);if(!r)try{r=await n.getPaymentStatus(e)}catch{throw t()}if(!r.referenceId)throw t();try{await m(r.referenceId)}catch{throw t()}return r},g=async(e,t)=>{const r={...e,...t,updatedAt:Date.now()};return await s.upsertPaymentSession(r),r};return{adapter:n,attach:async e=>l({...e,mode:e.mode??"subscription"}),cancelPayment:async(e,t)=>{const r=await p(e),a=t?.idempotencyKey??k("cancel_payment",n.identifier,e),i=await n.cancelPayment(e,{...t,idempotencyKey:a});return g(r,{state:i.state})},cancelSubscription:async(e,t)=>{const r=await s.getSubscription(n.identifier,e);if(!r)throw new f("NOT_FOUND",`subscription "${e}" not found`);try{await m(r.referenceId)}catch{throw new f("NOT_FOUND",`subscription "${e}" not found`)}const a=t?.idempotencyKey??k("cancel_subscription",n.identifier,e),i=await n.cancelSubscription(e,{...t,idempotencyKey:a});return await s.upsertSubscription(i),i},capturePayment:async e=>{const t=await p(e.sessionId),r=e.idempotencyKey??await v("capture_payment",n.identifier,e.sessionId,S(e.amount)),a=await n.capturePayment({...e,idempotencyKey:r});return g(t,{capturedAmount:a.capturedAmount,state:a.state})},check:async e=>{if(await m(e.referenceId),e.featureId===void 0&&e.priceId===void 0)throw new f("VALIDATION_ERROR","check() requires a featureId or priceId");if(n.checkEntitlement)return n.checkEntitlement(e);const t=await s.listSubscriptionsByReference(e.referenceId);if(e.priceId!==void 0)return{allowed:U(t,e.priceId),unlimited:!1};if(e.featureId===void 0)throw new f("VALIDATION_ERROR","check() requires a featureId or priceId");if(!o.entitlements)throw new f("CONFIG_INVALID","check() requires `entitlements` to be configured");const r=A(o.entitlements,t);return O(r,t,e.referenceId,e.featureId,e.quantity??1)},createCheckout:async e=>l(e),createPortalSession:async(e,t)=>{await m(e);const r=await s.getCustomerByReference(n.identifier,e);if(!r)throw new f("NOT_FOUND",`no customer for reference "${e}"`);return n.createPortalSession({customerId:r.id,returnUrl:t})},handleWebhook:async e=>{let t;try{const a=await e.text();t=await n.parseWebhook({headers:e.headers,payload:a})}catch(a){if(a instanceof f){const{body:i,status:d}=P(a);return y({error:i.message},d)}return y({error:"webhook error"},400)}const r=await C(s,t,o.observability);return r.reason==="orphaned"?y({applied:r.applied,reason:r.reason},500):y({applied:r.applied,reason:r.reason},200)},listBalances:async e=>{if(await m(e),n.getBalances)return n.getBalances(e);if(!o.entitlements)throw new f("CONFIG_INVALID","listBalances() requires `entitlements` to be configured");const t=await s.listSubscriptionsByReference(e),r=A(o.entitlements,t),a=N(o.entitlements),i=a.filter(c=>r.limit(c)!==void 0),d=i.length===0?new Map:await s.sumUsageByFeature(e,i,b(t));return a.map(c=>{const u=r.limit(c);return u!==void 0?{featureId:c,...w(u,d.get(c)??0,1)}:{featureId:c,allowed:r.has(c),unlimited:r.has(c)}})},listSubscriptions:async e=>(await m(e),s.listSubscriptionsByReference(e)),refundPayment:async e=>{const t=await p(e.sessionId),r=e.amount??E(t.capturedAmount,t.refundedAmount),a=K(t.refundedAmount,r);if(R(a,t.capturedAmount)>0)throw new f("VALIDATION_ERROR",`refundPayment(): refunding ${String(e.amount?.minorUnits)} would exceed the captured amount on session "${e.sessionId}"`);if(B(r))return t;const i=e.amount??(R(r,t.capturedAmount)===0?void 0:r),d=e.idempotencyKey??await v("refund_payment",n.identifier,e.sessionId,S(i),e.reason??""),c=await n.refundPayment({...e,amount:i,idempotencyKey:d});if(c.pending)return t;const u=_(e.sessionId,c.refundId,r);await s.markEventProcessed(n.identifier,u,D);try{return await g(t,{refundedAmount:a,state:R(a,t.capturedAmount)<0?"partially_refunded":"refunded"})}catch(I){throw await s.releaseEvent(n.identifier,u),I}},store:s,track:async e=>{await m(e.referenceId);const t=e.quantity===void 0?1:e.quantity;if(!Number.isSafeInteger(t)||t<0)throw new f("VALIDATION_ERROR",`track(): \`quantity\` must be a non-negative safe integer (got ${String(e.quantity)})`);const r=e.idempotencyKey??crypto.randomUUID(),a=e.mode==="set",i=a?await s.listSubscriptionsByReference(e.referenceId):void 0,d=i===void 0?0:await s.sumUsage(e.referenceId,e.featureId,b(i));if(a?t===d:t===0)return{recorded:!1,reportedToProvider:!1};const c=a?t-d:t;if(!await s.recordUsage({createdAt:F(),featureId:e.featureId,idempotencyKey:r,...a?{mode:"set"}:{},provider:n.identifier,quantity:t,referenceId:e.referenceId,reportedToProvider:!1}))return{recorded:!1,reportedToProvider:!1};if(c<=0||!n.capabilities.usageMetering||!n.reportUsage)return{recorded:!0,reportedToProvider:!1};try{const I=await s.getCustomerByReference(n.identifier,e.referenceId);return await n.reportUsage({customerId:I?.id,featureId:e.featureId,idempotencyKey:r,quantity:c,referenceId:e.referenceId}),await s.markUsageReported(n.identifier,r),{recorded:!0,reportedToProvider:!0}}catch{return T(o.observability,{featureId:e.featureId,provider:n.identifier,referenceId:e.referenceId,type:"usage.report_failed"}),{recorded:!0,reportedToProvider:!1}}}}};export{G as createPayment,W as webhookResponse};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
const f=new Set(["active","trialing"]),m=s=>{let t=0;for(const e of s)f.has(e.state)&&e.currentPeriodStart!==void 0&&(t=Math.max(t,e.currentPeriodStart));return t},p=s=>{const t=new Set;for(const e of Object.values(s.plans)){for(const o of e.features??[])t.add(o);for(const o of Object.keys(e.limits??{}))t.add(o)}return[...t].toSorted((e,o)=>e.localeCompare(o))},S=(s,t)=>s.some(e=>e.priceId===t&&f.has(e.state)),d=(s,t)=>{const e=new Set(t.filter(n=>f.has(n.state)).map(n=>n.priceId)),o=[],a=new Set,c=new Map;for(const[n,i]of Object.entries(s.plans))if(i.priceIds.some(r=>e.has(r))){o.push(n);for(const r of i.features??[])a.add(r);for(const[r,l]of Object.entries(i.limits??{})){const u=c.get(r);c.set(r,u===void 0?l:Math.max(u,l))}}return{features:a,has:n=>a.has(n),limit:n=>c.get(n),plans:o}},h=async(s,t,e)=>d(t,await s.listSubscriptionsByReference(e));export{h as entitlementsForReference,p as featureNames,S as hasActivePrice,d as resolveEntitlements,m as usagePeriodStart};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
const o=new TextEncoder,r=async t=>[...new Uint8Array(await crypto.subtle.digest("SHA-256",o.encode(t)))].map(n=>n.toString(16).padStart(2,"0")).join(""),a=(t,...n)=>[t,...n.map(String)].join(":"),i=async(t,n,...e)=>{const c=await r(JSON.stringify([n,...e.map(String)]));return`${t}:${n}:${c}`},d=(t,n,e)=>n===void 0?`local-refund:${t}:${e.currency}:${String(e.minorUnits)}`:`local-refund:${t}:id:${n}`,s="marker.local_refund";export{s as LOCAL_REFUND_CLAIM_TYPE,i as derivedIdempotencyKey,a as idempotencyKey,d as localRefundKey};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{defineTable as r}from"@lunora/server";import{v as e}from"@lunora/values";const n=r({createdAt:e.number(),email:e.optional(e.string()),provider:e.string(),providerCustomerId:e.string(),referenceId:e.string()}).index("by_provider_customer",["provider","providerCustomerId"],{unique:!0}).index("by_reference",["referenceId"]),i=r({cancelAtPeriodEnd:e.boolean(),createdAt:e.number(),currentPeriodEnd:e.optional(e.number()),currentPeriodStart:e.optional(e.number()),priceId:e.string(),provider:e.string(),providerSubscriptionId:e.string(),quantity:e.number(),referenceId:e.string(),state:e.string(),updatedAt:e.number()}).index("by_provider_subscription",["provider","providerSubscriptionId"],{unique:!0}).index("by_reference",["referenceId"]),t=r({amountMinor:e.bigint(),capturedMinor:e.bigint(),createdAt:e.number(),currency:e.string(),provider:e.string(),providerSessionId:e.string(),referenceId:e.string(),refundedMinor:e.bigint(),state:e.string(),updatedAt:e.number()}).index("by_provider_session",["provider","providerSessionId"],{unique:!0}).index("by_reference",["referenceId"]),d=r({processedAt:e.number(),provider:e.string(),providerEventId:e.string(),type:e.string()}).index("by_provider_event",["provider","providerEventId"],{unique:!0}),o=r({createdAt:e.number(),featureId:e.string(),idempotencyKey:e.string(),mode:e.optional(e.string()),provider:e.string(),quantity:e.number(),referenceId:e.string(),reportedToProvider:e.boolean()}).index("by_idempotency",["provider","idempotencyKey"],{unique:!0}).index("by_reference_feature",["referenceId","featureId"]),p={customers:n,events:d,paymentSessions:t,subscriptions:i,usageEvents:o};export{p as default};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{compareMoney as y}from"./addMoney-B4ufWAnD.mjs";import{n as u}from"./observability-BteZ2dJS.mjs";const l=100,f=(e,t)=>e.currency===t.currency&&y(e,t)===0,m=(e,t)=>e?.state!==t.state||e.cancelAtPeriodEnd!==t.cancelAtPeriodEnd||e.currentPeriodEnd!==t.currentPeriodEnd||e.priceId!==t.priceId||e.quantity!==t.quantity,A=(e,t)=>e?.state!==t.state||!f(e.capturedAmount,t.capturedAmount)||!f(e.refundedAmount,t.refundedAmount),I=new Set(["partially_refunded","refunded"]),S=(e,t)=>{if(!e)return t;const s=e.refundedAmount.currency===t.refundedAmount.currency&&y(e.refundedAmount,t.refundedAmount)>0?e.refundedAmount:t.refundedAmount,i=t.state==="captured"&&I.has(e.state)?e.state:t.state,r=t.referenceId===""?e.referenceId:t.referenceId;return{...t,referenceId:r,refundedAmount:s,state:i}},b=async(e,t,n,s)=>{const i=await e.getSubscriptionStatus(n),r=await t.getSubscription(e.identifier,n);return m(r,i)?(await t.upsertSubscription({...i,createdAt:r?.createdAt??i.createdAt}),u(s,{id:n,kind:"subscription",provider:e.identifier,type:"reconcile.drift"}),!0):!1},w=async(e,t,n,s)=>{const i=await e.getPaymentStatus(n),r=await t.getPaymentSession(e.identifier,n),a=S(r,i);return A(r,a)?(await t.upsertPaymentSession({...a,createdAt:r?.createdAt??a.createdAt}),u(s,{id:n,kind:"payment",provider:e.identifier,type:"reconcile.drift"}),!0):!1},P=async(e,t,n,s)=>{const{reportUsage:i}=e;if(n<=0||i===void 0||!e.capabilities.usageMetering)return{checked:0,failed:0,updated:0};const r=await t.listUnreportedUsage(e.identifier,n);let a=0,c=0;for(const d of r)try{const o=await t.getCustomerByReference(e.identifier,d.referenceId);await i({customerId:o?.id,featureId:d.featureId,idempotencyKey:d.idempotencyKey,quantity:d.quantity,referenceId:d.referenceId}),await t.markUsageReported(e.identifier,d.idempotencyKey),a+=1}catch{c+=1,u(s,{featureId:d.featureId,provider:e.identifier,referenceId:d.referenceId,type:"usage.report_failed"})}return{checked:r.length,failed:c,updated:a}},p=async(e,t,n,s,i)=>{const r=await Promise.allSettled(e.map(d=>n(d)));let a=0,c=0;for(const[d,o]of r.entries())o.status==="fulfilled"?o.value&&(a+=1):(c+=1,u(i,{error:o.reason,id:e[d]??"",kind:t,provider:s.identifier,type:"reconcile.error"}));return{failed:c,updated:a}},U=async e=>{const{adapter:t,observability:n,store:s}=e,i=e.subscriptionIds??[],r=e.paymentSessionIds??[],a=await p(i,"subscription",o=>b(t,s,o,n),t,n),c=await p(r,"payment",o=>w(t,s,o,n),t,n),d=await P(t,s,e.usageReportLimit??l,n);return u(n,{failedPayments:c.failed,failedSubscriptions:a.failed,provider:t.identifier,type:"reconcile.completed",updatedPayments:c.updated,updatedSubscriptions:a.updated}),{checkedPayments:r.length,checkedSubscriptions:i.length,checkedUsage:d.checked,failedPayments:c.failed,failedSubscriptions:a.failed,failedUsage:d.failed,updatedPayments:c.updated,updatedSubscriptions:a.updated,updatedUsage:d.updated}};export{U as reconcile};
|