@rpcbase/billing 0.1.0 → 0.2.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
@@ -82,65 +82,137 @@ const compareEvents = (left, right) => {
82
82
  if (occurredDelta !== 0) return occurredDelta;
83
83
  return (left.id ?? "").localeCompare(right.id ?? "");
84
84
  };
85
- const sortSubscriptionEvents = (events) => events.map((event) => ({
86
- ...event,
87
- occurredAt: assertValidDate(event.occurredAt, "occurredAt"),
88
- effectiveAt: assertValidDate(event.effectiveAt, "effectiveAt"),
89
- billingAnchor: event.billingAnchor ? assertValidDate(event.billingAnchor, "billingAnchor") : void 0
90
- })).sort(compareEvents);
85
+ const sortSubscriptionEvents = (events) => events.map((event) => {
86
+ const dates = {
87
+ occurredAt: assertValidDate(event.occurredAt, "occurredAt"),
88
+ effectiveAt: assertValidDate(event.effectiveAt, "effectiveAt")
89
+ };
90
+ if (event.type === "created") {
91
+ return {
92
+ ...event,
93
+ ...dates,
94
+ billingAnchor: assertValidDate(event.billingAnchor, "billingAnchor")
95
+ };
96
+ }
97
+ return {
98
+ ...event,
99
+ ...dates,
100
+ billingAnchor: event.billingAnchor ? assertValidDate(event.billingAnchor, "billingAnchor") : void 0
101
+ };
102
+ }).sort(compareEvents);
91
103
  const getEffectiveEvents = (events) => {
92
104
  const ordered = sortSubscriptionEvents(events);
93
105
  const supersededIds = new Set(ordered.map((event) => event.supersedesEventId).filter((eventId) => Boolean(eventId)));
94
- const inferredSupersededEvents = /* @__PURE__ */ new Set();
95
- for (const cancellation of ordered) {
96
- if (cancellation.type !== "canceled" || cancellation.effectiveAt.getTime() <= cancellation.occurredAt.getTime() || cancellation.id && supersededIds.has(cancellation.id)) {
97
- continue;
98
- }
99
- const laterResume = ordered.find((candidate) => candidate.type === "resumed" && candidate.occurredAt.getTime() > cancellation.occurredAt.getTime() && candidate.effectiveAt.getTime() <= cancellation.effectiveAt.getTime());
100
- if (laterResume) inferredSupersededEvents.add(cancellation);
101
- }
102
- return ordered.filter((event) => !(event.id && supersededIds.has(event.id)) && !inferredSupersededEvents.has(event));
106
+ return ordered.filter((event) => !(event.id && supersededIds.has(event.id)));
103
107
  };
104
108
  const assertSingleSubscription = (events) => {
109
+ if (events.length === 0) throw new Error("At least one subscription event is required");
105
110
  const subscriptionIds = new Set(events.map((event) => event.subscriptionId));
106
111
  if (subscriptionIds.size > 1) throw new Error("Events from multiple subscriptions cannot be projected together");
107
- return events[0]?.subscriptionId ?? "";
112
+ const tenantIds = new Set(events.map((event) => event.tenantId));
113
+ if (tenantIds.size > 1) throw new Error("Events from multiple tenants cannot be projected together");
114
+ return events[0].subscriptionId;
108
115
  };
109
- const getStatusForEvent = (event, currentStatus) => {
110
- if (event.toStatus) return event.toStatus;
111
- if (event.type === "created" || event.type === "resumed") return "active";
112
- if (event.type === "canceled") return "canceled";
113
- return currentStatus;
116
+ const assertNonEmptyString = (value, field) => {
117
+ if (typeof value !== "string" || !value.trim()) throw new Error(`${field} is required`);
118
+ };
119
+ const assertPositiveInteger = (value, field) => {
120
+ if (!Number.isInteger(value) || Number(value) < 1) throw new Error(`${field} must be a positive integer`);
121
+ };
122
+ function assertCreatedEvent(event) {
123
+ if (event.type !== "created") throw new Error("The first subscription event must be created");
124
+ assertNonEmptyString(event.tenantId, "tenantId");
125
+ assertNonEmptyString(event.subscriptionId, "subscriptionId");
126
+ if (!event.subscriptionType) throw new Error("subscriptionType is required");
127
+ if (!event.scope) throw new Error("scope is required");
128
+ if (event.subscriptionType === "addon") assertNonEmptyString(event.parentSubscriptionId, "parentSubscriptionId");
129
+ if (event.scope !== "tenant") assertNonEmptyString(event.scopeId, "scopeId");
130
+ assertNonEmptyString(event.toPlanKey, "toPlanKey");
131
+ if (!event.toStatus) throw new Error("Created subscription events require toStatus");
132
+ if (!Array.isArray(event.toModules)) throw new Error("Created subscription events require toModules");
133
+ if (!event.toIntervalUnit) throw new Error("Created subscription events require toIntervalUnit");
134
+ assertPositiveInteger(event.toIntervalCount, "toIntervalCount");
135
+ assertValidDate(event.billingAnchor, "billingAnchor");
136
+ }
137
+ const assertTransitionEvent = (event) => {
138
+ assertNonEmptyString(event.idempotencyKey, "idempotencyKey");
139
+ switch (event.type) {
140
+ case "created":
141
+ assertCreatedEvent(event);
142
+ return;
143
+ case "plan_changed":
144
+ assertNonEmptyString(event.fromPlanKey, "fromPlanKey");
145
+ assertNonEmptyString(event.toPlanKey, "toPlanKey");
146
+ if (!Array.isArray(event.fromModules)) throw new Error("Plan changes require fromModules");
147
+ if (!Array.isArray(event.toModules)) throw new Error("Plan changes require toModules");
148
+ if (!event.fromIntervalUnit) throw new Error("Plan changes require fromIntervalUnit");
149
+ if (!event.toIntervalUnit) throw new Error("Plan changes require toIntervalUnit");
150
+ assertPositiveInteger(event.fromIntervalCount, "fromIntervalCount");
151
+ assertPositiveInteger(event.toIntervalCount, "toIntervalCount");
152
+ return;
153
+ case "status_changed":
154
+ if (!event.fromStatus || !event.toStatus) throw new Error("Status changes require fromStatus and toStatus");
155
+ return;
156
+ case "resumed":
157
+ if (!event.fromStatus || event.toStatus !== "active") {
158
+ throw new Error("Resumed events require fromStatus and active toStatus");
159
+ }
160
+ return;
161
+ case "canceled":
162
+ if (!event.fromStatus || event.toStatus !== "canceled") {
163
+ throw new Error("Canceled events require fromStatus and canceled toStatus");
164
+ }
165
+ return;
166
+ case "renewed":
167
+ if (!event.fromStatus || !event.toStatus) throw new Error("Renewed events require fromStatus and toStatus");
168
+ }
169
+ };
170
+ const assertConsistentEventEnvelope = (event, created) => {
171
+ if (event.tenantId !== created.tenantId) throw new Error("Subscription event tenantId cannot change");
172
+ if (event.subscriptionType !== created.subscriptionType) {
173
+ throw new Error("Subscription event subscriptionType cannot change");
174
+ }
175
+ if ((event.parentSubscriptionId ?? null) !== (created.parentSubscriptionId ?? null)) {
176
+ throw new Error("Subscription event parentSubscriptionId cannot change");
177
+ }
178
+ if (event.scope !== created.scope) throw new Error("Subscription event scope cannot change");
179
+ if ((event.scopeId ?? null) !== (created.scopeId ?? null)) {
180
+ throw new Error("Subscription event scopeId cannot change");
181
+ }
114
182
  };
115
183
  const projectSubscription = (events, options = {}) => {
116
184
  if (events.length === 0) return null;
117
185
  const subscriptionId = assertSingleSubscription(events);
118
186
  const ordered = getEffectiveEvents(events);
187
+ const created = ordered[0];
188
+ assertCreatedEvent(created);
189
+ ordered.forEach((event, index) => {
190
+ if (index > 0 && event.type === "created") {
191
+ throw new Error("A subscription event stream cannot contain multiple created events");
192
+ }
193
+ assertTransitionEvent(event);
194
+ assertConsistentEventEnvelope(event, created);
195
+ });
119
196
  const asOf = assertValidDate(options.asOf ?? /* @__PURE__ */ new Date(), "asOf");
120
197
  const applicable = ordered.filter((event) => event.effectiveAt.getTime() <= asOf.getTime());
121
198
  if (applicable.length === 0) return null;
122
- const firstEvent = applicable[0];
123
- let type = firstEvent.subscriptionType ?? "primary";
124
- let parentSubscriptionId = firstEvent.parentSubscriptionId ?? null;
125
- let scope = firstEvent.scope ?? "tenant";
126
- let scopeId = firstEvent.scopeId ?? null;
127
- let planKey = "";
199
+ const type = created.subscriptionType;
200
+ const parentSubscriptionId = created.parentSubscriptionId ?? null;
201
+ const scope = created.scope;
202
+ const scopeId = created.scopeId ?? null;
203
+ let planKey = created.toPlanKey;
128
204
  let priceId = null;
129
- let status = "active";
130
- let intervalUnit = firstEvent.toIntervalUnit ?? "month";
131
- let intervalCount = firstEvent.toIntervalCount ?? 1;
132
- let modules = [];
133
- let billingAnchor = firstEvent.billingAnchor ?? firstEvent.effectiveAt;
205
+ let status = created.toStatus;
206
+ let intervalUnit = created.toIntervalUnit;
207
+ let intervalCount = created.toIntervalCount;
208
+ let modules = [...created.toModules];
209
+ let billingAnchor = created.billingAnchor;
134
210
  let provider = null;
135
211
  let canceledAt = null;
136
- for (const event of applicable) {
137
- type = event.subscriptionType ?? type;
138
- parentSubscriptionId = event.parentSubscriptionId ?? parentSubscriptionId;
139
- scope = event.scope ?? scope;
140
- scopeId = event.scopeId ?? scopeId;
212
+ for (const event of applicable.slice(1)) {
141
213
  planKey = event.toPlanKey ?? planKey;
142
214
  priceId = event.toPriceId ?? priceId;
143
- status = getStatusForEvent(event, status);
215
+ status = event.toStatus ?? status;
144
216
  intervalUnit = event.toIntervalUnit ?? intervalUnit;
145
217
  intervalCount = event.toIntervalCount ?? intervalCount;
146
218
  modules = event.toModules ? [...event.toModules] : modules;
@@ -148,18 +220,14 @@ const projectSubscription = (events, options = {}) => {
148
220
  provider = event.provider ?? provider;
149
221
  if (event.type === "canceled") {
150
222
  canceledAt = new Date(event.effectiveAt);
151
- } else if (event.type === "created" || event.type === "resumed") {
223
+ } else if (event.type === "resumed") {
152
224
  canceledAt = null;
153
225
  }
154
226
  }
155
- if (!planKey) return null;
156
- if (!Number.isInteger(intervalCount) || intervalCount < 1) {
157
- throw new Error("Subscription intervalCount must be a positive integer");
158
- }
159
227
  const futureEvents = ordered.filter((event) => event.effectiveAt.getTime() > asOf.getTime());
160
228
  const scheduledCancellation = futureEvents.find((event) => event.type === "canceled") ?? null;
161
- const scheduledPlanEvent = futureEvents.find((event) => event.type === "plan_changed" && event.toPlanKey) ?? null;
162
- const scheduledPlan = scheduledPlanEvent?.toPlanKey ? {
229
+ const scheduledPlanEvent = futureEvents.find((event) => event.type === "plan_changed") ?? null;
230
+ const scheduledPlan = scheduledPlanEvent ? {
163
231
  planKey: scheduledPlanEvent.toPlanKey,
164
232
  effectiveAt: new Date(scheduledPlanEvent.effectiveAt)
165
233
  } : null;
@@ -257,7 +325,6 @@ const runWithOptionalTransaction = async (storage, operation) => {
257
325
  return storage.runInTransaction((transaction) => operation(transaction));
258
326
  };
259
327
  const buildStoredProjection = (params) => {
260
- if (!params.latestEvent.id) throw new Error("Persisted subscription events must have an id");
261
328
  return {
262
329
  ...params.projection,
263
330
  tenantId: params.tenantId,
@@ -275,9 +342,8 @@ const projectAndStore = async (params) => {
275
342
  const latestEvent = [...events].sort((left, right) => {
276
343
  const occurredDelta = right.occurredAt.getTime() - left.occurredAt.getTime();
277
344
  if (occurredDelta !== 0) return occurredDelta;
278
- return (right.id ?? "").localeCompare(left.id ?? "");
345
+ return right.id.localeCompare(left.id);
279
346
  })[0];
280
- if (!latestEvent) return null;
281
347
  const storedProjection = buildStoredProjection({
282
348
  tenantId: params.tenantId,
283
349
  projection,
@@ -287,20 +353,25 @@ const projectAndStore = async (params) => {
287
353
  await params.storage.upsertProjection(storedProjection, params.transaction);
288
354
  return storedProjection;
289
355
  };
290
- const appendSubscriptionEvent = async (params) => runWithOptionalTransaction(params.storage, async (transaction) => {
291
- const event = await params.storage.createEvent(params.event, transaction);
292
- const projection = await projectAndStore({
293
- storage: params.storage,
294
- tenantId: params.tenantId,
295
- subscriptionId: event.subscriptionId,
296
- asOf: params.asOf ?? /* @__PURE__ */ new Date(),
297
- transaction
356
+ const appendSubscriptionEvent = async (params) => {
357
+ if (params.event.tenantId !== params.tenantId) {
358
+ throw new Error("Billing event tenantId does not match the requested tenant");
359
+ }
360
+ return runWithOptionalTransaction(params.storage, async (transaction) => {
361
+ const event = await params.storage.createEvent(params.event, transaction);
362
+ const projection = await projectAndStore({
363
+ storage: params.storage,
364
+ tenantId: params.tenantId,
365
+ subscriptionId: event.subscriptionId,
366
+ asOf: params.asOf ?? /* @__PURE__ */ new Date(),
367
+ transaction
368
+ });
369
+ return {
370
+ event,
371
+ projection
372
+ };
298
373
  });
299
- return {
300
- event,
301
- projection
302
- };
303
- });
374
+ };
304
375
  const rebuildSubscriptionProjection = async (params) => runWithOptionalTransaction(params.storage, (transaction) => projectAndStore({
305
376
  storage: params.storage,
306
377
  tenantId: params.tenantId,
@@ -313,7 +384,9 @@ const SUBSCRIPTION_INTERVAL_UNITS = ["month", "year"];
313
384
  const SUBSCRIPTION_TYPES = ["primary", "addon"];
314
385
  const SUBSCRIPTION_SCOPES = ["tenant", "workspace", "shop", "custom"];
315
386
  const SUBSCRIPTION_EVENT_TYPES = ["created", "plan_changed", "status_changed", "resumed", "canceled", "renewed"];
387
+ const SUBSCRIPTION_CHANGE_DIRECTIONS = ["upgrade", "downgrade", "lateral"];
316
388
  export {
389
+ SUBSCRIPTION_CHANGE_DIRECTIONS,
317
390
  SUBSCRIPTION_EVENT_TYPES,
318
391
  SUBSCRIPTION_INTERVAL_UNITS,
319
392
  SUBSCRIPTION_SCOPES,
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../src/calendar.ts","../src/proration.ts","../src/projection.ts","../src/segments.ts","../src/storage.ts","../src/types.ts"],"sourcesContent":["import type { SubscriptionIntervalUnit } from \"./types\"\n\n\nconst assertValidDate = (value: Date, field: string): Date => {\n const date = new Date(value)\n if (Number.isNaN(date.getTime())) throw new Error(`${field} must be a valid date`)\n return date\n}\n\nconst normalizeIntervalCount = (value: number): number => {\n if (!Number.isInteger(value) || value < 1) throw new Error(\"intervalCount must be a positive integer\")\n return value\n}\n\nconst getDaysInUtcMonth = (year: number, month: number): number =>\n new Date(Date.UTC(year, month + 1, 0)).getUTCDate()\n\nconst createClampedUtcDate = (source: Date, year: number, month: number): Date => {\n const day = Math.min(source.getUTCDate(), getDaysInUtcMonth(year, month))\n return new Date(Date.UTC(\n year,\n month,\n day,\n source.getUTCHours(),\n source.getUTCMinutes(),\n source.getUTCSeconds(),\n source.getUTCMilliseconds(),\n ))\n}\n\nexport const addBillingInterval = (\n value: Date,\n intervalUnit: SubscriptionIntervalUnit,\n intervalCount = 1,\n): Date => {\n const date = assertValidDate(value, \"value\")\n const count = normalizeIntervalCount(intervalCount)\n\n if (intervalUnit === \"year\") {\n return createClampedUtcDate(date, date.getUTCFullYear() + count, date.getUTCMonth())\n }\n\n const absoluteMonth = date.getUTCFullYear() * 12 + date.getUTCMonth() + count\n const year = Math.floor(absoluteMonth / 12)\n const month = ((absoluteMonth % 12) + 12) % 12\n return createClampedUtcDate(date, year, month)\n}\n\nconst getEstimatedPeriodIndex = (\n anchor: Date,\n asOf: Date,\n intervalUnit: SubscriptionIntervalUnit,\n intervalCount: number,\n): number => {\n if (asOf.getTime() <= anchor.getTime()) return 0\n\n const rawDifference = intervalUnit === \"year\"\n ? asOf.getUTCFullYear() - anchor.getUTCFullYear()\n : (asOf.getUTCFullYear() - anchor.getUTCFullYear()) * 12 + asOf.getUTCMonth() - anchor.getUTCMonth()\n\n return Math.max(0, Math.floor(rawDifference / intervalCount))\n}\n\nexport const resolveBillingPeriod = (params: {\n billingAnchor: Date\n intervalUnit: SubscriptionIntervalUnit\n intervalCount?: number\n asOf: Date\n}): { start: Date; end: Date } => {\n const anchor = assertValidDate(params.billingAnchor, \"billingAnchor\")\n const asOf = assertValidDate(params.asOf, \"asOf\")\n const intervalCount = normalizeIntervalCount(params.intervalCount ?? 1)\n\n let periodIndex = getEstimatedPeriodIndex(anchor, asOf, params.intervalUnit, intervalCount)\n let start = addBillingInterval(anchor, params.intervalUnit, Math.max(1, periodIndex * intervalCount))\n\n if (periodIndex === 0) start = new Date(anchor)\n\n while (start.getTime() > asOf.getTime() && periodIndex > 0) {\n periodIndex -= 1\n start = periodIndex === 0\n ? new Date(anchor)\n : addBillingInterval(anchor, params.intervalUnit, periodIndex * intervalCount)\n }\n\n let end = addBillingInterval(anchor, params.intervalUnit, (periodIndex + 1) * intervalCount)\n while (end.getTime() <= asOf.getTime()) {\n periodIndex += 1\n start = new Date(end)\n end = addBillingInterval(anchor, params.intervalUnit, (periodIndex + 1) * intervalCount)\n }\n\n return { start, end }\n}\n","const assertValidDate = (value: Date, field: string): Date => {\n const date = new Date(value)\n if (Number.isNaN(date.getTime())) throw new Error(`${field} must be a valid date`)\n return date\n}\n\nexport const calculateProratedAmount = (params: {\n unitAmount: number\n segmentStart: Date\n segmentEnd: Date\n periodStart: Date\n periodEnd: Date\n}): number => {\n if (!Number.isSafeInteger(params.unitAmount) || params.unitAmount < 0) {\n throw new Error(\"unitAmount must be a non-negative safe integer\")\n }\n\n const segmentStart = assertValidDate(params.segmentStart, \"segmentStart\")\n const segmentEnd = assertValidDate(params.segmentEnd, \"segmentEnd\")\n const periodStart = assertValidDate(params.periodStart, \"periodStart\")\n const periodEnd = assertValidDate(params.periodEnd, \"periodEnd\")\n const periodDuration = periodEnd.getTime() - periodStart.getTime()\n if (periodDuration <= 0) throw new Error(\"Billing period end must be after its start\")\n\n const overlapStart = Math.max(segmentStart.getTime(), periodStart.getTime())\n const overlapEnd = Math.min(segmentEnd.getTime(), periodEnd.getTime())\n const overlapDuration = Math.max(0, overlapEnd - overlapStart)\n\n return Math.round(params.unitAmount * overlapDuration / periodDuration)\n}\n","import { resolveBillingPeriod } from \"./calendar\"\nimport type {\n ScheduledPlanChange,\n SubscriptionEvent,\n SubscriptionProjection,\n SubscriptionStatus,\n} from \"./types\"\n\n\nconst assertValidDate = (value: Date, field: string): Date => {\n const date = new Date(value)\n if (Number.isNaN(date.getTime())) throw new Error(`${field} must be a valid date`)\n return date\n}\n\nconst compareEvents = (left: SubscriptionEvent, right: SubscriptionEvent): number => {\n const effectiveDelta = left.effectiveAt.getTime() - right.effectiveAt.getTime()\n if (effectiveDelta !== 0) return effectiveDelta\n\n const occurredDelta = left.occurredAt.getTime() - right.occurredAt.getTime()\n if (occurredDelta !== 0) return occurredDelta\n\n return (left.id ?? \"\").localeCompare(right.id ?? \"\")\n}\n\nexport const sortSubscriptionEvents = (events: readonly SubscriptionEvent[]): SubscriptionEvent[] =>\n events\n .map((event) => ({\n ...event,\n occurredAt: assertValidDate(event.occurredAt, \"occurredAt\"),\n effectiveAt: assertValidDate(event.effectiveAt, \"effectiveAt\"),\n billingAnchor: event.billingAnchor\n ? assertValidDate(event.billingAnchor, \"billingAnchor\")\n : undefined,\n }))\n .sort(compareEvents)\n\nconst getEffectiveEvents = (events: readonly SubscriptionEvent[]): SubscriptionEvent[] => {\n const ordered = sortSubscriptionEvents(events)\n const supersededIds = new Set(\n ordered\n .map((event) => event.supersedesEventId)\n .filter((eventId): eventId is string => Boolean(eventId)),\n )\n const inferredSupersededEvents = new Set<SubscriptionEvent>()\n\n for (const cancellation of ordered) {\n if (\n cancellation.type !== \"canceled\"\n || cancellation.effectiveAt.getTime() <= cancellation.occurredAt.getTime()\n || (cancellation.id && supersededIds.has(cancellation.id))\n ) {\n continue\n }\n\n const laterResume = ordered.find((candidate) =>\n candidate.type === \"resumed\"\n && candidate.occurredAt.getTime() > cancellation.occurredAt.getTime()\n && candidate.effectiveAt.getTime() <= cancellation.effectiveAt.getTime(),\n )\n\n if (laterResume) inferredSupersededEvents.add(cancellation)\n }\n\n return ordered.filter((event) =>\n !(event.id && supersededIds.has(event.id))\n && !inferredSupersededEvents.has(event),\n )\n}\n\nconst assertSingleSubscription = (events: readonly SubscriptionEvent[]): string => {\n const subscriptionIds = new Set(events.map((event) => event.subscriptionId))\n if (subscriptionIds.size > 1) throw new Error(\"Events from multiple subscriptions cannot be projected together\")\n return events[0]?.subscriptionId ?? \"\"\n}\n\nconst getStatusForEvent = (\n event: SubscriptionEvent,\n currentStatus: SubscriptionStatus,\n): SubscriptionStatus => {\n if (event.toStatus) return event.toStatus\n if (event.type === \"created\" || event.type === \"resumed\") return \"active\"\n if (event.type === \"canceled\") return \"canceled\"\n return currentStatus\n}\n\nexport const projectSubscription = (\n events: readonly SubscriptionEvent[],\n options: { asOf?: Date } = {},\n): SubscriptionProjection | null => {\n if (events.length === 0) return null\n\n const subscriptionId = assertSingleSubscription(events)\n const ordered = getEffectiveEvents(events)\n const asOf = assertValidDate(options.asOf ?? new Date(), \"asOf\")\n const applicable = ordered.filter((event) => event.effectiveAt.getTime() <= asOf.getTime())\n if (applicable.length === 0) return null\n\n const firstEvent = applicable[0]\n let type = firstEvent.subscriptionType ?? \"primary\"\n let parentSubscriptionId = firstEvent.parentSubscriptionId ?? null\n let scope = firstEvent.scope ?? \"tenant\"\n let scopeId = firstEvent.scopeId ?? null\n let planKey = \"\"\n let priceId: string | null = null\n let status: SubscriptionStatus = \"active\"\n let intervalUnit = firstEvent.toIntervalUnit ?? \"month\"\n let intervalCount = firstEvent.toIntervalCount ?? 1\n let modules: string[] = []\n let billingAnchor = firstEvent.billingAnchor ?? firstEvent.effectiveAt\n let provider: string | null = null\n let canceledAt: Date | null = null\n\n for (const event of applicable) {\n type = event.subscriptionType ?? type\n parentSubscriptionId = event.parentSubscriptionId ?? parentSubscriptionId\n scope = event.scope ?? scope\n scopeId = event.scopeId ?? scopeId\n planKey = event.toPlanKey ?? planKey\n priceId = event.toPriceId ?? priceId\n status = getStatusForEvent(event, status)\n intervalUnit = event.toIntervalUnit ?? intervalUnit\n intervalCount = event.toIntervalCount ?? intervalCount\n modules = event.toModules ? [...event.toModules] : modules\n billingAnchor = event.billingAnchor ?? billingAnchor\n provider = event.provider ?? provider\n\n if (event.type === \"canceled\") {\n canceledAt = new Date(event.effectiveAt)\n } else if (event.type === \"created\" || event.type === \"resumed\") {\n canceledAt = null\n }\n }\n\n if (!planKey) return null\n if (!Number.isInteger(intervalCount) || intervalCount < 1) {\n throw new Error(\"Subscription intervalCount must be a positive integer\")\n }\n\n const futureEvents = ordered.filter((event) => event.effectiveAt.getTime() > asOf.getTime())\n const scheduledCancellation = futureEvents.find((event) => event.type === \"canceled\") ?? null\n const scheduledPlanEvent = futureEvents.find((event) => event.type === \"plan_changed\" && event.toPlanKey) ?? null\n const scheduledPlan: ScheduledPlanChange | null = scheduledPlanEvent?.toPlanKey\n ? {\n planKey: scheduledPlanEvent.toPlanKey,\n effectiveAt: new Date(scheduledPlanEvent.effectiveAt),\n }\n : null\n\n const periodAsOf = canceledAt && canceledAt.getTime() <= asOf.getTime()\n ? new Date(canceledAt.getTime() - 1)\n : asOf\n const period = resolveBillingPeriod({\n billingAnchor,\n intervalUnit,\n intervalCount,\n asOf: periodAsOf,\n })\n\n return {\n subscriptionId,\n type,\n parentSubscriptionId,\n scope,\n scopeId,\n planKey,\n priceId,\n status,\n intervalUnit,\n intervalCount,\n modules,\n billingAnchor: new Date(billingAnchor),\n currentPeriodStart: period.start,\n currentPeriodEnd: period.end,\n cancelAtPeriodEnd: status !== \"canceled\" && Boolean(scheduledCancellation),\n cancelAt: scheduledCancellation\n ? new Date(scheduledCancellation.effectiveAt)\n : canceledAt\n ? new Date(canceledAt)\n : null,\n canceledAt: canceledAt ? new Date(canceledAt) : null,\n scheduledPlan,\n provider,\n }\n}\n\nexport const getSubscriptionTransitionDates = (\n events: readonly SubscriptionEvent[],\n params: { after: Date; before: Date },\n): Date[] => {\n assertSingleSubscription(events)\n const after = assertValidDate(params.after, \"after\")\n const before = assertValidDate(params.before, \"before\")\n\n return [...new Set(\n getEffectiveEvents(events)\n .map((event) => event.effectiveAt.getTime())\n .filter((time) => time > after.getTime() && time < before.getTime()),\n )]\n .sort((left, right) => left - right)\n .map((time) => new Date(time))\n}\n","import { getSubscriptionTransitionDates, projectSubscription } from \"./projection\"\nimport type {\n BillableSubscriptionSegment,\n SubscriptionEvent,\n SubscriptionStatus,\n} from \"./types\"\n\n\nconst DEFAULT_BILLABLE_STATUSES: readonly SubscriptionStatus[] = [\"active\"]\n\nconst assertValidWindow = (from: Date, to: Date): { from: Date; to: Date } => {\n const normalizedFrom = new Date(from)\n const normalizedTo = new Date(to)\n if (Number.isNaN(normalizedFrom.getTime()) || Number.isNaN(normalizedTo.getTime())) {\n throw new Error(\"Billing segment window must contain valid dates\")\n }\n if (normalizedTo.getTime() <= normalizedFrom.getTime()) {\n throw new Error(\"Billing segment window end must be after its start\")\n }\n return { from: normalizedFrom, to: normalizedTo }\n}\n\nexport const buildBillableSegments = (\n events: readonly SubscriptionEvent[],\n params: {\n from: Date\n to: Date\n billableStatuses?: readonly SubscriptionStatus[]\n },\n): BillableSubscriptionSegment[] => {\n if (events.length === 0) return []\n\n const window = assertValidWindow(params.from, params.to)\n const billableStatuses = new Set(params.billableStatuses ?? DEFAULT_BILLABLE_STATUSES)\n const transitionDates = getSubscriptionTransitionDates(events, {\n after: window.from,\n before: window.to,\n })\n const segments: BillableSubscriptionSegment[] = []\n let cursor = new Date(window.from)\n\n while (cursor.getTime() < window.to.getTime()) {\n const projection = projectSubscription(events, { asOf: cursor })\n const nextTransition = transitionDates.find((date) => date.getTime() > cursor.getTime()) ?? null\n const nextPeriodEnd = projection && projection.currentPeriodEnd.getTime() > cursor.getTime()\n ? projection.currentPeriodEnd\n : null\n const candidateTimes = [\n window.to.getTime(),\n nextTransition?.getTime() ?? Number.POSITIVE_INFINITY,\n nextPeriodEnd?.getTime() ?? Number.POSITIVE_INFINITY,\n ]\n const nextTime = Math.min(...candidateTimes)\n\n if (!Number.isFinite(nextTime) || nextTime <= cursor.getTime()) {\n throw new Error(\"Unable to advance while building billing segments\")\n }\n\n const next = new Date(nextTime)\n if (projection && billableStatuses.has(projection.status)) {\n segments.push({\n subscriptionId: projection.subscriptionId,\n planKey: projection.planKey,\n priceId: projection.priceId,\n status: projection.status,\n modules: [...projection.modules],\n start: new Date(cursor),\n end: next,\n periodStart: new Date(projection.currentPeriodStart),\n periodEnd: new Date(projection.currentPeriodEnd),\n })\n }\n\n cursor = next\n }\n\n return segments\n}\n","import { projectSubscription } from \"./projection\"\nimport type {\n StoredSubscriptionProjection,\n SubscriptionEvent,\n SubscriptionProjection,\n} from \"./types\"\n\n\nexport type BillingStorageTransaction = unknown\n\nexport type BillingStorage = {\n runInTransaction?: <T>(operation: (transaction: BillingStorageTransaction) => Promise<T>) => Promise<T>\n createEvent: (\n event: SubscriptionEvent,\n transaction?: BillingStorageTransaction,\n ) => Promise<SubscriptionEvent>\n listEvents: (\n tenantId: string,\n subscriptionId: string,\n transaction?: BillingStorageTransaction,\n ) => Promise<SubscriptionEvent[]>\n upsertProjection: (\n projection: StoredSubscriptionProjection,\n transaction?: BillingStorageTransaction,\n ) => Promise<void>\n}\n\nconst runWithOptionalTransaction = async <T>(\n storage: BillingStorage,\n operation: (transaction?: BillingStorageTransaction) => Promise<T>,\n): Promise<T> => {\n if (!storage.runInTransaction) return operation()\n return storage.runInTransaction((transaction) => operation(transaction))\n}\n\nconst buildStoredProjection = (params: {\n tenantId: string\n projection: SubscriptionProjection\n latestEvent: SubscriptionEvent\n projectedAt: Date\n}): StoredSubscriptionProjection => {\n if (!params.latestEvent.id) throw new Error(\"Persisted subscription events must have an id\")\n\n return {\n ...params.projection,\n tenantId: params.tenantId,\n latestEventId: params.latestEvent.id,\n latestEventAt: new Date(params.latestEvent.occurredAt),\n projectedAt: new Date(params.projectedAt),\n }\n}\n\nconst projectAndStore = async (params: {\n storage: BillingStorage\n tenantId: string\n subscriptionId: string\n asOf: Date\n transaction?: BillingStorageTransaction\n}): Promise<StoredSubscriptionProjection | null> => {\n const events = await params.storage.listEvents(\n params.tenantId,\n params.subscriptionId,\n params.transaction,\n )\n const projection = projectSubscription(events, { asOf: params.asOf })\n if (!projection) return null\n\n const latestEvent = [...events].sort((left, right) => {\n const occurredDelta = right.occurredAt.getTime() - left.occurredAt.getTime()\n if (occurredDelta !== 0) return occurredDelta\n return (right.id ?? \"\").localeCompare(left.id ?? \"\")\n })[0]\n if (!latestEvent) return null\n\n const storedProjection = buildStoredProjection({\n tenantId: params.tenantId,\n projection,\n latestEvent,\n projectedAt: params.asOf,\n })\n await params.storage.upsertProjection(storedProjection, params.transaction)\n return storedProjection\n}\n\nexport const appendSubscriptionEvent = async (params: {\n storage: BillingStorage\n tenantId: string\n event: SubscriptionEvent\n asOf?: Date\n}): Promise<{\n event: SubscriptionEvent\n projection: StoredSubscriptionProjection | null\n}> => runWithOptionalTransaction(params.storage, async (transaction) => {\n const event = await params.storage.createEvent(params.event, transaction)\n const projection = await projectAndStore({\n storage: params.storage,\n tenantId: params.tenantId,\n subscriptionId: event.subscriptionId,\n asOf: params.asOf ?? new Date(),\n transaction,\n })\n\n return { event, projection }\n})\n\nexport const rebuildSubscriptionProjection = async (params: {\n storage: BillingStorage\n tenantId: string\n subscriptionId: string\n asOf?: Date\n}): Promise<StoredSubscriptionProjection | null> => runWithOptionalTransaction(\n params.storage,\n (transaction) => projectAndStore({\n storage: params.storage,\n tenantId: params.tenantId,\n subscriptionId: params.subscriptionId,\n asOf: params.asOf ?? new Date(),\n transaction,\n }),\n)\n","export const SUBSCRIPTION_STATUSES = [\n \"trialing\",\n \"active\",\n \"past_due\",\n \"paused\",\n \"canceled\",\n \"expired\",\n] as const\n\nexport type SubscriptionStatus = typeof SUBSCRIPTION_STATUSES[number]\n\nexport const SUBSCRIPTION_INTERVAL_UNITS = [\"month\", \"year\"] as const\n\nexport type SubscriptionIntervalUnit = typeof SUBSCRIPTION_INTERVAL_UNITS[number]\n\nexport const SUBSCRIPTION_TYPES = [\"primary\", \"addon\"] as const\n\nexport type SubscriptionType = typeof SUBSCRIPTION_TYPES[number]\n\nexport const SUBSCRIPTION_SCOPES = [\"tenant\", \"workspace\", \"shop\", \"custom\"] as const\n\nexport type SubscriptionScope = typeof SUBSCRIPTION_SCOPES[number]\n\nexport const SUBSCRIPTION_EVENT_TYPES = [\n \"created\",\n \"plan_changed\",\n \"status_changed\",\n \"resumed\",\n \"canceled\",\n \"renewed\",\n] as const\n\nexport type SubscriptionEventType = typeof SUBSCRIPTION_EVENT_TYPES[number]\n\nexport type SubscriptionEvent = {\n id?: string\n tenantId?: string\n subscriptionId: string\n type: SubscriptionEventType\n occurredAt: Date\n effectiveAt: Date\n subscriptionType?: SubscriptionType\n parentSubscriptionId?: string\n scope?: SubscriptionScope\n scopeId?: string\n fromPlanKey?: string\n toPlanKey?: string\n fromStatus?: SubscriptionStatus\n toStatus?: SubscriptionStatus\n fromModules?: string[]\n toModules?: string[]\n fromIntervalUnit?: SubscriptionIntervalUnit\n toIntervalUnit?: SubscriptionIntervalUnit\n fromIntervalCount?: number\n toIntervalCount?: number\n fromPriceId?: string\n toPriceId?: string\n billingAnchor?: Date\n supersedesEventId?: string\n idempotencyKey?: string\n actorUserId?: string\n source?: \"admin\" | \"system\" | \"webhook\" | \"user\"\n reason?: string\n provider?: string\n providerEventId?: string\n metadata?: Record<string, unknown>\n}\n\nexport type ScheduledPlanChange = {\n planKey: string\n effectiveAt: Date\n}\n\nexport type SubscriptionProjection = {\n subscriptionId: string\n type: SubscriptionType\n parentSubscriptionId: string | null\n scope: SubscriptionScope\n scopeId: string | null\n planKey: string\n priceId: string | null\n status: SubscriptionStatus\n intervalUnit: SubscriptionIntervalUnit\n intervalCount: number\n modules: string[]\n billingAnchor: Date\n currentPeriodStart: Date\n currentPeriodEnd: Date\n cancelAtPeriodEnd: boolean\n cancelAt: Date | null\n canceledAt: Date | null\n scheduledPlan: ScheduledPlanChange | null\n provider: string | null\n}\n\nexport type BillableSubscriptionSegment = {\n subscriptionId: string\n planKey: string\n priceId: string | null\n status: SubscriptionStatus\n modules: string[]\n start: Date\n end: Date\n periodStart: Date\n periodEnd: Date\n}\n\nexport type StoredSubscriptionProjection = SubscriptionProjection & {\n tenantId: string\n latestEventId: string\n latestEventAt: Date\n projectedAt: Date\n}\n"],"names":["assertValidDate","value","field","date","Date","Number","isNaN","getTime","Error","normalizeIntervalCount","isInteger","getDaysInUtcMonth","year","month","UTC","getUTCDate","createClampedUtcDate","source","day","Math","min","getUTCHours","getUTCMinutes","getUTCSeconds","getUTCMilliseconds","addBillingInterval","intervalUnit","intervalCount","count","getUTCFullYear","getUTCMonth","absoluteMonth","floor","getEstimatedPeriodIndex","anchor","asOf","rawDifference","max","resolveBillingPeriod","params","billingAnchor","periodIndex","start","end","calculateProratedAmount","isSafeInteger","unitAmount","segmentStart","segmentEnd","periodStart","periodEnd","periodDuration","overlapStart","overlapEnd","overlapDuration","round","compareEvents","left","right","effectiveDelta","effectiveAt","occurredDelta","occurredAt","id","localeCompare","sortSubscriptionEvents","events","map","event","undefined","sort","getEffectiveEvents","ordered","supersededIds","Set","supersedesEventId","filter","eventId","Boolean","inferredSupersededEvents","cancellation","type","has","laterResume","find","candidate","add","assertSingleSubscription","subscriptionIds","subscriptionId","size","getStatusForEvent","currentStatus","toStatus","projectSubscription","options","length","applicable","firstEvent","subscriptionType","parentSubscriptionId","scope","scopeId","planKey","priceId","status","toIntervalUnit","toIntervalCount","modules","provider","canceledAt","toPlanKey","toPriceId","toModules","futureEvents","scheduledCancellation","scheduledPlanEvent","scheduledPlan","periodAsOf","period","currentPeriodStart","currentPeriodEnd","cancelAtPeriodEnd","cancelAt","getSubscriptionTransitionDates","after","before","time","DEFAULT_BILLABLE_STATUSES","assertValidWindow","from","to","normalizedFrom","normalizedTo","buildBillableSegments","window","billableStatuses","transitionDates","segments","cursor","projection","nextTransition","nextPeriodEnd","candidateTimes","POSITIVE_INFINITY","nextTime","isFinite","next","push","runWithOptionalTransaction","storage","operation","runInTransaction","transaction","buildStoredProjection","latestEvent","tenantId","latestEventId","latestEventAt","projectedAt","projectAndStore","listEvents","storedProjection","upsertProjection","appendSubscriptionEvent","createEvent","rebuildSubscriptionProjection","SUBSCRIPTION_STATUSES","SUBSCRIPTION_INTERVAL_UNITS","SUBSCRIPTION_TYPES","SUBSCRIPTION_SCOPES","SUBSCRIPTION_EVENT_TYPES"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sources":["../src/calendar.ts","../src/proration.ts","../src/projection.ts","../src/segments.ts","../src/storage.ts","../src/types.ts"],"sourcesContent":["import type { SubscriptionIntervalUnit } from \"./types\"\n\n\nconst assertValidDate = (value: Date, field: string): Date => {\n const date = new Date(value)\n if (Number.isNaN(date.getTime())) throw new Error(`${field} must be a valid date`)\n return date\n}\n\nconst normalizeIntervalCount = (value: number): number => {\n if (!Number.isInteger(value) || value < 1) throw new Error(\"intervalCount must be a positive integer\")\n return value\n}\n\nconst getDaysInUtcMonth = (year: number, month: number): number =>\n new Date(Date.UTC(year, month + 1, 0)).getUTCDate()\n\nconst createClampedUtcDate = (source: Date, year: number, month: number): Date => {\n const day = Math.min(source.getUTCDate(), getDaysInUtcMonth(year, month))\n return new Date(Date.UTC(\n year,\n month,\n day,\n source.getUTCHours(),\n source.getUTCMinutes(),\n source.getUTCSeconds(),\n source.getUTCMilliseconds(),\n ))\n}\n\nexport const addBillingInterval = (\n value: Date,\n intervalUnit: SubscriptionIntervalUnit,\n intervalCount = 1,\n): Date => {\n const date = assertValidDate(value, \"value\")\n const count = normalizeIntervalCount(intervalCount)\n\n if (intervalUnit === \"year\") {\n return createClampedUtcDate(date, date.getUTCFullYear() + count, date.getUTCMonth())\n }\n\n const absoluteMonth = date.getUTCFullYear() * 12 + date.getUTCMonth() + count\n const year = Math.floor(absoluteMonth / 12)\n const month = ((absoluteMonth % 12) + 12) % 12\n return createClampedUtcDate(date, year, month)\n}\n\nconst getEstimatedPeriodIndex = (\n anchor: Date,\n asOf: Date,\n intervalUnit: SubscriptionIntervalUnit,\n intervalCount: number,\n): number => {\n if (asOf.getTime() <= anchor.getTime()) return 0\n\n const rawDifference = intervalUnit === \"year\"\n ? asOf.getUTCFullYear() - anchor.getUTCFullYear()\n : (asOf.getUTCFullYear() - anchor.getUTCFullYear()) * 12 + asOf.getUTCMonth() - anchor.getUTCMonth()\n\n return Math.max(0, Math.floor(rawDifference / intervalCount))\n}\n\nexport const resolveBillingPeriod = (params: {\n billingAnchor: Date\n intervalUnit: SubscriptionIntervalUnit\n intervalCount?: number\n asOf: Date\n}): { start: Date; end: Date } => {\n const anchor = assertValidDate(params.billingAnchor, \"billingAnchor\")\n const asOf = assertValidDate(params.asOf, \"asOf\")\n const intervalCount = normalizeIntervalCount(params.intervalCount ?? 1)\n\n let periodIndex = getEstimatedPeriodIndex(anchor, asOf, params.intervalUnit, intervalCount)\n let start = addBillingInterval(anchor, params.intervalUnit, Math.max(1, periodIndex * intervalCount))\n\n if (periodIndex === 0) start = new Date(anchor)\n\n while (start.getTime() > asOf.getTime() && periodIndex > 0) {\n periodIndex -= 1\n start = periodIndex === 0\n ? new Date(anchor)\n : addBillingInterval(anchor, params.intervalUnit, periodIndex * intervalCount)\n }\n\n let end = addBillingInterval(anchor, params.intervalUnit, (periodIndex + 1) * intervalCount)\n while (end.getTime() <= asOf.getTime()) {\n periodIndex += 1\n start = new Date(end)\n end = addBillingInterval(anchor, params.intervalUnit, (periodIndex + 1) * intervalCount)\n }\n\n return { start, end }\n}\n","const assertValidDate = (value: Date, field: string): Date => {\n const date = new Date(value)\n if (Number.isNaN(date.getTime())) throw new Error(`${field} must be a valid date`)\n return date\n}\n\nexport const calculateProratedAmount = (params: {\n unitAmount: number\n segmentStart: Date\n segmentEnd: Date\n periodStart: Date\n periodEnd: Date\n}): number => {\n if (!Number.isSafeInteger(params.unitAmount) || params.unitAmount < 0) {\n throw new Error(\"unitAmount must be a non-negative safe integer\")\n }\n\n const segmentStart = assertValidDate(params.segmentStart, \"segmentStart\")\n const segmentEnd = assertValidDate(params.segmentEnd, \"segmentEnd\")\n const periodStart = assertValidDate(params.periodStart, \"periodStart\")\n const periodEnd = assertValidDate(params.periodEnd, \"periodEnd\")\n const periodDuration = periodEnd.getTime() - periodStart.getTime()\n if (periodDuration <= 0) throw new Error(\"Billing period end must be after its start\")\n\n const overlapStart = Math.max(segmentStart.getTime(), periodStart.getTime())\n const overlapEnd = Math.min(segmentEnd.getTime(), periodEnd.getTime())\n const overlapDuration = Math.max(0, overlapEnd - overlapStart)\n\n return Math.round(params.unitAmount * overlapDuration / periodDuration)\n}\n","import { resolveBillingPeriod } from \"./calendar\"\nimport type {\n ScheduledPlanChange,\n SubscriptionCreatedEvent,\n SubscriptionEvent,\n SubscriptionProjection,\n SubscriptionStatus,\n} from \"./types\"\n\n\nconst assertValidDate = (value: Date, field: string): Date => {\n const date = new Date(value)\n if (Number.isNaN(date.getTime())) throw new Error(`${field} must be a valid date`)\n return date\n}\n\nconst compareEvents = (left: SubscriptionEvent, right: SubscriptionEvent): number => {\n const effectiveDelta = left.effectiveAt.getTime() - right.effectiveAt.getTime()\n if (effectiveDelta !== 0) return effectiveDelta\n\n const occurredDelta = left.occurredAt.getTime() - right.occurredAt.getTime()\n if (occurredDelta !== 0) return occurredDelta\n\n return (left.id ?? \"\").localeCompare(right.id ?? \"\")\n}\n\nexport const sortSubscriptionEvents = (events: readonly SubscriptionEvent[]): SubscriptionEvent[] =>\n events\n .map((event): SubscriptionEvent => {\n const dates = {\n occurredAt: assertValidDate(event.occurredAt, \"occurredAt\"),\n effectiveAt: assertValidDate(event.effectiveAt, \"effectiveAt\"),\n }\n if (event.type === \"created\") {\n return {\n ...event,\n ...dates,\n billingAnchor: assertValidDate(event.billingAnchor, \"billingAnchor\"),\n }\n }\n return {\n ...event,\n ...dates,\n billingAnchor: event.billingAnchor\n ? assertValidDate(event.billingAnchor, \"billingAnchor\")\n : undefined,\n }\n })\n .sort(compareEvents)\n\nconst getEffectiveEvents = (events: readonly SubscriptionEvent[]): SubscriptionEvent[] => {\n const ordered = sortSubscriptionEvents(events)\n const supersededIds = new Set(\n ordered\n .map((event) => event.supersedesEventId)\n .filter((eventId): eventId is string => Boolean(eventId)),\n )\n\n return ordered.filter((event) =>\n !(event.id && supersededIds.has(event.id)),\n )\n}\n\nconst assertSingleSubscription = (events: readonly SubscriptionEvent[]): string => {\n if (events.length === 0) throw new Error(\"At least one subscription event is required\")\n const subscriptionIds = new Set(events.map((event) => event.subscriptionId))\n if (subscriptionIds.size > 1) throw new Error(\"Events from multiple subscriptions cannot be projected together\")\n const tenantIds = new Set(events.map((event) => event.tenantId))\n if (tenantIds.size > 1) throw new Error(\"Events from multiple tenants cannot be projected together\")\n return events[0]!.subscriptionId\n}\n\nconst assertNonEmptyString = (value: unknown, field: string): void => {\n if (typeof value !== \"string\" || !value.trim()) throw new Error(`${field} is required`)\n}\n\nconst assertPositiveInteger = (value: unknown, field: string): void => {\n if (!Number.isInteger(value) || Number(value) < 1) throw new Error(`${field} must be a positive integer`)\n}\n\nfunction assertCreatedEvent(\n event: SubscriptionEvent,\n): asserts event is SubscriptionCreatedEvent {\n if (event.type !== \"created\") throw new Error(\"The first subscription event must be created\")\n assertNonEmptyString(event.tenantId, \"tenantId\")\n assertNonEmptyString(event.subscriptionId, \"subscriptionId\")\n if (!event.subscriptionType) throw new Error(\"subscriptionType is required\")\n if (!event.scope) throw new Error(\"scope is required\")\n if (event.subscriptionType === \"addon\") assertNonEmptyString(event.parentSubscriptionId, \"parentSubscriptionId\")\n if (event.scope !== \"tenant\") assertNonEmptyString(event.scopeId, \"scopeId\")\n assertNonEmptyString(event.toPlanKey, \"toPlanKey\")\n if (!event.toStatus) throw new Error(\"Created subscription events require toStatus\")\n if (!Array.isArray(event.toModules)) throw new Error(\"Created subscription events require toModules\")\n if (!event.toIntervalUnit) throw new Error(\"Created subscription events require toIntervalUnit\")\n assertPositiveInteger(event.toIntervalCount, \"toIntervalCount\")\n assertValidDate(event.billingAnchor, \"billingAnchor\")\n}\n\nconst assertTransitionEvent = (event: SubscriptionEvent): void => {\n assertNonEmptyString(event.idempotencyKey, \"idempotencyKey\")\n switch (event.type) {\n case \"created\":\n assertCreatedEvent(event)\n return\n case \"plan_changed\":\n assertNonEmptyString(event.fromPlanKey, \"fromPlanKey\")\n assertNonEmptyString(event.toPlanKey, \"toPlanKey\")\n if (!Array.isArray(event.fromModules)) throw new Error(\"Plan changes require fromModules\")\n if (!Array.isArray(event.toModules)) throw new Error(\"Plan changes require toModules\")\n if (!event.fromIntervalUnit) throw new Error(\"Plan changes require fromIntervalUnit\")\n if (!event.toIntervalUnit) throw new Error(\"Plan changes require toIntervalUnit\")\n assertPositiveInteger(event.fromIntervalCount, \"fromIntervalCount\")\n assertPositiveInteger(event.toIntervalCount, \"toIntervalCount\")\n return\n case \"status_changed\":\n if (!event.fromStatus || !event.toStatus) throw new Error(\"Status changes require fromStatus and toStatus\")\n return\n case \"resumed\":\n if (!event.fromStatus || event.toStatus !== \"active\") {\n throw new Error(\"Resumed events require fromStatus and active toStatus\")\n }\n return\n case \"canceled\":\n if (!event.fromStatus || event.toStatus !== \"canceled\") {\n throw new Error(\"Canceled events require fromStatus and canceled toStatus\")\n }\n return\n case \"renewed\":\n if (!event.fromStatus || !event.toStatus) throw new Error(\"Renewed events require fromStatus and toStatus\")\n }\n}\n\nconst assertConsistentEventEnvelope = (\n event: SubscriptionEvent,\n created: SubscriptionCreatedEvent,\n): void => {\n if (event.tenantId !== created.tenantId) throw new Error(\"Subscription event tenantId cannot change\")\n if (event.subscriptionType !== created.subscriptionType) {\n throw new Error(\"Subscription event subscriptionType cannot change\")\n }\n if ((event.parentSubscriptionId ?? null) !== (created.parentSubscriptionId ?? null)) {\n throw new Error(\"Subscription event parentSubscriptionId cannot change\")\n }\n if (event.scope !== created.scope) throw new Error(\"Subscription event scope cannot change\")\n if ((event.scopeId ?? null) !== (created.scopeId ?? null)) {\n throw new Error(\"Subscription event scopeId cannot change\")\n }\n}\n\nexport const projectSubscription = (\n events: readonly SubscriptionEvent[],\n options: { asOf?: Date } = {},\n): SubscriptionProjection | null => {\n if (events.length === 0) return null\n\n const subscriptionId = assertSingleSubscription(events)\n const ordered = getEffectiveEvents(events)\n const created = ordered[0]!\n assertCreatedEvent(created)\n ordered.forEach((event, index) => {\n if (index > 0 && event.type === \"created\") {\n throw new Error(\"A subscription event stream cannot contain multiple created events\")\n }\n assertTransitionEvent(event)\n assertConsistentEventEnvelope(event, created)\n })\n\n const asOf = assertValidDate(options.asOf ?? new Date(), \"asOf\")\n const applicable = ordered.filter((event) => event.effectiveAt.getTime() <= asOf.getTime())\n if (applicable.length === 0) return null\n\n const type = created.subscriptionType\n const parentSubscriptionId = created.parentSubscriptionId ?? null\n const scope = created.scope\n const scopeId = created.scopeId ?? null\n let planKey = created.toPlanKey\n let priceId: string | null = null\n let status: SubscriptionStatus = created.toStatus\n let intervalUnit = created.toIntervalUnit\n let intervalCount = created.toIntervalCount\n let modules = [...created.toModules]\n let billingAnchor = created.billingAnchor\n let provider: string | null = null\n let canceledAt: Date | null = null\n\n for (const event of applicable.slice(1)) {\n planKey = event.toPlanKey ?? planKey\n priceId = event.toPriceId ?? priceId\n status = event.toStatus ?? status\n intervalUnit = event.toIntervalUnit ?? intervalUnit\n intervalCount = event.toIntervalCount ?? intervalCount\n modules = event.toModules ? [...event.toModules] : modules\n billingAnchor = event.billingAnchor ?? billingAnchor\n provider = event.provider ?? provider\n\n if (event.type === \"canceled\") {\n canceledAt = new Date(event.effectiveAt)\n } else if (event.type === \"resumed\") {\n canceledAt = null\n }\n }\n\n const futureEvents = ordered.filter((event) => event.effectiveAt.getTime() > asOf.getTime())\n const scheduledCancellation = futureEvents.find((event) => event.type === \"canceled\") ?? null\n const scheduledPlanEvent = futureEvents.find((event) => event.type === \"plan_changed\") ?? null\n const scheduledPlan: ScheduledPlanChange | null = scheduledPlanEvent\n ? {\n planKey: scheduledPlanEvent.toPlanKey,\n effectiveAt: new Date(scheduledPlanEvent.effectiveAt),\n }\n : null\n\n const periodAsOf = canceledAt && canceledAt.getTime() <= asOf.getTime()\n ? new Date(canceledAt.getTime() - 1)\n : asOf\n const period = resolveBillingPeriod({\n billingAnchor,\n intervalUnit,\n intervalCount,\n asOf: periodAsOf,\n })\n\n return {\n subscriptionId,\n type,\n parentSubscriptionId,\n scope,\n scopeId,\n planKey,\n priceId,\n status,\n intervalUnit,\n intervalCount,\n modules,\n billingAnchor: new Date(billingAnchor),\n currentPeriodStart: period.start,\n currentPeriodEnd: period.end,\n cancelAtPeriodEnd: status !== \"canceled\" && Boolean(scheduledCancellation),\n cancelAt: scheduledCancellation\n ? new Date(scheduledCancellation.effectiveAt)\n : canceledAt\n ? new Date(canceledAt)\n : null,\n canceledAt: canceledAt ? new Date(canceledAt) : null,\n scheduledPlan,\n provider,\n }\n}\n\nexport const getSubscriptionTransitionDates = (\n events: readonly SubscriptionEvent[],\n params: { after: Date; before: Date },\n): Date[] => {\n assertSingleSubscription(events)\n const after = assertValidDate(params.after, \"after\")\n const before = assertValidDate(params.before, \"before\")\n\n return [...new Set(\n getEffectiveEvents(events)\n .map((event) => event.effectiveAt.getTime())\n .filter((time) => time > after.getTime() && time < before.getTime()),\n )]\n .sort((left, right) => left - right)\n .map((time) => new Date(time))\n}\n","import { getSubscriptionTransitionDates, projectSubscription } from \"./projection\"\nimport type {\n BillableSubscriptionSegment,\n SubscriptionEvent,\n SubscriptionStatus,\n} from \"./types\"\n\n\nconst DEFAULT_BILLABLE_STATUSES: readonly SubscriptionStatus[] = [\"active\"]\n\nconst assertValidWindow = (from: Date, to: Date): { from: Date; to: Date } => {\n const normalizedFrom = new Date(from)\n const normalizedTo = new Date(to)\n if (Number.isNaN(normalizedFrom.getTime()) || Number.isNaN(normalizedTo.getTime())) {\n throw new Error(\"Billing segment window must contain valid dates\")\n }\n if (normalizedTo.getTime() <= normalizedFrom.getTime()) {\n throw new Error(\"Billing segment window end must be after its start\")\n }\n return { from: normalizedFrom, to: normalizedTo }\n}\n\nexport const buildBillableSegments = (\n events: readonly SubscriptionEvent[],\n params: {\n from: Date\n to: Date\n billableStatuses?: readonly SubscriptionStatus[]\n },\n): BillableSubscriptionSegment[] => {\n if (events.length === 0) return []\n\n const window = assertValidWindow(params.from, params.to)\n const billableStatuses = new Set(params.billableStatuses ?? DEFAULT_BILLABLE_STATUSES)\n const transitionDates = getSubscriptionTransitionDates(events, {\n after: window.from,\n before: window.to,\n })\n const segments: BillableSubscriptionSegment[] = []\n let cursor = new Date(window.from)\n\n while (cursor.getTime() < window.to.getTime()) {\n const projection = projectSubscription(events, { asOf: cursor })\n const nextTransition = transitionDates.find((date) => date.getTime() > cursor.getTime()) ?? null\n const nextPeriodEnd = projection && projection.currentPeriodEnd.getTime() > cursor.getTime()\n ? projection.currentPeriodEnd\n : null\n const candidateTimes = [\n window.to.getTime(),\n nextTransition?.getTime() ?? Number.POSITIVE_INFINITY,\n nextPeriodEnd?.getTime() ?? Number.POSITIVE_INFINITY,\n ]\n const nextTime = Math.min(...candidateTimes)\n\n if (!Number.isFinite(nextTime) || nextTime <= cursor.getTime()) {\n throw new Error(\"Unable to advance while building billing segments\")\n }\n\n const next = new Date(nextTime)\n if (projection && billableStatuses.has(projection.status)) {\n segments.push({\n subscriptionId: projection.subscriptionId,\n planKey: projection.planKey,\n priceId: projection.priceId,\n status: projection.status,\n modules: [...projection.modules],\n start: new Date(cursor),\n end: next,\n periodStart: new Date(projection.currentPeriodStart),\n periodEnd: new Date(projection.currentPeriodEnd),\n })\n }\n\n cursor = next\n }\n\n return segments\n}\n","import { projectSubscription } from \"./projection\"\nimport type {\n PersistedSubscriptionEvent,\n StoredSubscriptionProjection,\n SubscriptionEvent,\n SubscriptionProjection,\n} from \"./types\"\n\n\nexport type BillingStorageTransaction = unknown\n\nexport type BillingStorage = {\n runInTransaction?: <T>(operation: (transaction: BillingStorageTransaction) => Promise<T>) => Promise<T>\n createEvent: (\n event: SubscriptionEvent,\n transaction?: BillingStorageTransaction,\n ) => Promise<PersistedSubscriptionEvent>\n listEvents: (\n tenantId: string,\n subscriptionId: string,\n transaction?: BillingStorageTransaction,\n ) => Promise<PersistedSubscriptionEvent[]>\n upsertProjection: (\n projection: StoredSubscriptionProjection,\n transaction?: BillingStorageTransaction,\n ) => Promise<void>\n}\n\nconst runWithOptionalTransaction = async <T>(\n storage: BillingStorage,\n operation: (transaction?: BillingStorageTransaction) => Promise<T>,\n): Promise<T> => {\n if (!storage.runInTransaction) return operation()\n return storage.runInTransaction((transaction) => operation(transaction))\n}\n\nconst buildStoredProjection = (params: {\n tenantId: string\n projection: SubscriptionProjection\n latestEvent: PersistedSubscriptionEvent\n projectedAt: Date\n}): StoredSubscriptionProjection => {\n return {\n ...params.projection,\n tenantId: params.tenantId,\n latestEventId: params.latestEvent.id,\n latestEventAt: new Date(params.latestEvent.occurredAt),\n projectedAt: new Date(params.projectedAt),\n }\n}\n\nconst projectAndStore = async (params: {\n storage: BillingStorage\n tenantId: string\n subscriptionId: string\n asOf: Date\n transaction?: BillingStorageTransaction\n}): Promise<StoredSubscriptionProjection | null> => {\n const events = await params.storage.listEvents(\n params.tenantId,\n params.subscriptionId,\n params.transaction,\n )\n const projection = projectSubscription(events, { asOf: params.asOf })\n if (!projection) return null\n\n const latestEvent = [...events].sort((left, right) => {\n const occurredDelta = right.occurredAt.getTime() - left.occurredAt.getTime()\n if (occurredDelta !== 0) return occurredDelta\n return right.id.localeCompare(left.id)\n })[0]!\n\n const storedProjection = buildStoredProjection({\n tenantId: params.tenantId,\n projection,\n latestEvent,\n projectedAt: params.asOf,\n })\n await params.storage.upsertProjection(storedProjection, params.transaction)\n return storedProjection\n}\n\nexport const appendSubscriptionEvent = async (params: {\n storage: BillingStorage\n tenantId: string\n event: SubscriptionEvent\n asOf?: Date\n}): Promise<{\n event: PersistedSubscriptionEvent\n projection: StoredSubscriptionProjection | null\n}> => {\n if (params.event.tenantId !== params.tenantId) {\n throw new Error(\"Billing event tenantId does not match the requested tenant\")\n }\n\n return runWithOptionalTransaction(params.storage, async (transaction) => {\n const event = await params.storage.createEvent(params.event, transaction)\n const projection = await projectAndStore({\n storage: params.storage,\n tenantId: params.tenantId,\n subscriptionId: event.subscriptionId,\n asOf: params.asOf ?? new Date(),\n transaction,\n })\n\n return { event, projection }\n })\n}\n\nexport const rebuildSubscriptionProjection = async (params: {\n storage: BillingStorage\n tenantId: string\n subscriptionId: string\n asOf?: Date\n}): Promise<StoredSubscriptionProjection | null> => runWithOptionalTransaction(\n params.storage,\n (transaction) => projectAndStore({\n storage: params.storage,\n tenantId: params.tenantId,\n subscriptionId: params.subscriptionId,\n asOf: params.asOf ?? new Date(),\n transaction,\n }),\n)\n","export const SUBSCRIPTION_STATUSES = [\n \"trialing\",\n \"active\",\n \"past_due\",\n \"paused\",\n \"canceled\",\n \"expired\",\n] as const\n\nexport type SubscriptionStatus = typeof SUBSCRIPTION_STATUSES[number]\n\nexport const SUBSCRIPTION_INTERVAL_UNITS = [\"month\", \"year\"] as const\n\nexport type SubscriptionIntervalUnit = typeof SUBSCRIPTION_INTERVAL_UNITS[number]\n\nexport const SUBSCRIPTION_TYPES = [\"primary\", \"addon\"] as const\n\nexport type SubscriptionType = typeof SUBSCRIPTION_TYPES[number]\n\nexport const SUBSCRIPTION_SCOPES = [\"tenant\", \"workspace\", \"shop\", \"custom\"] as const\n\nexport type SubscriptionScope = typeof SUBSCRIPTION_SCOPES[number]\n\nexport const SUBSCRIPTION_EVENT_TYPES = [\n \"created\",\n \"plan_changed\",\n \"status_changed\",\n \"resumed\",\n \"canceled\",\n \"renewed\",\n] as const\n\nexport type SubscriptionEventType = typeof SUBSCRIPTION_EVENT_TYPES[number]\n\nexport const SUBSCRIPTION_CHANGE_DIRECTIONS = [\n \"upgrade\",\n \"downgrade\",\n \"lateral\",\n] as const\n\nexport type SubscriptionChangeDirection = typeof SUBSCRIPTION_CHANGE_DIRECTIONS[number]\n\nexport type SubscriptionEventBase = {\n id?: string\n tenantId: string\n subscriptionId: string\n occurredAt: Date\n effectiveAt: Date\n subscriptionType: SubscriptionType\n parentSubscriptionId?: string\n scope: SubscriptionScope\n scopeId?: string\n fromPlanKey?: string\n toPlanKey?: string\n fromStatus?: SubscriptionStatus\n toStatus?: SubscriptionStatus\n fromModules?: string[]\n toModules?: string[]\n fromIntervalUnit?: SubscriptionIntervalUnit\n toIntervalUnit?: SubscriptionIntervalUnit\n fromIntervalCount?: number\n toIntervalCount?: number\n fromPriceId?: string\n toPriceId?: string\n billingAnchor?: Date\n supersedesEventId?: string\n idempotencyKey: string\n direction?: SubscriptionChangeDirection\n actorUserId?: string\n source?: \"admin\" | \"system\" | \"webhook\" | \"user\"\n reason?: string\n provider?: string\n providerEventId?: string\n providerPayload?: unknown\n metadata?: Record<string, unknown>\n}\n\nexport type SubscriptionCreatedEvent = SubscriptionEventBase & {\n type: \"created\"\n toPlanKey: string\n toStatus: SubscriptionStatus\n toModules: string[]\n toIntervalUnit: SubscriptionIntervalUnit\n toIntervalCount: number\n billingAnchor: Date\n}\n\nexport type SubscriptionPlanChangedEvent = SubscriptionEventBase & {\n type: \"plan_changed\"\n fromPlanKey: string\n toPlanKey: string\n fromModules: string[]\n toModules: string[]\n fromIntervalUnit: SubscriptionIntervalUnit\n toIntervalUnit: SubscriptionIntervalUnit\n fromIntervalCount: number\n toIntervalCount: number\n}\n\nexport type SubscriptionStatusChangedEvent = SubscriptionEventBase & {\n type: \"status_changed\"\n fromStatus: SubscriptionStatus\n toStatus: SubscriptionStatus\n}\n\nexport type SubscriptionResumedEvent = SubscriptionEventBase & {\n type: \"resumed\"\n fromStatus: SubscriptionStatus\n toStatus: \"active\"\n}\n\nexport type SubscriptionCanceledEvent = SubscriptionEventBase & {\n type: \"canceled\"\n fromStatus: SubscriptionStatus\n toStatus: \"canceled\"\n}\n\nexport type SubscriptionRenewedEvent = SubscriptionEventBase & {\n type: \"renewed\"\n fromStatus: SubscriptionStatus\n toStatus: SubscriptionStatus\n}\n\nexport type SubscriptionEvent =\n | SubscriptionCreatedEvent\n | SubscriptionPlanChangedEvent\n | SubscriptionStatusChangedEvent\n | SubscriptionResumedEvent\n | SubscriptionCanceledEvent\n | SubscriptionRenewedEvent\n\nexport type PersistedSubscriptionEvent = SubscriptionEvent & {\n id: string\n}\n\nexport type ScheduledPlanChange = {\n planKey: string\n effectiveAt: Date\n}\n\nexport type SubscriptionProjection = {\n subscriptionId: string\n type: SubscriptionType\n parentSubscriptionId: string | null\n scope: SubscriptionScope\n scopeId: string | null\n planKey: string\n priceId: string | null\n status: SubscriptionStatus\n intervalUnit: SubscriptionIntervalUnit\n intervalCount: number\n modules: string[]\n billingAnchor: Date\n currentPeriodStart: Date\n currentPeriodEnd: Date\n cancelAtPeriodEnd: boolean\n cancelAt: Date | null\n canceledAt: Date | null\n scheduledPlan: ScheduledPlanChange | null\n provider: string | null\n}\n\nexport type BillableSubscriptionSegment = {\n subscriptionId: string\n planKey: string\n priceId: string | null\n status: SubscriptionStatus\n modules: string[]\n start: Date\n end: Date\n periodStart: Date\n periodEnd: Date\n}\n\nexport type StoredSubscriptionProjection = SubscriptionProjection & {\n tenantId: string\n latestEventId: string\n latestEventAt: Date\n projectedAt: Date\n}\n"],"names":["assertValidDate","value","field","date","Date","Number","isNaN","getTime","Error","normalizeIntervalCount","isInteger","getDaysInUtcMonth","year","month","UTC","getUTCDate","createClampedUtcDate","source","day","Math","min","getUTCHours","getUTCMinutes","getUTCSeconds","getUTCMilliseconds","addBillingInterval","intervalUnit","intervalCount","count","getUTCFullYear","getUTCMonth","absoluteMonth","floor","getEstimatedPeriodIndex","anchor","asOf","rawDifference","max","resolveBillingPeriod","params","billingAnchor","periodIndex","start","end","calculateProratedAmount","isSafeInteger","unitAmount","segmentStart","segmentEnd","periodStart","periodEnd","periodDuration","overlapStart","overlapEnd","overlapDuration","round","compareEvents","left","right","effectiveDelta","effectiveAt","occurredDelta","occurredAt","id","localeCompare","sortSubscriptionEvents","events","map","event","dates","type","undefined","sort","getEffectiveEvents","ordered","supersededIds","Set","supersedesEventId","filter","eventId","Boolean","has","assertSingleSubscription","length","subscriptionIds","subscriptionId","size","tenantIds","tenantId","assertNonEmptyString","trim","assertPositiveInteger","assertCreatedEvent","subscriptionType","scope","parentSubscriptionId","scopeId","toPlanKey","toStatus","Array","isArray","toModules","toIntervalUnit","toIntervalCount","assertTransitionEvent","idempotencyKey","fromPlanKey","fromModules","fromIntervalUnit","fromIntervalCount","fromStatus","assertConsistentEventEnvelope","created","projectSubscription","options","forEach","index","applicable","planKey","priceId","status","modules","provider","canceledAt","slice","toPriceId","futureEvents","scheduledCancellation","find","scheduledPlanEvent","scheduledPlan","periodAsOf","period","currentPeriodStart","currentPeriodEnd","cancelAtPeriodEnd","cancelAt","getSubscriptionTransitionDates","after","before","time","DEFAULT_BILLABLE_STATUSES","assertValidWindow","from","to","normalizedFrom","normalizedTo","buildBillableSegments","window","billableStatuses","transitionDates","segments","cursor","projection","nextTransition","nextPeriodEnd","candidateTimes","POSITIVE_INFINITY","nextTime","isFinite","next","push","runWithOptionalTransaction","storage","operation","runInTransaction","transaction","buildStoredProjection","latestEventId","latestEvent","latestEventAt","projectedAt","projectAndStore","listEvents","storedProjection","upsertProjection","appendSubscriptionEvent","createEvent","rebuildSubscriptionProjection","SUBSCRIPTION_STATUSES","SUBSCRIPTION_INTERVAL_UNITS","SUBSCRIPTION_TYPES","SUBSCRIPTION_SCOPES","SUBSCRIPTION_EVENT_TYPES","SUBSCRIPTION_CHANGE_DIRECTIONS"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"projection.d.ts","sourceRoot":"","sources":["../src/projection.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAEV,iBAAiB,EACjB,sBAAsB,EAEvB,MAAM,SAAS,CAAA;AAmBhB,eAAO,MAAM,sBAAsB,GAAI,QAAQ,SAAS,iBAAiB,EAAE,KAAG,iBAAiB,EAUvE,CAAA;AAmDxB,eAAO,MAAM,mBAAmB,GAC9B,QAAQ,SAAS,iBAAiB,EAAE,EACpC,UAAS;IAAE,IAAI,CAAC,EAAE,IAAI,CAAA;CAAO,KAC5B,sBAAsB,GAAG,IA+F3B,CAAA;AAED,eAAO,MAAM,8BAA8B,GACzC,QAAQ,SAAS,iBAAiB,EAAE,EACpC,QAAQ;IAAE,KAAK,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,IAAI,CAAA;CAAE,KACpC,IAAI,EAYN,CAAA"}
1
+ {"version":3,"file":"projection.d.ts","sourceRoot":"","sources":["../src/projection.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAGV,iBAAiB,EACjB,sBAAsB,EAEvB,MAAM,SAAS,CAAA;AAmBhB,eAAO,MAAM,sBAAsB,GAAI,QAAQ,SAAS,iBAAiB,EAAE,KAAG,iBAAiB,EAsBvE,CAAA;AAqGxB,eAAO,MAAM,mBAAmB,GAC9B,QAAQ,SAAS,iBAAiB,EAAE,EACpC,UAAS;IAAE,IAAI,CAAC,EAAE,IAAI,CAAA;CAAO,KAC5B,sBAAsB,GAAG,IA+F3B,CAAA;AAED,eAAO,MAAM,8BAA8B,GACzC,QAAQ,SAAS,iBAAiB,EAAE,EACpC,QAAQ;IAAE,KAAK,EAAE,IAAI,CAAC;IAAC,MAAM,EAAE,IAAI,CAAA;CAAE,KACpC,IAAI,EAYN,CAAA"}
package/dist/storage.d.ts CHANGED
@@ -1,9 +1,9 @@
1
- import { StoredSubscriptionProjection, SubscriptionEvent } from './types';
1
+ import { PersistedSubscriptionEvent, StoredSubscriptionProjection, SubscriptionEvent } from './types';
2
2
  export type BillingStorageTransaction = unknown;
3
3
  export type BillingStorage = {
4
4
  runInTransaction?: <T>(operation: (transaction: BillingStorageTransaction) => Promise<T>) => Promise<T>;
5
- createEvent: (event: SubscriptionEvent, transaction?: BillingStorageTransaction) => Promise<SubscriptionEvent>;
6
- listEvents: (tenantId: string, subscriptionId: string, transaction?: BillingStorageTransaction) => Promise<SubscriptionEvent[]>;
5
+ createEvent: (event: SubscriptionEvent, transaction?: BillingStorageTransaction) => Promise<PersistedSubscriptionEvent>;
6
+ listEvents: (tenantId: string, subscriptionId: string, transaction?: BillingStorageTransaction) => Promise<PersistedSubscriptionEvent[]>;
7
7
  upsertProjection: (projection: StoredSubscriptionProjection, transaction?: BillingStorageTransaction) => Promise<void>;
8
8
  };
9
9
  export declare const appendSubscriptionEvent: (params: {
@@ -12,7 +12,7 @@ export declare const appendSubscriptionEvent: (params: {
12
12
  event: SubscriptionEvent;
13
13
  asOf?: Date;
14
14
  }) => Promise<{
15
- event: SubscriptionEvent;
15
+ event: PersistedSubscriptionEvent;
16
16
  projection: StoredSubscriptionProjection | null;
17
17
  }>;
18
18
  export declare const rebuildSubscriptionProjection: (params: {
@@ -1 +1 @@
1
- {"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../src/storage.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,4BAA4B,EAC5B,iBAAiB,EAElB,MAAM,SAAS,CAAA;AAGhB,MAAM,MAAM,yBAAyB,GAAG,OAAO,CAAA;AAE/C,MAAM,MAAM,cAAc,GAAG;IAC3B,gBAAgB,CAAC,EAAE,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,WAAW,EAAE,yBAAyB,KAAK,OAAO,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,CAAA;IACvG,WAAW,EAAE,CACX,KAAK,EAAE,iBAAiB,EACxB,WAAW,CAAC,EAAE,yBAAyB,KACpC,OAAO,CAAC,iBAAiB,CAAC,CAAA;IAC/B,UAAU,EAAE,CACV,QAAQ,EAAE,MAAM,EAChB,cAAc,EAAE,MAAM,EACtB,WAAW,CAAC,EAAE,yBAAyB,KACpC,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAAA;IACjC,gBAAgB,EAAE,CAChB,UAAU,EAAE,4BAA4B,EACxC,WAAW,CAAC,EAAE,yBAAyB,KACpC,OAAO,CAAC,IAAI,CAAC,CAAA;CACnB,CAAA;AA2DD,eAAO,MAAM,uBAAuB,GAAU,QAAQ;IACpD,OAAO,EAAE,cAAc,CAAA;IACvB,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,EAAE,iBAAiB,CAAA;IACxB,IAAI,CAAC,EAAE,IAAI,CAAA;CACZ,KAAG,OAAO,CAAC;IACV,KAAK,EAAE,iBAAiB,CAAA;IACxB,UAAU,EAAE,4BAA4B,GAAG,IAAI,CAAA;CAChD,CAWC,CAAA;AAEF,eAAO,MAAM,6BAA6B,GAAU,QAAQ;IAC1D,OAAO,EAAE,cAAc,CAAA;IACvB,QAAQ,EAAE,MAAM,CAAA;IAChB,cAAc,EAAE,MAAM,CAAA;IACtB,IAAI,CAAC,EAAE,IAAI,CAAA;CACZ,KAAG,OAAO,CAAC,4BAA4B,GAAG,IAAI,CAS9C,CAAA"}
1
+ {"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../src/storage.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,0BAA0B,EAC1B,4BAA4B,EAC5B,iBAAiB,EAElB,MAAM,SAAS,CAAA;AAGhB,MAAM,MAAM,yBAAyB,GAAG,OAAO,CAAA;AAE/C,MAAM,MAAM,cAAc,GAAG;IAC3B,gBAAgB,CAAC,EAAE,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,WAAW,EAAE,yBAAyB,KAAK,OAAO,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,CAAC,CAAC,CAAA;IACvG,WAAW,EAAE,CACX,KAAK,EAAE,iBAAiB,EACxB,WAAW,CAAC,EAAE,yBAAyB,KACpC,OAAO,CAAC,0BAA0B,CAAC,CAAA;IACxC,UAAU,EAAE,CACV,QAAQ,EAAE,MAAM,EAChB,cAAc,EAAE,MAAM,EACtB,WAAW,CAAC,EAAE,yBAAyB,KACpC,OAAO,CAAC,0BAA0B,EAAE,CAAC,CAAA;IAC1C,gBAAgB,EAAE,CAChB,UAAU,EAAE,4BAA4B,EACxC,WAAW,CAAC,EAAE,yBAAyB,KACpC,OAAO,CAAC,IAAI,CAAC,CAAA;CACnB,CAAA;AAwDD,eAAO,MAAM,uBAAuB,GAAU,QAAQ;IACpD,OAAO,EAAE,cAAc,CAAA;IACvB,QAAQ,EAAE,MAAM,CAAA;IAChB,KAAK,EAAE,iBAAiB,CAAA;IACxB,IAAI,CAAC,EAAE,IAAI,CAAA;CACZ,KAAG,OAAO,CAAC;IACV,KAAK,EAAE,0BAA0B,CAAA;IACjC,UAAU,EAAE,4BAA4B,GAAG,IAAI,CAAA;CAChD,CAiBA,CAAA;AAED,eAAO,MAAM,6BAA6B,GAAU,QAAQ;IAC1D,OAAO,EAAE,cAAc,CAAA;IACvB,QAAQ,EAAE,MAAM,CAAA;IAChB,cAAc,EAAE,MAAM,CAAA;IACtB,IAAI,CAAC,EAAE,IAAI,CAAA;CACZ,KAAG,OAAO,CAAC,4BAA4B,GAAG,IAAI,CAS9C,CAAA"}
package/dist/types.d.ts CHANGED
@@ -8,16 +8,17 @@ export declare const SUBSCRIPTION_SCOPES: readonly ["tenant", "workspace", "shop
8
8
  export type SubscriptionScope = typeof SUBSCRIPTION_SCOPES[number];
9
9
  export declare const SUBSCRIPTION_EVENT_TYPES: readonly ["created", "plan_changed", "status_changed", "resumed", "canceled", "renewed"];
10
10
  export type SubscriptionEventType = typeof SUBSCRIPTION_EVENT_TYPES[number];
11
- export type SubscriptionEvent = {
11
+ export declare const SUBSCRIPTION_CHANGE_DIRECTIONS: readonly ["upgrade", "downgrade", "lateral"];
12
+ export type SubscriptionChangeDirection = typeof SUBSCRIPTION_CHANGE_DIRECTIONS[number];
13
+ export type SubscriptionEventBase = {
12
14
  id?: string;
13
- tenantId?: string;
15
+ tenantId: string;
14
16
  subscriptionId: string;
15
- type: SubscriptionEventType;
16
17
  occurredAt: Date;
17
18
  effectiveAt: Date;
18
- subscriptionType?: SubscriptionType;
19
+ subscriptionType: SubscriptionType;
19
20
  parentSubscriptionId?: string;
20
- scope?: SubscriptionScope;
21
+ scope: SubscriptionScope;
21
22
  scopeId?: string;
22
23
  fromPlanKey?: string;
23
24
  toPlanKey?: string;
@@ -33,14 +34,60 @@ export type SubscriptionEvent = {
33
34
  toPriceId?: string;
34
35
  billingAnchor?: Date;
35
36
  supersedesEventId?: string;
36
- idempotencyKey?: string;
37
+ idempotencyKey: string;
38
+ direction?: SubscriptionChangeDirection;
37
39
  actorUserId?: string;
38
40
  source?: "admin" | "system" | "webhook" | "user";
39
41
  reason?: string;
40
42
  provider?: string;
41
43
  providerEventId?: string;
44
+ providerPayload?: unknown;
42
45
  metadata?: Record<string, unknown>;
43
46
  };
47
+ export type SubscriptionCreatedEvent = SubscriptionEventBase & {
48
+ type: "created";
49
+ toPlanKey: string;
50
+ toStatus: SubscriptionStatus;
51
+ toModules: string[];
52
+ toIntervalUnit: SubscriptionIntervalUnit;
53
+ toIntervalCount: number;
54
+ billingAnchor: Date;
55
+ };
56
+ export type SubscriptionPlanChangedEvent = SubscriptionEventBase & {
57
+ type: "plan_changed";
58
+ fromPlanKey: string;
59
+ toPlanKey: string;
60
+ fromModules: string[];
61
+ toModules: string[];
62
+ fromIntervalUnit: SubscriptionIntervalUnit;
63
+ toIntervalUnit: SubscriptionIntervalUnit;
64
+ fromIntervalCount: number;
65
+ toIntervalCount: number;
66
+ };
67
+ export type SubscriptionStatusChangedEvent = SubscriptionEventBase & {
68
+ type: "status_changed";
69
+ fromStatus: SubscriptionStatus;
70
+ toStatus: SubscriptionStatus;
71
+ };
72
+ export type SubscriptionResumedEvent = SubscriptionEventBase & {
73
+ type: "resumed";
74
+ fromStatus: SubscriptionStatus;
75
+ toStatus: "active";
76
+ };
77
+ export type SubscriptionCanceledEvent = SubscriptionEventBase & {
78
+ type: "canceled";
79
+ fromStatus: SubscriptionStatus;
80
+ toStatus: "canceled";
81
+ };
82
+ export type SubscriptionRenewedEvent = SubscriptionEventBase & {
83
+ type: "renewed";
84
+ fromStatus: SubscriptionStatus;
85
+ toStatus: SubscriptionStatus;
86
+ };
87
+ export type SubscriptionEvent = SubscriptionCreatedEvent | SubscriptionPlanChangedEvent | SubscriptionStatusChangedEvent | SubscriptionResumedEvent | SubscriptionCanceledEvent | SubscriptionRenewedEvent;
88
+ export type PersistedSubscriptionEvent = SubscriptionEvent & {
89
+ id: string;
90
+ };
44
91
  export type ScheduledPlanChange = {
45
92
  planKey: string;
46
93
  effectiveAt: Date;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rpcbase/billing",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "dist"