@saasicat/adapter-prisma 0.5.0 → 0.7.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.cjs CHANGED
@@ -23,24 +23,38 @@ var index_exports = {};
23
23
  __export(index_exports, {
24
24
  AsyncLocalRlsBypassAdapter: () => AsyncLocalRlsBypassAdapter,
25
25
  PASSWORD_HASHER_TOKEN: () => PASSWORD_HASHER_TOKEN,
26
+ PRISMA_BUNDLE_REPOSITORY_OPTIONS: () => PRISMA_BUNDLE_REPOSITORY_OPTIONS,
26
27
  PRISMA_CLIENT_TOKEN: () => PRISMA_CLIENT_TOKEN,
28
+ PRISMA_SCHEMA_OPTIONS_TOKEN: () => PRISMA_SCHEMA_OPTIONS_TOKEN,
27
29
  PrismaAuditAdapter: () => PrismaAuditAdapter,
28
30
  PrismaAuditQueryAdapter: () => PrismaAuditQueryAdapter,
29
31
  PrismaAuditStatsAdapter: () => PrismaAuditStatsAdapter,
32
+ PrismaBundleRepository: () => PrismaBundleRepository,
33
+ PrismaCatalogEntryRepository: () => PrismaCatalogEntryRepository,
34
+ PrismaMarketingProjectionRepository: () => PrismaMarketingProjectionRepository,
35
+ PrismaMarketingSettingsRepository: () => PrismaMarketingSettingsRepository,
30
36
  PrismaMfaAdapter: () => PrismaMfaAdapter,
31
37
  PrismaPlanCatalogImportSink: () => PrismaPlanCatalogImportSink,
32
38
  PrismaPlanCatalogReadSink: () => PrismaPlanCatalogReadSink,
39
+ PrismaPlanRepository: () => PrismaPlanRepository,
33
40
  PrismaPlanVersionRepository: () => PrismaPlanVersionRepository,
34
41
  PrismaPromoCodeRedemptionRepository: () => PrismaPromoCodeRedemptionRepository,
35
42
  PrismaPromoCodeRepository: () => PrismaPromoCodeRepository,
36
43
  PrismaPromoCodeValidationLogRepository: () => PrismaPromoCodeValidationLogRepository,
37
44
  PrismaPromoSubscriptionLookup: () => PrismaPromoSubscriptionLookup,
45
+ PrismaPromotionRepository: () => PrismaPromotionRepository,
46
+ PrismaSubscriptionBundleRepository: () => PrismaSubscriptionBundleRepository,
47
+ PrismaSubscriptionContractRepository: () => PrismaSubscriptionContractRepository,
38
48
  PrismaSubscriptionRepository: () => PrismaSubscriptionRepository,
39
49
  PrismaSuperAdminBootstrapAdapter: () => PrismaSuperAdminBootstrapAdapter,
50
+ PrismaTenantSubscriptionWriteAdapter: () => PrismaTenantSubscriptionWriteAdapter,
40
51
  PrismaTransactionRunner: () => PrismaTransactionRunner,
41
52
  ZeroPromoRevenueDeductionAggregator: () => ZeroPromoRevenueDeductionAggregator,
42
53
  buildActorTag: () => buildActorTag,
43
- prismaPersistence: () => prismaPersistence
54
+ createPrismaPlanBindingResolver: () => createPrismaPlanBindingResolver,
55
+ getPrismaDelegate: () => getPrismaDelegate,
56
+ prismaPersistence: () => prismaPersistence,
57
+ resolvePrismaSchemaOptions: () => resolvePrismaSchemaOptions
44
58
  });
45
59
  module.exports = __toCommonJS(index_exports);
46
60
 
@@ -129,7 +143,7 @@ PrismaAuditAdapter = _ts_decorate2([
129
143
  _ts_param(0, (0, import_common2.Inject)(PRISMA_CLIENT_TOKEN)),
130
144
  _ts_metadata("design:type", Function),
131
145
  _ts_metadata("design:paramtypes", [
132
- typeof PrismaLike === "undefined" ? Object : PrismaLike
146
+ typeof Pick === "undefined" ? Object : Pick
133
147
  ])
134
148
  ], PrismaAuditAdapter);
135
149
 
@@ -192,7 +206,7 @@ PrismaAuditQueryAdapter = _ts_decorate3([
192
206
  _ts_param2(0, (0, import_common3.Inject)(PRISMA_CLIENT_TOKEN)),
193
207
  _ts_metadata2("design:type", Function),
194
208
  _ts_metadata2("design:paramtypes", [
195
- typeof PrismaLike === "undefined" ? Object : PrismaLike
209
+ typeof Pick === "undefined" ? Object : Pick
196
210
  ])
197
211
  ], PrismaAuditQueryAdapter);
198
212
  function toActorTagFilter(actorTag) {
@@ -264,7 +278,7 @@ PrismaAuditStatsAdapter = _ts_decorate4([
264
278
  _ts_param3(0, (0, import_common4.Inject)(PRISMA_CLIENT_TOKEN)),
265
279
  _ts_metadata3("design:type", Function),
266
280
  _ts_metadata3("design:paramtypes", [
267
- typeof PrismaLike === "undefined" ? Object : PrismaLike
281
+ typeof Pick === "undefined" ? Object : Pick
268
282
  ])
269
283
  ], PrismaAuditStatsAdapter);
270
284
 
@@ -334,12 +348,149 @@ PrismaMfaAdapter = _ts_decorate5([
334
348
  _ts_param4(0, (0, import_common5.Inject)(PRISMA_CLIENT_TOKEN)),
335
349
  _ts_metadata4("design:type", Function),
336
350
  _ts_metadata4("design:paramtypes", [
337
- typeof PrismaLike === "undefined" ? Object : PrismaLike
351
+ typeof Pick === "undefined" ? Object : Pick
338
352
  ])
339
353
  ], PrismaMfaAdapter);
340
354
 
341
355
  // src/prisma-plan-catalog-import-sink.ts
342
356
  var import_common6 = require("@nestjs/common");
357
+
358
+ // src/prisma-plan-binding.ts
359
+ var PRISMA_SCHEMA_OPTIONS_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/adapter-prisma/PrismaSchemaOptions");
360
+ var DEFAULT_SCHEMA_OPTIONS = {
361
+ planBinding: {
362
+ mode: "legacy-plan-key"
363
+ },
364
+ delegates: {
365
+ catalogPlanVersion: "planVersion",
366
+ entitlementPlanVersion: "planVersion"
367
+ },
368
+ planVersionFields: {
369
+ catalog: {
370
+ validityWindows: false,
371
+ endsAt: false
372
+ },
373
+ entitlement: {
374
+ validityWindows: false,
375
+ endsAt: false
376
+ }
377
+ },
378
+ tenantSubscription: {
379
+ delegate: "subscription",
380
+ subscriptionBundleDelegate: false,
381
+ synchronizePlanVersion: false,
382
+ atomicOnboardingSelection: false,
383
+ activeVersionSelection: "latest-live",
384
+ withEndsAt: false
385
+ }
386
+ };
387
+ function resolvePrismaSchemaOptions(options) {
388
+ const mode = options?.planBinding?.mode ?? "legacy-plan-key";
389
+ const projectKey = options?.planBinding?.projectKey;
390
+ if (mode === "normalized-plan-id" && !projectKey?.trim()) {
391
+ throw new Error("Prisma plan binding mode 'normalized-plan-id' requires a non-empty projectKey.");
392
+ }
393
+ const sharedFields = options?.planVersionFields;
394
+ const catalogFields = sharedFields?.catalog;
395
+ const entitlementFields = sharedFields?.entitlement;
396
+ return {
397
+ planBinding: {
398
+ mode,
399
+ ...projectKey ? {
400
+ projectKey
401
+ } : {}
402
+ },
403
+ delegates: {
404
+ catalogPlanVersion: options?.delegates?.catalogPlanVersion ?? DEFAULT_SCHEMA_OPTIONS.delegates.catalogPlanVersion,
405
+ entitlementPlanVersion: options?.delegates?.entitlementPlanVersion ?? DEFAULT_SCHEMA_OPTIONS.delegates.entitlementPlanVersion
406
+ },
407
+ planVersionFields: {
408
+ catalog: {
409
+ validityWindows: catalogFields?.validityWindows ?? sharedFields?.validityWindows ?? false,
410
+ endsAt: catalogFields?.endsAt ?? sharedFields?.endsAt ?? false
411
+ },
412
+ entitlement: {
413
+ validityWindows: entitlementFields?.validityWindows ?? sharedFields?.validityWindows ?? false,
414
+ endsAt: entitlementFields?.endsAt ?? sharedFields?.endsAt ?? false
415
+ }
416
+ },
417
+ tenantSubscription: {
418
+ delegate: options?.tenantSubscription?.delegate ?? DEFAULT_SCHEMA_OPTIONS.tenantSubscription.delegate,
419
+ subscriptionBundleDelegate: options?.tenantSubscription?.subscriptionBundleDelegate ?? DEFAULT_SCHEMA_OPTIONS.tenantSubscription.subscriptionBundleDelegate,
420
+ synchronizePlanVersion: options?.tenantSubscription?.synchronizePlanVersion ?? DEFAULT_SCHEMA_OPTIONS.tenantSubscription.synchronizePlanVersion,
421
+ atomicOnboardingSelection: options?.tenantSubscription?.atomicOnboardingSelection ?? DEFAULT_SCHEMA_OPTIONS.tenantSubscription.atomicOnboardingSelection,
422
+ activeVersionSelection: options?.tenantSubscription?.activeVersionSelection ?? DEFAULT_SCHEMA_OPTIONS.tenantSubscription.activeVersionSelection,
423
+ withEndsAt: options?.tenantSubscription?.withEndsAt ?? DEFAULT_SCHEMA_OPTIONS.tenantSubscription.withEndsAt
424
+ }
425
+ };
426
+ }
427
+ __name(resolvePrismaSchemaOptions, "resolvePrismaSchemaOptions");
428
+ function createPrismaPlanBindingResolver(options) {
429
+ const resolved = resolvePrismaSchemaOptions({
430
+ planBinding: options
431
+ }).planBinding;
432
+ return {
433
+ mode: resolved.mode,
434
+ projectKey: resolved.projectKey,
435
+ async toStoragePlanId(client, planKey, projectKey) {
436
+ if (resolved.mode === "legacy-plan-key") return planKey;
437
+ const scope = resolveProjectKey(resolved.projectKey, projectKey);
438
+ const plan = await asPlanIdentityClient(client).plan.findFirst({
439
+ where: {
440
+ projectKey: scope,
441
+ planKey,
442
+ deletedAt: null
443
+ }
444
+ });
445
+ if (!plan) {
446
+ throw new Error(`Plan '${planKey}' not found in project '${scope}'.`);
447
+ }
448
+ return plan.id;
449
+ },
450
+ async toPlanKey(client, storedPlanId, projectKey) {
451
+ if (resolved.mode === "legacy-plan-key") return storedPlanId;
452
+ const scope = resolveProjectKey(resolved.projectKey, projectKey);
453
+ const plan = await asPlanIdentityClient(client).plan.findUnique({
454
+ where: {
455
+ id: storedPlanId
456
+ }
457
+ });
458
+ if (!plan || plan.projectKey !== scope) {
459
+ throw new Error(`Plan id '${storedPlanId}' not found in project '${scope}'.`);
460
+ }
461
+ return plan.planKey;
462
+ }
463
+ };
464
+ }
465
+ __name(createPrismaPlanBindingResolver, "createPrismaPlanBindingResolver");
466
+ function getPrismaDelegate(client, delegateName) {
467
+ const delegate = client?.[delegateName];
468
+ if (!delegate || typeof delegate !== "object") {
469
+ throw new Error(`Prisma client has no '${delegateName}' delegate.`);
470
+ }
471
+ return delegate;
472
+ }
473
+ __name(getPrismaDelegate, "getPrismaDelegate");
474
+ function resolveProjectKey(configured, requested) {
475
+ const projectKey = requested ?? configured;
476
+ if (!projectKey) {
477
+ throw new Error("Prisma plan binding mode 'normalized-plan-id' requires a projectKey.");
478
+ }
479
+ if (configured && requested && configured !== requested) {
480
+ throw new Error(`Prisma plan binding is configured for project '${configured}', not '${requested}'.`);
481
+ }
482
+ return projectKey;
483
+ }
484
+ __name(resolveProjectKey, "resolveProjectKey");
485
+ function asPlanIdentityClient(client) {
486
+ if (!client || typeof client !== "object" || !("plan" in client)) {
487
+ throw new Error("Prisma client has no 'plan' delegate.");
488
+ }
489
+ return client;
490
+ }
491
+ __name(asPlanIdentityClient, "asPlanIdentityClient");
492
+
493
+ // src/prisma-plan-catalog-import-sink.ts
343
494
  function _ts_decorate6(decorators, target, key, desc) {
344
495
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
345
496
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
@@ -362,11 +513,23 @@ var PrismaPlanCatalogImportSink = class {
362
513
  __name(this, "PrismaPlanCatalogImportSink");
363
514
  }
364
515
  prisma;
365
- constructor(prisma) {
516
+ binding;
517
+ delegateName;
518
+ constructor(prisma, options) {
366
519
  this.prisma = prisma;
520
+ const schema = resolvePrismaSchemaOptions(options);
521
+ this.binding = createPrismaPlanBindingResolver(options?.planBinding);
522
+ this.delegateName = schema.delegates.catalogPlanVersion;
523
+ }
524
+ db() {
525
+ return this.prisma;
367
526
  }
368
527
  async upsertPlan(input) {
369
- const existing = await this.prisma.plan.findFirst({
528
+ if (this.binding.mode === "normalized-plan-id" && this.binding.projectKey !== input.projectKey) {
529
+ throw new Error(`Prisma plan binding is configured for project '${this.binding.projectKey}', not '${input.projectKey}'.`);
530
+ }
531
+ const db = this.db();
532
+ const existing = await db.plan.findFirst({
370
533
  where: {
371
534
  projectKey: input.projectKey,
372
535
  planKey: input.planKey
@@ -376,7 +539,7 @@ var PrismaPlanCatalogImportSink = class {
376
539
  created: false,
377
540
  skipReason: "exists"
378
541
  };
379
- await this.prisma.plan.create({
542
+ await db.plan.create({
380
543
  data: {
381
544
  projectKey: input.projectKey,
382
545
  planKey: input.planKey,
@@ -390,9 +553,11 @@ var PrismaPlanCatalogImportSink = class {
390
553
  };
391
554
  }
392
555
  async upsertPlanVersion(input) {
393
- const existing = await this.prisma.planVersion.findFirst({
556
+ const planVersion = this.planVersions();
557
+ const storedPlanId = await this.binding.toStoragePlanId(this.prisma, input.planKey);
558
+ const existing = await planVersion.findFirst({
394
559
  where: {
395
- planId: input.planKey,
560
+ planId: storedPlanId,
396
561
  version: input.version
397
562
  }
398
563
  });
@@ -402,9 +567,9 @@ var PrismaPlanCatalogImportSink = class {
402
567
  };
403
568
  const now = /* @__PURE__ */ new Date();
404
569
  if (input.publish) {
405
- await this.prisma.planVersion.updateMany({
570
+ await planVersion.updateMany({
406
571
  where: {
407
- planId: input.planKey,
572
+ planId: storedPlanId,
408
573
  publishedAt: {
409
574
  not: null
410
575
  },
@@ -418,9 +583,9 @@ var PrismaPlanCatalogImportSink = class {
418
583
  }
419
584
  });
420
585
  }
421
- await this.prisma.planVersion.create({
586
+ await planVersion.create({
422
587
  data: {
423
- planId: input.planKey,
588
+ planId: storedPlanId,
424
589
  version: input.version,
425
590
  features: input.features,
426
591
  quotas: input.quotas,
@@ -435,8 +600,12 @@ var PrismaPlanCatalogImportSink = class {
435
600
  created: true
436
601
  };
437
602
  }
603
+ planVersions() {
604
+ return getPrismaDelegate(this.prisma, this.delegateName);
605
+ }
438
606
  async upsertFeatureCatalogEntry(input) {
439
- const existing = await this.prisma.featureCatalogEntry.findFirst({
607
+ const db = this.db();
608
+ const existing = await db.featureCatalogEntry.findFirst({
440
609
  where: {
441
610
  projectKey: input.projectKey,
442
611
  featureKey: input.featureKey
@@ -446,7 +615,7 @@ var PrismaPlanCatalogImportSink = class {
446
615
  created: false,
447
616
  skipReason: "exists"
448
617
  };
449
- await this.prisma.featureCatalogEntry.create({
618
+ await db.featureCatalogEntry.create({
450
619
  data: {
451
620
  projectKey: input.projectKey,
452
621
  featureKey: input.featureKey,
@@ -465,9 +634,12 @@ var PrismaPlanCatalogImportSink = class {
465
634
  PrismaPlanCatalogImportSink = _ts_decorate6([
466
635
  (0, import_common6.Injectable)(),
467
636
  _ts_param5(0, (0, import_common6.Inject)(PRISMA_CLIENT_TOKEN)),
637
+ _ts_param5(1, (0, import_common6.Optional)()),
638
+ _ts_param5(1, (0, import_common6.Inject)(PRISMA_SCHEMA_OPTIONS_TOKEN)),
468
639
  _ts_metadata5("design:type", Function),
469
640
  _ts_metadata5("design:paramtypes", [
470
- typeof PrismaLike === "undefined" ? Object : PrismaLike
641
+ typeof PlanCatalogImportClient === "undefined" ? Object : PlanCatalogImportClient,
642
+ typeof PrismaSchemaOptions === "undefined" ? Object : PrismaSchemaOptions
471
643
  ])
472
644
  ], PrismaPlanCatalogImportSink);
473
645
 
@@ -514,11 +686,25 @@ var PrismaPlanCatalogReadSink = class {
514
686
  __name(this, "PrismaPlanCatalogReadSink");
515
687
  }
516
688
  prisma;
517
- constructor(prisma) {
689
+ binding;
690
+ delegateName;
691
+ fields;
692
+ constructor(prisma, options) {
518
693
  this.prisma = prisma;
694
+ const schema = resolvePrismaSchemaOptions(options);
695
+ this.binding = createPrismaPlanBindingResolver(options?.planBinding);
696
+ this.delegateName = schema.delegates.catalogPlanVersion;
697
+ this.fields = schema.planVersionFields.catalog;
698
+ }
699
+ db() {
700
+ return this.prisma;
519
701
  }
520
702
  async loadSnapshot(projectKey) {
521
- const plans = await this.prisma.plan.findMany({
703
+ if (this.binding.mode === "normalized-plan-id" && this.binding.projectKey !== projectKey) {
704
+ throw new Error(`Prisma plan binding is configured for project '${this.binding.projectKey}', not '${projectKey}'.`);
705
+ }
706
+ const db = this.db();
707
+ const plans = await db.plan.findMany({
522
708
  where: {
523
709
  projectKey,
524
710
  deletedAt: null
@@ -527,11 +713,17 @@ var PrismaPlanCatalogReadSink = class {
527
713
  sortOrder: "asc"
528
714
  }
529
715
  });
530
- const planKeys = plans.map((plan) => plan.planKey);
531
- const livePlanVersions = planKeys.length === 0 ? [] : await this.prisma.planVersion.findMany({
716
+ const planKeysByStoredId = new Map(plans.map((plan) => [
717
+ this.binding.mode === "normalized-plan-id" ? plan.id : plan.planKey,
718
+ plan.planKey
719
+ ]));
720
+ const storedPlanIds = [
721
+ ...planKeysByStoredId.keys()
722
+ ];
723
+ const livePlanVersions = storedPlanIds.length === 0 ? [] : await this.planVersions().findMany({
532
724
  where: {
533
725
  planId: {
534
- in: planKeys
726
+ in: storedPlanIds
535
727
  },
536
728
  publishedAt: {
537
729
  not: null
@@ -539,7 +731,7 @@ var PrismaPlanCatalogReadSink = class {
539
731
  supersededAt: null
540
732
  }
541
733
  });
542
- const featureEntries = await this.prisma.featureCatalogEntry.findMany({
734
+ const featureEntries = await db.featureCatalogEntry.findMany({
543
735
  where: {
544
736
  projectKey,
545
737
  deletedAt: null
@@ -550,17 +742,29 @@ var PrismaPlanCatalogReadSink = class {
550
742
  });
551
743
  return {
552
744
  plans: plans.map(toPlanRow),
553
- livePlanVersions: livePlanVersions.map(toPlanVersionRow),
745
+ livePlanVersions: livePlanVersions.map((row) => {
746
+ const planKey = planKeysByStoredId.get(row.planId);
747
+ if (!planKey) {
748
+ throw new Error(`PlanVersion ${row.id} references plan '${row.planId}' outside project '${projectKey}'.`);
749
+ }
750
+ return toPlanVersionRow(row, planKey, this.fields);
751
+ }),
554
752
  featureEntries: featureEntries.map(toFeatureCatalogEntryRow)
555
753
  };
556
754
  }
755
+ planVersions() {
756
+ return getPrismaDelegate(this.prisma, this.delegateName);
757
+ }
557
758
  };
558
759
  PrismaPlanCatalogReadSink = _ts_decorate7([
559
760
  (0, import_common7.Injectable)(),
560
761
  _ts_param6(0, (0, import_common7.Inject)(PRISMA_CLIENT_TOKEN)),
762
+ _ts_param6(1, (0, import_common7.Optional)()),
763
+ _ts_param6(1, (0, import_common7.Inject)(PRISMA_SCHEMA_OPTIONS_TOKEN)),
561
764
  _ts_metadata6("design:type", Function),
562
765
  _ts_metadata6("design:paramtypes", [
563
- typeof PrismaLike === "undefined" ? Object : PrismaLike
766
+ typeof PlanCatalogReadClient === "undefined" ? Object : PlanCatalogReadClient,
767
+ typeof PrismaSchemaOptions === "undefined" ? Object : PrismaSchemaOptions
564
768
  ])
565
769
  ], PrismaPlanCatalogReadSink);
566
770
  function toPlanRow(row) {
@@ -578,10 +782,10 @@ function toPlanRow(row) {
578
782
  };
579
783
  }
580
784
  __name(toPlanRow, "toPlanRow");
581
- function toPlanVersionRow(row) {
582
- return {
785
+ function toPlanVersionRow(row, planKey, fields) {
786
+ const mapped = {
583
787
  id: row.id,
584
- planId: row.planId,
788
+ planId: planKey,
585
789
  version: row.version,
586
790
  baseVersionId: row.baseVersionId,
587
791
  publishedAt: row.publishedAt ? row.publishedAt.toISOString() : null,
@@ -589,8 +793,8 @@ function toPlanVersionRow(row) {
589
793
  publishedChanges: row.publishedChanges ?? null,
590
794
  changeNote: row.changeNote,
591
795
  nonRegressive: row.nonRegressive,
592
- validFrom: null,
593
- validUntil: null,
796
+ validFrom: fields.validityWindows && row.validFrom ? row.validFrom.toISOString() : null,
797
+ validUntil: fields.validityWindows && row.validUntil ? row.validUntil.toISOString() : null,
594
798
  createdByUserId: row.createdByUserId,
595
799
  publishedByUserId: row.publishedByUserId,
596
800
  createdAt: row.createdAt.toISOString(),
@@ -601,6 +805,10 @@ function toPlanVersionRow(row) {
601
805
  yearlyNet: String(row.yearlyNet),
602
806
  marketed: row.marketed
603
807
  };
808
+ if (fields.endsAt) {
809
+ mapped.endsAt = row.endsAt?.toISOString() ?? null;
810
+ }
811
+ return mapped;
604
812
  }
605
813
  __name(toPlanVersionRow, "toPlanVersionRow");
606
814
  function toFeatureCatalogEntryRow(row) {
@@ -634,6 +842,7 @@ __name(toFeatureCatalogEntryRow, "toFeatureCatalogEntryRow");
634
842
 
635
843
  // src/prisma-plan-version.repository.ts
636
844
  var import_common8 = require("@nestjs/common");
845
+ var import_types = require("@saasicat/types");
637
846
  function _ts_decorate8(decorators, target, key, desc) {
638
847
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
639
848
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
@@ -656,14 +865,29 @@ var PrismaPlanVersionRepository = class {
656
865
  __name(this, "PrismaPlanVersionRepository");
657
866
  }
658
867
  prisma;
659
- constructor(prisma) {
868
+ findActive;
869
+ binding;
870
+ delegateName;
871
+ fields;
872
+ constructor(prisma, options) {
660
873
  this.prisma = prisma;
874
+ const schema = resolvePrismaSchemaOptions(options);
875
+ this.binding = createPrismaPlanBindingResolver(options?.planBinding);
876
+ this.delegateName = schema.delegates.entitlementPlanVersion;
877
+ this.fields = schema.planVersionFields.entitlement;
878
+ if (this.fields.validityWindows) {
879
+ this.findActive = (planId, asOf = /* @__PURE__ */ new Date(), tx) => this.findActivePlanVersion(planId, asOf, tx);
880
+ }
881
+ }
882
+ db(tx) {
883
+ return tx ?? this.prisma;
661
884
  }
662
885
  async findLatestLive(planId, tx) {
663
- const db = resolveClient(this.prisma, tx);
664
- const row = await db.planVersion.findFirst({
886
+ const db = this.db(tx);
887
+ const storedPlanId = await this.binding.toStoragePlanId(db, planId);
888
+ const row = await this.versions(db).findFirst({
665
889
  where: {
666
- planId,
890
+ planId: storedPlanId,
667
891
  publishedAt: {
668
892
  not: null
669
893
  },
@@ -674,8 +898,40 @@ var PrismaPlanVersionRepository = class {
674
898
  }
675
899
  });
676
900
  if (!row) return null;
901
+ return this.toRecord(db, row);
902
+ }
903
+ async findActivePlanVersion(planId, asOf, tx) {
904
+ const db = this.db(tx);
905
+ const storedPlanId = await this.binding.toStoragePlanId(db, planId);
906
+ const activeWhere = this.fields.endsAt ? (0, import_types.buildActivePlanVersionWhere)(asOf, {
907
+ withEndsAt: true
908
+ }) : (0, import_types.buildActivePlanVersionWhere)(asOf);
909
+ const row = await this.versions(db).findFirst({
910
+ where: {
911
+ planId: storedPlanId,
912
+ ...activeWhere
913
+ },
914
+ orderBy: [
915
+ {
916
+ validFrom: {
917
+ sort: "desc",
918
+ nulls: "last"
919
+ }
920
+ },
921
+ {
922
+ version: "desc"
923
+ }
924
+ ]
925
+ });
926
+ if (!row) return null;
927
+ return this.toRecord(db, row);
928
+ }
929
+ versions(client) {
930
+ return getPrismaDelegate(client, this.delegateName);
931
+ }
932
+ async toRecord(client, row) {
677
933
  return {
678
- planId: row.planId,
934
+ planId: await this.binding.toPlanKey(client, row.planId),
679
935
  quotas: toQuotaMap(row.quotas),
680
936
  features: toStringArray(row.features)
681
937
  };
@@ -684,9 +940,12 @@ var PrismaPlanVersionRepository = class {
684
940
  PrismaPlanVersionRepository = _ts_decorate8([
685
941
  (0, import_common8.Injectable)(),
686
942
  _ts_param7(0, (0, import_common8.Inject)(PRISMA_CLIENT_TOKEN)),
943
+ _ts_param7(1, (0, import_common8.Optional)()),
944
+ _ts_param7(1, (0, import_common8.Inject)(PRISMA_SCHEMA_OPTIONS_TOKEN)),
687
945
  _ts_metadata7("design:type", Function),
688
946
  _ts_metadata7("design:paramtypes", [
689
- typeof PrismaLike === "undefined" ? Object : PrismaLike
947
+ typeof PlanVersionRepositoryClient === "undefined" ? Object : PlanVersionRepositoryClient,
948
+ typeof PrismaSchemaOptions === "undefined" ? Object : PrismaSchemaOptions
690
949
  ])
691
950
  ], PrismaPlanVersionRepository);
692
951
 
@@ -1154,19 +1413,35 @@ var PrismaSubscriptionRepository = class {
1154
1413
  __name(this, "PrismaSubscriptionRepository");
1155
1414
  }
1156
1415
  prisma;
1157
- constructor(prisma) {
1416
+ countByBundleVersionId;
1417
+ binding;
1418
+ planVersionDelegateName;
1419
+ subscriptionDelegateName;
1420
+ subscriptionBundleDelegateName;
1421
+ constructor(prisma, options) {
1158
1422
  this.prisma = prisma;
1423
+ const schema = resolvePrismaSchemaOptions(options);
1424
+ this.binding = createPrismaPlanBindingResolver(options?.planBinding);
1425
+ this.planVersionDelegateName = schema.delegates.entitlementPlanVersion;
1426
+ this.subscriptionDelegateName = schema.tenantSubscription.delegate;
1427
+ this.subscriptionBundleDelegateName = schema.tenantSubscription.subscriptionBundleDelegate;
1428
+ if (this.subscriptionBundleDelegateName) {
1429
+ this.countByBundleVersionId = (bundleVersionId) => this.countActiveBundleBindings(bundleVersionId);
1430
+ }
1431
+ }
1432
+ db(tx) {
1433
+ return tx ?? this.prisma;
1159
1434
  }
1160
1435
  async findByTenantId(tenantId) {
1161
- return this.loadByTenantId(this.prisma, tenantId);
1436
+ return this.loadByTenantId(this.db(), tenantId);
1162
1437
  }
1163
1438
  async findByTenantIdLocked(tenantId, tx) {
1164
- const db = resolveClient(this.prisma, tx);
1439
+ const db = this.db(tx);
1165
1440
  await db.$queryRaw`SELECT id FROM subscriptions WHERE "tenantId" = ${tenantId} FOR UPDATE`;
1166
1441
  return this.loadByTenantId(db, tenantId);
1167
1442
  }
1168
1443
  async countByPlanVersionId(planVersionId) {
1169
- return this.prisma.subscription.count({
1444
+ return this.subscriptions(this.db()).count({
1170
1445
  where: {
1171
1446
  OR: [
1172
1447
  {
@@ -1179,22 +1454,72 @@ var PrismaSubscriptionRepository = class {
1179
1454
  }
1180
1455
  });
1181
1456
  }
1182
- async countActiveByPlanKey(_projectKey) {
1183
- const rows = await this.prisma.subscription.findMany({
1457
+ async countActiveByPlanKey(projectKey) {
1458
+ const db = this.db();
1459
+ const subscriptions = await this.subscriptions(db).findMany({
1184
1460
  where: {
1185
1461
  status: {
1186
1462
  in: ACTIVE_STATUSES
1187
1463
  }
1464
+ },
1465
+ select: {
1466
+ planVersionId: true
1467
+ }
1468
+ });
1469
+ const versionIds = [
1470
+ ...new Set(subscriptions.map((subscription) => subscription.planVersionId))
1471
+ ];
1472
+ if (versionIds.length === 0) return {};
1473
+ const planVersions = await this.planVersions(db).findMany({
1474
+ where: {
1475
+ id: {
1476
+ in: versionIds
1477
+ }
1478
+ },
1479
+ select: {
1480
+ id: true,
1481
+ planId: true
1188
1482
  }
1189
1483
  });
1484
+ const planVersionById = new Map(planVersions.map((planVersion) => [
1485
+ planVersion.id,
1486
+ planVersion
1487
+ ]));
1488
+ const storedPlanIds = [
1489
+ ...new Set(planVersions.map((planVersion) => planVersion.planId))
1490
+ ];
1491
+ const planKeyByStoredId = await this.planKeysForProject(db, storedPlanIds, projectKey);
1190
1492
  const counts = {};
1191
- for (const row of rows) {
1192
- counts[row.plan] = (counts[row.plan] ?? 0) + 1;
1493
+ for (const subscription of subscriptions) {
1494
+ const planVersion = planVersionById.get(subscription.planVersionId);
1495
+ const planKey = planVersion ? planKeyByStoredId.get(planVersion.planId) : void 0;
1496
+ if (!planKey) continue;
1497
+ counts[planKey] = (counts[planKey] ?? 0) + 1;
1193
1498
  }
1194
1499
  return counts;
1195
1500
  }
1501
+ async countActiveBundleBindings(bundleVersionId) {
1502
+ if (!this.subscriptionBundleDelegateName) {
1503
+ throw new Error("SubscriptionBundle counting is not configured.");
1504
+ }
1505
+ return getPrismaDelegate(this.prisma, this.subscriptionBundleDelegateName).count({
1506
+ where: {
1507
+ bundleVersionId,
1508
+ OR: [
1509
+ {
1510
+ canceledAt: null
1511
+ },
1512
+ {
1513
+ canceledEffectiveAt: {
1514
+ gt: /* @__PURE__ */ new Date()
1515
+ }
1516
+ }
1517
+ ]
1518
+ }
1519
+ });
1520
+ }
1196
1521
  async loadByTenantId(db, tenantId) {
1197
- const row = await db.subscription.findUnique({
1522
+ const row = await this.subscriptions(db).findUnique({
1198
1523
  where: {
1199
1524
  tenantId
1200
1525
  }
@@ -1203,10 +1528,7 @@ var PrismaSubscriptionRepository = class {
1203
1528
  return this.toRecord(db, row);
1204
1529
  }
1205
1530
  async toRecord(db, row) {
1206
- if (!row.planVersionId) {
1207
- throw new Error(`Subscription ${row.id} binds no planVersionId (businessType-only composition). The shipped @saasicat/adapter-prisma SubscriptionRepository does not support BusinessType aggregation \u2014 provide a custom SubscriptionRepository adapter.`);
1208
- }
1209
- const planVersion = await db.planVersion.findUnique({
1531
+ const planVersion = await this.planVersions(db).findUnique({
1210
1532
  where: {
1211
1533
  id: row.planVersionId
1212
1534
  }
@@ -1214,10 +1536,13 @@ var PrismaSubscriptionRepository = class {
1214
1536
  if (!planVersion) {
1215
1537
  throw new Error(`Subscription ${row.id} references missing PlanVersion ${row.planVersionId}.`);
1216
1538
  }
1539
+ const planKey = await this.binding.toPlanKey(db, planVersion.planId);
1217
1540
  return {
1218
1541
  id: row.id,
1219
1542
  tenantId: row.tenantId,
1220
- plan: row.plan,
1543
+ // The concrete PlanVersion is authoritative. This also normalizes
1544
+ // legacy rows whose denormalized `Subscription.plan` drifted.
1545
+ plan: planKey,
1221
1546
  status: row.status,
1222
1547
  isPilot: row.isPilot,
1223
1548
  trialEntitlementPlan: row.trialEntitlementPlan,
@@ -1226,25 +1551,84 @@ var PrismaSubscriptionRepository = class {
1226
1551
  customLimits: row.customLimits ?? null,
1227
1552
  planVersionId: row.planVersionId,
1228
1553
  planVersion: {
1229
- planId: planVersion.planId,
1554
+ planId: planKey,
1230
1555
  quotas: toQuotaMap(planVersion.quotas),
1231
1556
  features: toStringArray(planVersion.features)
1232
1557
  }
1233
1558
  };
1234
1559
  }
1560
+ planVersions(client) {
1561
+ return getPrismaDelegate(client, this.planVersionDelegateName);
1562
+ }
1563
+ subscriptions(client) {
1564
+ return getPrismaDelegate(client, this.subscriptionDelegateName);
1565
+ }
1566
+ async planKeysForProject(db, storedPlanIds, projectKey) {
1567
+ if (storedPlanIds.length === 0) return /* @__PURE__ */ new Map();
1568
+ if (this.binding.mode === "normalized-plan-id") {
1569
+ if (this.binding.projectKey && this.binding.projectKey !== projectKey) {
1570
+ throw new Error(`Prisma plan binding is configured for project '${this.binding.projectKey}', not '${projectKey}'.`);
1571
+ }
1572
+ const plans2 = await db.plan.findMany({
1573
+ where: {
1574
+ projectKey,
1575
+ id: {
1576
+ in: storedPlanIds
1577
+ }
1578
+ },
1579
+ select: {
1580
+ id: true,
1581
+ planKey: true
1582
+ }
1583
+ });
1584
+ return new Map(plans2.map((plan) => [
1585
+ plan.id,
1586
+ plan.planKey
1587
+ ]));
1588
+ }
1589
+ const plans = await db.plan.findMany({
1590
+ where: {
1591
+ planKey: {
1592
+ in: storedPlanIds
1593
+ }
1594
+ },
1595
+ select: {
1596
+ projectKey: true,
1597
+ planKey: true
1598
+ }
1599
+ });
1600
+ const projectsByPlanKey = /* @__PURE__ */ new Map();
1601
+ for (const plan of plans) {
1602
+ const projects = projectsByPlanKey.get(plan.planKey) ?? /* @__PURE__ */ new Set();
1603
+ projects.add(plan.projectKey);
1604
+ projectsByPlanKey.set(plan.planKey, projects);
1605
+ }
1606
+ return new Map(storedPlanIds.flatMap((planKey) => {
1607
+ const projects = projectsByPlanKey.get(planKey);
1608
+ return projects?.size === 1 && projects.has(projectKey) ? [
1609
+ [
1610
+ planKey,
1611
+ planKey
1612
+ ]
1613
+ ] : [];
1614
+ }));
1615
+ }
1235
1616
  };
1236
1617
  PrismaSubscriptionRepository = _ts_decorate13([
1237
1618
  (0, import_common13.Injectable)(),
1238
1619
  _ts_param12(0, (0, import_common13.Inject)(PRISMA_CLIENT_TOKEN)),
1620
+ _ts_param12(1, (0, import_common13.Optional)()),
1621
+ _ts_param12(1, (0, import_common13.Inject)(PRISMA_SCHEMA_OPTIONS_TOKEN)),
1239
1622
  _ts_metadata12("design:type", Function),
1240
1623
  _ts_metadata12("design:paramtypes", [
1241
- typeof PrismaLike === "undefined" ? Object : PrismaLike
1624
+ typeof SubscriptionRepositoryClient === "undefined" ? Object : SubscriptionRepositoryClient,
1625
+ typeof PrismaSchemaOptions === "undefined" ? Object : PrismaSchemaOptions
1242
1626
  ])
1243
1627
  ], PrismaSubscriptionRepository);
1244
1628
 
1245
1629
  // src/prisma-super-admin-bootstrap.adapter.ts
1246
1630
  var import_common14 = require("@nestjs/common");
1247
- var import_types = require("@saasicat/types");
1631
+ var import_types2 = require("@saasicat/types");
1248
1632
  function _ts_decorate14(decorators, target, key, desc) {
1249
1633
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1250
1634
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
@@ -1289,7 +1673,7 @@ var PrismaSuperAdminBootstrapAdapter = class {
1289
1673
  }
1290
1674
  });
1291
1675
  if (existing) {
1292
- throw new import_types.PlatformUserExistsError(email, existing.platformRole);
1676
+ throw new import_types2.PlatformUserExistsError(email, existing.platformRole);
1293
1677
  }
1294
1678
  const row = await this.prisma.superAdminUser.create({
1295
1679
  data: {
@@ -1350,7 +1734,8 @@ var PrismaTransactionRunner = class {
1350
1734
  this.prisma = prisma;
1351
1735
  }
1352
1736
  async run(fn) {
1353
- return this.prisma.$transaction((tx) => fn(tx));
1737
+ const transaction = this.prisma.$transaction.bind(this.prisma);
1738
+ return transaction((tx) => fn(tx));
1354
1739
  }
1355
1740
  };
1356
1741
  PrismaTransactionRunner = _ts_decorate15([
@@ -1358,7 +1743,7 @@ PrismaTransactionRunner = _ts_decorate15([
1358
1743
  _ts_param14(0, (0, import_common15.Inject)(PRISMA_CLIENT_TOKEN)),
1359
1744
  _ts_metadata14("design:type", Function),
1360
1745
  _ts_metadata14("design:paramtypes", [
1361
- typeof PrismaLike === "undefined" ? Object : PrismaLike
1746
+ typeof Record === "undefined" ? Object : Record
1362
1747
  ])
1363
1748
  ], PrismaTransactionRunner);
1364
1749
 
@@ -1409,8 +1794,8 @@ function prismaPersistence(options) {
1409
1794
  superAdminProvisioning: buildProvisioning(client, options.passwordHasher)
1410
1795
  },
1411
1796
  entitlement: {
1412
- subscriptionRepository: provide((prisma) => new PrismaSubscriptionRepository(prisma)),
1413
- planVersionRepository: provide((prisma) => new PrismaPlanVersionRepository(prisma))
1797
+ subscriptionRepository: provide((prisma) => new PrismaSubscriptionRepository(prisma, options.schema)),
1798
+ planVersionRepository: provide((prisma) => new PrismaPlanVersionRepository(prisma, options.schema))
1414
1799
  },
1415
1800
  promo: {
1416
1801
  promoCodeRepository: provide((prisma) => new PrismaPromoCodeRepository(prisma)),
@@ -1419,8 +1804,8 @@ function prismaPersistence(options) {
1419
1804
  subscriptionLookup: provide((prisma) => new PrismaPromoSubscriptionLookup(prisma)),
1420
1805
  revenueAggregator: new ZeroPromoRevenueDeductionAggregator()
1421
1806
  },
1422
- planCatalogReadSink: provide((prisma) => new PrismaPlanCatalogReadSink(prisma)),
1423
- planCatalogImportSink: provide((prisma) => new PrismaPlanCatalogImportSink(prisma))
1807
+ planCatalogReadSink: provide((prisma) => new PrismaPlanCatalogReadSink(prisma, options.schema)),
1808
+ planCatalogImportSink: provide((prisma) => new PrismaPlanCatalogImportSink(prisma, options.schema))
1424
1809
  };
1425
1810
  }
1426
1811
  __name(prismaPersistence, "prismaPersistence");
@@ -1460,26 +1845,2747 @@ function buildProvisioning(client, hasher) {
1460
1845
  return new PrismaSuperAdminBootstrapAdapter(client, hasher);
1461
1846
  }
1462
1847
  __name(buildProvisioning, "buildProvisioning");
1848
+
1849
+ // src/prisma-subscription-bundle.repository.ts
1850
+ var import_common17 = require("@nestjs/common");
1851
+ function _ts_decorate17(decorators, target, key, desc) {
1852
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1853
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
1854
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
1855
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
1856
+ }
1857
+ __name(_ts_decorate17, "_ts_decorate");
1858
+ function _ts_metadata15(k, v) {
1859
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
1860
+ }
1861
+ __name(_ts_metadata15, "_ts_metadata");
1862
+ function _ts_param15(paramIndex, decorator) {
1863
+ return function(target, key) {
1864
+ decorator(target, key, paramIndex);
1865
+ };
1866
+ }
1867
+ __name(_ts_param15, "_ts_param");
1868
+ var PrismaSubscriptionBundleRepository = class {
1869
+ static {
1870
+ __name(this, "PrismaSubscriptionBundleRepository");
1871
+ }
1872
+ prisma;
1873
+ constructor(prisma) {
1874
+ this.prisma = prisma;
1875
+ }
1876
+ db(tx) {
1877
+ return tx ?? this.prisma;
1878
+ }
1879
+ async listBySubscription(subscriptionId) {
1880
+ const rows = await this.db().subscriptionBundle.findMany({
1881
+ where: {
1882
+ subscriptionId
1883
+ },
1884
+ orderBy: {
1885
+ startedAt: "desc"
1886
+ }
1887
+ });
1888
+ return rows.map(toRecord3);
1889
+ }
1890
+ async findById(subscriptionBundleId) {
1891
+ const row = await this.db().subscriptionBundle.findUnique({
1892
+ where: {
1893
+ id: subscriptionBundleId
1894
+ }
1895
+ });
1896
+ return row ? toRecord3(row) : null;
1897
+ }
1898
+ async listActiveBySubscription(subscriptionId, asOf = /* @__PURE__ */ new Date()) {
1899
+ const rows = await this.db().subscriptionBundle.findMany({
1900
+ where: {
1901
+ subscriptionId,
1902
+ OR: [
1903
+ {
1904
+ canceledAt: null
1905
+ },
1906
+ {
1907
+ canceledEffectiveAt: {
1908
+ gt: asOf
1909
+ }
1910
+ }
1911
+ ]
1912
+ },
1913
+ orderBy: {
1914
+ startedAt: "desc"
1915
+ }
1916
+ });
1917
+ return rows.map(toRecord3);
1918
+ }
1919
+ async add(data) {
1920
+ const row = await this.db().subscriptionBundle.create({
1921
+ data: {
1922
+ subscriptionId: data.subscriptionId,
1923
+ bundleVersionId: data.bundleVersionId,
1924
+ startedAt: data.startedAt,
1925
+ minimumTermEndsAt: data.minimumTermEndsAt ?? null
1926
+ }
1927
+ });
1928
+ return toRecord3(row);
1929
+ }
1930
+ async cancel(subscriptionBundleId, data) {
1931
+ const row = await this.db().subscriptionBundle.update({
1932
+ where: {
1933
+ id: subscriptionBundleId
1934
+ },
1935
+ data: {
1936
+ canceledAt: data.canceledAt,
1937
+ canceledEffectiveAt: data.canceledEffectiveAt
1938
+ }
1939
+ });
1940
+ return toRecord3(row);
1941
+ }
1942
+ async reactivate(subscriptionBundleId) {
1943
+ const row = await this.db().subscriptionBundle.update({
1944
+ where: {
1945
+ id: subscriptionBundleId
1946
+ },
1947
+ data: {
1948
+ canceledAt: null,
1949
+ canceledEffectiveAt: null
1950
+ }
1951
+ });
1952
+ return toRecord3(row);
1953
+ }
1954
+ async countActiveByBundleVersionId(bundleVersionId, asOf = /* @__PURE__ */ new Date()) {
1955
+ return this.db().subscriptionBundle.count({
1956
+ where: {
1957
+ bundleVersionId,
1958
+ OR: [
1959
+ {
1960
+ canceledAt: null
1961
+ },
1962
+ {
1963
+ canceledEffectiveAt: {
1964
+ gt: asOf
1965
+ }
1966
+ }
1967
+ ]
1968
+ }
1969
+ });
1970
+ }
1971
+ };
1972
+ PrismaSubscriptionBundleRepository = _ts_decorate17([
1973
+ (0, import_common17.Injectable)(),
1974
+ _ts_param15(0, (0, import_common17.Inject)(PRISMA_CLIENT_TOKEN)),
1975
+ _ts_metadata15("design:type", Function),
1976
+ _ts_metadata15("design:paramtypes", [
1977
+ typeof SubscriptionBundleClient === "undefined" ? Object : SubscriptionBundleClient
1978
+ ])
1979
+ ], PrismaSubscriptionBundleRepository);
1980
+ function toRecord3(row) {
1981
+ return {
1982
+ id: row.id,
1983
+ subscriptionId: row.subscriptionId,
1984
+ bundleVersionId: row.bundleVersionId,
1985
+ startedAt: row.startedAt,
1986
+ minimumTermEndsAt: row.minimumTermEndsAt,
1987
+ canceledAt: row.canceledAt,
1988
+ canceledEffectiveAt: row.canceledEffectiveAt,
1989
+ createdAt: row.createdAt,
1990
+ updatedAt: row.updatedAt
1991
+ };
1992
+ }
1993
+ __name(toRecord3, "toRecord");
1994
+
1995
+ // src/prisma-tenant-subscription-write.adapter.ts
1996
+ var import_common18 = require("@nestjs/common");
1997
+ var import_types3 = require("@saasicat/types");
1998
+ function _ts_decorate18(decorators, target, key, desc) {
1999
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
2000
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
2001
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
2002
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
2003
+ }
2004
+ __name(_ts_decorate18, "_ts_decorate");
2005
+ function _ts_metadata16(k, v) {
2006
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
2007
+ }
2008
+ __name(_ts_metadata16, "_ts_metadata");
2009
+ function _ts_param16(paramIndex, decorator) {
2010
+ return function(target, key) {
2011
+ decorator(target, key, paramIndex);
2012
+ };
2013
+ }
2014
+ __name(_ts_param16, "_ts_param");
2015
+ var PrismaTenantSubscriptionWriteAdapter = class {
2016
+ static {
2017
+ __name(this, "PrismaTenantSubscriptionWriteAdapter");
2018
+ }
2019
+ prisma;
2020
+ applyOnboardingSelection;
2021
+ schema;
2022
+ planBinding;
2023
+ constructor(prisma, options) {
2024
+ this.prisma = prisma;
2025
+ this.schema = resolvePrismaSchemaOptions(options);
2026
+ this.planBinding = createPrismaPlanBindingResolver(options?.planBinding);
2027
+ this.assertConfiguration();
2028
+ if (this.schema.tenantSubscription.atomicOnboardingSelection) {
2029
+ this.applyOnboardingSelection = (tenantId, input, redeemPromo) => this.applyOnboardingSelectionAtomic(tenantId, input, redeemPromo);
2030
+ }
2031
+ }
2032
+ async changePlanImmediate(tenantId, input) {
2033
+ if (this.schema.tenantSubscription.synchronizePlanVersion) {
2034
+ return this.prisma.$transaction((tx) => this.changePlanImmediateInClient(tx, tenantId, input));
2035
+ }
2036
+ return this.changePlanImmediateInClient(this.prisma, tenantId, input);
2037
+ }
2038
+ async changePlanImmediateInClient(client, tenantId, input) {
2039
+ const subscription = this.subscription(client);
2040
+ const data = {
2041
+ plan: input.planId,
2042
+ billingCycle: input.cycle,
2043
+ pendingPlan: null,
2044
+ pendingBillingCycle: null,
2045
+ pendingEffectiveAt: null,
2046
+ ...input.nextStatus ? {
2047
+ status: input.nextStatus
2048
+ } : {},
2049
+ ...input.periodStart && input.periodEnd ? {
2050
+ currentPeriodStart: input.periodStart,
2051
+ currentPeriodEnd: input.periodEnd
2052
+ } : {},
2053
+ // #17: the platform changePlan path computes the carried-over
2054
+ // trial end and passes it through; null/undefined leaves the
2055
+ // existing trialEndsAt untouched.
2056
+ ...input.trialEndsAt ? {
2057
+ trialEndsAt: input.trialEndsAt
2058
+ } : {}
2059
+ };
2060
+ if (this.schema.tenantSubscription.synchronizePlanVersion) {
2061
+ const current = await subscription.findUnique({
2062
+ where: {
2063
+ tenantId
2064
+ }
2065
+ });
2066
+ if (!current) {
2067
+ throw new Error(`No subscription for tenant ${tenantId}.`);
2068
+ }
2069
+ const storagePlanId = await this.planBinding.toStoragePlanId(client, input.planId);
2070
+ data.planVersionId = await this.findTargetPlanVersionId(client, storagePlanId, input.periodStart ?? /* @__PURE__ */ new Date());
2071
+ if (await this.pendingVersionBelongsToAnotherPlan(client, current.pendingPlanVersionId, storagePlanId)) {
2072
+ Object.assign(data, clearedPendingVersionData());
2073
+ }
2074
+ }
2075
+ const updated = await subscription.update({
2076
+ where: {
2077
+ tenantId
2078
+ },
2079
+ data
2080
+ });
2081
+ return {
2082
+ plan: updated.plan,
2083
+ billingCycle: updated.billingCycle
2084
+ };
2085
+ }
2086
+ async schedulePlanChange(tenantId, input) {
2087
+ await this.subscription(this.prisma).update({
2088
+ where: {
2089
+ tenantId
2090
+ },
2091
+ data: {
2092
+ pendingPlan: input.pendingPlan,
2093
+ pendingBillingCycle: input.pendingBillingCycle,
2094
+ pendingEffectiveAt: input.pendingEffectiveAt
2095
+ }
2096
+ });
2097
+ }
2098
+ async acceptPendingPlanVersion(tenantId, userId, now) {
2099
+ const subscription = this.subscription(this.prisma);
2100
+ const sub = await subscription.findUnique({
2101
+ where: {
2102
+ tenantId
2103
+ }
2104
+ });
2105
+ if (!sub) {
2106
+ throw new Error(`No subscription for tenant ${tenantId}.`);
2107
+ }
2108
+ if (!sub.pendingPlanVersionId) {
2109
+ throw new Error(`No pending PlanVersion for tenant ${tenantId}.`);
2110
+ }
2111
+ const pendingPlanVersionId = sub.pendingPlanVersionId;
2112
+ const claimed = await subscription.updateMany({
2113
+ where: {
2114
+ id: sub.id,
2115
+ pendingPlanVersionId,
2116
+ pendingPlanVersionAccepted: false
2117
+ },
2118
+ data: {
2119
+ pendingPlanVersionAccepted: true,
2120
+ pendingPlanVersionAcceptedAt: now,
2121
+ pendingPlanVersionAcceptedByUserId: userId
2122
+ }
2123
+ });
2124
+ const updated = await subscription.findUnique({
2125
+ where: {
2126
+ id: sub.id
2127
+ }
2128
+ });
2129
+ if (!updated) {
2130
+ throw new Error(`No subscription for tenant ${tenantId}.`);
2131
+ }
2132
+ if (claimed.count === 0 && (updated.pendingPlanVersionId !== pendingPlanVersionId || !updated.pendingPlanVersionAccepted)) {
2133
+ throw new Error(`Pending PlanVersion changed while accepting it for tenant ${tenantId}.`);
2134
+ }
2135
+ return {
2136
+ accepted: true,
2137
+ acceptedAt: updated.pendingPlanVersionAcceptedAt,
2138
+ effectiveAt: updated.pendingPlanVersionEffectiveAt,
2139
+ alreadyAccepted: claimed.count === 0
2140
+ };
2141
+ }
2142
+ async applyOnboardingSelectionAtomic(tenantId, input, redeemPromo) {
2143
+ return this.prisma.$transaction(async (tx) => {
2144
+ const data = {
2145
+ plan: input.planId,
2146
+ billingCycle: input.cycle,
2147
+ pendingPlan: null,
2148
+ pendingBillingCycle: null,
2149
+ pendingEffectiveAt: null,
2150
+ ...clearedPendingVersionData(),
2151
+ ...input.nextStatus ? {
2152
+ status: input.nextStatus
2153
+ } : {},
2154
+ ...input.periodStart && input.periodEnd ? {
2155
+ currentPeriodStart: input.periodStart,
2156
+ currentPeriodEnd: input.periodEnd
2157
+ } : {}
2158
+ };
2159
+ if (this.schema.tenantSubscription.synchronizePlanVersion) {
2160
+ const storagePlanId = await this.planBinding.toStoragePlanId(tx, input.planId);
2161
+ data.planVersionId = await this.findTargetPlanVersionId(tx, storagePlanId, input.periodStart ?? /* @__PURE__ */ new Date());
2162
+ }
2163
+ const updated = await this.subscription(tx).update({
2164
+ where: {
2165
+ tenantId
2166
+ },
2167
+ data
2168
+ });
2169
+ let promoRedemption = null;
2170
+ if (redeemPromo) {
2171
+ promoRedemption = await redeemPromo(tx, updated.id);
2172
+ }
2173
+ return {
2174
+ plan: updated.plan,
2175
+ billingCycle: updated.billingCycle,
2176
+ subscriptionId: updated.id,
2177
+ promoRedemption
2178
+ };
2179
+ });
2180
+ }
2181
+ async cancelSubscription(tenantId, immediate, now) {
2182
+ const subscription = this.subscription(this.prisma);
2183
+ const sub = await subscription.findUnique({
2184
+ where: {
2185
+ tenantId
2186
+ }
2187
+ });
2188
+ if (!sub) {
2189
+ throw new Error(`No subscription for tenant ${tenantId}.`);
2190
+ }
2191
+ const canceledAt = immediate ? now : sub.currentPeriodEnd ?? now;
2192
+ const updated = await subscription.update({
2193
+ where: {
2194
+ tenantId
2195
+ },
2196
+ data: {
2197
+ canceledAt,
2198
+ status: immediate ? "CANCELED" : sub.status
2199
+ }
2200
+ });
2201
+ return {
2202
+ canceledAt: updated.canceledAt,
2203
+ status: updated.status
2204
+ };
2205
+ }
2206
+ subscription(client) {
2207
+ return getPrismaDelegate(client, this.schema.tenantSubscription.delegate);
2208
+ }
2209
+ planVersions(client) {
2210
+ return getPrismaDelegate(client, this.schema.delegates.entitlementPlanVersion);
2211
+ }
2212
+ async findTargetPlanVersionId(client, storagePlanId, asOf) {
2213
+ const activeWindow = this.schema.tenantSubscription.activeVersionSelection === "validity-window";
2214
+ const activeVersionWhere = this.schema.tenantSubscription.withEndsAt ? (0, import_types3.buildActivePlanVersionWhere)(asOf, {
2215
+ withEndsAt: true
2216
+ }) : (0, import_types3.buildActivePlanVersionWhere)(asOf);
2217
+ const where = activeWindow ? {
2218
+ planId: storagePlanId,
2219
+ ...activeVersionWhere
2220
+ } : {
2221
+ planId: storagePlanId,
2222
+ publishedAt: {
2223
+ not: null
2224
+ },
2225
+ supersededAt: null,
2226
+ ...this.schema.tenantSubscription.withEndsAt ? {
2227
+ OR: [
2228
+ {
2229
+ endsAt: null
2230
+ },
2231
+ {
2232
+ endsAt: {
2233
+ gt: asOf
2234
+ }
2235
+ }
2236
+ ]
2237
+ } : {}
2238
+ };
2239
+ const target = await this.planVersions(client).findFirst({
2240
+ where,
2241
+ orderBy: activeWindow ? [
2242
+ {
2243
+ validFrom: {
2244
+ sort: "desc",
2245
+ nulls: "last"
2246
+ }
2247
+ },
2248
+ {
2249
+ version: "desc"
2250
+ }
2251
+ ] : {
2252
+ version: "desc"
2253
+ }
2254
+ });
2255
+ if (!target) {
2256
+ throw new Error(`No active PlanVersion for plan '${storagePlanId}'.`);
2257
+ }
2258
+ return target.id;
2259
+ }
2260
+ async pendingVersionBelongsToAnotherPlan(client, pendingPlanVersionId, targetStoragePlanId) {
2261
+ if (!pendingPlanVersionId) return false;
2262
+ const pending = await this.planVersions(client).findUnique({
2263
+ where: {
2264
+ id: pendingPlanVersionId
2265
+ }
2266
+ });
2267
+ return !pending || pending.planId !== targetStoragePlanId;
2268
+ }
2269
+ assertConfiguration() {
2270
+ if (!this.schema.tenantSubscription.synchronizePlanVersion) return;
2271
+ const entitlementFields = this.schema.planVersionFields.entitlement;
2272
+ if (this.schema.tenantSubscription.activeVersionSelection === "validity-window" && !entitlementFields.validityWindows) {
2273
+ throw new Error("tenantSubscription.activeVersionSelection='validity-window' requires planVersionFields.entitlement.validityWindows=true.");
2274
+ }
2275
+ if (this.schema.tenantSubscription.withEndsAt && !entitlementFields.endsAt) {
2276
+ throw new Error("tenantSubscription.withEndsAt=true requires planVersionFields.entitlement.endsAt=true.");
2277
+ }
2278
+ }
2279
+ };
2280
+ PrismaTenantSubscriptionWriteAdapter = _ts_decorate18([
2281
+ (0, import_common18.Injectable)(),
2282
+ _ts_param16(0, (0, import_common18.Inject)(PRISMA_CLIENT_TOKEN)),
2283
+ _ts_param16(1, (0, import_common18.Optional)()),
2284
+ _ts_param16(1, (0, import_common18.Inject)(PRISMA_SCHEMA_OPTIONS_TOKEN)),
2285
+ _ts_metadata16("design:type", Function),
2286
+ _ts_metadata16("design:paramtypes", [
2287
+ typeof TransactionalPrismaClient === "undefined" ? Object : TransactionalPrismaClient,
2288
+ typeof PrismaSchemaOptions === "undefined" ? Object : PrismaSchemaOptions
2289
+ ])
2290
+ ], PrismaTenantSubscriptionWriteAdapter);
2291
+ function clearedPendingVersionData() {
2292
+ return {
2293
+ pendingPlanVersionId: null,
2294
+ pendingPlanVersionEffectiveAt: null,
2295
+ pendingPlanVersionAccepted: false,
2296
+ pendingPlanVersionAcceptedAt: null,
2297
+ pendingPlanVersionAcceptedByUserId: null,
2298
+ pendingPlanVersionNotifiedAt: null,
2299
+ pendingPlanVersionReminderSentAt: null
2300
+ };
2301
+ }
2302
+ __name(clearedPendingVersionData, "clearedPendingVersionData");
2303
+
2304
+ // src/prisma-plan.repository.ts
2305
+ var import_common19 = require("@nestjs/common");
2306
+ var import_types4 = require("@saasicat/types");
2307
+ function _ts_decorate19(decorators, target, key, desc) {
2308
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
2309
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
2310
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
2311
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
2312
+ }
2313
+ __name(_ts_decorate19, "_ts_decorate");
2314
+ function _ts_metadata17(k, v) {
2315
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
2316
+ }
2317
+ __name(_ts_metadata17, "_ts_metadata");
2318
+ function _ts_param17(paramIndex, decorator) {
2319
+ return function(target, key) {
2320
+ decorator(target, key, paramIndex);
2321
+ };
2322
+ }
2323
+ __name(_ts_param17, "_ts_param");
2324
+ var PrismaPlanRepository = class {
2325
+ static {
2326
+ __name(this, "PrismaPlanRepository");
2327
+ }
2328
+ prisma;
2329
+ binding;
2330
+ delegateName;
2331
+ fields;
2332
+ constructor(prisma, options) {
2333
+ this.prisma = prisma;
2334
+ const schema = resolvePrismaSchemaOptions(options);
2335
+ this.binding = createPrismaPlanBindingResolver(options?.planBinding);
2336
+ this.delegateName = schema.delegates.catalogPlanVersion;
2337
+ this.fields = schema.planVersionFields.catalog;
2338
+ }
2339
+ db(tx) {
2340
+ return tx ?? this.prisma;
2341
+ }
2342
+ versions(client) {
2343
+ return getPrismaDelegate(client, this.delegateName);
2344
+ }
2345
+ // ─── Stem operations (Pack 1) ───
2346
+ async list(filter) {
2347
+ const excludeDeleted = filter.excludeDeleted ?? true;
2348
+ const db = this.db();
2349
+ let publishedKeys = null;
2350
+ if (filter.onlyPublished) {
2351
+ if (this.binding.mode === "legacy-plan-key") {
2352
+ const projectPlans = await db.plan.findMany({
2353
+ where: {
2354
+ projectKey: filter.projectKey,
2355
+ ...excludeDeleted ? {
2356
+ deletedAt: null
2357
+ } : {}
2358
+ }
2359
+ });
2360
+ const candidateKeys = [
2361
+ ...new Set(projectPlans.map((plan) => plan.planKey))
2362
+ ];
2363
+ const allMatchingPlans = candidateKeys.length === 0 ? [] : await db.plan.findMany({
2364
+ where: {
2365
+ planKey: {
2366
+ in: candidateKeys
2367
+ }
2368
+ }
2369
+ });
2370
+ const projectsByKey = /* @__PURE__ */ new Map();
2371
+ for (const plan of allMatchingPlans) {
2372
+ const projects = projectsByKey.get(plan.planKey) ?? /* @__PURE__ */ new Set();
2373
+ projects.add(plan.projectKey);
2374
+ projectsByKey.set(plan.planKey, projects);
2375
+ }
2376
+ const unambiguousKeys = candidateKeys.filter((planKey) => projectsByKey.get(planKey)?.size === 1);
2377
+ const live = await this.versions(db).findMany({
2378
+ where: {
2379
+ planId: {
2380
+ in: unambiguousKeys
2381
+ },
2382
+ publishedAt: {
2383
+ not: null
2384
+ },
2385
+ supersededAt: null
2386
+ }
2387
+ });
2388
+ publishedKeys = [
2389
+ ...new Set(live.map((version) => version.planId))
2390
+ ];
2391
+ } else {
2392
+ const projectPlans = await db.plan.findMany({
2393
+ where: {
2394
+ projectKey: filter.projectKey,
2395
+ ...excludeDeleted ? {
2396
+ deletedAt: null
2397
+ } : {}
2398
+ }
2399
+ });
2400
+ const planKeyById = new Map(projectPlans.map((plan) => [
2401
+ plan.id,
2402
+ plan.planKey
2403
+ ]));
2404
+ const live = await this.versions(db).findMany({
2405
+ where: {
2406
+ planId: {
2407
+ in: [
2408
+ ...planKeyById.keys()
2409
+ ]
2410
+ },
2411
+ publishedAt: {
2412
+ not: null
2413
+ },
2414
+ supersededAt: null
2415
+ }
2416
+ });
2417
+ publishedKeys = [
2418
+ ...new Set(live.flatMap((version) => {
2419
+ const planKey = planKeyById.get(version.planId);
2420
+ return planKey ? [
2421
+ planKey
2422
+ ] : [];
2423
+ }))
2424
+ ];
2425
+ }
2426
+ }
2427
+ const rows = await db.plan.findMany({
2428
+ where: {
2429
+ projectKey: filter.projectKey,
2430
+ ...excludeDeleted ? {
2431
+ deletedAt: null
2432
+ } : {},
2433
+ ...publishedKeys ? {
2434
+ planKey: {
2435
+ in: publishedKeys
2436
+ }
2437
+ } : {}
2438
+ },
2439
+ orderBy: [
2440
+ {
2441
+ sortOrder: "asc"
2442
+ },
2443
+ {
2444
+ planKey: "asc"
2445
+ }
2446
+ ]
2447
+ });
2448
+ return rows.map(toPlanRow2);
2449
+ }
2450
+ async findById(planId) {
2451
+ const row = await this.db().plan.findUnique({
2452
+ where: {
2453
+ id: planId
2454
+ }
2455
+ });
2456
+ return row ? toPlanRow2(row) : null;
2457
+ }
2458
+ async findByKey(projectKey, planKey) {
2459
+ const row = await this.db().plan.findFirst({
2460
+ where: {
2461
+ projectKey,
2462
+ planKey,
2463
+ deletedAt: null
2464
+ }
2465
+ });
2466
+ return row ? toPlanRow2(row) : null;
2467
+ }
2468
+ async create(data) {
2469
+ const created = await this.db().plan.create({
2470
+ data: {
2471
+ projectKey: data.projectKey,
2472
+ planKey: data.planKey,
2473
+ label: data.label,
2474
+ description: data.description ?? null,
2475
+ icon: data.icon ?? null,
2476
+ sortOrder: data.sortOrder ?? 0
2477
+ }
2478
+ });
2479
+ return toPlanRow2(created);
2480
+ }
2481
+ async update(planId, data) {
2482
+ const updated = await this.db().plan.update({
2483
+ where: {
2484
+ id: planId
2485
+ },
2486
+ data: {
2487
+ ...data.label !== void 0 ? {
2488
+ label: data.label
2489
+ } : {},
2490
+ ...data.description !== void 0 ? {
2491
+ description: data.description
2492
+ } : {},
2493
+ ...data.icon !== void 0 ? {
2494
+ icon: data.icon
2495
+ } : {},
2496
+ ...data.sortOrder !== void 0 ? {
2497
+ sortOrder: data.sortOrder
2498
+ } : {}
2499
+ }
2500
+ });
2501
+ return toPlanRow2(updated);
2502
+ }
2503
+ async softDelete(planId) {
2504
+ await this.db().plan.update({
2505
+ where: {
2506
+ id: planId
2507
+ },
2508
+ data: {
2509
+ deletedAt: /* @__PURE__ */ new Date()
2510
+ }
2511
+ });
2512
+ }
2513
+ async hardDelete(planId) {
2514
+ await this.db().plan.deleteMany({
2515
+ where: {
2516
+ id: planId
2517
+ }
2518
+ });
2519
+ }
2520
+ // ─── Lifecycle operations (Pack 2a) — keyed by planKey ───
2521
+ async listVersions(planKey) {
2522
+ const db = this.db();
2523
+ const storedPlanId = await this.binding.toStoragePlanId(db, planKey);
2524
+ const rows = await this.versions(db).findMany({
2525
+ where: {
2526
+ planId: storedPlanId
2527
+ },
2528
+ orderBy: {
2529
+ version: "asc"
2530
+ }
2531
+ });
2532
+ return rows.map((row) => this.toPlanVersionRow(row, planKey));
2533
+ }
2534
+ async findVersionById(versionId) {
2535
+ const db = this.db();
2536
+ const row = await this.versions(db).findUnique({
2537
+ where: {
2538
+ id: versionId
2539
+ }
2540
+ });
2541
+ return row ? this.toPlanVersionRow(row, await this.binding.toPlanKey(db, row.planId)) : null;
2542
+ }
2543
+ async findCurrentDraft(planKey) {
2544
+ const db = this.db();
2545
+ const storedPlanId = await this.binding.toStoragePlanId(db, planKey);
2546
+ const row = await this.versions(db).findFirst({
2547
+ where: {
2548
+ planId: storedPlanId,
2549
+ publishedAt: null
2550
+ }
2551
+ });
2552
+ return row ? this.toPlanVersionRow(row, planKey) : null;
2553
+ }
2554
+ async findLatestLivePlanVersion(planKey, tx) {
2555
+ const db = this.db(tx);
2556
+ const storedPlanId = await this.binding.toStoragePlanId(db, planKey);
2557
+ const row = await this.versions(db).findFirst({
2558
+ where: {
2559
+ planId: storedPlanId,
2560
+ publishedAt: {
2561
+ not: null
2562
+ },
2563
+ supersededAt: null,
2564
+ ...this.fields.endsAt ? {
2565
+ OR: [
2566
+ {
2567
+ endsAt: null
2568
+ },
2569
+ {
2570
+ endsAt: {
2571
+ gt: /* @__PURE__ */ new Date()
2572
+ }
2573
+ }
2574
+ ]
2575
+ } : {}
2576
+ },
2577
+ orderBy: {
2578
+ version: "desc"
2579
+ }
2580
+ });
2581
+ return row ? this.toPlanVersionRow(row, planKey) : null;
2582
+ }
2583
+ async findActivePlanVersion(planKey, asOf = /* @__PURE__ */ new Date(), tx) {
2584
+ if (!this.fields.validityWindows) {
2585
+ throw new Error("findActivePlanVersion requires schema.planVersionFields.catalog.validityWindows=true and the current @saasicat/spec PlanVersion validity columns. Apply the additive schema first, or use findLatestLivePlanVersion for a 0.6-compatible newest-live lookup.");
2586
+ }
2587
+ const db = this.db(tx);
2588
+ const storedPlanId = await this.binding.toStoragePlanId(db, planKey);
2589
+ const activeWhere = this.fields.endsAt ? (0, import_types4.buildActivePlanVersionWhere)(asOf, {
2590
+ withEndsAt: true
2591
+ }) : (0, import_types4.buildActivePlanVersionWhere)(asOf);
2592
+ const row = await this.versions(db).findFirst({
2593
+ where: {
2594
+ planId: storedPlanId,
2595
+ ...activeWhere
2596
+ },
2597
+ orderBy: [
2598
+ {
2599
+ validFrom: {
2600
+ sort: "desc",
2601
+ nulls: "last"
2602
+ }
2603
+ },
2604
+ {
2605
+ version: "desc"
2606
+ }
2607
+ ]
2608
+ });
2609
+ return row ? this.toPlanVersionRow(row, planKey) : null;
2610
+ }
2611
+ async createPlanVersionDraft(data) {
2612
+ const planKey = data.planId;
2613
+ const db = this.db();
2614
+ const planVersion = this.versions(db);
2615
+ const storedPlanId = await this.binding.toStoragePlanId(db, planKey);
2616
+ const latest = await planVersion.findFirst({
2617
+ where: {
2618
+ planId: storedPlanId
2619
+ },
2620
+ orderBy: {
2621
+ version: "desc"
2622
+ }
2623
+ });
2624
+ const nextVersion = (latest?.version ?? 0) + 1;
2625
+ const created = await planVersion.create({
2626
+ data: {
2627
+ planId: storedPlanId,
2628
+ version: nextVersion,
2629
+ baseVersionId: data.baseVersionId ?? null,
2630
+ features: data.features,
2631
+ quotas: data.quotas,
2632
+ monthlyNet: data.monthlyNet,
2633
+ yearlyNet: data.yearlyNet,
2634
+ marketed: data.marketed ?? true,
2635
+ changeNote: data.changeNote ?? "",
2636
+ createdByUserId: data.createdByUserId ?? null,
2637
+ ...this.fields.validityWindows ? {
2638
+ validFrom: data.validFrom ? new Date(data.validFrom) : null,
2639
+ validUntil: data.validUntil ? new Date(data.validUntil) : null
2640
+ } : {}
2641
+ }
2642
+ });
2643
+ return this.toPlanVersionRow(created, planKey);
2644
+ }
2645
+ async updatePlanVersionDraft(versionId, data) {
2646
+ const updated = await this.versions(this.db()).update({
2647
+ where: {
2648
+ id: versionId
2649
+ },
2650
+ data: {
2651
+ ...data.features !== void 0 ? {
2652
+ features: data.features
2653
+ } : {},
2654
+ ...data.quotas !== void 0 ? {
2655
+ quotas: data.quotas
2656
+ } : {},
2657
+ ...data.monthlyNet !== void 0 ? {
2658
+ monthlyNet: data.monthlyNet
2659
+ } : {},
2660
+ ...data.yearlyNet !== void 0 ? {
2661
+ yearlyNet: data.yearlyNet
2662
+ } : {},
2663
+ ...data.marketed !== void 0 ? {
2664
+ marketed: data.marketed
2665
+ } : {},
2666
+ ...data.changeNote !== void 0 ? {
2667
+ changeNote: data.changeNote
2668
+ } : {},
2669
+ ...this.fields.validityWindows && data.validFrom !== void 0 ? {
2670
+ validFrom: data.validFrom ? new Date(data.validFrom) : null
2671
+ } : {},
2672
+ ...this.fields.validityWindows && data.validUntil !== void 0 ? {
2673
+ validUntil: data.validUntil ? new Date(data.validUntil) : null
2674
+ } : {}
2675
+ }
2676
+ });
2677
+ const planKey = await this.binding.toPlanKey(this.db(), updated.planId);
2678
+ return this.toPlanVersionRow(updated, planKey);
2679
+ }
2680
+ async publishPlanVersionDraft(versionId, publishMeta, tx) {
2681
+ const operationDb = this.db(tx);
2682
+ const draft = await this.versions(operationDb).findUnique({
2683
+ where: {
2684
+ id: versionId
2685
+ }
2686
+ });
2687
+ if (!draft) {
2688
+ throw new Error(`PlanVersion ${versionId} not found.`);
2689
+ }
2690
+ const storedPlanId = draft.planId;
2691
+ const publish = /* @__PURE__ */ __name(async (db) => {
2692
+ const planVersion = this.versions(db);
2693
+ const previous = await planVersion.findFirst({
2694
+ where: {
2695
+ planId: storedPlanId,
2696
+ publishedAt: {
2697
+ not: null
2698
+ },
2699
+ supersededAt: null,
2700
+ id: {
2701
+ not: versionId
2702
+ }
2703
+ },
2704
+ orderBy: {
2705
+ version: "desc"
2706
+ }
2707
+ });
2708
+ const now = /* @__PURE__ */ new Date();
2709
+ if (previous) {
2710
+ const predecessorValidUntil = new Date(publishMeta.validFrom.getTime() - 24 * 60 * 60 * 1e3);
2711
+ await planVersion.update({
2712
+ where: {
2713
+ id: previous.id
2714
+ },
2715
+ data: {
2716
+ supersededAt: now,
2717
+ ...this.fields.validityWindows ? {
2718
+ validUntil: predecessorValidUntil
2719
+ } : {}
2720
+ }
2721
+ });
2722
+ }
2723
+ return planVersion.update({
2724
+ where: {
2725
+ id: versionId
2726
+ },
2727
+ data: {
2728
+ publishedAt: now,
2729
+ publishedChanges: publishMeta.publishedChanges,
2730
+ nonRegressive: publishMeta.nonRegressive,
2731
+ publishedByUserId: publishMeta.publishedByUserId,
2732
+ ...this.fields.validityWindows ? {
2733
+ validFrom: publishMeta.validFrom,
2734
+ validUntil: publishMeta.validUntil
2735
+ } : {}
2736
+ }
2737
+ });
2738
+ }, "publish");
2739
+ const published = tx ? await publish(this.db(tx)) : await this.prisma.$transaction((txClient) => publish(txClient));
2740
+ const planKey = await this.binding.toPlanKey(operationDb, storedPlanId);
2741
+ return this.toPlanVersionRow(published, planKey);
2742
+ }
2743
+ async deletePlanVersionDraft(versionId) {
2744
+ const planVersion = this.versions(this.db());
2745
+ const row = await planVersion.findUnique({
2746
+ where: {
2747
+ id: versionId
2748
+ }
2749
+ });
2750
+ if (!row) return;
2751
+ if (row.publishedAt !== null) {
2752
+ throw new Error(`PlanVersion ${versionId} is already published and cannot be discarded (published versions are immutable \u2014 contract protection P1).`);
2753
+ }
2754
+ await planVersion.deleteMany({
2755
+ where: {
2756
+ id: versionId,
2757
+ publishedAt: null
2758
+ }
2759
+ });
2760
+ }
2761
+ async terminate(versionId, endsAt) {
2762
+ if (!this.fields.endsAt) {
2763
+ throw new Error("terminate requires schema.planVersionFields.catalog.endsAt=true and the current @saasicat/spec PlanVersion.endsAt column. Apply the additive schema before enabling SuperAdmin-initiated plan-version termination.");
2764
+ }
2765
+ const db = this.db();
2766
+ const updated = await this.versions(db).update({
2767
+ where: {
2768
+ id: versionId
2769
+ },
2770
+ data: {
2771
+ endsAt
2772
+ }
2773
+ });
2774
+ const planKey = await this.binding.toPlanKey(db, updated.planId);
2775
+ return this.toPlanVersionRow(updated, planKey);
2776
+ }
2777
+ toPlanVersionRow(row, planKey) {
2778
+ return toPlanVersionRow2(row, planKey, this.fields);
2779
+ }
2780
+ };
2781
+ PrismaPlanRepository = _ts_decorate19([
2782
+ (0, import_common19.Injectable)(),
2783
+ _ts_param17(0, (0, import_common19.Inject)(PRISMA_CLIENT_TOKEN)),
2784
+ _ts_param17(1, (0, import_common19.Optional)()),
2785
+ _ts_param17(1, (0, import_common19.Inject)(PRISMA_SCHEMA_OPTIONS_TOKEN)),
2786
+ _ts_metadata17("design:type", Function),
2787
+ _ts_metadata17("design:paramtypes", [
2788
+ typeof PlanRepositoryClient === "undefined" ? Object : PlanRepositoryClient,
2789
+ typeof PrismaSchemaOptions === "undefined" ? Object : PrismaSchemaOptions
2790
+ ])
2791
+ ], PrismaPlanRepository);
2792
+ function toPlanRow2(row) {
2793
+ return {
2794
+ id: row.id,
2795
+ projectKey: row.projectKey,
2796
+ planKey: row.planKey,
2797
+ label: row.label,
2798
+ description: row.description,
2799
+ icon: row.icon,
2800
+ sortOrder: row.sortOrder,
2801
+ createdAt: row.createdAt.toISOString(),
2802
+ updatedAt: row.updatedAt.toISOString(),
2803
+ deletedAt: row.deletedAt?.toISOString() ?? null
2804
+ };
2805
+ }
2806
+ __name(toPlanRow2, "toPlanRow");
2807
+ function toPlanVersionRow2(row, planKey, fields) {
2808
+ const mapped = {
2809
+ id: row.id,
2810
+ version: row.version,
2811
+ baseVersionId: row.baseVersionId,
2812
+ planId: planKey,
2813
+ features: toStringArray(row.features),
2814
+ quotas: toQuotaMap(row.quotas),
2815
+ monthlyNet: row.monthlyNet.toString(),
2816
+ yearlyNet: row.yearlyNet.toString(),
2817
+ marketed: row.marketed,
2818
+ publishedAt: row.publishedAt?.toISOString() ?? null,
2819
+ supersededAt: row.supersededAt?.toISOString() ?? null,
2820
+ publishedChanges: Array.isArray(row.publishedChanges) ? row.publishedChanges : null,
2821
+ changeNote: row.changeNote,
2822
+ nonRegressive: row.nonRegressive,
2823
+ validFrom: fields.validityWindows && row.validFrom ? row.validFrom.toISOString() : null,
2824
+ validUntil: fields.validityWindows && row.validUntil ? row.validUntil.toISOString() : null,
2825
+ createdByUserId: row.createdByUserId,
2826
+ publishedByUserId: row.publishedByUserId,
2827
+ createdAt: row.createdAt.toISOString(),
2828
+ updatedAt: row.updatedAt.toISOString()
2829
+ };
2830
+ if (fields.endsAt) {
2831
+ mapped.endsAt = row.endsAt?.toISOString() ?? null;
2832
+ }
2833
+ return mapped;
2834
+ }
2835
+ __name(toPlanVersionRow2, "toPlanVersionRow");
2836
+
2837
+ // src/prisma-bundle.repository.ts
2838
+ var import_common20 = require("@nestjs/common");
2839
+ var import_types5 = require("@saasicat/types");
2840
+ function _ts_decorate20(decorators, target, key, desc) {
2841
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
2842
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
2843
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
2844
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
2845
+ }
2846
+ __name(_ts_decorate20, "_ts_decorate");
2847
+ function _ts_metadata18(k, v) {
2848
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
2849
+ }
2850
+ __name(_ts_metadata18, "_ts_metadata");
2851
+ function _ts_param18(paramIndex, decorator) {
2852
+ return function(target, key) {
2853
+ decorator(target, key, paramIndex);
2854
+ };
2855
+ }
2856
+ __name(_ts_param18, "_ts_param");
2857
+ var PRISMA_BUNDLE_REPOSITORY_OPTIONS = /* @__PURE__ */ Symbol.for("saasicat/adapter-prisma/PrismaBundleRepositoryOptions");
2858
+ var PrismaBundleRepository = class {
2859
+ static {
2860
+ __name(this, "PrismaBundleRepository");
2861
+ }
2862
+ prisma;
2863
+ validityWindows;
2864
+ /**
2865
+ * Present only when validity-window mode is enabled. This mirrors the
2866
+ * optional port capability and lets 0.6-schema consumers detect that an
2867
+ * active-at-time lookup is unavailable.
2868
+ */
2869
+ findActiveBundleVersion;
2870
+ constructor(prisma, options = {}) {
2871
+ this.prisma = prisma;
2872
+ this.validityWindows = options.validityWindows ?? false;
2873
+ if (this.validityWindows) {
2874
+ this.findActiveBundleVersion = (bundleId, asOf, tx) => this.findActiveBundleVersionWithValidity(bundleId, asOf ?? /* @__PURE__ */ new Date(), tx);
2875
+ }
2876
+ }
2877
+ db(tx) {
2878
+ return tx ?? this.prisma;
2879
+ }
2880
+ transaction(work) {
2881
+ const transaction = this.prisma.$transaction;
2882
+ return transaction.call(this.prisma, (tx) => work(tx));
2883
+ }
2884
+ // ─── Stem operations ───
2885
+ async list(filter) {
2886
+ const excludeDeleted = filter.excludeDeleted ?? true;
2887
+ const rows = await this.db().bundle.findMany({
2888
+ where: {
2889
+ projectKey: filter.projectKey,
2890
+ ...excludeDeleted ? {
2891
+ deletedAt: null
2892
+ } : {}
2893
+ },
2894
+ orderBy: [
2895
+ {
2896
+ sortOrder: "asc"
2897
+ },
2898
+ {
2899
+ bundleKey: "asc"
2900
+ }
2901
+ ]
2902
+ });
2903
+ return rows.map(toBundleRow);
2904
+ }
2905
+ async findById(bundleId) {
2906
+ const row = await this.db().bundle.findUnique({
2907
+ where: {
2908
+ id: bundleId
2909
+ }
2910
+ });
2911
+ return row ? toBundleRow(row) : null;
2912
+ }
2913
+ async findByKey(projectKey, bundleKey) {
2914
+ const row = await this.db().bundle.findFirst({
2915
+ where: {
2916
+ projectKey,
2917
+ bundleKey,
2918
+ deletedAt: null
2919
+ }
2920
+ });
2921
+ return row ? toBundleRow(row) : null;
2922
+ }
2923
+ async create(data) {
2924
+ const created = await this.db().bundle.create({
2925
+ data: {
2926
+ projectKey: data.projectKey,
2927
+ bundleKey: data.bundleKey,
2928
+ label: data.label,
2929
+ description: data.description ?? null,
2930
+ icon: data.icon ?? null,
2931
+ sortOrder: data.sortOrder ?? 0,
2932
+ i18n: data.i18n ?? {}
2933
+ }
2934
+ });
2935
+ return toBundleRow(created);
2936
+ }
2937
+ async update(bundleId, data) {
2938
+ const updated = await this.db().bundle.update({
2939
+ where: {
2940
+ id: bundleId
2941
+ },
2942
+ data: {
2943
+ ...data.label !== void 0 ? {
2944
+ label: data.label
2945
+ } : {},
2946
+ ...data.description !== void 0 ? {
2947
+ description: data.description
2948
+ } : {},
2949
+ ...data.icon !== void 0 ? {
2950
+ icon: data.icon
2951
+ } : {},
2952
+ ...data.sortOrder !== void 0 ? {
2953
+ sortOrder: data.sortOrder
2954
+ } : {},
2955
+ ...data.i18n !== void 0 ? {
2956
+ i18n: data.i18n
2957
+ } : {}
2958
+ }
2959
+ });
2960
+ return toBundleRow(updated);
2961
+ }
2962
+ async softDelete(bundleId) {
2963
+ await this.db().bundle.update({
2964
+ where: {
2965
+ id: bundleId
2966
+ },
2967
+ data: {
2968
+ deletedAt: /* @__PURE__ */ new Date()
2969
+ }
2970
+ });
2971
+ }
2972
+ // ─── Version operations ───
2973
+ async listVersions(bundleId) {
2974
+ const bundle = await this.db().bundle.findUnique({
2975
+ where: {
2976
+ id: bundleId
2977
+ }
2978
+ });
2979
+ if (!bundle) return [];
2980
+ const rows = await this.db().bundleVersion.findMany({
2981
+ where: {
2982
+ bundleId
2983
+ },
2984
+ orderBy: {
2985
+ version: "asc"
2986
+ }
2987
+ });
2988
+ return rows.map((row) => toBundleVersionRow(row, bundle, this.validityWindows));
2989
+ }
2990
+ async findVersionById(versionId) {
2991
+ const row = await this.db().bundleVersion.findUnique({
2992
+ where: {
2993
+ id: versionId
2994
+ }
2995
+ });
2996
+ if (!row) return null;
2997
+ const bundle = await this.db().bundle.findUnique({
2998
+ where: {
2999
+ id: row.bundleId
3000
+ }
3001
+ });
3002
+ return toBundleVersionRow(row, bundle, this.validityWindows);
3003
+ }
3004
+ async findCurrentDraft(bundleId) {
3005
+ const row = await this.db().bundleVersion.findFirst({
3006
+ where: {
3007
+ bundleId,
3008
+ publishedAt: null
3009
+ }
3010
+ });
3011
+ if (!row) return null;
3012
+ const bundle = await this.db().bundle.findUnique({
3013
+ where: {
3014
+ id: bundleId
3015
+ }
3016
+ });
3017
+ return toBundleVersionRow(row, bundle, this.validityWindows);
3018
+ }
3019
+ async findLatestLive(bundleId, tx) {
3020
+ const db = this.db(tx);
3021
+ const row = await db.bundleVersion.findFirst({
3022
+ where: {
3023
+ bundleId,
3024
+ publishedAt: {
3025
+ not: null
3026
+ },
3027
+ supersededAt: null
3028
+ },
3029
+ orderBy: {
3030
+ version: "desc"
3031
+ }
3032
+ });
3033
+ if (!row) return null;
3034
+ const bundle = await db.bundle.findUnique({
3035
+ where: {
3036
+ id: bundleId
3037
+ }
3038
+ });
3039
+ return toBundleVersionRow(row, bundle, this.validityWindows);
3040
+ }
3041
+ async findActiveBundleVersionWithValidity(bundleId, asOf, tx) {
3042
+ const db = this.db(tx);
3043
+ const row = await db.bundleVersion.findFirst({
3044
+ where: {
3045
+ bundleId,
3046
+ ...(0, import_types5.buildActiveVersionWhere)(asOf)
3047
+ },
3048
+ orderBy: [
3049
+ {
3050
+ validFrom: {
3051
+ sort: "desc",
3052
+ nulls: "last"
3053
+ }
3054
+ },
3055
+ {
3056
+ version: "desc"
3057
+ }
3058
+ ]
3059
+ });
3060
+ if (!row) return null;
3061
+ const bundle = await db.bundle.findUnique({
3062
+ where: {
3063
+ id: bundleId
3064
+ }
3065
+ });
3066
+ return toBundleVersionRow(row, bundle, true);
3067
+ }
3068
+ async createDraft(data) {
3069
+ const db = this.db();
3070
+ const existingDraft = await db.bundleVersion.findFirst({
3071
+ where: {
3072
+ bundleId: data.bundleId,
3073
+ publishedAt: null
3074
+ }
3075
+ });
3076
+ if (existingDraft) {
3077
+ throw new Error(`Bundle '${data.bundleId}' already has a draft version (v${existingDraft.version}); only one draft per bundle is allowed.`);
3078
+ }
3079
+ const latest = await db.bundleVersion.findFirst({
3080
+ where: {
3081
+ bundleId: data.bundleId
3082
+ },
3083
+ orderBy: {
3084
+ version: "desc"
3085
+ }
3086
+ });
3087
+ const nextVersion = latest ? latest.version + 1 : 1;
3088
+ const created = await db.bundleVersion.create({
3089
+ data: {
3090
+ bundleId: data.bundleId,
3091
+ version: nextVersion,
3092
+ baseVersionId: data.baseVersionId ?? null,
3093
+ features: data.features,
3094
+ quotas: data.quotas ?? {},
3095
+ compatibility: data.compatibility ?? {},
3096
+ pricingOverrides: data.pricingOverrides ?? [],
3097
+ monthlyNet: data.monthlyNet ?? null,
3098
+ yearlyNet: data.yearlyNet ?? null,
3099
+ marketed: data.marketed ?? true,
3100
+ changeNote: data.changeNote ?? "",
3101
+ createdByUserId: data.createdByUserId ?? null,
3102
+ ...this.validityWindows ? {
3103
+ validFrom: toNullableDate(data.validFrom),
3104
+ validUntil: toNullableDate(data.validUntil)
3105
+ } : {}
3106
+ }
3107
+ });
3108
+ const bundle = await db.bundle.findUnique({
3109
+ where: {
3110
+ id: data.bundleId
3111
+ }
3112
+ });
3113
+ return toBundleVersionRow(created, bundle, this.validityWindows);
3114
+ }
3115
+ async updateDraft(versionId, data) {
3116
+ const db = this.db();
3117
+ const updated = await db.bundleVersion.update({
3118
+ where: {
3119
+ id: versionId
3120
+ },
3121
+ data: {
3122
+ ...data.features !== void 0 ? {
3123
+ features: data.features
3124
+ } : {},
3125
+ ...data.quotas !== void 0 ? {
3126
+ quotas: data.quotas
3127
+ } : {},
3128
+ ...data.compatibility !== void 0 ? {
3129
+ compatibility: data.compatibility
3130
+ } : {},
3131
+ ...data.pricingOverrides !== void 0 ? {
3132
+ pricingOverrides: data.pricingOverrides
3133
+ } : {},
3134
+ ...data.monthlyNet !== void 0 ? {
3135
+ monthlyNet: data.monthlyNet
3136
+ } : {},
3137
+ ...data.yearlyNet !== void 0 ? {
3138
+ yearlyNet: data.yearlyNet
3139
+ } : {},
3140
+ ...data.marketed !== void 0 ? {
3141
+ marketed: data.marketed
3142
+ } : {},
3143
+ ...data.changeNote !== void 0 ? {
3144
+ changeNote: data.changeNote
3145
+ } : {},
3146
+ ...this.validityWindows && data.validFrom !== void 0 ? {
3147
+ validFrom: toNullableDate(data.validFrom)
3148
+ } : {},
3149
+ ...this.validityWindows && data.validUntil !== void 0 ? {
3150
+ validUntil: toNullableDate(data.validUntil)
3151
+ } : {}
3152
+ }
3153
+ });
3154
+ const bundle = await db.bundle.findUnique({
3155
+ where: {
3156
+ id: updated.bundleId
3157
+ }
3158
+ });
3159
+ return toBundleVersionRow(updated, bundle, this.validityWindows);
3160
+ }
3161
+ async publishDraft(versionId, publishMeta, tx) {
3162
+ if (this.validityWindows && tx === void 0) {
3163
+ return this.transaction((transaction) => this.publishDraftWithValidity(transaction, versionId, publishMeta));
3164
+ }
3165
+ if (this.validityWindows) {
3166
+ return this.publishDraftWithValidity(this.db(tx), versionId, publishMeta);
3167
+ }
3168
+ const db = this.db(tx);
3169
+ const draft = await db.bundleVersion.findUnique({
3170
+ where: {
3171
+ id: versionId
3172
+ }
3173
+ });
3174
+ if (!draft) {
3175
+ throw new Error(`BundleVersion '${versionId}' not found.`);
3176
+ }
3177
+ await db.bundleVersion.updateMany({
3178
+ where: {
3179
+ bundleId: draft.bundleId,
3180
+ publishedAt: {
3181
+ not: null
3182
+ },
3183
+ supersededAt: null,
3184
+ NOT: {
3185
+ id: versionId
3186
+ }
3187
+ },
3188
+ data: {
3189
+ supersededAt: /* @__PURE__ */ new Date()
3190
+ }
3191
+ });
3192
+ const published = await db.bundleVersion.update({
3193
+ where: {
3194
+ id: versionId
3195
+ },
3196
+ data: {
3197
+ publishedAt: /* @__PURE__ */ new Date(),
3198
+ publishedByUserId: publishMeta.publishedByUserId,
3199
+ publishedChanges: publishMeta.publishedChanges,
3200
+ nonRegressive: publishMeta.nonRegressive
3201
+ }
3202
+ });
3203
+ const bundle = await db.bundle.findUnique({
3204
+ where: {
3205
+ id: published.bundleId
3206
+ }
3207
+ });
3208
+ return toBundleVersionRow(published, bundle, false);
3209
+ }
3210
+ async publishDraftWithValidity(db, versionId, publishMeta) {
3211
+ const draft = await db.bundleVersion.findUnique({
3212
+ where: {
3213
+ id: versionId
3214
+ }
3215
+ });
3216
+ if (!draft) {
3217
+ throw new Error(`BundleVersion '${versionId}' not found.`);
3218
+ }
3219
+ const now = /* @__PURE__ */ new Date();
3220
+ await db.bundleVersion.updateMany({
3221
+ where: {
3222
+ bundleId: draft.bundleId,
3223
+ publishedAt: {
3224
+ not: null
3225
+ },
3226
+ supersededAt: null,
3227
+ NOT: {
3228
+ id: versionId
3229
+ }
3230
+ },
3231
+ data: {
3232
+ supersededAt: now,
3233
+ validUntil: previousUtcDay(publishMeta.validFrom)
3234
+ }
3235
+ });
3236
+ const published = await db.bundleVersion.update({
3237
+ where: {
3238
+ id: versionId
3239
+ },
3240
+ data: {
3241
+ publishedAt: now,
3242
+ publishedByUserId: publishMeta.publishedByUserId,
3243
+ publishedChanges: publishMeta.publishedChanges,
3244
+ nonRegressive: publishMeta.nonRegressive,
3245
+ validFrom: publishMeta.validFrom,
3246
+ validUntil: publishMeta.validUntil
3247
+ }
3248
+ });
3249
+ const bundle = await db.bundle.findUnique({
3250
+ where: {
3251
+ id: published.bundleId
3252
+ }
3253
+ });
3254
+ return toBundleVersionRow(published, bundle, true);
3255
+ }
3256
+ async deleteDraft(versionId) {
3257
+ const db = this.db();
3258
+ const row = await db.bundleVersion.findUnique({
3259
+ where: {
3260
+ id: versionId
3261
+ }
3262
+ });
3263
+ if (!row) return;
3264
+ if (row.publishedAt !== null) {
3265
+ throw new Error(`BundleVersion '${versionId}' is already published and cannot be discarded (published versions are immutable \u2014 contract protection P1).`);
3266
+ }
3267
+ try {
3268
+ await db.bundleVersion.delete({
3269
+ where: {
3270
+ id: versionId
3271
+ }
3272
+ });
3273
+ } catch (err) {
3274
+ if (err?.code === "P2025") return;
3275
+ throw err;
3276
+ }
3277
+ }
3278
+ };
3279
+ PrismaBundleRepository = _ts_decorate20([
3280
+ (0, import_common20.Injectable)(),
3281
+ _ts_param18(0, (0, import_common20.Inject)(PRISMA_CLIENT_TOKEN)),
3282
+ _ts_param18(1, (0, import_common20.Optional)()),
3283
+ _ts_param18(1, (0, import_common20.Inject)(PRISMA_BUNDLE_REPOSITORY_OPTIONS)),
3284
+ _ts_metadata18("design:type", Function),
3285
+ _ts_metadata18("design:paramtypes", [
3286
+ typeof BundlePrismaClient === "undefined" ? Object : BundlePrismaClient,
3287
+ typeof PrismaBundleRepositoryOptions === "undefined" ? Object : PrismaBundleRepositoryOptions
3288
+ ])
3289
+ ], PrismaBundleRepository);
3290
+ function isPlainObject(value) {
3291
+ return value !== null && typeof value === "object" && !Array.isArray(value);
3292
+ }
3293
+ __name(isPlainObject, "isPlainObject");
3294
+ function toDecimalString(value) {
3295
+ return value == null ? null : value.toString();
3296
+ }
3297
+ __name(toDecimalString, "toDecimalString");
3298
+ function toNullableDate(value) {
3299
+ return value ? new Date(value) : null;
3300
+ }
3301
+ __name(toNullableDate, "toNullableDate");
3302
+ function previousUtcDay(value) {
3303
+ const result = new Date(value);
3304
+ result.setUTCDate(result.getUTCDate() - 1);
3305
+ return result;
3306
+ }
3307
+ __name(previousUtcDay, "previousUtcDay");
3308
+ function toVersionChanges(value) {
3309
+ return Array.isArray(value) ? value : null;
3310
+ }
3311
+ __name(toVersionChanges, "toVersionChanges");
3312
+ function toCompatibility(value) {
3313
+ return isPlainObject(value) ? value : {};
3314
+ }
3315
+ __name(toCompatibility, "toCompatibility");
3316
+ function toPricingOverrides(value) {
3317
+ return Array.isArray(value) ? value : [];
3318
+ }
3319
+ __name(toPricingOverrides, "toPricingOverrides");
3320
+ function toI18n(value) {
3321
+ return isPlainObject(value) ? value : {};
3322
+ }
3323
+ __name(toI18n, "toI18n");
3324
+ function toBundleRow(row) {
3325
+ return {
3326
+ id: row.id,
3327
+ projectKey: row.projectKey,
3328
+ bundleKey: row.bundleKey,
3329
+ label: row.label,
3330
+ description: row.description,
3331
+ icon: row.icon,
3332
+ sortOrder: row.sortOrder,
3333
+ i18n: toI18n(row.i18n),
3334
+ createdAt: row.createdAt.toISOString(),
3335
+ updatedAt: row.updatedAt.toISOString(),
3336
+ deletedAt: row.deletedAt?.toISOString() ?? null
3337
+ };
3338
+ }
3339
+ __name(toBundleRow, "toBundleRow");
3340
+ function toBundleVersionRow(row, bundle, validityWindows) {
3341
+ return {
3342
+ id: row.id,
3343
+ bundleId: row.bundleId,
3344
+ bundleKey: bundle?.bundleKey ?? "",
3345
+ label: bundle?.label ?? "",
3346
+ version: row.version,
3347
+ baseVersionId: row.baseVersionId,
3348
+ features: toStringArray(row.features),
3349
+ quotas: toQuotaMap(row.quotas),
3350
+ compatibility: toCompatibility(row.compatibility),
3351
+ pricingOverrides: toPricingOverrides(row.pricingOverrides),
3352
+ monthlyNet: toDecimalString(row.monthlyNet),
3353
+ yearlyNet: toDecimalString(row.yearlyNet),
3354
+ marketed: row.marketed,
3355
+ publishedAt: row.publishedAt?.toISOString() ?? null,
3356
+ supersededAt: row.supersededAt?.toISOString() ?? null,
3357
+ validFrom: validityWindows && row.validFrom instanceof Date ? row.validFrom.toISOString() : null,
3358
+ validUntil: validityWindows && row.validUntil instanceof Date ? row.validUntil.toISOString() : null,
3359
+ publishedChanges: toVersionChanges(row.publishedChanges),
3360
+ changeNote: row.changeNote,
3361
+ nonRegressive: row.nonRegressive,
3362
+ createdByUserId: row.createdByUserId,
3363
+ publishedByUserId: row.publishedByUserId,
3364
+ createdAt: row.createdAt.toISOString(),
3365
+ updatedAt: row.updatedAt.toISOString()
3366
+ };
3367
+ }
3368
+ __name(toBundleVersionRow, "toBundleVersionRow");
3369
+
3370
+ // src/prisma-catalog-entry.repository.ts
3371
+ var import_common21 = require("@nestjs/common");
3372
+ function _ts_decorate21(decorators, target, key, desc) {
3373
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3374
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
3375
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
3376
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
3377
+ }
3378
+ __name(_ts_decorate21, "_ts_decorate");
3379
+ function _ts_metadata19(k, v) {
3380
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
3381
+ }
3382
+ __name(_ts_metadata19, "_ts_metadata");
3383
+ function _ts_param19(paramIndex, decorator) {
3384
+ return function(target, key) {
3385
+ decorator(target, key, paramIndex);
3386
+ };
3387
+ }
3388
+ __name(_ts_param19, "_ts_param");
3389
+ var PrismaCatalogEntryRepository = class {
3390
+ static {
3391
+ __name(this, "PrismaCatalogEntryRepository");
3392
+ }
3393
+ prisma;
3394
+ constructor(prisma) {
3395
+ this.prisma = prisma;
3396
+ }
3397
+ get db() {
3398
+ return this.prisma;
3399
+ }
3400
+ async listCapabilities(filter) {
3401
+ const rows = await this.db.capabilityCatalogEntry.findMany({
3402
+ where: {
3403
+ projectKey: filter.projectKey,
3404
+ deletedAt: null,
3405
+ ...filter.codeStatus ? {
3406
+ codeStatus: filter.codeStatus
3407
+ } : {}
3408
+ },
3409
+ orderBy: [
3410
+ {
3411
+ sortOrder: "asc"
3412
+ },
3413
+ {
3414
+ capabilityKey: "asc"
3415
+ }
3416
+ ]
3417
+ });
3418
+ return rows.map(toCapabilityRow);
3419
+ }
3420
+ async listFeatures(filter) {
3421
+ const rows = await this.db.featureCatalogEntry.findMany({
3422
+ where: {
3423
+ projectKey: filter.projectKey,
3424
+ deletedAt: null,
3425
+ ...filter.discoveryStatus ? {
3426
+ discoveryStatus: filter.discoveryStatus
3427
+ } : {}
3428
+ },
3429
+ orderBy: [
3430
+ {
3431
+ sortOrder: "asc"
3432
+ },
3433
+ {
3434
+ featureKey: "asc"
3435
+ }
3436
+ ]
3437
+ });
3438
+ return rows.map(toFeatureRow);
3439
+ }
3440
+ async listQuotas(filter) {
3441
+ const rows = await this.db.quotaCatalogEntry.findMany({
3442
+ where: {
3443
+ projectKey: filter.projectKey,
3444
+ deletedAt: null,
3445
+ ...filter.discoveryStatus ? {
3446
+ discoveryStatus: filter.discoveryStatus
3447
+ } : {}
3448
+ },
3449
+ orderBy: [
3450
+ {
3451
+ sortOrder: "asc"
3452
+ },
3453
+ {
3454
+ quotaKey: "asc"
3455
+ }
3456
+ ]
3457
+ });
3458
+ return rows.map(toQuotaRow);
3459
+ }
3460
+ async upsertCapability(data) {
3461
+ const codeFields = {
3462
+ label: data.label,
3463
+ description: data.description,
3464
+ featureKey: data.featureKey,
3465
+ bundleKey: data.bundleKey,
3466
+ codeStatus: data.codeStatus,
3467
+ owner: data.owner,
3468
+ kind: data.kind,
3469
+ replacementKey: data.replacementKey,
3470
+ deprecatedAt: data.deprecatedAt ? new Date(data.deprecatedAt) : null,
3471
+ removalPlannedAt: data.removalPlannedAt ? new Date(data.removalPlannedAt) : null,
3472
+ reason: data.reason
3473
+ };
3474
+ const row = await this.db.capabilityCatalogEntry.upsert({
3475
+ where: {
3476
+ projectKey_capabilityKey: {
3477
+ projectKey: data.projectKey,
3478
+ capabilityKey: data.capabilityKey
3479
+ }
3480
+ },
3481
+ create: {
3482
+ projectKey: data.projectKey,
3483
+ capabilityKey: data.capabilityKey,
3484
+ ...codeFields
3485
+ },
3486
+ update: codeFields
3487
+ });
3488
+ return toCapabilityRow(row);
3489
+ }
3490
+ async upsertFeature(data) {
3491
+ const codeFields = {
3492
+ label: data.label,
3493
+ description: data.description,
3494
+ discoveryStatus: data.discoveryStatus,
3495
+ requires: data.requires,
3496
+ replaces: data.replaces,
3497
+ ...data.core !== void 0 ? {
3498
+ core: data.core
3499
+ } : {}
3500
+ };
3501
+ const row = await this.db.featureCatalogEntry.upsert({
3502
+ where: {
3503
+ projectKey_featureKey: {
3504
+ projectKey: data.projectKey,
3505
+ featureKey: data.featureKey
3506
+ }
3507
+ },
3508
+ create: {
3509
+ projectKey: data.projectKey,
3510
+ featureKey: data.featureKey,
3511
+ ...codeFields
3512
+ },
3513
+ update: codeFields
3514
+ });
3515
+ return toFeatureRow(row);
3516
+ }
3517
+ async upsertQuota(data) {
3518
+ const codeFields = {
3519
+ label: data.label,
3520
+ description: data.description,
3521
+ unit: data.unit,
3522
+ featureKey: data.featureKey,
3523
+ usageProvider: data.usageProvider,
3524
+ enforcementMode: data.enforcementMode,
3525
+ discoveryStatus: data.discoveryStatus,
3526
+ replaces: data.replaces
3527
+ };
3528
+ const row = await this.db.quotaCatalogEntry.upsert({
3529
+ where: {
3530
+ projectKey_quotaKey: {
3531
+ projectKey: data.projectKey,
3532
+ quotaKey: data.quotaKey
3533
+ }
3534
+ },
3535
+ create: {
3536
+ projectKey: data.projectKey,
3537
+ quotaKey: data.quotaKey,
3538
+ ...codeFields
3539
+ },
3540
+ update: codeFields
3541
+ });
3542
+ return toQuotaRow(row);
3543
+ }
3544
+ async retireMissing(projectKey, type, presentKeys) {
3545
+ if (type === "capability") {
3546
+ const res2 = await this.db.capabilityCatalogEntry.updateMany({
3547
+ where: {
3548
+ projectKey,
3549
+ deletedAt: null,
3550
+ codeStatus: {
3551
+ not: "retired"
3552
+ },
3553
+ capabilityKey: {
3554
+ notIn: presentKeys
3555
+ }
3556
+ },
3557
+ data: {
3558
+ codeStatus: "retired"
3559
+ }
3560
+ });
3561
+ return res2.count;
3562
+ }
3563
+ if (type === "feature") {
3564
+ const res2 = await this.db.featureCatalogEntry.updateMany({
3565
+ where: {
3566
+ projectKey,
3567
+ deletedAt: null,
3568
+ discoveryStatus: {
3569
+ not: "obsolete"
3570
+ },
3571
+ featureKey: {
3572
+ notIn: presentKeys
3573
+ }
3574
+ },
3575
+ data: {
3576
+ discoveryStatus: "obsolete"
3577
+ }
3578
+ });
3579
+ return res2.count;
3580
+ }
3581
+ const res = await this.db.quotaCatalogEntry.updateMany({
3582
+ where: {
3583
+ projectKey,
3584
+ deletedAt: null,
3585
+ discoveryStatus: {
3586
+ not: "obsolete"
3587
+ },
3588
+ quotaKey: {
3589
+ notIn: presentKeys
3590
+ }
3591
+ },
3592
+ data: {
3593
+ discoveryStatus: "obsolete"
3594
+ }
3595
+ });
3596
+ return res.count;
3597
+ }
3598
+ async setFeatureSuccessor(projectKey, featureKey, successorKey) {
3599
+ const row = await this.db.featureCatalogEntry.update({
3600
+ where: {
3601
+ projectKey_featureKey: {
3602
+ projectKey,
3603
+ featureKey
3604
+ }
3605
+ },
3606
+ data: {
3607
+ successorKey
3608
+ }
3609
+ });
3610
+ return toFeatureRow(row);
3611
+ }
3612
+ async setQuotaSuccessor(projectKey, quotaKey, successorKey) {
3613
+ const row = await this.db.quotaCatalogEntry.update({
3614
+ where: {
3615
+ projectKey_quotaKey: {
3616
+ projectKey,
3617
+ quotaKey
3618
+ }
3619
+ },
3620
+ data: {
3621
+ successorKey
3622
+ }
3623
+ });
3624
+ return toQuotaRow(row);
3625
+ }
3626
+ async findFeature(projectKey, featureKey) {
3627
+ const row = await this.db.featureCatalogEntry.findUnique({
3628
+ where: {
3629
+ projectKey_featureKey: {
3630
+ projectKey,
3631
+ featureKey
3632
+ }
3633
+ }
3634
+ });
3635
+ return row ? toFeatureRow(row) : null;
3636
+ }
3637
+ async findQuota(projectKey, quotaKey) {
3638
+ const row = await this.db.quotaCatalogEntry.findUnique({
3639
+ where: {
3640
+ projectKey_quotaKey: {
3641
+ projectKey,
3642
+ quotaKey
3643
+ }
3644
+ }
3645
+ });
3646
+ return row ? toQuotaRow(row) : null;
3647
+ }
3648
+ async setFeatureReview(projectKey, featureKey, data) {
3649
+ const row = await this.db.featureCatalogEntry.update({
3650
+ where: {
3651
+ projectKey_featureKey: {
3652
+ projectKey,
3653
+ featureKey
3654
+ }
3655
+ },
3656
+ data: {
3657
+ discoveryStatus: data.discoveryStatus,
3658
+ approvedAt: data.approvedAt ? new Date(data.approvedAt) : null,
3659
+ approvedBy: data.approvedBy,
3660
+ approvedSignature: data.approvedSignature
3661
+ }
3662
+ });
3663
+ return toFeatureRow(row);
3664
+ }
3665
+ async setQuotaReview(projectKey, quotaKey, data) {
3666
+ const row = await this.db.quotaCatalogEntry.update({
3667
+ where: {
3668
+ projectKey_quotaKey: {
3669
+ projectKey,
3670
+ quotaKey
3671
+ }
3672
+ },
3673
+ data: {
3674
+ discoveryStatus: data.discoveryStatus,
3675
+ approvedAt: data.approvedAt ? new Date(data.approvedAt) : null,
3676
+ approvedBy: data.approvedBy,
3677
+ approvedSignature: data.approvedSignature
3678
+ }
3679
+ });
3680
+ return toQuotaRow(row);
3681
+ }
3682
+ async setFeatureI18n(projectKey, featureKey, i18n) {
3683
+ const row = await this.db.featureCatalogEntry.update({
3684
+ where: {
3685
+ projectKey_featureKey: {
3686
+ projectKey,
3687
+ featureKey
3688
+ }
3689
+ },
3690
+ data: {
3691
+ i18n
3692
+ }
3693
+ });
3694
+ return toFeatureRow(row);
3695
+ }
3696
+ async setQuotaI18n(projectKey, quotaKey, i18n) {
3697
+ const row = await this.db.quotaCatalogEntry.update({
3698
+ where: {
3699
+ projectKey_quotaKey: {
3700
+ projectKey,
3701
+ quotaKey
3702
+ }
3703
+ },
3704
+ data: {
3705
+ i18n
3706
+ }
3707
+ });
3708
+ return toQuotaRow(row);
3709
+ }
3710
+ async setFeatureBase(projectKey, featureKey, data) {
3711
+ const row = await this.db.featureCatalogEntry.update({
3712
+ where: {
3713
+ projectKey_featureKey: {
3714
+ projectKey,
3715
+ featureKey
3716
+ }
3717
+ },
3718
+ data: {
3719
+ ...data.label !== void 0 ? {
3720
+ label: data.label
3721
+ } : {},
3722
+ ...data.description !== void 0 ? {
3723
+ description: data.description
3724
+ } : {},
3725
+ ...data.icon !== void 0 ? {
3726
+ icon: data.icon
3727
+ } : {},
3728
+ ...data.tier !== void 0 ? {
3729
+ tier: data.tier
3730
+ } : {}
3731
+ }
3732
+ });
3733
+ return toFeatureRow(row);
3734
+ }
3735
+ async setQuotaBase(projectKey, quotaKey, data) {
3736
+ const row = await this.db.quotaCatalogEntry.update({
3737
+ where: {
3738
+ projectKey_quotaKey: {
3739
+ projectKey,
3740
+ quotaKey
3741
+ }
3742
+ },
3743
+ data: {
3744
+ ...data.label !== void 0 ? {
3745
+ label: data.label
3746
+ } : {},
3747
+ ...data.description !== void 0 ? {
3748
+ description: data.description
3749
+ } : {}
3750
+ }
3751
+ });
3752
+ return toQuotaRow(row);
3753
+ }
3754
+ };
3755
+ PrismaCatalogEntryRepository = _ts_decorate21([
3756
+ (0, import_common21.Injectable)(),
3757
+ _ts_param19(0, (0, import_common21.Inject)(PRISMA_CLIENT_TOKEN)),
3758
+ _ts_metadata19("design:type", Function),
3759
+ _ts_metadata19("design:paramtypes", [
3760
+ typeof CatalogEntryRepositoryClient === "undefined" ? Object : CatalogEntryRepositoryClient
3761
+ ])
3762
+ ], PrismaCatalogEntryRepository);
3763
+ function toI18n2(value) {
3764
+ if (value !== null && typeof value === "object" && !Array.isArray(value)) {
3765
+ return value;
3766
+ }
3767
+ return {};
3768
+ }
3769
+ __name(toI18n2, "toI18n");
3770
+ function toCapabilityRow(row) {
3771
+ return {
3772
+ id: row.id,
3773
+ projectKey: row.projectKey,
3774
+ capabilityKey: row.capabilityKey,
3775
+ label: row.label,
3776
+ description: row.description,
3777
+ featureKey: row.featureKey,
3778
+ bundleKey: row.bundleKey,
3779
+ codeStatus: row.codeStatus,
3780
+ owner: row.owner,
3781
+ kind: row.kind,
3782
+ replacementKey: row.replacementKey,
3783
+ deprecatedAt: row.deprecatedAt ? row.deprecatedAt.toISOString() : null,
3784
+ removalPlannedAt: row.removalPlannedAt ? row.removalPlannedAt.toISOString() : null,
3785
+ reason: row.reason,
3786
+ i18n: toI18n2(row.i18n),
3787
+ sortOrder: row.sortOrder,
3788
+ createdAt: row.createdAt.toISOString(),
3789
+ updatedAt: row.updatedAt.toISOString(),
3790
+ deletedAt: row.deletedAt ? row.deletedAt.toISOString() : null
3791
+ };
3792
+ }
3793
+ __name(toCapabilityRow, "toCapabilityRow");
3794
+ function toFeatureRow(row) {
3795
+ return {
3796
+ id: row.id,
3797
+ projectKey: row.projectKey,
3798
+ featureKey: row.featureKey,
3799
+ label: row.label,
3800
+ description: row.description,
3801
+ marketingLabel: row.marketingLabel,
3802
+ marketingDescription: row.marketingDescription,
3803
+ icon: row.icon,
3804
+ tier: row.tier,
3805
+ discoveryStatus: row.discoveryStatus,
3806
+ requires: row.requires,
3807
+ replaces: row.replaces,
3808
+ successorKey: row.successorKey,
3809
+ approvedAt: row.approvedAt ? row.approvedAt.toISOString() : null,
3810
+ approvedBy: row.approvedBy,
3811
+ approvedSignature: row.approvedSignature,
3812
+ plannedOnly: row.plannedOnly,
3813
+ core: row.core,
3814
+ i18n: toI18n2(row.i18n),
3815
+ sortOrder: row.sortOrder,
3816
+ createdAt: row.createdAt.toISOString(),
3817
+ updatedAt: row.updatedAt.toISOString(),
3818
+ deletedAt: row.deletedAt ? row.deletedAt.toISOString() : null
3819
+ };
3820
+ }
3821
+ __name(toFeatureRow, "toFeatureRow");
3822
+ function toQuotaRow(row) {
3823
+ return {
3824
+ id: row.id,
3825
+ projectKey: row.projectKey,
3826
+ quotaKey: row.quotaKey,
3827
+ label: row.label,
3828
+ description: row.description,
3829
+ unit: row.unit,
3830
+ featureKey: row.featureKey,
3831
+ usageProvider: row.usageProvider,
3832
+ enforcementMode: row.enforcementMode,
3833
+ discoveryStatus: row.discoveryStatus,
3834
+ replaces: row.replaces,
3835
+ successorKey: row.successorKey,
3836
+ approvedAt: row.approvedAt ? row.approvedAt.toISOString() : null,
3837
+ approvedBy: row.approvedBy,
3838
+ approvedSignature: row.approvedSignature,
3839
+ i18n: toI18n2(row.i18n),
3840
+ sortOrder: row.sortOrder,
3841
+ createdAt: row.createdAt.toISOString(),
3842
+ updatedAt: row.updatedAt.toISOString(),
3843
+ deletedAt: row.deletedAt ? row.deletedAt.toISOString() : null
3844
+ };
3845
+ }
3846
+ __name(toQuotaRow, "toQuotaRow");
3847
+
3848
+ // src/prisma-marketing-projection.repository.ts
3849
+ var import_common22 = require("@nestjs/common");
3850
+ function _ts_decorate22(decorators, target, key, desc) {
3851
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3852
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
3853
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
3854
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
3855
+ }
3856
+ __name(_ts_decorate22, "_ts_decorate");
3857
+ function _ts_metadata20(k, v) {
3858
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
3859
+ }
3860
+ __name(_ts_metadata20, "_ts_metadata");
3861
+ function _ts_param20(paramIndex, decorator) {
3862
+ return function(target, key) {
3863
+ decorator(target, key, paramIndex);
3864
+ };
3865
+ }
3866
+ __name(_ts_param20, "_ts_param");
3867
+ var PrismaMarketingProjectionRepository = class {
3868
+ static {
3869
+ __name(this, "PrismaMarketingProjectionRepository");
3870
+ }
3871
+ prisma;
3872
+ constructor(prisma) {
3873
+ this.prisma = prisma;
3874
+ }
3875
+ get db() {
3876
+ return this.prisma;
3877
+ }
3878
+ async list(filter) {
3879
+ const rows = await this.db.marketingProjection.findMany({
3880
+ where: {
3881
+ projectKey: filter.projectKey,
3882
+ ...filter.targetType ? {
3883
+ targetType: filter.targetType
3884
+ } : {},
3885
+ ...filter.targetVersionId ? {
3886
+ targetVersionId: filter.targetVersionId
3887
+ } : {},
3888
+ ...filter.locale ? {
3889
+ locale: filter.locale
3890
+ } : {}
3891
+ },
3892
+ orderBy: [
3893
+ {
3894
+ priority: "desc"
3895
+ },
3896
+ {
3897
+ displayLabel: "asc"
3898
+ }
3899
+ ]
3900
+ });
3901
+ return rows.map(toRow);
3902
+ }
3903
+ async findById(id) {
3904
+ const row = await this.db.marketingProjection.findUnique({
3905
+ where: {
3906
+ id
3907
+ }
3908
+ });
3909
+ return row ? toRow(row) : null;
3910
+ }
3911
+ async findByTarget(targetType, targetVersionId, locale) {
3912
+ const row = await this.db.marketingProjection.findUnique({
3913
+ where: {
3914
+ targetType_targetVersionId_locale: {
3915
+ targetType,
3916
+ targetVersionId,
3917
+ locale
3918
+ }
3919
+ }
3920
+ });
3921
+ return row ? toRow(row) : null;
3922
+ }
3923
+ async create(data) {
3924
+ const row = await this.db.marketingProjection.create({
3925
+ data: {
3926
+ projectKey: data.projectKey,
3927
+ targetType: data.targetType,
3928
+ targetVersionId: data.targetVersionId,
3929
+ locale: data.locale ?? "de",
3930
+ displayLabel: data.displayLabel,
3931
+ description: data.description,
3932
+ visible: data.visible ?? true,
3933
+ badge: data.badge ?? "",
3934
+ topFeatures: data.topFeatures ?? [],
3935
+ trialEnabled: data.trialEnabled ?? false,
3936
+ trialDays: data.trialDays ?? 30,
3937
+ priceTag: data.priceTag ?? null,
3938
+ ctaLabel: data.ctaLabel ?? null,
3939
+ priority: data.priority ?? 0,
3940
+ highlight: data.highlight ?? false
3941
+ }
3942
+ });
3943
+ return toRow(row);
3944
+ }
3945
+ async update(id, data) {
3946
+ const row = await this.db.marketingProjection.update({
3947
+ where: {
3948
+ id
3949
+ },
3950
+ data: {
3951
+ ...data.displayLabel !== void 0 ? {
3952
+ displayLabel: data.displayLabel
3953
+ } : {},
3954
+ ...data.description !== void 0 ? {
3955
+ description: data.description
3956
+ } : {},
3957
+ ...data.visible !== void 0 ? {
3958
+ visible: data.visible
3959
+ } : {},
3960
+ ...data.badge !== void 0 ? {
3961
+ badge: data.badge
3962
+ } : {},
3963
+ ...data.topFeatures !== void 0 ? {
3964
+ topFeatures: data.topFeatures
3965
+ } : {},
3966
+ ...data.trialEnabled !== void 0 ? {
3967
+ trialEnabled: data.trialEnabled
3968
+ } : {},
3969
+ ...data.trialDays !== void 0 ? {
3970
+ trialDays: data.trialDays
3971
+ } : {},
3972
+ ...data.priceTag !== void 0 ? {
3973
+ priceTag: data.priceTag
3974
+ } : {},
3975
+ ...data.ctaLabel !== void 0 ? {
3976
+ ctaLabel: data.ctaLabel
3977
+ } : {},
3978
+ ...data.priority !== void 0 ? {
3979
+ priority: data.priority
3980
+ } : {},
3981
+ ...data.highlight !== void 0 ? {
3982
+ highlight: data.highlight
3983
+ } : {}
3984
+ }
3985
+ });
3986
+ return toRow(row);
3987
+ }
3988
+ async delete(id) {
3989
+ await this.db.marketingProjection.delete({
3990
+ where: {
3991
+ id
3992
+ }
3993
+ });
3994
+ }
3995
+ };
3996
+ PrismaMarketingProjectionRepository = _ts_decorate22([
3997
+ (0, import_common22.Injectable)(),
3998
+ _ts_param20(0, (0, import_common22.Inject)(PRISMA_CLIENT_TOKEN)),
3999
+ _ts_metadata20("design:type", Function),
4000
+ _ts_metadata20("design:paramtypes", [
4001
+ typeof MarketingProjectionRepositoryClient === "undefined" ? Object : MarketingProjectionRepositoryClient
4002
+ ])
4003
+ ], PrismaMarketingProjectionRepository);
4004
+ function toTopFeatures(value) {
4005
+ return Array.isArray(value) ? value : [];
4006
+ }
4007
+ __name(toTopFeatures, "toTopFeatures");
4008
+ function toRow(row) {
4009
+ return {
4010
+ id: row.id,
4011
+ projectKey: row.projectKey,
4012
+ targetType: row.targetType,
4013
+ targetVersionId: row.targetVersionId,
4014
+ locale: row.locale,
4015
+ displayLabel: row.displayLabel,
4016
+ description: row.description,
4017
+ visible: row.visible,
4018
+ badge: row.badge,
4019
+ topFeatures: toTopFeatures(row.topFeatures),
4020
+ trialEnabled: row.trialEnabled,
4021
+ trialDays: row.trialDays,
4022
+ priceTag: row.priceTag,
4023
+ ctaLabel: row.ctaLabel,
4024
+ priority: row.priority,
4025
+ highlight: row.highlight,
4026
+ createdAt: row.createdAt.toISOString(),
4027
+ updatedAt: row.updatedAt.toISOString()
4028
+ };
4029
+ }
4030
+ __name(toRow, "toRow");
4031
+
4032
+ // src/prisma-marketing-settings.repository.ts
4033
+ var import_common23 = require("@nestjs/common");
4034
+ function _ts_decorate23(decorators, target, key, desc) {
4035
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4036
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4037
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
4038
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
4039
+ }
4040
+ __name(_ts_decorate23, "_ts_decorate");
4041
+ function _ts_metadata21(k, v) {
4042
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
4043
+ }
4044
+ __name(_ts_metadata21, "_ts_metadata");
4045
+ function _ts_param21(paramIndex, decorator) {
4046
+ return function(target, key) {
4047
+ decorator(target, key, paramIndex);
4048
+ };
4049
+ }
4050
+ __name(_ts_param21, "_ts_param");
4051
+ var PrismaMarketingSettingsRepository = class {
4052
+ static {
4053
+ __name(this, "PrismaMarketingSettingsRepository");
4054
+ }
4055
+ prisma;
4056
+ constructor(prisma) {
4057
+ this.prisma = prisma;
4058
+ }
4059
+ get db() {
4060
+ return this.prisma;
4061
+ }
4062
+ async get(projectKey) {
4063
+ const row = await this.db.marketingSettings.findUnique({
4064
+ where: {
4065
+ projectKey
4066
+ }
4067
+ });
4068
+ return row ? toRow2(row) : null;
4069
+ }
4070
+ async upsert(projectKey, data) {
4071
+ const row = await this.db.marketingSettings.upsert({
4072
+ where: {
4073
+ projectKey
4074
+ },
4075
+ create: {
4076
+ projectKey,
4077
+ activeLocales: data.activeLocales
4078
+ },
4079
+ update: {
4080
+ activeLocales: data.activeLocales
4081
+ }
4082
+ });
4083
+ return toRow2(row);
4084
+ }
4085
+ };
4086
+ PrismaMarketingSettingsRepository = _ts_decorate23([
4087
+ (0, import_common23.Injectable)(),
4088
+ _ts_param21(0, (0, import_common23.Inject)(PRISMA_CLIENT_TOKEN)),
4089
+ _ts_metadata21("design:type", Function),
4090
+ _ts_metadata21("design:paramtypes", [
4091
+ typeof MarketingSettingsRepositoryClient === "undefined" ? Object : MarketingSettingsRepositoryClient
4092
+ ])
4093
+ ], PrismaMarketingSettingsRepository);
4094
+ function toRow2(row) {
4095
+ return {
4096
+ projectKey: row.projectKey,
4097
+ activeLocales: toStringArray(row.activeLocales),
4098
+ updatedAt: row.updatedAt.toISOString()
4099
+ };
4100
+ }
4101
+ __name(toRow2, "toRow");
4102
+
4103
+ // src/prisma-promotion.repository.ts
4104
+ var import_common24 = require("@nestjs/common");
4105
+ function _ts_decorate24(decorators, target, key, desc) {
4106
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4107
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4108
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
4109
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
4110
+ }
4111
+ __name(_ts_decorate24, "_ts_decorate");
4112
+ function _ts_metadata22(k, v) {
4113
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
4114
+ }
4115
+ __name(_ts_metadata22, "_ts_metadata");
4116
+ function _ts_param22(paramIndex, decorator) {
4117
+ return function(target, key) {
4118
+ decorator(target, key, paramIndex);
4119
+ };
4120
+ }
4121
+ __name(_ts_param22, "_ts_param");
4122
+ var PrismaPromotionRepository = class {
4123
+ static {
4124
+ __name(this, "PrismaPromotionRepository");
4125
+ }
4126
+ prisma;
4127
+ constructor(prisma) {
4128
+ this.prisma = prisma;
4129
+ }
4130
+ get db() {
4131
+ return this.prisma;
4132
+ }
4133
+ async list(filter) {
4134
+ const rows = await this.db.promotion.findMany({
4135
+ where: {
4136
+ projectKey: filter.projectKey
4137
+ },
4138
+ orderBy: [
4139
+ {
4140
+ validFrom: "desc"
4141
+ }
4142
+ ]
4143
+ });
4144
+ return rows.map(toRow3);
4145
+ }
4146
+ async findById(id) {
4147
+ const row = await this.db.promotion.findUnique({
4148
+ where: {
4149
+ id
4150
+ }
4151
+ });
4152
+ return row ? toRow3(row) : null;
4153
+ }
4154
+ async create(data) {
4155
+ const row = await this.db.promotion.create({
4156
+ data: {
4157
+ projectKey: data.projectKey,
4158
+ internalLabel: data.internalLabel,
4159
+ type: data.type,
4160
+ value: data.value,
4161
+ targetType: data.targetType ?? "PLAN",
4162
+ appliesTo: data.appliesTo ?? [],
4163
+ billingCycle: data.billingCycle ?? "both",
4164
+ validFrom: new Date(data.validFrom),
4165
+ validTo: new Date(data.validTo),
4166
+ priority: data.priority ?? 0,
4167
+ requiresCoupon: data.requiresCoupon ?? false,
4168
+ codes: data.codes ?? [],
4169
+ color: data.color ?? "#2563eb",
4170
+ i18n: data.i18n ?? {},
4171
+ // Null/undefined restriction is left off so the nullable column
4172
+ // stays SQL NULL (= all locales).
4173
+ ...Array.isArray(data.onlyLocales) ? {
4174
+ onlyLocales: data.onlyLocales
4175
+ } : {}
4176
+ }
4177
+ });
4178
+ return toRow3(row);
4179
+ }
4180
+ async update(id, data) {
4181
+ if (data.onlyLocales === null) {
4182
+ const executeRaw = this.prisma.$executeRaw.bind(this.prisma);
4183
+ await executeRaw`
4184
+ UPDATE promotions SET "onlyLocales" = NULL, "updatedAt" = NOW() WHERE id = ${id}`;
4185
+ }
4186
+ const row = await this.db.promotion.update({
4187
+ where: {
4188
+ id
4189
+ },
4190
+ data: {
4191
+ ...data.internalLabel !== void 0 ? {
4192
+ internalLabel: data.internalLabel
4193
+ } : {},
4194
+ ...data.type !== void 0 ? {
4195
+ type: data.type
4196
+ } : {},
4197
+ ...data.value !== void 0 ? {
4198
+ value: data.value
4199
+ } : {},
4200
+ ...data.appliesTo !== void 0 ? {
4201
+ appliesTo: data.appliesTo
4202
+ } : {},
4203
+ ...data.targetType !== void 0 ? {
4204
+ targetType: data.targetType
4205
+ } : {},
4206
+ ...data.billingCycle !== void 0 ? {
4207
+ billingCycle: data.billingCycle
4208
+ } : {},
4209
+ ...data.validFrom !== void 0 ? {
4210
+ validFrom: new Date(data.validFrom)
4211
+ } : {},
4212
+ ...data.validTo !== void 0 ? {
4213
+ validTo: new Date(data.validTo)
4214
+ } : {},
4215
+ ...data.priority !== void 0 ? {
4216
+ priority: data.priority
4217
+ } : {},
4218
+ ...data.requiresCoupon !== void 0 ? {
4219
+ requiresCoupon: data.requiresCoupon
4220
+ } : {},
4221
+ ...data.codes !== void 0 ? {
4222
+ codes: data.codes
4223
+ } : {},
4224
+ ...data.color !== void 0 ? {
4225
+ color: data.color
4226
+ } : {},
4227
+ ...data.i18n !== void 0 ? {
4228
+ i18n: data.i18n
4229
+ } : {},
4230
+ ...Array.isArray(data.onlyLocales) ? {
4231
+ onlyLocales: data.onlyLocales
4232
+ } : {}
4233
+ }
4234
+ });
4235
+ return toRow3(row);
4236
+ }
4237
+ async delete(id) {
4238
+ await this.db.promotion.delete({
4239
+ where: {
4240
+ id
4241
+ }
4242
+ });
4243
+ }
4244
+ };
4245
+ PrismaPromotionRepository = _ts_decorate24([
4246
+ (0, import_common24.Injectable)(),
4247
+ _ts_param22(0, (0, import_common24.Inject)(PRISMA_CLIENT_TOKEN)),
4248
+ _ts_metadata22("design:type", Function),
4249
+ _ts_metadata22("design:paramtypes", [
4250
+ typeof PromotionRepositoryClient === "undefined" ? Object : PromotionRepositoryClient
4251
+ ])
4252
+ ], PrismaPromotionRepository);
4253
+ function toPromotionValue(value) {
4254
+ if (typeof value === "number") return value;
4255
+ if (value !== null && typeof value === "object" && !Array.isArray(value)) {
4256
+ const obj = value;
4257
+ return {
4258
+ price: Number(obj.price),
4259
+ months: Number(obj.months)
4260
+ };
4261
+ }
4262
+ throw new Error(`Promotion.value has an unexpected shape: ${JSON.stringify(value)}`);
4263
+ }
4264
+ __name(toPromotionValue, "toPromotionValue");
4265
+ function toNullableStringArray(value) {
4266
+ return Array.isArray(value) ? value : null;
4267
+ }
4268
+ __name(toNullableStringArray, "toNullableStringArray");
4269
+ function toPromotionI18n(value) {
4270
+ if (value !== null && typeof value === "object" && !Array.isArray(value)) {
4271
+ return value;
4272
+ }
4273
+ return {};
4274
+ }
4275
+ __name(toPromotionI18n, "toPromotionI18n");
4276
+ function toRow3(row) {
4277
+ return {
4278
+ id: row.id,
4279
+ projectKey: row.projectKey,
4280
+ internalLabel: row.internalLabel,
4281
+ type: row.type,
4282
+ value: toPromotionValue(row.value),
4283
+ appliesTo: toStringArray(row.appliesTo),
4284
+ targetType: row.targetType,
4285
+ billingCycle: row.billingCycle,
4286
+ validFrom: row.validFrom.toISOString().slice(0, 10),
4287
+ validTo: row.validTo.toISOString().slice(0, 10),
4288
+ priority: row.priority,
4289
+ onlyLocales: toNullableStringArray(row.onlyLocales),
4290
+ requiresCoupon: row.requiresCoupon,
4291
+ codes: toStringArray(row.codes),
4292
+ color: row.color,
4293
+ i18n: toPromotionI18n(row.i18n),
4294
+ createdAt: row.createdAt.toISOString(),
4295
+ updatedAt: row.updatedAt.toISOString()
4296
+ };
4297
+ }
4298
+ __name(toRow3, "toRow");
4299
+
4300
+ // src/prisma-subscription-contract.repository.ts
4301
+ var import_common25 = require("@nestjs/common");
4302
+ function _ts_decorate25(decorators, target, key, desc) {
4303
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4304
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4305
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
4306
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
4307
+ }
4308
+ __name(_ts_decorate25, "_ts_decorate");
4309
+ function _ts_metadata23(k, v) {
4310
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
4311
+ }
4312
+ __name(_ts_metadata23, "_ts_metadata");
4313
+ function _ts_param23(paramIndex, decorator) {
4314
+ return function(target, key) {
4315
+ decorator(target, key, paramIndex);
4316
+ };
4317
+ }
4318
+ __name(_ts_param23, "_ts_param");
4319
+ var ACTIVE_CONTRACT_STATUSES = [
4320
+ "active",
4321
+ "scheduled"
4322
+ ];
4323
+ var PrismaSubscriptionContractRepository = class {
4324
+ static {
4325
+ __name(this, "PrismaSubscriptionContractRepository");
4326
+ }
4327
+ prisma;
4328
+ constructor(prisma) {
4329
+ this.prisma = prisma;
4330
+ }
4331
+ get db() {
4332
+ return this.prisma;
4333
+ }
4334
+ async list(filter) {
4335
+ const rows = await this.db.subscriptionContract.findMany({
4336
+ where: {
4337
+ ...filter.projectKey ? {
4338
+ projectKey: filter.projectKey
4339
+ } : {},
4340
+ ...filter.tenantId ? {
4341
+ tenantId: filter.tenantId
4342
+ } : {},
4343
+ ...filter.status ? {
4344
+ status: filter.status
4345
+ } : {},
4346
+ ...filter.asOf ? {
4347
+ effectiveFrom: {
4348
+ lte: filter.asOf
4349
+ },
4350
+ OR: [
4351
+ {
4352
+ effectiveUntil: null
4353
+ },
4354
+ {
4355
+ effectiveUntil: {
4356
+ gt: filter.asOf
4357
+ }
4358
+ }
4359
+ ]
4360
+ } : {}
4361
+ },
4362
+ include: {
4363
+ lineItems: true
4364
+ },
4365
+ orderBy: [
4366
+ {
4367
+ effectiveFrom: "desc"
4368
+ },
4369
+ {
4370
+ createdAt: "desc"
4371
+ }
4372
+ ]
4373
+ });
4374
+ return rows.map(toRecord4);
4375
+ }
4376
+ async findById(contractId) {
4377
+ const row = await this.db.subscriptionContract.findUnique({
4378
+ where: {
4379
+ id: contractId
4380
+ },
4381
+ include: {
4382
+ lineItems: true
4383
+ }
4384
+ });
4385
+ return row ? toRecord4(row) : null;
4386
+ }
4387
+ async findActiveByTenantId(tenantId, asOf = /* @__PURE__ */ new Date()) {
4388
+ const row = await this.db.subscriptionContract.findFirst({
4389
+ where: {
4390
+ tenantId,
4391
+ status: {
4392
+ in: ACTIVE_CONTRACT_STATUSES
4393
+ },
4394
+ effectiveFrom: {
4395
+ lte: asOf
4396
+ },
4397
+ OR: [
4398
+ {
4399
+ effectiveUntil: null
4400
+ },
4401
+ {
4402
+ effectiveUntil: {
4403
+ gt: asOf
4404
+ }
4405
+ }
4406
+ ]
4407
+ },
4408
+ include: {
4409
+ lineItems: true
4410
+ },
4411
+ orderBy: [
4412
+ {
4413
+ effectiveFrom: "desc"
4414
+ },
4415
+ {
4416
+ createdAt: "desc"
4417
+ }
4418
+ ]
4419
+ });
4420
+ return row ? toRecord4(row) : null;
4421
+ }
4422
+ async create(data) {
4423
+ const row = await this.db.subscriptionContract.create({
4424
+ data: {
4425
+ projectKey: data.projectKey,
4426
+ tenantId: data.tenantId,
4427
+ status: data.status ?? "active",
4428
+ effectiveFrom: data.effectiveFrom,
4429
+ effectiveUntil: data.effectiveUntil ?? null,
4430
+ originalOfferId: data.originalOfferId ?? null,
4431
+ originalPlanVersionId: data.originalPlanVersionId ?? null,
4432
+ originalBundleVersionIds: data.originalBundleVersionIds ?? [],
4433
+ priceSnapshot: data.priceSnapshot,
4434
+ promotionSnapshots: data.promotionSnapshots ?? [],
4435
+ promoCodeSnapshots: data.promoCodeSnapshots ?? [],
4436
+ // Nullable JSON columns are omitted when absent so they stay SQL
4437
+ // NULL (the DbNull sentinel is not available in this package).
4438
+ ...data.entitlementSnapshot != null ? {
4439
+ entitlementSnapshot: data.entitlementSnapshot
4440
+ } : {},
4441
+ ...data.termsSnapshot != null ? {
4442
+ termsSnapshot: data.termsSnapshot
4443
+ } : {},
4444
+ lineItems: {
4445
+ create: data.lineItems.map(toLineItemCreate)
4446
+ }
4447
+ },
4448
+ include: {
4449
+ lineItems: true
4450
+ }
4451
+ });
4452
+ return toRecord4(row);
4453
+ }
4454
+ async terminate(contractId, data) {
4455
+ const row = await this.db.subscriptionContract.update({
4456
+ where: {
4457
+ id: contractId
4458
+ },
4459
+ data: {
4460
+ effectiveUntil: data.effectiveUntil,
4461
+ status: data.status
4462
+ },
4463
+ include: {
4464
+ lineItems: true
4465
+ }
4466
+ });
4467
+ return toRecord4(row);
4468
+ }
4469
+ };
4470
+ PrismaSubscriptionContractRepository = _ts_decorate25([
4471
+ (0, import_common25.Injectable)(),
4472
+ _ts_param23(0, (0, import_common25.Inject)(PRISMA_CLIENT_TOKEN)),
4473
+ _ts_metadata23("design:type", Function),
4474
+ _ts_metadata23("design:paramtypes", [
4475
+ typeof PrismaLike === "undefined" ? Object : PrismaLike
4476
+ ])
4477
+ ], PrismaSubscriptionContractRepository);
4478
+ function toLineItemCreate(item) {
4479
+ return {
4480
+ kind: item.kind,
4481
+ sourceKey: item.sourceKey,
4482
+ sourceVersionId: item.sourceVersionId ?? null,
4483
+ titleSnapshot: item.titleSnapshot,
4484
+ descriptionSnapshot: item.descriptionSnapshot ?? null,
4485
+ quantity: item.quantity,
4486
+ unit: item.unit ?? null,
4487
+ priceNet: item.priceNet,
4488
+ priceGross: item.priceGross,
4489
+ billingCycle: item.billingCycle,
4490
+ minimumTermUntil: item.minimumTermUntil ?? null,
4491
+ featuresSnapshot: item.featuresSnapshot,
4492
+ quotaEffectsSnapshot: item.quotaEffectsSnapshot,
4493
+ ...item.metadata != null ? {
4494
+ metadata: item.metadata
4495
+ } : {}
4496
+ };
4497
+ }
4498
+ __name(toLineItemCreate, "toLineItemCreate");
4499
+ function isPlainObject2(value) {
4500
+ return value !== null && typeof value === "object" && !Array.isArray(value);
4501
+ }
4502
+ __name(isPlainObject2, "isPlainObject");
4503
+ function toUnknownArray(value) {
4504
+ return Array.isArray(value) ? value : [];
4505
+ }
4506
+ __name(toUnknownArray, "toUnknownArray");
4507
+ function toRecordOrNull(value) {
4508
+ return isPlainObject2(value) ? value : null;
4509
+ }
4510
+ __name(toRecordOrNull, "toRecordOrNull");
4511
+ function toLineItem(row) {
4512
+ return {
4513
+ id: row.id,
4514
+ contractId: row.contractId,
4515
+ kind: row.kind,
4516
+ sourceKey: row.sourceKey,
4517
+ sourceVersionId: row.sourceVersionId,
4518
+ titleSnapshot: row.titleSnapshot,
4519
+ descriptionSnapshot: row.descriptionSnapshot,
4520
+ quantity: row.quantity,
4521
+ unit: row.unit,
4522
+ priceNet: Number(row.priceNet),
4523
+ priceGross: Number(row.priceGross),
4524
+ billingCycle: row.billingCycle,
4525
+ minimumTermUntil: row.minimumTermUntil,
4526
+ featuresSnapshot: toStringArray(row.featuresSnapshot),
4527
+ quotaEffectsSnapshot: toQuotaMap(row.quotaEffectsSnapshot),
4528
+ metadata: toRecordOrNull(row.metadata),
4529
+ createdAt: row.createdAt
4530
+ };
4531
+ }
4532
+ __name(toLineItem, "toLineItem");
4533
+ function toRecord4(row) {
4534
+ return {
4535
+ id: row.id,
4536
+ projectKey: row.projectKey,
4537
+ tenantId: row.tenantId,
4538
+ status: row.status,
4539
+ effectiveFrom: row.effectiveFrom,
4540
+ effectiveUntil: row.effectiveUntil,
4541
+ originalOfferId: row.originalOfferId,
4542
+ originalPlanVersionId: row.originalPlanVersionId,
4543
+ originalBundleVersionIds: toStringArray(row.originalBundleVersionIds),
4544
+ entitlementSnapshot: isPlainObject2(row.entitlementSnapshot) ? row.entitlementSnapshot : null,
4545
+ priceSnapshot: row.priceSnapshot,
4546
+ promotionSnapshots: toUnknownArray(row.promotionSnapshots),
4547
+ promoCodeSnapshots: toUnknownArray(row.promoCodeSnapshots),
4548
+ termsSnapshot: toRecordOrNull(row.termsSnapshot),
4549
+ lineItems: row.lineItems.map(toLineItem),
4550
+ createdAt: row.createdAt,
4551
+ updatedAt: row.updatedAt
4552
+ };
4553
+ }
4554
+ __name(toRecord4, "toRecord");
1463
4555
  // Annotate the CommonJS export names for ESM import in node:
1464
4556
  0 && (module.exports = {
1465
4557
  AsyncLocalRlsBypassAdapter,
1466
4558
  PASSWORD_HASHER_TOKEN,
4559
+ PRISMA_BUNDLE_REPOSITORY_OPTIONS,
1467
4560
  PRISMA_CLIENT_TOKEN,
4561
+ PRISMA_SCHEMA_OPTIONS_TOKEN,
1468
4562
  PrismaAuditAdapter,
1469
4563
  PrismaAuditQueryAdapter,
1470
4564
  PrismaAuditStatsAdapter,
4565
+ PrismaBundleRepository,
4566
+ PrismaCatalogEntryRepository,
4567
+ PrismaMarketingProjectionRepository,
4568
+ PrismaMarketingSettingsRepository,
1471
4569
  PrismaMfaAdapter,
1472
4570
  PrismaPlanCatalogImportSink,
1473
4571
  PrismaPlanCatalogReadSink,
4572
+ PrismaPlanRepository,
1474
4573
  PrismaPlanVersionRepository,
1475
4574
  PrismaPromoCodeRedemptionRepository,
1476
4575
  PrismaPromoCodeRepository,
1477
4576
  PrismaPromoCodeValidationLogRepository,
1478
4577
  PrismaPromoSubscriptionLookup,
4578
+ PrismaPromotionRepository,
4579
+ PrismaSubscriptionBundleRepository,
4580
+ PrismaSubscriptionContractRepository,
1479
4581
  PrismaSubscriptionRepository,
1480
4582
  PrismaSuperAdminBootstrapAdapter,
4583
+ PrismaTenantSubscriptionWriteAdapter,
1481
4584
  PrismaTransactionRunner,
1482
4585
  ZeroPromoRevenueDeductionAggregator,
1483
4586
  buildActorTag,
1484
- prismaPersistence
4587
+ createPrismaPlanBindingResolver,
4588
+ getPrismaDelegate,
4589
+ prismaPersistence,
4590
+ resolvePrismaSchemaOptions
1485
4591
  });