@lunora/payment 1.0.0-alpha.96 → 1.0.0-alpha.98

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 CHANGED
@@ -11,6 +11,21 @@ interface PaymentStore {
11
11
  getPaymentSession: (provider: ProviderId, id: string) => Promise<PaymentSession | undefined>;
12
12
  getSubscription: (provider: ProviderId, id: string) => Promise<Subscription | undefined>;
13
13
  listSubscriptionsByReference: (referenceId: string) => Promise<Subscription[]>;
14
+ /**
15
+ * Usage events that still owe an upstream forward, oldest first, at most `limit`.
16
+ *
17
+ * "Owes a forward" is narrower than `reportedToProvider === false`: only an
18
+ * ADDITIVE event with a positive `quantity` qualifies. A `"set"` event's
19
+ * upstream delta was measured against the period total at the moment it was
20
+ * recorded and is not recoverable afterwards, and a non-positive quantity was
21
+ * never sent, so neither is a retry candidate — returning them would make the
22
+ * sweep re-send the same rows forever (or double-count on an additive meter).
23
+ *
24
+ * Read by `reconcile` to retry a forward the provider rejected transiently;
25
+ * without it a single 5xx loses that metered unit upstream for good, which for
26
+ * a provider that owns entitlements under-bills and over-entitles the customer.
27
+ */
28
+ listUnreportedUsage: (provider: ProviderId, limit: number) => Promise<UsageEvent[]>;
14
29
  /**
15
30
  * Claims a provider event id for processing. Resolves `true` the first time an event is seen
16
31
  * and `false` for a duplicate — the inbound-idempotency primitive.
@@ -69,6 +84,7 @@ declare class MemoryPaymentStore implements PaymentStore {
69
84
  getPaymentSession(provider: ProviderId, id: string): Promise<PaymentSession | undefined>;
70
85
  getSubscription(provider: ProviderId, id: string): Promise<Subscription | undefined>;
71
86
  listSubscriptionsByReference(referenceId: string): Promise<Subscription[]>;
87
+ listUnreportedUsage(provider: ProviderId, limit: number): Promise<UsageEvent[]>;
72
88
  markEventProcessed(provider: ProviderId, eventId: string): Promise<boolean>;
73
89
  releaseEvent(provider: ProviderId, eventId: string): Promise<void>;
74
90
  markUsageReported(provider: ProviderId, idempotencyKey: string): Promise<void>;
@@ -273,6 +289,30 @@ declare const createPayment: (options: CreatePaymentOptions) => LunoraPayment;
273
289
  interface PaymentRow extends Record<string, unknown> {
274
290
  readonly _id: string;
275
291
  }
292
+ /**
293
+ * Bounded-read arguments for {@link PaymentDatabase.findMany}, mirroring what
294
+ * Lunora's `ctx.db.findMany` already accepts. `where` stays equality-only — these
295
+ * are the knobs that let a caller bound the number of rows FETCHED rather than
296
+ * fetching everything and slicing afterwards.
297
+ * @experimental
298
+ */
299
+ interface PaymentPageArgs {
300
+ /** Keyset cursor from a previous page's {@link PaymentPage.cursor}. */
301
+ cursor?: string;
302
+ /** Maximum rows to FETCH. Omit to read every match. */
303
+ limit?: number;
304
+ /** Sort keys, pushed down to the store so the keyset cursor is well-defined. */
305
+ orderBy?: Record<string, "asc" | "desc">[];
306
+ }
307
+ /**
308
+ * One page of rows plus the cursor that continues it.
309
+ * @experimental
310
+ */
311
+ interface PaymentPage {
312
+ /** Cursor for the next page, or `undefined` when this was the last one. */
313
+ readonly cursor: string | undefined;
314
+ readonly rows: PaymentRow[];
315
+ }
276
316
  /**
277
317
  * Minimal write/read surface this store needs; `ctx.db` satisfies it structurally.
278
318
  * @experimental
@@ -280,7 +320,12 @@ interface PaymentRow extends Record<string, unknown> {
280
320
  interface PaymentDatabase {
281
321
  delete: (id: string) => Promise<void>;
282
322
  findFirst: (table: string, where: Record<string, unknown>) => Promise<PaymentRow | null>;
283
- findMany: (table: string, where: Record<string, unknown>) => Promise<PaymentRow[]>;
323
+ /**
324
+ * Equality-only `where`, with optional order/limit/cursor pushed DOWN to the
325
+ * store (see {@link PaymentPageArgs}). Omitting `page` reads every match — do
326
+ * that only where the match set is inherently small (one reference's rows).
327
+ */
328
+ findMany: (table: string, where: Record<string, unknown>, page?: PaymentPageArgs) => Promise<PaymentPage>;
284
329
  insert: (table: string, document: Record<string, unknown>) => Promise<string>;
285
330
  patch: (id: string, patch: Record<string, unknown>) => Promise<void>;
286
331
  }
@@ -291,6 +336,12 @@ interface PaymentDatabase {
291
336
  declare const createDatabasePaymentStore: (database: PaymentDatabase) => PaymentStore;
292
337
  /**
293
338
  * Structural subset of Lunora's `ctx.db` (the `findFirst`/`findMany(tableName, { where })` form).
339
+ *
340
+ * `findMany` models the order/limit/cursor knobs too — {@link PaymentDatabase}
341
+ * pushes them down so a sweep over a large match set reads bounded chunks
342
+ * instead of materialising the lot. `continueCursor` is REQUIRED here (`ctx.db`
343
+ * always returns it): a double that omitted it would page exactly once and then
344
+ * silently report the rest of the table as absent.
294
345
  * @experimental
295
346
  */
296
347
  interface LunoraDatabaseLike {
@@ -299,8 +350,12 @@ interface LunoraDatabaseLike {
299
350
  where?: Record<string, unknown>;
300
351
  }) => Promise<Record<string, unknown> | null>;
301
352
  findMany: (table: string, args?: {
353
+ cursor?: string;
354
+ limit?: number;
355
+ orderBy?: Record<string, "asc" | "desc">[];
302
356
  where?: Record<string, unknown>;
303
357
  }) => Promise<{
358
+ continueCursor: null | string;
304
359
  page: Record<string, unknown>[];
305
360
  }>;
306
361
  insert: (table: string, document: Record<string, unknown>) => Promise<string>;
@@ -420,6 +475,12 @@ interface ReconcileInput {
420
475
  readonly paymentSessionIds?: ReadonlyArray<string>;
421
476
  readonly store: PaymentStore;
422
477
  readonly subscriptionIds?: ReadonlyArray<string>;
478
+ /**
479
+ * How many unreported usage events to retry forwarding upstream this sweep
480
+ * (oldest first). Default {@link DEFAULT_USAGE_REPORT_LIMIT}; `0` skips the
481
+ * usage sweep entirely. Ignored by an adapter that does not meter usage.
482
+ */
483
+ readonly usageReportLimit?: number;
423
484
  }
424
485
  /**
425
486
  * `ReconcileResult` is part of the experimental `@lunora/payment` API and may change without a major version bump.
@@ -428,10 +489,15 @@ interface ReconcileInput {
428
489
  interface ReconcileResult {
429
490
  readonly checkedPayments: number;
430
491
  readonly checkedSubscriptions: number;
492
+ readonly checkedUsage: number;
431
493
  readonly failedPayments: number;
432
494
  readonly failedSubscriptions: number;
495
+ /** Usage events whose retried forward failed again — still pending for the next sweep. */
496
+ readonly failedUsage: number;
433
497
  readonly updatedPayments: number;
434
498
  readonly updatedSubscriptions: number;
499
+ /** Usage events successfully forwarded upstream on this sweep. */
500
+ readonly updatedUsage: number;
435
501
  }
436
502
  /**
437
503
  * `reconcile` is part of the experimental `@lunora/payment` API and may change without a major version bump.
@@ -439,6 +505,11 @@ interface ReconcileResult {
439
505
  */
440
506
  declare const reconcile: (input: ReconcileInput) => Promise<ReconcileResult>;
441
507
  /**
508
+ * The canonical column reference for the payment tables — a value to READ (in a test, a migration
509
+ * check, or your editor), not one to spread. `defineSchema({ ...paymentTables })` does NOT work:
510
+ * codegen discovers tables by parsing your `lunora/schema.ts` AST and cannot resolve a
511
+ * cross-package spread, so declare the same columns inline there (see the module docstring).
512
+ *
442
513
  * `paymentTables` is part of the experimental `@lunora/payment` API and may change without a major version bump.
443
514
  * @experimental
444
515
  */
@@ -541,4 +612,4 @@ interface VerifyCreemSignatureInput {
541
612
  * replay-window check. Throws a {@link LunoraPaymentError} on any failure.
542
613
  */
543
614
  declare const verifyCreemSignature: (input: VerifyCreemSignatureInput) => Promise<void>;
544
- export { type ApplyResult, type AttachInput, type AuthorizeReference, type CancelSubscriptionOptions, type CaptureInput, type CheckInput, type CheckResult, type CheckoutInput, type CheckoutResult, type CreatePaymentOptions, type CurrencyCode, type Customer, type Entitlements, type EntitlementsConfig, type FeatureBalance, type LunoraDatabaseLike, type LunoraPayment, LunoraPaymentError, MemoryPaymentStore, type Money, type MoneyJSON, PAYMENT_TERMINAL_STATES, type PaymentAction, type PaymentAdapter, type PaymentContextLike, type PaymentDatabase, type PaymentErrorCode, type PaymentEvent, type PaymentObserver, type PaymentRow, type PaymentSession, type PaymentState, type PaymentStore, type PaymentsFromContextOptions, type PlanDefinition, type ProviderId, type ReconcileInput, type ReconcileResult, type RefundInput, SUBSCRIPTION_TERMINAL_STATES, type Subscription, type SubscriptionAction, type SubscriptionState, type TrackInput, type TrackResult, type UsageEvent, type VerifyCreemSignatureInput, type VerifyStandardWebhookInput, type WebhookAction, type WebhookActionType, addMoney, allocateMoney, applyWebhookAction, canTransitionPayment, canTransitionSubscription, compareMoney, constantTimeEqual, createDatabasePaymentStore, createPayment, entitlementsForReference, featureNames, formatMoney, fromMoneyJSON, hasActivePrice, hmacSha256Hex, idempotencyKey, isZeroDecimalCurrency, isZeroMoney, lunoraDatabaseToPaymentDatabase, money, nextPaymentState, nextSubscriptionState, paymentTables, paymentsFromContext, reconcile, resolveEntitlements, subtractMoney, toMoneyJSON, usagePeriodStart, verifyCreemSignature, verifyStandardWebhook, zeroMoney };
615
+ export { type ApplyResult, type AttachInput, type AuthorizeReference, type CancelSubscriptionOptions, type CaptureInput, type CheckInput, type CheckResult, type CheckoutInput, type CheckoutResult, type CreatePaymentOptions, type CurrencyCode, type Customer, type Entitlements, type EntitlementsConfig, type FeatureBalance, type LunoraDatabaseLike, type LunoraPayment, LunoraPaymentError, MemoryPaymentStore, type Money, type MoneyJSON, PAYMENT_TERMINAL_STATES, type PaymentAction, type PaymentAdapter, type PaymentContextLike, type PaymentDatabase, type PaymentErrorCode, type PaymentEvent, type PaymentObserver, type PaymentPage, type PaymentPageArgs, type PaymentRow, type PaymentSession, type PaymentState, type PaymentStore, type PaymentsFromContextOptions, type PlanDefinition, type ProviderId, type ReconcileInput, type ReconcileResult, type RefundInput, SUBSCRIPTION_TERMINAL_STATES, type Subscription, type SubscriptionAction, type SubscriptionState, type TrackInput, type TrackResult, type UsageEvent, type VerifyCreemSignatureInput, type VerifyStandardWebhookInput, type WebhookAction, type WebhookActionType, addMoney, allocateMoney, applyWebhookAction, canTransitionPayment, canTransitionSubscription, compareMoney, constantTimeEqual, createDatabasePaymentStore, createPayment, entitlementsForReference, featureNames, formatMoney, fromMoneyJSON, hasActivePrice, hmacSha256Hex, idempotencyKey, isZeroDecimalCurrency, isZeroMoney, lunoraDatabaseToPaymentDatabase, money, nextPaymentState, nextSubscriptionState, paymentTables, paymentsFromContext, reconcile, resolveEntitlements, subtractMoney, toMoneyJSON, usagePeriodStart, verifyCreemSignature, verifyStandardWebhook, zeroMoney };
package/dist/index.d.ts CHANGED
@@ -11,6 +11,21 @@ interface PaymentStore {
11
11
  getPaymentSession: (provider: ProviderId, id: string) => Promise<PaymentSession | undefined>;
12
12
  getSubscription: (provider: ProviderId, id: string) => Promise<Subscription | undefined>;
13
13
  listSubscriptionsByReference: (referenceId: string) => Promise<Subscription[]>;
14
+ /**
15
+ * Usage events that still owe an upstream forward, oldest first, at most `limit`.
16
+ *
17
+ * "Owes a forward" is narrower than `reportedToProvider === false`: only an
18
+ * ADDITIVE event with a positive `quantity` qualifies. A `"set"` event's
19
+ * upstream delta was measured against the period total at the moment it was
20
+ * recorded and is not recoverable afterwards, and a non-positive quantity was
21
+ * never sent, so neither is a retry candidate — returning them would make the
22
+ * sweep re-send the same rows forever (or double-count on an additive meter).
23
+ *
24
+ * Read by `reconcile` to retry a forward the provider rejected transiently;
25
+ * without it a single 5xx loses that metered unit upstream for good, which for
26
+ * a provider that owns entitlements under-bills and over-entitles the customer.
27
+ */
28
+ listUnreportedUsage: (provider: ProviderId, limit: number) => Promise<UsageEvent[]>;
14
29
  /**
15
30
  * Claims a provider event id for processing. Resolves `true` the first time an event is seen
16
31
  * and `false` for a duplicate — the inbound-idempotency primitive.
@@ -69,6 +84,7 @@ declare class MemoryPaymentStore implements PaymentStore {
69
84
  getPaymentSession(provider: ProviderId, id: string): Promise<PaymentSession | undefined>;
70
85
  getSubscription(provider: ProviderId, id: string): Promise<Subscription | undefined>;
71
86
  listSubscriptionsByReference(referenceId: string): Promise<Subscription[]>;
87
+ listUnreportedUsage(provider: ProviderId, limit: number): Promise<UsageEvent[]>;
72
88
  markEventProcessed(provider: ProviderId, eventId: string): Promise<boolean>;
73
89
  releaseEvent(provider: ProviderId, eventId: string): Promise<void>;
74
90
  markUsageReported(provider: ProviderId, idempotencyKey: string): Promise<void>;
@@ -273,6 +289,30 @@ declare const createPayment: (options: CreatePaymentOptions) => LunoraPayment;
273
289
  interface PaymentRow extends Record<string, unknown> {
274
290
  readonly _id: string;
275
291
  }
292
+ /**
293
+ * Bounded-read arguments for {@link PaymentDatabase.findMany}, mirroring what
294
+ * Lunora's `ctx.db.findMany` already accepts. `where` stays equality-only — these
295
+ * are the knobs that let a caller bound the number of rows FETCHED rather than
296
+ * fetching everything and slicing afterwards.
297
+ * @experimental
298
+ */
299
+ interface PaymentPageArgs {
300
+ /** Keyset cursor from a previous page's {@link PaymentPage.cursor}. */
301
+ cursor?: string;
302
+ /** Maximum rows to FETCH. Omit to read every match. */
303
+ limit?: number;
304
+ /** Sort keys, pushed down to the store so the keyset cursor is well-defined. */
305
+ orderBy?: Record<string, "asc" | "desc">[];
306
+ }
307
+ /**
308
+ * One page of rows plus the cursor that continues it.
309
+ * @experimental
310
+ */
311
+ interface PaymentPage {
312
+ /** Cursor for the next page, or `undefined` when this was the last one. */
313
+ readonly cursor: string | undefined;
314
+ readonly rows: PaymentRow[];
315
+ }
276
316
  /**
277
317
  * Minimal write/read surface this store needs; `ctx.db` satisfies it structurally.
278
318
  * @experimental
@@ -280,7 +320,12 @@ interface PaymentRow extends Record<string, unknown> {
280
320
  interface PaymentDatabase {
281
321
  delete: (id: string) => Promise<void>;
282
322
  findFirst: (table: string, where: Record<string, unknown>) => Promise<PaymentRow | null>;
283
- findMany: (table: string, where: Record<string, unknown>) => Promise<PaymentRow[]>;
323
+ /**
324
+ * Equality-only `where`, with optional order/limit/cursor pushed DOWN to the
325
+ * store (see {@link PaymentPageArgs}). Omitting `page` reads every match — do
326
+ * that only where the match set is inherently small (one reference's rows).
327
+ */
328
+ findMany: (table: string, where: Record<string, unknown>, page?: PaymentPageArgs) => Promise<PaymentPage>;
284
329
  insert: (table: string, document: Record<string, unknown>) => Promise<string>;
285
330
  patch: (id: string, patch: Record<string, unknown>) => Promise<void>;
286
331
  }
@@ -291,6 +336,12 @@ interface PaymentDatabase {
291
336
  declare const createDatabasePaymentStore: (database: PaymentDatabase) => PaymentStore;
292
337
  /**
293
338
  * Structural subset of Lunora's `ctx.db` (the `findFirst`/`findMany(tableName, { where })` form).
339
+ *
340
+ * `findMany` models the order/limit/cursor knobs too — {@link PaymentDatabase}
341
+ * pushes them down so a sweep over a large match set reads bounded chunks
342
+ * instead of materialising the lot. `continueCursor` is REQUIRED here (`ctx.db`
343
+ * always returns it): a double that omitted it would page exactly once and then
344
+ * silently report the rest of the table as absent.
294
345
  * @experimental
295
346
  */
296
347
  interface LunoraDatabaseLike {
@@ -299,8 +350,12 @@ interface LunoraDatabaseLike {
299
350
  where?: Record<string, unknown>;
300
351
  }) => Promise<Record<string, unknown> | null>;
301
352
  findMany: (table: string, args?: {
353
+ cursor?: string;
354
+ limit?: number;
355
+ orderBy?: Record<string, "asc" | "desc">[];
302
356
  where?: Record<string, unknown>;
303
357
  }) => Promise<{
358
+ continueCursor: null | string;
304
359
  page: Record<string, unknown>[];
305
360
  }>;
306
361
  insert: (table: string, document: Record<string, unknown>) => Promise<string>;
@@ -420,6 +475,12 @@ interface ReconcileInput {
420
475
  readonly paymentSessionIds?: ReadonlyArray<string>;
421
476
  readonly store: PaymentStore;
422
477
  readonly subscriptionIds?: ReadonlyArray<string>;
478
+ /**
479
+ * How many unreported usage events to retry forwarding upstream this sweep
480
+ * (oldest first). Default {@link DEFAULT_USAGE_REPORT_LIMIT}; `0` skips the
481
+ * usage sweep entirely. Ignored by an adapter that does not meter usage.
482
+ */
483
+ readonly usageReportLimit?: number;
423
484
  }
424
485
  /**
425
486
  * `ReconcileResult` is part of the experimental `@lunora/payment` API and may change without a major version bump.
@@ -428,10 +489,15 @@ interface ReconcileInput {
428
489
  interface ReconcileResult {
429
490
  readonly checkedPayments: number;
430
491
  readonly checkedSubscriptions: number;
492
+ readonly checkedUsage: number;
431
493
  readonly failedPayments: number;
432
494
  readonly failedSubscriptions: number;
495
+ /** Usage events whose retried forward failed again — still pending for the next sweep. */
496
+ readonly failedUsage: number;
433
497
  readonly updatedPayments: number;
434
498
  readonly updatedSubscriptions: number;
499
+ /** Usage events successfully forwarded upstream on this sweep. */
500
+ readonly updatedUsage: number;
435
501
  }
436
502
  /**
437
503
  * `reconcile` is part of the experimental `@lunora/payment` API and may change without a major version bump.
@@ -439,6 +505,11 @@ interface ReconcileResult {
439
505
  */
440
506
  declare const reconcile: (input: ReconcileInput) => Promise<ReconcileResult>;
441
507
  /**
508
+ * The canonical column reference for the payment tables — a value to READ (in a test, a migration
509
+ * check, or your editor), not one to spread. `defineSchema({ ...paymentTables })` does NOT work:
510
+ * codegen discovers tables by parsing your `lunora/schema.ts` AST and cannot resolve a
511
+ * cross-package spread, so declare the same columns inline there (see the module docstring).
512
+ *
442
513
  * `paymentTables` is part of the experimental `@lunora/payment` API and may change without a major version bump.
443
514
  * @experimental
444
515
  */
@@ -541,4 +612,4 @@ interface VerifyCreemSignatureInput {
541
612
  * replay-window check. Throws a {@link LunoraPaymentError} on any failure.
542
613
  */
543
614
  declare const verifyCreemSignature: (input: VerifyCreemSignatureInput) => Promise<void>;
544
- export { type ApplyResult, type AttachInput, type AuthorizeReference, type CancelSubscriptionOptions, type CaptureInput, type CheckInput, type CheckResult, type CheckoutInput, type CheckoutResult, type CreatePaymentOptions, type CurrencyCode, type Customer, type Entitlements, type EntitlementsConfig, type FeatureBalance, type LunoraDatabaseLike, type LunoraPayment, LunoraPaymentError, MemoryPaymentStore, type Money, type MoneyJSON, PAYMENT_TERMINAL_STATES, type PaymentAction, type PaymentAdapter, type PaymentContextLike, type PaymentDatabase, type PaymentErrorCode, type PaymentEvent, type PaymentObserver, type PaymentRow, type PaymentSession, type PaymentState, type PaymentStore, type PaymentsFromContextOptions, type PlanDefinition, type ProviderId, type ReconcileInput, type ReconcileResult, type RefundInput, SUBSCRIPTION_TERMINAL_STATES, type Subscription, type SubscriptionAction, type SubscriptionState, type TrackInput, type TrackResult, type UsageEvent, type VerifyCreemSignatureInput, type VerifyStandardWebhookInput, type WebhookAction, type WebhookActionType, addMoney, allocateMoney, applyWebhookAction, canTransitionPayment, canTransitionSubscription, compareMoney, constantTimeEqual, createDatabasePaymentStore, createPayment, entitlementsForReference, featureNames, formatMoney, fromMoneyJSON, hasActivePrice, hmacSha256Hex, idempotencyKey, isZeroDecimalCurrency, isZeroMoney, lunoraDatabaseToPaymentDatabase, money, nextPaymentState, nextSubscriptionState, paymentTables, paymentsFromContext, reconcile, resolveEntitlements, subtractMoney, toMoneyJSON, usagePeriodStart, verifyCreemSignature, verifyStandardWebhook, zeroMoney };
615
+ export { type ApplyResult, type AttachInput, type AuthorizeReference, type CancelSubscriptionOptions, type CaptureInput, type CheckInput, type CheckResult, type CheckoutInput, type CheckoutResult, type CreatePaymentOptions, type CurrencyCode, type Customer, type Entitlements, type EntitlementsConfig, type FeatureBalance, type LunoraDatabaseLike, type LunoraPayment, LunoraPaymentError, MemoryPaymentStore, type Money, type MoneyJSON, PAYMENT_TERMINAL_STATES, type PaymentAction, type PaymentAdapter, type PaymentContextLike, type PaymentDatabase, type PaymentErrorCode, type PaymentEvent, type PaymentObserver, type PaymentPage, type PaymentPageArgs, type PaymentRow, type PaymentSession, type PaymentState, type PaymentStore, type PaymentsFromContextOptions, type PlanDefinition, type ProviderId, type ReconcileInput, type ReconcileResult, type RefundInput, SUBSCRIPTION_TERMINAL_STATES, type Subscription, type SubscriptionAction, type SubscriptionState, type TrackInput, type TrackResult, type UsageEvent, type VerifyCreemSignatureInput, type VerifyStandardWebhookInput, type WebhookAction, type WebhookActionType, addMoney, allocateMoney, applyWebhookAction, canTransitionPayment, canTransitionSubscription, compareMoney, constantTimeEqual, createDatabasePaymentStore, createPayment, entitlementsForReference, featureNames, formatMoney, fromMoneyJSON, hasActivePrice, hmacSha256Hex, idempotencyKey, isZeroDecimalCurrency, isZeroMoney, lunoraDatabaseToPaymentDatabase, money, nextPaymentState, nextSubscriptionState, paymentTables, paymentsFromContext, reconcile, resolveEntitlements, subtractMoney, toMoneyJSON, usagePeriodStart, verifyCreemSignature, verifyStandardWebhook, zeroMoney };
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-DBveGQxx.mjs";import{createPayment as y}from"./packem_shared/createPayment-Dmh6IWLZ.mjs";import{createDatabasePaymentStore as p}from"./packem_shared/createDatabasePaymentStore-BlMXuCW_.mjs";import{entitlementsForReference as s,featureNames as c,hasActivePrice as x,resolveEntitlements as S,usagePeriodStart as l}from"./packem_shared/entitlementsForReference-Bq-9UUL8.mjs";import{LunoraPaymentError as T}from"./packem_shared/LunoraPaymentError-BSxyhWgu.mjs";import{idempotencyKey as P}from"./packem_shared/idempotencyKey-BjxjMMna.mjs";import{addMoney as d,allocateMoney as A,compareMoney as E,formatMoney as N,fromMoneyJSON as h,isZeroDecimalCurrency as R,isZeroMoney as v,money as C,subtractMoney as D,toMoneyJSON as I,zeroMoney as _}from"./packem_shared/addMoney-B4ufWAnD.mjs";import{reconcile as L}from"./packem_shared/reconcile-Dq48_gHU.mjs";import{default as k}from"./packem_shared/paymentTables-Be-_11ux.mjs";import{PAYMENT_TERMINAL_STATES as J,SUBSCRIPTION_TERMINAL_STATES as W,canTransitionPayment as Z,canTransitionSubscription as q,nextPaymentState as z,nextSubscriptionState as B}from"./packem_shared/PAYMENT_TERMINAL_STATES-DVerjPR6.mjs";import{MemoryPaymentStore as K}from"./packem_shared/MemoryPaymentStore-C2iTSo5g.mjs";import{default as Y}from"./packem_shared/applyWebhookAction-daHKTG_Q.mjs";import{constantTimeEqual as w,hmacSha256Hex as G,verifyCreemSignature as Q,verifyStandardWebhook as V}from"./packem_shared/constantTimeEqual-Bj5tU-zT.mjs";export{T as LunoraPaymentError,K as MemoryPaymentStore,J as PAYMENT_TERMINAL_STATES,W as SUBSCRIPTION_TERMINAL_STATES,d as addMoney,A as allocateMoney,Y as applyWebhookAction,Z as canTransitionPayment,q as canTransitionSubscription,E as compareMoney,w as constantTimeEqual,r as createAdapterRegistry,p as createDatabasePaymentStore,y as createPayment,s as entitlementsForReference,c as featureNames,N as formatMoney,h as fromMoneyJSON,x as hasActivePrice,G as hmacSha256Hex,P as idempotencyKey,R as isZeroDecimalCurrency,v as isZeroMoney,a as lunoraDatabaseToPaymentDatabase,C as money,z as nextPaymentState,B as nextSubscriptionState,k as paymentTables,n as paymentsFromContext,L as reconcile,S as resolveEntitlements,D as subtractMoney,I as toMoneyJSON,l as usagePeriodStart,Q as verifyCreemSignature,V as verifyStandardWebhook,_ as zeroMoney};
1
+ import{createAdapterRegistry as r}from"./packem_shared/createAdapterRegistry-DyCsry1Q.mjs";import{lunoraDatabaseToPaymentDatabase as a,paymentsFromContext as n}from"./packem_shared/lunoraDatabaseToPaymentDatabase-5WkBd3aZ.mjs";import{createPayment as y}from"./packem_shared/createPayment-Dmh6IWLZ.mjs";import{createDatabasePaymentStore as p}from"./packem_shared/createDatabasePaymentStore-CVrAhWjP.mjs";import{entitlementsForReference as s,featureNames as c,hasActivePrice as x,resolveEntitlements as S,usagePeriodStart as l}from"./packem_shared/entitlementsForReference-Bq-9UUL8.mjs";import{LunoraPaymentError as T}from"./packem_shared/LunoraPaymentError-BSxyhWgu.mjs";import{idempotencyKey as P}from"./packem_shared/idempotencyKey-BjxjMMna.mjs";import{addMoney as d,allocateMoney as A,compareMoney as E,formatMoney as N,fromMoneyJSON as h,isZeroDecimalCurrency as R,isZeroMoney as v,money as C,subtractMoney as D,toMoneyJSON as I,zeroMoney as _}from"./packem_shared/addMoney-B4ufWAnD.mjs";import{reconcile as L}from"./packem_shared/reconcile-Cm45pURT.mjs";import{default as k}from"./packem_shared/paymentTables-Be-_11ux.mjs";import{PAYMENT_TERMINAL_STATES as J,SUBSCRIPTION_TERMINAL_STATES as W,canTransitionPayment as Z,canTransitionSubscription as q,nextPaymentState as z,nextSubscriptionState as B}from"./packem_shared/PAYMENT_TERMINAL_STATES-DVerjPR6.mjs";import{MemoryPaymentStore as K}from"./packem_shared/MemoryPaymentStore-Cu9J-zf9.mjs";import{default as Y}from"./packem_shared/applyWebhookAction-daHKTG_Q.mjs";import{constantTimeEqual as w,hmacSha256Hex as G,verifyCreemSignature as Q,verifyStandardWebhook as V}from"./packem_shared/constantTimeEqual-D_ynru-O.mjs";export{T as LunoraPaymentError,K as MemoryPaymentStore,J as PAYMENT_TERMINAL_STATES,W as SUBSCRIPTION_TERMINAL_STATES,d as addMoney,A as allocateMoney,Y as applyWebhookAction,Z as canTransitionPayment,q as canTransitionSubscription,E as compareMoney,w as constantTimeEqual,r as createAdapterRegistry,p as createDatabasePaymentStore,y as createPayment,s as entitlementsForReference,c as featureNames,N as formatMoney,h as fromMoneyJSON,x as hasActivePrice,G as hmacSha256Hex,P as idempotencyKey,R as isZeroDecimalCurrency,v as isZeroMoney,a as lunoraDatabaseToPaymentDatabase,C as money,z as nextPaymentState,B as nextSubscriptionState,k as paymentTables,n as paymentsFromContext,L as reconcile,S as resolveEntitlements,D as subtractMoney,I as toMoneyJSON,l as usagePeriodStart,Q as verifyCreemSignature,V as verifyStandardWebhook,_ as zeroMoney};
@@ -0,0 +1 @@
1
+ const a=(i,e)=>`${i}:${e}`,n=(i,e)=>`${i}:${e}`,u=i=>{const e=i.toSorted((t,r)=>t.createdAt-r.createdAt||t.idempotencyKey.localeCompare(r.idempotencyKey));let s=0;for(const t of e)s=t.mode==="set"?t.quantity:s+t.quantity;return s};class d{customers=new Map;processedEvents=new Set;sessions=new Map;subscriptions=new Map;usageEvents=new Map;getCustomerByReference(e,s){return Promise.resolve(this.customers.get(a(e,s)))}getPaymentSession(e,s){return Promise.resolve(this.sessions.get(n(e,s)))}getSubscription(e,s){return Promise.resolve(this.subscriptions.get(n(e,s)))}listSubscriptionsByReference(e){return Promise.resolve([...this.subscriptions.values()].filter(s=>s.referenceId===e))}listUnreportedUsage(e,s){const t=[...this.usageEvents.values()].filter(r=>r.provider===e&&!r.reportedToProvider&&r.mode!=="set"&&r.quantity>0).toSorted((r,o)=>r.createdAt-o.createdAt||r.idempotencyKey.localeCompare(o.idempotencyKey));return Promise.resolve(t.slice(0,Math.max(0,s)))}markEventProcessed(e,s){const t=n(e,s);return this.processedEvents.has(t)?Promise.resolve(!1):(this.processedEvents.add(t),Promise.resolve(!0))}releaseEvent(e,s){return this.processedEvents.delete(n(e,s)),Promise.resolve()}markUsageReported(e,s){const t=n(e,s),r=this.usageEvents.get(t);return r&&this.usageEvents.set(t,{...r,reportedToProvider:!0}),Promise.resolve()}recordUsage(e){const s=n(e.provider,e.idempotencyKey);return this.usageEvents.has(s)?Promise.resolve(!1):(this.usageEvents.set(s,e),Promise.resolve(!0))}sumUsage(e,s,t){const r=[];for(const o of this.usageEvents.values())o.referenceId===e&&o.featureId===s&&o.createdAt>=t&&r.push(o);return Promise.resolve(u(r))}sumUsageByFeature(e,s,t){const r=new Map(s.map(o=>[o,[]]));for(const o of this.usageEvents.values())o.referenceId===e&&o.createdAt>=t&&r.get(o.featureId)?.push(o);return Promise.resolve(new Map([...r].map(([o,c])=>[o,u(c)])))}upsertCustomer(e){return this.customers.set(a(e.provider,e.referenceId),e),Promise.resolve()}upsertPaymentSession(e){return this.sessions.set(n(e.provider,e.id),e),Promise.resolve()}upsertSubscription(e){return this.subscriptions.set(n(e.provider,e.id),e),Promise.resolve()}}export{d as MemoryPaymentStore,u as foldUsage};
@@ -0,0 +1 @@
1
+ import{LunoraPaymentError as s}from"./LunoraPaymentError-BSxyhWgu.mjs";const m=e=>{let t="";for(let o=0;o<e.length;o+=32768)t+=String.fromCharCode(...e.subarray(o,o+32768));return btoa(t)},l=e=>{const t=atob(e),n=new Uint8Array(t.length);for(let o=0;o<t.length;o+=1)n[o]=t.codePointAt(o)??0;return n},I=(e,t)=>{const n=Math.max(e.length,t.length);let o=e.length^t.length;for(let r=0;r<n;r+=1){const a=r<e.length?e.charCodeAt(r):0,i=r<t.length?t.charCodeAt(r):0;o|=a^i}return o===0},h=new TextEncoder,f=e=>[...new Uint8Array(e)].map(t=>t.toString(16).padStart(2,"0")).join(""),d="whsec_",A=async(e,t)=>{const n=await crypto.subtle.importKey("raw",e,{hash:"SHA-256",name:"HMAC"},!1,["sign"]),o=await crypto.subtle.sign("HMAC",n,h.encode(t));return m(new Uint8Array(o))},g=I,y=async(e,t)=>{const n=await crypto.subtle.importKey("raw",h.encode(e),{hash:"SHA-256",name:"HMAC"},!1,["sign"]),o=await crypto.subtle.sign("HMAC",n,h.encode(t));return f(o)},u=async e=>{if(!e.secret)throw new s("CONFIG_INVALID","webhook secret not configured");const t=e.toleranceSeconds??300,n=e.now??Date.now(),o=Number(e.webhookTimestamp);if(!e.webhookId||!e.webhookSignature||!Number.isFinite(o))throw new s("WEBHOOK_SIGNATURE_INVALID","missing standard-webhooks headers");if(Math.abs(Math.floor(n/1e3)-o)>t)throw new s("WEBHOOK_TIMESTAMP_INVALID","signature timestamp outside tolerance");const r=e.secret.startsWith(d)?e.secret.slice(d.length):e.secret;if(!r)throw new s("CONFIG_INVALID","webhook secret not configured");const a=l(r);if(a.length===0)throw new s("CONFIG_INVALID","webhook secret not configured");const i=await A(a,`${e.webhookId}.${e.webhookTimestamp}.${e.payload}`);if(!e.webhookSignature.split(" ").map(c=>{const w=c.indexOf(",");return w===-1?"":c.slice(w+1)}).filter(Boolean).some(c=>g(c,i)))throw new s("WEBHOOK_SIGNATURE_INVALID","no matching signature")},N=async e=>{if(!e.secret)throw new s("CONFIG_INVALID","webhook secret not configured");if(!e.signature)throw new s("WEBHOOK_SIGNATURE_INVALID","missing creem-signature header");const t=await y(e.secret,e.payload);if(!g(e.signature,t))throw new s("WEBHOOK_SIGNATURE_INVALID","no matching signature")};export{g as constantTimeEqual,y as hmacSha256Hex,N as verifyCreemSignature,u as verifyStandardWebhook};
@@ -0,0 +1 @@
1
+ import{money as y}from"./addMoney-B4ufWAnD.mjs";import{foldUsage as m}from"./MemoryPaymentStore-Cu9J-zf9.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 s=await e.findFirst(t,i);if(s){await e.patch(s._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 s=[{createdAt:"asc"},{idempotencyKey:"asc"}],a=[];let n;do{const u=await e.findMany("usageEvents",{provider:t,reportedToProvider:!1},{cursor:n,limit:r,orderBy:s});for(const g of u.rows){const p=q(g);if(p.mode!=="set"&&p.quantity>0&&(a.push(p),a.length===r))return a}n=u.cursor}while(n!==void 0);return a},markEventProcessed:async(t,i)=>await e.findFirst("events",{provider:t,providerEventId:i})?!1:(await e.insert("events",{processedAt:Date.now(),provider:t,providerEventId:i,type:""}),!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:s}=await e.findMany("usageEvents",{featureId:i,referenceId:t}),a=s.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(a)},sumUsageByFeature:async(t,i,r)=>{const{rows:s}=await e.findMany("usageEvents",{referenceId:t}),a=new Map(i.map(n=>[n,[]]));for(const n of s)c(n,"createdAt")<r||a.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([...a].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};
@@ -0,0 +1 @@
1
+ import{createPayment as i}from"./createPayment-Dmh6IWLZ.mjs";import{createDatabasePaymentStore as s}from"./createDatabasePaymentStore-CVrAhWjP.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{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};
@@ -1 +1 @@
1
- import{LunoraPaymentError as O}from"../packem_shared/LunoraPaymentError-BSxyhWgu.mjs";import{a as i,r as x,c as o,d as p,e as u}from"../packem_shared/json-BJJPJVYj.mjs";import{money as h}from"../packem_shared/addMoney-B4ufWAnD.mjs";import{verifyStandardWebhook as C}from"../packem_shared/constantTimeEqual-Bj5tU-zT.mjs";import{m as D}from"../packem_shared/not-supported-Cl0brzhn.mjs";import{s as E}from"../packem_shared/subscription-event-C8GiQSFM.mjs";const P={active:"active",canceled:"canceled",expired:"canceled",past_due:"past_due",scheduled:"paused",trialing:"trialing"},N={activated:"active",canceled:"canceled",cancelled:"canceled",expired:"canceled",scheduled:"paused"},w="::",y=D("autumn"),f=(a,c)=>`${a}${w}${c}`,g=a=>{const c=a.lastIndexOf(w);if(c===-1)throw new O("PROVIDER_ERROR",`malformed autumn subscription id "${a}" (expected "<customerId>::<productId>")`);return{customerId:a.slice(0,c),productId:a.slice(c+w.length)}},A=a=>u(a,"canceled_at","canceledAt")!==void 0||o(a,"status")==="scheduled",k=(a,c)=>{const r=Date.now(),e=o(c,"id","product_id","productId","plan_id","planId")??"",n=o(c,"status")??"active",t=p(c,"past_due")??p(c,"pastDue")??!1;return{cancelAtPeriodEnd:A(c),createdAt:r,currentPeriodEnd:u(c,"current_period_end","currentPeriodEnd")??void 0,currentPeriodStart:u(c,"current_period_start","currentPeriodStart")??void 0,id:f(a,e),priceId:e,provider:"autumn",quantity:u(c,"quantity")??1,referenceId:a,state:t?"past_due":P[n]??"past_due",updatedAt:r}},S=a=>Array.isArray(a)?a.map(c=>i(c)):[],T=(a,c)=>[...S(a.products),...S(a.subscriptions)].find(e=>(o(e,"id","product_id","productId","plan_id","planId")??"")===c),b=a=>({balance:u(a,"remaining","balance"),limit:u(a,"granted","included_usage","limit"),unlimited:p(a,"unlimited")??!1,used:u(a,"usage","used")}),R=(a,c,r,e)=>{const n=Date.now();return{cancelAtPeriodEnd:e,createdAt:n,id:f(a,c),priceId:c,provider:"autumn",quantity:1,referenceId:a,state:r,updatedAt:n}},v=async(a,c,r)=>{const e=i(await a.customers.get({customerId:c})),n=T(e,r);return n?k(c,n):R(c,r,"canceled",!1)},I=a=>o(a,"customer_id","customerId"),q=(a,c)=>{const r={eventId:a,provider:"autumn",raw:{object:c,type:"billing.updated"}},e=I(c),n=S(c.plan_changes)[0]??c,t=n.subscription?i(n.subscription):n,d=o(t,"plan_id","planId","product_id","productId","id"),s=o(t,"status"),m=o(n,"action"),l=p(t,"past_due")??p(t,"pastDue")??!1,_=s===void 0?void 0:P[s],U=m===void 0?void 0:N[m],B=l?"past_due":_??U;return{...r,cancelAtPeriodEnd:p(t,"cancel_at_period_end")??A(t),currentPeriodEnd:u(t,"current_period_end","currentPeriodEnd"),currentPeriodStart:u(t,"current_period_start","currentPeriodStart"),customerId:e,priceId:d,referenceId:e,subscriptionId:e===void 0||d===void 0?void 0:f(e,d),type:E(B)}},M=(a,c,r)=>{const e={eventId:a,provider:"autumn",raw:{object:r,type:c}},n=o(r,"currency")??"usd";switch(c){case"billing.auto_topup_succeeded":{const t=i(r.invoice),d=u(t,"total","amount")??u(r,"total","amount"),s=o(t,"currency")??n;return{...e,amount:d===void 0?void 0:h(BigInt(Math.round(d)),s),customerId:I(r),referenceId:I(r),sessionId:o(t,"id","stripe_id","invoice_id")??o(r,"id"),type:"payment.captured"}}case"billing.updated":return q(a,r);case"customer.product.added":case"customer.product.canceled":case"customer.product.expired":case"customer.product.updated":case"product.attached":{const t=r.product?i(r.product):r,d=c==="customer.product.canceled"||c==="customer.product.expired"?"canceled":o(t,"status"),s=I(r)??I(t);return{...e,cancelAtPeriodEnd:p(t,"cancel_at_period_end")??A(t),currentPeriodEnd:u(t,"current_period_end","currentPeriodEnd"),currentPeriodStart:u(t,"current_period_start","currentPeriodStart"),customerId:s,priceId:o(t,"id","product_id","productId"),referenceId:s,subscriptionId:s===void 0?void 0:f(s,o(t,"id","product_id","productId")??""),type:E(P[d??""]??"past_due")}}case"invoice.paid":case"payment.succeeded":{const t=u(r,"total","amount","amount_paid");return{...e,amount:t===void 0?void 0:h(BigInt(Math.round(t)),n),customerId:I(r),referenceId:I(r),sessionId:o(r,"id","invoice_id","stripe_id"),type:"payment.captured"}}default:return{...e,type:"unhandled"}}},$=a=>o(a,"checkout_url","checkoutUrl","payment_url","paymentUrl","url")??"",z=a=>{const{webhookSecret:c}=a,r=a.client;return{cancelPayment:()=>y("manual payment cancellation"),cancelSubscription:async(e,n)=>{const{customerId:t,productId:d}=g(e);return await r.billing.update({cancelAction:n?.atPeriodEnd?"cancel_end_of_cycle":"cancel_immediately",customerId:t,planId:d}),n?.atPeriodEnd?{...await v(r,t,d),cancelAtPeriodEnd:!0}:R(t,d,"canceled",!1)},capabilities:{merchantOfRecord:!1,portal:!0,usageMetering:!0},capturePayment:e=>y("manual capture"),checkEntitlement:async e=>{if(e.featureId===void 0){const m=i(await r.customers.get({customerId:e.referenceId})),l=T(m,e.priceId??""),_=l?k(e.referenceId,l).state:void 0;return{allowed:_==="active"||_==="trialing",unlimited:!1}}const n=i(await r.check({customerId:e.referenceId,featureId:e.featureId,requiredBalance:e.quantity??1})),t=p(n,"allowed")??!1,d=n.balance,s=typeof d=="object"&&d!==null?i(d):n;return{allowed:t,...b(s)}},createCheckout:async e=>{const n=i(await r.billing.attach({customerId:e.referenceId,planId:e.priceId}));return{id:f(e.referenceId,e.priceId),provider:"autumn",url:$(n)}},createPortalSession:async e=>{const n=i(await r.billing.openCustomerPortal({customerId:e.customerId}));return{url:o(n,"url")??""}},getBalances:async e=>{const n=i(await r.customers.get({customerId:e})),t=i(n.balances??n.features);return Object.entries(t).map(([d,s])=>{const m=i(s),l=b(m);return{allowed:l.unlimited||(l.balance??0)>0,featureId:o(m,"featureId","feature_id")??d,...l}})},getOrCreateCustomer:async e=>{const n=i(await r.customers.getOrCreate({customerId:e.referenceId,email:e.email,name:e.metadata?.name}));return{createdAt:Date.now(),email:o(n,"email")??e.email,id:o(n,"id")??e.referenceId,provider:"autumn",referenceId:e.referenceId}},getPaymentStatus:()=>y("payment-session reconciliation"),getSubscriptionStatus:async e=>{const{customerId:n,productId:t}=g(e);return v(r,n,t)},identifier:"autumn",parseWebhook:async({headers:e,payload:n})=>{const t=e.get("svix-id")??e.get("webhook-id")??"";await C({payload:n,secret:c,toleranceSeconds:a.webhookToleranceSeconds,webhookId:t,webhookSignature:e.get("svix-signature")??e.get("webhook-signature")??"",webhookTimestamp:e.get("svix-timestamp")??e.get("webhook-timestamp")??""});const d=i(JSON.parse(n));return M(t,x(d,"type")??"",i(d.data))},refundPayment:()=>y("refunds"),reportUsage:async e=>{await r.track({customerId:e.referenceId,featureId:e.featureId,value:e.quantity})},resumeSubscription:async e=>{const{customerId:n,productId:t}=g(e);return await r.billing.update({cancelAction:"uncancel",customerId:n,planId:t}),{...await v(r,n,t),cancelAtPeriodEnd:!1}},updateSubscription:async(e,n)=>{const{customerId:t,productId:d}=g(e),s=n.priceId??d;return await r.billing.attach({customerId:t,planId:s}),v(r,t,s)}}};export{z as createAutumnAdapter};
1
+ import{LunoraPaymentError as O}from"../packem_shared/LunoraPaymentError-BSxyhWgu.mjs";import{a as i,r as x,c as o,d as p,e as u}from"../packem_shared/json-BJJPJVYj.mjs";import{money as h}from"../packem_shared/addMoney-B4ufWAnD.mjs";import{verifyStandardWebhook as C}from"../packem_shared/constantTimeEqual-D_ynru-O.mjs";import{m as D}from"../packem_shared/not-supported-Cl0brzhn.mjs";import{s as E}from"../packem_shared/subscription-event-C8GiQSFM.mjs";const P={active:"active",canceled:"canceled",expired:"canceled",past_due:"past_due",scheduled:"paused",trialing:"trialing"},N={activated:"active",canceled:"canceled",cancelled:"canceled",expired:"canceled",scheduled:"paused"},w="::",y=D("autumn"),f=(a,c)=>`${a}${w}${c}`,g=a=>{const c=a.lastIndexOf(w);if(c===-1)throw new O("PROVIDER_ERROR",`malformed autumn subscription id "${a}" (expected "<customerId>::<productId>")`);return{customerId:a.slice(0,c),productId:a.slice(c+w.length)}},A=a=>u(a,"canceled_at","canceledAt")!==void 0||o(a,"status")==="scheduled",k=(a,c)=>{const r=Date.now(),e=o(c,"id","product_id","productId","plan_id","planId")??"",n=o(c,"status")??"active",t=p(c,"past_due")??p(c,"pastDue")??!1;return{cancelAtPeriodEnd:A(c),createdAt:r,currentPeriodEnd:u(c,"current_period_end","currentPeriodEnd")??void 0,currentPeriodStart:u(c,"current_period_start","currentPeriodStart")??void 0,id:f(a,e),priceId:e,provider:"autumn",quantity:u(c,"quantity")??1,referenceId:a,state:t?"past_due":P[n]??"past_due",updatedAt:r}},S=a=>Array.isArray(a)?a.map(c=>i(c)):[],T=(a,c)=>[...S(a.products),...S(a.subscriptions)].find(e=>(o(e,"id","product_id","productId","plan_id","planId")??"")===c),b=a=>({balance:u(a,"remaining","balance"),limit:u(a,"granted","included_usage","limit"),unlimited:p(a,"unlimited")??!1,used:u(a,"usage","used")}),R=(a,c,r,e)=>{const n=Date.now();return{cancelAtPeriodEnd:e,createdAt:n,id:f(a,c),priceId:c,provider:"autumn",quantity:1,referenceId:a,state:r,updatedAt:n}},v=async(a,c,r)=>{const e=i(await a.customers.get({customerId:c})),n=T(e,r);return n?k(c,n):R(c,r,"canceled",!1)},I=a=>o(a,"customer_id","customerId"),q=(a,c)=>{const r={eventId:a,provider:"autumn",raw:{object:c,type:"billing.updated"}},e=I(c),n=S(c.plan_changes)[0]??c,t=n.subscription?i(n.subscription):n,d=o(t,"plan_id","planId","product_id","productId","id"),s=o(t,"status"),m=o(n,"action"),l=p(t,"past_due")??p(t,"pastDue")??!1,_=s===void 0?void 0:P[s],U=m===void 0?void 0:N[m],B=l?"past_due":_??U;return{...r,cancelAtPeriodEnd:p(t,"cancel_at_period_end")??A(t),currentPeriodEnd:u(t,"current_period_end","currentPeriodEnd"),currentPeriodStart:u(t,"current_period_start","currentPeriodStart"),customerId:e,priceId:d,referenceId:e,subscriptionId:e===void 0||d===void 0?void 0:f(e,d),type:E(B)}},M=(a,c,r)=>{const e={eventId:a,provider:"autumn",raw:{object:r,type:c}},n=o(r,"currency")??"usd";switch(c){case"billing.auto_topup_succeeded":{const t=i(r.invoice),d=u(t,"total","amount")??u(r,"total","amount"),s=o(t,"currency")??n;return{...e,amount:d===void 0?void 0:h(BigInt(Math.round(d)),s),customerId:I(r),referenceId:I(r),sessionId:o(t,"id","stripe_id","invoice_id")??o(r,"id"),type:"payment.captured"}}case"billing.updated":return q(a,r);case"customer.product.added":case"customer.product.canceled":case"customer.product.expired":case"customer.product.updated":case"product.attached":{const t=r.product?i(r.product):r,d=c==="customer.product.canceled"||c==="customer.product.expired"?"canceled":o(t,"status"),s=I(r)??I(t);return{...e,cancelAtPeriodEnd:p(t,"cancel_at_period_end")??A(t),currentPeriodEnd:u(t,"current_period_end","currentPeriodEnd"),currentPeriodStart:u(t,"current_period_start","currentPeriodStart"),customerId:s,priceId:o(t,"id","product_id","productId"),referenceId:s,subscriptionId:s===void 0?void 0:f(s,o(t,"id","product_id","productId")??""),type:E(P[d??""]??"past_due")}}case"invoice.paid":case"payment.succeeded":{const t=u(r,"total","amount","amount_paid");return{...e,amount:t===void 0?void 0:h(BigInt(Math.round(t)),n),customerId:I(r),referenceId:I(r),sessionId:o(r,"id","invoice_id","stripe_id"),type:"payment.captured"}}default:return{...e,type:"unhandled"}}},$=a=>o(a,"checkout_url","checkoutUrl","payment_url","paymentUrl","url")??"",z=a=>{const{webhookSecret:c}=a,r=a.client;return{cancelPayment:()=>y("manual payment cancellation"),cancelSubscription:async(e,n)=>{const{customerId:t,productId:d}=g(e);return await r.billing.update({cancelAction:n?.atPeriodEnd?"cancel_end_of_cycle":"cancel_immediately",customerId:t,planId:d}),n?.atPeriodEnd?{...await v(r,t,d),cancelAtPeriodEnd:!0}:R(t,d,"canceled",!1)},capabilities:{merchantOfRecord:!1,portal:!0,usageMetering:!0},capturePayment:e=>y("manual capture"),checkEntitlement:async e=>{if(e.featureId===void 0){const m=i(await r.customers.get({customerId:e.referenceId})),l=T(m,e.priceId??""),_=l?k(e.referenceId,l).state:void 0;return{allowed:_==="active"||_==="trialing",unlimited:!1}}const n=i(await r.check({customerId:e.referenceId,featureId:e.featureId,requiredBalance:e.quantity??1})),t=p(n,"allowed")??!1,d=n.balance,s=typeof d=="object"&&d!==null?i(d):n;return{allowed:t,...b(s)}},createCheckout:async e=>{const n=i(await r.billing.attach({customerId:e.referenceId,planId:e.priceId}));return{id:f(e.referenceId,e.priceId),provider:"autumn",url:$(n)}},createPortalSession:async e=>{const n=i(await r.billing.openCustomerPortal({customerId:e.customerId}));return{url:o(n,"url")??""}},getBalances:async e=>{const n=i(await r.customers.get({customerId:e})),t=i(n.balances??n.features);return Object.entries(t).map(([d,s])=>{const m=i(s),l=b(m);return{allowed:l.unlimited||(l.balance??0)>0,featureId:o(m,"featureId","feature_id")??d,...l}})},getOrCreateCustomer:async e=>{const n=i(await r.customers.getOrCreate({customerId:e.referenceId,email:e.email,name:e.metadata?.name}));return{createdAt:Date.now(),email:o(n,"email")??e.email,id:o(n,"id")??e.referenceId,provider:"autumn",referenceId:e.referenceId}},getPaymentStatus:()=>y("payment-session reconciliation"),getSubscriptionStatus:async e=>{const{customerId:n,productId:t}=g(e);return v(r,n,t)},identifier:"autumn",parseWebhook:async({headers:e,payload:n})=>{const t=e.get("svix-id")??e.get("webhook-id")??"";await C({payload:n,secret:c,toleranceSeconds:a.webhookToleranceSeconds,webhookId:t,webhookSignature:e.get("svix-signature")??e.get("webhook-signature")??"",webhookTimestamp:e.get("svix-timestamp")??e.get("webhook-timestamp")??""});const d=i(JSON.parse(n));return M(t,x(d,"type")??"",i(d.data))},refundPayment:()=>y("refunds"),reportUsage:async e=>{await r.track({customerId:e.referenceId,featureId:e.featureId,value:e.quantity})},resumeSubscription:async e=>{const{customerId:n,productId:t}=g(e);return await r.billing.update({cancelAction:"uncancel",customerId:n,planId:t}),{...await v(r,n,t),cancelAtPeriodEnd:!1}},updateSubscription:async(e,n)=>{const{customerId:t,productId:d}=g(e),s=n.priceId??d;return await r.billing.attach({customerId:t,planId:s}),v(r,t,s)}}};export{z as createAutumnAdapter};
@@ -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-Bj5tU-zT.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}},B=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}},D=(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":{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),sessionId:i(t.transaction)??i(t.subscription)??i(t.order)??i(t.checkout)??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=>B(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 D(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
+ 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-D_ynru-O.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}},B=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}},D=(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":{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),sessionId:i(t.transaction)??i(t.subscription)??i(t.order)??i(t.checkout)??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=>B(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 D(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 +1 @@
1
- import{LunoraPaymentError as v}from"../packem_shared/LunoraPaymentError-BSxyhWgu.mjs";import{idempotencyKey as S}from"../packem_shared/idempotencyKey-BjxjMMna.mjs";import{a as i,b as o,r as a,f as u,p as l,d as w}from"../packem_shared/json-BJJPJVYj.mjs";import{money as _,zeroMoney as f}from"../packem_shared/addMoney-B4ufWAnD.mjs";import{verifyStandardWebhook as b}from"../packem_shared/constantTimeEqual-Bj5tU-zT.mjs";import{m as h}from"../packem_shared/not-supported-Cl0brzhn.mjs";import{s as A}from"../packem_shared/subscription-event-C8GiQSFM.mjs";const P={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=h("dodopayments (merchant-of-record)"),p=d=>a(i(d.customer),"customer_id")??a(d,"customer_id"),m=d=>{const n=i(d),t=Date.now(),e=a(n,"status")??"";return{cancelAtPeriodEnd:w(n,"cancel_at_next_billing_date")??!1,createdAt:t,currentPeriodEnd:l(a(n,"next_billing_date")),currentPeriodStart:l(a(n,"previous_billing_date")),id:a(n,"subscription_id")??"",priceId:a(n,"product_id")??"",provider:"dodopayments",quantity:o(n,"quantity")??1,referenceId:u(n)??p(n)??"",state:g[e]??"past_due",updatedAt:t}},q=d=>{const n=i(d),t=Date.now(),e=a(n,"currency")??"usd",r=_(BigInt(Math.round(o(n,"total_amount")??0)),e),s=P[a(n,"status")??""]??"initiated";return{amount:r,capturedAmount:s==="captured"?r:f(e),createdAt:t,id:a(n,"payment_id")??"",provider:"dodopayments",referenceId:u(n)??"",refundedAmount:f(e),state:s,updatedAt:t}},k=(d,n,t)=>{const e={eventId:d,provider:"dodopayments",raw:{object:t,type:n}},r=a(t,"currency")??"usd";switch(n){case"dispute.lost":case"refund.succeeded":return{...e,amount:_(BigInt(Math.round(o(t,"amount")??0)),r),referenceId:u(t),sessionId:a(t,"payment_id"),type:"payment.refunded"};case"payment.cancelled":case"payment.failed":return{...e,referenceId:u(t),sessionId:a(t,"payment_id"),type:"payment.failed"};case"payment.succeeded":return{...e,amount:_(BigInt(Math.round(o(t,"total_amount")??0)),r),customerId:p(t),referenceId:u(t),sessionId:a(t,"payment_id"),subscriptionId:a(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(t,"status");return{...e,cancelAtPeriodEnd:w(t,"cancel_at_next_billing_date"),currentPeriodEnd:l(a(t,"next_billing_date")),currentPeriodStart:l(a(t,"previous_billing_date")),customerId:p(t),priceId:a(t,"product_id"),quantity:o(t,"quantity"),referenceId:u(t)??p(t),subscriptionId:a(t,"subscription_id"),type:A(g[s??""]??"past_due")}}default:return{...e,type:"unhandled"}}},R=d=>{const{webhookSecret:n}=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 m(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:a(r,"session_id")??"",provider:"dodopayments",url:a(r,"checkout_url")??""}},createPortalSession:async e=>{const r=i(await t.customers.customerPortal.create(e.customerId,{return_url:e.returnUrl}));return{url:a(r,"link")??a(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:a(r,"email")??e.email,id:a(r,"customer_id")??"",provider:"dodopayments",referenceId:e.referenceId}},getPaymentStatus:async e=>q(await t.payments.retrieve(e)),getSubscriptionStatus:async e=>m(await t.subscriptions.retrieve(e)),identifier:"dodopayments",parseWebhook:async({headers:e,payload:r})=>{const s=e.get("webhook-id")??"";await b({payload:r,secret:n,toleranceSeconds:d.webhookToleranceSeconds,webhookId:s,webhookSignature:e.get("webhook-signature")??"",webhookTimestamp:e.get("webhook-timestamp")??""});const c=i(JSON.parse(r));return k(s,a(c,"type")??"",i(c.data))},refundPayment:async e=>{if(e.amount!==void 0)throw new v("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=a(r,"currency")??"usd",c=_(BigInt(Math.round(o(r,"amount")??0)),s);let y="captured";return a(r,"status")==="succeeded"&&(y="refunded"),{amount:c,capturedAmount:c,createdAt:Date.now(),id:e.sessionId,provider:"dodopayments",referenceId:"",refundedAmount:c,state:y,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 m(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??a(s,"product_id")??"",proration_billing_mode:"prorated_immediately",quantity:r.quantity??o(s,"quantity")??1})}return m(await t.subscriptions.retrieve(e))}}};export{R as createDodoPaymentsAdapter};
1
+ import{LunoraPaymentError as v}from"../packem_shared/LunoraPaymentError-BSxyhWgu.mjs";import{idempotencyKey as S}from"../packem_shared/idempotencyKey-BjxjMMna.mjs";import{a as i,b as o,r as a,f as u,p as l,d as w}from"../packem_shared/json-BJJPJVYj.mjs";import{money as _,zeroMoney as f}from"../packem_shared/addMoney-B4ufWAnD.mjs";import{verifyStandardWebhook as b}from"../packem_shared/constantTimeEqual-D_ynru-O.mjs";import{m as h}from"../packem_shared/not-supported-Cl0brzhn.mjs";import{s as A}from"../packem_shared/subscription-event-C8GiQSFM.mjs";const P={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=h("dodopayments (merchant-of-record)"),p=d=>a(i(d.customer),"customer_id")??a(d,"customer_id"),m=d=>{const n=i(d),t=Date.now(),e=a(n,"status")??"";return{cancelAtPeriodEnd:w(n,"cancel_at_next_billing_date")??!1,createdAt:t,currentPeriodEnd:l(a(n,"next_billing_date")),currentPeriodStart:l(a(n,"previous_billing_date")),id:a(n,"subscription_id")??"",priceId:a(n,"product_id")??"",provider:"dodopayments",quantity:o(n,"quantity")??1,referenceId:u(n)??p(n)??"",state:g[e]??"past_due",updatedAt:t}},q=d=>{const n=i(d),t=Date.now(),e=a(n,"currency")??"usd",r=_(BigInt(Math.round(o(n,"total_amount")??0)),e),s=P[a(n,"status")??""]??"initiated";return{amount:r,capturedAmount:s==="captured"?r:f(e),createdAt:t,id:a(n,"payment_id")??"",provider:"dodopayments",referenceId:u(n)??"",refundedAmount:f(e),state:s,updatedAt:t}},k=(d,n,t)=>{const e={eventId:d,provider:"dodopayments",raw:{object:t,type:n}},r=a(t,"currency")??"usd";switch(n){case"dispute.lost":case"refund.succeeded":return{...e,amount:_(BigInt(Math.round(o(t,"amount")??0)),r),referenceId:u(t),sessionId:a(t,"payment_id"),type:"payment.refunded"};case"payment.cancelled":case"payment.failed":return{...e,referenceId:u(t),sessionId:a(t,"payment_id"),type:"payment.failed"};case"payment.succeeded":return{...e,amount:_(BigInt(Math.round(o(t,"total_amount")??0)),r),customerId:p(t),referenceId:u(t),sessionId:a(t,"payment_id"),subscriptionId:a(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(t,"status");return{...e,cancelAtPeriodEnd:w(t,"cancel_at_next_billing_date"),currentPeriodEnd:l(a(t,"next_billing_date")),currentPeriodStart:l(a(t,"previous_billing_date")),customerId:p(t),priceId:a(t,"product_id"),quantity:o(t,"quantity"),referenceId:u(t)??p(t),subscriptionId:a(t,"subscription_id"),type:A(g[s??""]??"past_due")}}default:return{...e,type:"unhandled"}}},R=d=>{const{webhookSecret:n}=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 m(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:a(r,"session_id")??"",provider:"dodopayments",url:a(r,"checkout_url")??""}},createPortalSession:async e=>{const r=i(await t.customers.customerPortal.create(e.customerId,{return_url:e.returnUrl}));return{url:a(r,"link")??a(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:a(r,"email")??e.email,id:a(r,"customer_id")??"",provider:"dodopayments",referenceId:e.referenceId}},getPaymentStatus:async e=>q(await t.payments.retrieve(e)),getSubscriptionStatus:async e=>m(await t.subscriptions.retrieve(e)),identifier:"dodopayments",parseWebhook:async({headers:e,payload:r})=>{const s=e.get("webhook-id")??"";await b({payload:r,secret:n,toleranceSeconds:d.webhookToleranceSeconds,webhookId:s,webhookSignature:e.get("webhook-signature")??"",webhookTimestamp:e.get("webhook-timestamp")??""});const c=i(JSON.parse(r));return k(s,a(c,"type")??"",i(c.data))},refundPayment:async e=>{if(e.amount!==void 0)throw new v("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=a(r,"currency")??"usd",c=_(BigInt(Math.round(o(r,"amount")??0)),s);let y="captured";return a(r,"status")==="succeeded"&&(y="refunded"),{amount:c,capturedAmount:c,createdAt:Date.now(),id:e.sessionId,provider:"dodopayments",referenceId:"",refundedAmount:c,state:y,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 m(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??a(s,"product_id")??"",proration_billing_mode:"prorated_immediately",quantity:r.quantity??o(s,"quantity")??1})}return m(await t.subscriptions.retrieve(e))}}};export{R as createDodoPaymentsAdapter};
@@ -1 +1 @@
1
- import{a as p,r as n,f as c,d as w,p as f,b as i}from"../packem_shared/json-BJJPJVYj.mjs";import{money as m,zeroMoney as I}from"../packem_shared/addMoney-B4ufWAnD.mjs";import{verifyStandardWebhook as P}from"../packem_shared/constantTimeEqual-Bj5tU-zT.mjs";import{m as g}from"../packem_shared/not-supported-Cl0brzhn.mjs";import{s as b}from"../packem_shared/subscription-event-C8GiQSFM.mjs";const y=s=>s instanceof Date?s.getTime():f(typeof s=="string"?s:void 0),S={draft:"initiated",paid:"captured",partially_refunded:"partially_refunded",pending:"initiated",refunded:"refunded",void:"canceled"},A={active:"active",canceled:"canceled",incomplete:"past_due",incomplete_expired:"canceled",past_due:"past_due",trialing:"trialing",unpaid:"past_due"},_=g("polar (merchant-of-record)"),u=s=>{const a=p(s),r=Date.now();return{cancelAtPeriodEnd:w(a,"cancelAtPeriodEnd")??!1,createdAt:r,currentPeriodEnd:y(a.currentPeriodEnd),currentPeriodStart:y(a.currentPeriodStart),id:n(a,"id")??"",priceId:n(a,"productId")??"",provider:"polar",quantity:1,referenceId:c(a)??"",state:A[n(a,"status")??""]??"past_due",updatedAt:r}},v=s=>{const a=p(s),r=Date.now(),e=n(a,"currency")??"usd",t=m(BigInt(Math.round(i(a,"totalAmount")??i(a,"amount")??0)),e),d=S[n(a,"status")??""]??"initiated";return{amount:t,capturedAmount:d==="captured"||d==="partially_refunded"||d==="refunded"?t:I(e),createdAt:r,id:n(a,"id")??"",provider:"polar",referenceId:c(a)??"",refundedAmount:d==="refunded"?t:I(e),state:d,updatedAt:r}},h=(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"&&S[n(r,"status")??""]!=="captured"?{...e,type:"unhandled"}:{...e,amount:m(i(r,"total_amount")??i(r,"amount")??0,t),customerId:n(r,"customer_id"),referenceId:c(r),sessionId:n(r,"id"),subscriptionId:n(r,"subscription_id"),type:"payment.captured"};case"refund.created":return{...e,amount:m(i(r,"amount")??0,t),referenceId:c(r),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":b(A[n(r,"status")??""]??"past_due");return{...e,cancelAtPeriodEnd:w(r,"cancel_at_period_end"),currentPeriodEnd:f(n(r,"current_period_end")),currentPeriodStart:f(n(r,"current_period_start")),customerId:n(r,"customer_id"),priceId:n(r,"product_id"),referenceId:c(r),subscriptionId:n(r,"id"),type:d}}default:return{...e,type:"unhandled"}}},M=s=>{const{webhookSecret:a}=s,r=s.client;return{cancelPayment:()=>_("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 u(d)},capabilities:{merchantOfRecord:!0,portal:!0,usageMetering:!0},capturePayment:e=>_("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=>v(await r.orders.get({id:e})),getSubscriptionStatus:async e=>u(await r.subscriptions.get({id:e})),identifier:"polar",parseWebhook:async({headers:e,payload:t})=>{const d=e.get("webhook-id")??"";await P({payload:t,secret:a,toleranceSeconds:s.webhookToleranceSeconds,webhookId:d,webhookSignature:e.get("webhook-signature")??"",webhookTimestamp:e.get("webhook-timestamp")??""});const o=p(JSON.parse(t));return h(d,n(o,"type")??"",p(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;await r.refunds.create({amount:o,orderId:e.sessionId,reason:e.reason??"customer_request"});const l=e.amount??m(BigInt(Math.round(o)),d);return{amount:l,capturedAmount:l,createdAt:Date.now(),id:e.sessionId,provider:"polar",referenceId:"",refundedAmount:l,state:"refunded",updatedAt:Date.now()}},reportUsage:async e=>{await r.events.ingest({events:[{externalCustomerId:e.referenceId,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 u(t)},updateSubscription:async(e,t)=>{const d=await r.subscriptions.update({id:e,subscriptionUpdate:t.priceId?{productId:t.priceId}:{}});return u(d)}}};export{M as createPolarAdapter};
1
+ import{a as p,r as n,f as c,d as w,p as f,b as i}from"../packem_shared/json-BJJPJVYj.mjs";import{money as m,zeroMoney as I}from"../packem_shared/addMoney-B4ufWAnD.mjs";import{verifyStandardWebhook as P}from"../packem_shared/constantTimeEqual-D_ynru-O.mjs";import{m as g}from"../packem_shared/not-supported-Cl0brzhn.mjs";import{s as b}from"../packem_shared/subscription-event-C8GiQSFM.mjs";const y=s=>s instanceof Date?s.getTime():f(typeof s=="string"?s:void 0),S={draft:"initiated",paid:"captured",partially_refunded:"partially_refunded",pending:"initiated",refunded:"refunded",void:"canceled"},A={active:"active",canceled:"canceled",incomplete:"past_due",incomplete_expired:"canceled",past_due:"past_due",trialing:"trialing",unpaid:"past_due"},_=g("polar (merchant-of-record)"),u=s=>{const a=p(s),r=Date.now();return{cancelAtPeriodEnd:w(a,"cancelAtPeriodEnd")??!1,createdAt:r,currentPeriodEnd:y(a.currentPeriodEnd),currentPeriodStart:y(a.currentPeriodStart),id:n(a,"id")??"",priceId:n(a,"productId")??"",provider:"polar",quantity:1,referenceId:c(a)??"",state:A[n(a,"status")??""]??"past_due",updatedAt:r}},v=s=>{const a=p(s),r=Date.now(),e=n(a,"currency")??"usd",t=m(BigInt(Math.round(i(a,"totalAmount")??i(a,"amount")??0)),e),d=S[n(a,"status")??""]??"initiated";return{amount:t,capturedAmount:d==="captured"||d==="partially_refunded"||d==="refunded"?t:I(e),createdAt:r,id:n(a,"id")??"",provider:"polar",referenceId:c(a)??"",refundedAmount:d==="refunded"?t:I(e),state:d,updatedAt:r}},h=(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"&&S[n(r,"status")??""]!=="captured"?{...e,type:"unhandled"}:{...e,amount:m(i(r,"total_amount")??i(r,"amount")??0,t),customerId:n(r,"customer_id"),referenceId:c(r),sessionId:n(r,"id"),subscriptionId:n(r,"subscription_id"),type:"payment.captured"};case"refund.created":return{...e,amount:m(i(r,"amount")??0,t),referenceId:c(r),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":b(A[n(r,"status")??""]??"past_due");return{...e,cancelAtPeriodEnd:w(r,"cancel_at_period_end"),currentPeriodEnd:f(n(r,"current_period_end")),currentPeriodStart:f(n(r,"current_period_start")),customerId:n(r,"customer_id"),priceId:n(r,"product_id"),referenceId:c(r),subscriptionId:n(r,"id"),type:d}}default:return{...e,type:"unhandled"}}},M=s=>{const{webhookSecret:a}=s,r=s.client;return{cancelPayment:()=>_("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 u(d)},capabilities:{merchantOfRecord:!0,portal:!0,usageMetering:!0},capturePayment:e=>_("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=>v(await r.orders.get({id:e})),getSubscriptionStatus:async e=>u(await r.subscriptions.get({id:e})),identifier:"polar",parseWebhook:async({headers:e,payload:t})=>{const d=e.get("webhook-id")??"";await P({payload:t,secret:a,toleranceSeconds:s.webhookToleranceSeconds,webhookId:d,webhookSignature:e.get("webhook-signature")??"",webhookTimestamp:e.get("webhook-timestamp")??""});const o=p(JSON.parse(t));return h(d,n(o,"type")??"",p(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;await r.refunds.create({amount:o,orderId:e.sessionId,reason:e.reason??"customer_request"});const l=e.amount??m(BigInt(Math.round(o)),d);return{amount:l,capturedAmount:l,createdAt:Date.now(),id:e.sessionId,provider:"polar",referenceId:"",refundedAmount:l,state:"refunded",updatedAt:Date.now()}},reportUsage:async e=>{await r.events.ingest({events:[{externalCustomerId:e.referenceId,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 u(t)},updateSubscription:async(e,t)=>{const d=await r.subscriptions.update({id:e,subscriptionUpdate:t.priceId?{productId:t.priceId}:{}});return u(d)}}};export{M as createPolarAdapter};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lunora/payment",
3
- "version": "1.0.0-alpha.96",
3
+ "version": "1.0.0-alpha.98",
4
4
  "description": "Provider-agnostic payments for Lunora: Stripe-first adapter, webhook sync, and subscription/payment state machine",
5
5
  "keywords": [
6
6
  "billing",
@@ -71,9 +71,9 @@
71
71
  "access": "public"
72
72
  },
73
73
  "dependencies": {
74
- "@lunora/errors": "1.0.0-alpha.26",
75
- "@lunora/server": "1.0.0-alpha.94",
76
- "@lunora/values": "1.0.0-alpha.34",
74
+ "@lunora/errors": "1.0.0-alpha.27",
75
+ "@lunora/server": "1.0.0-alpha.96",
76
+ "@lunora/values": "1.0.0-alpha.35",
77
77
  "dinero.js": "2.0.2"
78
78
  },
79
79
  "peerDependencies": {
@@ -1 +0,0 @@
1
- const u=(i,e)=>`${i}:${e}`,n=(i,e)=>`${i}:${e}`,a=i=>{const e=i.toSorted((r,o)=>r.createdAt-o.createdAt||r.idempotencyKey.localeCompare(o.idempotencyKey));let s=0;for(const r of e)s=r.mode==="set"?r.quantity:s+r.quantity;return s};class d{customers=new Map;processedEvents=new Set;sessions=new Map;subscriptions=new Map;usageEvents=new Map;getCustomerByReference(e,s){return Promise.resolve(this.customers.get(u(e,s)))}getPaymentSession(e,s){return Promise.resolve(this.sessions.get(n(e,s)))}getSubscription(e,s){return Promise.resolve(this.subscriptions.get(n(e,s)))}listSubscriptionsByReference(e){return Promise.resolve([...this.subscriptions.values()].filter(s=>s.referenceId===e))}markEventProcessed(e,s){const r=n(e,s);return this.processedEvents.has(r)?Promise.resolve(!1):(this.processedEvents.add(r),Promise.resolve(!0))}releaseEvent(e,s){return this.processedEvents.delete(n(e,s)),Promise.resolve()}markUsageReported(e,s){const r=n(e,s),o=this.usageEvents.get(r);return o&&this.usageEvents.set(r,{...o,reportedToProvider:!0}),Promise.resolve()}recordUsage(e){const s=n(e.provider,e.idempotencyKey);return this.usageEvents.has(s)?Promise.resolve(!1):(this.usageEvents.set(s,e),Promise.resolve(!0))}sumUsage(e,s,r){const o=[];for(const t of this.usageEvents.values())t.referenceId===e&&t.featureId===s&&t.createdAt>=r&&o.push(t);return Promise.resolve(a(o))}sumUsageByFeature(e,s,r){const o=new Map(s.map(t=>[t,[]]));for(const t of this.usageEvents.values())t.referenceId===e&&t.createdAt>=r&&o.get(t.featureId)?.push(t);return Promise.resolve(new Map([...o].map(([t,c])=>[t,a(c)])))}upsertCustomer(e){return this.customers.set(u(e.provider,e.referenceId),e),Promise.resolve()}upsertPaymentSession(e){return this.sessions.set(n(e.provider,e.id),e),Promise.resolve()}upsertSubscription(e){return this.subscriptions.set(n(e.provider,e.id),e),Promise.resolve()}}export{d as MemoryPaymentStore,a as foldUsage};
@@ -1 +0,0 @@
1
- import{LunoraPaymentError as r}from"./LunoraPaymentError-BSxyhWgu.mjs";const g=(e,t)=>{const s=Math.max(e.length,t.length);let o=e.length^t.length;for(let n=0;n<s;n+=1){const a=n<e.length?e.charCodeAt(n):0,i=n<t.length?t.charCodeAt(n):0;o|=a^i}return o===0},h=new TextEncoder,I=e=>[...new Uint8Array(e)].map(t=>t.toString(16).padStart(2,"0")).join(""),d="whsec_",l=e=>new Uint8Array(Array.from(atob(e),t=>t.codePointAt(0)??0)),A=e=>btoa(String.fromCodePoint(...new Uint8Array(e))),f=async(e,t)=>{const s=await crypto.subtle.importKey("raw",e,{hash:"SHA-256",name:"HMAC"},!1,["sign"]),o=await crypto.subtle.sign("HMAC",s,h.encode(t));return A(o)},m=g,y=async(e,t)=>{const s=await crypto.subtle.importKey("raw",h.encode(e),{hash:"SHA-256",name:"HMAC"},!1,["sign"]),o=await crypto.subtle.sign("HMAC",s,h.encode(t));return I(o)},N=async e=>{if(!e.secret)throw new r("CONFIG_INVALID","webhook secret not configured");const t=e.toleranceSeconds??300,s=e.now??Date.now(),o=Number(e.webhookTimestamp);if(!e.webhookId||!e.webhookSignature||!Number.isFinite(o))throw new r("WEBHOOK_SIGNATURE_INVALID","missing standard-webhooks headers");if(Math.abs(Math.floor(s/1e3)-o)>t)throw new r("WEBHOOK_TIMESTAMP_INVALID","signature timestamp outside tolerance");const n=e.secret.startsWith(d)?e.secret.slice(d.length):e.secret;if(!n)throw new r("CONFIG_INVALID","webhook secret not configured");const a=l(n);if(a.length===0)throw new r("CONFIG_INVALID","webhook secret not configured");const i=await f(a,`${e.webhookId}.${e.webhookTimestamp}.${e.payload}`);if(!e.webhookSignature.split(" ").map(c=>{const w=c.indexOf(",");return w===-1?"":c.slice(w+1)}).filter(Boolean).some(c=>m(c,i)))throw new r("WEBHOOK_SIGNATURE_INVALID","no matching signature")},E=async e=>{if(!e.secret)throw new r("CONFIG_INVALID","webhook secret not configured");if(!e.signature)throw new r("WEBHOOK_SIGNATURE_INVALID","missing creem-signature header");const t=await y(e.secret,e.payload);if(!m(e.signature,t))throw new r("WEBHOOK_SIGNATURE_INVALID","no matching signature")};export{m as constantTimeEqual,y as hmacSha256Hex,E as verifyCreemSignature,N as verifyStandardWebhook};
@@ -1 +0,0 @@
1
- import{money as u}from"./addMoney-B4ufWAnD.mjs";import{foldUsage as y}from"./MemoryPaymentStore-C2iTSo5g.mjs";const o=(e,n)=>typeof e[n]=="string"?e[n]:"",A=(e,n)=>typeof e[n]=="string"?e[n]:void 0,c=(e,n)=>typeof e[n]=="number"?e[n]:0,f=(e,n)=>typeof e[n]=="number"?e[n]:void 0,I=(e,n)=>e[n]===!0,p=(e,n)=>{const t=e[n];return typeof t=="bigint"?t:typeof t=="number"||typeof t=="string"?BigInt(t):0n},g=e=>({createdAt:e.createdAt,email:e.email,provider:e.provider,providerCustomerId:e.id,referenceId:e.referenceId}),S=e=>({createdAt:c(e,"createdAt"),email:A(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}),P=e=>{const n=o(e,"currency");return{amount:u(p(e,"amountMinor"),n),capturedAmount:u(p(e,"capturedMinor"),n),createdAt:c(e,"createdAt"),id:o(e,"providerSessionId"),provider:o(e,"provider"),referenceId:o(e,"referenceId"),refundedAmount:u(p(e,"refundedMinor"),n),state:o(e,"state"),updatedAt:c(e,"updatedAt")}},l=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}),m=e=>({cancelAtPeriodEnd:I(e,"cancelAtPeriodEnd"),createdAt:c(e,"createdAt"),currentPeriodEnd:f(e,"currentPeriodEnd"),currentPeriodStart:f(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")}),M=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}),T=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?S(r):void 0},getPaymentSession:async(t,d)=>{const r=await e.findFirst("paymentSessions",{provider:t,providerSessionId:d});return r?P(r):void 0},getSubscription:async(t,d)=>{const r=await e.findFirst("subscriptions",{provider:t,providerSubscriptionId:d});return r?m(r):void 0},listSubscriptionsByReference:async t=>(await e.findMany("subscriptions",{referenceId:t})).map(r=>m(r)),markEventProcessed:async(t,d)=>await e.findFirst("events",{provider:t,providerEventId:d})?!1:(await e.insert("events",{processedAt:Date.now(),provider:t,providerEventId:d,type:""}),!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",M(t)),!0),sumUsage:async(t,d,r)=>{const s=(await e.findMany("usageEvents",{featureId:d,referenceId:t})).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 y(s)},sumUsageByFeature:async(t,d,r)=>{const 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,v])=>[i,y(v)]))},upsertCustomer:async t=>n("customers",{provider:t.provider,referenceId:t.referenceId},g(t)),upsertPaymentSession:async t=>n("paymentSessions",{provider:t.provider,providerSessionId:t.id},E(t)),upsertSubscription:async t=>n("subscriptions",{provider:t.provider,providerSubscriptionId:t.id},l(t))}};export{T as createDatabasePaymentStore};
@@ -1 +0,0 @@
1
- import{createPayment as n}from"./createPayment-Dmh6IWLZ.mjs";import{createDatabasePaymentStore as i}from"./createDatabasePaymentStore-BlMXuCW_.mjs";const s=r=>({delete:async t=>r.delete(t),findFirst:async(t,e)=>await r.findFirst(t,{where:e}),findMany:async(t,e)=>(await r.findMany(t,{where:e})).page,insert:async(t,e)=>r.insert(t,e),patch:async(t,e)=>r.patch(t,e)}),m=(r,t)=>{const e=r.auth?.userId??void 0;return n({adapter:t.adapter,authorize:t.authorize??(a=>a.trim()!==""&&e!==void 0&&a===e),entitlements:t.entitlements,observability:t.observability,store:i(s(r.db))})};export{s as lunoraDatabaseToPaymentDatabase,m as paymentsFromContext};
@@ -1 +0,0 @@
1
- import{compareMoney as m}from"./addMoney-B4ufWAnD.mjs";import{n as c}from"./observability-BteZ2dJS.mjs";const f=(t,e)=>t.currency===e.currency&&m(t,e)===0,l=(t,e)=>t?.state!==e.state||t.cancelAtPeriodEnd!==e.cancelAtPeriodEnd||t.currentPeriodEnd!==e.currentPeriodEnd||t.priceId!==e.priceId||t.quantity!==e.quantity,y=(t,e)=>t?.state!==e.state||!f(t.capturedAmount,e.capturedAmount)||!f(t.refundedAmount,e.refundedAmount),A=new Set(["partially_refunded","refunded"]),S=(t,e)=>{if(!t)return e;const a=t.refundedAmount.currency===e.refundedAmount.currency&&m(t.refundedAmount,e.refundedAmount)>0?t.refundedAmount:e.refundedAmount,d=e.state==="captured"&&A.has(t.state)?t.state:e.state,r=e.referenceId===""?t.referenceId:e.referenceId;return{...e,referenceId:r,refundedAmount:a,state:d}},b=async(t,e,n,a)=>{const d=await t.getSubscriptionStatus(n),r=await e.getSubscription(t.identifier,n);return l(r,d)?(await e.upsertSubscription({...d,createdAt:r?.createdAt??d.createdAt}),c(a,{id:n,kind:"subscription",provider:t.identifier,type:"reconcile.drift"}),!0):!1},P=async(t,e,n,a)=>{const d=await t.getPaymentStatus(n),r=await e.getPaymentSession(t.identifier,n),s=S(r,d);return y(r,s)?(await e.upsertPaymentSession({...s,createdAt:r?.createdAt??s.createdAt}),c(a,{id:n,kind:"payment",provider:t.identifier,type:"reconcile.drift"}),!0):!1},p=async(t,e,n,a,d)=>{const r=await Promise.allSettled(t.map(i=>n(i)));let s=0,o=0;for(const[i,u]of r.entries())u.status==="fulfilled"?u.value&&(s+=1):(o+=1,c(d,{error:u.reason,id:t[i]??"",kind:e,provider:a.identifier,type:"reconcile.error"}));return{failed:o,updated:s}},v=async t=>{const{adapter:e,observability:n,store:a}=t,d=t.subscriptionIds??[],r=t.paymentSessionIds??[],s=await p(d,"subscription",i=>b(e,a,i,n),e,n),o=await p(r,"payment",i=>P(e,a,i,n),e,n);return c(n,{failedPayments:o.failed,failedSubscriptions:s.failed,provider:e.identifier,type:"reconcile.completed",updatedPayments:o.updated,updatedSubscriptions:s.updated}),{checkedPayments:r.length,checkedSubscriptions:d.length,failedPayments:o.failed,failedSubscriptions:s.failed,updatedPayments:o.updated,updatedSubscriptions:s.updated}};export{v as reconcile};