@saasicat/adapter-prisma 0.4.0 → 0.6.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.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { PersistenceInjectionToken, PasswordHasher, SaasicatPersistenceAdapter, TransactionRunner, TransactionContext, MfaPort, AuditPort, AdminActor, AuditQueryPort, AuditQuery, AuditEntry, AuditStatsPort, RlsBypassPort, SubscriptionRepository, SubscriptionRecord, 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 } from '@saasicat/types';
1
+ import { PersistenceInjectionToken, PasswordHasher, SaasicatPersistenceAdapter, TransactionRunner, TransactionContext, MfaPort, AuditPort, AdminActor, AuditQueryPort, AuditQuery, AuditEntry, AuditStatsPort, RlsBypassPort, SubscriptionRepository, SubscriptionRecord, SubscriptionBundleRepository, SubscriptionBundleRecord, CreateSubscriptionBundleData, CancelSubscriptionBundleData, TenantSubscriptionWritePort, 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, BundleListFilter, BundleRow, CreateBundleData, UpdateBundleData, BundleVersionRow, 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';
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. */
@@ -16,7 +16,7 @@ interface SubscriptionRowLike {
16
16
  pendingPlan: string | null;
17
17
  pendingEffectiveAt: Date | null;
18
18
  customLimits: unknown;
19
- planVersionId: string | null;
19
+ planVersionId: string;
20
20
  pendingPlanVersionId: string | null;
21
21
  startedAt: Date | null;
22
22
  }
@@ -547,6 +547,36 @@ interface PrismaTxLike {
547
547
  interface PrismaLike extends PrismaTxLike {
548
548
  $transaction<T>(fn: (tx: PrismaTxLike) => Promise<T>): Promise<T>;
549
549
  }
550
+ /**
551
+ * Generic structural minimum of a Prisma model delegate. The catalog-plane
552
+ * repositories (bundle, plan, catalog-entry, marketing,
553
+ * promotion, contract) declare their own DB-row interfaces and view the
554
+ * injected client through `{ model: PrismaModelDelegateLike<Row> }` casts —
555
+ * this keeps each repo self-contained and avoids hard-coding every delegate on
556
+ * `PrismaTxLike`. Args mirror Prisma's `where`/`data`/`select`/`orderBy` shapes
557
+ * and are typed `unknown`: the repos build them inline and Prisma validates
558
+ * them at runtime; only the results are typed, matching the package's
559
+ * structural-minimum philosophy.
560
+ */
561
+ interface PrismaModelDelegateLike<Row> {
562
+ findMany(args?: unknown): Promise<Row[]>;
563
+ findUnique(args: unknown): Promise<Row | null>;
564
+ findFirst(args?: unknown): Promise<Row | null>;
565
+ create(args: unknown): Promise<Row>;
566
+ update(args: unknown): Promise<Row>;
567
+ delete(args: unknown): Promise<Row>;
568
+ upsert(args: unknown): Promise<Row>;
569
+ updateMany(args: unknown): Promise<{
570
+ count: number;
571
+ }>;
572
+ createMany(args: unknown): Promise<{
573
+ count: number;
574
+ }>;
575
+ deleteMany(args: unknown): Promise<{
576
+ count: number;
577
+ }>;
578
+ count(args?: unknown): Promise<number>;
579
+ }
550
580
 
551
581
  interface PrismaPersistenceOptions {
552
582
  /**
@@ -581,9 +611,14 @@ interface PrismaPersistenceOptions {
581
611
  * });
582
612
  * ```
583
613
  *
584
- * Slices not shipped by this adapter (contracts, bundles, registration,
585
- * tenant-billing write ports) stay absent consumers keep providing custom
586
- * adapters for those features.
614
+ * This bundle covers the core/entitlement/promo/plan-catalog slices consumed
615
+ * by `SaasPlatformModule`. The catalog plane (CatalogModule) and the V3
616
+ * contract loop take their repositories directly as `forRoot` options — wire
617
+ * the standalone `PrismaPlanRepository` / `PrismaBundleRepository` /
618
+ * `PrismaCatalogEntryRepository` /
619
+ * `PrismaMarketingProjectionRepository` / `PrismaMarketingSettingsRepository` /
620
+ * `PrismaPromotionRepository` / `PrismaSubscriptionContractRepository` exports
621
+ * there. The registration and tenant-billing write ports remain app-specific.
587
622
  */
588
623
  declare function prismaPersistence(options: PrismaPersistenceOptions): SaasicatPersistenceAdapter;
589
624
 
@@ -696,11 +731,6 @@ declare class AsyncLocalRlsBypassAdapter implements RlsBypassPort {
696
731
  * `SubscriptionRepository` against the canonical `subscriptions` +
697
732
  * `plan_versions` tables.
698
733
  *
699
- * Limitation: subscriptions that bind ONLY a `businessTypeVersionId` (no
700
- * `planVersionId`) are not supported by this shipped adapter — the
701
- * BusinessType composition needs app-specific aggregation. Such rows raise a
702
- * descriptive error instead of returning wrong entitlements.
703
- *
704
734
  * `countByBundleVersionId` is deliberately not implemented (the
705
735
  * `subscription_bundles` junction is not part of this adapter's slice);
706
736
  * the platform then treats affected bundle versions as frozen (fail-closed).
@@ -716,6 +746,58 @@ declare class PrismaSubscriptionRepository implements SubscriptionRepository {
716
746
  private toRecord;
717
747
  }
718
748
 
749
+ /**
750
+ * `SubscriptionBundleRepository` against the canonical `subscription_bundles`
751
+ * junction (SPEC_V2 §11.1 M6 Pack 2e). Dumb persistence: domain constraints
752
+ * (plan compatibility, minimum-term default, cancellation-window computation)
753
+ * live in the platform's `SubscriptionBundlesService`; `add`/`cancel` here only
754
+ * write what they are handed. "Active" is `canceledAt IS NULL OR
755
+ * canceledEffectiveAt > asOf`, mirroring the port contract.
756
+ */
757
+ declare class PrismaSubscriptionBundleRepository implements SubscriptionBundleRepository {
758
+ private readonly prisma;
759
+ constructor(prisma: PrismaLike);
760
+ private db;
761
+ listBySubscription(subscriptionId: string): Promise<SubscriptionBundleRecord[]>;
762
+ findById(subscriptionBundleId: string): Promise<SubscriptionBundleRecord | null>;
763
+ listActiveBySubscription(subscriptionId: string, asOf?: Date): Promise<SubscriptionBundleRecord[]>;
764
+ add(data: CreateSubscriptionBundleData): Promise<SubscriptionBundleRecord>;
765
+ cancel(subscriptionBundleId: string, data: CancelSubscriptionBundleData): Promise<SubscriptionBundleRecord>;
766
+ reactivate(subscriptionBundleId: string): Promise<SubscriptionBundleRecord>;
767
+ countActiveByBundleVersionId(bundleVersionId: string, asOf?: Date): Promise<number>;
768
+ }
769
+
770
+ /**
771
+ * `TenantSubscriptionWritePort` against the canonical `subscriptions` table.
772
+ * Pure persistence: trial carry-over (#17) and contract freeze (#18) are
773
+ * resolved in the platform `changePlan` path and handed down as plain values —
774
+ * this adapter only writes what it receives.
775
+ *
776
+ * The optional `applyOnboardingSelection` is not implemented; the platform
777
+ * service then falls back to sequential `changePlanImmediate` + promo redeem
778
+ * (best-effort, port contract P10.1.1).
779
+ */
780
+ declare class PrismaTenantSubscriptionWriteAdapter implements TenantSubscriptionWritePort {
781
+ private readonly prisma;
782
+ constructor(prisma: PrismaLike);
783
+ private db;
784
+ changePlanImmediate(tenantId: string, input: ImmediatePlanChangeInput): Promise<{
785
+ plan: string;
786
+ billingCycle: string;
787
+ }>;
788
+ schedulePlanChange(tenantId: string, input: ScheduledPlanChangeInput): Promise<void>;
789
+ acceptPendingPlanVersion(tenantId: string, userId: string, now: Date): Promise<{
790
+ accepted: boolean;
791
+ acceptedAt: Date | null;
792
+ effectiveAt: Date | null;
793
+ alreadyAccepted: boolean;
794
+ }>;
795
+ cancelSubscription(tenantId: string, immediate: boolean, now: Date): Promise<{
796
+ canceledAt: Date | null;
797
+ status: string;
798
+ }>;
799
+ }
800
+
719
801
  /**
720
802
  * `PlanVersionRepository` against the canonical `plan_versions` table.
721
803
  *
@@ -856,4 +938,198 @@ declare class PrismaPlanCatalogImportSink implements PlanCatalogImportSink {
856
938
  upsertFeatureCatalogEntry(input: UpsertFeatureCatalogEntryInput): Promise<UpsertResult>;
857
939
  }
858
940
 
859
- export { AsyncLocalRlsBypassAdapter, type DecimalLike, PASSWORD_HASHER_TOKEN, PRISMA_CLIENT_TOKEN, PrismaAuditAdapter, PrismaAuditQueryAdapter, PrismaAuditStatsAdapter, type PrismaLike, PrismaMfaAdapter, type PrismaPersistenceOptions, PrismaPlanCatalogImportSink, PrismaPlanCatalogReadSink, PrismaPlanVersionRepository, PrismaPromoCodeRedemptionRepository, PrismaPromoCodeRepository, PrismaPromoCodeValidationLogRepository, PrismaPromoSubscriptionLookup, PrismaSubscriptionRepository, PrismaSuperAdminBootstrapAdapter, PrismaTransactionRunner, type PrismaTxLike, ZeroPromoRevenueDeductionAggregator, buildActorTag, prismaPersistence };
941
+ /**
942
+ * `PlanRepository` against the canonical `plans` + `plan_versions` tables
943
+ * (SPEC_V2 §11.1 M6). Plan stem CRUD (Pack 1) and PlanVersion lifecycle
944
+ * (Pack 2a) live in one adapter; the soft binding is
945
+ * `PlanVersion.planId === Plan.planKey`, so the lifecycle methods take the
946
+ * **planKey**, not the plan UUID.
947
+ *
948
+ * Schema limitation: the canonical `plan_versions` fragment
949
+ * (03-plan-versions.prisma) intentionally has no validity-window columns
950
+ * (`validFrom`/`validUntil`) and no `endsAt` column — it carries a generic
951
+ * `quotas Json` instead of fixed quota columns. Consequences:
952
+ * - Every `PlanVersionRow.validFrom`/`validUntil` maps to `null`.
953
+ * - `publishPlanVersionDraft` persists only the publish/supersede state; the
954
+ * `validFrom`/`validUntil` in `publishMeta` cannot be stored, so
955
+ * auto-succession reduces to setting `supersededAt` on the previous live version.
956
+ * - `findActivePlanVersion` (validity-window read) and `terminate` (endsAt)
957
+ * throw, because their contract depends on columns this schema does not have.
958
+ * Consumers that need them provide a custom adapter on an extended schema.
959
+ */
960
+ declare class PrismaPlanRepository implements PlanRepository {
961
+ private readonly prisma;
962
+ constructor(prisma: PrismaLike);
963
+ private db;
964
+ list(filter: PlanListFilter): Promise<PlanRow[]>;
965
+ findById(planId: string): Promise<PlanRow | null>;
966
+ findByKey(projectKey: string, planKey: string): Promise<PlanRow | null>;
967
+ create(data: CreatePlanData): Promise<PlanRow>;
968
+ update(planId: string, data: UpdatePlanData): Promise<PlanRow>;
969
+ softDelete(planId: string): Promise<void>;
970
+ hardDelete(planId: string): Promise<void>;
971
+ listVersions(planKey: string): Promise<PlanVersionRow[]>;
972
+ findVersionById(versionId: string): Promise<PlanVersionRow | null>;
973
+ findCurrentDraft(planKey: string): Promise<PlanVersionRow | null>;
974
+ findLatestLivePlanVersion(planKey: string, tx?: TransactionContext): Promise<PlanVersionRow | null>;
975
+ findActivePlanVersion(): Promise<PlanVersionRow | null>;
976
+ createPlanVersionDraft(data: CreatePlanVersionDraftData): Promise<PlanVersionRow>;
977
+ updatePlanVersionDraft(versionId: string, data: UpdatePlanVersionDraftData): Promise<PlanVersionRow>;
978
+ publishPlanVersionDraft(versionId: string, publishMeta: {
979
+ publishedByUserId: string | null;
980
+ publishedChanges: VersionChange[];
981
+ nonRegressive: boolean;
982
+ validFrom: Date;
983
+ validUntil: Date | null;
984
+ }, tx?: TransactionContext): Promise<PlanVersionRow>;
985
+ deletePlanVersionDraft(versionId: string): Promise<void>;
986
+ terminate(): Promise<PlanVersionRow>;
987
+ }
988
+
989
+ /**
990
+ * `BundleRepository` against the canonical `bundles` + `bundle_versions`
991
+ * tables (SPEC_V2 §5 + §11.1 M3). Versioning mirrors `PlanVersion`: at most one
992
+ * draft (`publishedAt IS NULL`) per bundle, monotonically incrementing
993
+ * `version`, `supersededAt` marking the previous live version on publish.
994
+ *
995
+ * Divergence from time-aware consumer schemas: the canonical `bundle_versions`
996
+ * table carries **no** `validFrom`/`validUntil` columns. The `BundleVersionRow`
997
+ * therefore always reports both as `null`, and the `validFrom`/`validUntil`
998
+ * inputs on the Create/Update DTOs and on `publishDraft`'s `publishMeta` are
999
+ * accepted (to satisfy the port signature) but not persisted — consistent with
1000
+ * `PrismaPlanVersionRepository`, which documents the same schema gap.
1001
+ *
1002
+ * Atomicity of `publishDraft` (supersede-previous + publish-draft) is delegated
1003
+ * to the caller's `TransactionContext`, following the package convention that
1004
+ * repositories never open their own `$transaction`.
1005
+ */
1006
+ declare class PrismaBundleRepository implements BundleRepository {
1007
+ private readonly prisma;
1008
+ constructor(prisma: PrismaLike);
1009
+ private db;
1010
+ list(filter: BundleListFilter): Promise<BundleRow[]>;
1011
+ findById(bundleId: string): Promise<BundleRow | null>;
1012
+ findByKey(projectKey: string, bundleKey: string): Promise<BundleRow | null>;
1013
+ create(data: CreateBundleData): Promise<BundleRow>;
1014
+ update(bundleId: string, data: UpdateBundleData): Promise<BundleRow>;
1015
+ softDelete(bundleId: string): Promise<void>;
1016
+ listVersions(bundleId: string): Promise<BundleVersionRow[]>;
1017
+ findVersionById(versionId: string): Promise<BundleVersionRow | null>;
1018
+ findCurrentDraft(bundleId: string): Promise<BundleVersionRow | null>;
1019
+ findLatestLive(bundleId: string, tx?: TransactionContext): Promise<BundleVersionRow | null>;
1020
+ createDraft(data: CreateBundleVersionDraftData): Promise<BundleVersionRow>;
1021
+ updateDraft(versionId: string, data: UpdateBundleVersionDraftData): Promise<BundleVersionRow>;
1022
+ publishDraft(versionId: string, publishMeta: {
1023
+ publishedByUserId: string | null;
1024
+ publishedChanges: VersionChange[];
1025
+ nonRegressive: boolean;
1026
+ validFrom: Date;
1027
+ validUntil: Date | null;
1028
+ }, tx?: TransactionContext): Promise<BundleVersionRow>;
1029
+ deleteDraft(versionId: string): Promise<void>;
1030
+ }
1031
+
1032
+ /**
1033
+ * `CatalogEntryRepository` against the canonical `capability_catalog_entries`,
1034
+ * `feature_catalog_entries` and `quota_catalog_entries` tables (SPEC_V2 §6.3 —
1035
+ * discovery review workflow).
1036
+ *
1037
+ * `upsert*` writes only the code-derived fields + the service-resolved status
1038
+ * and leaves `i18n`, `sortOrder`, `createdAt` and the approval fields untouched
1039
+ * on update (Prisma's `update` payload simply omits them). `retireMissing`
1040
+ * marks entries whose key vanished from the code snapshot.
1041
+ */
1042
+ declare class PrismaCatalogEntryRepository implements CatalogEntryRepository {
1043
+ private readonly prisma;
1044
+ constructor(prisma: PrismaLike);
1045
+ private get db();
1046
+ listCapabilities(filter: CatalogEntryFilter): Promise<CapabilityCatalogEntryRow[]>;
1047
+ listFeatures(filter: CatalogEntryFilter): Promise<FeatureCatalogEntryRow[]>;
1048
+ listQuotas(filter: CatalogEntryFilter): Promise<QuotaCatalogEntryRow[]>;
1049
+ upsertCapability(data: UpsertCapabilityEntryData): Promise<CapabilityCatalogEntryRow>;
1050
+ upsertFeature(data: UpsertFeatureEntryData): Promise<FeatureCatalogEntryRow>;
1051
+ upsertQuota(data: UpsertQuotaEntryData): Promise<QuotaCatalogEntryRow>;
1052
+ retireMissing(projectKey: string, type: 'capability' | 'feature' | 'quota', presentKeys: string[]): Promise<number>;
1053
+ setFeatureSuccessor(projectKey: string, featureKey: string, successorKey: string | null): Promise<FeatureCatalogEntryRow>;
1054
+ setQuotaSuccessor(projectKey: string, quotaKey: string, successorKey: string | null): Promise<QuotaCatalogEntryRow>;
1055
+ findFeature(projectKey: string, featureKey: string): Promise<FeatureCatalogEntryRow | null>;
1056
+ findQuota(projectKey: string, quotaKey: string): Promise<QuotaCatalogEntryRow | null>;
1057
+ setFeatureReview(projectKey: string, featureKey: string, data: SetCatalogEntryReviewData): Promise<FeatureCatalogEntryRow>;
1058
+ setQuotaReview(projectKey: string, quotaKey: string, data: SetCatalogEntryReviewData): Promise<QuotaCatalogEntryRow>;
1059
+ setFeatureI18n(projectKey: string, featureKey: string, i18n: CatalogEntryI18n): Promise<FeatureCatalogEntryRow>;
1060
+ setQuotaI18n(projectKey: string, quotaKey: string, i18n: CatalogEntryI18n): Promise<QuotaCatalogEntryRow>;
1061
+ setFeatureBase(projectKey: string, featureKey: string, data: UpdateCatalogEntryBaseData): Promise<FeatureCatalogEntryRow>;
1062
+ setQuotaBase(projectKey: string, quotaKey: string, data: UpdateCatalogEntryBaseData): Promise<QuotaCatalogEntryRow>;
1063
+ }
1064
+
1065
+ /**
1066
+ * `MarketingProjectionRepository` against the canonical `marketing_projections`
1067
+ * table. Not versioned: per (`targetType`, `targetVersionId`, `locale`) there is
1068
+ * exactly one row (enforced by a unique index), edited directly. `create` on a
1069
+ * duplicate triple therefore raises the DB unique-constraint error.
1070
+ */
1071
+ declare class PrismaMarketingProjectionRepository implements MarketingProjectionRepository {
1072
+ private readonly prisma;
1073
+ constructor(prisma: PrismaLike);
1074
+ private get db();
1075
+ list(filter: MarketingProjectionFilter): Promise<MarketingProjectionRow[]>;
1076
+ findById(id: string): Promise<MarketingProjectionRow | null>;
1077
+ findByTarget(targetType: string, targetVersionId: string, locale: string): Promise<MarketingProjectionRow | null>;
1078
+ create(data: CreateMarketingProjectionData): Promise<MarketingProjectionRow>;
1079
+ update(id: string, data: UpdateMarketingProjectionData): Promise<MarketingProjectionRow>;
1080
+ delete(id: string): Promise<void>;
1081
+ }
1082
+
1083
+ /**
1084
+ * `MarketingSettingsRepository` against the canonical `marketing_settings`
1085
+ * table (one row per project). A missing row means "full locale pool active",
1086
+ * so `get` returns null and the platform falls back to the pool.
1087
+ */
1088
+ declare class PrismaMarketingSettingsRepository implements MarketingSettingsRepository {
1089
+ private readonly prisma;
1090
+ constructor(prisma: PrismaLike);
1091
+ private get db();
1092
+ get(projectKey: string): Promise<MarketingSettingsRow | null>;
1093
+ upsert(projectKey: string, data: UpdateMarketingSettingsData): Promise<MarketingSettingsRow>;
1094
+ }
1095
+
1096
+ /**
1097
+ * `PromotionRepository` against the canonical `promotions` table. Not
1098
+ * versioned: promotions are edited directly.
1099
+ *
1100
+ * The nullable `onlyLocales` JSON column cannot be set to null through Prisma's
1101
+ * query API without the `Prisma.DbNull` sentinel — which this Prisma-agnostic
1102
+ * package deliberately does not import. On `create` a null restriction is
1103
+ * therefore written by omission (the column defaults to SQL NULL); on `update`
1104
+ * an explicit null clear runs as a raw statement.
1105
+ */
1106
+ declare class PrismaPromotionRepository implements PromotionRepository {
1107
+ private readonly prisma;
1108
+ constructor(prisma: PrismaLike);
1109
+ private get db();
1110
+ list(filter: PromotionFilter): Promise<PromotionRow[]>;
1111
+ findById(id: string): Promise<PromotionRow | null>;
1112
+ create(data: CreatePromotionData): Promise<PromotionRow>;
1113
+ update(id: string, data: UpdatePromotionData): Promise<PromotionRow>;
1114
+ delete(id: string): Promise<void>;
1115
+ }
1116
+
1117
+ /**
1118
+ * Append-only `SubscriptionContractRepository` against the canonical
1119
+ * `subscription_contracts` + `contract_line_items` tables. Contracts store full
1120
+ * snapshots and are never rewritten: `create` writes the contract and its line
1121
+ * items atomically via a single nested-create, and `terminate` only closes a
1122
+ * contract (sets `effectiveUntil` + `status`). There is no line-item mutation.
1123
+ */
1124
+ declare class PrismaSubscriptionContractRepository implements SubscriptionContractRepository {
1125
+ private readonly prisma;
1126
+ constructor(prisma: PrismaLike);
1127
+ private get db();
1128
+ list(filter: SubscriptionContractFilter): Promise<SubscriptionContractRecord[]>;
1129
+ findById(contractId: string): Promise<SubscriptionContractRecord | null>;
1130
+ findActiveByTenantId(tenantId: string, asOf?: Date): Promise<SubscriptionContractRecord | null>;
1131
+ create(data: CreateSubscriptionContractData): Promise<SubscriptionContractRecord>;
1132
+ terminate(contractId: string, data: TerminateSubscriptionContractData): Promise<SubscriptionContractRecord>;
1133
+ }
1134
+
1135
+ export { AsyncLocalRlsBypassAdapter, type DecimalLike, PASSWORD_HASHER_TOKEN, PRISMA_CLIENT_TOKEN, PrismaAuditAdapter, PrismaAuditQueryAdapter, PrismaAuditStatsAdapter, PrismaBundleRepository, PrismaCatalogEntryRepository, type PrismaLike, PrismaMarketingProjectionRepository, PrismaMarketingSettingsRepository, PrismaMfaAdapter, type PrismaModelDelegateLike, type PrismaPersistenceOptions, PrismaPlanCatalogImportSink, PrismaPlanCatalogReadSink, PrismaPlanRepository, PrismaPlanVersionRepository, PrismaPromoCodeRedemptionRepository, PrismaPromoCodeRepository, PrismaPromoCodeValidationLogRepository, PrismaPromoSubscriptionLookup, PrismaPromotionRepository, PrismaSubscriptionBundleRepository, PrismaSubscriptionContractRepository, PrismaSubscriptionRepository, PrismaSuperAdminBootstrapAdapter, PrismaTenantSubscriptionWriteAdapter, PrismaTransactionRunner, type PrismaTxLike, ZeroPromoRevenueDeductionAggregator, buildActorTag, prismaPersistence };