@rpcbase/db 0.121.0 → 0.122.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.
@@ -0,0 +1,7 @@
1
+ import { BillingStorage } from '@rpcbase/billing';
2
+ import { LoadModelCtx } from './modelsApi';
3
+ export declare const createTenantBillingStorage: (params: {
4
+ ctx: LoadModelCtx;
5
+ tenantId: string;
6
+ }) => BillingStorage;
7
+ //# sourceMappingURL=billingStorage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"billingStorage.d.ts","sourceRoot":"","sources":["../src/billingStorage.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,cAAc,EAIf,MAAM,kBAAkB,CAAA;AAGzB,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAkE/C,eAAO,MAAM,0BAA0B,GAAI,QAAQ;IACjD,GAAG,EAAE,YAAY,CAAA;IACjB,QAAQ,EAAE,MAAM,CAAA;CACjB,KAAG,cAwEH,CAAA"}
package/dist/index.d.ts CHANGED
@@ -6,6 +6,7 @@ export * from './search';
6
6
  export * from './zod';
7
7
  export * from './modelTypes';
8
8
  export * from './createModels';
9
+ export * from './billingStorage';
9
10
  export * from './modelsApi';
10
11
  export * from './tenantFilesystemDb';
11
12
  export * from './transactions';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,OAAO,CAAA;AACrB,cAAc,UAAU,CAAA;AACxB,cAAc,YAAY,CAAA;AAC1B,cAAc,cAAc,CAAA;AAC5B,cAAc,UAAU,CAAA;AACxB,cAAc,OAAO,CAAA;AAErB,cAAc,cAAc,CAAA;AAC5B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,aAAa,CAAA;AAC3B,cAAc,sBAAsB,CAAA;AACpC,cAAc,gBAAgB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,OAAO,CAAA;AACrB,cAAc,UAAU,CAAA;AACxB,cAAc,YAAY,CAAA;AAC1B,cAAc,cAAc,CAAA;AAC5B,cAAc,UAAU,CAAA;AACxB,cAAc,OAAO,CAAA;AAErB,cAAc,cAAc,CAAA;AAC5B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,kBAAkB,CAAA;AAChC,cAAc,aAAa,CAAA;AAC3B,cAAc,sBAAsB,CAAA;AACpC,cAAc,gBAAgB,CAAA"}
package/dist/index.js CHANGED
@@ -3,6 +3,7 @@ import { b, a, c, g, d, e, f } from "./can-B4pD_pnR.js";
3
3
  import mongoose, { Schema as Schema$1, Types } from "mongoose";
4
4
  import { default as default2 } from "mongoose";
5
5
  import { z } from "zod";
6
+ import { SUBSCRIPTION_STATUSES, SUBSCRIPTION_INTERVAL_UNITS, SUBSCRIPTION_TYPES, SUBSCRIPTION_SCOPES, SUBSCRIPTION_EVENT_TYPES } from "@rpcbase/billing";
6
7
  import { timingSafeEqual, createHmac } from "node:crypto";
7
8
  import { w as withLocalizedStringFallback } from "./index-DrIoUXc2.js";
8
9
  import { E, a as a2, L, b as b2, e as e2, m, r, z as z2, c as c2, d as d2, f as f2 } from "./index-DrIoUXc2.js";
@@ -166,16 +167,23 @@ const RBTenantSchema = new Schema$1({
166
167
  type: String
167
168
  }
168
169
  });
169
- const ZRBTenantSubscriptionStatus = z.enum(["trialing", "active", "past_due", "paused", "canceled", "expired"]);
170
- const ZRBTenantSubscriptionIntervalUnit = z.enum(["month", "year"]);
170
+ const ZRBTenantSubscriptionStatus = z.enum(SUBSCRIPTION_STATUSES);
171
+ const ZRBTenantSubscriptionIntervalUnit = z.enum(SUBSCRIPTION_INTERVAL_UNITS);
172
+ const ZRBTenantSubscriptionType = z.enum(SUBSCRIPTION_TYPES);
173
+ const ZRBTenantSubscriptionScope = z.enum(SUBSCRIPTION_SCOPES);
174
+ const ZRBTenantSubscriptionEventType = z.enum(SUBSCRIPTION_EVENT_TYPES);
171
175
  const ZRBTenantSubscriptionEventSource = z.enum(["admin", "system", "webhook", "user"]);
172
176
  const ZRBTenantSubscriptionChangeDirection = z.enum(["upgrade", "downgrade", "lateral"]);
173
177
  const ZRBTenantSubscriptionEvent = z.object({
174
178
  tenantId: z.string(),
175
179
  subscriptionId: z.string(),
176
- type: z.string(),
180
+ type: ZRBTenantSubscriptionEventType,
177
181
  occurredAt: z.date(),
178
- effectiveAt: z.date().optional(),
182
+ effectiveAt: z.date(),
183
+ subscriptionType: ZRBTenantSubscriptionType.optional(),
184
+ parentSubscriptionId: z.string().optional(),
185
+ scope: ZRBTenantSubscriptionScope.optional(),
186
+ scopeId: z.string().optional(),
179
187
  fromPlanKey: z.string().optional(),
180
188
  toPlanKey: z.string().optional(),
181
189
  fromStatus: ZRBTenantSubscriptionStatus.optional(),
@@ -186,6 +194,11 @@ const ZRBTenantSubscriptionEvent = z.object({
186
194
  toIntervalUnit: ZRBTenantSubscriptionIntervalUnit.optional(),
187
195
  fromIntervalCount: z.number().int().min(1).optional(),
188
196
  toIntervalCount: z.number().int().min(1).optional(),
197
+ fromPriceId: z.string().optional(),
198
+ toPriceId: z.string().optional(),
199
+ billingAnchor: z.date().optional(),
200
+ supersedesEventId: z.string().optional(),
201
+ idempotencyKey: z.string().optional(),
189
202
  direction: ZRBTenantSubscriptionChangeDirection.optional(),
190
203
  actorUserId: z.string().optional(),
191
204
  source: ZRBTenantSubscriptionEventSource.optional(),
@@ -208,7 +221,8 @@ const RBTenantSubscriptionEventSchema = new Schema$1({
208
221
  },
209
222
  type: {
210
223
  type: String,
211
- required: true
224
+ required: true,
225
+ enum: ZRBTenantSubscriptionEventType.options
212
226
  },
213
227
  occurredAt: {
214
228
  type: Date,
@@ -216,7 +230,22 @@ const RBTenantSubscriptionEventSchema = new Schema$1({
216
230
  default: Date.now
217
231
  },
218
232
  effectiveAt: {
219
- type: Date
233
+ type: Date,
234
+ required: true
235
+ },
236
+ subscriptionType: {
237
+ type: String,
238
+ enum: ZRBTenantSubscriptionType.options
239
+ },
240
+ parentSubscriptionId: {
241
+ type: String
242
+ },
243
+ scope: {
244
+ type: String,
245
+ enum: ZRBTenantSubscriptionScope.options
246
+ },
247
+ scopeId: {
248
+ type: String
220
249
  },
221
250
  fromPlanKey: {
222
251
  type: String
@@ -256,6 +285,21 @@ const RBTenantSubscriptionEventSchema = new Schema$1({
256
285
  type: Number,
257
286
  min: 1
258
287
  },
288
+ fromPriceId: {
289
+ type: String
290
+ },
291
+ toPriceId: {
292
+ type: String
293
+ },
294
+ billingAnchor: {
295
+ type: Date
296
+ },
297
+ supersedesEventId: {
298
+ type: String
299
+ },
300
+ idempotencyKey: {
301
+ type: String
302
+ },
259
303
  direction: {
260
304
  type: String,
261
305
  enum: ZRBTenantSubscriptionChangeDirection.options
@@ -286,6 +330,7 @@ const RBTenantSubscriptionEventSchema = new Schema$1({
286
330
  RBTenantSubscriptionEventSchema.index({
287
331
  tenantId: 1,
288
332
  subscriptionId: 1,
333
+ effectiveAt: 1,
289
334
  occurredAt: 1
290
335
  });
291
336
  RBTenantSubscriptionEventSchema.index({
@@ -295,6 +340,148 @@ RBTenantSubscriptionEventSchema.index({
295
340
  unique: true,
296
341
  sparse: true
297
342
  });
343
+ RBTenantSubscriptionEventSchema.index({
344
+ tenantId: 1,
345
+ idempotencyKey: 1
346
+ }, {
347
+ unique: true,
348
+ sparse: true
349
+ });
350
+ const ZRBTenantSubscriptionProjection = z.object({
351
+ tenantId: z.string(),
352
+ subscriptionId: z.string(),
353
+ type: ZRBTenantSubscriptionType,
354
+ parentSubscriptionId: z.string().optional(),
355
+ scope: ZRBTenantSubscriptionScope,
356
+ scopeId: z.string().optional(),
357
+ planKey: z.string(),
358
+ priceId: z.string().optional(),
359
+ status: ZRBTenantSubscriptionStatus,
360
+ intervalUnit: ZRBTenantSubscriptionIntervalUnit,
361
+ intervalCount: z.number().int().min(1),
362
+ modules: z.array(z.string()),
363
+ billingAnchor: z.date(),
364
+ currentPeriodStart: z.date(),
365
+ currentPeriodEnd: z.date(),
366
+ cancelAtPeriodEnd: z.boolean(),
367
+ cancelAt: z.date().optional(),
368
+ canceledAt: z.date().optional(),
369
+ scheduledPlanKey: z.string().optional(),
370
+ scheduledPlanEffectiveAt: z.date().optional(),
371
+ provider: z.string().optional(),
372
+ latestEventId: z.string(),
373
+ latestEventAt: z.date(),
374
+ projectedAt: z.date()
375
+ });
376
+ const RBTenantSubscriptionProjectionSchema = new Schema$1({
377
+ tenantId: {
378
+ type: String,
379
+ required: true,
380
+ index: true
381
+ },
382
+ subscriptionId: {
383
+ type: String,
384
+ required: true
385
+ },
386
+ type: {
387
+ type: String,
388
+ required: true,
389
+ enum: ZRBTenantSubscriptionType.options
390
+ },
391
+ parentSubscriptionId: {
392
+ type: String
393
+ },
394
+ scope: {
395
+ type: String,
396
+ required: true,
397
+ enum: ZRBTenantSubscriptionScope.options
398
+ },
399
+ scopeId: {
400
+ type: String
401
+ },
402
+ planKey: {
403
+ type: String,
404
+ required: true
405
+ },
406
+ priceId: {
407
+ type: String
408
+ },
409
+ status: {
410
+ type: String,
411
+ required: true,
412
+ enum: ZRBTenantSubscriptionStatus.options
413
+ },
414
+ intervalUnit: {
415
+ type: String,
416
+ required: true,
417
+ enum: ZRBTenantSubscriptionIntervalUnit.options
418
+ },
419
+ intervalCount: {
420
+ type: Number,
421
+ required: true,
422
+ min: 1
423
+ },
424
+ modules: {
425
+ type: [String],
426
+ required: true,
427
+ default: []
428
+ },
429
+ billingAnchor: {
430
+ type: Date,
431
+ required: true
432
+ },
433
+ currentPeriodStart: {
434
+ type: Date,
435
+ required: true
436
+ },
437
+ currentPeriodEnd: {
438
+ type: Date,
439
+ required: true
440
+ },
441
+ cancelAtPeriodEnd: {
442
+ type: Boolean,
443
+ required: true,
444
+ default: false
445
+ },
446
+ cancelAt: {
447
+ type: Date
448
+ },
449
+ canceledAt: {
450
+ type: Date
451
+ },
452
+ scheduledPlanKey: {
453
+ type: String
454
+ },
455
+ scheduledPlanEffectiveAt: {
456
+ type: Date
457
+ },
458
+ provider: {
459
+ type: String
460
+ },
461
+ latestEventId: {
462
+ type: String,
463
+ required: true
464
+ },
465
+ latestEventAt: {
466
+ type: Date,
467
+ required: true
468
+ },
469
+ projectedAt: {
470
+ type: Date,
471
+ required: true
472
+ }
473
+ });
474
+ RBTenantSubscriptionProjectionSchema.index({
475
+ tenantId: 1,
476
+ subscriptionId: 1
477
+ }, {
478
+ unique: true
479
+ });
480
+ RBTenantSubscriptionProjectionSchema.index({
481
+ tenantId: 1,
482
+ scope: 1,
483
+ scopeId: 1
484
+ });
298
485
  const ZRBRtsCounter = z.object({
299
486
  _id: z.string(),
300
487
  seq: z.number().int().min(0)
@@ -889,6 +1076,7 @@ const frameworkSchemas = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.de
889
1076
  RBRtsCounterSchema,
890
1077
  RBTenantSchema,
891
1078
  RBTenantSubscriptionEventSchema,
1079
+ RBTenantSubscriptionProjectionSchema,
892
1080
  RBUploadChunkSchema,
893
1081
  RBUploadSessionPolicy,
894
1082
  RBUploadSessionSchema,
@@ -907,8 +1095,12 @@ const frameworkSchemas = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.de
907
1095
  ZRBTenantSubscriptionChangeDirection,
908
1096
  ZRBTenantSubscriptionEvent,
909
1097
  ZRBTenantSubscriptionEventSource,
1098
+ ZRBTenantSubscriptionEventType,
910
1099
  ZRBTenantSubscriptionIntervalUnit,
1100
+ ZRBTenantSubscriptionProjection,
1101
+ ZRBTenantSubscriptionScope,
911
1102
  ZRBTenantSubscriptionStatus,
1103
+ ZRBTenantSubscriptionType,
912
1104
  ZRBUploadChunk,
913
1105
  ZRBUploadSession,
914
1106
  ZRBUploadSessionStatus,
@@ -2045,6 +2237,135 @@ async function withTransaction(scope, fn, options) {
2045
2237
  await session.endSession();
2046
2238
  }
2047
2239
  }
2240
+ const getTransactionSession = (transaction) => {
2241
+ if (!transaction || typeof transaction !== "object" || !("session" in transaction)) return void 0;
2242
+ return transaction.session;
2243
+ };
2244
+ const toSubscriptionEvent = (document) => {
2245
+ const parsed = ZRBTenantSubscriptionEvent.parse(document);
2246
+ return {
2247
+ ...parsed,
2248
+ id: document._id ? String(document._id) : void 0
2249
+ };
2250
+ };
2251
+ const getExistingEventQuery = (event, tenantId) => {
2252
+ if (event.idempotencyKey) {
2253
+ return {
2254
+ tenantId,
2255
+ idempotencyKey: event.idempotencyKey
2256
+ };
2257
+ }
2258
+ if (event.provider && event.providerEventId) {
2259
+ return {
2260
+ provider: event.provider,
2261
+ providerEventId: event.providerEventId
2262
+ };
2263
+ }
2264
+ return null;
2265
+ };
2266
+ const isDuplicateKeyError = (error) => Boolean(error && typeof error === "object" && "code" in error && error.code === 11e3);
2267
+ const toProjectionDocument = (projection) => ({
2268
+ tenantId: projection.tenantId,
2269
+ subscriptionId: projection.subscriptionId,
2270
+ type: projection.type,
2271
+ parentSubscriptionId: projection.parentSubscriptionId ?? void 0,
2272
+ scope: projection.scope,
2273
+ scopeId: projection.scopeId ?? void 0,
2274
+ planKey: projection.planKey,
2275
+ priceId: projection.priceId ?? void 0,
2276
+ status: projection.status,
2277
+ intervalUnit: projection.intervalUnit,
2278
+ intervalCount: projection.intervalCount,
2279
+ modules: projection.modules,
2280
+ billingAnchor: projection.billingAnchor,
2281
+ currentPeriodStart: projection.currentPeriodStart,
2282
+ currentPeriodEnd: projection.currentPeriodEnd,
2283
+ cancelAtPeriodEnd: projection.cancelAtPeriodEnd,
2284
+ cancelAt: projection.cancelAt ?? void 0,
2285
+ canceledAt: projection.canceledAt ?? void 0,
2286
+ scheduledPlanKey: projection.scheduledPlan?.planKey,
2287
+ scheduledPlanEffectiveAt: projection.scheduledPlan?.effectiveAt,
2288
+ provider: projection.provider ?? void 0,
2289
+ latestEventId: projection.latestEventId,
2290
+ latestEventAt: projection.latestEventAt,
2291
+ projectedAt: projection.projectedAt
2292
+ });
2293
+ const createTenantBillingStorage = (params) => {
2294
+ const findExistingEvent = async (query, transaction) => {
2295
+ const EventModel = await models.get("RBTenantSubscriptionEvent", params.ctx);
2296
+ const request = EventModel.findOne(query);
2297
+ const session = getTransactionSession(transaction);
2298
+ if (session) request.session(session);
2299
+ const document = await request.lean();
2300
+ return document ? toSubscriptionEvent(document) : null;
2301
+ };
2302
+ return {
2303
+ runInTransaction: (operation) => withTransaction({
2304
+ ctx: params.ctx
2305
+ }, ({
2306
+ session
2307
+ }) => operation({
2308
+ session
2309
+ })),
2310
+ createEvent: async (event, transaction) => {
2311
+ const existingQuery = getExistingEventQuery(event, params.tenantId);
2312
+ if (existingQuery) {
2313
+ const existing = await findExistingEvent(existingQuery, transaction);
2314
+ if (existing) return existing;
2315
+ }
2316
+ const EventModel = await models.get("RBTenantSubscriptionEvent", params.ctx);
2317
+ const eventDocument = ZRBTenantSubscriptionEvent.parse({
2318
+ ...event,
2319
+ tenantId: params.tenantId
2320
+ });
2321
+ const session = getTransactionSession(transaction);
2322
+ try {
2323
+ const documents = await EventModel.create([eventDocument], session ? {
2324
+ session
2325
+ } : void 0);
2326
+ const document = documents[0]?.toObject();
2327
+ if (!document) throw new Error("Subscription event was not persisted");
2328
+ return toSubscriptionEvent(document);
2329
+ } catch (error) {
2330
+ if (!existingQuery || !isDuplicateKeyError(error)) throw error;
2331
+ const existing = await findExistingEvent(existingQuery, transaction);
2332
+ if (!existing) throw error;
2333
+ return existing;
2334
+ }
2335
+ },
2336
+ listEvents: async (tenantId, subscriptionId, transaction) => {
2337
+ if (tenantId !== params.tenantId) throw new Error("Billing storage tenant mismatch");
2338
+ const EventModel = await models.get("RBTenantSubscriptionEvent", params.ctx);
2339
+ const request = EventModel.find({
2340
+ tenantId,
2341
+ subscriptionId
2342
+ }).sort({
2343
+ effectiveAt: 1,
2344
+ occurredAt: 1,
2345
+ _id: 1
2346
+ });
2347
+ const session = getTransactionSession(transaction);
2348
+ if (session) request.session(session);
2349
+ const documents = await request.lean();
2350
+ return documents.map(toSubscriptionEvent);
2351
+ },
2352
+ upsertProjection: async (projection, transaction) => {
2353
+ if (projection.tenantId !== params.tenantId) throw new Error("Billing projection tenant mismatch");
2354
+ const ProjectionModel = await models.get("RBTenantSubscriptionProjection", params.ctx);
2355
+ const session = getTransactionSession(transaction);
2356
+ await ProjectionModel.replaceOne({
2357
+ tenantId: params.tenantId,
2358
+ subscriptionId: projection.subscriptionId
2359
+ }, toProjectionDocument(projection), {
2360
+ upsert: true,
2361
+ runValidators: true,
2362
+ ...session ? {
2363
+ session
2364
+ } : {}
2365
+ });
2366
+ }
2367
+ };
2368
+ };
2048
2369
  export {
2049
2370
  E as E164_PHONE_OR_EMPTY_REGEX,
2050
2371
  a2 as E164_PHONE_REGEX,
@@ -2061,6 +2382,7 @@ export {
2061
2382
  RBRtsCounterSchema,
2062
2383
  RBTenantSchema,
2063
2384
  RBTenantSubscriptionEventSchema,
2385
+ RBTenantSubscriptionProjectionSchema,
2064
2386
  RBUploadChunkSchema,
2065
2387
  RBUploadSessionPolicy,
2066
2388
  RBUploadSessionSchema,
@@ -2080,8 +2402,12 @@ export {
2080
2402
  ZRBTenantSubscriptionChangeDirection,
2081
2403
  ZRBTenantSubscriptionEvent,
2082
2404
  ZRBTenantSubscriptionEventSource,
2405
+ ZRBTenantSubscriptionEventType,
2083
2406
  ZRBTenantSubscriptionIntervalUnit,
2407
+ ZRBTenantSubscriptionProjection,
2408
+ ZRBTenantSubscriptionScope,
2084
2409
  ZRBTenantSubscriptionStatus,
2410
+ ZRBTenantSubscriptionType,
2085
2411
  ZRBUploadChunk,
2086
2412
  ZRBUploadSession,
2087
2413
  ZRBUploadSessionStatus,
@@ -2092,6 +2418,7 @@ export {
2092
2418
  buildSearchTextStage,
2093
2419
  c as can,
2094
2420
  createModels,
2421
+ createTenantBillingStorage,
2095
2422
  ensureSearchIndex,
2096
2423
  extendMongooseSchema,
2097
2424
  e2 as extendZod,