@saasicat/adapter-prisma 0.9.0 → 0.10.1

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
@@ -2239,9 +2239,14 @@ var PrismaPlanCatalogReadSink = class {
2239
2239
  projectKey,
2240
2240
  deletedAt: null
2241
2241
  },
2242
- orderBy: {
2243
- sortOrder: "asc"
2244
- }
2242
+ orderBy: [
2243
+ {
2244
+ sortOrder: "asc"
2245
+ },
2246
+ {
2247
+ planKey: "asc"
2248
+ }
2249
+ ]
2245
2250
  });
2246
2251
  const planKeysByStoredId = new Map(plans.map((plan) => [
2247
2252
  this.binding.mode === "normalized-plan-id" ? plan.id : plan.planKey,
@@ -2259,16 +2264,29 @@ var PrismaPlanCatalogReadSink = class {
2259
2264
  not: null
2260
2265
  },
2261
2266
  supersededAt: null
2262
- }
2267
+ },
2268
+ orderBy: [
2269
+ {
2270
+ planId: "asc"
2271
+ },
2272
+ {
2273
+ version: "asc"
2274
+ }
2275
+ ]
2263
2276
  });
2264
2277
  const featureEntries = await db.featureCatalogEntry.findMany({
2265
2278
  where: {
2266
2279
  projectKey,
2267
2280
  deletedAt: null
2268
2281
  },
2269
- orderBy: {
2270
- sortOrder: "asc"
2271
- }
2282
+ orderBy: [
2283
+ {
2284
+ sortOrder: "asc"
2285
+ },
2286
+ {
2287
+ featureKey: "asc"
2288
+ }
2289
+ ]
2272
2290
  });
2273
2291
  return {
2274
2292
  plans: plans.map(toPlanRow),
@@ -4894,11 +4912,11 @@ function prismaPersistence(options) {
4894
4912
  planVersionRepository: provide((prisma) => new PrismaPlanVersionRepository(prisma, options.schema)),
4895
4913
  subscriptionContractRepository: provide((prisma) => new PrismaSubscriptionContractRepository(prisma)),
4896
4914
  subscriptionBundleRepository: provide((prisma) => new PrismaSubscriptionBundleRepository(canonical(prisma))),
4897
- bundleRepository: provide((prisma) => new PrismaBundleRepository(canonical(prisma)))
4915
+ bundleRepository: provide((prisma) => new PrismaBundleRepository(canonical(prisma), options.bundle))
4898
4916
  },
4899
4917
  catalog: {
4900
4918
  planRepository: provide((prisma) => new PrismaPlanRepository(prisma, options.schema)),
4901
- bundleRepository: provide((prisma) => new PrismaBundleRepository(canonical(prisma))),
4919
+ bundleRepository: provide((prisma) => new PrismaBundleRepository(canonical(prisma), options.bundle)),
4902
4920
  catalogEntryRepository: provide((prisma) => new PrismaCatalogEntryRepository(canonical(prisma))),
4903
4921
  marketingProjectionRepository: provide((prisma) => new PrismaMarketingProjectionRepository(canonical(prisma))),
4904
4922
  promotionRepository: provide((prisma) => new PrismaPromotionRepository(canonical(prisma))),
package/dist/index.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { AdminResourcesPort, AdminTenantListFilter, AdminTenantListRow, AdminTenantDetail, AdminTenantStateResult, AdminUserListFilter, AdminUserListRow, AdminAuditListFilter, AuditEntry, AdminSubscriptionListRow, PersistenceInjectionToken, PasswordHasher, SaasicatPersistenceAdapter, TransactionRunner, TransactionContext, MfaPort, AuditPort, AdminActor, AuditQueryPort, AuditQuery, AuditStatsPort, RlsBypassPort, SubscriptionRepository, SubscriptionRecord, SubscriptionUsagePort, SubscriptionUsageRecord, SubscriptionBundleRepository, SubscriptionBundleRecord, CreateSubscriptionBundleData, CancelSubscriptionBundleData, TenantSubscriptionWritePort, ApplyOnboardingSelectionInput, RedeemPromoInTransactionCallback, ApplyOnboardingSelectionResult, ImmediatePlanChangeInput, ScheduledPlanChangeInput, PlanVersionRepository, PlanVersionRecord, PromoCodeRepository, PromoCodeRecord, PromoCodeFilter, CreatePromoCodeData, UpdatePromoCodeData, PromoCodeRedemptionRepository, PromoCodeRedemptionRecord, PromoCodeRedemptionStatus, PromoCodeRedemptionListItem, PromoCodeValidationLogRepository, PromoSubscriptionLookup, BillingCycle, PromoRevenueDeductionAggregator, SuperAdminProvisioningPort, CreateSuperAdminCliInput, PlatformUserDto, PlanCatalogReadSink, PlanCatalogReadSnapshot, PlanCatalogImportSink, UpsertPlanInput, UpsertResult, UpsertPlanVersionInput, UpsertFeatureCatalogEntryInput, PlanRepository, PlanListFilter, PlanRow, CreatePlanData, UpdatePlanData, PlanVersionRow, CreatePlanVersionDraftData, UpdatePlanVersionDraftData, VersionChange, BundleRepository, BundleVersionRow, BundleListFilter, BundleRow, CreateBundleData, UpdateBundleData, CreateBundleVersionDraftData, UpdateBundleVersionDraftData, CatalogEntryRepository, CatalogEntryFilter, CapabilityCatalogEntryRow, FeatureCatalogEntryRow, QuotaCatalogEntryRow, UpsertCapabilityEntryData, UpsertFeatureEntryData, UpsertQuotaEntryData, SetCatalogEntryReviewData, CatalogEntryI18n, UpdateCatalogEntryBaseData, MarketingProjectionRepository, MarketingProjectionFilter, MarketingProjectionRow, CreateMarketingProjectionData, UpdateMarketingProjectionData, MarketingSettingsRepository, MarketingSettingsRow, UpdateMarketingSettingsData, PromotionRepository, PromotionFilter, PromotionRow, CreatePromotionData, UpdatePromotionData, SubscriptionContractRepository, SubscriptionContractFilter, SubscriptionContractRecord, CreateSubscriptionContractData, TerminateSubscriptionContractData } from '@saasicat/types';
1
+ import { AdminResourcesPort, AdminTenantListFilter, AdminTenantListRow, AdminTenantDetail, AdminTenantStateResult, AdminUserListFilter, AdminUserListRow, AdminAuditListFilter, AuditEntry, AdminSubscriptionListRow, BundleRepository, TransactionContext, BundleVersionRow, BundleListFilter, BundleRow, CreateBundleData, UpdateBundleData, CreateBundleVersionDraftData, UpdateBundleVersionDraftData, VersionChange, PersistenceInjectionToken, PasswordHasher, SaasicatPersistenceAdapter, TransactionRunner, MfaPort, AuditPort, AdminActor, AuditQueryPort, AuditQuery, AuditStatsPort, RlsBypassPort, SubscriptionRepository, SubscriptionRecord, SubscriptionUsagePort, SubscriptionUsageRecord, SubscriptionBundleRepository, SubscriptionBundleRecord, CreateSubscriptionBundleData, CancelSubscriptionBundleData, TenantSubscriptionWritePort, ApplyOnboardingSelectionInput, RedeemPromoInTransactionCallback, ApplyOnboardingSelectionResult, ImmediatePlanChangeInput, ScheduledPlanChangeInput, PlanVersionRepository, PlanVersionRecord, PromoCodeRepository, PromoCodeRecord, PromoCodeFilter, CreatePromoCodeData, UpdatePromoCodeData, PromoCodeRedemptionRepository, PromoCodeRedemptionRecord, PromoCodeRedemptionStatus, PromoCodeRedemptionListItem, PromoCodeValidationLogRepository, PromoSubscriptionLookup, BillingCycle, PromoRevenueDeductionAggregator, SuperAdminProvisioningPort, CreateSuperAdminCliInput, PlatformUserDto, PlanCatalogReadSink, PlanCatalogReadSnapshot, PlanCatalogImportSink, UpsertPlanInput, UpsertResult, UpsertPlanVersionInput, UpsertFeatureCatalogEntryInput, PlanRepository, PlanListFilter, PlanRow, CreatePlanData, UpdatePlanData, PlanVersionRow, CreatePlanVersionDraftData, UpdatePlanVersionDraftData, CatalogEntryRepository, CatalogEntryFilter, CapabilityCatalogEntryRow, FeatureCatalogEntryRow, QuotaCatalogEntryRow, UpsertCapabilityEntryData, UpsertFeatureEntryData, UpsertQuotaEntryData, SetCatalogEntryReviewData, CatalogEntryI18n, UpdateCatalogEntryBaseData, MarketingProjectionRepository, MarketingProjectionFilter, MarketingProjectionRow, CreateMarketingProjectionData, UpdateMarketingProjectionData, MarketingSettingsRepository, MarketingSettingsRow, UpdateMarketingSettingsData, PromotionRepository, PromotionFilter, PromotionRow, CreatePromotionData, UpdatePromotionData, SubscriptionContractRepository, SubscriptionContractFilter, SubscriptionContractRecord, CreateSubscriptionContractData, TerminateSubscriptionContractData } from '@saasicat/types';
2
2
 
3
3
  declare const PRISMA_CLIENT_TOKEN: unique symbol;
4
4
  /** Prisma `Decimal` values arrive as objects with `toString()`; tests may use plain values. */
@@ -736,6 +736,84 @@ declare class PrismaAdminResourcesAdapter implements AdminResourcesPort {
736
736
  private subscriptions;
737
737
  }
738
738
 
739
+ /**
740
+ * Root-client shape accepted by this repository. Delegates and `$transaction`
741
+ * stay opaque at the injection boundary because generated Prisma delegates
742
+ * have schema-specific generic signatures; calls are narrowed locally to the
743
+ * exact Bundle operations below.
744
+ */
745
+ interface BundlePrismaClient {
746
+ bundle: unknown;
747
+ bundleVersion: unknown;
748
+ $transaction: unknown;
749
+ }
750
+ /**
751
+ * Optional DI token for apps that register `PrismaBundleRepository` directly
752
+ * as a Nest provider. Factory users may pass the same options as the second
753
+ * constructor argument.
754
+ */
755
+ declare const PRISMA_BUNDLE_REPOSITORY_OPTIONS: unique symbol;
756
+ interface PrismaBundleRepositoryOptions {
757
+ /**
758
+ * Enables reads and writes of `BundleVersion.validFrom`/`validUntil`.
759
+ *
760
+ * Default `false` preserves compatibility with databases and Prisma
761
+ * clients generated from the 0.6 schema, where the columns do not exist.
762
+ */
763
+ validityWindows?: boolean;
764
+ }
765
+ /**
766
+ * `BundleRepository` against the canonical `bundles` + `bundle_versions`
767
+ * tables (SPEC_V2 §5 + §11.1 M3). Versioning mirrors `PlanVersion`: at most one
768
+ * draft (`publishedAt IS NULL`) per bundle, monotonically incrementing
769
+ * `version`, `supersededAt` marking the previous live version on publish.
770
+ *
771
+ * Validity-window support is opt-in via `{ validityWindows: true }`. The
772
+ * default deliberately does not select, read or write `validFrom`/
773
+ * `validUntil`, and therefore keeps working with the 0.6 schema. In the
774
+ * enabled mode the repository expects both nullable columns to exist.
775
+ *
776
+ * In validity-window mode `publishDraft` opens an internal transaction when
777
+ * the caller did not provide one. This makes superseding the predecessor,
778
+ * applying its auto-succession end date and publishing the draft atomic.
779
+ * Legacy mode retains the 0.6 transaction behavior unchanged.
780
+ */
781
+ declare class PrismaBundleRepository implements BundleRepository {
782
+ private readonly prisma;
783
+ private readonly validityWindows;
784
+ /**
785
+ * Present only when validity-window mode is enabled. This mirrors the
786
+ * optional port capability and lets 0.6-schema consumers detect that an
787
+ * active-at-time lookup is unavailable.
788
+ */
789
+ readonly findActiveBundleVersion?: (bundleId: string, asOf?: Date, tx?: TransactionContext) => Promise<BundleVersionRow | null>;
790
+ constructor(prisma: BundlePrismaClient, options?: PrismaBundleRepositoryOptions);
791
+ private db;
792
+ private transaction;
793
+ list(filter: BundleListFilter): Promise<BundleRow[]>;
794
+ findById(bundleId: string): Promise<BundleRow | null>;
795
+ findByKey(projectKey: string, bundleKey: string): Promise<BundleRow | null>;
796
+ create(data: CreateBundleData): Promise<BundleRow>;
797
+ update(bundleId: string, data: UpdateBundleData): Promise<BundleRow>;
798
+ softDelete(bundleId: string): Promise<void>;
799
+ listVersions(bundleId: string): Promise<BundleVersionRow[]>;
800
+ findVersionById(versionId: string): Promise<BundleVersionRow | null>;
801
+ findCurrentDraft(bundleId: string): Promise<BundleVersionRow | null>;
802
+ findLatestLive(bundleId: string, tx?: TransactionContext): Promise<BundleVersionRow | null>;
803
+ private findActiveBundleVersionWithValidity;
804
+ createDraft(data: CreateBundleVersionDraftData): Promise<BundleVersionRow>;
805
+ updateDraft(versionId: string, data: UpdateBundleVersionDraftData): Promise<BundleVersionRow>;
806
+ publishDraft(versionId: string, publishMeta: {
807
+ publishedByUserId: string | null;
808
+ publishedChanges: VersionChange[];
809
+ nonRegressive: boolean;
810
+ validFrom: Date;
811
+ validUntil: Date | null;
812
+ }, tx?: TransactionContext): Promise<BundleVersionRow>;
813
+ private publishDraftWithValidity;
814
+ deleteDraft(versionId: string): Promise<void>;
815
+ }
816
+
739
817
  interface PrismaPersistenceOptions {
740
818
  /**
741
819
  * The app's Prisma client: either its injection token (typically the
@@ -768,6 +846,17 @@ interface PrismaPersistenceOptions {
768
846
  * for schemas without conventional `tenant`/`user` delegates.
769
847
  */
770
848
  adminResources?: false | PrismaAdminResourcesOptions;
849
+ /**
850
+ * Options for the bundle repository the catalog and entitlement slices
851
+ * share — notably `{ validityWindows: true }` for schemas that carry
852
+ * `BundleVersion.validFrom`/`validUntil`.
853
+ *
854
+ * Without this the bundle builds the repository with its 0.6-compatible
855
+ * defaults, and the repository's `@Optional() @Inject(...)` options
856
+ * provider never applies, because the bundle constructs the instance
857
+ * directly rather than through Nest DI.
858
+ */
859
+ bundle?: PrismaBundleRepositoryOptions;
771
860
  }
772
861
  /**
773
862
  * Builds the `SaasicatPersistenceAdapter` bundle for Prisma + PostgreSQL on
@@ -1254,84 +1343,6 @@ declare class PrismaPlanRepository implements PlanRepository {
1254
1343
  private toPlanVersionRow;
1255
1344
  }
1256
1345
 
1257
- /**
1258
- * Root-client shape accepted by this repository. Delegates and `$transaction`
1259
- * stay opaque at the injection boundary because generated Prisma delegates
1260
- * have schema-specific generic signatures; calls are narrowed locally to the
1261
- * exact Bundle operations below.
1262
- */
1263
- interface BundlePrismaClient {
1264
- bundle: unknown;
1265
- bundleVersion: unknown;
1266
- $transaction: unknown;
1267
- }
1268
- /**
1269
- * Optional DI token for apps that register `PrismaBundleRepository` directly
1270
- * as a Nest provider. Factory users may pass the same options as the second
1271
- * constructor argument.
1272
- */
1273
- declare const PRISMA_BUNDLE_REPOSITORY_OPTIONS: unique symbol;
1274
- interface PrismaBundleRepositoryOptions {
1275
- /**
1276
- * Enables reads and writes of `BundleVersion.validFrom`/`validUntil`.
1277
- *
1278
- * Default `false` preserves compatibility with databases and Prisma
1279
- * clients generated from the 0.6 schema, where the columns do not exist.
1280
- */
1281
- validityWindows?: boolean;
1282
- }
1283
- /**
1284
- * `BundleRepository` against the canonical `bundles` + `bundle_versions`
1285
- * tables (SPEC_V2 §5 + §11.1 M3). Versioning mirrors `PlanVersion`: at most one
1286
- * draft (`publishedAt IS NULL`) per bundle, monotonically incrementing
1287
- * `version`, `supersededAt` marking the previous live version on publish.
1288
- *
1289
- * Validity-window support is opt-in via `{ validityWindows: true }`. The
1290
- * default deliberately does not select, read or write `validFrom`/
1291
- * `validUntil`, and therefore keeps working with the 0.6 schema. In the
1292
- * enabled mode the repository expects both nullable columns to exist.
1293
- *
1294
- * In validity-window mode `publishDraft` opens an internal transaction when
1295
- * the caller did not provide one. This makes superseding the predecessor,
1296
- * applying its auto-succession end date and publishing the draft atomic.
1297
- * Legacy mode retains the 0.6 transaction behavior unchanged.
1298
- */
1299
- declare class PrismaBundleRepository implements BundleRepository {
1300
- private readonly prisma;
1301
- private readonly validityWindows;
1302
- /**
1303
- * Present only when validity-window mode is enabled. This mirrors the
1304
- * optional port capability and lets 0.6-schema consumers detect that an
1305
- * active-at-time lookup is unavailable.
1306
- */
1307
- readonly findActiveBundleVersion?: (bundleId: string, asOf?: Date, tx?: TransactionContext) => Promise<BundleVersionRow | null>;
1308
- constructor(prisma: BundlePrismaClient, options?: PrismaBundleRepositoryOptions);
1309
- private db;
1310
- private transaction;
1311
- list(filter: BundleListFilter): Promise<BundleRow[]>;
1312
- findById(bundleId: string): Promise<BundleRow | null>;
1313
- findByKey(projectKey: string, bundleKey: string): Promise<BundleRow | null>;
1314
- create(data: CreateBundleData): Promise<BundleRow>;
1315
- update(bundleId: string, data: UpdateBundleData): Promise<BundleRow>;
1316
- softDelete(bundleId: string): Promise<void>;
1317
- listVersions(bundleId: string): Promise<BundleVersionRow[]>;
1318
- findVersionById(versionId: string): Promise<BundleVersionRow | null>;
1319
- findCurrentDraft(bundleId: string): Promise<BundleVersionRow | null>;
1320
- findLatestLive(bundleId: string, tx?: TransactionContext): Promise<BundleVersionRow | null>;
1321
- private findActiveBundleVersionWithValidity;
1322
- createDraft(data: CreateBundleVersionDraftData): Promise<BundleVersionRow>;
1323
- updateDraft(versionId: string, data: UpdateBundleVersionDraftData): Promise<BundleVersionRow>;
1324
- publishDraft(versionId: string, publishMeta: {
1325
- publishedByUserId: string | null;
1326
- publishedChanges: VersionChange[];
1327
- nonRegressive: boolean;
1328
- validFrom: Date;
1329
- validUntil: Date | null;
1330
- }, tx?: TransactionContext): Promise<BundleVersionRow>;
1331
- private publishDraftWithValidity;
1332
- deleteDraft(versionId: string): Promise<void>;
1333
- }
1334
-
1335
1346
  interface CatalogEntryRepositoryClient {
1336
1347
  capabilityCatalogEntry: unknown;
1337
1348
  featureCatalogEntry: unknown;
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { AdminResourcesPort, AdminTenantListFilter, AdminTenantListRow, AdminTenantDetail, AdminTenantStateResult, AdminUserListFilter, AdminUserListRow, AdminAuditListFilter, AuditEntry, AdminSubscriptionListRow, PersistenceInjectionToken, PasswordHasher, SaasicatPersistenceAdapter, TransactionRunner, TransactionContext, MfaPort, AuditPort, AdminActor, AuditQueryPort, AuditQuery, AuditStatsPort, RlsBypassPort, SubscriptionRepository, SubscriptionRecord, SubscriptionUsagePort, SubscriptionUsageRecord, SubscriptionBundleRepository, SubscriptionBundleRecord, CreateSubscriptionBundleData, CancelSubscriptionBundleData, TenantSubscriptionWritePort, ApplyOnboardingSelectionInput, RedeemPromoInTransactionCallback, ApplyOnboardingSelectionResult, ImmediatePlanChangeInput, ScheduledPlanChangeInput, PlanVersionRepository, PlanVersionRecord, PromoCodeRepository, PromoCodeRecord, PromoCodeFilter, CreatePromoCodeData, UpdatePromoCodeData, PromoCodeRedemptionRepository, PromoCodeRedemptionRecord, PromoCodeRedemptionStatus, PromoCodeRedemptionListItem, PromoCodeValidationLogRepository, PromoSubscriptionLookup, BillingCycle, PromoRevenueDeductionAggregator, SuperAdminProvisioningPort, CreateSuperAdminCliInput, PlatformUserDto, PlanCatalogReadSink, PlanCatalogReadSnapshot, PlanCatalogImportSink, UpsertPlanInput, UpsertResult, UpsertPlanVersionInput, UpsertFeatureCatalogEntryInput, PlanRepository, PlanListFilter, PlanRow, CreatePlanData, UpdatePlanData, PlanVersionRow, CreatePlanVersionDraftData, UpdatePlanVersionDraftData, VersionChange, BundleRepository, BundleVersionRow, BundleListFilter, BundleRow, CreateBundleData, UpdateBundleData, CreateBundleVersionDraftData, UpdateBundleVersionDraftData, CatalogEntryRepository, CatalogEntryFilter, CapabilityCatalogEntryRow, FeatureCatalogEntryRow, QuotaCatalogEntryRow, UpsertCapabilityEntryData, UpsertFeatureEntryData, UpsertQuotaEntryData, SetCatalogEntryReviewData, CatalogEntryI18n, UpdateCatalogEntryBaseData, MarketingProjectionRepository, MarketingProjectionFilter, MarketingProjectionRow, CreateMarketingProjectionData, UpdateMarketingProjectionData, MarketingSettingsRepository, MarketingSettingsRow, UpdateMarketingSettingsData, PromotionRepository, PromotionFilter, PromotionRow, CreatePromotionData, UpdatePromotionData, SubscriptionContractRepository, SubscriptionContractFilter, SubscriptionContractRecord, CreateSubscriptionContractData, TerminateSubscriptionContractData } from '@saasicat/types';
1
+ import { AdminResourcesPort, AdminTenantListFilter, AdminTenantListRow, AdminTenantDetail, AdminTenantStateResult, AdminUserListFilter, AdminUserListRow, AdminAuditListFilter, AuditEntry, AdminSubscriptionListRow, BundleRepository, TransactionContext, BundleVersionRow, BundleListFilter, BundleRow, CreateBundleData, UpdateBundleData, CreateBundleVersionDraftData, UpdateBundleVersionDraftData, VersionChange, PersistenceInjectionToken, PasswordHasher, SaasicatPersistenceAdapter, TransactionRunner, MfaPort, AuditPort, AdminActor, AuditQueryPort, AuditQuery, AuditStatsPort, RlsBypassPort, SubscriptionRepository, SubscriptionRecord, SubscriptionUsagePort, SubscriptionUsageRecord, SubscriptionBundleRepository, SubscriptionBundleRecord, CreateSubscriptionBundleData, CancelSubscriptionBundleData, TenantSubscriptionWritePort, ApplyOnboardingSelectionInput, RedeemPromoInTransactionCallback, ApplyOnboardingSelectionResult, ImmediatePlanChangeInput, ScheduledPlanChangeInput, PlanVersionRepository, PlanVersionRecord, PromoCodeRepository, PromoCodeRecord, PromoCodeFilter, CreatePromoCodeData, UpdatePromoCodeData, PromoCodeRedemptionRepository, PromoCodeRedemptionRecord, PromoCodeRedemptionStatus, PromoCodeRedemptionListItem, PromoCodeValidationLogRepository, PromoSubscriptionLookup, BillingCycle, PromoRevenueDeductionAggregator, SuperAdminProvisioningPort, CreateSuperAdminCliInput, PlatformUserDto, PlanCatalogReadSink, PlanCatalogReadSnapshot, PlanCatalogImportSink, UpsertPlanInput, UpsertResult, UpsertPlanVersionInput, UpsertFeatureCatalogEntryInput, PlanRepository, PlanListFilter, PlanRow, CreatePlanData, UpdatePlanData, PlanVersionRow, CreatePlanVersionDraftData, UpdatePlanVersionDraftData, CatalogEntryRepository, CatalogEntryFilter, CapabilityCatalogEntryRow, FeatureCatalogEntryRow, QuotaCatalogEntryRow, UpsertCapabilityEntryData, UpsertFeatureEntryData, UpsertQuotaEntryData, SetCatalogEntryReviewData, CatalogEntryI18n, UpdateCatalogEntryBaseData, MarketingProjectionRepository, MarketingProjectionFilter, MarketingProjectionRow, CreateMarketingProjectionData, UpdateMarketingProjectionData, MarketingSettingsRepository, MarketingSettingsRow, UpdateMarketingSettingsData, PromotionRepository, PromotionFilter, PromotionRow, CreatePromotionData, UpdatePromotionData, SubscriptionContractRepository, SubscriptionContractFilter, SubscriptionContractRecord, CreateSubscriptionContractData, TerminateSubscriptionContractData } from '@saasicat/types';
2
2
 
3
3
  declare const PRISMA_CLIENT_TOKEN: unique symbol;
4
4
  /** Prisma `Decimal` values arrive as objects with `toString()`; tests may use plain values. */
@@ -736,6 +736,84 @@ declare class PrismaAdminResourcesAdapter implements AdminResourcesPort {
736
736
  private subscriptions;
737
737
  }
738
738
 
739
+ /**
740
+ * Root-client shape accepted by this repository. Delegates and `$transaction`
741
+ * stay opaque at the injection boundary because generated Prisma delegates
742
+ * have schema-specific generic signatures; calls are narrowed locally to the
743
+ * exact Bundle operations below.
744
+ */
745
+ interface BundlePrismaClient {
746
+ bundle: unknown;
747
+ bundleVersion: unknown;
748
+ $transaction: unknown;
749
+ }
750
+ /**
751
+ * Optional DI token for apps that register `PrismaBundleRepository` directly
752
+ * as a Nest provider. Factory users may pass the same options as the second
753
+ * constructor argument.
754
+ */
755
+ declare const PRISMA_BUNDLE_REPOSITORY_OPTIONS: unique symbol;
756
+ interface PrismaBundleRepositoryOptions {
757
+ /**
758
+ * Enables reads and writes of `BundleVersion.validFrom`/`validUntil`.
759
+ *
760
+ * Default `false` preserves compatibility with databases and Prisma
761
+ * clients generated from the 0.6 schema, where the columns do not exist.
762
+ */
763
+ validityWindows?: boolean;
764
+ }
765
+ /**
766
+ * `BundleRepository` against the canonical `bundles` + `bundle_versions`
767
+ * tables (SPEC_V2 §5 + §11.1 M3). Versioning mirrors `PlanVersion`: at most one
768
+ * draft (`publishedAt IS NULL`) per bundle, monotonically incrementing
769
+ * `version`, `supersededAt` marking the previous live version on publish.
770
+ *
771
+ * Validity-window support is opt-in via `{ validityWindows: true }`. The
772
+ * default deliberately does not select, read or write `validFrom`/
773
+ * `validUntil`, and therefore keeps working with the 0.6 schema. In the
774
+ * enabled mode the repository expects both nullable columns to exist.
775
+ *
776
+ * In validity-window mode `publishDraft` opens an internal transaction when
777
+ * the caller did not provide one. This makes superseding the predecessor,
778
+ * applying its auto-succession end date and publishing the draft atomic.
779
+ * Legacy mode retains the 0.6 transaction behavior unchanged.
780
+ */
781
+ declare class PrismaBundleRepository implements BundleRepository {
782
+ private readonly prisma;
783
+ private readonly validityWindows;
784
+ /**
785
+ * Present only when validity-window mode is enabled. This mirrors the
786
+ * optional port capability and lets 0.6-schema consumers detect that an
787
+ * active-at-time lookup is unavailable.
788
+ */
789
+ readonly findActiveBundleVersion?: (bundleId: string, asOf?: Date, tx?: TransactionContext) => Promise<BundleVersionRow | null>;
790
+ constructor(prisma: BundlePrismaClient, options?: PrismaBundleRepositoryOptions);
791
+ private db;
792
+ private transaction;
793
+ list(filter: BundleListFilter): Promise<BundleRow[]>;
794
+ findById(bundleId: string): Promise<BundleRow | null>;
795
+ findByKey(projectKey: string, bundleKey: string): Promise<BundleRow | null>;
796
+ create(data: CreateBundleData): Promise<BundleRow>;
797
+ update(bundleId: string, data: UpdateBundleData): Promise<BundleRow>;
798
+ softDelete(bundleId: string): Promise<void>;
799
+ listVersions(bundleId: string): Promise<BundleVersionRow[]>;
800
+ findVersionById(versionId: string): Promise<BundleVersionRow | null>;
801
+ findCurrentDraft(bundleId: string): Promise<BundleVersionRow | null>;
802
+ findLatestLive(bundleId: string, tx?: TransactionContext): Promise<BundleVersionRow | null>;
803
+ private findActiveBundleVersionWithValidity;
804
+ createDraft(data: CreateBundleVersionDraftData): Promise<BundleVersionRow>;
805
+ updateDraft(versionId: string, data: UpdateBundleVersionDraftData): Promise<BundleVersionRow>;
806
+ publishDraft(versionId: string, publishMeta: {
807
+ publishedByUserId: string | null;
808
+ publishedChanges: VersionChange[];
809
+ nonRegressive: boolean;
810
+ validFrom: Date;
811
+ validUntil: Date | null;
812
+ }, tx?: TransactionContext): Promise<BundleVersionRow>;
813
+ private publishDraftWithValidity;
814
+ deleteDraft(versionId: string): Promise<void>;
815
+ }
816
+
739
817
  interface PrismaPersistenceOptions {
740
818
  /**
741
819
  * The app's Prisma client: either its injection token (typically the
@@ -768,6 +846,17 @@ interface PrismaPersistenceOptions {
768
846
  * for schemas without conventional `tenant`/`user` delegates.
769
847
  */
770
848
  adminResources?: false | PrismaAdminResourcesOptions;
849
+ /**
850
+ * Options for the bundle repository the catalog and entitlement slices
851
+ * share — notably `{ validityWindows: true }` for schemas that carry
852
+ * `BundleVersion.validFrom`/`validUntil`.
853
+ *
854
+ * Without this the bundle builds the repository with its 0.6-compatible
855
+ * defaults, and the repository's `@Optional() @Inject(...)` options
856
+ * provider never applies, because the bundle constructs the instance
857
+ * directly rather than through Nest DI.
858
+ */
859
+ bundle?: PrismaBundleRepositoryOptions;
771
860
  }
772
861
  /**
773
862
  * Builds the `SaasicatPersistenceAdapter` bundle for Prisma + PostgreSQL on
@@ -1254,84 +1343,6 @@ declare class PrismaPlanRepository implements PlanRepository {
1254
1343
  private toPlanVersionRow;
1255
1344
  }
1256
1345
 
1257
- /**
1258
- * Root-client shape accepted by this repository. Delegates and `$transaction`
1259
- * stay opaque at the injection boundary because generated Prisma delegates
1260
- * have schema-specific generic signatures; calls are narrowed locally to the
1261
- * exact Bundle operations below.
1262
- */
1263
- interface BundlePrismaClient {
1264
- bundle: unknown;
1265
- bundleVersion: unknown;
1266
- $transaction: unknown;
1267
- }
1268
- /**
1269
- * Optional DI token for apps that register `PrismaBundleRepository` directly
1270
- * as a Nest provider. Factory users may pass the same options as the second
1271
- * constructor argument.
1272
- */
1273
- declare const PRISMA_BUNDLE_REPOSITORY_OPTIONS: unique symbol;
1274
- interface PrismaBundleRepositoryOptions {
1275
- /**
1276
- * Enables reads and writes of `BundleVersion.validFrom`/`validUntil`.
1277
- *
1278
- * Default `false` preserves compatibility with databases and Prisma
1279
- * clients generated from the 0.6 schema, where the columns do not exist.
1280
- */
1281
- validityWindows?: boolean;
1282
- }
1283
- /**
1284
- * `BundleRepository` against the canonical `bundles` + `bundle_versions`
1285
- * tables (SPEC_V2 §5 + §11.1 M3). Versioning mirrors `PlanVersion`: at most one
1286
- * draft (`publishedAt IS NULL`) per bundle, monotonically incrementing
1287
- * `version`, `supersededAt` marking the previous live version on publish.
1288
- *
1289
- * Validity-window support is opt-in via `{ validityWindows: true }`. The
1290
- * default deliberately does not select, read or write `validFrom`/
1291
- * `validUntil`, and therefore keeps working with the 0.6 schema. In the
1292
- * enabled mode the repository expects both nullable columns to exist.
1293
- *
1294
- * In validity-window mode `publishDraft` opens an internal transaction when
1295
- * the caller did not provide one. This makes superseding the predecessor,
1296
- * applying its auto-succession end date and publishing the draft atomic.
1297
- * Legacy mode retains the 0.6 transaction behavior unchanged.
1298
- */
1299
- declare class PrismaBundleRepository implements BundleRepository {
1300
- private readonly prisma;
1301
- private readonly validityWindows;
1302
- /**
1303
- * Present only when validity-window mode is enabled. This mirrors the
1304
- * optional port capability and lets 0.6-schema consumers detect that an
1305
- * active-at-time lookup is unavailable.
1306
- */
1307
- readonly findActiveBundleVersion?: (bundleId: string, asOf?: Date, tx?: TransactionContext) => Promise<BundleVersionRow | null>;
1308
- constructor(prisma: BundlePrismaClient, options?: PrismaBundleRepositoryOptions);
1309
- private db;
1310
- private transaction;
1311
- list(filter: BundleListFilter): Promise<BundleRow[]>;
1312
- findById(bundleId: string): Promise<BundleRow | null>;
1313
- findByKey(projectKey: string, bundleKey: string): Promise<BundleRow | null>;
1314
- create(data: CreateBundleData): Promise<BundleRow>;
1315
- update(bundleId: string, data: UpdateBundleData): Promise<BundleRow>;
1316
- softDelete(bundleId: string): Promise<void>;
1317
- listVersions(bundleId: string): Promise<BundleVersionRow[]>;
1318
- findVersionById(versionId: string): Promise<BundleVersionRow | null>;
1319
- findCurrentDraft(bundleId: string): Promise<BundleVersionRow | null>;
1320
- findLatestLive(bundleId: string, tx?: TransactionContext): Promise<BundleVersionRow | null>;
1321
- private findActiveBundleVersionWithValidity;
1322
- createDraft(data: CreateBundleVersionDraftData): Promise<BundleVersionRow>;
1323
- updateDraft(versionId: string, data: UpdateBundleVersionDraftData): Promise<BundleVersionRow>;
1324
- publishDraft(versionId: string, publishMeta: {
1325
- publishedByUserId: string | null;
1326
- publishedChanges: VersionChange[];
1327
- nonRegressive: boolean;
1328
- validFrom: Date;
1329
- validUntil: Date | null;
1330
- }, tx?: TransactionContext): Promise<BundleVersionRow>;
1331
- private publishDraftWithValidity;
1332
- deleteDraft(versionId: string): Promise<void>;
1333
- }
1334
-
1335
1346
  interface CatalogEntryRepositoryClient {
1336
1347
  capabilityCatalogEntry: unknown;
1337
1348
  featureCatalogEntry: unknown;
package/dist/index.js CHANGED
@@ -2180,9 +2180,14 @@ var PrismaPlanCatalogReadSink = class {
2180
2180
  projectKey,
2181
2181
  deletedAt: null
2182
2182
  },
2183
- orderBy: {
2184
- sortOrder: "asc"
2185
- }
2183
+ orderBy: [
2184
+ {
2185
+ sortOrder: "asc"
2186
+ },
2187
+ {
2188
+ planKey: "asc"
2189
+ }
2190
+ ]
2186
2191
  });
2187
2192
  const planKeysByStoredId = new Map(plans.map((plan) => [
2188
2193
  this.binding.mode === "normalized-plan-id" ? plan.id : plan.planKey,
@@ -2200,16 +2205,29 @@ var PrismaPlanCatalogReadSink = class {
2200
2205
  not: null
2201
2206
  },
2202
2207
  supersededAt: null
2203
- }
2208
+ },
2209
+ orderBy: [
2210
+ {
2211
+ planId: "asc"
2212
+ },
2213
+ {
2214
+ version: "asc"
2215
+ }
2216
+ ]
2204
2217
  });
2205
2218
  const featureEntries = await db.featureCatalogEntry.findMany({
2206
2219
  where: {
2207
2220
  projectKey,
2208
2221
  deletedAt: null
2209
2222
  },
2210
- orderBy: {
2211
- sortOrder: "asc"
2212
- }
2223
+ orderBy: [
2224
+ {
2225
+ sortOrder: "asc"
2226
+ },
2227
+ {
2228
+ featureKey: "asc"
2229
+ }
2230
+ ]
2213
2231
  });
2214
2232
  return {
2215
2233
  plans: plans.map(toPlanRow),
@@ -4835,11 +4853,11 @@ function prismaPersistence(options) {
4835
4853
  planVersionRepository: provide((prisma) => new PrismaPlanVersionRepository(prisma, options.schema)),
4836
4854
  subscriptionContractRepository: provide((prisma) => new PrismaSubscriptionContractRepository(prisma)),
4837
4855
  subscriptionBundleRepository: provide((prisma) => new PrismaSubscriptionBundleRepository(canonical(prisma))),
4838
- bundleRepository: provide((prisma) => new PrismaBundleRepository(canonical(prisma)))
4856
+ bundleRepository: provide((prisma) => new PrismaBundleRepository(canonical(prisma), options.bundle))
4839
4857
  },
4840
4858
  catalog: {
4841
4859
  planRepository: provide((prisma) => new PrismaPlanRepository(prisma, options.schema)),
4842
- bundleRepository: provide((prisma) => new PrismaBundleRepository(canonical(prisma))),
4860
+ bundleRepository: provide((prisma) => new PrismaBundleRepository(canonical(prisma), options.bundle)),
4843
4861
  catalogEntryRepository: provide((prisma) => new PrismaCatalogEntryRepository(canonical(prisma))),
4844
4862
  marketingProjectionRepository: provide((prisma) => new PrismaMarketingProjectionRepository(canonical(prisma))),
4845
4863
  promotionRepository: provide((prisma) => new PrismaPromotionRepository(canonical(prisma))),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@saasicat/adapter-prisma",
3
- "version": "0.9.0",
3
+ "version": "0.10.1",
4
4
  "description": "Prisma + PostgreSQL persistence for SaaSiCat: one standard bundle for core, catalog, entitlement, tenant billing, Admin resources and promo, plus individual adapters for custom compositions.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -22,7 +22,7 @@
22
22
  "dist"
23
23
  ],
24
24
  "dependencies": {
25
- "@saasicat/types": "^0.9.0"
25
+ "@saasicat/types": "^0.10.1"
26
26
  },
27
27
  "peerDependencies": {
28
28
  "@nestjs/common": "^11.0.0"
@@ -34,8 +34,8 @@
34
34
  "@prisma/client": "^6.19.0",
35
35
  "tsup": "^8.0.0",
36
36
  "typescript": "^6.0.0",
37
- "@saasicat/persistence-testing": "^0.9.0",
38
- "@saasicat/spec": "^0.9.0"
37
+ "@saasicat/persistence-testing": "^0.10.1",
38
+ "@saasicat/spec": "^0.10.1"
39
39
  },
40
40
  "license": "Apache-2.0",
41
41
  "author": "Taci Uelker",