@voltro/plugin-billing 0.54.0 → 0.56.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,22 +1,23 @@
1
1
  import { BillingError as e, BillingService as t, DEFAULT_PLAN as n, EntitlementExceeded as r, SubscriptionLocked as i } from "./types.js";
2
2
  import { billingRpcClientImports as a, changePlanDescriptor as o, changeSeatsDescriptor as s, entitlementStatusDescriptor as c, invoicesDescriptor as l, portalUrlDescriptor as u, previewChangeDescriptor as d, reportUsageDescriptor as f, startCheckoutDescriptor as ee, subscriptionDescriptor as te } from "./rpc.js";
3
3
  import { Effect as p, Layer as m, Schedule as h, Schema as ne } from "effect";
4
- import { pluginEnv as g } from "@voltro/env";
5
- import { composeRpcInterceptors as re, definePlugin as ie, pluginInstanceName as ae } from "@voltro/protocol";
6
- import { and as _, eq as v, gte as y, id as b, integer as x, registerRetention as S, retentionTtlMsFromEnv as C, table as w, text as T, timestamp as E } from "@voltro/database";
7
- import { createLogger as D } from "@voltro/logger";
8
- import O from "stripe";
9
- import { defineIncomingWebhook as oe, mountIncomingWebhook as k } from "@voltro/plugin-webhooks";
10
- import { stripeProvider as A } from "@voltro/plugin-webhooks/providers";
4
+ import { pluginEnv as re } from "@voltro/env";
5
+ import { composeRpcInterceptors as ie, definePlugin as ae, pluginInstanceName as oe } from "@voltro/protocol";
6
+ import { OccurrenceCounter as g, and as _, changeDigest as se, composeChangeKey as ce, eq as v, gte as le, id as y, integer as b, occurrenceWindowMs as ue, registerRetention as x, retentionTtlMsFromEnv as S, table as C, text as w, timestamp as T } from "@voltro/database";
7
+ import { replicaId as de } from "@voltro/protocol/identity";
8
+ import { createLogger as E } from "@voltro/logger";
9
+ import D from "stripe";
10
+ import { defineIncomingWebhook as fe, mountIncomingWebhook as pe } from "@voltro/plugin-webhooks";
11
+ import { stripeProvider as O } from "@voltro/plugin-webhooks/providers";
11
12
  //#region src/entitlement.ts
12
- var j = (e, t, n, r) => ({
13
+ var k = (e, t, n, r) => ({
13
14
  allowed: !Number.isFinite(t) || r <= 0 || n + r <= t,
14
15
  entitlement: e,
15
16
  limit: t,
16
17
  used: n,
17
18
  cost: r
18
- }), M = (e) => e.tenantId, se = (e, n, i) => p.gen(function* () {
19
- let a = M(e.request.subject);
19
+ }), A = (e) => e.tenantId, me = (e, n, i) => p.gen(function* () {
20
+ let a = A(e.request.subject);
20
21
  if (a === null) return i <= 0 ? void 0 : yield* p.fail(new r({
21
22
  entitlement: n,
22
23
  limit: 0,
@@ -24,8 +25,8 @@ var j = (e, t, n, r) => ({
24
25
  cost: i
25
26
  }));
26
27
  yield* (yield* t).consumeEntitlement(a, n, i);
27
- }), N = (e) => p.gen(function* () {
28
- let n = M(e.request.subject);
28
+ }), he = (e) => p.gen(function* () {
29
+ let n = A(e.request.subject);
29
30
  if (n === null) return;
30
31
  let r = yield* (yield* t).entitlementStatus(n);
31
32
  if (!r.entitled) return yield* p.fail(new i({
@@ -34,7 +35,7 @@ var j = (e, t, n, r) => ({
34
35
  lockedSince: (r.lockedSince ?? /* @__PURE__ */ new Date()).toISOString(),
35
36
  lockout: r.lockout
36
37
  }));
37
- }), ce = (e, t) => (n, i) => {
38
+ }), ge = (e, t) => (n, i) => {
38
39
  let a = e[i.tag];
39
40
  if (a === void 0) return n;
40
41
  let o = a.cost ?? 1, s = i.subject.tenantId;
@@ -44,66 +45,66 @@ var j = (e, t, n, r) => ({
44
45
  used: 0,
45
46
  cost: o
46
47
  })) : p.flatMap(t.consumeEntitlement(s, a.entitlement, o), () => n);
47
- }, P = "_voltro_billing_customers", F = "_voltro_billing_subscriptions", I = "_voltro_billing_invoices", L = "_voltro_billing_usage", le = w(P, {
48
- id: b({ prefix: "bcust" }),
49
- tenantId: T(),
50
- provider: T(),
51
- providerCustomerId: T(),
52
- createdAt: E(),
53
- updatedAt: E()
54
- }).index("byBillingCustomerTenant", ["tenantId"]).index("byBillingProviderCustomer", ["providerCustomerId"]), ue = w(F, {
55
- id: b({ prefix: "bsub" }),
56
- tenantId: T(),
57
- provider: T(),
58
- providerSubscriptionId: T(),
59
- plan: T(),
60
- status: T(),
61
- quantity: x().default(1),
62
- currentPeriodStart: E().nullable(),
63
- currentPeriodEnd: E().nullable(),
64
- cancelAt: E().nullable(),
65
- pastDueSince: E().nullable(),
66
- statusEventAt: E().nullable(),
67
- createdAt: E(),
68
- updatedAt: E()
69
- }).index("byBillingSubscriptionTenant", ["tenantId"]).index("byBillingProviderSubscription", ["providerSubscriptionId"]).index("byBillingSubscriptionStatus", ["status"]), de = w(I, {
70
- id: b({ prefix: "binv" }),
71
- tenantId: T(),
72
- provider: T(),
73
- providerInvoiceId: T(),
74
- amountMinor: x(),
75
- currency: T(),
76
- status: T(),
77
- statusEventAt: E().nullable(),
78
- createdAt: E()
79
- }).index("byBillingInvoiceTenant", ["tenantId"]).index("byBillingProviderInvoice", ["providerInvoiceId"]), fe = w(L, {
80
- id: b({ prefix: "buse" }),
81
- tenantId: T().maxLength(191),
82
- entitlementKey: T().maxLength(191),
83
- period: T().maxLength(16),
84
- used: x().default(0),
85
- reportedToProvider: x().default(0),
86
- updatedAt: E()
48
+ }, j = "_voltro_billing_customers", M = "_voltro_billing_subscriptions", N = "_voltro_billing_invoices", P = "_voltro_billing_usage", _e = C(j, {
49
+ id: y({ prefix: "bcust" }),
50
+ tenantId: w(),
51
+ provider: w(),
52
+ providerCustomerId: w(),
53
+ createdAt: T(),
54
+ updatedAt: T()
55
+ }).index("byBillingCustomerTenant", ["tenantId"]).index("byBillingProviderCustomer", ["providerCustomerId"]), ve = C(M, {
56
+ id: y({ prefix: "bsub" }),
57
+ tenantId: w(),
58
+ provider: w(),
59
+ providerSubscriptionId: w(),
60
+ plan: w(),
61
+ status: w(),
62
+ quantity: b().default(1),
63
+ currentPeriodStart: T().nullable(),
64
+ currentPeriodEnd: T().nullable(),
65
+ cancelAt: T().nullable(),
66
+ pastDueSince: T().nullable(),
67
+ statusEventAt: T().nullable(),
68
+ createdAt: T(),
69
+ updatedAt: T()
70
+ }).index("byBillingSubscriptionTenant", ["tenantId"]).index("byBillingProviderSubscription", ["providerSubscriptionId"]).index("byBillingSubscriptionStatus", ["status"]), ye = C(N, {
71
+ id: y({ prefix: "binv" }),
72
+ tenantId: w(),
73
+ provider: w(),
74
+ providerInvoiceId: w(),
75
+ amountMinor: b(),
76
+ currency: w(),
77
+ status: w(),
78
+ statusEventAt: T().nullable(),
79
+ createdAt: T()
80
+ }).index("byBillingInvoiceTenant", ["tenantId"]).index("byBillingProviderInvoice", ["providerInvoiceId"]), be = C(P, {
81
+ id: y({ prefix: "buse" }),
82
+ tenantId: w().maxLength(191),
83
+ entitlementKey: w().maxLength(191),
84
+ period: w().maxLength(16),
85
+ used: b().default(0),
86
+ reportedToProvider: b().default(0),
87
+ updatedAt: T()
87
88
  }).unique("byBillingUsageWindow", [
88
89
  "tenantId",
89
90
  "entitlementKey",
90
91
  "period"
91
- ]), pe = () => [
92
- le,
93
- ue,
94
- de,
95
- fe
96
- ], R = "_voltro_billing_dunning_notices", me = w(R, {
97
- id: b({ prefix: "bdun" }),
98
- tenantId: T().maxLength(191),
99
- episode: T().maxLength(32),
100
- stepId: T().maxLength(64),
101
- sentAt: E()
92
+ ]), xe = () => [
93
+ _e,
94
+ ve,
95
+ ye,
96
+ be
97
+ ], F = "_voltro_billing_dunning_notices", Se = C(F, {
98
+ id: y({ prefix: "bdun" }),
99
+ tenantId: w().maxLength(191),
100
+ episode: w().maxLength(32),
101
+ stepId: w().maxLength(64),
102
+ sentAt: T()
102
103
  }).unique("byBillingDunningNotice", [
103
104
  "tenantId",
104
105
  "episode",
105
106
  "stepId"
106
- ]), he = "locked", ge = [
107
+ ]), I = "locked", Ce = [
107
108
  {
108
109
  id: "payment-failed",
109
110
  afterHours: 0
@@ -116,28 +117,28 @@ var j = (e, t, n, r) => ({
116
117
  id: "final-warning",
117
118
  afterHours: 144
118
119
  }
119
- ], _e = 168, ve = "hard", ye = (e, t, n) => {
120
+ ], we = 168, Te = "hard", Ee = (e, t, n) => {
120
121
  if (e === void 0 || e.trim() === "") return t;
121
122
  let r = Number(e);
122
123
  if (!Number.isFinite(r) || r < 0) throw Error(`billingPlugin: ${n} must be a non-negative number, got '${e}'`);
123
124
  return r;
124
- }, be = (e, t) => {
125
+ }, L = (e, t) => {
125
126
  let n = t.VOLTRO_BILLING_DUNNING;
126
127
  if (n !== void 0 && n !== "" && n !== "on" && n !== "off") throw Error(`billingPlugin: VOLTRO_BILLING_DUNNING must be 'on' or 'off', got '${n}'`);
127
128
  let r = n === "off" ? !1 : n === "on" ? !0 : e?.enabled ?? !0, i = t.VOLTRO_BILLING_LOCKOUT;
128
129
  if (i !== void 0 && i !== "" && i !== "hard" && i !== "soft") throw Error(`billingPlugin: VOLTRO_BILLING_LOCKOUT must be 'hard' or 'soft', got '${i}'`);
129
- let a = i === "hard" || i === "soft" ? i : e?.lockout ?? "hard", o = ye(t.VOLTRO_BILLING_GRACE_HOURS, e?.graceHours ?? 168, "VOLTRO_BILLING_GRACE_HOURS"), s = e?.steps ?? ge, c = t.VOLTRO_BILLING_DUNNING_STEP_HOURS, l = s;
130
+ let a = i === "hard" || i === "soft" ? i : e?.lockout ?? "hard", o = Ee(t.VOLTRO_BILLING_GRACE_HOURS, e?.graceHours ?? 168, "VOLTRO_BILLING_GRACE_HOURS"), s = e?.steps ?? Ce, c = t.VOLTRO_BILLING_DUNNING_STEP_HOURS, l = s;
130
131
  if (c !== void 0 && c.trim() !== "") {
131
132
  let e = c.split(",").map((e) => e.trim());
132
133
  if (e.length !== s.length) throw Error(`billingPlugin: VOLTRO_BILLING_DUNNING_STEP_HOURS lists ${e.length} value(s) but the sequence declares ${s.length} step(s) (${s.map((e) => e.id).join(", ")})`);
133
134
  l = s.map((t, n) => ({
134
135
  id: t.id,
135
- afterHours: ye(e[n], t.afterHours, "VOLTRO_BILLING_DUNNING_STEP_HOURS")
136
+ afterHours: Ee(e[n], t.afterHours, "VOLTRO_BILLING_DUNNING_STEP_HOURS")
136
137
  }));
137
138
  }
138
139
  let u = /* @__PURE__ */ new Set();
139
140
  for (let e of l) {
140
- if (e.id === "locked") throw Error(`billingPlugin: '${he}' is the reserved lockout step id`);
141
+ if (e.id === "locked") throw Error(`billingPlugin: '${I}' is the reserved lockout step id`);
141
142
  if (u.has(e.id)) throw Error(`billingPlugin: duplicate dunning step id '${e.id}'`);
142
143
  u.add(e.id);
143
144
  }
@@ -150,10 +151,10 @@ var j = (e, t, n, r) => ({
150
151
  ...e?.resolveRecipient === void 0 ? {} : { resolveRecipient: e.resolveRecipient },
151
152
  ...e?.portalReturnUrl === void 0 ? {} : { portalReturnUrl: e.portalReturnUrl }
152
153
  };
153
- }, xe = 36e5, Se = (e) => String(e.getTime()), Ce = (e, t) => new Date(e.getTime() + t * xe), we = (e, t, n) => {
154
- let r = (n.getTime() - t.getTime()) / xe;
154
+ }, De = 36e5, Oe = (e) => String(e.getTime()), ke = (e, t) => new Date(e.getTime() + t * De), Ae = (e, t, n) => {
155
+ let r = (n.getTime() - t.getTime()) / De;
155
156
  return e.filter((e) => r >= e.afterHours);
156
- }, z = (e, t, r, i) => {
157
+ }, R = (e, t, r, i) => {
157
158
  let a = {
158
159
  tenantId: e?.tenantId ?? i ?? "",
159
160
  lockout: t.lockout
@@ -199,7 +200,7 @@ var j = (e, t, n, r) => ({
199
200
  graceEndsAt: null,
200
201
  lockedSince: null
201
202
  };
202
- let i = Ce(e.pastDueSince, t.graceHours), o = r.getTime() >= i.getTime();
203
+ let i = ke(e.pastDueSince, t.graceHours), o = r.getTime() >= i.getTime();
203
204
  return {
204
205
  ...a,
205
206
  plan: o && t.lockout === "hard" ? n : e.plan,
@@ -221,29 +222,29 @@ var j = (e, t, n, r) => ({
221
222
  graceEndsAt: null,
222
223
  lockedSince: null
223
224
  };
224
- }, Te = (e) => e.toISOString().slice(0, 10), Ee = (e) => {
225
+ }, je = (e) => e.toISOString().slice(0, 10), Me = (e) => {
225
226
  let t = e.portalUrl, n = t === null ? "<p>Please update your payment method in the billing settings.</p>" : `<p><a href="${t}">Update your payment method</a></p>`, r = t === null ? "Please update your payment method in the billing settings." : `Update your payment method: ${t}`;
226
227
  if (e.locked) return {
227
228
  subject: "Your subscription has been suspended",
228
229
  html: `<p>We were unable to collect payment, and your subscription is now suspended.</p>${n}`,
229
230
  text: `We were unable to collect payment, and your subscription is now suspended.\n\n${r}`
230
231
  };
231
- let i = Te(e.graceEndsAt), a = e.stepId === "payment-failed" ? "Your last payment could not be collected." : "Your payment is still outstanding.";
232
+ let i = je(e.graceEndsAt), a = e.stepId === "payment-failed" ? "Your last payment could not be collected." : "Your payment is still outstanding.";
232
233
  return {
233
234
  subject: "Action needed: your payment could not be collected",
234
235
  html: `<p>${a} Your subscription stays active until ${i}.</p>${n}`,
235
236
  text: `${a} Your subscription stays active until ${i}.\n\n${r}`
236
237
  };
237
- }, De = (e) => (t) => t.to === null ? p.void : e.send({
238
+ }, Ne = (e) => (t) => t.to === null ? p.void : e.send({
238
239
  to: t.to,
239
240
  subject: t.subject,
240
241
  html: t.html,
241
242
  text: t.text
242
- }).pipe(p.asVoid), Oe = (e, t, n) => `${e}\u0000${t}\u0000${n}`, ke = () => {
243
+ }).pipe(p.asVoid), Pe = (e, t, n) => `${e}\u0000${t}\u0000${n}`, Fe = () => {
243
244
  let e = /* @__PURE__ */ new Map();
244
245
  return {
245
246
  claim: (t, n, r, i) => p.sync(() => {
246
- let a = Oe(t, n, r);
247
+ let a = Pe(t, n, r);
247
248
  return !e.has(a) && (e.set(a, {
248
249
  tenantId: t,
249
250
  episode: n,
@@ -253,10 +254,10 @@ var j = (e, t, n, r) => ({
253
254
  }),
254
255
  sentSteps: (t, n) => p.sync(() => [...e.values()].filter((e) => e.tenantId === t && e.episode === n))
255
256
  };
256
- }, Ae = () => `bdun_${Math.random().toString(36).slice(2)}${Date.now().toString(36)}`, je = (t) => ({
257
+ }, Ie = () => `bdun_${Math.random().toString(36).slice(2)}${Date.now().toString(36)}`, Le = (t) => ({
257
258
  claim: (n, r, i, a) => p.tryPromise({
258
259
  try: async () => {
259
- let e = Ae(), o = await t.insertIgnore(R, {
260
+ let e = Ie(), o = await t.insertIgnore(F, {
260
261
  id: e,
261
262
  tenantId: n,
262
263
  episode: r,
@@ -277,7 +278,7 @@ var j = (e, t, n, r) => ({
277
278
  }),
278
279
  sentSteps: (n, r) => p.tryPromise({
279
280
  try: async () => (await t.query({
280
- table: R,
281
+ table: F,
281
282
  predicate: _(v("tenantId", n), v("episode", r)),
282
283
  order: [],
283
284
  take: void 0,
@@ -295,21 +296,21 @@ var j = (e, t, n, r) => ({
295
296
  transient: !0
296
297
  })
297
298
  })
298
- }), B = (e) => `${e}_${Math.random().toString(36).slice(2)}${Date.now().toString(36)}`, V = (t, n) => p.tryPromise({
299
+ }), z = (e) => `${e}_${Math.random().toString(36).slice(2)}${Date.now().toString(36)}`, B = (t, n) => p.tryPromise({
299
300
  try: t,
300
301
  catch: (t) => new e({
301
302
  source: n,
302
303
  message: String(t?.message ?? t),
303
304
  transient: !0
304
305
  })
305
- }), H = (e) => ({
306
+ }), V = (e) => ({
306
307
  table: e.table,
307
308
  predicate: e.predicate,
308
309
  order: e.order ?? [],
309
310
  take: e.take,
310
311
  skip: void 0,
311
312
  projection: void 0
312
- }), Me = () => {
313
+ }), Re = () => {
313
314
  let e = /* @__PURE__ */ new Map();
314
315
  return {
315
316
  upsert: (t) => p.sync(() => {
@@ -317,42 +318,42 @@ var j = (e, t, n, r) => ({
317
318
  }),
318
319
  getByTenant: (t) => p.sync(() => e.get(t) ?? null)
319
320
  };
320
- }, Ne = (e) => ({
321
+ }, ze = (e) => ({
321
322
  tenantId: String(e.tenantId),
322
323
  provider: String(e.provider),
323
324
  providerCustomerId: String(e.providerCustomerId)
324
- }), Pe = (e) => ({
325
- upsert: (t) => V(async () => {
326
- let n = await e.query(H({
327
- table: P,
325
+ }), Be = (e) => ({
326
+ upsert: (t) => B(async () => {
327
+ let n = await e.query(V({
328
+ table: j,
328
329
  predicate: v("tenantId", t.tenantId),
329
330
  take: 1
330
331
  })), r = /* @__PURE__ */ new Date();
331
- n[0] ? await e.update(P, String(n[0].id), {
332
+ n[0] ? await e.update(j, String(n[0].id), {
332
333
  provider: t.provider,
333
334
  providerCustomerId: t.providerCustomerId,
334
335
  updatedAt: r
335
- }) : await e.insert(P, {
336
- id: B("bcust"),
336
+ }) : await e.insert(j, {
337
+ id: z("bcust"),
337
338
  ...t,
338
339
  createdAt: r,
339
340
  updatedAt: r
340
341
  });
341
342
  }, "customerStore"),
342
- getByTenant: (t) => V(async () => {
343
- let n = await e.query(H({
344
- table: P,
343
+ getByTenant: (t) => B(async () => {
344
+ let n = await e.query(V({
345
+ table: j,
345
346
  predicate: v("tenantId", t),
346
347
  take: 1
347
348
  }));
348
- return n[0] ? Ne(n[0]) : null;
349
+ return n[0] ? ze(n[0]) : null;
349
350
  }, "customerStore")
350
- }), U = (e, t) => e === null ? !1 : t === null || t.getTime() < e.getTime(), Fe = () => {
351
+ }), H = (e, t) => e === null ? !1 : t === null || t.getTime() < e.getTime(), Ve = () => {
351
352
  let e = /* @__PURE__ */ new Map();
352
353
  return {
353
354
  upsert: (t) => p.sync(() => {
354
355
  let n = e.get(t.tenantId);
355
- n && U(n.statusEventAt, t.statusEventAt) || e.set(t.tenantId, {
356
+ n && H(n.statusEventAt, t.statusEventAt) || e.set(t.tenantId, {
356
357
  ...t,
357
358
  pastDueSince: n ? n.pastDueSince : t.pastDueSince
358
359
  });
@@ -379,7 +380,7 @@ var j = (e, t, n, r) => ({
379
380
  });
380
381
  })
381
382
  };
382
- }, Ie = (e) => ({
383
+ }, He = (e) => ({
383
384
  tenantId: String(e.tenantId),
384
385
  provider: String(e.provider),
385
386
  providerSubscriptionId: String(e.providerSubscriptionId),
@@ -391,16 +392,16 @@ var j = (e, t, n, r) => ({
391
392
  cancelAt: e.cancelAt == null ? null : new Date(e.cancelAt),
392
393
  pastDueSince: e.pastDueSince == null ? null : new Date(e.pastDueSince),
393
394
  statusEventAt: e.statusEventAt == null ? null : new Date(e.statusEventAt)
394
- }), Le = async (e, t) => (await e.query(H({
395
+ }), Ue = async (e, t) => (await e.query(V({
395
396
  table: "_voltro_billing_subscriptions",
396
397
  predicate: v("providerSubscriptionId", t),
397
398
  take: 1
398
- })))[0] ?? null, Re = (e) => ({
399
- upsert: (t) => V(async () => {
400
- let n = await Le(e, t.providerSubscriptionId), r = /* @__PURE__ */ new Date();
399
+ })))[0] ?? null, We = (e) => ({
400
+ upsert: (t) => B(async () => {
401
+ let n = await Ue(e, t.providerSubscriptionId), r = /* @__PURE__ */ new Date();
401
402
  if (n) {
402
- if (U(n.statusEventAt == null ? null : new Date(n.statusEventAt), t.statusEventAt)) return;
403
- await e.update(F, String(n.id), {
403
+ if (H(n.statusEventAt == null ? null : new Date(n.statusEventAt), t.statusEventAt)) return;
404
+ await e.update(M, String(n.id), {
404
405
  tenantId: t.tenantId,
405
406
  provider: t.provider,
406
407
  plan: t.plan,
@@ -412,8 +413,8 @@ var j = (e, t, n, r) => ({
412
413
  statusEventAt: t.statusEventAt,
413
414
  updatedAt: r
414
415
  });
415
- } else await e.insert(F, {
416
- id: B("bsub"),
416
+ } else await e.insert(M, {
417
+ id: z("bsub"),
417
418
  tenantId: t.tenantId,
418
419
  provider: t.provider,
419
420
  providerSubscriptionId: t.providerSubscriptionId,
@@ -429,9 +430,9 @@ var j = (e, t, n, r) => ({
429
430
  updatedAt: r
430
431
  });
431
432
  }, "subscriptionStore"),
432
- getByTenant: (t) => V(async () => {
433
- let n = await e.query(H({
434
- table: F,
433
+ getByTenant: (t) => B(async () => {
434
+ let n = await e.query(V({
435
+ table: M,
435
436
  predicate: v("tenantId", t),
436
437
  order: [{
437
438
  column: "updatedAt",
@@ -439,26 +440,26 @@ var j = (e, t, n, r) => ({
439
440
  }],
440
441
  take: 1
441
442
  }));
442
- return n[0] ? Ie(n[0]) : null;
443
+ return n[0] ? He(n[0]) : null;
443
444
  }, "subscriptionStore"),
444
- listByStatus: (t) => V(async () => (await e.query(H({
445
- table: F,
445
+ listByStatus: (t) => B(async () => (await e.query(V({
446
+ table: M,
446
447
  predicate: v("status", t),
447
448
  order: [{
448
449
  column: "updatedAt",
449
450
  direction: "asc"
450
451
  }]
451
- }))).map(Ie), "subscriptionStore"),
452
- markCanceled: (t) => V(async () => {
453
- let n = await Le(e, t);
454
- n && await e.update(F, String(n.id), {
452
+ }))).map(He), "subscriptionStore"),
453
+ markCanceled: (t) => B(async () => {
454
+ let n = await Ue(e, t);
455
+ n && await e.update(M, String(n.id), {
455
456
  status: "canceled",
456
457
  updatedAt: /* @__PURE__ */ new Date()
457
458
  });
458
459
  }, "subscriptionStore"),
459
- patchByTenant: (t, n) => V(async () => {
460
- let r = (await e.query(H({
461
- table: F,
460
+ patchByTenant: (t, n) => B(async () => {
461
+ let r = (await e.query(V({
462
+ table: M,
462
463
  predicate: v("tenantId", t),
463
464
  order: [{
464
465
  column: "updatedAt",
@@ -466,7 +467,7 @@ var j = (e, t, n, r) => ({
466
467
  }],
467
468
  take: 1
468
469
  })))[0];
469
- r && await e.update(F, String(r.id), {
470
+ r && await e.update(M, String(r.id), {
470
471
  ...n.plan === void 0 ? {} : { plan: n.plan },
471
472
  ...n.quantity === void 0 ? {} : { quantity: n.quantity },
472
473
  ...n.status === void 0 ? {} : { status: n.status },
@@ -477,23 +478,23 @@ var j = (e, t, n, r) => ({
477
478
  updatedAt: /* @__PURE__ */ new Date()
478
479
  });
479
480
  }, "subscriptionStore"),
480
- setStatus: (t, n) => V(async () => {
481
- let r = await Le(e, t);
482
- r && await e.update(F, String(r.id), {
481
+ setStatus: (t, n) => B(async () => {
482
+ let r = await Ue(e, t);
483
+ r && await e.update(M, String(r.id), {
483
484
  status: n,
484
485
  updatedAt: /* @__PURE__ */ new Date()
485
486
  });
486
487
  }, "subscriptionStore")
487
- }), ze = () => {
488
+ }), Ge = () => {
488
489
  let e = /* @__PURE__ */ new Map();
489
490
  return {
490
491
  upsert: (t) => p.sync(() => {
491
492
  let n = e.get(t.providerInvoiceId);
492
- n && U(n.statusEventAt, t.statusEventAt) || e.set(t.providerInvoiceId, t);
493
+ n && H(n.statusEventAt, t.statusEventAt) || e.set(t.providerInvoiceId, t);
493
494
  }),
494
495
  listByTenant: (t) => p.sync(() => [...e.values()].filter((e) => e.tenantId === t))
495
496
  };
496
- }, Be = (e) => ({
497
+ }, Ke = (e) => ({
497
498
  tenantId: String(e.tenantId),
498
499
  provider: String(e.provider),
499
500
  providerInvoiceId: String(e.providerInvoiceId),
@@ -501,41 +502,41 @@ var j = (e, t, n, r) => ({
501
502
  currency: String(e.currency),
502
503
  status: String(e.status),
503
504
  statusEventAt: e.statusEventAt == null ? null : new Date(e.statusEventAt)
504
- }), Ve = (e) => ({
505
- upsert: (t) => V(async () => {
506
- let n = (await e.query(H({
507
- table: I,
505
+ }), qe = (e) => ({
506
+ upsert: (t) => B(async () => {
507
+ let n = (await e.query(V({
508
+ table: N,
508
509
  predicate: v("providerInvoiceId", t.providerInvoiceId),
509
510
  take: 1
510
511
  })))[0];
511
512
  if (n) {
512
- if (U(n.statusEventAt == null ? null : new Date(n.statusEventAt), t.statusEventAt)) return;
513
- await e.update(I, String(n.id), {
513
+ if (H(n.statusEventAt == null ? null : new Date(n.statusEventAt), t.statusEventAt)) return;
514
+ await e.update(N, String(n.id), {
514
515
  amountMinor: t.amountMinor,
515
516
  currency: t.currency,
516
517
  status: t.status,
517
518
  statusEventAt: t.statusEventAt
518
519
  });
519
- } else await e.insert(I, {
520
- id: B("binv"),
520
+ } else await e.insert(N, {
521
+ id: z("binv"),
521
522
  ...t,
522
523
  createdAt: /* @__PURE__ */ new Date()
523
524
  });
524
525
  }, "invoiceStore"),
525
- listByTenant: (t) => V(async () => (await e.query(H({
526
- table: I,
526
+ listByTenant: (t) => B(async () => (await e.query(V({
527
+ table: N,
527
528
  predicate: v("tenantId", t),
528
529
  order: [{
529
530
  column: "createdAt",
530
531
  direction: "desc"
531
532
  }]
532
- }))).map(Be), "invoiceStore")
533
- }), W = (e, t, n) => `${e}\u0000${t}\u0000${n}`, He = () => {
533
+ }))).map(Ke), "invoiceStore")
534
+ }), U = (e, t, n) => `${e}\u0000${t}\u0000${n}`, Je = () => {
534
535
  let e = /* @__PURE__ */ new Map();
535
536
  return {
536
- used: (t, n, r) => p.sync(() => e.get(W(t, n, r))?.used ?? 0),
537
+ used: (t, n, r) => p.sync(() => e.get(U(t, n, r))?.used ?? 0),
537
538
  consume: (t, n, r, i, a) => p.sync(() => {
538
- let o = W(t, n, r), s = e.get(o), c = s?.used ?? 0, l = c + i <= a;
539
+ let o = U(t, n, r), s = e.get(o), c = s?.used ?? 0, l = c + i <= a;
539
540
  return l && e.set(o, {
540
541
  tenantId: t,
541
542
  entitlementKey: n,
@@ -551,7 +552,7 @@ var j = (e, t, n, r) => ({
551
552
  };
552
553
  }),
553
554
  increment: (t, n, r, i) => p.sync(() => {
554
- let a = W(t, n, r), o = e.get(a), s = (o?.used ?? 0) + i;
555
+ let a = U(t, n, r), o = e.get(a), s = (o?.used ?? 0) + i;
555
556
  return e.set(a, {
556
557
  tenantId: t,
557
558
  entitlementKey: n,
@@ -562,32 +563,32 @@ var j = (e, t, n, r) => ({
562
563
  }),
563
564
  pending: () => p.sync(() => [...e.values()].filter((e) => e.used > e.reportedToProvider)),
564
565
  markReported: (t, n, r, i) => p.sync(() => {
565
- let a = W(t, n, r), o = e.get(a);
566
+ let a = U(t, n, r), o = e.get(a);
566
567
  o && e.set(a, {
567
568
  ...o,
568
569
  reportedToProvider: i
569
570
  });
570
571
  })
571
572
  };
572
- }, Ue = (e) => ({
573
+ }, Ye = (e) => ({
573
574
  tenantId: String(e.tenantId),
574
575
  entitlementKey: String(e.entitlementKey),
575
576
  period: String(e.period),
576
577
  used: Number(e.used ?? 0),
577
578
  reportedToProvider: Number(e.reportedToProvider ?? 0)
578
- }), G = async (e, t, n, r) => (await e.query(H({
579
+ }), W = async (e, t, n, r) => (await e.query(V({
579
580
  table: "_voltro_billing_usage",
580
581
  predicate: _(v("tenantId", t), v("entitlementKey", n), v("period", r)),
581
582
  take: 1
582
- })))[0] ?? null, We = (e) => ({
583
- used: (t, n, r) => V(async () => {
584
- let i = await G(e, t, n, r);
583
+ })))[0] ?? null, Xe = (e) => ({
584
+ used: (t, n, r) => B(async () => {
585
+ let i = await W(e, t, n, r);
585
586
  return i ? Number(i.used ?? 0) : 0;
586
587
  }, "usageStore"),
587
- consume: (t, n, r, i, a) => V(async () => {
588
+ consume: (t, n, r, i, a) => B(async () => {
588
589
  for (let o = 0; o < 32; o++) {
589
590
  o > 0 && await new Promise((e) => setTimeout(e, o));
590
- let s = await G(e, t, n, r), c = s ? Number(s.used ?? 0) : 0;
591
+ let s = await W(e, t, n, r), c = s ? Number(s.used ?? 0) : 0;
591
592
  if (c + i > a) return {
592
593
  allowed: !1,
593
594
  entitlement: n,
@@ -607,7 +608,7 @@ var j = (e, t, n, r) => ({
607
608
  cost: i
608
609
  };
609
610
  } else {
610
- let o = B("buse"), s = await e.insertIgnore(L, {
611
+ let o = z("buse"), s = await e.insertIgnore(P, {
611
612
  id: o,
612
613
  tenantId: t,
613
614
  entitlementKey: n,
@@ -631,10 +632,10 @@ var j = (e, t, n, r) => ({
631
632
  }
632
633
  throw Error(`billing usage consume: contention on (${t}, ${n}, ${r}) exceeded 32 attempts`);
633
634
  }, "usageStore"),
634
- increment: (t, n, r, i) => V(async () => {
635
+ increment: (t, n, r, i) => B(async () => {
635
636
  for (let a = 0; a < 32; a++) {
636
637
  a > 0 && await new Promise((e) => setTimeout(e, a));
637
- let o = await G(e, t, n, r);
638
+ let o = await W(e, t, n, r);
638
639
  if (o) {
639
640
  let t = Number(o.used ?? 0);
640
641
  if (await e.updateMany("_voltro_billing_usage", {
@@ -642,7 +643,7 @@ var j = (e, t, n, r) => ({
642
643
  updatedAt: /* @__PURE__ */ new Date()
643
644
  }, { where: _(v("id", String(o.id)), v("used", t)) }) === 1) return t + i;
644
645
  } else {
645
- let a = B("buse"), o = await e.insertIgnore(L, {
646
+ let a = z("buse"), o = await e.insertIgnore(P, {
646
647
  id: a,
647
648
  tenantId: t,
648
649
  entitlementKey: n,
@@ -660,31 +661,31 @@ var j = (e, t, n, r) => ({
660
661
  }
661
662
  throw Error(`billing usage increment: contention on (${t}, ${n}, ${r}) exceeded 32 attempts`);
662
663
  }, "usageStore"),
663
- pending: () => V(async () => (await e.query(H({ table: L }))).map(Ue).filter((e) => e.used > e.reportedToProvider), "usageStore"),
664
- markReported: (t, n, r, i) => V(async () => {
665
- let a = await G(e, t, n, r);
666
- a && await e.update(L, String(a.id), {
664
+ pending: () => B(async () => (await e.query(V({ table: P }))).map(Ye).filter((e) => e.used > e.reportedToProvider), "usageStore"),
665
+ markReported: (t, n, r, i) => B(async () => {
666
+ let a = await W(e, t, n, r);
667
+ a && await e.update(P, String(a.id), {
667
668
  reportedToProvider: i,
668
669
  updatedAt: /* @__PURE__ */ new Date()
669
670
  });
670
671
  }, "usageStore")
671
- }), Ge = () => ({
672
- customers: Me(),
673
- subscriptions: Fe(),
674
- invoices: ze(),
675
- usage: He(),
676
- dunningNotices: ke()
677
- }), Ke = (e) => ({
678
- customers: Pe(e),
679
- subscriptions: Re(e),
680
- invoices: Ve(e),
681
- usage: We(e),
682
- dunningNotices: je(e)
683
- }), K = D({ scope: "@voltro/plugin-billing" }), q = (e = /* @__PURE__ */ new Date()) => `${e.getUTCFullYear()}-${String(e.getUTCMonth() + 1).padStart(2, "0")}`, qe = (e) => ({ stores: e ?? Ge() }), J = (e, t) => e.pipe(p.retry({
672
+ }), Ze = () => ({
673
+ customers: Re(),
674
+ subscriptions: Ve(),
675
+ invoices: Ge(),
676
+ usage: Je(),
677
+ dunningNotices: Fe()
678
+ }), Qe = (e) => ({
679
+ customers: Be(e),
680
+ subscriptions: We(e),
681
+ invoices: qe(e),
682
+ usage: Xe(e),
683
+ dunningNotices: Le(e)
684
+ }), G = E({ scope: "@voltro/plugin-billing" }), K = (e = /* @__PURE__ */ new Date()) => `${e.getUTCFullYear()}-${String(e.getUTCMonth() + 1).padStart(2, "0")}`, $e = (e) => ({ stores: e ?? Ze() }), q = (e, t) => e.pipe(p.retry({
684
685
  schedule: h.recurs(Math.max(0, t - 1)),
685
686
  while: (e) => e.transient
686
- })), Je = (t) => {
687
- let { provider: n, plans: i } = t, a = t.attempts ?? 3, o = t.checkout, s = t.now ?? (() => /* @__PURE__ */ new Date()), c = qe(t.stores), l = t.dunning ?? be(void 0, {}), u = (e) => c.stores.subscriptions.getByTenant(e).pipe(p.map((t) => z(t, l, s(), e))), d = (e) => u(e).pipe(p.map((e) => e.plan)), f = (e) => c.stores.subscriptions.getByTenant(e), ee = (e, n) => p.gen(function* () {
687
+ })), et = (t) => {
688
+ let { provider: n, plans: i } = t, a = t.attempts ?? 3, o = t.checkout, s = t.now ?? (() => /* @__PURE__ */ new Date()), c = $e(t.stores), l = t.dunning ?? L(void 0, {}), u = (e) => c.stores.subscriptions.getByTenant(e).pipe(p.map((t) => R(t, l, s(), e))), d = (e) => u(e).pipe(p.map((e) => e.plan)), f = (e) => c.stores.subscriptions.getByTenant(e), ee = (e, n) => p.gen(function* () {
688
689
  if (t.resolveEntitlementLimit !== void 0) {
689
690
  let r = yield* t.resolveEntitlementLimit(e, n);
690
691
  if (r !== null) return r;
@@ -692,29 +693,29 @@ var j = (e, t, n, r) => ({
692
693
  let r = yield* d(e);
693
694
  return i.entitlementLimit(r, n);
694
695
  }), te = (e, t, n) => p.gen(function* () {
695
- return j(t, yield* ee(e, t), yield* c.stores.usage.used(e, t, q(s())), n);
696
+ return k(t, yield* ee(e, t), yield* c.stores.usage.used(e, t, K(s())), n);
696
697
  }), m = (e, t, n) => p.gen(function* () {
697
698
  let i = yield* ee(e, t);
698
699
  if (!Number.isFinite(i) || n <= 0) return;
699
- let a = q(s()), o = yield* c.stores.usage.consume(e, t, a, n, i);
700
+ let a = K(s()), o = yield* c.stores.usage.consume(e, t, a, n, i);
700
701
  if (!o.allowed) return yield* p.fail(new r({
701
702
  entitlement: t,
702
703
  limit: o.limit,
703
704
  used: o.used,
704
705
  cost: n
705
706
  }));
706
- }), h = (e, t, n) => n <= 0 ? p.void : c.stores.usage.increment(e, t, q(s()), n).pipe(p.asVoid), ne = () => p.gen(function* () {
707
+ }), h = (e, t, n) => n <= 0 ? p.void : c.stores.usage.increment(e, t, K(s()), n).pipe(p.asVoid), ne = () => p.gen(function* () {
707
708
  if (!n.supportsMeteredUsage) return;
708
709
  let e = yield* c.stores.usage.pending();
709
710
  for (let t of e) {
710
711
  let e = t.used - t.reportedToProvider;
711
- e <= 0 || (yield* J(n.reportUsage({
712
+ e <= 0 || (yield* q(n.reportUsage({
712
713
  tenantId: t.tenantId,
713
714
  entitlementKey: t.entitlementKey,
714
715
  quantity: e
715
716
  }), a), yield* c.stores.usage.markReported(t.tenantId, t.entitlementKey, t.period, t.used));
716
717
  }
717
- }), g = (t) => p.gen(function* () {
718
+ }), re = (t) => p.gen(function* () {
718
719
  let r = i.priceIdFor(t.plan);
719
720
  if (r === null) return yield* p.fail(new e({
720
721
  source: "billing",
@@ -722,7 +723,7 @@ var j = (e, t, n, r) => ({
722
723
  transient: !1
723
724
  }));
724
725
  let s = yield* c.stores.customers.getByTenant(t.tenantId);
725
- return yield* J(n.createCheckoutSession({
726
+ return yield* q(n.createCheckoutSession({
726
727
  tenantId: t.tenantId,
727
728
  priceId: r,
728
729
  successUrl: t.successUrl,
@@ -732,18 +733,18 @@ var j = (e, t, n, r) => ({
732
733
  ...o?.adjustableQuantity === void 0 ? {} : { adjustableQuantity: o.adjustableQuantity },
733
734
  ...o?.trialDays === void 0 ? {} : { trialDays: o.trialDays }
734
735
  }), a);
735
- }), re = (t, r) => p.gen(function* () {
736
+ }), ie = (t, r) => p.gen(function* () {
736
737
  let i = yield* c.stores.customers.getByTenant(t);
737
738
  return i === null ? yield* p.fail(new e({
738
739
  source: "billing",
739
740
  message: `no provider customer linked for tenant '${t}'`,
740
741
  transient: !1
741
- })) : yield* J(n.createPortalSession({
742
+ })) : yield* q(n.createPortalSession({
742
743
  tenantId: t,
743
744
  providerCustomerId: i.providerCustomerId,
744
745
  returnUrl: r
745
746
  }), a);
746
- }), ie = (e) => p.gen(function* () {
747
+ }), ae = (e) => p.gen(function* () {
747
748
  if (l.resolveRecipient !== void 0) {
748
749
  let t = yield* l.resolveRecipient(e);
749
750
  if (t !== null) return t;
@@ -751,11 +752,11 @@ var j = (e, t, n, r) => ({
751
752
  if (n.customerEmail === void 0) return null;
752
753
  let t = yield* c.stores.customers.getByTenant(e);
753
754
  return t === null ? null : yield* n.customerEmail(t.providerCustomerId);
754
- }), ae = (e) => {
755
+ }), oe = (e) => {
755
756
  let t = l.portalReturnUrl;
756
- return t === void 0 ? p.succeed(null) : re(e, t).pipe(p.map((e) => e.url), p.catchAll(() => p.succeed(null)));
757
- }, _ = (e, t, n, r, i) => p.gen(function* () {
758
- let a = yield* ie(e.tenantId).pipe(p.catchAll(() => p.succeed(null))), o = yield* ae(e.tenantId), s = t.lockedSince !== null, c = Ee({
757
+ return t === void 0 ? p.succeed(null) : ie(e, t).pipe(p.map((e) => e.url), p.catchAll(() => p.succeed(null)));
758
+ }, g = (e, t, n, r, i) => p.gen(function* () {
759
+ let a = yield* ae(e.tenantId).pipe(p.catchAll(() => p.succeed(null))), o = yield* oe(e.tenantId), s = t.lockedSince !== null, c = Me({
759
760
  stepId: n,
760
761
  locked: s,
761
762
  graceEndsAt: i,
@@ -773,7 +774,7 @@ var j = (e, t, n, r) => ({
773
774
  portalUrl: o,
774
775
  ...c
775
776
  };
776
- K.info("billing dunning notice", {
777
+ G.info("billing dunning notice", {
777
778
  tenant: e.tenantId,
778
779
  step: n,
779
780
  locked: s,
@@ -782,16 +783,16 @@ var j = (e, t, n, r) => ({
782
783
  });
783
784
  let d = l.notify;
784
785
  d !== void 0 && (yield* d(u).pipe(p.catchAllCause((t) => p.sync(() => {
785
- K.warn("billing dunning notify failed", {
786
+ G.warn("billing dunning notify failed", {
786
787
  tenant: e.tenantId,
787
788
  step: n,
788
789
  cause: String(t)
789
790
  });
790
791
  }))));
791
- }), v = (e) => p.gen(function* () {
792
+ }), _ = (e) => p.gen(function* () {
792
793
  let t = yield* c.stores.subscriptions.getByTenant(e);
793
- if (t === null) return z(null, l, s(), e);
794
- let r = yield* n.fetchSubscription(t.providerSubscriptionId).pipe(p.catchAll((t) => p.sync(() => (K.warn("billing dunning reconcile: provider unreachable, not escalating", {
794
+ if (t === null) return R(null, l, s(), e);
795
+ let r = yield* n.fetchSubscription(t.providerSubscriptionId).pipe(p.catchAll((t) => p.sync(() => (G.warn("billing dunning reconcile: provider unreachable, not escalating", {
795
796
  tenant: e,
796
797
  source: t.source,
797
798
  message: t.message
@@ -817,28 +818,28 @@ var j = (e, t, n, r) => ({
817
818
  statusEventAt: n
818
819
  };
819
820
  }
820
- let a = z(i, l, s(), e);
821
+ let a = R(i, l, s(), e);
821
822
  if (!l.enabled || i.status !== "pastDue" || i.pastDueSince === null) return a;
822
- let o = i.pastDueSince, u = Se(o), d = a.graceEndsAt ?? o, f = we(l.steps, o, s()).map((e) => e.id);
823
- a.lockedSince !== null && f.push(he);
824
- for (let t of f) (yield* c.stores.dunningNotices.claim(e, u, t, s())) && (yield* _(i, a, t, o, d));
823
+ let o = i.pastDueSince, u = Oe(o), d = a.graceEndsAt ?? o, f = Ae(l.steps, o, s()).map((e) => e.id);
824
+ a.lockedSince !== null && f.push(I);
825
+ for (let t of f) (yield* c.stores.dunningNotices.claim(e, u, t, s())) && (yield* g(i, a, t, o, d));
825
826
  return a;
826
- }), y = () => p.gen(function* () {
827
+ }), se = () => p.gen(function* () {
827
828
  let e = yield* c.stores.subscriptions.listByStatus("pastDue"), t = 0;
828
- for (let n of e) yield* v(n.tenantId).pipe(p.catchAll((e) => p.sync(() => {
829
- K.warn("billing dunning sweep: tenant failed", {
829
+ for (let n of e) yield* _(n.tenantId).pipe(p.catchAll((e) => p.sync(() => {
830
+ G.warn("billing dunning sweep: tenant failed", {
830
831
  tenant: n.tenantId,
831
832
  message: e.message
832
833
  });
833
834
  }))), t += 1;
834
835
  return t;
835
- }), b = (e) => {
836
+ }), ce = (e) => {
836
837
  if (!l.enabled) return p.void;
837
- if (e._tag === "invoicePaymentFailed") return v(e.tenantId).pipe(p.asVoid);
838
+ if (e._tag === "invoicePaymentFailed") return _(e.tenantId).pipe(p.asVoid);
838
839
  if (e._tag !== "invoicePaid" && e._tag !== "subscriptionUpserted") return p.void;
839
840
  let t = e.tenantId;
840
- return c.stores.subscriptions.getByTenant(t).pipe(p.flatMap((e) => e !== null && (e.status === "pastDue" || e.pastDueSince !== null) ? v(t).pipe(p.asVoid) : p.void));
841
- }, x = (e) => {
841
+ return c.stores.subscriptions.getByTenant(t).pipe(p.flatMap((e) => e !== null && (e.status === "pastDue" || e.pastDueSince !== null) ? _(t).pipe(p.asVoid) : p.void));
842
+ }, v = (e) => {
842
843
  switch (e._tag) {
843
844
  case "subscriptionUpserted": return c.stores.subscriptions.upsert({
844
845
  tenantId: e.tenantId,
@@ -878,7 +879,7 @@ var j = (e, t, n, r) => ({
878
879
  providerCustomerId: e.providerCustomerId
879
880
  });
880
881
  }
881
- }, S = (e) => x(e).pipe(p.zipRight(b(e))), C = (t, r) => p.gen(function* () {
882
+ }, le = (e) => v(e).pipe(p.zipRight(ce(e))), y = (t, r) => p.gen(function* () {
882
883
  let o = yield* c.stores.subscriptions.getByTenant(t);
883
884
  if (o === null) return yield* p.fail(new e({
884
885
  source: "billing",
@@ -896,7 +897,7 @@ var j = (e, t, n, r) => ({
896
897
  message: `seat quantity must be a positive integer, got ${l}`,
897
898
  transient: !1
898
899
  }));
899
- let u = yield* J(n.updateSubscription({
900
+ let u = yield* q(n.updateSubscription({
900
901
  providerSubscriptionId: o.providerSubscriptionId,
901
902
  ...r.plan === void 0 ? {} : { priceId: i.priceIdFor(s) ?? s },
902
903
  ...r.quantity === void 0 ? {} : { quantity: l },
@@ -920,17 +921,17 @@ var j = (e, t, n, r) => ({
920
921
  subscription: f,
921
922
  plan: d,
922
923
  entitlementStatus: u,
923
- reconcileDunning: v,
924
- dunningSweep: y,
924
+ reconcileDunning: _,
925
+ dunningSweep: se,
925
926
  checkEntitlement: te,
926
927
  consumeEntitlement: m,
927
928
  reportUsage: h,
928
929
  flushUsage: ne,
929
- startCheckout: g,
930
- portalUrl: re,
931
- applyEvent: S,
932
- changePlan: (e, t) => C(e, { plan: t }),
933
- changeSeats: (e, t) => C(e, { quantity: t }),
930
+ startCheckout: re,
931
+ portalUrl: ie,
932
+ applyEvent: le,
933
+ changePlan: (e, t) => y(e, { plan: t }),
934
+ changeSeats: (e, t) => y(e, { quantity: t }),
934
935
  previewChange: (t, r) => p.gen(function* () {
935
936
  let o = yield* c.stores.subscriptions.getByTenant(t);
936
937
  if (o === null) return yield* p.fail(new e({
@@ -938,7 +939,7 @@ var j = (e, t, n, r) => ({
938
939
  message: `no subscription for tenant '${t}' to preview`,
939
940
  transient: !1
940
941
  }));
941
- let s = r.plan ?? o.plan, l = yield* J(n.previewSubscriptionChange({
942
+ let s = r.plan ?? o.plan, l = yield* q(n.previewSubscriptionChange({
942
943
  providerSubscriptionId: o.providerSubscriptionId,
943
944
  ...r.plan === void 0 ? {} : { priceId: i.priceIdFor(s) ?? s },
944
945
  ...r.quantity === void 0 ? {} : { quantity: r.quantity },
@@ -954,12 +955,12 @@ var j = (e, t, n, r) => ({
954
955
  }),
955
956
  invoices: (e) => p.gen(function* () {
956
957
  let t = yield* c.stores.customers.getByTenant(e);
957
- return t === null ? [] : yield* J(n.listInvoices({ providerCustomerId: t.providerCustomerId }), a);
958
+ return t === null ? [] : yield* q(n.listInvoices({ providerCustomerId: t.providerCustomerId }), a);
958
959
  })
959
960
  },
960
961
  holder: c
961
962
  };
962
- }, Ye = (e) => m.succeed(t, e), Xe = "_voltro_ai_usage", Ze = (e) => {
963
+ }, tt = (e) => m.succeed(t, e), nt = "_voltro_ai_usage", rt = (e) => {
963
964
  for (let [t, n] of Object.entries(e)) {
964
965
  if (t.length === 0) throw Error("billing metering: a meter key must be non-empty");
965
966
  if (n.from === "rpc") {
@@ -968,28 +969,44 @@ var j = (e, t, n, r) => ({
968
969
  if (typeof n.table != "string" || n.table.length === 0) throw Error(`billing metering: cdc meter '${t}' needs a 'table'`);
969
970
  } else if (n.from !== "ai") throw Error(`billing metering: meter '${t}' has unknown source '${String(n.from)}'`);
970
971
  }
971
- }, Qe = /* @__PURE__ */ new WeakMap(), $e = (e) => {
972
+ }, it = /* @__PURE__ */ new WeakMap(), at = (e) => {
972
973
  if (!e.global && !e.sticky) return e;
973
- let t = Qe.get(e);
974
- return t === void 0 && (t = new RegExp(e.source, e.flags.replace(/[gy]/g, "")), Qe.set(e, t)), t;
975
- }, et = (e, t) => typeof e == "string" ? t === e : $e(e).test(t), tt = (e, t, n) => Object.entries(e).filter(([, e]) => e.from === "rpc" && (e.kind === void 0 || e.kind === n) && et(e.match, t)).map(([e]) => e), nt = (e, t, n) => Object.entries(e).filter(([, e]) => e.from === "cdc" && e.table === t && (e.op ?? "insert") === n).map(([e]) => e), rt = (e) => Object.entries(e).filter(([, e]) => e.from === "ai").map(([e, t]) => [e, t.metric ?? "tokens"]), it = (e) => e.tenantId, at = (e, t, n, r) => p.forEach(n, (n) => e.reportUsage(t, n, r).pipe(p.catchAll(() => p.void)), { discard: !0 }), ot = (e, t) => (n, r) => {
976
- let i = tt(t, r.tag, r.kind);
974
+ let t = it.get(e);
975
+ return t === void 0 && (t = new RegExp(e.source, e.flags.replace(/[gy]/g, "")), it.set(e, t)), t;
976
+ }, ot = (e, t) => typeof e == "string" ? t === e : at(e).test(t), st = (e, t, n) => Object.entries(e).filter(([, e]) => e.from === "rpc" && (e.kind === void 0 || e.kind === n) && ot(e.match, t)).map(([e]) => e), ct = (e, t, n) => Object.entries(e).filter(([, e]) => e.from === "cdc" && e.table === t && (e.op ?? "insert") === n).map(([e]) => e), lt = (e) => Object.entries(e).filter(([, e]) => e.from === "ai").map(([e, t]) => [e, t.metric ?? "tokens"]), ut = (e) => e.tenantId, dt = (e, t, n, r) => p.forEach(n, (n) => e.reportUsage(t, n, r).pipe(p.catchAll(() => p.void)), { discard: !0 }), ft = (e, t) => (n, r) => {
977
+ let i = st(t, r.tag, r.kind);
977
978
  if (i.length === 0) return n;
978
- let a = it(r.subject);
979
- return a === null ? n : n.pipe(p.tap(() => at(e, a, i, 1)));
980
- }, st = (e, t) => (n) => {
981
- let r = nt(t, n.table, n.op);
982
- if (r.length === 0) return p.void;
983
- let i = n.new?.tenantId ?? n.old?.tenantId ?? null;
984
- return i === null ? p.void : at(e, i, r, 1);
985
- }, ct = (e) => new Date(Date.UTC(e.getUTCFullYear(), e.getUTCMonth(), 1, 0, 0, 0, 0)), lt = (e, t, n, r = () => /* @__PURE__ */ new Date()) => p.gen(function* () {
986
- let i = rt(n);
979
+ let a = ut(r.subject);
980
+ return a === null ? n : n.pipe(p.tap(() => dt(e, a, i, 1)));
981
+ }, pt = "billing-meter", mt = 5e4, ht = (e, t, n = {}) => {
982
+ let r = new g({
983
+ windowMs: ue(),
984
+ maxEntries: mt
985
+ }), i = n.now ?? (() => Date.now()), a = !1;
986
+ return (o) => {
987
+ let s = ct(t, o.table, o.op);
988
+ if (s.length === 0) return p.void;
989
+ let c = o.new?.tenantId ?? o.old?.tenantId ?? null;
990
+ if (c === null) return p.void;
991
+ let l = n.claimChange?.();
992
+ if (l === void 0) return a || (a = !0, n.onUngated?.()), dt(e, c, s, 1);
993
+ let u = String(o.new?.id ?? o.old?.id ?? ""), d = se({
994
+ pipe: pt,
995
+ op: o.op,
996
+ key: u,
997
+ next: o.new ?? null,
998
+ prev: o.old ?? null
999
+ }), f = ce(d, r.next(d, i()));
1000
+ return p.promise(() => l(pt, f)).pipe(p.flatMap((t) => t ? dt(e, c, s, 1) : p.void));
1001
+ };
1002
+ }, gt = (e) => new Date(Date.UTC(e.getUTCFullYear(), e.getUTCMonth(), 1, 0, 0, 0, 0)), _t = (e, t, n, r = () => /* @__PURE__ */ new Date()) => p.gen(function* () {
1003
+ let i = lt(n);
987
1004
  if (i.length === 0) return;
988
1005
  let a = r();
989
- q(a);
1006
+ K(a);
990
1007
  let o = {
991
- table: Xe,
992
- predicate: y("calledAt", ct(a)),
1008
+ table: nt,
1009
+ predicate: le("calledAt", gt(a)),
993
1010
  order: [],
994
1011
  take: void 0,
995
1012
  skip: void 0,
@@ -1010,14 +1027,14 @@ var j = (e, t, n, r) => ({
1010
1027
  let o = a - (yield* e.checkEntitlement(r, t, 0).pipe(p.map((e) => e.used), p.catchAll(() => p.succeed(0))));
1011
1028
  o > 0 && (yield* e.reportUsage(r, t, o).pipe(p.catchAll(() => p.void)));
1012
1029
  }
1013
- }), ut = (e, t, n, r) => lt(e, t, n, r).pipe(p.andThen(e.flushUsage().pipe(p.catchAll(() => p.void)))), dt = (e) => Object.values(e).some((e) => e.from === "cdc"), ft = (e) => e === void 0 ? 0 : e === "unlimited" ? Infinity : e, pt = (e) => {
1030
+ }), vt = (e, t, n, r) => _t(e, t, n, r).pipe(p.andThen(e.flushUsage().pipe(p.catchAll(() => p.void)))), yt = (e) => Object.values(e).some((e) => e.from === "cdc"), bt = (e) => e === void 0 ? 0 : e === "unlimited" ? Infinity : e, xt = (e) => {
1014
1031
  let t = /* @__PURE__ */ new Map();
1015
1032
  for (let [n, r] of Object.entries(e)) r.priceId !== void 0 && t.set(r.priceId, n);
1016
1033
  return {
1017
1034
  has: (t) => Object.prototype.hasOwnProperty.call(e, t),
1018
1035
  entitlementLimit: (t, n) => {
1019
1036
  let r = e[t];
1020
- return r === void 0 ? 0 : ft(r.entitlements[n]);
1037
+ return r === void 0 ? 0 : bt(r.entitlements[n]);
1021
1038
  },
1022
1039
  planForPriceId: (e) => t.get(e) ?? null,
1023
1040
  priceIdFor: (t) => e[t]?.priceId ?? null,
@@ -1028,14 +1045,14 @@ var j = (e, t, n, r) => ({
1028
1045
  currencyFor: (t) => (e[t]?.currency ?? "usd").toLowerCase(),
1029
1046
  planIds: () => Object.keys(e)
1030
1047
  };
1031
- }, mt = () => pt({ [n]: { entitlements: {} } }), Y = "_voltro_billing_flush_claims", ht = w(Y, {
1032
- id: b({ scheme: "numeric" }),
1033
- windowKey: T(),
1034
- claimedBy: T(),
1035
- claimedAt: E().default("now")
1036
- }).unique("billingFlushClaimWindow", ["windowKey"]), gt = (e, t) => `billing-flush:${Math.floor(e / Math.max(1, t))}`, _t = async (e, t, n, r) => {
1048
+ }, St = () => xt({ [n]: { entitlements: {} } }), J = "_voltro_billing_flush_claims", Ct = C(J, {
1049
+ id: y({ scheme: "numeric" }),
1050
+ windowKey: w(),
1051
+ claimedBy: w(),
1052
+ claimedAt: T().default("now")
1053
+ }).unique("billingFlushClaimWindow", ["windowKey"]), wt = (e, t) => `billing-flush:${Math.floor(e / Math.max(1, t))}`, Tt = async (e, t, n, r) => {
1037
1054
  try {
1038
- return (await e.insertIgnore(Y, {
1055
+ return (await e.insertIgnore(J, {
1039
1056
  windowKey: t,
1040
1057
  claimedBy: n,
1041
1058
  claimedAt: new Date(r)
@@ -1043,38 +1060,38 @@ var j = (e, t, n, r) => ({
1043
1060
  } catch {
1044
1061
  return !0;
1045
1062
  }
1046
- }, vt = 3, yt = 2e4, bt = (e) => e.client ?? new O(e.apiKey, {
1047
- maxNetworkRetries: vt,
1048
- timeout: yt,
1063
+ }, Et = 3, Dt = 2e4, Ot = (e) => e.client ?? new D(e.apiKey, {
1064
+ maxNetworkRetries: Et,
1065
+ timeout: Dt,
1049
1066
  appInfo: {
1050
1067
  name: "voltro",
1051
1068
  url: "https://voltro.dev"
1052
1069
  }
1053
- }), xt = (e) => e instanceof O.errors.StripeConnectionError || e instanceof O.errors.StripeAPIError || e instanceof O.errors.StripeRateLimitError, St = (e) => e instanceof O.errors.StripeError ? e.code ?? e.type : void 0, X = (t, n) => p.tryPromise({
1070
+ }), kt = (e) => e instanceof D.errors.StripeConnectionError || e instanceof D.errors.StripeAPIError || e instanceof D.errors.StripeRateLimitError, At = (e) => e instanceof D.errors.StripeError ? e.code ?? e.type : void 0, Y = (t, n) => p.tryPromise({
1054
1071
  try: n,
1055
1072
  catch: (n) => new e({
1056
1073
  source: t,
1057
- message: Ct(n),
1058
- transient: xt(n)
1074
+ message: jt(n),
1075
+ transient: kt(n)
1059
1076
  })
1060
- }), Ct = (e) => {
1061
- if (e instanceof O.errors.StripeError) {
1062
- let t = St(e);
1077
+ }), jt = (e) => {
1078
+ if (e instanceof D.errors.StripeError) {
1079
+ let t = At(e);
1063
1080
  return t === void 0 ? e.message : `${e.message} (${t})`;
1064
1081
  }
1065
1082
  return String(e?.message ?? e);
1066
- }, wt = (e) => {
1083
+ }, Mt = (e) => {
1067
1084
  let t = e.items?.data?.[0];
1068
1085
  return {
1069
- start: Z(t?.current_period_start),
1070
- end: Z(t?.current_period_end)
1086
+ start: X(t?.current_period_start),
1087
+ end: X(t?.current_period_end)
1071
1088
  };
1072
- }, Z = (e) => typeof e == "number" && Number.isFinite(e) ? /* @__PURE__ */ new Date(e * 1e3) : null, Tt = (e) => {
1089
+ }, X = (e) => typeof e == "number" && Number.isFinite(e) ? /* @__PURE__ */ new Date(e * 1e3) : null, Nt = (e) => {
1073
1090
  let t = e.items?.data ?? [];
1074
1091
  if (t.length === 0) return 1;
1075
1092
  let n = t.reduce((e, t) => e + (t.quantity ?? 0), 0);
1076
1093
  return n > 0 ? n : 1;
1077
- }, Et = {
1094
+ }, Pt = {
1078
1095
  active: "active",
1079
1096
  trialing: "trialing",
1080
1097
  past_due: "pastDue",
@@ -1083,44 +1100,44 @@ var j = (e, t, n, r) => ({
1083
1100
  incomplete: "incomplete",
1084
1101
  incomplete_expired: "canceled",
1085
1102
  paused: "pastDue"
1086
- }, Q = (e) => {
1103
+ }, Z = (e) => {
1087
1104
  let t = e.metadata?.tenantId;
1088
1105
  if (typeof t == "string" && t.length > 0) return t;
1089
1106
  let n = e.client_reference_id;
1090
1107
  return typeof n == "string" && n.length > 0 ? n : null;
1091
- }, Dt = (e) => {
1108
+ }, Ft = (e) => {
1092
1109
  let t = e.items?.data?.[0]?.price;
1093
1110
  return typeof t?.id == "string" ? t.id : null;
1094
- }, Ot = (e, t) => {
1111
+ }, Q = (e, t) => {
1095
1112
  let n = e.metadata?.plan;
1096
1113
  if (typeof n == "string" && n.length > 0) return n;
1097
- let r = Dt(e);
1114
+ let r = Ft(e);
1098
1115
  return r !== null && t ? t(r) : null;
1099
- }, kt = (e, t) => {
1100
- let n = Z(e.created);
1116
+ }, It = (e, t) => {
1117
+ let n = X(e.created);
1101
1118
  switch (e.type) {
1102
1119
  case "customer.subscription.created":
1103
1120
  case "customer.subscription.updated":
1104
1121
  case "customer.subscription.resumed":
1105
1122
  case "customer.subscription.paused": {
1106
- let r = e.data.object, i = Q(r), a = Ot(r, t), o = Et[r.status];
1123
+ let r = e.data.object, i = Z(r), a = Q(r, t), o = Pt[r.status];
1107
1124
  if (i === null || a === null || o === void 0) return null;
1108
- let s = wt(r);
1125
+ let s = Mt(r);
1109
1126
  return {
1110
1127
  _tag: "subscriptionUpserted",
1111
1128
  tenantId: i,
1112
1129
  providerSubscriptionId: r.id,
1113
1130
  plan: a,
1114
1131
  status: o,
1115
- quantity: Tt(r),
1132
+ quantity: Nt(r),
1116
1133
  currentPeriodStart: s.start,
1117
1134
  currentPeriodEnd: s.end,
1118
- cancelAt: Z(r.cancel_at),
1135
+ cancelAt: X(r.cancel_at),
1119
1136
  occurredAt: n
1120
1137
  };
1121
1138
  }
1122
1139
  case "customer.subscription.deleted": {
1123
- let t = e.data.object, r = Q(t);
1140
+ let t = e.data.object, r = Z(t);
1124
1141
  return r === null ? null : {
1125
1142
  _tag: "subscriptionCanceled",
1126
1143
  tenantId: r,
@@ -1130,7 +1147,7 @@ var j = (e, t, n, r) => ({
1130
1147
  }
1131
1148
  case "invoice.paid":
1132
1149
  case "invoice.payment_failed": {
1133
- let t = e.data.object, r = Q(t);
1150
+ let t = e.data.object, r = Z(t);
1134
1151
  return r === null || typeof t.id != "string" ? null : {
1135
1152
  _tag: e.type === "invoice.paid" ? "invoicePaid" : "invoicePaymentFailed",
1136
1153
  tenantId: r,
@@ -1141,7 +1158,7 @@ var j = (e, t, n, r) => ({
1141
1158
  };
1142
1159
  }
1143
1160
  case "customer.created": {
1144
- let t = e.data.object, r = Q(t);
1161
+ let t = e.data.object, r = Z(t);
1145
1162
  return r === null ? null : {
1146
1163
  _tag: "customerLinked",
1147
1164
  tenantId: r,
@@ -1151,16 +1168,16 @@ var j = (e, t, n, r) => ({
1151
1168
  }
1152
1169
  default: return null;
1153
1170
  }
1154
- }, At = {
1171
+ }, Lt = {
1155
1172
  prorate: "create_prorations",
1156
1173
  none: "none",
1157
1174
  always_invoice: "always_invoice"
1158
- }, jt = (t) => {
1159
- let n = bt(t), r = t.planForPriceId, i = (e) => n.subscriptions.retrieve(e, { expand: ["items.data.price"] }), a = (e, t) => {
1160
- let n = wt(e), i = e.items?.data?.[0]?.price;
1175
+ }, Rt = (t) => {
1176
+ let n = Ot(t), r = t.planForPriceId, i = (e) => n.subscriptions.retrieve(e, { expand: ["items.data.price"] }), a = (e, t) => {
1177
+ let n = Mt(e), i = e.items?.data?.[0]?.price;
1161
1178
  return {
1162
- plan: Ot(e, r) ?? "free",
1163
- quantity: Tt(e),
1179
+ plan: Q(e, r) ?? "free",
1180
+ quantity: Nt(e),
1164
1181
  prorationMinor: t,
1165
1182
  currency: (i?.currency ?? "usd").toLowerCase(),
1166
1183
  currentPeriodStart: n.start,
@@ -1174,7 +1191,7 @@ var j = (e, t, n, r) => ({
1174
1191
  ...t.priceId === void 0 ? {} : { price: t.priceId },
1175
1192
  ...t.quantity === void 0 ? {} : { quantity: t.quantity }
1176
1193
  }],
1177
- proration_behavior: At[t.proration ?? "prorate"],
1194
+ proration_behavior: Lt[t.proration ?? "prorate"],
1178
1195
  ...t.priceId !== void 0 && r ? { metadata: {
1179
1196
  ...e.metadata,
1180
1197
  plan: r(t.priceId) ?? ""
@@ -1184,7 +1201,7 @@ var j = (e, t, n, r) => ({
1184
1201
  return {
1185
1202
  name: "stripe",
1186
1203
  supportsMeteredUsage: t.supportsMeteredUsage ?? !0,
1187
- createCheckoutSession: (e) => X("stripe.checkout.sessions.create", async () => {
1204
+ createCheckoutSession: (e) => Y("stripe.checkout.sessions.create", async () => {
1188
1205
  let t = await n.checkout.sessions.create({
1189
1206
  mode: "subscription",
1190
1207
  line_items: [{
@@ -1216,11 +1233,11 @@ var j = (e, t, n, r) => ({
1216
1233
  if (typeof t.url != "string") throw Error("checkout session has no url");
1217
1234
  return { url: t.url };
1218
1235
  }),
1219
- createPortalSession: (e) => X("stripe.billingPortal.sessions.create", async () => ({ url: (await n.billingPortal.sessions.create({
1236
+ createPortalSession: (e) => Y("stripe.billingPortal.sessions.create", async () => ({ url: (await n.billingPortal.sessions.create({
1220
1237
  customer: e.providerCustomerId,
1221
1238
  return_url: e.returnUrl
1222
1239
  })).url })),
1223
- reportUsage: (e) => X("stripe.billing.meterEvents.create", async () => {
1240
+ reportUsage: (e) => Y("stripe.billing.meterEvents.create", async () => {
1224
1241
  await n.billing.meterEvents.create({
1225
1242
  event_name: e.entitlementKey,
1226
1243
  identifier: `${e.tenantId}:${e.entitlementKey}:${e.periodEnd?.toISOString() ?? "current"}`,
@@ -1230,11 +1247,11 @@ var j = (e, t, n, r) => ({
1230
1247
  }
1231
1248
  });
1232
1249
  }),
1233
- updateSubscription: (e) => X("stripe.subscriptions.update", async () => {
1234
- let t = await i(e.providerSubscriptionId), r = await n.subscriptions.update(e.providerSubscriptionId, o(t, e)), s = await Nt(n, r);
1250
+ updateSubscription: (e) => Y("stripe.subscriptions.update", async () => {
1251
+ let t = await i(e.providerSubscriptionId), r = await n.subscriptions.update(e.providerSubscriptionId, o(t, e)), s = await Bt(n, r);
1235
1252
  return a(r, s);
1236
1253
  }),
1237
- previewSubscriptionChange: (e) => X("stripe.invoices.createPreview", async () => {
1254
+ previewSubscriptionChange: (e) => Y("stripe.invoices.createPreview", async () => {
1238
1255
  let t = await i(e.providerSubscriptionId), s = o(t, e), c = (await n.invoices.createPreview({
1239
1256
  subscription: e.providerSubscriptionId,
1240
1257
  subscription_details: {
@@ -1248,27 +1265,27 @@ var j = (e, t, n, r) => ({
1248
1265
  ...e.priceId !== void 0 && r ? { plan: r(e.priceId) ?? "free" } : {}
1249
1266
  };
1250
1267
  }),
1251
- fetchSubscription: (e) => X("stripe.subscriptions.retrieve", async () => {
1268
+ fetchSubscription: (e) => Y("stripe.subscriptions.retrieve", async () => {
1252
1269
  try {
1253
- let t = await i(e), n = wt(t);
1270
+ let t = await i(e), n = Mt(t);
1254
1271
  return {
1255
- status: Et[t.status] ?? "incomplete",
1256
- plan: Ot(t, r),
1257
- quantity: Tt(t),
1272
+ status: Pt[t.status] ?? "incomplete",
1273
+ plan: Q(t, r),
1274
+ quantity: Nt(t),
1258
1275
  currentPeriodStart: n.start,
1259
1276
  currentPeriodEnd: n.end,
1260
- cancelAt: Z(t.cancel_at)
1277
+ cancelAt: X(t.cancel_at)
1261
1278
  };
1262
1279
  } catch (e) {
1263
- if (e instanceof O.errors.StripeInvalidRequestError && e.statusCode === 404) return null;
1280
+ if (e instanceof D.errors.StripeInvalidRequestError && e.statusCode === 404) return null;
1264
1281
  throw e;
1265
1282
  }
1266
1283
  }),
1267
- customerEmail: (e) => X("stripe.customers.retrieve", async () => {
1284
+ customerEmail: (e) => Y("stripe.customers.retrieve", async () => {
1268
1285
  let t = await n.customers.retrieve(e);
1269
1286
  return t.deleted === !0 ? null : typeof t.email == "string" && t.email.length > 0 ? t.email : null;
1270
1287
  }),
1271
- listInvoices: (e) => X("stripe.invoices.list", async () => (await n.invoices.list({
1288
+ listInvoices: (e) => Y("stripe.invoices.list", async () => (await n.invoices.list({
1272
1289
  customer: e.providerCustomerId,
1273
1290
  limit: e.limit ?? 20
1274
1291
  })).data.map((e) => ({
@@ -1276,7 +1293,7 @@ var j = (e, t, n, r) => ({
1276
1293
  amountMinor: e.amount_due,
1277
1294
  currency: e.currency,
1278
1295
  status: e.status ?? "unknown",
1279
- createdAt: Z(e.created),
1296
+ createdAt: X(e.created),
1280
1297
  hostedUrl: e.hosted_invoice_url ?? null,
1281
1298
  pdfUrl: e.invoice_pdf ?? null
1282
1299
  }))),
@@ -1288,15 +1305,15 @@ var j = (e, t, n, r) => ({
1288
1305
  transient: !1
1289
1306
  })
1290
1307
  }),
1291
- normalizeEvent: (e) => p.succeed(Mt(e) ? kt(e, r) : null)
1308
+ normalizeEvent: (e) => p.succeed(zt(e) ? It(e, r) : null)
1292
1309
  };
1293
- }, Mt = (e) => typeof e == "object" && !!e && typeof e.type == "string" && typeof e.data == "object", Nt = async (e, t) => {
1310
+ }, zt = (e) => typeof e == "object" && !!e && typeof e.type == "string" && typeof e.data == "object", Bt = async (e, t) => {
1294
1311
  try {
1295
1312
  return (await e.invoices.createPreview({ subscription: t.id })).lines.data.filter((e) => e.parent?.subscription_item_details?.proration === !0).reduce((e, t) => e + t.amount, 0);
1296
1313
  } catch {
1297
1314
  return 0;
1298
1315
  }
1299
- }, Pt = (e) => {
1316
+ }, Vt = (e) => {
1300
1317
  let t = e?.baseUrl ?? "https://mock.billing.local", n = [], r = [], i = [], a = /* @__PURE__ */ new Map(), o = /* @__PURE__ */ new Map(), s = (e) => typeof e == "object" && !!e && typeof e._tag == "string";
1301
1318
  return {
1302
1319
  name: "mock",
@@ -1336,22 +1353,22 @@ var j = (e, t, n, r) => ({
1336
1353
  listInvoices: () => p.succeed([]),
1337
1354
  normalizeEvent: (e) => p.succeed(s(e) ? e : null)
1338
1355
  };
1339
- }, Ft = (e) => {
1356
+ }, Ht = (e) => {
1340
1357
  let { provider: t, env: n } = e;
1341
1358
  if (t !== void 0 && typeof t == "object") return t;
1342
1359
  if ((t ?? (n.STRIPE_SECRET_KEY ? "stripe" : "mock")) === "stripe") {
1343
1360
  let t = e.apiKey ?? n.STRIPE_SECRET_KEY;
1344
1361
  if (!t) throw Error("billingPlugin: provider 'stripe' needs an apiKey (option or STRIPE_SECRET_KEY env)");
1345
- return jt({
1362
+ return Rt({
1346
1363
  apiKey: t,
1347
1364
  ...e.planForPriceId ? { planForPriceId: e.planForPriceId } : {}
1348
1365
  });
1349
1366
  }
1350
- return Pt();
1351
- }, It = D({ scope: "@voltro/plugin-billing" }), Lt = "billing", $ = "/billing/webhook", Rt = (e) => oe({
1352
- id: Lt,
1367
+ return Vt();
1368
+ }, Ut = E({ scope: "@voltro/plugin-billing" }), Wt = "billing", $ = "/billing/webhook", Gt = (e) => fe({
1369
+ id: Wt,
1353
1370
  path: $,
1354
- provider: A(),
1371
+ provider: O(),
1355
1372
  payload: ne.Unknown,
1356
1373
  handler: async (t) => {
1357
1374
  let n = e.provider.verifyWebhook !== void 0 && e.webhookSecret !== null && e.webhookSecret !== void 0 ? await p.runPromise(e.provider.verifyWebhook({
@@ -1363,25 +1380,25 @@ var j = (e, t, n, r) => ({
1363
1380
  await p.runPromise(e.service.applyEvent(r));
1364
1381
  let i = e.onEvent?.[r._tag];
1365
1382
  i !== void 0 && await p.runPromise(i(r).pipe(p.catchAllCause((e) => p.sync(() => {
1366
- It.warn("billing onEvent side effect failed", {
1383
+ Ut.warn("billing onEvent side effect failed", {
1367
1384
  event: r._tag,
1368
1385
  cause: String(e)
1369
1386
  });
1370
1387
  }))));
1371
1388
  }
1372
- }), zt = (e) => k(Rt(e), {
1389
+ }), Kt = (e) => pe(Gt(e), {
1373
1390
  resolveSecret: () => Promise.resolve(e.webhookSecret),
1374
1391
  ...e.idempotencyCache === void 0 ? {} : { idempotencyCache: e.idempotencyCache },
1375
1392
  log: (e) => {
1376
- e.status >= 400 && It.warn("billing webhook rejected", { ...e });
1393
+ e.status >= 400 && Ut.warn("billing webhook rejected", { ...e });
1377
1394
  }
1378
- }), Bt = (e) => e === null ? null : {
1395
+ }), qt = (e) => e === null ? null : {
1379
1396
  plan: e.plan,
1380
1397
  status: e.status,
1381
1398
  quantity: e.quantity,
1382
1399
  currentPeriodEnd: e.currentPeriodEnd ? e.currentPeriodEnd.toISOString() : null,
1383
1400
  cancelAt: e.cancelAt ? e.cancelAt.toISOString() : null
1384
- }, Vt = g([{
1401
+ }, Jt = re([{
1385
1402
  name: "STRIPE_SECRET_KEY",
1386
1403
  required: !1,
1387
1404
  secret: !0,
@@ -1391,50 +1408,50 @@ var j = (e, t, n, r) => ({
1391
1408
  required: !1,
1392
1409
  secret: !0,
1393
1410
  description: "Stripe webhook signing secret (whsec_…) for verifying webhook payloads."
1394
- }]), Ht = "@voltro/plugin-billing", Ut = (t = {}) => {
1395
- let n = process.env, m = pt(t.plans ?? {}), h = Ft({
1411
+ }]), Yt = "@voltro/plugin-billing", Xt = (t = {}) => {
1412
+ let n = process.env, m = xt(t.plans ?? {}), h = Ht({
1396
1413
  ...t.provider === void 0 ? {} : { provider: t.provider },
1397
1414
  ...t.apiKey === void 0 ? {} : { apiKey: t.apiKey },
1398
1415
  planForPriceId: m.planForPriceId,
1399
1416
  env: n
1400
- }), ne = t.webhookSecret ?? Vt.read("STRIPE_WEBHOOK_SECRET") ?? null, g = be(t.dunning, n);
1401
- S({
1417
+ }), ne = t.webhookSecret ?? Jt.read("STRIPE_WEBHOOK_SECRET") ?? null, re = L(t.dunning, n);
1418
+ x({
1402
1419
  source: "plugin",
1403
- table: L,
1420
+ table: P,
1404
1421
  timeColumn: "updatedAt",
1405
- ttlMs: C(process.env.VOLTRO_BILLING_USAGE_TTL_HOURS, 9600),
1422
+ ttlMs: S(process.env.VOLTRO_BILLING_USAGE_TTL_HOURS, 9600),
1406
1423
  label: "billing usage counters"
1407
- }), S({
1424
+ }), x({
1408
1425
  source: "plugin",
1409
- table: Y,
1426
+ table: J,
1410
1427
  timeColumn: "claimedAt",
1411
- ttlMs: C(process.env.VOLTRO_BILLING_FLUSH_CLAIM_TTL_HOURS, 1),
1428
+ ttlMs: S(process.env.VOLTRO_BILLING_FLUSH_CLAIM_TTL_HOURS, 1),
1412
1429
  label: "billing flush claims"
1413
- }), S({
1430
+ }), x({
1414
1431
  source: "plugin",
1415
- table: R,
1432
+ table: F,
1416
1433
  timeColumn: "sentAt",
1417
- ttlMs: C(process.env.VOLTRO_BILLING_DUNNING_TTL_HOURS, 9600),
1434
+ ttlMs: S(process.env.VOLTRO_BILLING_DUNNING_TTL_HOURS, 9600),
1418
1435
  label: "billing dunning notices"
1419
1436
  });
1420
- let { service: _, holder: v } = Je({
1437
+ let { service: g, holder: _ } = et({
1421
1438
  provider: h,
1422
1439
  plans: m,
1423
1440
  ...t.attempts === void 0 ? {} : { attempts: t.attempts },
1424
1441
  ...t.checkout === void 0 ? {} : { checkout: t.checkout },
1425
1442
  ...t.resolveEntitlementLimit === void 0 ? {} : { resolveEntitlementLimit: t.resolveEntitlementLimit },
1426
- dunning: g
1427
- }), y = Ye(_), b = zt({
1443
+ dunning: re
1444
+ }), se = tt(g), ce = Kt({
1428
1445
  provider: h,
1429
- service: _,
1446
+ service: g,
1430
1447
  webhookSecret: ne,
1431
1448
  ...t.onEvent === void 0 ? {} : { onEvent: t.onEvent }
1432
- }), x = {
1449
+ }), v = {
1433
1450
  method: "POST",
1434
1451
  path: $,
1435
1452
  originGuard: "exempt",
1436
1453
  handle: async (e) => {
1437
- let t = await b({
1454
+ let t = await ce({
1438
1455
  method: e.method,
1439
1456
  path: e.path,
1440
1457
  headers: e.headers,
@@ -1447,12 +1464,12 @@ var j = (e, t, n, r) => ({
1447
1464
  ...t.headers === void 0 ? {} : { headers: { ...t.headers } }
1448
1465
  };
1449
1466
  }
1450
- }, w = [
1467
+ }, le = [
1451
1468
  {
1452
1469
  ...ee,
1453
1470
  execute: (e, t) => {
1454
1471
  let n = e;
1455
- return _.startCheckout({
1472
+ return g.startCheckout({
1456
1473
  tenantId: t.request.subject.tenantId ?? "",
1457
1474
  plan: n.plan,
1458
1475
  successUrl: n.successUrl,
@@ -1465,16 +1482,16 @@ var j = (e, t, n, r) => ({
1465
1482
  ...u,
1466
1483
  execute: (e, t) => {
1467
1484
  let n = e;
1468
- return _.portalUrl(t.request.subject.tenantId ?? "", n.returnUrl);
1485
+ return g.portalUrl(t.request.subject.tenantId ?? "", n.returnUrl);
1469
1486
  }
1470
1487
  },
1471
1488
  {
1472
1489
  ...te,
1473
- execute: (e, t) => _.subscription(t.request.subject.tenantId ?? "").pipe(p.map((e) => ({ subscription: Bt(e) })))
1490
+ execute: (e, t) => g.subscription(t.request.subject.tenantId ?? "").pipe(p.map((e) => ({ subscription: qt(e) })))
1474
1491
  },
1475
1492
  {
1476
1493
  ...c,
1477
- execute: (e, t) => _.entitlementStatus(t.request.subject.tenantId ?? "").pipe(p.map((e) => ({
1494
+ execute: (e, t) => g.entitlementStatus(t.request.subject.tenantId ?? "").pipe(p.map((e) => ({
1478
1495
  plan: e.plan,
1479
1496
  billedPlan: e.billedPlan,
1480
1497
  status: e.status,
@@ -1489,7 +1506,7 @@ var j = (e, t, n, r) => ({
1489
1506
  ...d,
1490
1507
  execute: (e, t) => {
1491
1508
  let n = e;
1492
- return _.previewChange(t.request.subject.tenantId ?? "", {
1509
+ return g.previewChange(t.request.subject.tenantId ?? "", {
1493
1510
  ...n.plan === void 0 ? {} : { plan: n.plan },
1494
1511
  ...n.quantity === void 0 ? {} : { quantity: n.quantity }
1495
1512
  }).pipe(p.map((e) => ({
@@ -1502,7 +1519,7 @@ var j = (e, t, n, r) => ({
1502
1519
  },
1503
1520
  {
1504
1521
  ...l,
1505
- execute: (e, t) => _.invoices(t.request.subject.tenantId ?? "").pipe(p.map((e) => ({ invoices: e.map((e) => ({
1522
+ execute: (e, t) => g.invoices(t.request.subject.tenantId ?? "").pipe(p.map((e) => ({ invoices: e.map((e) => ({
1506
1523
  ...e,
1507
1524
  createdAt: e.createdAt?.toISOString() ?? null
1508
1525
  })) })))
@@ -1511,14 +1528,14 @@ var j = (e, t, n, r) => ({
1511
1528
  ...f,
1512
1529
  execute: (e, t) => {
1513
1530
  let n = e;
1514
- return _.reportUsage(t.request.subject.tenantId ?? "", n.key, n.quantity).pipe(p.map(() => ({ ok: !0 })));
1531
+ return g.reportUsage(t.request.subject.tenantId ?? "", n.key, n.quantity).pipe(p.map(() => ({ ok: !0 })));
1515
1532
  }
1516
1533
  },
1517
1534
  {
1518
1535
  ...o,
1519
1536
  execute: (e, t) => {
1520
1537
  let n = e;
1521
- return _.changePlan(t.request.subject.tenantId ?? "", n.plan).pipe(p.map((e) => ({
1538
+ return g.changePlan(t.request.subject.tenantId ?? "", n.plan).pipe(p.map((e) => ({
1522
1539
  plan: e.plan,
1523
1540
  quantity: e.quantity,
1524
1541
  prorationMinor: e.prorationMinor,
@@ -1530,7 +1547,7 @@ var j = (e, t, n, r) => ({
1530
1547
  ...s,
1531
1548
  execute: (e, t) => {
1532
1549
  let n = e;
1533
- return _.changeSeats(t.request.subject.tenantId ?? "", n.quantity).pipe(p.map((e) => ({
1550
+ return g.changeSeats(t.request.subject.tenantId ?? "", n.quantity).pipe(p.map((e) => ({
1534
1551
  plan: e.plan,
1535
1552
  quantity: e.quantity,
1536
1553
  prorationMinor: e.prorationMinor,
@@ -1538,11 +1555,11 @@ var j = (e, t, n, r) => ({
1538
1555
  })));
1539
1556
  }
1540
1557
  }
1541
- ], T = (e, t) => ({
1558
+ ], y = (e, t) => ({
1542
1559
  kind: "json",
1543
1560
  status: e,
1544
1561
  data: { error: t }
1545
- }), E = [{
1562
+ }), b = [{
1546
1563
  method: "GET",
1547
1564
  path: "/stats",
1548
1565
  description: "Billing config: provider, declared plans, enforced tags",
@@ -1560,11 +1577,11 @@ var j = (e, t, n, r) => ({
1560
1577
  method: "GET",
1561
1578
  path: "/usage",
1562
1579
  description: "Pending (un-flushed) metered usage counters",
1563
- handler: () => v.stores.usage.pending().pipe(p.map((e) => ({
1580
+ handler: () => _.stores.usage.pending().pipe(p.map((e) => ({
1564
1581
  kind: "json",
1565
1582
  data: { usage: e }
1566
- })), p.catchAll((e) => p.succeed(T(500, e.message))))
1567
- }], D = [
1583
+ })), p.catchAll((e) => p.succeed(y(500, e.message))))
1584
+ }], ue = [
1568
1585
  {
1569
1586
  schema: e,
1570
1587
  import: {
@@ -1586,72 +1603,77 @@ var j = (e, t, n, r) => ({
1586
1603
  name: "SubscriptionLocked"
1587
1604
  }
1588
1605
  }
1589
- ], O = t.enforce, oe = O !== void 0 && Object.keys(O).length > 0 ? ce(O, _) : void 0, k = t.metering;
1590
- k !== void 0 && Ze(k);
1591
- let A = k !== void 0 && Object.keys(k).length > 0 ? ot(_, k) : void 0, j = k !== void 0 && dt(k), M = re([A, oe].filter((e) => e !== void 0)), se, N, P = [
1606
+ ], C = t.enforce, w = C !== void 0 && Object.keys(C).length > 0 ? ge(C, g) : void 0, T = t.metering;
1607
+ T !== void 0 && rt(T);
1608
+ let E = T !== void 0 && Object.keys(T).length > 0 ? ft(g, T) : void 0, D = T !== void 0 && yt(T), fe = { claim: void 0 }, pe = T === void 0 ? void 0 : ht(g, T, {
1609
+ claimChange: () => fe.claim,
1610
+ onUngated: () => {
1611
+ p.runSync(p.logWarning("metering: CDC meters are accruing PER PROCESS — with N replicas a tenant is billed N times. The framework did not hand this plugin a change claimer (expected on the memory store; on a SQL store this is a bug worth reporting).").pipe(p.annotateLogs({ scope: "voltro:billing" })));
1612
+ }
1613
+ }), O = ie([E, w].filter((e) => e !== void 0)), k, A, me = [
1592
1614
  "store:write",
1593
1615
  "inspect:read",
1594
1616
  "inspect:write",
1595
1617
  "network:outbound:*",
1596
- ...M === void 0 ? [] : ["rpc:intercept:mutation", "rpc:intercept:action"],
1597
- ...A === void 0 ? [] : ["rpc:intercept:query"],
1598
- ...j ? ["store:changes:read"] : []
1618
+ ...O === void 0 ? [] : ["rpc:intercept:mutation", "rpc:intercept:action"],
1619
+ ...E === void 0 ? [] : ["rpc:intercept:query"],
1620
+ ...D ? ["store:changes:read"] : []
1599
1621
  ];
1600
- return ie({
1601
- name: ae({
1602
- base: Ht,
1622
+ return ae({
1623
+ name: oe({
1624
+ base: Yt,
1603
1625
  alias: t.alias,
1604
1626
  instance: t.name
1605
1627
  }),
1606
- baseName: Ht,
1628
+ baseName: Yt,
1607
1629
  description: "Billing — subscriptions, plans, entitlements + usage metering over a pluggable BillingProvider (Stripe + mock). Ships the BillingService, the requireEntitlement() in-handler guard + the enforce-map interceptor, the /billing/webhook receiver (riding @voltro/plugin-webhooks for signature + idempotency), and the _voltro_billing_* tables. Money is integer minor units.",
1608
- permissions: P,
1609
- declaredEnv: Vt.declared,
1610
- services: y,
1611
- routes: w,
1630
+ permissions: me,
1631
+ declaredEnv: Jt.declared,
1632
+ services: se,
1633
+ routes: le,
1612
1634
  rpcClientDescriptors: a,
1613
- httpRoutes: [x],
1614
- inspectEndpoints: E,
1635
+ httpRoutes: [v],
1636
+ inspectEndpoints: b,
1615
1637
  extendSchema: { tables: [
1616
- ...pe(),
1617
- ht,
1618
- me
1638
+ ...xe(),
1639
+ Ct,
1640
+ Se
1619
1641
  ] },
1620
- errorSchemas: D,
1621
- ...M === void 0 ? {} : {
1622
- interceptMutation: M,
1623
- interceptAction: M
1642
+ errorSchemas: ue,
1643
+ ...O === void 0 ? {} : {
1644
+ interceptMutation: O,
1645
+ interceptAction: O
1624
1646
  },
1625
- ...A === void 0 ? {} : { interceptQuery: A },
1626
- ...j ? { onChangeEvent: st(_, k) } : {},
1627
- bindDataStore: (e) => {
1628
- v.stores = Ke(e), se = e;
1647
+ ...E === void 0 ? {} : { interceptQuery: E },
1648
+ ...D ? { onChangeEvent: pe } : {},
1649
+ bindDataStore: (e, t) => {
1650
+ _.stores = Qe(e), k = e, fe.claim = t?.claimChange;
1629
1651
  },
1630
1652
  onActivate: (e) => p.sync(() => {
1631
1653
  e.logger.info("billing active", {
1632
1654
  provider: h.name,
1633
1655
  plans: m.planIds().length,
1634
- enforce: O ? Object.keys(O).length : 0,
1635
- metering: k ? Object.keys(k).length : 0,
1656
+ enforce: C ? Object.keys(C).length : 0,
1657
+ metering: T ? Object.keys(T).length : 0,
1636
1658
  webhook: $
1637
1659
  });
1638
- let n = t.flushIntervalMs ?? 6e4, r = k, i = r !== void 0 && Object.keys(r).length > 0;
1660
+ let n = t.flushIntervalMs ?? 6e4, r = T, i = r !== void 0 && Object.keys(r).length > 0;
1639
1661
  if (n > 0) {
1640
- let e = process.env.HOSTNAME ?? `pid-${process.pid}`;
1641
- N = setInterval(() => {
1642
- let t = se;
1662
+ let e = de();
1663
+ A = setInterval(() => {
1664
+ let t = k;
1643
1665
  if (t === void 0) return;
1644
1666
  let a = Date.now();
1645
1667
  (async () => {
1646
- await _t(t, gt(a, n), e, a) && i && await p.runPromise(ut(_, t, r).pipe(p.catchAll(() => p.void)));
1668
+ await Tt(t, wt(a, n), e, a) && i && await p.runPromise(vt(g, t, r).pipe(p.catchAll(() => p.void)));
1647
1669
  })();
1648
- }, n), N.unref?.();
1670
+ }, n), A.unref?.();
1649
1671
  }
1650
1672
  }),
1651
1673
  onDeactivate: () => p.sync(() => {
1652
- N !== void 0 && (clearInterval(N), N = void 0);
1674
+ A !== void 0 && (clearInterval(A), A = void 0);
1653
1675
  })
1654
1676
  });
1655
1677
  };
1656
1678
  //#endregion
1657
- export { P as BILLING_CUSTOMERS_TABLE, R as BILLING_DUNNING_NOTICES_TABLE, Y as BILLING_FLUSH_CLAIMS_TABLE, I as BILLING_INVOICES_TABLE, F as BILLING_SUBSCRIPTIONS_TABLE, L as BILLING_USAGE_TABLE, Lt as BILLING_WEBHOOK_ID, $ as BILLING_WEBHOOK_PATH, e as BillingError, t as BillingService, ge as DEFAULT_DUNNING_STEPS, _e as DEFAULT_GRACE_HOURS, ve as DEFAULT_LOCKOUT, n as DEFAULT_PLAN, he as DUNNING_LOCK_STEP_ID, r as EntitlementExceeded, i as SubscriptionLocked, le as billingCustomersTable, me as billingDunningNoticesTable, ht as billingFlushClaimsTable, de as billingInvoicesTable, Ut as billingPlugin, Ye as billingServiceLayer, ue as billingSubscriptionsTable, pe as billingTables, fe as billingUsageTable, Rt as billingWebhookDescriptor, Je as buildBillingService, ce as buildEnforceInterceptor, pt as buildPlanRegistry, _t as claimFlushWindow, je as dataStoreDunningNoticeStore, Ke as dataStoreStores, Ee as defaultDunningEmail, we as dueSteps, De as dunningMailNotifier, mt as emptyPlanRegistry, Se as episodeKeyOf, z as evaluateBillingEntitlement, j as evaluateEntitlement, gt as flushWindowKey, Ce as graceEndOf, U as isStaleStatusEvent, ke as memoryDunningNoticeStore, Ge as memoryStores, Pt as mockProvider, zt as mountBillingWebhook, kt as normalizeStripeEvent, q as periodKey, N as requireEntitled, se as requireEntitlement, be as resolveDunningConfig, Ft as resolveProvider, jt as stripeProvider };
1679
+ export { j as BILLING_CUSTOMERS_TABLE, F as BILLING_DUNNING_NOTICES_TABLE, J as BILLING_FLUSH_CLAIMS_TABLE, N as BILLING_INVOICES_TABLE, M as BILLING_SUBSCRIPTIONS_TABLE, P as BILLING_USAGE_TABLE, Wt as BILLING_WEBHOOK_ID, $ as BILLING_WEBHOOK_PATH, e as BillingError, t as BillingService, Ce as DEFAULT_DUNNING_STEPS, we as DEFAULT_GRACE_HOURS, Te as DEFAULT_LOCKOUT, n as DEFAULT_PLAN, I as DUNNING_LOCK_STEP_ID, r as EntitlementExceeded, i as SubscriptionLocked, _e as billingCustomersTable, Se as billingDunningNoticesTable, Ct as billingFlushClaimsTable, ye as billingInvoicesTable, Xt as billingPlugin, tt as billingServiceLayer, ve as billingSubscriptionsTable, xe as billingTables, be as billingUsageTable, Gt as billingWebhookDescriptor, et as buildBillingService, ge as buildEnforceInterceptor, xt as buildPlanRegistry, Tt as claimFlushWindow, Le as dataStoreDunningNoticeStore, Qe as dataStoreStores, Me as defaultDunningEmail, Ae as dueSteps, Ne as dunningMailNotifier, St as emptyPlanRegistry, Oe as episodeKeyOf, R as evaluateBillingEntitlement, k as evaluateEntitlement, wt as flushWindowKey, ke as graceEndOf, H as isStaleStatusEvent, Fe as memoryDunningNoticeStore, Ze as memoryStores, Vt as mockProvider, Kt as mountBillingWebhook, It as normalizeStripeEvent, K as periodKey, he as requireEntitled, me as requireEntitlement, L as resolveDunningConfig, Ht as resolveProvider, Rt as stripeProvider };