@saasicat/core 1.0.0-rc.6 → 1.0.0-rc.8
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 +2 -1
- package/dist/.build-stamp +1 -1
- package/dist/index.cjs +285 -14
- package/dist/index.d.cts +747 -449
- package/dist/index.d.ts +747 -449
- package/dist/index.js +273 -13
- package/package.json +1 -1
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
|
|
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
|
-
|
|
1
|
+
e80fad3df961a7d15db07510ea75706570d020538e9e4027cf2d53fbf841b872
|
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",
|
|
@@ -405,6 +472,42 @@ var BILLING_ERROR_CODES = {
|
|
|
405
472
|
PLAN_NOT_SELF_SERVICE: "PLAN_NOT_SELF_SERVICE",
|
|
406
473
|
/** Plan change refused. Carries `blockers[]` with their own codes. */
|
|
407
474
|
PLAN_CHANGE_BLOCKED: "PLAN_CHANGE_BLOCKED",
|
|
475
|
+
// ── the plan-change preview's own blockers and warnings ──
|
|
476
|
+
//
|
|
477
|
+
// These travel inside a 200 response, in `blockers[]` and `warnings[]`, not
|
|
478
|
+
// as thrown errors — but they are read by a person and so belong in the same
|
|
479
|
+
// catalogue. Each carries `params` with the values its sentence names.
|
|
480
|
+
//
|
|
481
|
+
// Three of them used to construct their code from the subject:
|
|
482
|
+
// `VEHICLES_OVER_TARGET`, `ENTERPRISE_LOCKED`, `PRO_NOT_SELF_SERVICE`. That
|
|
483
|
+
// made the set grow with every quota and plan an installation defines, so no
|
|
484
|
+
// catalogue could be complete against it and no guard could check one. The
|
|
485
|
+
// subject is a parameter now.
|
|
486
|
+
/** The subscription has ended; its plan can no longer be changed. */
|
|
487
|
+
SUBSCRIPTION_ENDED: "SUBSCRIPTION_ENDED",
|
|
488
|
+
/** An active special contract blocks self-service plan changes. */
|
|
489
|
+
PLAN_LOCKED: "PLAN_LOCKED",
|
|
490
|
+
/** Current usage of one quota exceeds what the target plan allows. */
|
|
491
|
+
QUOTA_OVER_TARGET: "QUOTA_OVER_TARGET",
|
|
492
|
+
/** The change drops features the tenant has today. */
|
|
493
|
+
FEATURE_LOST: "FEATURE_LOST",
|
|
494
|
+
FEATURES_LOST: "FEATURES_LOST",
|
|
495
|
+
/** Target plan and cycle already match what is in place. */
|
|
496
|
+
NO_CHANGE: "NO_CHANGE",
|
|
497
|
+
/** A shorter cycle cannot start inside the term already running. */
|
|
498
|
+
CYCLE_SHORTENS_AT_TERM_END: "CYCLE_SHORTENS_AT_TERM_END",
|
|
499
|
+
/** A cancelled subscription cannot change its billing cycle. */
|
|
500
|
+
CANCELLATION_LOCKS_THE_CYCLE: "CANCELLATION_LOCKS_THE_CYCLE",
|
|
501
|
+
/**
|
|
502
|
+
* A bundle the tenant already holds runs past the cycle they are moving to.
|
|
503
|
+
*
|
|
504
|
+
* Its own code rather than `BUNDLE_CYCLE_EXCEEDS_PLAN`, which states the
|
|
505
|
+
* same rule about a booking that has not been made yet. The two need
|
|
506
|
+
* different sentences: this one can name the day the obstacle lifts and
|
|
507
|
+
* tell the reader to cancel the booking, and that advice is wrong for
|
|
508
|
+
* someone who is only about to book. One template cannot serve both.
|
|
509
|
+
*/
|
|
510
|
+
BUNDLE_BOOKING_OUTLASTS_TARGET_CYCLE: "BUNDLE_BOOKING_OUTLASTS_TARGET_CYCLE",
|
|
408
511
|
NO_PENDING_PLAN_VERSION: "NO_PENDING_PLAN_VERSION",
|
|
409
512
|
ONBOARDING_CREATE_FAILED: "ONBOARDING_CREATE_FAILED",
|
|
410
513
|
BUNDLE_PREVIEW_ARGUMENT_AMBIGUOUS: "BUNDLE_PREVIEW_ARGUMENT_AMBIGUOUS",
|
|
@@ -595,6 +698,137 @@ var REGISTRATION_STEP_BY_STATUS = {
|
|
|
595
698
|
};
|
|
596
699
|
var REGISTRATION_RESUME_TTL_MINUTES = 60;
|
|
597
700
|
|
|
701
|
+
// src/plan-mapping.ts
|
|
702
|
+
function toPlanRow(row) {
|
|
703
|
+
return {
|
|
704
|
+
id: row.id,
|
|
705
|
+
planKey: row.planKey,
|
|
706
|
+
label: row.label,
|
|
707
|
+
description: row.description,
|
|
708
|
+
icon: row.icon,
|
|
709
|
+
sortOrder: row.sortOrder,
|
|
710
|
+
createdAt: row.createdAt.toISOString(),
|
|
711
|
+
updatedAt: row.updatedAt.toISOString(),
|
|
712
|
+
deletedAt: toIsoOrNull(row.deletedAt)
|
|
713
|
+
};
|
|
714
|
+
}
|
|
715
|
+
function toPlanVersionRow(row, planKey, fields) {
|
|
716
|
+
const mapped = {
|
|
717
|
+
id: row.id,
|
|
718
|
+
version: row.version,
|
|
719
|
+
baseVersionId: row.baseVersionId,
|
|
720
|
+
planId: planKey,
|
|
721
|
+
features: toFeatureKeys(row.features),
|
|
722
|
+
quotas: toQuotaEffects(row.quotas),
|
|
723
|
+
monthlyNet: String(row.monthlyNet),
|
|
724
|
+
yearlyNet: String(row.yearlyNet),
|
|
725
|
+
marketed: row.marketed,
|
|
726
|
+
publishedAt: toIsoOrNull(row.publishedAt),
|
|
727
|
+
supersededAt: toIsoOrNull(row.supersededAt),
|
|
728
|
+
publishedChanges: Array.isArray(row.publishedChanges) ? row.publishedChanges : null,
|
|
729
|
+
changeNote: row.changeNote,
|
|
730
|
+
nonRegressive: row.nonRegressive,
|
|
731
|
+
validFrom: fields.validityWindows ? toIsoOrNull(row.validFrom) : null,
|
|
732
|
+
validUntil: fields.validityWindows ? toIsoOrNull(row.validUntil) : null,
|
|
733
|
+
createdByUserId: row.createdByUserId,
|
|
734
|
+
publishedByUserId: row.publishedByUserId,
|
|
735
|
+
createdAt: row.createdAt.toISOString(),
|
|
736
|
+
updatedAt: row.updatedAt.toISOString()
|
|
737
|
+
};
|
|
738
|
+
if (fields.endsAt) {
|
|
739
|
+
mapped.endsAt = toIsoOrNull(row.endsAt);
|
|
740
|
+
}
|
|
741
|
+
return mapped;
|
|
742
|
+
}
|
|
743
|
+
function toIsoOrNull(value) {
|
|
744
|
+
return value ? value.toISOString() : null;
|
|
745
|
+
}
|
|
746
|
+
function toFeatureKeys(value) {
|
|
747
|
+
if (!Array.isArray(value)) return [];
|
|
748
|
+
return value.filter((entry) => typeof entry === "string");
|
|
749
|
+
}
|
|
750
|
+
function toQuotaEffects(value) {
|
|
751
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
752
|
+
return {};
|
|
753
|
+
}
|
|
754
|
+
const quotas = {};
|
|
755
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
756
|
+
if (typeof entry === "number") quotas[key] = entry;
|
|
757
|
+
}
|
|
758
|
+
return quotas;
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
// src/subscription-contract-mapping.ts
|
|
762
|
+
function toSubscriptionContractRecord(row, lineItems) {
|
|
763
|
+
return {
|
|
764
|
+
id: row.id,
|
|
765
|
+
tenantId: row.tenantId,
|
|
766
|
+
status: row.status,
|
|
767
|
+
effectiveFrom: row.effectiveFrom,
|
|
768
|
+
effectiveUntil: row.effectiveUntil,
|
|
769
|
+
originalOfferId: row.originalOfferId,
|
|
770
|
+
originalPlanVersionId: row.originalPlanVersionId,
|
|
771
|
+
originalBundleVersionIds: toStringArray(row.originalBundleVersionIds),
|
|
772
|
+
entitlementSnapshot: isPlainObject(row.entitlementSnapshot) ? row.entitlementSnapshot : null,
|
|
773
|
+
priceSnapshot: row.priceSnapshot,
|
|
774
|
+
promotionSnapshots: toUnknownArray(row.promotionSnapshots),
|
|
775
|
+
promoCodeSnapshots: toUnknownArray(row.promoCodeSnapshots),
|
|
776
|
+
termsSnapshot: toRecordOrNull(row.termsSnapshot),
|
|
777
|
+
lineItems: lineItems.map(toContractLineItemRecord),
|
|
778
|
+
createdAt: row.createdAt,
|
|
779
|
+
updatedAt: row.updatedAt
|
|
780
|
+
};
|
|
781
|
+
}
|
|
782
|
+
function toContractLineItemRecord(row) {
|
|
783
|
+
return {
|
|
784
|
+
id: row.id,
|
|
785
|
+
contractId: row.contractId,
|
|
786
|
+
kind: row.kind,
|
|
787
|
+
sourceKey: row.sourceKey,
|
|
788
|
+
sourceVersionId: row.sourceVersionId,
|
|
789
|
+
titleSnapshot: row.titleSnapshot,
|
|
790
|
+
descriptionSnapshot: row.descriptionSnapshot,
|
|
791
|
+
quantity: row.quantity,
|
|
792
|
+
unit: row.unit,
|
|
793
|
+
priceNet: Number(row.priceNet),
|
|
794
|
+
priceGross: Number(row.priceGross),
|
|
795
|
+
billingCycle: row.billingCycle,
|
|
796
|
+
minimumTermUntil: row.minimumTermUntil,
|
|
797
|
+
featuresSnapshot: toStringArray(row.featuresSnapshot),
|
|
798
|
+
quotaEffectsSnapshot: toQuotaEffects2(row.quotaEffectsSnapshot),
|
|
799
|
+
metadata: toRecordOrNull(row.metadata),
|
|
800
|
+
createdAt: row.createdAt
|
|
801
|
+
};
|
|
802
|
+
}
|
|
803
|
+
function isPlainObject(value) {
|
|
804
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
805
|
+
}
|
|
806
|
+
function toUnknownArray(value) {
|
|
807
|
+
return Array.isArray(value) ? value : [];
|
|
808
|
+
}
|
|
809
|
+
function toRecordOrNull(value) {
|
|
810
|
+
return isPlainObject(value) ? value : null;
|
|
811
|
+
}
|
|
812
|
+
function toStringArray(value) {
|
|
813
|
+
if (!Array.isArray(value)) return [];
|
|
814
|
+
return value.filter((entry) => typeof entry === "string");
|
|
815
|
+
}
|
|
816
|
+
function toQuotaEffects2(value) {
|
|
817
|
+
if (!isPlainObject(value)) return {};
|
|
818
|
+
const effects = {};
|
|
819
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
820
|
+
if (typeof entry === "number") effects[key] = entry;
|
|
821
|
+
}
|
|
822
|
+
return effects;
|
|
823
|
+
}
|
|
824
|
+
|
|
825
|
+
// src/subscription-contract.types.ts
|
|
826
|
+
var BUNDLE_PRICE_LOOKUP_LIMIT = 200;
|
|
827
|
+
var ACTIVE_SUBSCRIPTION_CONTRACT_STATUSES = [
|
|
828
|
+
"active",
|
|
829
|
+
"scheduled"
|
|
830
|
+
];
|
|
831
|
+
|
|
598
832
|
// src/version-editability.ts
|
|
599
833
|
function isVersionEditable(v, now = /* @__PURE__ */ new Date()) {
|
|
600
834
|
if (v.publishedAt === null) {
|
|
@@ -666,6 +900,8 @@ var ERROR_MESSAGES_EN = {
|
|
|
666
900
|
BUNDLE_VERSION_SUPERSEDED: "BundleVersion '{bundleVersionId}' has been superseded by a newer version.",
|
|
667
901
|
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
902
|
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.",
|
|
903
|
+
BUNDLE_VERSION_NO_PRICE: "This bundle version cannot be published without a price: neither a base price nor any plan override resolves one.",
|
|
904
|
+
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
905
|
BUNDLE_VERSION_DISCARD_NOT_IMPLEMENTED: "Discard is not implemented in the current repository. Implement BundleRepository.deleteDraft.",
|
|
670
906
|
BUNDLE_VERSION_VALID_FROM_REQUIRED: "Published bundle versions must keep a validFrom. Set a new future date, or edit the draft before publishing.",
|
|
671
907
|
BUNDLE_VERSION_VALID_FROM_INVALID: "validFrom '{validFrom}' is not a valid date",
|
|
@@ -679,12 +915,12 @@ var ERROR_MESSAGES_EN = {
|
|
|
679
915
|
PLAN_VERSION_NOT_FOUND: "PlanVersion '{versionId}' not found",
|
|
680
916
|
BUNDLE_NOT_FOUND: "Bundle '{bundleId}' not found",
|
|
681
917
|
BUNDLE_VERSION_NOT_FOUND: "BundleVersion '{bundleVersionId}' not found",
|
|
682
|
-
FEATURE_NOT_FOUND: "Feature '{featureKey}' not found
|
|
683
|
-
QUOTA_NOT_FOUND: "Quota '{quotaKey}' not found
|
|
918
|
+
FEATURE_NOT_FOUND: "Feature '{featureKey}' not found",
|
|
919
|
+
QUOTA_NOT_FOUND: "Quota '{quotaKey}' not found",
|
|
684
920
|
PROMOTION_NOT_FOUND: "Promotion '{promotionId}' not found",
|
|
685
921
|
MARKETING_PROJECTION_NOT_FOUND: "MarketingProjection '{projectionId}' not found",
|
|
686
|
-
PLAN_ALREADY_EXISTS: "Plan '{planKey}' already exists
|
|
687
|
-
BUNDLE_ALREADY_EXISTS: "Bundle '{bundleKey}' already exists
|
|
922
|
+
PLAN_ALREADY_EXISTS: "Plan '{planKey}' already exists",
|
|
923
|
+
BUNDLE_ALREADY_EXISTS: "Bundle '{bundleKey}' already exists",
|
|
688
924
|
MARKETING_PROJECTION_ALREADY_EXISTS: "Marketing projection for {targetType}/{targetVersionId}/{locale} already exists \u2014 use PATCH to edit it",
|
|
689
925
|
PLAN_DRAFT_ALREADY_EXISTS: "Plan '{planKey}' already has a draft version v{draftVersion}; publish or discard it first",
|
|
690
926
|
BUNDLE_DRAFT_ALREADY_EXISTS: "Bundle '{bundleKey}' already has a draft version v{draftVersion}; publish or discard it first",
|
|
@@ -698,6 +934,8 @@ var ERROR_MESSAGES_EN = {
|
|
|
698
934
|
BUNDLE_ALREADY_SUBSCRIBED: "Subscription '{subscriptionId}' has already actively booked this bundle.",
|
|
699
935
|
BUNDLE_INCOMPATIBLE_WITH_PLAN: "BundleVersion '{bundleVersionId}' is not compatible with plan '{planKey}'. Allowed: [{allowedPlanKeys}].",
|
|
700
936
|
BUNDLE_NOT_SELF_SERVICE: "Bundle '{bundleKey}' is only activated via a special contract. Please contact the contract manager.",
|
|
937
|
+
BUNDLE_CYCLE_EXCEEDS_PLAN: "A yearly bundle cannot run beside a monthly plan: it would still be committed on every day the plan could end.",
|
|
938
|
+
BUNDLE_NOT_PRICED_FOR_THIS_PLAN: "This bundle has no {billingCycle} price for the {planKey} plan, so it cannot be booked from here.",
|
|
701
939
|
SUBSCRIPTION_BUNDLE_ALREADY_CANCELLED: "SubscriptionBundle '{subscriptionBundleId}' is already cancelled.",
|
|
702
940
|
SUBSCRIPTION_BUNDLE_NOT_CANCELLED: "SubscriptionBundle '{subscriptionBundleId}' is not cancelled.",
|
|
703
941
|
SUBSCRIPTION_BUNDLE_CANCELLATION_EFFECTIVE: "Cancellation already in effect \u2014 book the bundle again.",
|
|
@@ -706,9 +944,18 @@ var ERROR_MESSAGES_EN = {
|
|
|
706
944
|
SUBSCRIPTION_BUNDLE_NOT_FOUND: "SubscriptionBundle '{subscriptionBundleId}' not found",
|
|
707
945
|
TENANT_NOT_FOUND: "Tenant {slug} not found",
|
|
708
946
|
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
|
|
710
|
-
PLAN_NOT_SELF_SERVICE: "{
|
|
947
|
+
PLAN_NOT_IN_CATALOG: 'Plan "{planKey}" is not in the catalog',
|
|
948
|
+
PLAN_NOT_SELF_SERVICE: "{planName} is only activated via a special contract. Please contact the contract manager.",
|
|
711
949
|
PLAN_CHANGE_BLOCKED: "Plan change during onboarding is blocked.",
|
|
950
|
+
SUBSCRIPTION_ENDED: "This subscription has ended. Its plan can no longer be changed.",
|
|
951
|
+
PLAN_LOCKED: "Active {planName} special contract \u2014 please contact the contract manager to change plans.",
|
|
952
|
+
QUOTA_OVER_TARGET: "Current usage {used} exceeds the target limit {targetMax} ({quotaKey}) in the {planName} plan. Please reduce usage first.",
|
|
953
|
+
FEATURE_LOST: "Switching means losing access to one feature. Existing data is retained and never deleted \u2014 upgrading again unlocks it.",
|
|
954
|
+
FEATURES_LOST: "Switching means losing access to {count} features. Existing data is retained and never deleted \u2014 upgrading again unlocks it.",
|
|
955
|
+
NO_CHANGE: "Target plan and billing cycle already match the current state.",
|
|
956
|
+
CANCELLATION_LOCKS_THE_CYCLE: "This subscription is cancelled, so its billing cycle cannot change. The plan can \u2014 keep the current cycle to change it today.",
|
|
957
|
+
CYCLE_SHORTENS_AT_TERM_END: "A monthly {planName} cannot start inside the yearly term you are in. The upgrade takes effect when that term ends; to have it today, keep the yearly cycle.",
|
|
958
|
+
BUNDLE_BOOKING_OUTLASTS_TARGET_CYCLE: "A yearly bundle is booked until {until}. A monthly plan cannot carry it \u2014 cancel the bundle first, or keep the yearly cycle.",
|
|
712
959
|
NO_PENDING_PLAN_VERSION: "There is no pending plan version awaiting confirmation.",
|
|
713
960
|
ONBOARDING_CREATE_FAILED: "The account could not be created. Please try again.",
|
|
714
961
|
BUNDLE_PREVIEW_ARGUMENT_AMBIGUOUS: "Exactly one of bundleVersionId (add preview) or subscriptionBundleId (cancel preview) must be given.",
|
|
@@ -826,6 +1073,8 @@ var ERROR_MESSAGES_DE = {
|
|
|
826
1073
|
BUNDLE_VERSION_SUPERSEDED: "BundleVersion '{bundleVersionId}' wurde durch eine neuere Version abgel\xF6st.",
|
|
827
1074
|
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
1075
|
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.",
|
|
1076
|
+
BUNDLE_VERSION_NO_PRICE: "Diese Bundle-Version kann ohne Preis nicht ver\xF6ffentlicht werden: weder ein Grundpreis noch eine Plan-\xDCberschreibung ergibt einen.",
|
|
1077
|
+
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
1078
|
BUNDLE_VERSION_DISCARD_NOT_IMPLEMENTED: "Das Verwerfen ist im aktuellen Repository nicht implementiert. Implementiere BundleRepository.deleteDraft.",
|
|
830
1079
|
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
1080
|
BUNDLE_VERSION_VALID_FROM_INVALID: "validFrom '{validFrom}' ist kein g\xFCltiges Datum",
|
|
@@ -839,12 +1088,12 @@ var ERROR_MESSAGES_DE = {
|
|
|
839
1088
|
PLAN_VERSION_NOT_FOUND: "PlanVersion '{versionId}' nicht gefunden",
|
|
840
1089
|
BUNDLE_NOT_FOUND: "Bundle '{bundleId}' nicht gefunden",
|
|
841
1090
|
BUNDLE_VERSION_NOT_FOUND: "BundleVersion '{bundleVersionId}' nicht gefunden",
|
|
842
|
-
FEATURE_NOT_FOUND: "Feature '{featureKey}'
|
|
843
|
-
QUOTA_NOT_FOUND: "Quota '{quotaKey}'
|
|
1091
|
+
FEATURE_NOT_FOUND: "Feature '{featureKey}' nicht gefunden",
|
|
1092
|
+
QUOTA_NOT_FOUND: "Quota '{quotaKey}' nicht gefunden",
|
|
844
1093
|
PROMOTION_NOT_FOUND: "Promotion '{promotionId}' nicht gefunden",
|
|
845
1094
|
MARKETING_PROJECTION_NOT_FOUND: "MarketingProjection '{projectionId}' nicht gefunden",
|
|
846
|
-
PLAN_ALREADY_EXISTS: "Plan '{planKey}' gibt es
|
|
847
|
-
BUNDLE_ALREADY_EXISTS: "Bundle '{bundleKey}' gibt es
|
|
1095
|
+
PLAN_ALREADY_EXISTS: "Plan '{planKey}' gibt es bereits",
|
|
1096
|
+
BUNDLE_ALREADY_EXISTS: "Bundle '{bundleKey}' gibt es bereits",
|
|
848
1097
|
MARKETING_PROJECTION_ALREADY_EXISTS: "F\xFCr {targetType}/{targetVersionId}/{locale} gibt es bereits eine Marketing-Projektion \u2014 bearbeite sie per PATCH",
|
|
849
1098
|
PLAN_DRAFT_ALREADY_EXISTS: "Plan '{planKey}' hat bereits die Entwurfsversion v{draftVersion}; ver\xF6ffentliche oder verwirf sie zuerst",
|
|
850
1099
|
BUNDLE_DRAFT_ALREADY_EXISTS: "Bundle '{bundleKey}' hat bereits die Entwurfsversion v{draftVersion}; ver\xF6ffentliche oder verwirf sie zuerst",
|
|
@@ -858,6 +1107,8 @@ var ERROR_MESSAGES_DE = {
|
|
|
858
1107
|
BUNDLE_ALREADY_SUBSCRIBED: "Abonnement '{subscriptionId}' hat dieses Bundle bereits aktiv gebucht.",
|
|
859
1108
|
BUNDLE_INCOMPATIBLE_WITH_PLAN: "BundleVersion '{bundleVersionId}' passt nicht zum Plan '{planKey}'. Erlaubt: [{allowedPlanKeys}].",
|
|
860
1109
|
BUNDLE_NOT_SELF_SERVICE: "Bundle '{bundleKey}' wird nur \xFCber einen Sondervertrag freigeschaltet. Bitte wende dich an die Vertragsverwaltung.",
|
|
1110
|
+
BUNDLE_CYCLE_EXCEEDS_PLAN: "Ein j\xE4hrlich abgerechnetes Bundle passt nicht zu einem monatlich abgerechneten Plan: es w\xE4re an jedem Tag gebunden, an dem der Plan enden kann.",
|
|
1111
|
+
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
1112
|
SUBSCRIPTION_BUNDLE_ALREADY_CANCELLED: "SubscriptionBundle '{subscriptionBundleId}' ist bereits gek\xFCndigt.",
|
|
862
1113
|
SUBSCRIPTION_BUNDLE_NOT_CANCELLED: "SubscriptionBundle '{subscriptionBundleId}' ist nicht gek\xFCndigt.",
|
|
863
1114
|
SUBSCRIPTION_BUNDLE_CANCELLATION_EFFECTIVE: "Die K\xFCndigung ist bereits wirksam \u2014 buche das Bundle einfach neu.",
|
|
@@ -866,9 +1117,18 @@ var ERROR_MESSAGES_DE = {
|
|
|
866
1117
|
SUBSCRIPTION_BUNDLE_NOT_FOUND: "SubscriptionBundle '{subscriptionBundleId}' nicht gefunden",
|
|
867
1118
|
TENANT_NOT_FOUND: "Mandant {slug} nicht gefunden",
|
|
868
1119
|
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
|
|
870
|
-
PLAN_NOT_SELF_SERVICE: "{
|
|
1120
|
+
PLAN_NOT_IN_CATALOG: 'Plan "{planKey}" steht nicht im Katalog',
|
|
1121
|
+
PLAN_NOT_SELF_SERVICE: "{planName} wird nur \xFCber einen Sondervertrag freigeschaltet. Bitte wenden Sie sich an die Vertragsverwaltung.",
|
|
871
1122
|
PLAN_CHANGE_BLOCKED: "W\xE4hrend des Onboardings ist ein Planwechsel gesperrt.",
|
|
1123
|
+
SUBSCRIPTION_ENDED: "Dieses Abonnement ist beendet. Sein Paket kann nicht mehr gewechselt werden.",
|
|
1124
|
+
PLAN_LOCKED: "Aktiver Sondervertrag {planName} \u2014 f\xFCr einen Paketwechsel wenden Sie sich bitte an die Vertragsverwaltung.",
|
|
1125
|
+
QUOTA_OVER_TARGET: "Aktuelle Nutzung {used} \xFCberschreitet das Ziel-Limit {targetMax} ({quotaKey}) im Paket {planName}. Bitte zuerst die Nutzung reduzieren.",
|
|
1126
|
+
FEATURE_LOST: "Beim Wechsel verlieren Sie den Zugriff auf eine Funktion. Vorhandene Daten bleiben erhalten und werden nie gel\xF6scht \u2014 ein sp\xE4teres Upgrade schaltet sie wieder frei.",
|
|
1127
|
+
FEATURES_LOST: "Beim Wechsel verlieren Sie den Zugriff auf {count} Funktionen. Vorhandene Daten bleiben erhalten und werden nie gel\xF6scht \u2014 ein sp\xE4teres Upgrade schaltet sie wieder frei.",
|
|
1128
|
+
NO_CHANGE: "Zielpaket und Abrechnungsrhythmus entsprechen bereits dem aktuellen Stand.",
|
|
1129
|
+
CANCELLATION_LOCKS_THE_CYCLE: "Dieses Abonnement ist gek\xFCndigt, sein Abrechnungsrhythmus kann daher nicht wechseln. Das Paket schon \u2014 behalten Sie den aktuellen Rhythmus, um es heute zu wechseln.",
|
|
1130
|
+
CYCLE_SHORTENS_AT_TERM_END: "Ein monatlich abgerechnetes {planName} kann nicht innerhalb der laufenden Jahreslaufzeit beginnen. Das Upgrade greift zum Ende dieser Laufzeit; wer es sofort m\xF6chte, beh\xE4lt den j\xE4hrlichen Rhythmus.",
|
|
1131
|
+
BUNDLE_BOOKING_OUTLASTS_TARGET_CYCLE: "Ein j\xE4hrlich abgerechnetes Bundle ist bis {until} gebucht. Ein monatlich abgerechnetes Paket kann es nicht tragen \u2014 k\xFCndigen Sie das Bundle zuerst, oder behalten Sie den j\xE4hrlichen Rhythmus.",
|
|
872
1132
|
NO_PENDING_PLAN_VERSION: "Es wartet keine Planversion auf eine Best\xE4tigung.",
|
|
873
1133
|
ONBOARDING_CREATE_FAILED: "Das Konto konnte nicht angelegt werden. Bitte versuche es noch einmal.",
|
|
874
1134
|
BUNDLE_PREVIEW_ARGUMENT_AMBIGUOUS: "Genau eines von bundleVersionId (Vorschau f\xFCrs Buchen) oder subscriptionBundleId (Vorschau f\xFCrs K\xFCndigen) muss angegeben sein.",
|
|
@@ -928,8 +1188,10 @@ var ERROR_MESSAGES_DE = {
|
|
|
928
1188
|
};
|
|
929
1189
|
// Annotate the CommonJS export names for ESM import in node:
|
|
930
1190
|
0 && (module.exports = {
|
|
1191
|
+
ACTIVE_SUBSCRIPTION_CONTRACT_STATUSES,
|
|
931
1192
|
AUTH_ERROR_CODES,
|
|
932
1193
|
BILLING_ERROR_CODES,
|
|
1194
|
+
BUNDLE_PRICE_LOOKUP_LIMIT,
|
|
933
1195
|
CATALOG_ERROR_CODES,
|
|
934
1196
|
CONTRACT_ERROR_CODES,
|
|
935
1197
|
ERROR_MESSAGES_DE,
|
|
@@ -958,19 +1220,28 @@ var ERROR_MESSAGES_DE = {
|
|
|
958
1220
|
buildActivePlanVersionWhere,
|
|
959
1221
|
buildActiveVersionWhere,
|
|
960
1222
|
buildFeatureRequiresIndex,
|
|
1223
|
+
bundleDraftDefaults,
|
|
1224
|
+
bundleStemDefaults,
|
|
961
1225
|
classifyBundleVersionDiff,
|
|
962
1226
|
classifyPlanDiff,
|
|
963
1227
|
collectUnsatisfiedRequires,
|
|
964
1228
|
coverageExcludingSelf,
|
|
1229
|
+
definedFields,
|
|
965
1230
|
formatErrorMessage,
|
|
966
1231
|
isBundleRedundant,
|
|
967
1232
|
isPlatformUserExistsError,
|
|
968
1233
|
isVersionEditable,
|
|
969
1234
|
missingRequiresFor,
|
|
970
1235
|
pickActivePromo,
|
|
1236
|
+
previousUtcDay,
|
|
971
1237
|
promoStatus,
|
|
972
1238
|
resolveBundleAvailability,
|
|
973
1239
|
resolveErrorMessage,
|
|
974
1240
|
selectChargeableBundles,
|
|
975
|
-
startOfUtcDay
|
|
1241
|
+
startOfUtcDay,
|
|
1242
|
+
toBundleStemRow,
|
|
1243
|
+
toContractLineItemRecord,
|
|
1244
|
+
toPlanRow,
|
|
1245
|
+
toPlanVersionRow,
|
|
1246
|
+
toSubscriptionContractRecord
|
|
976
1247
|
});
|