@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.js CHANGED
@@ -1160,9 +1160,6 @@ var PrismaSubscriptionRepository = class {
1160
1160
  return this.toRecord(db, row);
1161
1161
  }
1162
1162
  async toRecord(db, row) {
1163
- if (!row.planVersionId) {
1164
- 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.`);
1165
- }
1166
1163
  const planVersion = await db.planVersion.findUnique({
1167
1164
  where: {
1168
1165
  id: row.planVersionId
@@ -1417,6 +1414,2259 @@ function buildProvisioning(client, hasher) {
1417
1414
  return new PrismaSuperAdminBootstrapAdapter(client, hasher);
1418
1415
  }
1419
1416
  __name(buildProvisioning, "buildProvisioning");
1417
+
1418
+ // src/prisma-subscription-bundle.repository.ts
1419
+ import { Inject as Inject15, Injectable as Injectable17 } from "@nestjs/common";
1420
+ function _ts_decorate17(decorators, target, key, desc) {
1421
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1422
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
1423
+ 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;
1424
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
1425
+ }
1426
+ __name(_ts_decorate17, "_ts_decorate");
1427
+ function _ts_metadata15(k, v) {
1428
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
1429
+ }
1430
+ __name(_ts_metadata15, "_ts_metadata");
1431
+ function _ts_param15(paramIndex, decorator) {
1432
+ return function(target, key) {
1433
+ decorator(target, key, paramIndex);
1434
+ };
1435
+ }
1436
+ __name(_ts_param15, "_ts_param");
1437
+ var PrismaSubscriptionBundleRepository = class {
1438
+ static {
1439
+ __name(this, "PrismaSubscriptionBundleRepository");
1440
+ }
1441
+ prisma;
1442
+ constructor(prisma) {
1443
+ this.prisma = prisma;
1444
+ }
1445
+ db(tx) {
1446
+ return resolveClient(this.prisma, tx);
1447
+ }
1448
+ async listBySubscription(subscriptionId) {
1449
+ const rows = await this.db().subscriptionBundle.findMany({
1450
+ where: {
1451
+ subscriptionId
1452
+ },
1453
+ orderBy: {
1454
+ startedAt: "desc"
1455
+ }
1456
+ });
1457
+ return rows.map(toRecord3);
1458
+ }
1459
+ async findById(subscriptionBundleId) {
1460
+ const row = await this.db().subscriptionBundle.findUnique({
1461
+ where: {
1462
+ id: subscriptionBundleId
1463
+ }
1464
+ });
1465
+ return row ? toRecord3(row) : null;
1466
+ }
1467
+ async listActiveBySubscription(subscriptionId, asOf = /* @__PURE__ */ new Date()) {
1468
+ const rows = await this.db().subscriptionBundle.findMany({
1469
+ where: {
1470
+ subscriptionId,
1471
+ OR: [
1472
+ {
1473
+ canceledAt: null
1474
+ },
1475
+ {
1476
+ canceledEffectiveAt: {
1477
+ gt: asOf
1478
+ }
1479
+ }
1480
+ ]
1481
+ },
1482
+ orderBy: {
1483
+ startedAt: "desc"
1484
+ }
1485
+ });
1486
+ return rows.map(toRecord3);
1487
+ }
1488
+ async add(data) {
1489
+ const row = await this.db().subscriptionBundle.create({
1490
+ data: {
1491
+ subscriptionId: data.subscriptionId,
1492
+ bundleVersionId: data.bundleVersionId,
1493
+ startedAt: data.startedAt,
1494
+ minimumTermEndsAt: data.minimumTermEndsAt ?? null
1495
+ }
1496
+ });
1497
+ return toRecord3(row);
1498
+ }
1499
+ async cancel(subscriptionBundleId, data) {
1500
+ const row = await this.db().subscriptionBundle.update({
1501
+ where: {
1502
+ id: subscriptionBundleId
1503
+ },
1504
+ data: {
1505
+ canceledAt: data.canceledAt,
1506
+ canceledEffectiveAt: data.canceledEffectiveAt
1507
+ }
1508
+ });
1509
+ return toRecord3(row);
1510
+ }
1511
+ async reactivate(subscriptionBundleId) {
1512
+ const row = await this.db().subscriptionBundle.update({
1513
+ where: {
1514
+ id: subscriptionBundleId
1515
+ },
1516
+ data: {
1517
+ canceledAt: null,
1518
+ canceledEffectiveAt: null
1519
+ }
1520
+ });
1521
+ return toRecord3(row);
1522
+ }
1523
+ async countActiveByBundleVersionId(bundleVersionId, asOf = /* @__PURE__ */ new Date()) {
1524
+ return this.db().subscriptionBundle.count({
1525
+ where: {
1526
+ bundleVersionId,
1527
+ OR: [
1528
+ {
1529
+ canceledAt: null
1530
+ },
1531
+ {
1532
+ canceledEffectiveAt: {
1533
+ gt: asOf
1534
+ }
1535
+ }
1536
+ ]
1537
+ }
1538
+ });
1539
+ }
1540
+ };
1541
+ PrismaSubscriptionBundleRepository = _ts_decorate17([
1542
+ Injectable17(),
1543
+ _ts_param15(0, Inject15(PRISMA_CLIENT_TOKEN)),
1544
+ _ts_metadata15("design:type", Function),
1545
+ _ts_metadata15("design:paramtypes", [
1546
+ typeof PrismaLike === "undefined" ? Object : PrismaLike
1547
+ ])
1548
+ ], PrismaSubscriptionBundleRepository);
1549
+ function toRecord3(row) {
1550
+ return {
1551
+ id: row.id,
1552
+ subscriptionId: row.subscriptionId,
1553
+ bundleVersionId: row.bundleVersionId,
1554
+ startedAt: row.startedAt,
1555
+ minimumTermEndsAt: row.minimumTermEndsAt,
1556
+ canceledAt: row.canceledAt,
1557
+ canceledEffectiveAt: row.canceledEffectiveAt,
1558
+ createdAt: row.createdAt,
1559
+ updatedAt: row.updatedAt
1560
+ };
1561
+ }
1562
+ __name(toRecord3, "toRecord");
1563
+
1564
+ // src/prisma-tenant-subscription-write.adapter.ts
1565
+ import { Inject as Inject16, Injectable as Injectable18 } from "@nestjs/common";
1566
+ function _ts_decorate18(decorators, target, key, desc) {
1567
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1568
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
1569
+ 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;
1570
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
1571
+ }
1572
+ __name(_ts_decorate18, "_ts_decorate");
1573
+ function _ts_metadata16(k, v) {
1574
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
1575
+ }
1576
+ __name(_ts_metadata16, "_ts_metadata");
1577
+ function _ts_param16(paramIndex, decorator) {
1578
+ return function(target, key) {
1579
+ decorator(target, key, paramIndex);
1580
+ };
1581
+ }
1582
+ __name(_ts_param16, "_ts_param");
1583
+ var PrismaTenantSubscriptionWriteAdapter = class {
1584
+ static {
1585
+ __name(this, "PrismaTenantSubscriptionWriteAdapter");
1586
+ }
1587
+ prisma;
1588
+ constructor(prisma) {
1589
+ this.prisma = prisma;
1590
+ }
1591
+ db(tx) {
1592
+ return resolveClient(this.prisma, tx);
1593
+ }
1594
+ async changePlanImmediate(tenantId, input) {
1595
+ const updated = await this.db().subscription.update({
1596
+ where: {
1597
+ tenantId
1598
+ },
1599
+ data: {
1600
+ plan: input.planId,
1601
+ billingCycle: input.cycle,
1602
+ pendingPlan: null,
1603
+ pendingBillingCycle: null,
1604
+ pendingEffectiveAt: null,
1605
+ ...input.nextStatus ? {
1606
+ status: input.nextStatus
1607
+ } : {},
1608
+ ...input.periodStart && input.periodEnd ? {
1609
+ currentPeriodStart: input.periodStart,
1610
+ currentPeriodEnd: input.periodEnd
1611
+ } : {},
1612
+ // #17: the platform changePlan path computes the carried-over
1613
+ // trial end and passes it through; null/undefined leaves the
1614
+ // existing trialEndsAt untouched.
1615
+ ...input.trialEndsAt ? {
1616
+ trialEndsAt: input.trialEndsAt
1617
+ } : {}
1618
+ }
1619
+ });
1620
+ return {
1621
+ plan: updated.plan,
1622
+ billingCycle: updated.billingCycle
1623
+ };
1624
+ }
1625
+ async schedulePlanChange(tenantId, input) {
1626
+ await this.db().subscription.update({
1627
+ where: {
1628
+ tenantId
1629
+ },
1630
+ data: {
1631
+ pendingPlan: input.pendingPlan,
1632
+ pendingBillingCycle: input.pendingBillingCycle,
1633
+ pendingEffectiveAt: input.pendingEffectiveAt
1634
+ }
1635
+ });
1636
+ }
1637
+ async acceptPendingPlanVersion(tenantId, userId, now) {
1638
+ const sub = await this.db().subscription.findUnique({
1639
+ where: {
1640
+ tenantId
1641
+ }
1642
+ });
1643
+ if (!sub) {
1644
+ throw new Error(`No subscription for tenant ${tenantId}.`);
1645
+ }
1646
+ if (sub.pendingPlanVersionAccepted) {
1647
+ return {
1648
+ accepted: true,
1649
+ acceptedAt: sub.pendingPlanVersionAcceptedAt,
1650
+ effectiveAt: sub.pendingPlanVersionEffectiveAt,
1651
+ alreadyAccepted: true
1652
+ };
1653
+ }
1654
+ const updated = await this.db().subscription.update({
1655
+ where: {
1656
+ id: sub.id
1657
+ },
1658
+ data: {
1659
+ pendingPlanVersionAccepted: true,
1660
+ pendingPlanVersionAcceptedAt: now,
1661
+ pendingPlanVersionAcceptedByUserId: userId
1662
+ }
1663
+ });
1664
+ return {
1665
+ accepted: true,
1666
+ acceptedAt: updated.pendingPlanVersionAcceptedAt,
1667
+ effectiveAt: updated.pendingPlanVersionEffectiveAt,
1668
+ alreadyAccepted: false
1669
+ };
1670
+ }
1671
+ async cancelSubscription(tenantId, immediate, now) {
1672
+ const sub = await this.db().subscription.findUnique({
1673
+ where: {
1674
+ tenantId
1675
+ }
1676
+ });
1677
+ if (!sub) {
1678
+ throw new Error(`No subscription for tenant ${tenantId}.`);
1679
+ }
1680
+ const canceledAt = immediate ? now : sub.currentPeriodEnd ?? now;
1681
+ const updated = await this.db().subscription.update({
1682
+ where: {
1683
+ tenantId
1684
+ },
1685
+ data: {
1686
+ canceledAt,
1687
+ status: immediate ? "CANCELED" : sub.status
1688
+ }
1689
+ });
1690
+ return {
1691
+ canceledAt: updated.canceledAt,
1692
+ status: updated.status
1693
+ };
1694
+ }
1695
+ };
1696
+ PrismaTenantSubscriptionWriteAdapter = _ts_decorate18([
1697
+ Injectable18(),
1698
+ _ts_param16(0, Inject16(PRISMA_CLIENT_TOKEN)),
1699
+ _ts_metadata16("design:type", Function),
1700
+ _ts_metadata16("design:paramtypes", [
1701
+ typeof PrismaLike === "undefined" ? Object : PrismaLike
1702
+ ])
1703
+ ], PrismaTenantSubscriptionWriteAdapter);
1704
+
1705
+ // src/prisma-plan.repository.ts
1706
+ import { Inject as Inject17, Injectable as Injectable19 } from "@nestjs/common";
1707
+ function _ts_decorate19(decorators, target, key, desc) {
1708
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1709
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
1710
+ 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;
1711
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
1712
+ }
1713
+ __name(_ts_decorate19, "_ts_decorate");
1714
+ function _ts_metadata17(k, v) {
1715
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
1716
+ }
1717
+ __name(_ts_metadata17, "_ts_metadata");
1718
+ function _ts_param17(paramIndex, decorator) {
1719
+ return function(target, key) {
1720
+ decorator(target, key, paramIndex);
1721
+ };
1722
+ }
1723
+ __name(_ts_param17, "_ts_param");
1724
+ var PrismaPlanRepository = class {
1725
+ static {
1726
+ __name(this, "PrismaPlanRepository");
1727
+ }
1728
+ prisma;
1729
+ constructor(prisma) {
1730
+ this.prisma = prisma;
1731
+ }
1732
+ db(tx) {
1733
+ return resolveClient(this.prisma, tx);
1734
+ }
1735
+ // ─── Stem operations (Pack 1) ───
1736
+ async list(filter) {
1737
+ const excludeDeleted = filter.excludeDeleted ?? true;
1738
+ let publishedKeys = null;
1739
+ if (filter.onlyPublished) {
1740
+ const live = await this.db().planVersion.findMany({
1741
+ where: {
1742
+ publishedAt: {
1743
+ not: null
1744
+ },
1745
+ supersededAt: null
1746
+ }
1747
+ });
1748
+ publishedKeys = [
1749
+ ...new Set(live.map((version) => version.planId))
1750
+ ];
1751
+ }
1752
+ const rows = await this.db().plan.findMany({
1753
+ where: {
1754
+ projectKey: filter.projectKey,
1755
+ ...excludeDeleted ? {
1756
+ deletedAt: null
1757
+ } : {},
1758
+ ...publishedKeys ? {
1759
+ planKey: {
1760
+ in: publishedKeys
1761
+ }
1762
+ } : {}
1763
+ },
1764
+ orderBy: [
1765
+ {
1766
+ sortOrder: "asc"
1767
+ },
1768
+ {
1769
+ planKey: "asc"
1770
+ }
1771
+ ]
1772
+ });
1773
+ return rows.map(toPlanRow2);
1774
+ }
1775
+ async findById(planId) {
1776
+ const row = await this.db().plan.findUnique({
1777
+ where: {
1778
+ id: planId
1779
+ }
1780
+ });
1781
+ return row ? toPlanRow2(row) : null;
1782
+ }
1783
+ async findByKey(projectKey, planKey) {
1784
+ const row = await this.db().plan.findFirst({
1785
+ where: {
1786
+ projectKey,
1787
+ planKey,
1788
+ deletedAt: null
1789
+ }
1790
+ });
1791
+ return row ? toPlanRow2(row) : null;
1792
+ }
1793
+ async create(data) {
1794
+ const created = await this.db().plan.create({
1795
+ data: {
1796
+ projectKey: data.projectKey,
1797
+ planKey: data.planKey,
1798
+ label: data.label,
1799
+ description: data.description ?? null,
1800
+ icon: data.icon ?? null,
1801
+ sortOrder: data.sortOrder ?? 0
1802
+ }
1803
+ });
1804
+ return toPlanRow2(created);
1805
+ }
1806
+ async update(planId, data) {
1807
+ const updated = await this.db().plan.update({
1808
+ where: {
1809
+ id: planId
1810
+ },
1811
+ data: {
1812
+ ...data.label !== void 0 ? {
1813
+ label: data.label
1814
+ } : {},
1815
+ ...data.description !== void 0 ? {
1816
+ description: data.description
1817
+ } : {},
1818
+ ...data.icon !== void 0 ? {
1819
+ icon: data.icon
1820
+ } : {},
1821
+ ...data.sortOrder !== void 0 ? {
1822
+ sortOrder: data.sortOrder
1823
+ } : {}
1824
+ }
1825
+ });
1826
+ return toPlanRow2(updated);
1827
+ }
1828
+ async softDelete(planId) {
1829
+ await this.db().plan.update({
1830
+ where: {
1831
+ id: planId
1832
+ },
1833
+ data: {
1834
+ deletedAt: /* @__PURE__ */ new Date()
1835
+ }
1836
+ });
1837
+ }
1838
+ async hardDelete(planId) {
1839
+ await this.db().plan.deleteMany({
1840
+ where: {
1841
+ id: planId
1842
+ }
1843
+ });
1844
+ }
1845
+ // ─── Lifecycle operations (Pack 2a) — keyed by planKey ───
1846
+ async listVersions(planKey) {
1847
+ const rows = await this.db().planVersion.findMany({
1848
+ where: {
1849
+ planId: planKey
1850
+ },
1851
+ orderBy: {
1852
+ version: "asc"
1853
+ }
1854
+ });
1855
+ return rows.map(toPlanVersionRow2);
1856
+ }
1857
+ async findVersionById(versionId) {
1858
+ const row = await this.db().planVersion.findUnique({
1859
+ where: {
1860
+ id: versionId
1861
+ }
1862
+ });
1863
+ return row ? toPlanVersionRow2(row) : null;
1864
+ }
1865
+ async findCurrentDraft(planKey) {
1866
+ const row = await this.db().planVersion.findFirst({
1867
+ where: {
1868
+ planId: planKey,
1869
+ publishedAt: null
1870
+ }
1871
+ });
1872
+ return row ? toPlanVersionRow2(row) : null;
1873
+ }
1874
+ async findLatestLivePlanVersion(planKey, tx) {
1875
+ const row = await this.db(tx).planVersion.findFirst({
1876
+ where: {
1877
+ planId: planKey,
1878
+ publishedAt: {
1879
+ not: null
1880
+ },
1881
+ supersededAt: null
1882
+ },
1883
+ orderBy: {
1884
+ version: "desc"
1885
+ }
1886
+ });
1887
+ return row ? toPlanVersionRow2(row) : null;
1888
+ }
1889
+ async findActivePlanVersion() {
1890
+ throw new Error("findActivePlanVersion is not supported by the shipped @saasicat/adapter-prisma PlanRepository: the canonical plan_versions schema (03-plan-versions.prisma) has no validFrom/validUntil columns, so a version cannot be resolved by validity window. Use findLatestLivePlanVersion for the newest live version, or provide a custom PlanRepository adapter on a schema that carries the validity-window columns.");
1891
+ }
1892
+ async createPlanVersionDraft(data) {
1893
+ const planKey = data.planId;
1894
+ const latest = await this.db().planVersion.findFirst({
1895
+ where: {
1896
+ planId: planKey
1897
+ },
1898
+ orderBy: {
1899
+ version: "desc"
1900
+ }
1901
+ });
1902
+ const nextVersion = (latest?.version ?? 0) + 1;
1903
+ const created = await this.db().planVersion.create({
1904
+ data: {
1905
+ planId: planKey,
1906
+ version: nextVersion,
1907
+ baseVersionId: data.baseVersionId ?? null,
1908
+ features: data.features,
1909
+ quotas: data.quotas,
1910
+ monthlyNet: data.monthlyNet,
1911
+ yearlyNet: data.yearlyNet,
1912
+ marketed: data.marketed ?? true,
1913
+ changeNote: data.changeNote ?? "",
1914
+ createdByUserId: data.createdByUserId ?? null
1915
+ }
1916
+ });
1917
+ return toPlanVersionRow2(created);
1918
+ }
1919
+ async updatePlanVersionDraft(versionId, data) {
1920
+ const updated = await this.db().planVersion.update({
1921
+ where: {
1922
+ id: versionId
1923
+ },
1924
+ data: {
1925
+ ...data.features !== void 0 ? {
1926
+ features: data.features
1927
+ } : {},
1928
+ ...data.quotas !== void 0 ? {
1929
+ quotas: data.quotas
1930
+ } : {},
1931
+ ...data.monthlyNet !== void 0 ? {
1932
+ monthlyNet: data.monthlyNet
1933
+ } : {},
1934
+ ...data.yearlyNet !== void 0 ? {
1935
+ yearlyNet: data.yearlyNet
1936
+ } : {},
1937
+ ...data.marketed !== void 0 ? {
1938
+ marketed: data.marketed
1939
+ } : {},
1940
+ ...data.changeNote !== void 0 ? {
1941
+ changeNote: data.changeNote
1942
+ } : {}
1943
+ }
1944
+ });
1945
+ return toPlanVersionRow2(updated);
1946
+ }
1947
+ async publishPlanVersionDraft(versionId, publishMeta, tx) {
1948
+ const draft = await this.db(tx).planVersion.findUnique({
1949
+ where: {
1950
+ id: versionId
1951
+ }
1952
+ });
1953
+ if (!draft) {
1954
+ throw new Error(`PlanVersion ${versionId} not found.`);
1955
+ }
1956
+ const planKey = draft.planId;
1957
+ const publish = /* @__PURE__ */ __name(async (db) => {
1958
+ const previous = await db.planVersion.findFirst({
1959
+ where: {
1960
+ planId: planKey,
1961
+ publishedAt: {
1962
+ not: null
1963
+ },
1964
+ supersededAt: null,
1965
+ id: {
1966
+ not: versionId
1967
+ }
1968
+ },
1969
+ orderBy: {
1970
+ version: "desc"
1971
+ }
1972
+ });
1973
+ const now = /* @__PURE__ */ new Date();
1974
+ if (previous) {
1975
+ await db.planVersion.update({
1976
+ where: {
1977
+ id: previous.id
1978
+ },
1979
+ data: {
1980
+ supersededAt: now
1981
+ }
1982
+ });
1983
+ }
1984
+ return db.planVersion.update({
1985
+ where: {
1986
+ id: versionId
1987
+ },
1988
+ data: {
1989
+ publishedAt: now,
1990
+ publishedChanges: publishMeta.publishedChanges,
1991
+ nonRegressive: publishMeta.nonRegressive,
1992
+ publishedByUserId: publishMeta.publishedByUserId
1993
+ }
1994
+ });
1995
+ }, "publish");
1996
+ const published = tx ? await publish(this.db(tx)) : await this.prisma.$transaction((txClient) => publish(txClient));
1997
+ return toPlanVersionRow2(published);
1998
+ }
1999
+ async deletePlanVersionDraft(versionId) {
2000
+ const row = await this.db().planVersion.findUnique({
2001
+ where: {
2002
+ id: versionId
2003
+ }
2004
+ });
2005
+ if (!row) return;
2006
+ if (row.publishedAt !== null) {
2007
+ throw new Error(`PlanVersion ${versionId} is already published and cannot be discarded (published versions are immutable \u2014 contract protection P1).`);
2008
+ }
2009
+ await this.db().planVersion.deleteMany({
2010
+ where: {
2011
+ id: versionId,
2012
+ publishedAt: null
2013
+ }
2014
+ });
2015
+ }
2016
+ async terminate() {
2017
+ throw new Error("terminate is not supported by the shipped @saasicat/adapter-prisma PlanRepository: the canonical plan_versions schema (03-plan-versions.prisma) has no endsAt column. Provide a custom PlanRepository adapter on a schema that carries endsAt to support SuperAdmin-initiated plan-version termination.");
2018
+ }
2019
+ };
2020
+ PrismaPlanRepository = _ts_decorate19([
2021
+ Injectable19(),
2022
+ _ts_param17(0, Inject17(PRISMA_CLIENT_TOKEN)),
2023
+ _ts_metadata17("design:type", Function),
2024
+ _ts_metadata17("design:paramtypes", [
2025
+ typeof PrismaLike === "undefined" ? Object : PrismaLike
2026
+ ])
2027
+ ], PrismaPlanRepository);
2028
+ function toPlanRow2(row) {
2029
+ return {
2030
+ id: row.id,
2031
+ projectKey: row.projectKey,
2032
+ planKey: row.planKey,
2033
+ label: row.label,
2034
+ description: row.description,
2035
+ icon: row.icon,
2036
+ sortOrder: row.sortOrder,
2037
+ createdAt: row.createdAt.toISOString(),
2038
+ updatedAt: row.updatedAt.toISOString(),
2039
+ deletedAt: row.deletedAt?.toISOString() ?? null
2040
+ };
2041
+ }
2042
+ __name(toPlanRow2, "toPlanRow");
2043
+ function toPlanVersionRow2(row) {
2044
+ return {
2045
+ id: row.id,
2046
+ version: row.version,
2047
+ baseVersionId: row.baseVersionId,
2048
+ planId: row.planId,
2049
+ features: toStringArray(row.features),
2050
+ quotas: toQuotaMap(row.quotas),
2051
+ monthlyNet: row.monthlyNet.toString(),
2052
+ yearlyNet: row.yearlyNet.toString(),
2053
+ marketed: row.marketed,
2054
+ publishedAt: row.publishedAt?.toISOString() ?? null,
2055
+ supersededAt: row.supersededAt?.toISOString() ?? null,
2056
+ publishedChanges: Array.isArray(row.publishedChanges) ? row.publishedChanges : null,
2057
+ changeNote: row.changeNote,
2058
+ nonRegressive: row.nonRegressive,
2059
+ // The canonical plan_versions schema carries no validity-window columns.
2060
+ validFrom: null,
2061
+ validUntil: null,
2062
+ createdByUserId: row.createdByUserId,
2063
+ publishedByUserId: row.publishedByUserId,
2064
+ createdAt: row.createdAt.toISOString(),
2065
+ updatedAt: row.updatedAt.toISOString()
2066
+ };
2067
+ }
2068
+ __name(toPlanVersionRow2, "toPlanVersionRow");
2069
+
2070
+ // src/prisma-bundle.repository.ts
2071
+ import { Inject as Inject18, Injectable as Injectable20 } from "@nestjs/common";
2072
+ function _ts_decorate20(decorators, target, key, desc) {
2073
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
2074
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
2075
+ 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;
2076
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
2077
+ }
2078
+ __name(_ts_decorate20, "_ts_decorate");
2079
+ function _ts_metadata18(k, v) {
2080
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
2081
+ }
2082
+ __name(_ts_metadata18, "_ts_metadata");
2083
+ function _ts_param18(paramIndex, decorator) {
2084
+ return function(target, key) {
2085
+ decorator(target, key, paramIndex);
2086
+ };
2087
+ }
2088
+ __name(_ts_param18, "_ts_param");
2089
+ var PrismaBundleRepository = class {
2090
+ static {
2091
+ __name(this, "PrismaBundleRepository");
2092
+ }
2093
+ prisma;
2094
+ constructor(prisma) {
2095
+ this.prisma = prisma;
2096
+ }
2097
+ db(tx) {
2098
+ return resolveClient(this.prisma, tx);
2099
+ }
2100
+ // ─── Stem operations ───
2101
+ async list(filter) {
2102
+ const excludeDeleted = filter.excludeDeleted ?? true;
2103
+ const rows = await this.db().bundle.findMany({
2104
+ where: {
2105
+ projectKey: filter.projectKey,
2106
+ ...excludeDeleted ? {
2107
+ deletedAt: null
2108
+ } : {}
2109
+ },
2110
+ orderBy: [
2111
+ {
2112
+ sortOrder: "asc"
2113
+ },
2114
+ {
2115
+ bundleKey: "asc"
2116
+ }
2117
+ ]
2118
+ });
2119
+ return rows.map(toBundleRow);
2120
+ }
2121
+ async findById(bundleId) {
2122
+ const row = await this.db().bundle.findUnique({
2123
+ where: {
2124
+ id: bundleId
2125
+ }
2126
+ });
2127
+ return row ? toBundleRow(row) : null;
2128
+ }
2129
+ async findByKey(projectKey, bundleKey) {
2130
+ const row = await this.db().bundle.findFirst({
2131
+ where: {
2132
+ projectKey,
2133
+ bundleKey,
2134
+ deletedAt: null
2135
+ }
2136
+ });
2137
+ return row ? toBundleRow(row) : null;
2138
+ }
2139
+ async create(data) {
2140
+ const created = await this.db().bundle.create({
2141
+ data: {
2142
+ projectKey: data.projectKey,
2143
+ bundleKey: data.bundleKey,
2144
+ label: data.label,
2145
+ description: data.description ?? null,
2146
+ icon: data.icon ?? null,
2147
+ sortOrder: data.sortOrder ?? 0,
2148
+ i18n: data.i18n ?? {}
2149
+ }
2150
+ });
2151
+ return toBundleRow(created);
2152
+ }
2153
+ async update(bundleId, data) {
2154
+ const updated = await this.db().bundle.update({
2155
+ where: {
2156
+ id: bundleId
2157
+ },
2158
+ data: {
2159
+ ...data.label !== void 0 ? {
2160
+ label: data.label
2161
+ } : {},
2162
+ ...data.description !== void 0 ? {
2163
+ description: data.description
2164
+ } : {},
2165
+ ...data.icon !== void 0 ? {
2166
+ icon: data.icon
2167
+ } : {},
2168
+ ...data.sortOrder !== void 0 ? {
2169
+ sortOrder: data.sortOrder
2170
+ } : {},
2171
+ ...data.i18n !== void 0 ? {
2172
+ i18n: data.i18n
2173
+ } : {}
2174
+ }
2175
+ });
2176
+ return toBundleRow(updated);
2177
+ }
2178
+ async softDelete(bundleId) {
2179
+ await this.db().bundle.update({
2180
+ where: {
2181
+ id: bundleId
2182
+ },
2183
+ data: {
2184
+ deletedAt: /* @__PURE__ */ new Date()
2185
+ }
2186
+ });
2187
+ }
2188
+ // ─── Version operations ───
2189
+ async listVersions(bundleId) {
2190
+ const bundle = await this.db().bundle.findUnique({
2191
+ where: {
2192
+ id: bundleId
2193
+ }
2194
+ });
2195
+ if (!bundle) return [];
2196
+ const rows = await this.db().bundleVersion.findMany({
2197
+ where: {
2198
+ bundleId
2199
+ },
2200
+ orderBy: {
2201
+ version: "asc"
2202
+ }
2203
+ });
2204
+ return rows.map((row) => toBundleVersionRow(row, bundle));
2205
+ }
2206
+ async findVersionById(versionId) {
2207
+ const row = await this.db().bundleVersion.findUnique({
2208
+ where: {
2209
+ id: versionId
2210
+ }
2211
+ });
2212
+ if (!row) return null;
2213
+ const bundle = await this.db().bundle.findUnique({
2214
+ where: {
2215
+ id: row.bundleId
2216
+ }
2217
+ });
2218
+ return toBundleVersionRow(row, bundle);
2219
+ }
2220
+ async findCurrentDraft(bundleId) {
2221
+ const row = await this.db().bundleVersion.findFirst({
2222
+ where: {
2223
+ bundleId,
2224
+ publishedAt: null
2225
+ }
2226
+ });
2227
+ if (!row) return null;
2228
+ const bundle = await this.db().bundle.findUnique({
2229
+ where: {
2230
+ id: bundleId
2231
+ }
2232
+ });
2233
+ return toBundleVersionRow(row, bundle);
2234
+ }
2235
+ async findLatestLive(bundleId, tx) {
2236
+ const db = this.db(tx);
2237
+ const row = await db.bundleVersion.findFirst({
2238
+ where: {
2239
+ bundleId,
2240
+ publishedAt: {
2241
+ not: null
2242
+ },
2243
+ supersededAt: null
2244
+ },
2245
+ orderBy: {
2246
+ version: "desc"
2247
+ }
2248
+ });
2249
+ if (!row) return null;
2250
+ const bundle = await db.bundle.findUnique({
2251
+ where: {
2252
+ id: bundleId
2253
+ }
2254
+ });
2255
+ return toBundleVersionRow(row, bundle);
2256
+ }
2257
+ async createDraft(data) {
2258
+ const db = this.db();
2259
+ const existingDraft = await db.bundleVersion.findFirst({
2260
+ where: {
2261
+ bundleId: data.bundleId,
2262
+ publishedAt: null
2263
+ }
2264
+ });
2265
+ if (existingDraft) {
2266
+ throw new Error(`Bundle '${data.bundleId}' already has a draft version (v${existingDraft.version}); only one draft per bundle is allowed.`);
2267
+ }
2268
+ const latest = await db.bundleVersion.findFirst({
2269
+ where: {
2270
+ bundleId: data.bundleId
2271
+ },
2272
+ orderBy: {
2273
+ version: "desc"
2274
+ }
2275
+ });
2276
+ const nextVersion = latest ? latest.version + 1 : 1;
2277
+ const created = await db.bundleVersion.create({
2278
+ data: {
2279
+ bundleId: data.bundleId,
2280
+ version: nextVersion,
2281
+ baseVersionId: data.baseVersionId ?? null,
2282
+ features: data.features,
2283
+ quotas: data.quotas ?? {},
2284
+ compatibility: data.compatibility ?? {},
2285
+ pricingOverrides: data.pricingOverrides ?? [],
2286
+ monthlyNet: data.monthlyNet ?? null,
2287
+ yearlyNet: data.yearlyNet ?? null,
2288
+ marketed: data.marketed ?? true,
2289
+ changeNote: data.changeNote ?? "",
2290
+ createdByUserId: data.createdByUserId ?? null
2291
+ }
2292
+ });
2293
+ const bundle = await db.bundle.findUnique({
2294
+ where: {
2295
+ id: data.bundleId
2296
+ }
2297
+ });
2298
+ return toBundleVersionRow(created, bundle);
2299
+ }
2300
+ async updateDraft(versionId, data) {
2301
+ const db = this.db();
2302
+ const updated = await db.bundleVersion.update({
2303
+ where: {
2304
+ id: versionId
2305
+ },
2306
+ data: {
2307
+ ...data.features !== void 0 ? {
2308
+ features: data.features
2309
+ } : {},
2310
+ ...data.quotas !== void 0 ? {
2311
+ quotas: data.quotas
2312
+ } : {},
2313
+ ...data.compatibility !== void 0 ? {
2314
+ compatibility: data.compatibility
2315
+ } : {},
2316
+ ...data.pricingOverrides !== void 0 ? {
2317
+ pricingOverrides: data.pricingOverrides
2318
+ } : {},
2319
+ ...data.monthlyNet !== void 0 ? {
2320
+ monthlyNet: data.monthlyNet
2321
+ } : {},
2322
+ ...data.yearlyNet !== void 0 ? {
2323
+ yearlyNet: data.yearlyNet
2324
+ } : {},
2325
+ ...data.marketed !== void 0 ? {
2326
+ marketed: data.marketed
2327
+ } : {},
2328
+ ...data.changeNote !== void 0 ? {
2329
+ changeNote: data.changeNote
2330
+ } : {}
2331
+ }
2332
+ });
2333
+ const bundle = await db.bundle.findUnique({
2334
+ where: {
2335
+ id: updated.bundleId
2336
+ }
2337
+ });
2338
+ return toBundleVersionRow(updated, bundle);
2339
+ }
2340
+ async publishDraft(versionId, publishMeta, tx) {
2341
+ const db = this.db(tx);
2342
+ const draft = await db.bundleVersion.findUnique({
2343
+ where: {
2344
+ id: versionId
2345
+ }
2346
+ });
2347
+ if (!draft) {
2348
+ throw new Error(`BundleVersion '${versionId}' not found.`);
2349
+ }
2350
+ await db.bundleVersion.updateMany({
2351
+ where: {
2352
+ bundleId: draft.bundleId,
2353
+ publishedAt: {
2354
+ not: null
2355
+ },
2356
+ supersededAt: null,
2357
+ NOT: {
2358
+ id: versionId
2359
+ }
2360
+ },
2361
+ data: {
2362
+ supersededAt: /* @__PURE__ */ new Date()
2363
+ }
2364
+ });
2365
+ const published = await db.bundleVersion.update({
2366
+ where: {
2367
+ id: versionId
2368
+ },
2369
+ data: {
2370
+ publishedAt: /* @__PURE__ */ new Date(),
2371
+ publishedByUserId: publishMeta.publishedByUserId,
2372
+ publishedChanges: publishMeta.publishedChanges,
2373
+ nonRegressive: publishMeta.nonRegressive
2374
+ }
2375
+ });
2376
+ const bundle = await db.bundle.findUnique({
2377
+ where: {
2378
+ id: published.bundleId
2379
+ }
2380
+ });
2381
+ return toBundleVersionRow(published, bundle);
2382
+ }
2383
+ async deleteDraft(versionId) {
2384
+ const db = this.db();
2385
+ const row = await db.bundleVersion.findUnique({
2386
+ where: {
2387
+ id: versionId
2388
+ }
2389
+ });
2390
+ if (!row) return;
2391
+ if (row.publishedAt !== null) {
2392
+ throw new Error(`BundleVersion '${versionId}' is already published and cannot be discarded (published versions are immutable \u2014 contract protection P1).`);
2393
+ }
2394
+ try {
2395
+ await db.bundleVersion.delete({
2396
+ where: {
2397
+ id: versionId
2398
+ }
2399
+ });
2400
+ } catch (err) {
2401
+ if (err?.code === "P2025") return;
2402
+ throw err;
2403
+ }
2404
+ }
2405
+ };
2406
+ PrismaBundleRepository = _ts_decorate20([
2407
+ Injectable20(),
2408
+ _ts_param18(0, Inject18(PRISMA_CLIENT_TOKEN)),
2409
+ _ts_metadata18("design:type", Function),
2410
+ _ts_metadata18("design:paramtypes", [
2411
+ typeof PrismaLike === "undefined" ? Object : PrismaLike
2412
+ ])
2413
+ ], PrismaBundleRepository);
2414
+ function isPlainObject(value) {
2415
+ return value !== null && typeof value === "object" && !Array.isArray(value);
2416
+ }
2417
+ __name(isPlainObject, "isPlainObject");
2418
+ function toDecimalString(value) {
2419
+ return value == null ? null : value.toString();
2420
+ }
2421
+ __name(toDecimalString, "toDecimalString");
2422
+ function toVersionChanges(value) {
2423
+ return Array.isArray(value) ? value : null;
2424
+ }
2425
+ __name(toVersionChanges, "toVersionChanges");
2426
+ function toCompatibility(value) {
2427
+ return isPlainObject(value) ? value : {};
2428
+ }
2429
+ __name(toCompatibility, "toCompatibility");
2430
+ function toPricingOverrides(value) {
2431
+ return Array.isArray(value) ? value : [];
2432
+ }
2433
+ __name(toPricingOverrides, "toPricingOverrides");
2434
+ function toI18n(value) {
2435
+ return isPlainObject(value) ? value : {};
2436
+ }
2437
+ __name(toI18n, "toI18n");
2438
+ function toBundleRow(row) {
2439
+ return {
2440
+ id: row.id,
2441
+ projectKey: row.projectKey,
2442
+ bundleKey: row.bundleKey,
2443
+ label: row.label,
2444
+ description: row.description,
2445
+ icon: row.icon,
2446
+ sortOrder: row.sortOrder,
2447
+ i18n: toI18n(row.i18n),
2448
+ createdAt: row.createdAt.toISOString(),
2449
+ updatedAt: row.updatedAt.toISOString(),
2450
+ deletedAt: row.deletedAt?.toISOString() ?? null
2451
+ };
2452
+ }
2453
+ __name(toBundleRow, "toBundleRow");
2454
+ function toBundleVersionRow(row, bundle) {
2455
+ return {
2456
+ id: row.id,
2457
+ bundleId: row.bundleId,
2458
+ bundleKey: bundle?.bundleKey ?? "",
2459
+ label: bundle?.label ?? "",
2460
+ version: row.version,
2461
+ baseVersionId: row.baseVersionId,
2462
+ features: toStringArray(row.features),
2463
+ quotas: toQuotaMap(row.quotas),
2464
+ compatibility: toCompatibility(row.compatibility),
2465
+ pricingOverrides: toPricingOverrides(row.pricingOverrides),
2466
+ monthlyNet: toDecimalString(row.monthlyNet),
2467
+ yearlyNet: toDecimalString(row.yearlyNet),
2468
+ marketed: row.marketed,
2469
+ publishedAt: row.publishedAt?.toISOString() ?? null,
2470
+ supersededAt: row.supersededAt?.toISOString() ?? null,
2471
+ // The canonical `bundle_versions` table has no validFrom/validUntil
2472
+ // columns; time-aware validity is not expressible on this schema.
2473
+ validFrom: null,
2474
+ validUntil: null,
2475
+ publishedChanges: toVersionChanges(row.publishedChanges),
2476
+ changeNote: row.changeNote,
2477
+ nonRegressive: row.nonRegressive,
2478
+ createdByUserId: row.createdByUserId,
2479
+ publishedByUserId: row.publishedByUserId,
2480
+ createdAt: row.createdAt.toISOString(),
2481
+ updatedAt: row.updatedAt.toISOString()
2482
+ };
2483
+ }
2484
+ __name(toBundleVersionRow, "toBundleVersionRow");
2485
+
2486
+ // src/prisma-catalog-entry.repository.ts
2487
+ import { Inject as Inject19, Injectable as Injectable21 } from "@nestjs/common";
2488
+ function _ts_decorate21(decorators, target, key, desc) {
2489
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
2490
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
2491
+ 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;
2492
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
2493
+ }
2494
+ __name(_ts_decorate21, "_ts_decorate");
2495
+ function _ts_metadata19(k, v) {
2496
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
2497
+ }
2498
+ __name(_ts_metadata19, "_ts_metadata");
2499
+ function _ts_param19(paramIndex, decorator) {
2500
+ return function(target, key) {
2501
+ decorator(target, key, paramIndex);
2502
+ };
2503
+ }
2504
+ __name(_ts_param19, "_ts_param");
2505
+ var PrismaCatalogEntryRepository = class {
2506
+ static {
2507
+ __name(this, "PrismaCatalogEntryRepository");
2508
+ }
2509
+ prisma;
2510
+ constructor(prisma) {
2511
+ this.prisma = prisma;
2512
+ }
2513
+ get db() {
2514
+ return this.prisma;
2515
+ }
2516
+ async listCapabilities(filter) {
2517
+ const rows = await this.db.capabilityCatalogEntry.findMany({
2518
+ where: {
2519
+ projectKey: filter.projectKey,
2520
+ deletedAt: null,
2521
+ ...filter.codeStatus ? {
2522
+ codeStatus: filter.codeStatus
2523
+ } : {}
2524
+ },
2525
+ orderBy: [
2526
+ {
2527
+ sortOrder: "asc"
2528
+ },
2529
+ {
2530
+ capabilityKey: "asc"
2531
+ }
2532
+ ]
2533
+ });
2534
+ return rows.map(toCapabilityRow);
2535
+ }
2536
+ async listFeatures(filter) {
2537
+ const rows = await this.db.featureCatalogEntry.findMany({
2538
+ where: {
2539
+ projectKey: filter.projectKey,
2540
+ deletedAt: null,
2541
+ ...filter.discoveryStatus ? {
2542
+ discoveryStatus: filter.discoveryStatus
2543
+ } : {}
2544
+ },
2545
+ orderBy: [
2546
+ {
2547
+ sortOrder: "asc"
2548
+ },
2549
+ {
2550
+ featureKey: "asc"
2551
+ }
2552
+ ]
2553
+ });
2554
+ return rows.map(toFeatureRow);
2555
+ }
2556
+ async listQuotas(filter) {
2557
+ const rows = await this.db.quotaCatalogEntry.findMany({
2558
+ where: {
2559
+ projectKey: filter.projectKey,
2560
+ deletedAt: null,
2561
+ ...filter.discoveryStatus ? {
2562
+ discoveryStatus: filter.discoveryStatus
2563
+ } : {}
2564
+ },
2565
+ orderBy: [
2566
+ {
2567
+ sortOrder: "asc"
2568
+ },
2569
+ {
2570
+ quotaKey: "asc"
2571
+ }
2572
+ ]
2573
+ });
2574
+ return rows.map(toQuotaRow);
2575
+ }
2576
+ async upsertCapability(data) {
2577
+ const codeFields = {
2578
+ label: data.label,
2579
+ description: data.description,
2580
+ featureKey: data.featureKey,
2581
+ bundleKey: data.bundleKey,
2582
+ codeStatus: data.codeStatus,
2583
+ owner: data.owner,
2584
+ kind: data.kind,
2585
+ replacementKey: data.replacementKey,
2586
+ deprecatedAt: data.deprecatedAt ? new Date(data.deprecatedAt) : null,
2587
+ removalPlannedAt: data.removalPlannedAt ? new Date(data.removalPlannedAt) : null,
2588
+ reason: data.reason
2589
+ };
2590
+ const row = await this.db.capabilityCatalogEntry.upsert({
2591
+ where: {
2592
+ projectKey_capabilityKey: {
2593
+ projectKey: data.projectKey,
2594
+ capabilityKey: data.capabilityKey
2595
+ }
2596
+ },
2597
+ create: {
2598
+ projectKey: data.projectKey,
2599
+ capabilityKey: data.capabilityKey,
2600
+ ...codeFields
2601
+ },
2602
+ update: codeFields
2603
+ });
2604
+ return toCapabilityRow(row);
2605
+ }
2606
+ async upsertFeature(data) {
2607
+ const codeFields = {
2608
+ label: data.label,
2609
+ description: data.description,
2610
+ discoveryStatus: data.discoveryStatus,
2611
+ requires: data.requires,
2612
+ replaces: data.replaces,
2613
+ ...data.core !== void 0 ? {
2614
+ core: data.core
2615
+ } : {}
2616
+ };
2617
+ const row = await this.db.featureCatalogEntry.upsert({
2618
+ where: {
2619
+ projectKey_featureKey: {
2620
+ projectKey: data.projectKey,
2621
+ featureKey: data.featureKey
2622
+ }
2623
+ },
2624
+ create: {
2625
+ projectKey: data.projectKey,
2626
+ featureKey: data.featureKey,
2627
+ ...codeFields
2628
+ },
2629
+ update: codeFields
2630
+ });
2631
+ return toFeatureRow(row);
2632
+ }
2633
+ async upsertQuota(data) {
2634
+ const codeFields = {
2635
+ label: data.label,
2636
+ description: data.description,
2637
+ unit: data.unit,
2638
+ featureKey: data.featureKey,
2639
+ usageProvider: data.usageProvider,
2640
+ enforcementMode: data.enforcementMode,
2641
+ discoveryStatus: data.discoveryStatus,
2642
+ replaces: data.replaces
2643
+ };
2644
+ const row = await this.db.quotaCatalogEntry.upsert({
2645
+ where: {
2646
+ projectKey_quotaKey: {
2647
+ projectKey: data.projectKey,
2648
+ quotaKey: data.quotaKey
2649
+ }
2650
+ },
2651
+ create: {
2652
+ projectKey: data.projectKey,
2653
+ quotaKey: data.quotaKey,
2654
+ ...codeFields
2655
+ },
2656
+ update: codeFields
2657
+ });
2658
+ return toQuotaRow(row);
2659
+ }
2660
+ async retireMissing(projectKey, type, presentKeys) {
2661
+ if (type === "capability") {
2662
+ const res2 = await this.db.capabilityCatalogEntry.updateMany({
2663
+ where: {
2664
+ projectKey,
2665
+ deletedAt: null,
2666
+ codeStatus: {
2667
+ not: "retired"
2668
+ },
2669
+ capabilityKey: {
2670
+ notIn: presentKeys
2671
+ }
2672
+ },
2673
+ data: {
2674
+ codeStatus: "retired"
2675
+ }
2676
+ });
2677
+ return res2.count;
2678
+ }
2679
+ if (type === "feature") {
2680
+ const res2 = await this.db.featureCatalogEntry.updateMany({
2681
+ where: {
2682
+ projectKey,
2683
+ deletedAt: null,
2684
+ discoveryStatus: {
2685
+ not: "obsolete"
2686
+ },
2687
+ featureKey: {
2688
+ notIn: presentKeys
2689
+ }
2690
+ },
2691
+ data: {
2692
+ discoveryStatus: "obsolete"
2693
+ }
2694
+ });
2695
+ return res2.count;
2696
+ }
2697
+ const res = await this.db.quotaCatalogEntry.updateMany({
2698
+ where: {
2699
+ projectKey,
2700
+ deletedAt: null,
2701
+ discoveryStatus: {
2702
+ not: "obsolete"
2703
+ },
2704
+ quotaKey: {
2705
+ notIn: presentKeys
2706
+ }
2707
+ },
2708
+ data: {
2709
+ discoveryStatus: "obsolete"
2710
+ }
2711
+ });
2712
+ return res.count;
2713
+ }
2714
+ async setFeatureSuccessor(projectKey, featureKey, successorKey) {
2715
+ const row = await this.db.featureCatalogEntry.update({
2716
+ where: {
2717
+ projectKey_featureKey: {
2718
+ projectKey,
2719
+ featureKey
2720
+ }
2721
+ },
2722
+ data: {
2723
+ successorKey
2724
+ }
2725
+ });
2726
+ return toFeatureRow(row);
2727
+ }
2728
+ async setQuotaSuccessor(projectKey, quotaKey, successorKey) {
2729
+ const row = await this.db.quotaCatalogEntry.update({
2730
+ where: {
2731
+ projectKey_quotaKey: {
2732
+ projectKey,
2733
+ quotaKey
2734
+ }
2735
+ },
2736
+ data: {
2737
+ successorKey
2738
+ }
2739
+ });
2740
+ return toQuotaRow(row);
2741
+ }
2742
+ async findFeature(projectKey, featureKey) {
2743
+ const row = await this.db.featureCatalogEntry.findUnique({
2744
+ where: {
2745
+ projectKey_featureKey: {
2746
+ projectKey,
2747
+ featureKey
2748
+ }
2749
+ }
2750
+ });
2751
+ return row ? toFeatureRow(row) : null;
2752
+ }
2753
+ async findQuota(projectKey, quotaKey) {
2754
+ const row = await this.db.quotaCatalogEntry.findUnique({
2755
+ where: {
2756
+ projectKey_quotaKey: {
2757
+ projectKey,
2758
+ quotaKey
2759
+ }
2760
+ }
2761
+ });
2762
+ return row ? toQuotaRow(row) : null;
2763
+ }
2764
+ async setFeatureReview(projectKey, featureKey, data) {
2765
+ const row = await this.db.featureCatalogEntry.update({
2766
+ where: {
2767
+ projectKey_featureKey: {
2768
+ projectKey,
2769
+ featureKey
2770
+ }
2771
+ },
2772
+ data: {
2773
+ discoveryStatus: data.discoveryStatus,
2774
+ approvedAt: data.approvedAt ? new Date(data.approvedAt) : null,
2775
+ approvedBy: data.approvedBy,
2776
+ approvedSignature: data.approvedSignature
2777
+ }
2778
+ });
2779
+ return toFeatureRow(row);
2780
+ }
2781
+ async setQuotaReview(projectKey, quotaKey, data) {
2782
+ const row = await this.db.quotaCatalogEntry.update({
2783
+ where: {
2784
+ projectKey_quotaKey: {
2785
+ projectKey,
2786
+ quotaKey
2787
+ }
2788
+ },
2789
+ data: {
2790
+ discoveryStatus: data.discoveryStatus,
2791
+ approvedAt: data.approvedAt ? new Date(data.approvedAt) : null,
2792
+ approvedBy: data.approvedBy,
2793
+ approvedSignature: data.approvedSignature
2794
+ }
2795
+ });
2796
+ return toQuotaRow(row);
2797
+ }
2798
+ async setFeatureI18n(projectKey, featureKey, i18n) {
2799
+ const row = await this.db.featureCatalogEntry.update({
2800
+ where: {
2801
+ projectKey_featureKey: {
2802
+ projectKey,
2803
+ featureKey
2804
+ }
2805
+ },
2806
+ data: {
2807
+ i18n
2808
+ }
2809
+ });
2810
+ return toFeatureRow(row);
2811
+ }
2812
+ async setQuotaI18n(projectKey, quotaKey, i18n) {
2813
+ const row = await this.db.quotaCatalogEntry.update({
2814
+ where: {
2815
+ projectKey_quotaKey: {
2816
+ projectKey,
2817
+ quotaKey
2818
+ }
2819
+ },
2820
+ data: {
2821
+ i18n
2822
+ }
2823
+ });
2824
+ return toQuotaRow(row);
2825
+ }
2826
+ async setFeatureBase(projectKey, featureKey, data) {
2827
+ const row = await this.db.featureCatalogEntry.update({
2828
+ where: {
2829
+ projectKey_featureKey: {
2830
+ projectKey,
2831
+ featureKey
2832
+ }
2833
+ },
2834
+ data: {
2835
+ ...data.label !== void 0 ? {
2836
+ label: data.label
2837
+ } : {},
2838
+ ...data.description !== void 0 ? {
2839
+ description: data.description
2840
+ } : {},
2841
+ ...data.icon !== void 0 ? {
2842
+ icon: data.icon
2843
+ } : {},
2844
+ ...data.tier !== void 0 ? {
2845
+ tier: data.tier
2846
+ } : {}
2847
+ }
2848
+ });
2849
+ return toFeatureRow(row);
2850
+ }
2851
+ async setQuotaBase(projectKey, quotaKey, data) {
2852
+ const row = await this.db.quotaCatalogEntry.update({
2853
+ where: {
2854
+ projectKey_quotaKey: {
2855
+ projectKey,
2856
+ quotaKey
2857
+ }
2858
+ },
2859
+ data: {
2860
+ ...data.label !== void 0 ? {
2861
+ label: data.label
2862
+ } : {},
2863
+ ...data.description !== void 0 ? {
2864
+ description: data.description
2865
+ } : {}
2866
+ }
2867
+ });
2868
+ return toQuotaRow(row);
2869
+ }
2870
+ };
2871
+ PrismaCatalogEntryRepository = _ts_decorate21([
2872
+ Injectable21(),
2873
+ _ts_param19(0, Inject19(PRISMA_CLIENT_TOKEN)),
2874
+ _ts_metadata19("design:type", Function),
2875
+ _ts_metadata19("design:paramtypes", [
2876
+ typeof PrismaLike === "undefined" ? Object : PrismaLike
2877
+ ])
2878
+ ], PrismaCatalogEntryRepository);
2879
+ function toI18n2(value) {
2880
+ if (value !== null && typeof value === "object" && !Array.isArray(value)) {
2881
+ return value;
2882
+ }
2883
+ return {};
2884
+ }
2885
+ __name(toI18n2, "toI18n");
2886
+ function toCapabilityRow(row) {
2887
+ return {
2888
+ id: row.id,
2889
+ projectKey: row.projectKey,
2890
+ capabilityKey: row.capabilityKey,
2891
+ label: row.label,
2892
+ description: row.description,
2893
+ featureKey: row.featureKey,
2894
+ bundleKey: row.bundleKey,
2895
+ codeStatus: row.codeStatus,
2896
+ owner: row.owner,
2897
+ kind: row.kind,
2898
+ replacementKey: row.replacementKey,
2899
+ deprecatedAt: row.deprecatedAt ? row.deprecatedAt.toISOString() : null,
2900
+ removalPlannedAt: row.removalPlannedAt ? row.removalPlannedAt.toISOString() : null,
2901
+ reason: row.reason,
2902
+ i18n: toI18n2(row.i18n),
2903
+ sortOrder: row.sortOrder,
2904
+ createdAt: row.createdAt.toISOString(),
2905
+ updatedAt: row.updatedAt.toISOString(),
2906
+ deletedAt: row.deletedAt ? row.deletedAt.toISOString() : null
2907
+ };
2908
+ }
2909
+ __name(toCapabilityRow, "toCapabilityRow");
2910
+ function toFeatureRow(row) {
2911
+ return {
2912
+ id: row.id,
2913
+ projectKey: row.projectKey,
2914
+ featureKey: row.featureKey,
2915
+ label: row.label,
2916
+ description: row.description,
2917
+ marketingLabel: row.marketingLabel,
2918
+ marketingDescription: row.marketingDescription,
2919
+ icon: row.icon,
2920
+ tier: row.tier,
2921
+ discoveryStatus: row.discoveryStatus,
2922
+ requires: row.requires,
2923
+ replaces: row.replaces,
2924
+ successorKey: row.successorKey,
2925
+ approvedAt: row.approvedAt ? row.approvedAt.toISOString() : null,
2926
+ approvedBy: row.approvedBy,
2927
+ approvedSignature: row.approvedSignature,
2928
+ plannedOnly: row.plannedOnly,
2929
+ core: row.core,
2930
+ i18n: toI18n2(row.i18n),
2931
+ sortOrder: row.sortOrder,
2932
+ createdAt: row.createdAt.toISOString(),
2933
+ updatedAt: row.updatedAt.toISOString(),
2934
+ deletedAt: row.deletedAt ? row.deletedAt.toISOString() : null
2935
+ };
2936
+ }
2937
+ __name(toFeatureRow, "toFeatureRow");
2938
+ function toQuotaRow(row) {
2939
+ return {
2940
+ id: row.id,
2941
+ projectKey: row.projectKey,
2942
+ quotaKey: row.quotaKey,
2943
+ label: row.label,
2944
+ description: row.description,
2945
+ unit: row.unit,
2946
+ featureKey: row.featureKey,
2947
+ usageProvider: row.usageProvider,
2948
+ enforcementMode: row.enforcementMode,
2949
+ discoveryStatus: row.discoveryStatus,
2950
+ replaces: row.replaces,
2951
+ successorKey: row.successorKey,
2952
+ approvedAt: row.approvedAt ? row.approvedAt.toISOString() : null,
2953
+ approvedBy: row.approvedBy,
2954
+ approvedSignature: row.approvedSignature,
2955
+ i18n: toI18n2(row.i18n),
2956
+ sortOrder: row.sortOrder,
2957
+ createdAt: row.createdAt.toISOString(),
2958
+ updatedAt: row.updatedAt.toISOString(),
2959
+ deletedAt: row.deletedAt ? row.deletedAt.toISOString() : null
2960
+ };
2961
+ }
2962
+ __name(toQuotaRow, "toQuotaRow");
2963
+
2964
+ // src/prisma-marketing-projection.repository.ts
2965
+ import { Inject as Inject20, Injectable as Injectable22 } from "@nestjs/common";
2966
+ function _ts_decorate22(decorators, target, key, desc) {
2967
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
2968
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
2969
+ 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;
2970
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
2971
+ }
2972
+ __name(_ts_decorate22, "_ts_decorate");
2973
+ function _ts_metadata20(k, v) {
2974
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
2975
+ }
2976
+ __name(_ts_metadata20, "_ts_metadata");
2977
+ function _ts_param20(paramIndex, decorator) {
2978
+ return function(target, key) {
2979
+ decorator(target, key, paramIndex);
2980
+ };
2981
+ }
2982
+ __name(_ts_param20, "_ts_param");
2983
+ var PrismaMarketingProjectionRepository = class {
2984
+ static {
2985
+ __name(this, "PrismaMarketingProjectionRepository");
2986
+ }
2987
+ prisma;
2988
+ constructor(prisma) {
2989
+ this.prisma = prisma;
2990
+ }
2991
+ get db() {
2992
+ return this.prisma;
2993
+ }
2994
+ async list(filter) {
2995
+ const rows = await this.db.marketingProjection.findMany({
2996
+ where: {
2997
+ projectKey: filter.projectKey,
2998
+ ...filter.targetType ? {
2999
+ targetType: filter.targetType
3000
+ } : {},
3001
+ ...filter.targetVersionId ? {
3002
+ targetVersionId: filter.targetVersionId
3003
+ } : {},
3004
+ ...filter.locale ? {
3005
+ locale: filter.locale
3006
+ } : {}
3007
+ },
3008
+ orderBy: [
3009
+ {
3010
+ priority: "desc"
3011
+ },
3012
+ {
3013
+ displayLabel: "asc"
3014
+ }
3015
+ ]
3016
+ });
3017
+ return rows.map(toRow);
3018
+ }
3019
+ async findById(id) {
3020
+ const row = await this.db.marketingProjection.findUnique({
3021
+ where: {
3022
+ id
3023
+ }
3024
+ });
3025
+ return row ? toRow(row) : null;
3026
+ }
3027
+ async findByTarget(targetType, targetVersionId, locale) {
3028
+ const row = await this.db.marketingProjection.findUnique({
3029
+ where: {
3030
+ targetType_targetVersionId_locale: {
3031
+ targetType,
3032
+ targetVersionId,
3033
+ locale
3034
+ }
3035
+ }
3036
+ });
3037
+ return row ? toRow(row) : null;
3038
+ }
3039
+ async create(data) {
3040
+ const row = await this.db.marketingProjection.create({
3041
+ data: {
3042
+ projectKey: data.projectKey,
3043
+ targetType: data.targetType,
3044
+ targetVersionId: data.targetVersionId,
3045
+ locale: data.locale ?? "de",
3046
+ displayLabel: data.displayLabel,
3047
+ description: data.description,
3048
+ visible: data.visible ?? true,
3049
+ badge: data.badge ?? "",
3050
+ topFeatures: data.topFeatures ?? [],
3051
+ trialEnabled: data.trialEnabled ?? false,
3052
+ trialDays: data.trialDays ?? 30,
3053
+ priceTag: data.priceTag ?? null,
3054
+ ctaLabel: data.ctaLabel ?? null,
3055
+ priority: data.priority ?? 0,
3056
+ highlight: data.highlight ?? false
3057
+ }
3058
+ });
3059
+ return toRow(row);
3060
+ }
3061
+ async update(id, data) {
3062
+ const row = await this.db.marketingProjection.update({
3063
+ where: {
3064
+ id
3065
+ },
3066
+ data: {
3067
+ ...data.displayLabel !== void 0 ? {
3068
+ displayLabel: data.displayLabel
3069
+ } : {},
3070
+ ...data.description !== void 0 ? {
3071
+ description: data.description
3072
+ } : {},
3073
+ ...data.visible !== void 0 ? {
3074
+ visible: data.visible
3075
+ } : {},
3076
+ ...data.badge !== void 0 ? {
3077
+ badge: data.badge
3078
+ } : {},
3079
+ ...data.topFeatures !== void 0 ? {
3080
+ topFeatures: data.topFeatures
3081
+ } : {},
3082
+ ...data.trialEnabled !== void 0 ? {
3083
+ trialEnabled: data.trialEnabled
3084
+ } : {},
3085
+ ...data.trialDays !== void 0 ? {
3086
+ trialDays: data.trialDays
3087
+ } : {},
3088
+ ...data.priceTag !== void 0 ? {
3089
+ priceTag: data.priceTag
3090
+ } : {},
3091
+ ...data.ctaLabel !== void 0 ? {
3092
+ ctaLabel: data.ctaLabel
3093
+ } : {},
3094
+ ...data.priority !== void 0 ? {
3095
+ priority: data.priority
3096
+ } : {},
3097
+ ...data.highlight !== void 0 ? {
3098
+ highlight: data.highlight
3099
+ } : {}
3100
+ }
3101
+ });
3102
+ return toRow(row);
3103
+ }
3104
+ async delete(id) {
3105
+ await this.db.marketingProjection.delete({
3106
+ where: {
3107
+ id
3108
+ }
3109
+ });
3110
+ }
3111
+ };
3112
+ PrismaMarketingProjectionRepository = _ts_decorate22([
3113
+ Injectable22(),
3114
+ _ts_param20(0, Inject20(PRISMA_CLIENT_TOKEN)),
3115
+ _ts_metadata20("design:type", Function),
3116
+ _ts_metadata20("design:paramtypes", [
3117
+ typeof PrismaLike === "undefined" ? Object : PrismaLike
3118
+ ])
3119
+ ], PrismaMarketingProjectionRepository);
3120
+ function toTopFeatures(value) {
3121
+ return Array.isArray(value) ? value : [];
3122
+ }
3123
+ __name(toTopFeatures, "toTopFeatures");
3124
+ function toRow(row) {
3125
+ return {
3126
+ id: row.id,
3127
+ projectKey: row.projectKey,
3128
+ targetType: row.targetType,
3129
+ targetVersionId: row.targetVersionId,
3130
+ locale: row.locale,
3131
+ displayLabel: row.displayLabel,
3132
+ description: row.description,
3133
+ visible: row.visible,
3134
+ badge: row.badge,
3135
+ topFeatures: toTopFeatures(row.topFeatures),
3136
+ trialEnabled: row.trialEnabled,
3137
+ trialDays: row.trialDays,
3138
+ priceTag: row.priceTag,
3139
+ ctaLabel: row.ctaLabel,
3140
+ priority: row.priority,
3141
+ highlight: row.highlight,
3142
+ createdAt: row.createdAt.toISOString(),
3143
+ updatedAt: row.updatedAt.toISOString()
3144
+ };
3145
+ }
3146
+ __name(toRow, "toRow");
3147
+
3148
+ // src/prisma-marketing-settings.repository.ts
3149
+ import { Inject as Inject21, Injectable as Injectable23 } from "@nestjs/common";
3150
+ function _ts_decorate23(decorators, target, key, desc) {
3151
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3152
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
3153
+ 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;
3154
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
3155
+ }
3156
+ __name(_ts_decorate23, "_ts_decorate");
3157
+ function _ts_metadata21(k, v) {
3158
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
3159
+ }
3160
+ __name(_ts_metadata21, "_ts_metadata");
3161
+ function _ts_param21(paramIndex, decorator) {
3162
+ return function(target, key) {
3163
+ decorator(target, key, paramIndex);
3164
+ };
3165
+ }
3166
+ __name(_ts_param21, "_ts_param");
3167
+ var PrismaMarketingSettingsRepository = class {
3168
+ static {
3169
+ __name(this, "PrismaMarketingSettingsRepository");
3170
+ }
3171
+ prisma;
3172
+ constructor(prisma) {
3173
+ this.prisma = prisma;
3174
+ }
3175
+ get db() {
3176
+ return this.prisma;
3177
+ }
3178
+ async get(projectKey) {
3179
+ const row = await this.db.marketingSettings.findUnique({
3180
+ where: {
3181
+ projectKey
3182
+ }
3183
+ });
3184
+ return row ? toRow2(row) : null;
3185
+ }
3186
+ async upsert(projectKey, data) {
3187
+ const row = await this.db.marketingSettings.upsert({
3188
+ where: {
3189
+ projectKey
3190
+ },
3191
+ create: {
3192
+ projectKey,
3193
+ activeLocales: data.activeLocales
3194
+ },
3195
+ update: {
3196
+ activeLocales: data.activeLocales
3197
+ }
3198
+ });
3199
+ return toRow2(row);
3200
+ }
3201
+ };
3202
+ PrismaMarketingSettingsRepository = _ts_decorate23([
3203
+ Injectable23(),
3204
+ _ts_param21(0, Inject21(PRISMA_CLIENT_TOKEN)),
3205
+ _ts_metadata21("design:type", Function),
3206
+ _ts_metadata21("design:paramtypes", [
3207
+ typeof PrismaLike === "undefined" ? Object : PrismaLike
3208
+ ])
3209
+ ], PrismaMarketingSettingsRepository);
3210
+ function toRow2(row) {
3211
+ return {
3212
+ projectKey: row.projectKey,
3213
+ activeLocales: toStringArray(row.activeLocales),
3214
+ updatedAt: row.updatedAt.toISOString()
3215
+ };
3216
+ }
3217
+ __name(toRow2, "toRow");
3218
+
3219
+ // src/prisma-promotion.repository.ts
3220
+ import { Inject as Inject22, Injectable as Injectable24 } from "@nestjs/common";
3221
+ function _ts_decorate24(decorators, target, key, desc) {
3222
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3223
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
3224
+ 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;
3225
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
3226
+ }
3227
+ __name(_ts_decorate24, "_ts_decorate");
3228
+ function _ts_metadata22(k, v) {
3229
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
3230
+ }
3231
+ __name(_ts_metadata22, "_ts_metadata");
3232
+ function _ts_param22(paramIndex, decorator) {
3233
+ return function(target, key) {
3234
+ decorator(target, key, paramIndex);
3235
+ };
3236
+ }
3237
+ __name(_ts_param22, "_ts_param");
3238
+ var PrismaPromotionRepository = class {
3239
+ static {
3240
+ __name(this, "PrismaPromotionRepository");
3241
+ }
3242
+ prisma;
3243
+ constructor(prisma) {
3244
+ this.prisma = prisma;
3245
+ }
3246
+ get db() {
3247
+ return this.prisma;
3248
+ }
3249
+ async list(filter) {
3250
+ const rows = await this.db.promotion.findMany({
3251
+ where: {
3252
+ projectKey: filter.projectKey
3253
+ },
3254
+ orderBy: [
3255
+ {
3256
+ validFrom: "desc"
3257
+ }
3258
+ ]
3259
+ });
3260
+ return rows.map(toRow3);
3261
+ }
3262
+ async findById(id) {
3263
+ const row = await this.db.promotion.findUnique({
3264
+ where: {
3265
+ id
3266
+ }
3267
+ });
3268
+ return row ? toRow3(row) : null;
3269
+ }
3270
+ async create(data) {
3271
+ const row = await this.db.promotion.create({
3272
+ data: {
3273
+ projectKey: data.projectKey,
3274
+ internalLabel: data.internalLabel,
3275
+ type: data.type,
3276
+ value: data.value,
3277
+ targetType: data.targetType ?? "PLAN",
3278
+ appliesTo: data.appliesTo ?? [],
3279
+ billingCycle: data.billingCycle ?? "both",
3280
+ validFrom: new Date(data.validFrom),
3281
+ validTo: new Date(data.validTo),
3282
+ priority: data.priority ?? 0,
3283
+ requiresCoupon: data.requiresCoupon ?? false,
3284
+ codes: data.codes ?? [],
3285
+ color: data.color ?? "#2563eb",
3286
+ i18n: data.i18n ?? {},
3287
+ // Null/undefined restriction is left off so the nullable column
3288
+ // stays SQL NULL (= all locales).
3289
+ ...Array.isArray(data.onlyLocales) ? {
3290
+ onlyLocales: data.onlyLocales
3291
+ } : {}
3292
+ }
3293
+ });
3294
+ return toRow3(row);
3295
+ }
3296
+ async update(id, data) {
3297
+ if (data.onlyLocales === null) {
3298
+ await this.prisma.$executeRaw`
3299
+ UPDATE promotions SET "onlyLocales" = NULL, "updatedAt" = NOW() WHERE id = ${id}`;
3300
+ }
3301
+ const row = await this.db.promotion.update({
3302
+ where: {
3303
+ id
3304
+ },
3305
+ data: {
3306
+ ...data.internalLabel !== void 0 ? {
3307
+ internalLabel: data.internalLabel
3308
+ } : {},
3309
+ ...data.type !== void 0 ? {
3310
+ type: data.type
3311
+ } : {},
3312
+ ...data.value !== void 0 ? {
3313
+ value: data.value
3314
+ } : {},
3315
+ ...data.appliesTo !== void 0 ? {
3316
+ appliesTo: data.appliesTo
3317
+ } : {},
3318
+ ...data.targetType !== void 0 ? {
3319
+ targetType: data.targetType
3320
+ } : {},
3321
+ ...data.billingCycle !== void 0 ? {
3322
+ billingCycle: data.billingCycle
3323
+ } : {},
3324
+ ...data.validFrom !== void 0 ? {
3325
+ validFrom: new Date(data.validFrom)
3326
+ } : {},
3327
+ ...data.validTo !== void 0 ? {
3328
+ validTo: new Date(data.validTo)
3329
+ } : {},
3330
+ ...data.priority !== void 0 ? {
3331
+ priority: data.priority
3332
+ } : {},
3333
+ ...data.requiresCoupon !== void 0 ? {
3334
+ requiresCoupon: data.requiresCoupon
3335
+ } : {},
3336
+ ...data.codes !== void 0 ? {
3337
+ codes: data.codes
3338
+ } : {},
3339
+ ...data.color !== void 0 ? {
3340
+ color: data.color
3341
+ } : {},
3342
+ ...data.i18n !== void 0 ? {
3343
+ i18n: data.i18n
3344
+ } : {},
3345
+ ...Array.isArray(data.onlyLocales) ? {
3346
+ onlyLocales: data.onlyLocales
3347
+ } : {}
3348
+ }
3349
+ });
3350
+ return toRow3(row);
3351
+ }
3352
+ async delete(id) {
3353
+ await this.db.promotion.delete({
3354
+ where: {
3355
+ id
3356
+ }
3357
+ });
3358
+ }
3359
+ };
3360
+ PrismaPromotionRepository = _ts_decorate24([
3361
+ Injectable24(),
3362
+ _ts_param22(0, Inject22(PRISMA_CLIENT_TOKEN)),
3363
+ _ts_metadata22("design:type", Function),
3364
+ _ts_metadata22("design:paramtypes", [
3365
+ typeof PrismaLike === "undefined" ? Object : PrismaLike
3366
+ ])
3367
+ ], PrismaPromotionRepository);
3368
+ function toPromotionValue(value) {
3369
+ if (typeof value === "number") return value;
3370
+ if (value !== null && typeof value === "object" && !Array.isArray(value)) {
3371
+ const obj = value;
3372
+ return {
3373
+ price: Number(obj.price),
3374
+ months: Number(obj.months)
3375
+ };
3376
+ }
3377
+ throw new Error(`Promotion.value has an unexpected shape: ${JSON.stringify(value)}`);
3378
+ }
3379
+ __name(toPromotionValue, "toPromotionValue");
3380
+ function toNullableStringArray(value) {
3381
+ return Array.isArray(value) ? value : null;
3382
+ }
3383
+ __name(toNullableStringArray, "toNullableStringArray");
3384
+ function toPromotionI18n(value) {
3385
+ if (value !== null && typeof value === "object" && !Array.isArray(value)) {
3386
+ return value;
3387
+ }
3388
+ return {};
3389
+ }
3390
+ __name(toPromotionI18n, "toPromotionI18n");
3391
+ function toRow3(row) {
3392
+ return {
3393
+ id: row.id,
3394
+ projectKey: row.projectKey,
3395
+ internalLabel: row.internalLabel,
3396
+ type: row.type,
3397
+ value: toPromotionValue(row.value),
3398
+ appliesTo: toStringArray(row.appliesTo),
3399
+ targetType: row.targetType,
3400
+ billingCycle: row.billingCycle,
3401
+ validFrom: row.validFrom.toISOString().slice(0, 10),
3402
+ validTo: row.validTo.toISOString().slice(0, 10),
3403
+ priority: row.priority,
3404
+ onlyLocales: toNullableStringArray(row.onlyLocales),
3405
+ requiresCoupon: row.requiresCoupon,
3406
+ codes: toStringArray(row.codes),
3407
+ color: row.color,
3408
+ i18n: toPromotionI18n(row.i18n),
3409
+ createdAt: row.createdAt.toISOString(),
3410
+ updatedAt: row.updatedAt.toISOString()
3411
+ };
3412
+ }
3413
+ __name(toRow3, "toRow");
3414
+
3415
+ // src/prisma-subscription-contract.repository.ts
3416
+ import { Inject as Inject23, Injectable as Injectable25 } from "@nestjs/common";
3417
+ function _ts_decorate25(decorators, target, key, desc) {
3418
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3419
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
3420
+ 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;
3421
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
3422
+ }
3423
+ __name(_ts_decorate25, "_ts_decorate");
3424
+ function _ts_metadata23(k, v) {
3425
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
3426
+ }
3427
+ __name(_ts_metadata23, "_ts_metadata");
3428
+ function _ts_param23(paramIndex, decorator) {
3429
+ return function(target, key) {
3430
+ decorator(target, key, paramIndex);
3431
+ };
3432
+ }
3433
+ __name(_ts_param23, "_ts_param");
3434
+ var ACTIVE_CONTRACT_STATUSES = [
3435
+ "active",
3436
+ "scheduled"
3437
+ ];
3438
+ var PrismaSubscriptionContractRepository = class {
3439
+ static {
3440
+ __name(this, "PrismaSubscriptionContractRepository");
3441
+ }
3442
+ prisma;
3443
+ constructor(prisma) {
3444
+ this.prisma = prisma;
3445
+ }
3446
+ get db() {
3447
+ return this.prisma;
3448
+ }
3449
+ async list(filter) {
3450
+ const rows = await this.db.subscriptionContract.findMany({
3451
+ where: {
3452
+ ...filter.projectKey ? {
3453
+ projectKey: filter.projectKey
3454
+ } : {},
3455
+ ...filter.tenantId ? {
3456
+ tenantId: filter.tenantId
3457
+ } : {},
3458
+ ...filter.status ? {
3459
+ status: filter.status
3460
+ } : {},
3461
+ ...filter.asOf ? {
3462
+ effectiveFrom: {
3463
+ lte: filter.asOf
3464
+ },
3465
+ OR: [
3466
+ {
3467
+ effectiveUntil: null
3468
+ },
3469
+ {
3470
+ effectiveUntil: {
3471
+ gt: filter.asOf
3472
+ }
3473
+ }
3474
+ ]
3475
+ } : {}
3476
+ },
3477
+ include: {
3478
+ lineItems: true
3479
+ },
3480
+ orderBy: [
3481
+ {
3482
+ effectiveFrom: "desc"
3483
+ },
3484
+ {
3485
+ createdAt: "desc"
3486
+ }
3487
+ ]
3488
+ });
3489
+ return rows.map(toRecord4);
3490
+ }
3491
+ async findById(contractId) {
3492
+ const row = await this.db.subscriptionContract.findUnique({
3493
+ where: {
3494
+ id: contractId
3495
+ },
3496
+ include: {
3497
+ lineItems: true
3498
+ }
3499
+ });
3500
+ return row ? toRecord4(row) : null;
3501
+ }
3502
+ async findActiveByTenantId(tenantId, asOf = /* @__PURE__ */ new Date()) {
3503
+ const row = await this.db.subscriptionContract.findFirst({
3504
+ where: {
3505
+ tenantId,
3506
+ status: {
3507
+ in: ACTIVE_CONTRACT_STATUSES
3508
+ },
3509
+ effectiveFrom: {
3510
+ lte: asOf
3511
+ },
3512
+ OR: [
3513
+ {
3514
+ effectiveUntil: null
3515
+ },
3516
+ {
3517
+ effectiveUntil: {
3518
+ gt: asOf
3519
+ }
3520
+ }
3521
+ ]
3522
+ },
3523
+ include: {
3524
+ lineItems: true
3525
+ },
3526
+ orderBy: [
3527
+ {
3528
+ effectiveFrom: "desc"
3529
+ },
3530
+ {
3531
+ createdAt: "desc"
3532
+ }
3533
+ ]
3534
+ });
3535
+ return row ? toRecord4(row) : null;
3536
+ }
3537
+ async create(data) {
3538
+ const row = await this.db.subscriptionContract.create({
3539
+ data: {
3540
+ projectKey: data.projectKey,
3541
+ tenantId: data.tenantId,
3542
+ status: data.status ?? "active",
3543
+ effectiveFrom: data.effectiveFrom,
3544
+ effectiveUntil: data.effectiveUntil ?? null,
3545
+ originalOfferId: data.originalOfferId ?? null,
3546
+ originalPlanVersionId: data.originalPlanVersionId ?? null,
3547
+ originalBundleVersionIds: data.originalBundleVersionIds ?? [],
3548
+ priceSnapshot: data.priceSnapshot,
3549
+ promotionSnapshots: data.promotionSnapshots ?? [],
3550
+ promoCodeSnapshots: data.promoCodeSnapshots ?? [],
3551
+ // Nullable JSON columns are omitted when absent so they stay SQL
3552
+ // NULL (the DbNull sentinel is not available in this package).
3553
+ ...data.entitlementSnapshot != null ? {
3554
+ entitlementSnapshot: data.entitlementSnapshot
3555
+ } : {},
3556
+ ...data.termsSnapshot != null ? {
3557
+ termsSnapshot: data.termsSnapshot
3558
+ } : {},
3559
+ lineItems: {
3560
+ create: data.lineItems.map(toLineItemCreate)
3561
+ }
3562
+ },
3563
+ include: {
3564
+ lineItems: true
3565
+ }
3566
+ });
3567
+ return toRecord4(row);
3568
+ }
3569
+ async terminate(contractId, data) {
3570
+ const row = await this.db.subscriptionContract.update({
3571
+ where: {
3572
+ id: contractId
3573
+ },
3574
+ data: {
3575
+ effectiveUntil: data.effectiveUntil,
3576
+ status: data.status
3577
+ },
3578
+ include: {
3579
+ lineItems: true
3580
+ }
3581
+ });
3582
+ return toRecord4(row);
3583
+ }
3584
+ };
3585
+ PrismaSubscriptionContractRepository = _ts_decorate25([
3586
+ Injectable25(),
3587
+ _ts_param23(0, Inject23(PRISMA_CLIENT_TOKEN)),
3588
+ _ts_metadata23("design:type", Function),
3589
+ _ts_metadata23("design:paramtypes", [
3590
+ typeof PrismaLike === "undefined" ? Object : PrismaLike
3591
+ ])
3592
+ ], PrismaSubscriptionContractRepository);
3593
+ function toLineItemCreate(item) {
3594
+ return {
3595
+ kind: item.kind,
3596
+ sourceKey: item.sourceKey,
3597
+ sourceVersionId: item.sourceVersionId ?? null,
3598
+ titleSnapshot: item.titleSnapshot,
3599
+ descriptionSnapshot: item.descriptionSnapshot ?? null,
3600
+ quantity: item.quantity,
3601
+ unit: item.unit ?? null,
3602
+ priceNet: item.priceNet,
3603
+ priceGross: item.priceGross,
3604
+ billingCycle: item.billingCycle,
3605
+ minimumTermUntil: item.minimumTermUntil ?? null,
3606
+ featuresSnapshot: item.featuresSnapshot,
3607
+ quotaEffectsSnapshot: item.quotaEffectsSnapshot,
3608
+ ...item.metadata != null ? {
3609
+ metadata: item.metadata
3610
+ } : {}
3611
+ };
3612
+ }
3613
+ __name(toLineItemCreate, "toLineItemCreate");
3614
+ function isPlainObject2(value) {
3615
+ return value !== null && typeof value === "object" && !Array.isArray(value);
3616
+ }
3617
+ __name(isPlainObject2, "isPlainObject");
3618
+ function toUnknownArray(value) {
3619
+ return Array.isArray(value) ? value : [];
3620
+ }
3621
+ __name(toUnknownArray, "toUnknownArray");
3622
+ function toRecordOrNull(value) {
3623
+ return isPlainObject2(value) ? value : null;
3624
+ }
3625
+ __name(toRecordOrNull, "toRecordOrNull");
3626
+ function toLineItem(row) {
3627
+ return {
3628
+ id: row.id,
3629
+ contractId: row.contractId,
3630
+ kind: row.kind,
3631
+ sourceKey: row.sourceKey,
3632
+ sourceVersionId: row.sourceVersionId,
3633
+ titleSnapshot: row.titleSnapshot,
3634
+ descriptionSnapshot: row.descriptionSnapshot,
3635
+ quantity: row.quantity,
3636
+ unit: row.unit,
3637
+ priceNet: Number(row.priceNet),
3638
+ priceGross: Number(row.priceGross),
3639
+ billingCycle: row.billingCycle,
3640
+ minimumTermUntil: row.minimumTermUntil,
3641
+ featuresSnapshot: toStringArray(row.featuresSnapshot),
3642
+ quotaEffectsSnapshot: toQuotaMap(row.quotaEffectsSnapshot),
3643
+ metadata: toRecordOrNull(row.metadata),
3644
+ createdAt: row.createdAt
3645
+ };
3646
+ }
3647
+ __name(toLineItem, "toLineItem");
3648
+ function toRecord4(row) {
3649
+ return {
3650
+ id: row.id,
3651
+ projectKey: row.projectKey,
3652
+ tenantId: row.tenantId,
3653
+ status: row.status,
3654
+ effectiveFrom: row.effectiveFrom,
3655
+ effectiveUntil: row.effectiveUntil,
3656
+ originalOfferId: row.originalOfferId,
3657
+ originalPlanVersionId: row.originalPlanVersionId,
3658
+ originalBundleVersionIds: toStringArray(row.originalBundleVersionIds),
3659
+ entitlementSnapshot: isPlainObject2(row.entitlementSnapshot) ? row.entitlementSnapshot : null,
3660
+ priceSnapshot: row.priceSnapshot,
3661
+ promotionSnapshots: toUnknownArray(row.promotionSnapshots),
3662
+ promoCodeSnapshots: toUnknownArray(row.promoCodeSnapshots),
3663
+ termsSnapshot: toRecordOrNull(row.termsSnapshot),
3664
+ lineItems: row.lineItems.map(toLineItem),
3665
+ createdAt: row.createdAt,
3666
+ updatedAt: row.updatedAt
3667
+ };
3668
+ }
3669
+ __name(toRecord4, "toRecord");
1420
3670
  export {
1421
3671
  AsyncLocalRlsBypassAdapter,
1422
3672
  PASSWORD_HASHER_TOKEN,
@@ -1424,16 +3674,25 @@ export {
1424
3674
  PrismaAuditAdapter,
1425
3675
  PrismaAuditQueryAdapter,
1426
3676
  PrismaAuditStatsAdapter,
3677
+ PrismaBundleRepository,
3678
+ PrismaCatalogEntryRepository,
3679
+ PrismaMarketingProjectionRepository,
3680
+ PrismaMarketingSettingsRepository,
1427
3681
  PrismaMfaAdapter,
1428
3682
  PrismaPlanCatalogImportSink,
1429
3683
  PrismaPlanCatalogReadSink,
3684
+ PrismaPlanRepository,
1430
3685
  PrismaPlanVersionRepository,
1431
3686
  PrismaPromoCodeRedemptionRepository,
1432
3687
  PrismaPromoCodeRepository,
1433
3688
  PrismaPromoCodeValidationLogRepository,
1434
3689
  PrismaPromoSubscriptionLookup,
3690
+ PrismaPromotionRepository,
3691
+ PrismaSubscriptionBundleRepository,
3692
+ PrismaSubscriptionContractRepository,
1435
3693
  PrismaSubscriptionRepository,
1436
3694
  PrismaSuperAdminBootstrapAdapter,
3695
+ PrismaTenantSubscriptionWriteAdapter,
1437
3696
  PrismaTransactionRunner,
1438
3697
  ZeroPromoRevenueDeductionAggregator,
1439
3698
  buildActorTag,