@saasicat/core 1.0.0-rc.6 → 1.0.0-rc.7

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/README.md CHANGED
@@ -74,5 +74,6 @@ Produces `dist/index.{js,cjs,d.ts,d.cts}` via `tsup`.
74
74
  ## Next
75
75
 
76
76
  - [The vocabulary](../../docs/explanation/concepts.md) — capability, feature, quota, plan, contract
77
- - [Codegen](../../docs/explanation/adr/0006-spec-to-types-codegen.md) — what is generated, and what is not
77
+ - [Codegen](../../docs/explanation/adr/0006-spec-to-types-codegen.md) — what is generated, and what
78
+ is not
78
79
  - [`@saasicat/spec`](../spec/README.md) — the schemas these types come from
package/dist/.build-stamp CHANGED
@@ -1 +1 @@
1
- 0c786c82cbbbdc8c75e264412f0eb8783769f233ca44e937e497a3d7992a54da
1
+ 9ad6205a66054b865cdec958983f004f58c3ac359b6eedffa9c8bfa91414741d
package/dist/index.cjs CHANGED
@@ -20,8 +20,10 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/index.ts
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
+ ACTIVE_SUBSCRIPTION_CONTRACT_STATUSES: () => ACTIVE_SUBSCRIPTION_CONTRACT_STATUSES,
23
24
  AUTH_ERROR_CODES: () => AUTH_ERROR_CODES,
24
25
  BILLING_ERROR_CODES: () => BILLING_ERROR_CODES,
26
+ BUNDLE_PRICE_LOOKUP_LIMIT: () => BUNDLE_PRICE_LOOKUP_LIMIT,
25
27
  CATALOG_ERROR_CODES: () => CATALOG_ERROR_CODES,
26
28
  CONTRACT_ERROR_CODES: () => CONTRACT_ERROR_CODES,
27
29
  ERROR_MESSAGES_DE: () => ERROR_MESSAGES_DE,
@@ -50,21 +52,30 @@ __export(index_exports, {
50
52
  buildActivePlanVersionWhere: () => buildActivePlanVersionWhere,
51
53
  buildActiveVersionWhere: () => buildActiveVersionWhere,
52
54
  buildFeatureRequiresIndex: () => buildFeatureRequiresIndex,
55
+ bundleDraftDefaults: () => bundleDraftDefaults,
56
+ bundleStemDefaults: () => bundleStemDefaults,
53
57
  classifyBundleVersionDiff: () => classifyBundleVersionDiff,
54
58
  classifyPlanDiff: () => classifyPlanDiff,
55
59
  collectUnsatisfiedRequires: () => collectUnsatisfiedRequires,
56
60
  coverageExcludingSelf: () => coverageExcludingSelf,
61
+ definedFields: () => definedFields,
57
62
  formatErrorMessage: () => formatErrorMessage,
58
63
  isBundleRedundant: () => isBundleRedundant,
59
64
  isPlatformUserExistsError: () => isPlatformUserExistsError,
60
65
  isVersionEditable: () => isVersionEditable,
61
66
  missingRequiresFor: () => missingRequiresFor,
62
67
  pickActivePromo: () => pickActivePromo,
68
+ previousUtcDay: () => previousUtcDay,
63
69
  promoStatus: () => promoStatus,
64
70
  resolveBundleAvailability: () => resolveBundleAvailability,
65
71
  resolveErrorMessage: () => resolveErrorMessage,
66
72
  selectChargeableBundles: () => selectChargeableBundles,
67
- startOfUtcDay: () => startOfUtcDay
73
+ startOfUtcDay: () => startOfUtcDay,
74
+ toBundleStemRow: () => toBundleStemRow,
75
+ toContractLineItemRecord: () => toContractLineItemRecord,
76
+ toPlanRow: () => toPlanRow,
77
+ toPlanVersionRow: () => toPlanVersionRow,
78
+ toSubscriptionContractRecord: () => toSubscriptionContractRecord
68
79
  });
69
80
  module.exports = __toCommonJS(index_exports);
70
81
 
@@ -72,6 +83,11 @@ module.exports = __toCommonJS(index_exports);
72
83
  function startOfUtcDay(date) {
73
84
  return new Date(Date.UTC(date.getUTCFullYear(), date.getUTCMonth(), date.getUTCDate()));
74
85
  }
86
+ function previousUtcDay(value) {
87
+ const result = new Date(value);
88
+ result.setUTCDate(result.getUTCDate() - 1);
89
+ return result;
90
+ }
75
91
  function buildActivePlanVersionWhere(asOf, options = {}) {
76
92
  const asOfDayStart = startOfUtcDay(asOf);
77
93
  const validityWindow = [
@@ -88,6 +104,53 @@ function buildActivePlanVersionWhere(asOf, options = {}) {
88
104
  }
89
105
  var buildActiveVersionWhere = buildActivePlanVersionWhere;
90
106
 
107
+ // src/bundle-draft-defaults.ts
108
+ function bundleDraftDefaults(data) {
109
+ return {
110
+ baseVersionId: data.baseVersionId ?? null,
111
+ features: data.features,
112
+ quotas: data.quotas ?? {},
113
+ compatibility: data.compatibility ?? {},
114
+ pricingOverrides: data.pricingOverrides ?? [],
115
+ monthlyNet: data.monthlyNet ?? null,
116
+ yearlyNet: data.yearlyNet ?? null,
117
+ marketed: data.marketed ?? true,
118
+ changeNote: data.changeNote ?? "",
119
+ createdByUserId: data.createdByUserId ?? null
120
+ };
121
+ }
122
+ function bundleStemDefaults(data) {
123
+ return {
124
+ bundleKey: data.bundleKey,
125
+ label: data.label,
126
+ description: data.description ?? null,
127
+ icon: data.icon ?? null,
128
+ sortOrder: data.sortOrder ?? 0,
129
+ i18n: data.i18n ?? {}
130
+ };
131
+ }
132
+ function toBundleStemRow(row) {
133
+ return {
134
+ id: row.id,
135
+ bundleKey: row.bundleKey,
136
+ label: row.label,
137
+ description: row.description,
138
+ icon: row.icon,
139
+ sortOrder: row.sortOrder,
140
+ i18n: row.i18n !== null && typeof row.i18n === "object" && !Array.isArray(row.i18n) ? row.i18n : {},
141
+ createdAt: row.createdAt.toISOString(),
142
+ updatedAt: row.updatedAt.toISOString(),
143
+ deletedAt: row.deletedAt?.toISOString() ?? null
144
+ };
145
+ }
146
+ function definedFields(data, keys) {
147
+ const patch = {};
148
+ for (const key of keys) {
149
+ if (data[key] !== void 0) patch[key] = data[key];
150
+ }
151
+ return patch;
152
+ }
153
+
91
154
  // src/catalog-entry.types.ts
92
155
  var MARKETING_PRIORITY_MIN = 0;
93
156
  var MARKETING_PRIORITY_MAX = 1e4;
@@ -343,6 +406,8 @@ var CATALOG_ERROR_CODES = {
343
406
  BUNDLE_VERSION_SUPERSEDED: "BUNDLE_VERSION_SUPERSEDED",
344
407
  BUNDLE_VERSION_REGRESSION: "BUNDLE_VERSION_REGRESSION",
345
408
  BUNDLE_VERSION_ZERO_PRICE: "BUNDLE_VERSION_ZERO_PRICE",
409
+ BUNDLE_VERSION_NO_PRICE: "BUNDLE_VERSION_NO_PRICE",
410
+ BUNDLE_VERSION_NOT_PRICED_FOR_PLAN: "BUNDLE_VERSION_NOT_PRICED_FOR_PLAN",
346
411
  BUNDLE_VERSION_DISCARD_NOT_IMPLEMENTED: "BUNDLE_VERSION_DISCARD_NOT_IMPLEMENTED",
347
412
  BUNDLE_VERSION_VALID_FROM_REQUIRED: "BUNDLE_VERSION_VALID_FROM_REQUIRED",
348
413
  BUNDLE_VERSION_VALID_FROM_INVALID: "BUNDLE_VERSION_VALID_FROM_INVALID",
@@ -389,6 +454,8 @@ var BILLING_ERROR_CODES = {
389
454
  BUNDLE_ALREADY_SUBSCRIBED: "BUNDLE_ALREADY_SUBSCRIBED",
390
455
  BUNDLE_INCOMPATIBLE_WITH_PLAN: "BUNDLE_INCOMPATIBLE_WITH_PLAN",
391
456
  BUNDLE_NOT_SELF_SERVICE: "BUNDLE_NOT_SELF_SERVICE",
457
+ BUNDLE_CYCLE_EXCEEDS_PLAN: "BUNDLE_CYCLE_EXCEEDS_PLAN",
458
+ BUNDLE_NOT_PRICED_FOR_THIS_PLAN: "BUNDLE_NOT_PRICED_FOR_THIS_PLAN",
392
459
  SUBSCRIPTION_BUNDLE_ALREADY_CANCELLED: "SUBSCRIPTION_BUNDLE_ALREADY_CANCELLED",
393
460
  SUBSCRIPTION_BUNDLE_NOT_CANCELLED: "SUBSCRIPTION_BUNDLE_NOT_CANCELLED",
394
461
  SUBSCRIPTION_BUNDLE_CANCELLATION_EFFECTIVE: "SUBSCRIPTION_BUNDLE_CANCELLATION_EFFECTIVE",
@@ -595,6 +662,137 @@ var REGISTRATION_STEP_BY_STATUS = {
595
662
  };
596
663
  var REGISTRATION_RESUME_TTL_MINUTES = 60;
597
664
 
665
+ // src/plan-mapping.ts
666
+ function toPlanRow(row) {
667
+ return {
668
+ id: row.id,
669
+ planKey: row.planKey,
670
+ label: row.label,
671
+ description: row.description,
672
+ icon: row.icon,
673
+ sortOrder: row.sortOrder,
674
+ createdAt: row.createdAt.toISOString(),
675
+ updatedAt: row.updatedAt.toISOString(),
676
+ deletedAt: toIsoOrNull(row.deletedAt)
677
+ };
678
+ }
679
+ function toPlanVersionRow(row, planKey, fields) {
680
+ const mapped = {
681
+ id: row.id,
682
+ version: row.version,
683
+ baseVersionId: row.baseVersionId,
684
+ planId: planKey,
685
+ features: toFeatureKeys(row.features),
686
+ quotas: toQuotaEffects(row.quotas),
687
+ monthlyNet: String(row.monthlyNet),
688
+ yearlyNet: String(row.yearlyNet),
689
+ marketed: row.marketed,
690
+ publishedAt: toIsoOrNull(row.publishedAt),
691
+ supersededAt: toIsoOrNull(row.supersededAt),
692
+ publishedChanges: Array.isArray(row.publishedChanges) ? row.publishedChanges : null,
693
+ changeNote: row.changeNote,
694
+ nonRegressive: row.nonRegressive,
695
+ validFrom: fields.validityWindows ? toIsoOrNull(row.validFrom) : null,
696
+ validUntil: fields.validityWindows ? toIsoOrNull(row.validUntil) : null,
697
+ createdByUserId: row.createdByUserId,
698
+ publishedByUserId: row.publishedByUserId,
699
+ createdAt: row.createdAt.toISOString(),
700
+ updatedAt: row.updatedAt.toISOString()
701
+ };
702
+ if (fields.endsAt) {
703
+ mapped.endsAt = toIsoOrNull(row.endsAt);
704
+ }
705
+ return mapped;
706
+ }
707
+ function toIsoOrNull(value) {
708
+ return value ? value.toISOString() : null;
709
+ }
710
+ function toFeatureKeys(value) {
711
+ if (!Array.isArray(value)) return [];
712
+ return value.filter((entry) => typeof entry === "string");
713
+ }
714
+ function toQuotaEffects(value) {
715
+ if (value === null || typeof value !== "object" || Array.isArray(value)) {
716
+ return {};
717
+ }
718
+ const quotas = {};
719
+ for (const [key, entry] of Object.entries(value)) {
720
+ if (typeof entry === "number") quotas[key] = entry;
721
+ }
722
+ return quotas;
723
+ }
724
+
725
+ // src/subscription-contract-mapping.ts
726
+ function toSubscriptionContractRecord(row, lineItems) {
727
+ return {
728
+ id: row.id,
729
+ tenantId: row.tenantId,
730
+ status: row.status,
731
+ effectiveFrom: row.effectiveFrom,
732
+ effectiveUntil: row.effectiveUntil,
733
+ originalOfferId: row.originalOfferId,
734
+ originalPlanVersionId: row.originalPlanVersionId,
735
+ originalBundleVersionIds: toStringArray(row.originalBundleVersionIds),
736
+ entitlementSnapshot: isPlainObject(row.entitlementSnapshot) ? row.entitlementSnapshot : null,
737
+ priceSnapshot: row.priceSnapshot,
738
+ promotionSnapshots: toUnknownArray(row.promotionSnapshots),
739
+ promoCodeSnapshots: toUnknownArray(row.promoCodeSnapshots),
740
+ termsSnapshot: toRecordOrNull(row.termsSnapshot),
741
+ lineItems: lineItems.map(toContractLineItemRecord),
742
+ createdAt: row.createdAt,
743
+ updatedAt: row.updatedAt
744
+ };
745
+ }
746
+ function toContractLineItemRecord(row) {
747
+ return {
748
+ id: row.id,
749
+ contractId: row.contractId,
750
+ kind: row.kind,
751
+ sourceKey: row.sourceKey,
752
+ sourceVersionId: row.sourceVersionId,
753
+ titleSnapshot: row.titleSnapshot,
754
+ descriptionSnapshot: row.descriptionSnapshot,
755
+ quantity: row.quantity,
756
+ unit: row.unit,
757
+ priceNet: Number(row.priceNet),
758
+ priceGross: Number(row.priceGross),
759
+ billingCycle: row.billingCycle,
760
+ minimumTermUntil: row.minimumTermUntil,
761
+ featuresSnapshot: toStringArray(row.featuresSnapshot),
762
+ quotaEffectsSnapshot: toQuotaEffects2(row.quotaEffectsSnapshot),
763
+ metadata: toRecordOrNull(row.metadata),
764
+ createdAt: row.createdAt
765
+ };
766
+ }
767
+ function isPlainObject(value) {
768
+ return value !== null && typeof value === "object" && !Array.isArray(value);
769
+ }
770
+ function toUnknownArray(value) {
771
+ return Array.isArray(value) ? value : [];
772
+ }
773
+ function toRecordOrNull(value) {
774
+ return isPlainObject(value) ? value : null;
775
+ }
776
+ function toStringArray(value) {
777
+ if (!Array.isArray(value)) return [];
778
+ return value.filter((entry) => typeof entry === "string");
779
+ }
780
+ function toQuotaEffects2(value) {
781
+ if (!isPlainObject(value)) return {};
782
+ const effects = {};
783
+ for (const [key, entry] of Object.entries(value)) {
784
+ if (typeof entry === "number") effects[key] = entry;
785
+ }
786
+ return effects;
787
+ }
788
+
789
+ // src/subscription-contract.types.ts
790
+ var BUNDLE_PRICE_LOOKUP_LIMIT = 200;
791
+ var ACTIVE_SUBSCRIPTION_CONTRACT_STATUSES = [
792
+ "active",
793
+ "scheduled"
794
+ ];
795
+
598
796
  // src/version-editability.ts
599
797
  function isVersionEditable(v, now = /* @__PURE__ */ new Date()) {
600
798
  if (v.publishedAt === null) {
@@ -666,6 +864,8 @@ var ERROR_MESSAGES_EN = {
666
864
  BUNDLE_VERSION_SUPERSEDED: "BundleVersion '{bundleVersionId}' has been superseded by a newer version.",
667
865
  BUNDLE_VERSION_REGRESSION: "This bundle version is regressive (feature removed / quota lowered / price raised). Publishing requires an explicit `forceRegressive: true` (UI confirmation dialog with MFA).",
668
866
  BUNDLE_VERSION_ZERO_PRICE: "A bundle version cannot be published with an explicit price of 0.00 (guard against seed placeholders). For free bundles leave it null, or set allowZeroPrice.",
867
+ BUNDLE_VERSION_NO_PRICE: "This bundle version cannot be published without a price: neither a base price nor any plan override resolves one.",
868
+ BUNDLE_VERSION_NOT_PRICED_FOR_PLAN: "This bundle is offered to plan '{planKey}', which is sold {billingCycle}, and no {billingCycle} price resolves for it \u2014 neither a base price nor a plan override.",
669
869
  BUNDLE_VERSION_DISCARD_NOT_IMPLEMENTED: "Discard is not implemented in the current repository. Implement BundleRepository.deleteDraft.",
670
870
  BUNDLE_VERSION_VALID_FROM_REQUIRED: "Published bundle versions must keep a validFrom. Set a new future date, or edit the draft before publishing.",
671
871
  BUNDLE_VERSION_VALID_FROM_INVALID: "validFrom '{validFrom}' is not a valid date",
@@ -679,12 +879,12 @@ var ERROR_MESSAGES_EN = {
679
879
  PLAN_VERSION_NOT_FOUND: "PlanVersion '{versionId}' not found",
680
880
  BUNDLE_NOT_FOUND: "Bundle '{bundleId}' not found",
681
881
  BUNDLE_VERSION_NOT_FOUND: "BundleVersion '{bundleVersionId}' not found",
682
- FEATURE_NOT_FOUND: "Feature '{featureKey}' not found in project '{projectKey}'",
683
- QUOTA_NOT_FOUND: "Quota '{quotaKey}' not found in project '{projectKey}'",
882
+ FEATURE_NOT_FOUND: "Feature '{featureKey}' not found",
883
+ QUOTA_NOT_FOUND: "Quota '{quotaKey}' not found",
684
884
  PROMOTION_NOT_FOUND: "Promotion '{promotionId}' not found",
685
885
  MARKETING_PROJECTION_NOT_FOUND: "MarketingProjection '{projectionId}' not found",
686
- PLAN_ALREADY_EXISTS: "Plan '{planKey}' already exists in project '{projectKey}'",
687
- BUNDLE_ALREADY_EXISTS: "Bundle '{bundleKey}' already exists in project '{projectKey}'",
886
+ PLAN_ALREADY_EXISTS: "Plan '{planKey}' already exists",
887
+ BUNDLE_ALREADY_EXISTS: "Bundle '{bundleKey}' already exists",
688
888
  MARKETING_PROJECTION_ALREADY_EXISTS: "Marketing projection for {targetType}/{targetVersionId}/{locale} already exists \u2014 use PATCH to edit it",
689
889
  PLAN_DRAFT_ALREADY_EXISTS: "Plan '{planKey}' already has a draft version v{draftVersion}; publish or discard it first",
690
890
  BUNDLE_DRAFT_ALREADY_EXISTS: "Bundle '{bundleKey}' already has a draft version v{draftVersion}; publish or discard it first",
@@ -698,6 +898,8 @@ var ERROR_MESSAGES_EN = {
698
898
  BUNDLE_ALREADY_SUBSCRIBED: "Subscription '{subscriptionId}' has already actively booked this bundle.",
699
899
  BUNDLE_INCOMPATIBLE_WITH_PLAN: "BundleVersion '{bundleVersionId}' is not compatible with plan '{planKey}'. Allowed: [{allowedPlanKeys}].",
700
900
  BUNDLE_NOT_SELF_SERVICE: "Bundle '{bundleKey}' is only activated via a special contract. Please contact the contract manager.",
901
+ BUNDLE_CYCLE_EXCEEDS_PLAN: "A {billingCycle} bundle cannot run beside a {planCycle} plan: it would still be committed on every day the plan could end.",
902
+ BUNDLE_NOT_PRICED_FOR_THIS_PLAN: "This bundle has no {billingCycle} price for the {planKey} plan, so it cannot be booked from here.",
701
903
  SUBSCRIPTION_BUNDLE_ALREADY_CANCELLED: "SubscriptionBundle '{subscriptionBundleId}' is already cancelled.",
702
904
  SUBSCRIPTION_BUNDLE_NOT_CANCELLED: "SubscriptionBundle '{subscriptionBundleId}' is not cancelled.",
703
905
  SUBSCRIPTION_BUNDLE_CANCELLATION_EFFECTIVE: "Cancellation already in effect \u2014 book the bundle again.",
@@ -706,7 +908,7 @@ var ERROR_MESSAGES_EN = {
706
908
  SUBSCRIPTION_BUNDLE_NOT_FOUND: "SubscriptionBundle '{subscriptionBundleId}' not found",
707
909
  TENANT_NOT_FOUND: "Tenant {slug} not found",
708
910
  NO_ACTIVE_PLAN_VERSION: "No plan version for {planId} active as of {asOf} \u2014 neither the validFrom window is satisfied nor is a latest-live version available.",
709
- PLAN_NOT_IN_CATALOG: 'Plan "{planKey}" is not in the catalog ({projectKey})',
911
+ PLAN_NOT_IN_CATALOG: 'Plan "{planKey}" is not in the catalog',
710
912
  PLAN_NOT_SELF_SERVICE: "{planKey} is not activated via self-service.",
711
913
  PLAN_CHANGE_BLOCKED: "Plan change during onboarding is blocked.",
712
914
  NO_PENDING_PLAN_VERSION: "There is no pending plan version awaiting confirmation.",
@@ -826,6 +1028,8 @@ var ERROR_MESSAGES_DE = {
826
1028
  BUNDLE_VERSION_SUPERSEDED: "BundleVersion '{bundleVersionId}' wurde durch eine neuere Version abgel\xF6st.",
827
1029
  BUNDLE_VERSION_REGRESSION: "Diese Bundle-Version ist regressiv (Feature entfernt / Quota gesenkt / Preis erh\xF6ht). Das Ver\xF6ffentlichen erfordert ein ausdr\xFCckliches `forceRegressive: true` (Best\xE4tigungsdialog in der UI mit MFA).",
828
1030
  BUNDLE_VERSION_ZERO_PRICE: "Eine Bundle-Version l\xE4sst sich nicht mit einem ausdr\xFCcklichen Preis von 0,00 ver\xF6ffentlichen (Schutz vor Seed-Platzhaltern). Kostenlose Bundles l\xE4sst du auf null, oder du setzt allowZeroPrice.",
1031
+ BUNDLE_VERSION_NO_PRICE: "Diese Bundle-Version kann ohne Preis nicht ver\xF6ffentlicht werden: weder ein Grundpreis noch eine Plan-\xDCberschreibung ergibt einen.",
1032
+ BUNDLE_VERSION_NOT_PRICED_FOR_PLAN: "Dieses Bundle wird dem Plan '{planKey}' angeboten, der {billingCycle} verkauft wird, und daf\xFCr ergibt sich kein {billingCycle} Preis \u2014 weder als Grundpreis noch als Plan-\xDCberschreibung.",
829
1033
  BUNDLE_VERSION_DISCARD_NOT_IMPLEMENTED: "Das Verwerfen ist im aktuellen Repository nicht implementiert. Implementiere BundleRepository.deleteDraft.",
830
1034
  BUNDLE_VERSION_VALID_FROM_REQUIRED: "Ver\xF6ffentlichte Bundle-Versionen m\xFCssen ein validFrom behalten. Setze ein neues Datum in der Zukunft, oder bearbeite den Entwurf vor dem Ver\xF6ffentlichen.",
831
1035
  BUNDLE_VERSION_VALID_FROM_INVALID: "validFrom '{validFrom}' ist kein g\xFCltiges Datum",
@@ -839,12 +1043,12 @@ var ERROR_MESSAGES_DE = {
839
1043
  PLAN_VERSION_NOT_FOUND: "PlanVersion '{versionId}' nicht gefunden",
840
1044
  BUNDLE_NOT_FOUND: "Bundle '{bundleId}' nicht gefunden",
841
1045
  BUNDLE_VERSION_NOT_FOUND: "BundleVersion '{bundleVersionId}' nicht gefunden",
842
- FEATURE_NOT_FOUND: "Feature '{featureKey}' im Projekt '{projectKey}' nicht gefunden",
843
- QUOTA_NOT_FOUND: "Quota '{quotaKey}' im Projekt '{projectKey}' nicht gefunden",
1046
+ FEATURE_NOT_FOUND: "Feature '{featureKey}' nicht gefunden",
1047
+ QUOTA_NOT_FOUND: "Quota '{quotaKey}' nicht gefunden",
844
1048
  PROMOTION_NOT_FOUND: "Promotion '{promotionId}' nicht gefunden",
845
1049
  MARKETING_PROJECTION_NOT_FOUND: "MarketingProjection '{projectionId}' nicht gefunden",
846
- PLAN_ALREADY_EXISTS: "Plan '{planKey}' gibt es im Projekt '{projectKey}' bereits",
847
- BUNDLE_ALREADY_EXISTS: "Bundle '{bundleKey}' gibt es im Projekt '{projectKey}' bereits",
1050
+ PLAN_ALREADY_EXISTS: "Plan '{planKey}' gibt es bereits",
1051
+ BUNDLE_ALREADY_EXISTS: "Bundle '{bundleKey}' gibt es bereits",
848
1052
  MARKETING_PROJECTION_ALREADY_EXISTS: "F\xFCr {targetType}/{targetVersionId}/{locale} gibt es bereits eine Marketing-Projektion \u2014 bearbeite sie per PATCH",
849
1053
  PLAN_DRAFT_ALREADY_EXISTS: "Plan '{planKey}' hat bereits die Entwurfsversion v{draftVersion}; ver\xF6ffentliche oder verwirf sie zuerst",
850
1054
  BUNDLE_DRAFT_ALREADY_EXISTS: "Bundle '{bundleKey}' hat bereits die Entwurfsversion v{draftVersion}; ver\xF6ffentliche oder verwirf sie zuerst",
@@ -858,6 +1062,8 @@ var ERROR_MESSAGES_DE = {
858
1062
  BUNDLE_ALREADY_SUBSCRIBED: "Abonnement '{subscriptionId}' hat dieses Bundle bereits aktiv gebucht.",
859
1063
  BUNDLE_INCOMPATIBLE_WITH_PLAN: "BundleVersion '{bundleVersionId}' passt nicht zum Plan '{planKey}'. Erlaubt: [{allowedPlanKeys}].",
860
1064
  BUNDLE_NOT_SELF_SERVICE: "Bundle '{bundleKey}' wird nur \xFCber einen Sondervertrag freigeschaltet. Bitte wende dich an die Vertragsverwaltung.",
1065
+ BUNDLE_CYCLE_EXCEEDS_PLAN: "Ein {billingCycle} abgerechnetes Bundle passt nicht zu einem {planCycle} abgerechneten Plan: es w\xE4re an jedem Tag gebunden, an dem der Plan enden kann.",
1066
+ BUNDLE_NOT_PRICED_FOR_THIS_PLAN: "F\xFCr dieses Bundle ist im Plan {planKey} kein {billingCycle} Preis hinterlegt, es kann hier deshalb nicht gebucht werden.",
861
1067
  SUBSCRIPTION_BUNDLE_ALREADY_CANCELLED: "SubscriptionBundle '{subscriptionBundleId}' ist bereits gek\xFCndigt.",
862
1068
  SUBSCRIPTION_BUNDLE_NOT_CANCELLED: "SubscriptionBundle '{subscriptionBundleId}' ist nicht gek\xFCndigt.",
863
1069
  SUBSCRIPTION_BUNDLE_CANCELLATION_EFFECTIVE: "Die K\xFCndigung ist bereits wirksam \u2014 buche das Bundle einfach neu.",
@@ -866,7 +1072,7 @@ var ERROR_MESSAGES_DE = {
866
1072
  SUBSCRIPTION_BUNDLE_NOT_FOUND: "SubscriptionBundle '{subscriptionBundleId}' nicht gefunden",
867
1073
  TENANT_NOT_FOUND: "Mandant {slug} nicht gefunden",
868
1074
  NO_ACTIVE_PLAN_VERSION: "Zum {asOf} ist keine Planversion f\xFCr {planId} aktiv \u2014 weder ist das validFrom-Fenster erf\xFCllt, noch steht eine j\xFCngste Live-Version bereit.",
869
- PLAN_NOT_IN_CATALOG: 'Plan "{planKey}" steht nicht im Katalog ({projectKey})',
1075
+ PLAN_NOT_IN_CATALOG: 'Plan "{planKey}" steht nicht im Katalog',
870
1076
  PLAN_NOT_SELF_SERVICE: "{planKey} wird nicht per Self-Service freigeschaltet.",
871
1077
  PLAN_CHANGE_BLOCKED: "W\xE4hrend des Onboardings ist ein Planwechsel gesperrt.",
872
1078
  NO_PENDING_PLAN_VERSION: "Es wartet keine Planversion auf eine Best\xE4tigung.",
@@ -928,8 +1134,10 @@ var ERROR_MESSAGES_DE = {
928
1134
  };
929
1135
  // Annotate the CommonJS export names for ESM import in node:
930
1136
  0 && (module.exports = {
1137
+ ACTIVE_SUBSCRIPTION_CONTRACT_STATUSES,
931
1138
  AUTH_ERROR_CODES,
932
1139
  BILLING_ERROR_CODES,
1140
+ BUNDLE_PRICE_LOOKUP_LIMIT,
933
1141
  CATALOG_ERROR_CODES,
934
1142
  CONTRACT_ERROR_CODES,
935
1143
  ERROR_MESSAGES_DE,
@@ -958,19 +1166,28 @@ var ERROR_MESSAGES_DE = {
958
1166
  buildActivePlanVersionWhere,
959
1167
  buildActiveVersionWhere,
960
1168
  buildFeatureRequiresIndex,
1169
+ bundleDraftDefaults,
1170
+ bundleStemDefaults,
961
1171
  classifyBundleVersionDiff,
962
1172
  classifyPlanDiff,
963
1173
  collectUnsatisfiedRequires,
964
1174
  coverageExcludingSelf,
1175
+ definedFields,
965
1176
  formatErrorMessage,
966
1177
  isBundleRedundant,
967
1178
  isPlatformUserExistsError,
968
1179
  isVersionEditable,
969
1180
  missingRequiresFor,
970
1181
  pickActivePromo,
1182
+ previousUtcDay,
971
1183
  promoStatus,
972
1184
  resolveBundleAvailability,
973
1185
  resolveErrorMessage,
974
1186
  selectChargeableBundles,
975
- startOfUtcDay
1187
+ startOfUtcDay,
1188
+ toBundleStemRow,
1189
+ toContractLineItemRecord,
1190
+ toPlanRow,
1191
+ toPlanVersionRow,
1192
+ toSubscriptionContractRecord
976
1193
  });