@saasicat/nest 0.2.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/LICENSE +202 -0
- package/README.md +53 -0
- package/dist/admin/index.cjs +1283 -0
- package/dist/admin/index.d.cts +225 -0
- package/dist/admin/index.d.ts +225 -0
- package/dist/admin/index.js +58 -0
- package/dist/admin-audit.service-9IqXMlZm.d.cts +30 -0
- package/dist/admin-audit.service-9IqXMlZm.d.ts +30 -0
- package/dist/admin-manifest.config-DyrQNT7M.d.cts +10 -0
- package/dist/admin-manifest.config-DyrQNT7M.d.ts +10 -0
- package/dist/aggregation-CJ3qQf92.d.cts +288 -0
- package/dist/aggregation-Dvz9e8X2.d.ts +288 -0
- package/dist/billing/index.cjs +5205 -0
- package/dist/billing/index.d.cts +1326 -0
- package/dist/billing/index.d.ts +1326 -0
- package/dist/billing/index.js +197 -0
- package/dist/catalog/index.cjs +6449 -0
- package/dist/catalog/index.d.cts +1073 -0
- package/dist/catalog/index.d.ts +1073 -0
- package/dist/catalog/index.js +158 -0
- package/dist/checkout-offer/index.cjs +807 -0
- package/dist/checkout-offer/index.d.cts +120 -0
- package/dist/checkout-offer/index.d.ts +120 -0
- package/dist/checkout-offer/index.js +20 -0
- package/dist/chunk-2FR6ZL7R.js +0 -0
- package/dist/chunk-2PNX2QL2.js +347 -0
- package/dist/chunk-2VNZYRDV.js +326 -0
- package/dist/chunk-7MLGHWKO.js +12 -0
- package/dist/chunk-ABB2CRAS.js +31 -0
- package/dist/chunk-AJ3EPELS.js +157 -0
- package/dist/chunk-E56W4U2P.js +90 -0
- package/dist/chunk-HRU3CP57.js +71 -0
- package/dist/chunk-L4SUWH5B.js +14 -0
- package/dist/chunk-M6CZQYPY.js +314 -0
- package/dist/chunk-MDIZUVIK.js +87 -0
- package/dist/chunk-MV6LW5UB.js +217 -0
- package/dist/chunk-NYLON2VC.js +6 -0
- package/dist/chunk-P6MYZMXQ.js +951 -0
- package/dist/chunk-Q53N43LQ.js +13 -0
- package/dist/chunk-QJVPRD3R.js +573 -0
- package/dist/chunk-RIGLQ4BV.js +3367 -0
- package/dist/chunk-SABTXESR.js +24 -0
- package/dist/chunk-SHUYVCID.js +6 -0
- package/dist/chunk-SYEVGPFC.js +686 -0
- package/dist/chunk-V7HUZ6UQ.js +5923 -0
- package/dist/chunk-WPUVJRIN.js +29 -0
- package/dist/chunk-XCZ3TTFK.js +22 -0
- package/dist/chunk-XSGU2Y2O.js +1611 -0
- package/dist/chunk-YNEW3L63.js +190 -0
- package/dist/chunk-YXGHPILG.js +614 -0
- package/dist/chunk-ZL4LLE2Z.js +465 -0
- package/dist/di-CcNeq9v-.d.cts +16 -0
- package/dist/di-CcNeq9v-.d.ts +16 -0
- package/dist/discovery/index.cjs +588 -0
- package/dist/discovery/index.d.cts +299 -0
- package/dist/discovery/index.d.ts +299 -0
- package/dist/discovery/index.js +49 -0
- package/dist/discovery.scanner-CUYLKlYT.d.cts +59 -0
- package/dist/discovery.scanner-CUYLKlYT.d.ts +59 -0
- package/dist/entitlement/index.cjs +805 -0
- package/dist/entitlement/index.d.cts +60 -0
- package/dist/entitlement/index.d.ts +60 -0
- package/dist/entitlement/index.js +57 -0
- package/dist/index.cjs +15918 -0
- package/dist/index.d.cts +85 -0
- package/dist/index.d.ts +85 -0
- package/dist/index.js +956 -0
- package/dist/plan-resolution-CFCoUkrE.d.cts +41 -0
- package/dist/plan-resolution-CFCoUkrE.d.ts +41 -0
- package/dist/platform/index.cjs +2772 -0
- package/dist/platform/index.d.cts +118 -0
- package/dist/platform/index.d.ts +118 -0
- package/dist/platform/index.js +37 -0
- package/dist/promo/index.cjs +995 -0
- package/dist/promo/index.d.cts +121 -0
- package/dist/promo/index.d.ts +121 -0
- package/dist/promo/index.js +58 -0
- package/dist/registration/index.cjs +1687 -0
- package/dist/registration/index.d.cts +444 -0
- package/dist/registration/index.d.ts +444 -0
- package/dist/registration/index.js +82 -0
- package/dist/saas-platform.module-CgZ2omgg.d.cts +180 -0
- package/dist/saas-platform.module-DT9TnCzk.d.ts +180 -0
- package/dist/service-DX8KbGXl.d.cts +109 -0
- package/dist/service-DX8KbGXl.d.ts +109 -0
- package/dist/subscription-contract/index.cjs +471 -0
- package/dist/subscription-contract/index.d.cts +17 -0
- package/dist/subscription-contract/index.d.ts +17 -0
- package/dist/subscription-contract/index.js +21 -0
- package/dist/subscription-contract.service--cm47ZJJ.d.cts +39 -0
- package/dist/subscription-contract.service--cm47ZJJ.d.ts +39 -0
- package/dist/testing/index.cjs +3942 -0
- package/dist/testing/index.d.cts +279 -0
- package/dist/testing/index.d.ts +279 -0
- package/dist/testing/index.js +1195 -0
- package/package.json +185 -0
|
@@ -0,0 +1,805 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
+
for (let key of __getOwnPropNames(from))
|
|
14
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
20
|
+
|
|
21
|
+
// src/entitlement/index.ts
|
|
22
|
+
var entitlement_exports = {};
|
|
23
|
+
__export(entitlement_exports, {
|
|
24
|
+
ENTITLEMENT_RESOLUTION_CONFIG_TOKEN: () => ENTITLEMENT_RESOLUTION_CONFIG_TOKEN,
|
|
25
|
+
EntitlementModule: () => EntitlementModule,
|
|
26
|
+
EntitlementService: () => EntitlementService,
|
|
27
|
+
LimitExceededError: () => LimitExceededError,
|
|
28
|
+
PLAN_VERSION_REPOSITORY_TOKEN: () => PLAN_VERSION_REPOSITORY_TOKEN,
|
|
29
|
+
SUBSCRIPTION_REPOSITORY_TOKEN: () => SUBSCRIPTION_REPOSITORY_TOKEN,
|
|
30
|
+
TRANSACTION_RUNNER_TOKEN: () => TRANSACTION_RUNNER_TOKEN,
|
|
31
|
+
aggregateBusinessTypeQuotas: () => aggregateBusinessTypeQuotas,
|
|
32
|
+
aggregateContractLineItemEntitlements: () => aggregateContractLineItemEntitlements,
|
|
33
|
+
aggregateLimits: () => aggregateLimits,
|
|
34
|
+
aggregateSubscriptionBundleQuotas: () => aggregateSubscriptionBundleQuotas,
|
|
35
|
+
applyCustomLimits: () => applyCustomLimits,
|
|
36
|
+
buildReplacedByIndex: () => buildReplacedByIndex,
|
|
37
|
+
collectBusinessTypeFeatures: () => collectBusinessTypeFeatures,
|
|
38
|
+
collectSubscriptionBundleFeatures: () => collectSubscriptionBundleFeatures,
|
|
39
|
+
expandReplacedFeatures: () => expandReplacedFeatures,
|
|
40
|
+
filterActiveSubscriptionBundles: () => filterActiveSubscriptionBundles,
|
|
41
|
+
filterPlannedOnlyFeatures: () => filterPlannedOnlyFeatures,
|
|
42
|
+
hasAnyFeature: () => hasAnyFeature,
|
|
43
|
+
hasFeature: () => hasFeature,
|
|
44
|
+
resolveEntitlementPlan: () => resolveEntitlementPlan,
|
|
45
|
+
toEffectiveLimitsSnapshot: () => toEffectiveLimitsSnapshot
|
|
46
|
+
});
|
|
47
|
+
module.exports = __toCommonJS(entitlement_exports);
|
|
48
|
+
|
|
49
|
+
// src/billing/plan-helpers.ts
|
|
50
|
+
function isFeaturePlannedOnly(catalog, featureKey) {
|
|
51
|
+
const def = (catalog.features ?? []).find((f) => f.key === featureKey);
|
|
52
|
+
return def?.plannedOnly === true;
|
|
53
|
+
}
|
|
54
|
+
__name(isFeaturePlannedOnly, "isFeaturePlannedOnly");
|
|
55
|
+
|
|
56
|
+
// src/entitlement/aggregation.ts
|
|
57
|
+
function aggregateBusinessTypeQuotas(snapshot) {
|
|
58
|
+
const sums = {};
|
|
59
|
+
for (const bundle of snapshot.bundles) {
|
|
60
|
+
for (const [key, value] of Object.entries(bundle.quotas)) {
|
|
61
|
+
if (sums[key] === -1 || value === -1) {
|
|
62
|
+
sums[key] = -1;
|
|
63
|
+
} else {
|
|
64
|
+
sums[key] = (sums[key] ?? 0) + value;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
for (const [key, value] of Object.entries(snapshot.quotaOverrides)) {
|
|
69
|
+
if (value !== void 0) {
|
|
70
|
+
sums[key] = value;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return sums;
|
|
74
|
+
}
|
|
75
|
+
__name(aggregateBusinessTypeQuotas, "aggregateBusinessTypeQuotas");
|
|
76
|
+
function filterActiveSubscriptionBundles(bundles, now) {
|
|
77
|
+
return bundles.filter((b) => b.canceledEffectiveAt === null || b.canceledEffectiveAt > now);
|
|
78
|
+
}
|
|
79
|
+
__name(filterActiveSubscriptionBundles, "filterActiveSubscriptionBundles");
|
|
80
|
+
function aggregateSubscriptionBundleQuotas(bundles) {
|
|
81
|
+
const sums = {};
|
|
82
|
+
for (const bundle of bundles) {
|
|
83
|
+
for (const [key, value] of Object.entries(bundle.quotas)) {
|
|
84
|
+
if (sums[key] === -1 || value === -1) {
|
|
85
|
+
sums[key] = -1;
|
|
86
|
+
} else {
|
|
87
|
+
sums[key] = (sums[key] ?? 0) + value;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return sums;
|
|
92
|
+
}
|
|
93
|
+
__name(aggregateSubscriptionBundleQuotas, "aggregateSubscriptionBundleQuotas");
|
|
94
|
+
function collectSubscriptionBundleFeatures(bundles) {
|
|
95
|
+
const set = /* @__PURE__ */ new Set();
|
|
96
|
+
for (const bundle of bundles) {
|
|
97
|
+
for (const f of bundle.features) set.add(f);
|
|
98
|
+
}
|
|
99
|
+
return Array.from(set);
|
|
100
|
+
}
|
|
101
|
+
__name(collectSubscriptionBundleFeatures, "collectSubscriptionBundleFeatures");
|
|
102
|
+
function aggregateContractLineItemEntitlements(lineItems, fallbackPlan = "UNKNOWN") {
|
|
103
|
+
const planItem = lineItems.find((item) => item.kind === "plan");
|
|
104
|
+
const plan = planItem?.sourceKey ?? fallbackPlan;
|
|
105
|
+
const quotas = {};
|
|
106
|
+
const features = /* @__PURE__ */ new Set();
|
|
107
|
+
for (const item of lineItems) {
|
|
108
|
+
for (const feature of item.featuresSnapshot) {
|
|
109
|
+
features.add(feature);
|
|
110
|
+
}
|
|
111
|
+
for (const [key, value] of Object.entries(item.quotaEffectsSnapshot)) {
|
|
112
|
+
if (quotas[key] === -1 || value === -1) {
|
|
113
|
+
quotas[key] = -1;
|
|
114
|
+
} else {
|
|
115
|
+
quotas[key] = (quotas[key] ?? 0) + value;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
return {
|
|
120
|
+
plan,
|
|
121
|
+
quotas,
|
|
122
|
+
features
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
__name(aggregateContractLineItemEntitlements, "aggregateContractLineItemEntitlements");
|
|
126
|
+
function collectBusinessTypeFeatures(snapshot) {
|
|
127
|
+
const set = /* @__PURE__ */ new Set();
|
|
128
|
+
for (const bundle of snapshot.bundles) {
|
|
129
|
+
for (const f of bundle.features) {
|
|
130
|
+
set.add(f);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return Array.from(set);
|
|
134
|
+
}
|
|
135
|
+
__name(collectBusinessTypeFeatures, "collectBusinessTypeFeatures");
|
|
136
|
+
function filterPlannedOnlyFeatures(features, catalog) {
|
|
137
|
+
const out = /* @__PURE__ */ new Set();
|
|
138
|
+
for (const f of features) {
|
|
139
|
+
if (!isFeaturePlannedOnly(catalog, f)) {
|
|
140
|
+
out.add(f);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
return out;
|
|
144
|
+
}
|
|
145
|
+
__name(filterPlannedOnlyFeatures, "filterPlannedOnlyFeatures");
|
|
146
|
+
function applyCustomLimits(base, custom) {
|
|
147
|
+
if (!custom) return base;
|
|
148
|
+
const quotas = {
|
|
149
|
+
...base.quotas
|
|
150
|
+
};
|
|
151
|
+
if (custom.quotas) {
|
|
152
|
+
for (const [k, v] of Object.entries(custom.quotas)) {
|
|
153
|
+
quotas[k] = v;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
const features = new Set(base.features);
|
|
157
|
+
if (custom.features) {
|
|
158
|
+
for (const f of custom.features) features.add(f);
|
|
159
|
+
}
|
|
160
|
+
return {
|
|
161
|
+
plan: base.plan,
|
|
162
|
+
quotas,
|
|
163
|
+
features
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
__name(applyCustomLimits, "applyCustomLimits");
|
|
167
|
+
function aggregateLimits(input, catalog, now) {
|
|
168
|
+
const businessTypeQuotas = input.businessTypeVersion ? aggregateBusinessTypeQuotas(input.businessTypeVersion) : {};
|
|
169
|
+
const businessTypeFeatures = input.businessTypeVersion ? collectBusinessTypeFeatures(input.businessTypeVersion) : [];
|
|
170
|
+
const activeBundles = filterActiveSubscriptionBundles(input.subscriptionBundles ?? [], now);
|
|
171
|
+
const subBundleQuotas = aggregateSubscriptionBundleQuotas(activeBundles);
|
|
172
|
+
const subBundleFeatures = collectSubscriptionBundleFeatures(activeBundles);
|
|
173
|
+
const quotas = {};
|
|
174
|
+
for (const [k, v] of Object.entries(input.planVersion.quotas)) {
|
|
175
|
+
quotas[k] = v;
|
|
176
|
+
}
|
|
177
|
+
for (const [k, v] of Object.entries(businessTypeQuotas)) {
|
|
178
|
+
if (quotas[k] === -1 || v === -1) {
|
|
179
|
+
quotas[k] = -1;
|
|
180
|
+
} else {
|
|
181
|
+
quotas[k] = (quotas[k] ?? 0) + v;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
for (const [k, v] of Object.entries(subBundleQuotas)) {
|
|
185
|
+
if (quotas[k] === -1 || v === -1) {
|
|
186
|
+
quotas[k] = -1;
|
|
187
|
+
} else {
|
|
188
|
+
quotas[k] = (quotas[k] ?? 0) + v;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
const features = /* @__PURE__ */ new Set([
|
|
192
|
+
...input.planVersion.features,
|
|
193
|
+
...businessTypeFeatures,
|
|
194
|
+
...subBundleFeatures
|
|
195
|
+
]);
|
|
196
|
+
const withCustom = applyCustomLimits({
|
|
197
|
+
plan: input.plan,
|
|
198
|
+
quotas,
|
|
199
|
+
features
|
|
200
|
+
}, input.customLimits);
|
|
201
|
+
const filteredFeatures = filterPlannedOnlyFeatures(withCustom.features, catalog);
|
|
202
|
+
return {
|
|
203
|
+
plan: withCustom.plan,
|
|
204
|
+
quotas: withCustom.quotas,
|
|
205
|
+
features: filteredFeatures
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
__name(aggregateLimits, "aggregateLimits");
|
|
209
|
+
function hasFeature(limits, feature) {
|
|
210
|
+
return limits.features.has(feature);
|
|
211
|
+
}
|
|
212
|
+
__name(hasFeature, "hasFeature");
|
|
213
|
+
function hasAnyFeature(limits, features) {
|
|
214
|
+
return features.some((f) => limits.features.has(f));
|
|
215
|
+
}
|
|
216
|
+
__name(hasAnyFeature, "hasAnyFeature");
|
|
217
|
+
function toEffectiveLimitsSnapshot(limits) {
|
|
218
|
+
return {
|
|
219
|
+
plan: limits.plan,
|
|
220
|
+
quotas: {
|
|
221
|
+
...limits.quotas
|
|
222
|
+
},
|
|
223
|
+
features: Array.from(limits.features).sort()
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
__name(toEffectiveLimitsSnapshot, "toEffectiveLimitsSnapshot");
|
|
227
|
+
|
|
228
|
+
// src/entitlement/feature-aliases.ts
|
|
229
|
+
function buildReplacedByIndex(features) {
|
|
230
|
+
const index = /* @__PURE__ */ new Map();
|
|
231
|
+
for (const feature of features) {
|
|
232
|
+
for (const oldKey of feature.replaces ?? []) {
|
|
233
|
+
if (oldKey === feature.featureKey) continue;
|
|
234
|
+
const list = index.get(oldKey) ?? [];
|
|
235
|
+
list.push(feature.featureKey);
|
|
236
|
+
index.set(oldKey, list);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
for (const list of index.values()) list.sort((a, b) => a.localeCompare(b));
|
|
240
|
+
assertNoReplacesCycle(index);
|
|
241
|
+
return index;
|
|
242
|
+
}
|
|
243
|
+
__name(buildReplacedByIndex, "buildReplacedByIndex");
|
|
244
|
+
function expandReplacedFeatures(granted, index) {
|
|
245
|
+
const expanded = new Set(granted);
|
|
246
|
+
const worklist = [
|
|
247
|
+
...granted
|
|
248
|
+
];
|
|
249
|
+
while (worklist.length > 0) {
|
|
250
|
+
const key = worklist.pop();
|
|
251
|
+
for (const successor of index.get(key) ?? []) {
|
|
252
|
+
if (expanded.has(successor)) continue;
|
|
253
|
+
expanded.add(successor);
|
|
254
|
+
worklist.push(successor);
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
return expanded;
|
|
258
|
+
}
|
|
259
|
+
__name(expandReplacedFeatures, "expandReplacedFeatures");
|
|
260
|
+
function assertNoReplacesCycle(index) {
|
|
261
|
+
const DONE = 2;
|
|
262
|
+
const IN_PROGRESS = 1;
|
|
263
|
+
const state = /* @__PURE__ */ new Map();
|
|
264
|
+
const visit = /* @__PURE__ */ __name((key, path) => {
|
|
265
|
+
const s = state.get(key);
|
|
266
|
+
if (s === DONE) return;
|
|
267
|
+
if (s === IN_PROGRESS) {
|
|
268
|
+
const cycleStart = path.indexOf(key);
|
|
269
|
+
const cycle = [
|
|
270
|
+
...path.slice(cycleStart),
|
|
271
|
+
key
|
|
272
|
+
].join(" \u2192 ");
|
|
273
|
+
throw new Error(`replaces-Zyklus in den Discovery-Metadaten: ${cycle}. Feature-Ersetzungen m\xFCssen azyklisch sein \u2014 replaces-Deklarationen im Code korrigieren (#39).`);
|
|
274
|
+
}
|
|
275
|
+
state.set(key, IN_PROGRESS);
|
|
276
|
+
for (const successor of index.get(key) ?? []) {
|
|
277
|
+
visit(successor, [
|
|
278
|
+
...path,
|
|
279
|
+
key
|
|
280
|
+
]);
|
|
281
|
+
}
|
|
282
|
+
state.set(key, DONE);
|
|
283
|
+
}, "visit");
|
|
284
|
+
for (const key of index.keys()) visit(key, []);
|
|
285
|
+
}
|
|
286
|
+
__name(assertNoReplacesCycle, "assertNoReplacesCycle");
|
|
287
|
+
|
|
288
|
+
// src/entitlement/plan-resolution.ts
|
|
289
|
+
function resolveEntitlementPlan(input, config, now) {
|
|
290
|
+
if (input.isPilot && config.pilotEntitlementPlan !== void 0) {
|
|
291
|
+
return config.pilotEntitlementPlan;
|
|
292
|
+
}
|
|
293
|
+
if (input.status === "TRIAL") {
|
|
294
|
+
return input.trialEntitlementPlan ?? config.defaultTrialEntitlementPlan ?? input.plan;
|
|
295
|
+
}
|
|
296
|
+
if (input.status === "PENDING_SALES" && config.pendingSalesEntitlementPlan !== void 0) {
|
|
297
|
+
return config.pendingSalesEntitlementPlan;
|
|
298
|
+
}
|
|
299
|
+
if (input.pendingPlan && input.pendingEffectiveAt && input.pendingEffectiveAt <= now) {
|
|
300
|
+
return input.pendingPlan;
|
|
301
|
+
}
|
|
302
|
+
return input.plan;
|
|
303
|
+
}
|
|
304
|
+
__name(resolveEntitlementPlan, "resolveEntitlementPlan");
|
|
305
|
+
|
|
306
|
+
// src/entitlement/limit-exceeded-error.ts
|
|
307
|
+
var LimitExceededError = class extends Error {
|
|
308
|
+
static {
|
|
309
|
+
__name(this, "LimitExceededError");
|
|
310
|
+
}
|
|
311
|
+
dimension;
|
|
312
|
+
max;
|
|
313
|
+
used;
|
|
314
|
+
constructor(dimension, max, used) {
|
|
315
|
+
super(`Limit f\xFCr ${dimension} erreicht: ${used}/${max}.`), this.dimension = dimension, this.max = max, this.used = used;
|
|
316
|
+
this.name = "LimitExceededError";
|
|
317
|
+
}
|
|
318
|
+
};
|
|
319
|
+
|
|
320
|
+
// src/entitlement/service.ts
|
|
321
|
+
var import_common2 = require("@nestjs/common");
|
|
322
|
+
|
|
323
|
+
// src/catalog/tokens.ts
|
|
324
|
+
var BUNDLE_REPOSITORY_TOKEN = /* @__PURE__ */ Symbol("BUNDLE_REPOSITORY");
|
|
325
|
+
|
|
326
|
+
// src/billing/plan-catalog.module.ts
|
|
327
|
+
var import_common = require("@nestjs/common");
|
|
328
|
+
|
|
329
|
+
// src/core/di.ts
|
|
330
|
+
function asProvider(token, impl) {
|
|
331
|
+
if (typeof impl === "object" && impl !== null && "useFactory" in impl && typeof impl.useFactory === "function") {
|
|
332
|
+
const factory = impl;
|
|
333
|
+
return {
|
|
334
|
+
provide: token,
|
|
335
|
+
useFactory: factory.useFactory,
|
|
336
|
+
inject: factory.inject
|
|
337
|
+
};
|
|
338
|
+
}
|
|
339
|
+
return {
|
|
340
|
+
provide: token,
|
|
341
|
+
useValue: impl
|
|
342
|
+
};
|
|
343
|
+
}
|
|
344
|
+
__name(asProvider, "asProvider");
|
|
345
|
+
|
|
346
|
+
// src/billing/plan-catalog-from-snapshot.ts
|
|
347
|
+
function buildPlanCatalogFromSnapshot(settings, snapshot) {
|
|
348
|
+
const liveByPlanKey = new Map(snapshot.livePlanVersions.map((v) => [
|
|
349
|
+
v.planId,
|
|
350
|
+
v
|
|
351
|
+
]));
|
|
352
|
+
const plans = snapshot.plans.filter((p) => p.deletedAt === null).sort((a, b) => a.sortOrder - b.sortOrder).map((stem) => {
|
|
353
|
+
const live = liveByPlanKey.get(stem.planKey);
|
|
354
|
+
if (!live) {
|
|
355
|
+
return {
|
|
356
|
+
id: stem.planKey,
|
|
357
|
+
name: stem.label,
|
|
358
|
+
tagline: stem.description ?? void 0,
|
|
359
|
+
marketed: false,
|
|
360
|
+
monthlyNet: null,
|
|
361
|
+
yearlyNet: null,
|
|
362
|
+
features: [],
|
|
363
|
+
quotas: {}
|
|
364
|
+
};
|
|
365
|
+
}
|
|
366
|
+
return {
|
|
367
|
+
id: stem.planKey,
|
|
368
|
+
name: stem.label,
|
|
369
|
+
tagline: stem.description ?? void 0,
|
|
370
|
+
marketed: live.marketed,
|
|
371
|
+
monthlyNet: parseFloat(live.monthlyNet),
|
|
372
|
+
yearlyNet: parseFloat(live.yearlyNet),
|
|
373
|
+
features: live.features,
|
|
374
|
+
quotas: live.quotas ?? {}
|
|
375
|
+
};
|
|
376
|
+
});
|
|
377
|
+
const features = snapshot.featureEntries.filter((f) => f.deletedAt === null).sort((a, b) => a.sortOrder - b.sortOrder).map((row) => ({
|
|
378
|
+
key: row.featureKey,
|
|
379
|
+
label: row.label,
|
|
380
|
+
icon: row.icon ?? void 0,
|
|
381
|
+
tier: row.tier ?? void 0,
|
|
382
|
+
plannedOnly: row.plannedOnly
|
|
383
|
+
}));
|
|
384
|
+
return {
|
|
385
|
+
schemaVersion: 1,
|
|
386
|
+
projectKey: settings.projectKey,
|
|
387
|
+
...settings.app ? {
|
|
388
|
+
app: settings.app
|
|
389
|
+
} : {},
|
|
390
|
+
currency: settings.currency,
|
|
391
|
+
vatRate: settings.vatRate,
|
|
392
|
+
...settings.marketing ? {
|
|
393
|
+
marketing: settings.marketing
|
|
394
|
+
} : {},
|
|
395
|
+
features,
|
|
396
|
+
plans
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
__name(buildPlanCatalogFromSnapshot, "buildPlanCatalogFromSnapshot");
|
|
400
|
+
|
|
401
|
+
// src/billing/plan-catalog.module.ts
|
|
402
|
+
function _ts_decorate(decorators, target, key, desc) {
|
|
403
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
404
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
405
|
+
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;
|
|
406
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
407
|
+
}
|
|
408
|
+
__name(_ts_decorate, "_ts_decorate");
|
|
409
|
+
var PLAN_CATALOG_TOKEN = /* @__PURE__ */ Symbol("PLAN_CATALOG");
|
|
410
|
+
var PLAN_CATALOG_READ_SINK_TOKEN = /* @__PURE__ */ Symbol("PLAN_CATALOG_READ_SINK");
|
|
411
|
+
var PlanCatalogModule = class _PlanCatalogModule {
|
|
412
|
+
static {
|
|
413
|
+
__name(this, "PlanCatalogModule");
|
|
414
|
+
}
|
|
415
|
+
static forRoot(options) {
|
|
416
|
+
return {
|
|
417
|
+
module: _PlanCatalogModule,
|
|
418
|
+
global: options.global ?? true,
|
|
419
|
+
imports: options.imports ?? [],
|
|
420
|
+
providers: [
|
|
421
|
+
...options.extraProviders ?? [],
|
|
422
|
+
asProvider(PLAN_CATALOG_READ_SINK_TOKEN, options.sink),
|
|
423
|
+
{
|
|
424
|
+
provide: PLAN_CATALOG_TOKEN,
|
|
425
|
+
useFactory: /* @__PURE__ */ __name(async (sink) => {
|
|
426
|
+
const snapshot = await sink.loadSnapshot(options.projectKey);
|
|
427
|
+
return buildPlanCatalogFromSnapshot({
|
|
428
|
+
projectKey: options.projectKey,
|
|
429
|
+
app: options.app,
|
|
430
|
+
currency: options.currency,
|
|
431
|
+
vatRate: options.vatRate,
|
|
432
|
+
marketing: options.marketing
|
|
433
|
+
}, snapshot);
|
|
434
|
+
}, "useFactory"),
|
|
435
|
+
inject: [
|
|
436
|
+
PLAN_CATALOG_READ_SINK_TOKEN
|
|
437
|
+
]
|
|
438
|
+
}
|
|
439
|
+
],
|
|
440
|
+
exports: [
|
|
441
|
+
PLAN_CATALOG_TOKEN,
|
|
442
|
+
PLAN_CATALOG_READ_SINK_TOKEN
|
|
443
|
+
]
|
|
444
|
+
};
|
|
445
|
+
}
|
|
446
|
+
/**
|
|
447
|
+
* Tests / in-memory setup: takes the catalog object directly, without a
|
|
448
|
+
* sink/DB lookup. For unit tests + test bootstraps.
|
|
449
|
+
*/
|
|
450
|
+
static forRootWithCatalog(catalog, opts = {}) {
|
|
451
|
+
return {
|
|
452
|
+
module: _PlanCatalogModule,
|
|
453
|
+
providers: [
|
|
454
|
+
{
|
|
455
|
+
provide: PLAN_CATALOG_TOKEN,
|
|
456
|
+
useValue: catalog
|
|
457
|
+
}
|
|
458
|
+
],
|
|
459
|
+
exports: [
|
|
460
|
+
PLAN_CATALOG_TOKEN
|
|
461
|
+
],
|
|
462
|
+
global: opts.global ?? true
|
|
463
|
+
};
|
|
464
|
+
}
|
|
465
|
+
};
|
|
466
|
+
PlanCatalogModule = _ts_decorate([
|
|
467
|
+
(0, import_common.Module)({})
|
|
468
|
+
], PlanCatalogModule);
|
|
469
|
+
|
|
470
|
+
// src/billing/subscription-bundles.tokens.ts
|
|
471
|
+
var SUBSCRIPTION_BUNDLE_REPOSITORY_TOKEN = /* @__PURE__ */ Symbol.for("saas-platform/SubscriptionBundleRepository");
|
|
472
|
+
|
|
473
|
+
// src/subscription-contract/tokens.ts
|
|
474
|
+
var SUBSCRIPTION_CONTRACT_REPOSITORY_TOKEN = /* @__PURE__ */ Symbol.for("saas-platform/SubscriptionContractRepository");
|
|
475
|
+
|
|
476
|
+
// src/discovery/tokens.ts
|
|
477
|
+
var DISCOVERY_SNAPSHOT_TOKEN = /* @__PURE__ */ Symbol.for("saas-platform/DiscoverySnapshot");
|
|
478
|
+
|
|
479
|
+
// src/entitlement/tokens.ts
|
|
480
|
+
var SUBSCRIPTION_REPOSITORY_TOKEN = /* @__PURE__ */ Symbol.for("saas-platform/SubscriptionRepository");
|
|
481
|
+
var PLAN_VERSION_REPOSITORY_TOKEN = /* @__PURE__ */ Symbol.for("saas-platform/PlanVersionRepository");
|
|
482
|
+
var TRANSACTION_RUNNER_TOKEN = /* @__PURE__ */ Symbol.for("saas-platform/TransactionRunner");
|
|
483
|
+
var ENTITLEMENT_RESOLUTION_CONFIG_TOKEN = /* @__PURE__ */ Symbol.for("saas-platform/EntitlementResolutionConfig");
|
|
484
|
+
|
|
485
|
+
// src/entitlement/service.ts
|
|
486
|
+
function _ts_decorate2(decorators, target, key, desc) {
|
|
487
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
488
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
489
|
+
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;
|
|
490
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
491
|
+
}
|
|
492
|
+
__name(_ts_decorate2, "_ts_decorate");
|
|
493
|
+
function _ts_metadata(k, v) {
|
|
494
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
495
|
+
}
|
|
496
|
+
__name(_ts_metadata, "_ts_metadata");
|
|
497
|
+
function _ts_param(paramIndex, decorator) {
|
|
498
|
+
return function(target, key) {
|
|
499
|
+
decorator(target, key, paramIndex);
|
|
500
|
+
};
|
|
501
|
+
}
|
|
502
|
+
__name(_ts_param, "_ts_param");
|
|
503
|
+
var CACHE_TTL_MS = 6e4;
|
|
504
|
+
var CACHE_MAX_ENTRIES = 1e3;
|
|
505
|
+
var EntitlementService = class {
|
|
506
|
+
static {
|
|
507
|
+
__name(this, "EntitlementService");
|
|
508
|
+
}
|
|
509
|
+
catalog;
|
|
510
|
+
subscriptions;
|
|
511
|
+
planVersions;
|
|
512
|
+
tx;
|
|
513
|
+
resolutionConfig;
|
|
514
|
+
subscriptionBundles;
|
|
515
|
+
bundles;
|
|
516
|
+
subscriptionContracts;
|
|
517
|
+
discoverySnapshot;
|
|
518
|
+
// Map preserves insert order — on a hit the entry is removed and
|
|
519
|
+
// re-inserted (LRU). The TTL is a safety net for forgotten
|
|
520
|
+
// invalidations — 60s is enough, because limits generally only change
|
|
521
|
+
// through mutations, not through time (a pending plan's effective date
|
|
522
|
+
// is day-granular).
|
|
523
|
+
cache = /* @__PURE__ */ new Map();
|
|
524
|
+
// #39 — replaces alias index, built lazily from the boot-static snapshot;
|
|
525
|
+
// throws on replaces cycles (a clear error instead of an infinite loop).
|
|
526
|
+
replacedByIndex = null;
|
|
527
|
+
constructor(catalog, subscriptions, planVersions, tx, resolutionConfig = null, subscriptionBundles = null, bundles = null, subscriptionContracts = null, discoverySnapshot = null) {
|
|
528
|
+
this.catalog = catalog;
|
|
529
|
+
this.subscriptions = subscriptions;
|
|
530
|
+
this.planVersions = planVersions;
|
|
531
|
+
this.tx = tx;
|
|
532
|
+
this.resolutionConfig = resolutionConfig;
|
|
533
|
+
this.subscriptionBundles = subscriptionBundles;
|
|
534
|
+
this.bundles = bundles;
|
|
535
|
+
this.subscriptionContracts = subscriptionContracts;
|
|
536
|
+
this.discoverySnapshot = discoverySnapshot;
|
|
537
|
+
}
|
|
538
|
+
// ---------------------------------------------------------------------
|
|
539
|
+
// Read path — for FeatureGuard, sidebar hooks, GET /billing/entitlement
|
|
540
|
+
// ---------------------------------------------------------------------
|
|
541
|
+
async computeLimits(tenantId, now = /* @__PURE__ */ new Date()) {
|
|
542
|
+
const cached = this.readCache(tenantId, now.getTime());
|
|
543
|
+
if (cached) return cached;
|
|
544
|
+
const sub = await this.subscriptions.findByTenantId(tenantId);
|
|
545
|
+
if (!sub) {
|
|
546
|
+
throw new import_common2.NotFoundException(`Keine Subscription f\xFCr Tenant ${tenantId}`);
|
|
547
|
+
}
|
|
548
|
+
const limits = await this.deriveLimits(sub, now);
|
|
549
|
+
this.writeCache(tenantId, limits, now.getTime());
|
|
550
|
+
return limits;
|
|
551
|
+
}
|
|
552
|
+
/**
|
|
553
|
+
* Clears a tenant's cache entry. MUST be called as soon as a mutation
|
|
554
|
+
* changes the subscription, a bundle booking, or a PlanVersion binding —
|
|
555
|
+
* otherwise FeatureGuard and the sidebar stay on stale state for up to
|
|
556
|
+
* 60s.
|
|
557
|
+
*/
|
|
558
|
+
invalidateTenant(tenantId) {
|
|
559
|
+
this.cache.delete(tenantId);
|
|
560
|
+
}
|
|
561
|
+
/** Clears the entire cache. Only for tests / bootstrap. */
|
|
562
|
+
invalidateAll() {
|
|
563
|
+
this.cache.clear();
|
|
564
|
+
}
|
|
565
|
+
/**
|
|
566
|
+
* Aggregator path — also callable directly by consumers that already
|
|
567
|
+
* have a `SubscriptionRecord` (e.g. within a transaction).
|
|
568
|
+
*/
|
|
569
|
+
async deriveLimits(sub, now, tx) {
|
|
570
|
+
const contractLimits = await this.deriveLimitsFromContract(sub.tenantId, now);
|
|
571
|
+
if (contractLimits) return this.withReplacedFeatureAliases(contractLimits);
|
|
572
|
+
const effectivePlan = resolveEntitlementPlan(sub, this.resolutionConfig ?? {}, now);
|
|
573
|
+
const planVersion = effectivePlan === sub.plan ? sub.planVersion : await this.findActivePlanVersionOrFallback(effectivePlan, now, tx);
|
|
574
|
+
const subscriptionBundles = await this.loadSubscriptionBundleSnapshots(sub.id, now);
|
|
575
|
+
return this.withReplacedFeatureAliases(aggregateLimits({
|
|
576
|
+
plan: effectivePlan,
|
|
577
|
+
planVersion,
|
|
578
|
+
subscriptionBundles,
|
|
579
|
+
customLimits: sub.customLimits ?? null
|
|
580
|
+
}, this.catalog, now));
|
|
581
|
+
}
|
|
582
|
+
/**
|
|
583
|
+
* Grandfathering (#39): granted old feature keys transitively grant
|
|
584
|
+
* their successors from the `replaces` chains of the discovery snapshot.
|
|
585
|
+
* A no-op without a snapshot or without replaces declarations.
|
|
586
|
+
*/
|
|
587
|
+
withReplacedFeatureAliases(limits) {
|
|
588
|
+
if (!this.discoverySnapshot) return limits;
|
|
589
|
+
if (!this.replacedByIndex) {
|
|
590
|
+
this.replacedByIndex = buildReplacedByIndex(this.discoverySnapshot.features);
|
|
591
|
+
}
|
|
592
|
+
if (this.replacedByIndex.size === 0) return limits;
|
|
593
|
+
return {
|
|
594
|
+
...limits,
|
|
595
|
+
features: expandReplacedFeatures(limits.features, this.replacedByIndex)
|
|
596
|
+
};
|
|
597
|
+
}
|
|
598
|
+
async deriveLimitsFromContract(tenantId, now) {
|
|
599
|
+
if (!this.subscriptionContracts) return null;
|
|
600
|
+
const contract = await this.subscriptionContracts.findActiveByTenantId(tenantId, now);
|
|
601
|
+
if (!contract) return null;
|
|
602
|
+
if (contract.entitlementSnapshot) {
|
|
603
|
+
return {
|
|
604
|
+
plan: contract.entitlementSnapshot.plan,
|
|
605
|
+
quotas: {
|
|
606
|
+
...contract.entitlementSnapshot.quotas
|
|
607
|
+
},
|
|
608
|
+
features: new Set(contract.entitlementSnapshot.features)
|
|
609
|
+
};
|
|
610
|
+
}
|
|
611
|
+
return aggregateContractLineItemEntitlements(contract.lineItems);
|
|
612
|
+
}
|
|
613
|
+
/**
|
|
614
|
+
* Loads a subscription's active bundle bookings and resolves the
|
|
615
|
+
* `BundleVersion` features/quotas per entry. Without a registered
|
|
616
|
+
* `SubscriptionBundleRepository` or `BundleRepository` the method
|
|
617
|
+
* returns an empty list — apps without a bundle schema stay unchanged
|
|
618
|
+
* (plan-only aggregation).
|
|
619
|
+
*/
|
|
620
|
+
async loadSubscriptionBundleSnapshots(subscriptionId, now) {
|
|
621
|
+
if (!this.subscriptionBundles || !this.bundles) return [];
|
|
622
|
+
const active = await this.subscriptionBundles.listActiveBySubscription(subscriptionId, now);
|
|
623
|
+
if (active.length === 0) return [];
|
|
624
|
+
return Promise.all(active.map(async (booking) => {
|
|
625
|
+
const bv = await this.bundles.findVersionById(booking.bundleVersionId);
|
|
626
|
+
if (!bv) {
|
|
627
|
+
throw new Error(`BundleVersion '${booking.bundleVersionId}' aus aktiver SubscriptionBundle nicht gefunden`);
|
|
628
|
+
}
|
|
629
|
+
return {
|
|
630
|
+
bundleKey: bv.bundleKey,
|
|
631
|
+
features: bv.features,
|
|
632
|
+
quotas: bv.quotas,
|
|
633
|
+
canceledEffectiveAt: booking.canceledEffectiveAt
|
|
634
|
+
};
|
|
635
|
+
}));
|
|
636
|
+
}
|
|
637
|
+
// ---------------------------------------------------------------------
|
|
638
|
+
// Write/consumption path — row lock + count + insert in the same
|
|
639
|
+
// transaction. Protects against race conditions on concurrent creations
|
|
640
|
+
// for the same tenant.
|
|
641
|
+
// ---------------------------------------------------------------------
|
|
642
|
+
async enforceLimit(input) {
|
|
643
|
+
const now = input.now ?? /* @__PURE__ */ new Date();
|
|
644
|
+
const delta = input.delta ?? 1;
|
|
645
|
+
return this.tx.run(async (tx) => {
|
|
646
|
+
const sub = await this.subscriptions.findByTenantIdLocked(input.tenantId, tx);
|
|
647
|
+
if (!sub) {
|
|
648
|
+
throw new import_common2.NotFoundException(`Keine Subscription f\xFCr Tenant ${input.tenantId}`);
|
|
649
|
+
}
|
|
650
|
+
const limits = await this.deriveLimits(sub, now, tx);
|
|
651
|
+
const max = limits.quotas[input.dimension];
|
|
652
|
+
if (max === void 0) {
|
|
653
|
+
throw new Error(`Quota-Dimension "${input.dimension}" nicht im PlanCatalog (${this.catalog.projectKey}).`);
|
|
654
|
+
}
|
|
655
|
+
const used = await input.currentUsage(tx, input.tenantId);
|
|
656
|
+
if (max !== -1 && used + delta > max) {
|
|
657
|
+
throw new LimitExceededError(input.dimension, max, used);
|
|
658
|
+
}
|
|
659
|
+
return input.insert(tx);
|
|
660
|
+
});
|
|
661
|
+
}
|
|
662
|
+
// ---------------------------------------------------------------------
|
|
663
|
+
// Helpers
|
|
664
|
+
// ---------------------------------------------------------------------
|
|
665
|
+
/**
|
|
666
|
+
* Plan fallback for TRIAL/PENDING_SALES: returns the PlanVersion active
|
|
667
|
+
* as of `asOf` (SPEC_V2 §4.2). If the repo does not implement
|
|
668
|
+
* `findActive`, we fall back to `findLatestLive` (backward compat for
|
|
669
|
+
* adapters without `validFrom` columns).
|
|
670
|
+
*/
|
|
671
|
+
async findActivePlanVersionOrFallback(planId, asOf, tx) {
|
|
672
|
+
const v = this.planVersions.findActive ? await this.planVersions.findActive(planId, asOf, tx) : await this.planVersions.findLatestLive(planId, tx);
|
|
673
|
+
if (!v) {
|
|
674
|
+
throw new import_common2.NotFoundException(`Keine zu ${asOf.toISOString().slice(0, 10)} aktive PlanVersion f\xFCr ${planId} \u2014 weder validFrom-window erf\xFCllt noch latest-live verf\xFCgbar.`);
|
|
675
|
+
}
|
|
676
|
+
return v;
|
|
677
|
+
}
|
|
678
|
+
readCache(tenantId, nowMs) {
|
|
679
|
+
const entry = this.cache.get(tenantId);
|
|
680
|
+
if (!entry) return null;
|
|
681
|
+
if (entry.expiresAt < nowMs) {
|
|
682
|
+
this.cache.delete(tenantId);
|
|
683
|
+
return null;
|
|
684
|
+
}
|
|
685
|
+
this.cache.delete(tenantId);
|
|
686
|
+
this.cache.set(tenantId, entry);
|
|
687
|
+
return entry.value;
|
|
688
|
+
}
|
|
689
|
+
writeCache(tenantId, value, nowMs) {
|
|
690
|
+
if (this.cache.has(tenantId)) this.cache.delete(tenantId);
|
|
691
|
+
this.cache.set(tenantId, {
|
|
692
|
+
value,
|
|
693
|
+
expiresAt: nowMs + CACHE_TTL_MS
|
|
694
|
+
});
|
|
695
|
+
while (this.cache.size > CACHE_MAX_ENTRIES) {
|
|
696
|
+
const oldest = this.cache.keys().next().value;
|
|
697
|
+
if (oldest === void 0) break;
|
|
698
|
+
this.cache.delete(oldest);
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
};
|
|
702
|
+
EntitlementService = _ts_decorate2([
|
|
703
|
+
(0, import_common2.Injectable)(),
|
|
704
|
+
_ts_param(0, (0, import_common2.Inject)(PLAN_CATALOG_TOKEN)),
|
|
705
|
+
_ts_param(1, (0, import_common2.Inject)(SUBSCRIPTION_REPOSITORY_TOKEN)),
|
|
706
|
+
_ts_param(2, (0, import_common2.Inject)(PLAN_VERSION_REPOSITORY_TOKEN)),
|
|
707
|
+
_ts_param(3, (0, import_common2.Inject)(TRANSACTION_RUNNER_TOKEN)),
|
|
708
|
+
_ts_param(4, (0, import_common2.Optional)()),
|
|
709
|
+
_ts_param(4, (0, import_common2.Inject)(ENTITLEMENT_RESOLUTION_CONFIG_TOKEN)),
|
|
710
|
+
_ts_param(5, (0, import_common2.Optional)()),
|
|
711
|
+
_ts_param(5, (0, import_common2.Inject)(SUBSCRIPTION_BUNDLE_REPOSITORY_TOKEN)),
|
|
712
|
+
_ts_param(6, (0, import_common2.Optional)()),
|
|
713
|
+
_ts_param(6, (0, import_common2.Inject)(BUNDLE_REPOSITORY_TOKEN)),
|
|
714
|
+
_ts_param(7, (0, import_common2.Optional)()),
|
|
715
|
+
_ts_param(7, (0, import_common2.Inject)(SUBSCRIPTION_CONTRACT_REPOSITORY_TOKEN)),
|
|
716
|
+
_ts_param(8, (0, import_common2.Optional)()),
|
|
717
|
+
_ts_param(8, (0, import_common2.Inject)(DISCOVERY_SNAPSHOT_TOKEN)),
|
|
718
|
+
_ts_metadata("design:type", Function),
|
|
719
|
+
_ts_metadata("design:paramtypes", [
|
|
720
|
+
typeof PlanCatalog === "undefined" ? Object : PlanCatalog,
|
|
721
|
+
typeof SubscriptionRepository === "undefined" ? Object : SubscriptionRepository,
|
|
722
|
+
typeof PlanVersionRepository === "undefined" ? Object : PlanVersionRepository,
|
|
723
|
+
typeof TransactionRunner === "undefined" ? Object : TransactionRunner,
|
|
724
|
+
Object,
|
|
725
|
+
Object,
|
|
726
|
+
Object,
|
|
727
|
+
Object,
|
|
728
|
+
Object
|
|
729
|
+
])
|
|
730
|
+
], EntitlementService);
|
|
731
|
+
|
|
732
|
+
// src/entitlement/module.ts
|
|
733
|
+
var import_common3 = require("@nestjs/common");
|
|
734
|
+
function _ts_decorate3(decorators, target, key, desc) {
|
|
735
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
736
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
737
|
+
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;
|
|
738
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
739
|
+
}
|
|
740
|
+
__name(_ts_decorate3, "_ts_decorate");
|
|
741
|
+
var EntitlementModule = class _EntitlementModule {
|
|
742
|
+
static {
|
|
743
|
+
__name(this, "EntitlementModule");
|
|
744
|
+
}
|
|
745
|
+
static forRoot(options) {
|
|
746
|
+
const providers = [
|
|
747
|
+
asProvider(SUBSCRIPTION_REPOSITORY_TOKEN, options.subscriptionRepository),
|
|
748
|
+
asProvider(PLAN_VERSION_REPOSITORY_TOKEN, options.planVersionRepository),
|
|
749
|
+
asProvider(TRANSACTION_RUNNER_TOKEN, options.transactionRunner),
|
|
750
|
+
EntitlementService
|
|
751
|
+
];
|
|
752
|
+
if (options.resolutionConfig) {
|
|
753
|
+
providers.push({
|
|
754
|
+
provide: ENTITLEMENT_RESOLUTION_CONFIG_TOKEN,
|
|
755
|
+
useValue: options.resolutionConfig
|
|
756
|
+
});
|
|
757
|
+
}
|
|
758
|
+
if (options.subscriptionContractRepository) {
|
|
759
|
+
providers.push(asProvider(SUBSCRIPTION_CONTRACT_REPOSITORY_TOKEN, options.subscriptionContractRepository));
|
|
760
|
+
}
|
|
761
|
+
if (options.subscriptionBundleRepository) {
|
|
762
|
+
providers.push(asProvider(SUBSCRIPTION_BUNDLE_REPOSITORY_TOKEN, options.subscriptionBundleRepository));
|
|
763
|
+
}
|
|
764
|
+
if (options.bundleRepository) {
|
|
765
|
+
providers.push(asProvider(BUNDLE_REPOSITORY_TOKEN, options.bundleRepository));
|
|
766
|
+
}
|
|
767
|
+
return {
|
|
768
|
+
module: _EntitlementModule,
|
|
769
|
+
global: options.global ?? false,
|
|
770
|
+
providers,
|
|
771
|
+
exports: [
|
|
772
|
+
EntitlementService,
|
|
773
|
+
SUBSCRIPTION_REPOSITORY_TOKEN
|
|
774
|
+
]
|
|
775
|
+
};
|
|
776
|
+
}
|
|
777
|
+
};
|
|
778
|
+
EntitlementModule = _ts_decorate3([
|
|
779
|
+
(0, import_common3.Module)({})
|
|
780
|
+
], EntitlementModule);
|
|
781
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
782
|
+
0 && (module.exports = {
|
|
783
|
+
ENTITLEMENT_RESOLUTION_CONFIG_TOKEN,
|
|
784
|
+
EntitlementModule,
|
|
785
|
+
EntitlementService,
|
|
786
|
+
LimitExceededError,
|
|
787
|
+
PLAN_VERSION_REPOSITORY_TOKEN,
|
|
788
|
+
SUBSCRIPTION_REPOSITORY_TOKEN,
|
|
789
|
+
TRANSACTION_RUNNER_TOKEN,
|
|
790
|
+
aggregateBusinessTypeQuotas,
|
|
791
|
+
aggregateContractLineItemEntitlements,
|
|
792
|
+
aggregateLimits,
|
|
793
|
+
aggregateSubscriptionBundleQuotas,
|
|
794
|
+
applyCustomLimits,
|
|
795
|
+
buildReplacedByIndex,
|
|
796
|
+
collectBusinessTypeFeatures,
|
|
797
|
+
collectSubscriptionBundleFeatures,
|
|
798
|
+
expandReplacedFeatures,
|
|
799
|
+
filterActiveSubscriptionBundles,
|
|
800
|
+
filterPlannedOnlyFeatures,
|
|
801
|
+
hasAnyFeature,
|
|
802
|
+
hasFeature,
|
|
803
|
+
resolveEntitlementPlan,
|
|
804
|
+
toEffectiveLimitsSnapshot
|
|
805
|
+
});
|