@saasicat/nest 0.26.0 → 0.27.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 +90 -201
- package/dist/_entries.cjs +3265 -2846
- package/dist/billing/index.d.cts +4 -4
- package/dist/billing/index.d.ts +4 -4
- package/dist/billing/index.js +33 -31
- package/dist/catalog/index.js +5 -5
- package/dist/checkout-offer/index.js +2 -2
- package/dist/chunk-2FR6ZL7R.js +0 -0
- package/dist/chunk-2JTISFUZ.js +792 -0
- package/dist/chunk-2SLTRKXC.js +0 -0
- package/dist/chunk-3E6ONOMG.js +50 -0
- package/dist/{chunk-UOWK2HYG.js → chunk-7ZPFQXHM.js} +1 -1
- package/dist/{chunk-B7NRY2LV.js → chunk-CJFAOD7K.js} +1 -39
- package/dist/{chunk-J62YI25C.js → chunk-EHKMPP6J.js} +1194 -775
- package/dist/{chunk-RPO4IVUY.js → chunk-F4B2NJUZ.js} +26 -91
- package/dist/chunk-H4DOTO7S.js +85 -0
- package/dist/{chunk-V3MRZ7SH.js → chunk-UHD6FJBQ.js} +421 -1197
- package/dist/{define-saasicat-BK6RRWWG.d.ts → define-saasicat-3ois8t8s.d.ts} +26 -3
- package/dist/{define-saasicat-D30I-WET.d.cts → define-saasicat-CFxut1VR.d.cts} +26 -3
- package/dist/{enforce-quota.interceptor-B9QueAFf.d.ts → enforce-quota.interceptor-CYDNvAQz.d.ts} +3 -3
- package/dist/{enforce-quota.interceptor-DY6CLjoP.d.cts → enforce-quota.interceptor-N80KC34N.d.cts} +3 -3
- package/dist/entitlement/index.js +7 -4
- package/dist/index.d.cts +5 -5
- package/dist/index.d.ts +5 -5
- package/dist/index.js +87 -79
- package/dist/{saas-platform.module-D1mUZPrz.d.ts → module-options-ByJL7FZm.d.ts} +40 -27
- package/dist/{saas-platform.module-CgalxzcT.d.cts → module-options-klrPnWGF.d.cts} +40 -27
- package/dist/platform/index.d.cts +201 -19
- package/dist/platform/index.d.ts +201 -19
- package/dist/platform/index.js +58 -33
- package/dist/promo/index.js +2 -2
- package/dist/subscription-contract/index.js +5 -2
- package/dist/{tenant-billing.controller-DHSUrT_N.d.cts → tenant-billing.controller-CAMMdfn1.d.cts} +1 -1
- package/dist/{tenant-billing.controller-BSlpFqVA.d.ts → tenant-billing.controller-CYYK0CpT.d.ts} +1 -1
- package/dist/{subscription-bundles.module-BDbODWvA.d.ts → tenant-billing.module-B0stLoJn.d.ts} +51 -51
- package/dist/{subscription-bundles.module-Cfi-lFWF.d.cts → tenant-billing.module-BxJS6fX4.d.cts} +51 -51
- package/dist/testing/index.d.cts +8 -8
- package/dist/testing/index.d.ts +8 -8
- package/dist/testing/index.js +13 -11
- package/package.json +4 -4
- package/dist/{chunk-QB7MICKQ.js → chunk-7X5MSAIL.js} +9 -9
- package/dist/{chunk-FY4EJTV4.js → chunk-OYNHOY45.js} +0 -0
- package/dist/{chunk-I4XD43AN.js → chunk-XTVAFJ3P.js} +3 -3
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
} from "./chunk-37HEKVDH.js";
|
|
4
4
|
import {
|
|
5
5
|
SubscriptionContractService
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-CJFAOD7K.js";
|
|
7
7
|
import {
|
|
8
8
|
AUDIT_CONTEXT_RESOLVER_TOKEN,
|
|
9
9
|
PENDING_PLAN_QUERY_PORT_TOKEN,
|
|
@@ -16,13 +16,18 @@ import {
|
|
|
16
16
|
USER_EMAIL_RESOLVER_TOKEN,
|
|
17
17
|
USER_ID_RESOLVER_TOKEN
|
|
18
18
|
} from "./chunk-WPUVJRIN.js";
|
|
19
|
+
import {
|
|
20
|
+
AdminAuditService
|
|
21
|
+
} from "./chunk-E56W4U2P.js";
|
|
22
|
+
import {
|
|
23
|
+
SaaSiCatPublicRoute
|
|
24
|
+
} from "./chunk-YSC46BGM.js";
|
|
19
25
|
import {
|
|
20
26
|
EntitlementService,
|
|
21
27
|
SUBSCRIPTION_BUNDLE_CONFIG_TOKEN,
|
|
22
28
|
SUBSCRIPTION_BUNDLE_REPOSITORY_TOKEN,
|
|
23
|
-
isLimitExceededError,
|
|
24
29
|
toEffectiveLimitsSnapshot
|
|
25
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-F4B2NJUZ.js";
|
|
26
31
|
import {
|
|
27
32
|
PLAN_CATALOG_TOKEN,
|
|
28
33
|
findPlan,
|
|
@@ -32,6 +37,9 @@ import {
|
|
|
32
37
|
import {
|
|
33
38
|
SUBSCRIPTION_CONTRACT_REPOSITORY_TOKEN
|
|
34
39
|
} from "./chunk-NYLON2VC.js";
|
|
40
|
+
import {
|
|
41
|
+
codedError
|
|
42
|
+
} from "./chunk-EBJJNTW6.js";
|
|
35
43
|
import {
|
|
36
44
|
ENTITLEMENT_SERVICE_TOKEN
|
|
37
45
|
} from "./chunk-WKVBNTYC.js";
|
|
@@ -40,15 +48,6 @@ import {
|
|
|
40
48
|
CATALOG_ENTRY_REPOSITORY_TOKEN,
|
|
41
49
|
PLAN_REPOSITORY_TOKEN
|
|
42
50
|
} from "./chunk-L4KTQ6CL.js";
|
|
43
|
-
import {
|
|
44
|
-
AdminAuditService
|
|
45
|
-
} from "./chunk-E56W4U2P.js";
|
|
46
|
-
import {
|
|
47
|
-
SaaSiCatPublicRoute
|
|
48
|
-
} from "./chunk-YSC46BGM.js";
|
|
49
|
-
import {
|
|
50
|
-
codedError
|
|
51
|
-
} from "./chunk-EBJJNTW6.js";
|
|
52
51
|
import {
|
|
53
52
|
asProvider
|
|
54
53
|
} from "./chunk-SABTXESR.js";
|
|
@@ -92,88 +91,6 @@ function periodEndWithMinLead(startedAt, cycle, now, minLeadDays = 42) {
|
|
|
92
91
|
}
|
|
93
92
|
__name(periodEndWithMinLead, "periodEndWithMinLead");
|
|
94
93
|
|
|
95
|
-
// src/billing/version-publish.ts
|
|
96
|
-
var PublishValidationError = class extends Error {
|
|
97
|
-
static {
|
|
98
|
-
__name(this, "PublishValidationError");
|
|
99
|
-
}
|
|
100
|
-
code;
|
|
101
|
-
constructor(code, message) {
|
|
102
|
-
super(message), this.code = code;
|
|
103
|
-
this.name = "PublishValidationError";
|
|
104
|
-
}
|
|
105
|
-
};
|
|
106
|
-
function assertChangeNote(changeNote) {
|
|
107
|
-
const trimmed = (changeNote ?? "").trim();
|
|
108
|
-
if (trimmed.length === 0) {
|
|
109
|
-
throw new PublishValidationError("CHANGE_NOTE_REQUIRED", "changeNote is required when publishing a version.");
|
|
110
|
-
}
|
|
111
|
-
return trimmed;
|
|
112
|
-
}
|
|
113
|
-
__name(assertChangeNote, "assertChangeNote");
|
|
114
|
-
function assertDraftPublishable(draft, draftId) {
|
|
115
|
-
if (!draft) {
|
|
116
|
-
throw new PublishValidationError("NOT_FOUND", `PlanVersion ${draftId} not found`);
|
|
117
|
-
}
|
|
118
|
-
if (draft.publishedAt !== null) {
|
|
119
|
-
throw new PublishValidationError("ALREADY_PUBLISHED", `PlanVersion ${draftId} has already been published.`);
|
|
120
|
-
}
|
|
121
|
-
if (!draft.baseVersionId) {
|
|
122
|
-
throw new PublishValidationError("NO_BASE_VERSION", `Draft ${draftId} has no baseVersion \u2014 probably a manually created v1 that may only be published via a migration.`);
|
|
123
|
-
}
|
|
124
|
-
}
|
|
125
|
-
__name(assertDraftPublishable, "assertDraftPublishable");
|
|
126
|
-
function assertBaseVersionFresh(base, baseId, planContext) {
|
|
127
|
-
if (!base) {
|
|
128
|
-
throw new PublishValidationError("BASE_NOT_FOUND", `baseVersion ${baseId} no longer exists.`);
|
|
129
|
-
}
|
|
130
|
-
if (base.supersededAt !== null) {
|
|
131
|
-
throw new PublishValidationError("BASE_SUPERSEDED", `The draft is based on a superseded version (${planContext}). Rebase the draft onto the current live version, or create a new one.`);
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
__name(assertBaseVersionFresh, "assertBaseVersionFresh");
|
|
135
|
-
function assertOptimisticLockHeld(updateCount, draftId) {
|
|
136
|
-
if (updateCount !== 1) {
|
|
137
|
-
throw new PublishValidationError("OPTIMISTIC_LOCK_CONFLICT", `Draft ${draftId} has meanwhile been published by another admin.`);
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
__name(assertOptimisticLockHeld, "assertOptimisticLockHeld");
|
|
141
|
-
|
|
142
|
-
// src/billing/version-renewal.ts
|
|
143
|
-
function decideRenewal(sub, now) {
|
|
144
|
-
if (!sub.pendingPlanVersionId || !sub.pendingPlanVersionEffectiveAt) return "SKIP";
|
|
145
|
-
if (sub.pendingPlanVersionEffectiveAt > now) return "SKIP";
|
|
146
|
-
if (sub.pendingPlanVersionNonRegressive || sub.pendingPlanVersionAccepted) {
|
|
147
|
-
return "ROLL_FORWARD";
|
|
148
|
-
}
|
|
149
|
-
return "CLEAR_PENDING";
|
|
150
|
-
}
|
|
151
|
-
__name(decideRenewal, "decideRenewal");
|
|
152
|
-
function clearPendingPlanVersionFields() {
|
|
153
|
-
return {
|
|
154
|
-
pendingPlanVersionId: null,
|
|
155
|
-
pendingPlanVersionEffectiveAt: null,
|
|
156
|
-
pendingPlanVersionAccepted: false,
|
|
157
|
-
pendingPlanVersionAcceptedAt: null,
|
|
158
|
-
pendingPlanVersionAcceptedByUserId: null,
|
|
159
|
-
pendingPlanVersionNotifiedAt: null,
|
|
160
|
-
pendingPlanVersionReminderSentAt: null
|
|
161
|
-
};
|
|
162
|
-
}
|
|
163
|
-
__name(clearPendingPlanVersionFields, "clearPendingPlanVersionFields");
|
|
164
|
-
function computeNextPeriod(sub, now) {
|
|
165
|
-
if (sub.canceledAt !== null) return null;
|
|
166
|
-
if (sub.currentPeriodEnd === null) return null;
|
|
167
|
-
if (sub.currentPeriodEnd > now) return null;
|
|
168
|
-
const newStart = sub.currentPeriodEnd;
|
|
169
|
-
const newEnd = periodEndAfter(newStart, sub.billingCycle, now);
|
|
170
|
-
return {
|
|
171
|
-
currentPeriodStart: newStart,
|
|
172
|
-
currentPeriodEnd: newEnd
|
|
173
|
-
};
|
|
174
|
-
}
|
|
175
|
-
__name(computeNextPeriod, "computeNextPeriod");
|
|
176
|
-
|
|
177
94
|
// src/billing/feature-guard-marker.ts
|
|
178
95
|
var FEATURE_GUARD_MARKER = /* @__PURE__ */ Symbol.for("saasicat/nest/feature-guard");
|
|
179
96
|
function isPlatformFeatureGuard(target) {
|
|
@@ -189,628 +106,35 @@ import { SetMetadata } from "@nestjs/common";
|
|
|
189
106
|
var REQUIRE_FEATURE_KEY = "require-feature";
|
|
190
107
|
var RequireFeature = /* @__PURE__ */ __name((...features) => SetMetadata(REQUIRE_FEATURE_KEY, features), "RequireFeature");
|
|
191
108
|
|
|
192
|
-
// src/billing/feature-guard.tokens.ts
|
|
193
|
-
var FEATURE_GUARD_CONFIG_TOKEN = /* @__PURE__ */ Symbol.for("saas-platform/FeatureGuardConfig");
|
|
194
|
-
|
|
195
|
-
// src/billing/feature.guard.ts
|
|
196
|
-
import { ForbiddenException, Inject, Injectable, Logger, Optional } from "@nestjs/common";
|
|
197
|
-
import { Reflector } from "@nestjs/core";
|
|
198
|
-
import { AUTH_ERROR_CODES, FEATURE_NOT_LICENSED } from "@saasicat/types";
|
|
199
|
-
|
|
200
|
-
// src/billing/upsell.tokens.ts
|
|
201
|
-
var UPSELL_OFFER_RESOLVER_TOKEN = /* @__PURE__ */ Symbol.for("saas-platform/UpsellOfferResolver");
|
|
202
|
-
var UPSELL_OFFER_CURRENCY_TOKEN = /* @__PURE__ */ Symbol.for("saas-platform/UpsellOfferCurrency");
|
|
203
|
-
|
|
204
|
-
// src/billing/feature.guard.ts
|
|
205
|
-
function _ts_decorate(decorators, target, key, desc) {
|
|
206
|
-
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
207
|
-
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
208
|
-
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;
|
|
209
|
-
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
210
|
-
}
|
|
211
|
-
__name(_ts_decorate, "_ts_decorate");
|
|
212
|
-
function _ts_metadata(k, v) {
|
|
213
|
-
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
214
|
-
}
|
|
215
|
-
__name(_ts_metadata, "_ts_metadata");
|
|
216
|
-
function _ts_param(paramIndex, decorator) {
|
|
217
|
-
return function(target, key) {
|
|
218
|
-
decorator(target, key, paramIndex);
|
|
219
|
-
};
|
|
220
|
-
}
|
|
221
|
-
__name(_ts_param, "_ts_param");
|
|
222
|
-
var FeatureGuard = class _FeatureGuard {
|
|
223
|
-
static {
|
|
224
|
-
__name(this, "FeatureGuard");
|
|
225
|
-
}
|
|
226
|
-
reflector;
|
|
227
|
-
entitlements;
|
|
228
|
-
config;
|
|
229
|
-
upsellResolver;
|
|
230
|
-
/** Lets `FeatureGuardCoverageCheck` recognise this guard across CJS entries. */
|
|
231
|
-
static [FEATURE_GUARD_MARKER] = true;
|
|
232
|
-
logger = new Logger(_FeatureGuard.name);
|
|
233
|
-
constructor(reflector, entitlements, config = null, upsellResolver = null) {
|
|
234
|
-
this.reflector = reflector;
|
|
235
|
-
this.entitlements = entitlements;
|
|
236
|
-
this.config = config;
|
|
237
|
-
this.upsellResolver = upsellResolver;
|
|
238
|
-
}
|
|
239
|
-
async canActivate(context) {
|
|
240
|
-
const required = this.reflector.getAllAndOverride(REQUIRE_FEATURE_KEY, [
|
|
241
|
-
context.getHandler(),
|
|
242
|
-
context.getClass()
|
|
243
|
-
]);
|
|
244
|
-
if (!required || required.length === 0) return true;
|
|
245
|
-
const request = context.switchToHttp().getRequest();
|
|
246
|
-
const user = request.user;
|
|
247
|
-
if (!user) {
|
|
248
|
-
throw new ForbiddenException({
|
|
249
|
-
code: AUTH_ERROR_CODES.NOT_AUTHENTICATED,
|
|
250
|
-
message: "Not authenticated"
|
|
251
|
-
});
|
|
252
|
-
}
|
|
253
|
-
const role = this.config?.userRoleResolver ? this.config.userRoleResolver(user) : user.role ?? user.platformRole;
|
|
254
|
-
if (role === "SUPER_ADMIN") return true;
|
|
255
|
-
const tenantId = this.config?.tenantIdResolver ? this.config.tenantIdResolver(request) : request.tenantId ?? user.tenantId;
|
|
256
|
-
if (!tenantId) {
|
|
257
|
-
throw new ForbiddenException({
|
|
258
|
-
code: AUTH_ERROR_CODES.NO_TENANT_ASSIGNED,
|
|
259
|
-
message: "No tenant assigned"
|
|
260
|
-
});
|
|
261
|
-
}
|
|
262
|
-
const compute = /* @__PURE__ */ __name(() => this.entitlements.computeLimits(tenantId), "compute");
|
|
263
|
-
const limits = this.config?.tenantContextRunner ? await this.config.tenantContextRunner(tenantId, compute) : await compute();
|
|
264
|
-
const allowed = required.some((f) => limits.features.has(f));
|
|
265
|
-
if (!allowed) {
|
|
266
|
-
throw await this.buildNotLicensedException(required, tenantId);
|
|
267
|
-
}
|
|
268
|
-
return true;
|
|
269
|
-
}
|
|
270
|
-
/**
|
|
271
|
-
* Upsell response (#36): the 403 body is always the full
|
|
272
|
-
* `FeatureNotLicensedBody`, so a consumer that matches on `code` can read
|
|
273
|
-
* `featureKey`/`offers` unconditionally. Without a registered
|
|
274
|
-
* `UpsellOfferResolver` there is simply nothing to offer — `offers` is
|
|
275
|
-
* empty, the same degradation a failing resolver produces.
|
|
276
|
-
*
|
|
277
|
-
* Deliberately 403 + `code` field instead of 402 — rationale in
|
|
278
|
-
* `@saasicat/types` upsell.types.ts (402 is reserved / inconsistently
|
|
279
|
-
* supported; SPA interceptors must not treat the 403 as an auth error, the
|
|
280
|
-
* distinction runs through `code`).
|
|
281
|
-
*
|
|
282
|
-
* The message must keep starting with the word `Feature` — consumers
|
|
283
|
-
* classify the response by that prefix.
|
|
284
|
-
*/
|
|
285
|
-
async buildNotLicensedException(required, tenantId) {
|
|
286
|
-
const body = {
|
|
287
|
-
code: FEATURE_NOT_LICENSED,
|
|
288
|
-
featureKey: required[0],
|
|
289
|
-
featureKeys: required,
|
|
290
|
-
offers: this.upsellResolver ? await this.resolveOffersSafe(required, tenantId) : [],
|
|
291
|
-
message: `Feature ${required.join(" / ")} is not included in the current plan.`
|
|
292
|
-
};
|
|
293
|
-
return new ForbiddenException(body);
|
|
294
|
-
}
|
|
295
|
-
/**
|
|
296
|
-
* A resolver error must not turn the semantically correct 403 into a 500 —
|
|
297
|
-
* degrade to empty offers and log.
|
|
298
|
-
*/
|
|
299
|
-
async resolveOffersSafe(required, tenantId) {
|
|
300
|
-
try {
|
|
301
|
-
return await this.upsellResolver.resolveOffers(required, tenantId);
|
|
302
|
-
} catch (error) {
|
|
303
|
-
this.logger.warn(`UpsellOfferResolver failed for [${required.join(", ")}]: ${String(error)}`);
|
|
304
|
-
return [];
|
|
305
|
-
}
|
|
306
|
-
}
|
|
307
|
-
};
|
|
308
|
-
FeatureGuard = _ts_decorate([
|
|
309
|
-
Injectable(),
|
|
310
|
-
_ts_param(0, Inject(Reflector)),
|
|
311
|
-
_ts_param(1, Inject(ENTITLEMENT_SERVICE_TOKEN)),
|
|
312
|
-
_ts_param(2, Optional()),
|
|
313
|
-
_ts_param(2, Inject(FEATURE_GUARD_CONFIG_TOKEN)),
|
|
314
|
-
_ts_param(3, Optional()),
|
|
315
|
-
_ts_param(3, Inject(UPSELL_OFFER_RESOLVER_TOKEN)),
|
|
316
|
-
_ts_metadata("design:type", Function),
|
|
317
|
-
_ts_metadata("design:paramtypes", [
|
|
318
|
-
typeof Reflector === "undefined" ? Object : Reflector,
|
|
319
|
-
typeof EntitlementService === "undefined" ? Object : EntitlementService,
|
|
320
|
-
Object,
|
|
321
|
-
Object
|
|
322
|
-
])
|
|
323
|
-
], FeatureGuard);
|
|
324
|
-
|
|
325
|
-
// src/billing/catalog-bundle-upsell-resolver.ts
|
|
326
|
-
import { Inject as Inject2, Injectable as Injectable2, Optional as Optional2 } from "@nestjs/common";
|
|
327
|
-
import { buildFeatureRequiresIndex, collectUnsatisfiedRequires } from "@saasicat/types";
|
|
328
|
-
|
|
329
109
|
// src/billing/public-catalog.tokens.ts
|
|
330
110
|
var PUBLIC_CATALOG_PROJECT_KEY_TOKEN = /* @__PURE__ */ Symbol.for("saas-platform/PublicCatalogProjectKey");
|
|
331
111
|
var PUBLIC_CATALOG_BUNDLE_REPOSITORY_TOKEN = /* @__PURE__ */ Symbol.for("saas-platform/PublicCatalogBundleRepository");
|
|
332
112
|
var PUBLIC_CATALOG_MARKETING_REPOSITORY_TOKEN = /* @__PURE__ */ Symbol.for("saas-platform/PublicCatalogMarketingRepository");
|
|
333
113
|
var PUBLIC_CATALOG_CATALOG_ENTRY_REPOSITORY_TOKEN = /* @__PURE__ */ Symbol.for("saas-platform/PublicCatalogCatalogEntryRepository");
|
|
334
114
|
|
|
335
|
-
// src/billing/catalog-bundle-upsell-resolver.ts
|
|
336
|
-
function _ts_decorate2(decorators, target, key, desc) {
|
|
337
|
-
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
338
|
-
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
339
|
-
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;
|
|
340
|
-
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
341
|
-
}
|
|
342
|
-
__name(_ts_decorate2, "_ts_decorate");
|
|
343
|
-
function _ts_metadata2(k, v) {
|
|
344
|
-
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
345
|
-
}
|
|
346
|
-
__name(_ts_metadata2, "_ts_metadata");
|
|
347
|
-
function _ts_param2(paramIndex, decorator) {
|
|
348
|
-
return function(target, key) {
|
|
349
|
-
decorator(target, key, paramIndex);
|
|
350
|
-
};
|
|
351
|
-
}
|
|
352
|
-
__name(_ts_param2, "_ts_param");
|
|
353
|
-
var DEFAULT_CURRENCY = "EUR";
|
|
354
|
-
var CatalogBundleUpsellResolver = class {
|
|
355
|
-
static {
|
|
356
|
-
__name(this, "CatalogBundleUpsellResolver");
|
|
357
|
-
}
|
|
358
|
-
bundleRepo;
|
|
359
|
-
projectKey;
|
|
360
|
-
catalogEntryRepo;
|
|
361
|
-
currency;
|
|
362
|
-
constructor(bundleRepo, projectKey, catalogEntryRepo = null, currency = null) {
|
|
363
|
-
this.bundleRepo = bundleRepo;
|
|
364
|
-
this.projectKey = projectKey;
|
|
365
|
-
this.catalogEntryRepo = catalogEntryRepo;
|
|
366
|
-
this.currency = currency;
|
|
367
|
-
}
|
|
368
|
-
async resolveOffers(featureKeys, tenantId) {
|
|
369
|
-
void tenantId;
|
|
370
|
-
if (featureKeys.length === 0) return [];
|
|
371
|
-
const missing = new Set(featureKeys);
|
|
372
|
-
const wanted = /* @__PURE__ */ new Set([
|
|
373
|
-
...featureKeys,
|
|
374
|
-
...await this.lookupUnmetRequires(featureKeys)
|
|
375
|
-
]);
|
|
376
|
-
const ranked = [];
|
|
377
|
-
for (const live of await this.listLiveMarketedBundles()) {
|
|
378
|
-
const features = live.features;
|
|
379
|
-
if (!features.some((key) => missing.has(key))) continue;
|
|
380
|
-
ranked.push({
|
|
381
|
-
offer: this.toOffer(live),
|
|
382
|
-
coverage: features.filter((key) => wanted.has(key)).length
|
|
383
|
-
});
|
|
384
|
-
}
|
|
385
|
-
return ranked.sort(compareRankedOffers).map((r) => r.offer);
|
|
386
|
-
}
|
|
387
|
-
/**
|
|
388
|
-
* Uncovered dependencies of the missing features (#35) — feed into the
|
|
389
|
-
* coverage ranking. Without a CatalogEntryRepository: empty (ranking
|
|
390
|
-
* degrades to price).
|
|
391
|
-
*/
|
|
392
|
-
async lookupUnmetRequires(featureKeys) {
|
|
393
|
-
if (!this.catalogEntryRepo) return [];
|
|
394
|
-
const rows = await this.catalogEntryRepo.listFeatures({
|
|
395
|
-
projectKey: this.projectKey
|
|
396
|
-
});
|
|
397
|
-
return collectUnsatisfiedRequires(featureKeys, buildFeatureRequiresIndex(rows));
|
|
398
|
-
}
|
|
399
|
-
/** Only published-and-live AND marketed — non-marketed bundles are not an offer. */
|
|
400
|
-
async listLiveMarketedBundles() {
|
|
401
|
-
const stems = await this.bundleRepo.list({
|
|
402
|
-
projectKey: this.projectKey,
|
|
403
|
-
excludeDeleted: true
|
|
404
|
-
});
|
|
405
|
-
const out = [];
|
|
406
|
-
for (const stem of stems) {
|
|
407
|
-
const live = await this.bundleRepo.findLatestLive(stem.id);
|
|
408
|
-
if (live?.marketed) out.push(live);
|
|
409
|
-
}
|
|
410
|
-
return out;
|
|
411
|
-
}
|
|
412
|
-
toOffer(live) {
|
|
413
|
-
return {
|
|
414
|
-
bundleKey: live.bundleKey,
|
|
415
|
-
bundleVersionId: live.id,
|
|
416
|
-
priceMonthlyNet: parsePrice(live.monthlyNet),
|
|
417
|
-
currency: this.currency ?? DEFAULT_CURRENCY,
|
|
418
|
-
label: live.label
|
|
419
|
-
};
|
|
420
|
-
}
|
|
421
|
-
};
|
|
422
|
-
CatalogBundleUpsellResolver = _ts_decorate2([
|
|
423
|
-
Injectable2(),
|
|
424
|
-
_ts_param2(0, Inject2(PUBLIC_CATALOG_BUNDLE_REPOSITORY_TOKEN)),
|
|
425
|
-
_ts_param2(1, Inject2(PUBLIC_CATALOG_PROJECT_KEY_TOKEN)),
|
|
426
|
-
_ts_param2(2, Optional2()),
|
|
427
|
-
_ts_param2(2, Inject2(PUBLIC_CATALOG_CATALOG_ENTRY_REPOSITORY_TOKEN)),
|
|
428
|
-
_ts_param2(3, Optional2()),
|
|
429
|
-
_ts_param2(3, Inject2(UPSELL_OFFER_CURRENCY_TOKEN)),
|
|
430
|
-
_ts_metadata2("design:type", Function),
|
|
431
|
-
_ts_metadata2("design:paramtypes", [
|
|
432
|
-
typeof BundleRepository === "undefined" ? Object : BundleRepository,
|
|
433
|
-
String,
|
|
434
|
-
Object,
|
|
435
|
-
Object
|
|
436
|
-
])
|
|
437
|
-
], CatalogBundleUpsellResolver);
|
|
438
|
-
function parsePrice(decimal) {
|
|
439
|
-
if (decimal === null) return null;
|
|
440
|
-
const n = Number.parseFloat(decimal);
|
|
441
|
-
return Number.isFinite(n) ? n : null;
|
|
442
|
-
}
|
|
443
|
-
__name(parsePrice, "parsePrice");
|
|
444
|
-
function compareRankedOffers(a, b) {
|
|
445
|
-
if (a.coverage !== b.coverage) return b.coverage - a.coverage;
|
|
446
|
-
const priceA = a.offer.priceMonthlyNet ?? Number.POSITIVE_INFINITY;
|
|
447
|
-
const priceB = b.offer.priceMonthlyNet ?? Number.POSITIVE_INFINITY;
|
|
448
|
-
if (priceA !== priceB) return priceA - priceB;
|
|
449
|
-
return a.offer.bundleKey.localeCompare(b.offer.bundleKey);
|
|
450
|
-
}
|
|
451
|
-
__name(compareRankedOffers, "compareRankedOffers");
|
|
452
|
-
|
|
453
|
-
// src/billing/limit-exceeded.filter.ts
|
|
454
|
-
import { Catch, HttpStatus, Logger as Logger2 } from "@nestjs/common";
|
|
455
|
-
import { BaseExceptionFilter } from "@nestjs/core";
|
|
456
|
-
import { BILLING_ERROR_CODES } from "@saasicat/types";
|
|
457
|
-
function _ts_decorate3(decorators, target, key, desc) {
|
|
458
|
-
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
459
|
-
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
460
|
-
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;
|
|
461
|
-
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
462
|
-
}
|
|
463
|
-
__name(_ts_decorate3, "_ts_decorate");
|
|
464
|
-
var LimitExceededFilter = class _LimitExceededFilter extends BaseExceptionFilter {
|
|
465
|
-
static {
|
|
466
|
-
__name(this, "LimitExceededFilter");
|
|
467
|
-
}
|
|
468
|
-
logger = new Logger2(_LimitExceededFilter.name);
|
|
469
|
-
catch(exception, host) {
|
|
470
|
-
if (!isLimitExceededError(exception)) {
|
|
471
|
-
super.catch(exception, host);
|
|
472
|
-
return;
|
|
473
|
-
}
|
|
474
|
-
const ctx = host.switchToHttp();
|
|
475
|
-
const response = ctx.getResponse();
|
|
476
|
-
const request = ctx.getRequest();
|
|
477
|
-
this.logger.warn(`Limit ${exception.dimension} exceeded: ${exception.used}/${exception.max} on ${request.method ?? "?"} ${request.url ?? ""}`);
|
|
478
|
-
response.status(HttpStatus.PAYMENT_REQUIRED).send({
|
|
479
|
-
statusCode: HttpStatus.PAYMENT_REQUIRED,
|
|
480
|
-
error: "PaymentRequired",
|
|
481
|
-
code: BILLING_ERROR_CODES.LIMIT_EXCEEDED,
|
|
482
|
-
// Deprecated: superseded by `code`, kept until consumers have
|
|
483
|
-
// migrated. Same value, only under the older field name.
|
|
484
|
-
reason: BILLING_ERROR_CODES.LIMIT_EXCEEDED,
|
|
485
|
-
dimension: exception.dimension,
|
|
486
|
-
used: exception.used,
|
|
487
|
-
max: exception.max,
|
|
488
|
-
message: exception.message
|
|
489
|
-
});
|
|
490
|
-
}
|
|
491
|
-
};
|
|
492
|
-
LimitExceededFilter = _ts_decorate3([
|
|
493
|
-
Catch()
|
|
494
|
-
], LimitExceededFilter);
|
|
495
|
-
|
|
496
|
-
// src/billing/plan-catalog-loader.ts
|
|
497
|
-
import { readFileSync } from "fs";
|
|
498
|
-
import { resolve as resolvePath } from "path";
|
|
499
|
-
import yaml from "js-yaml";
|
|
500
|
-
import Ajv2020 from "ajv/dist/2020.js";
|
|
501
|
-
import addFormats from "ajv-formats";
|
|
502
|
-
import { planCatalogSchema } from "@saasicat/spec";
|
|
503
|
-
var PlanCatalogValidationError = class extends Error {
|
|
504
|
-
static {
|
|
505
|
-
__name(this, "PlanCatalogValidationError");
|
|
506
|
-
}
|
|
507
|
-
source;
|
|
508
|
-
errors;
|
|
509
|
-
constructor(source, errors) {
|
|
510
|
-
const messages = errors.map((e) => `${e.instancePath || "/"}: ${e.message ?? "unknown"}`).join("\n ");
|
|
511
|
-
super(`Plan catalog validation failed for ${source}:
|
|
512
|
-
${messages}`), this.source = source, this.errors = errors;
|
|
513
|
-
this.name = "PlanCatalogValidationError";
|
|
514
|
-
}
|
|
515
|
-
};
|
|
516
|
-
function loadPlanCatalogFromFile(opts) {
|
|
517
|
-
const absolutePath = resolvePath(opts.path);
|
|
518
|
-
const raw = readFileSync(absolutePath, "utf-8");
|
|
519
|
-
return loadPlanCatalogFromString(raw, {
|
|
520
|
-
source: absolutePath,
|
|
521
|
-
crossFieldChecks: opts.crossFieldChecks ?? true
|
|
522
|
-
});
|
|
523
|
-
}
|
|
524
|
-
__name(loadPlanCatalogFromFile, "loadPlanCatalogFromFile");
|
|
525
|
-
function loadPlanCatalogFromString(yamlContent, opts) {
|
|
526
|
-
const parsed = yaml.load(yamlContent);
|
|
527
|
-
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
528
|
-
throw new Error(`The YAML content of ${opts.source} is not an object`);
|
|
529
|
-
}
|
|
530
|
-
const ajv = new Ajv2020({
|
|
531
|
-
strict: false,
|
|
532
|
-
allErrors: true
|
|
533
|
-
});
|
|
534
|
-
addFormats.default(ajv);
|
|
535
|
-
const validate = ajv.compile(planCatalogSchema);
|
|
536
|
-
if (!validate(parsed)) {
|
|
537
|
-
throw new PlanCatalogValidationError(opts.source, validate.errors ?? []);
|
|
538
|
-
}
|
|
539
|
-
const catalog = parsed;
|
|
540
|
-
if (opts.crossFieldChecks ?? true) {
|
|
541
|
-
validateConsistency(catalog, opts.source);
|
|
542
|
-
}
|
|
543
|
-
return catalog;
|
|
544
|
-
}
|
|
545
|
-
__name(loadPlanCatalogFromString, "loadPlanCatalogFromString");
|
|
546
|
-
function validateConsistency(catalog, source) {
|
|
547
|
-
const errors = [];
|
|
548
|
-
const declaredFeatureKeys = new Set((catalog.features ?? []).map((f) => f.key));
|
|
549
|
-
const planIds = /* @__PURE__ */ new Set();
|
|
550
|
-
for (const plan of catalog.plans ?? []) {
|
|
551
|
-
if (planIds.has(plan.id)) {
|
|
552
|
-
errors.push(`plans[].id: duplicate plan id "${plan.id}"`);
|
|
553
|
-
}
|
|
554
|
-
planIds.add(plan.id);
|
|
555
|
-
if (catalog.features) {
|
|
556
|
-
for (const fk of plan.features) {
|
|
557
|
-
if (!declaredFeatureKeys.has(fk)) {
|
|
558
|
-
errors.push(`plans[id=${plan.id}].features: Unknown featureKey "${fk}" \u2014 not declared in catalog.features`);
|
|
559
|
-
}
|
|
560
|
-
}
|
|
561
|
-
}
|
|
562
|
-
}
|
|
563
|
-
if (errors.length > 0) {
|
|
564
|
-
const err = new Error(`Plan catalog consistency error in ${source}:
|
|
565
|
-
${errors.join("\n ")}`);
|
|
566
|
-
err.name = "PlanCatalogConsistencyError";
|
|
567
|
-
throw err;
|
|
568
|
-
}
|
|
569
|
-
}
|
|
570
|
-
__name(validateConsistency, "validateConsistency");
|
|
571
|
-
|
|
572
|
-
// src/billing/plan-catalog-importer.service.ts
|
|
573
|
-
import { Inject as Inject3, Injectable as Injectable3 } from "@nestjs/common";
|
|
574
|
-
function _ts_decorate4(decorators, target, key, desc) {
|
|
575
|
-
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
576
|
-
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
577
|
-
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;
|
|
578
|
-
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
579
|
-
}
|
|
580
|
-
__name(_ts_decorate4, "_ts_decorate");
|
|
581
|
-
function _ts_metadata3(k, v) {
|
|
582
|
-
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
583
|
-
}
|
|
584
|
-
__name(_ts_metadata3, "_ts_metadata");
|
|
585
|
-
function _ts_param3(paramIndex, decorator) {
|
|
586
|
-
return function(target, key) {
|
|
587
|
-
decorator(target, key, paramIndex);
|
|
588
|
-
};
|
|
589
|
-
}
|
|
590
|
-
__name(_ts_param3, "_ts_param");
|
|
591
|
-
var PLAN_CATALOG_IMPORT_SINK_TOKEN = /* @__PURE__ */ Symbol.for("saas-platform/PlanCatalogImportSink");
|
|
592
|
-
var IMPORT_CHANGE_NOTE = "Initial import from saas.yaml";
|
|
593
|
-
var PlanCatalogImporterService = class {
|
|
594
|
-
static {
|
|
595
|
-
__name(this, "PlanCatalogImporterService");
|
|
596
|
-
}
|
|
597
|
-
sink;
|
|
598
|
-
constructor(sink) {
|
|
599
|
-
this.sink = sink;
|
|
600
|
-
}
|
|
601
|
-
/**
|
|
602
|
-
* Import directly from a YAML string. Apps pass the contents of the
|
|
603
|
-
* `saas.yaml` through via the HTTP body; CLI tools can read the file
|
|
604
|
-
* contents themselves beforehand.
|
|
605
|
-
*
|
|
606
|
-
* @throws on a schema failure of the YAML (validated first via the loader).
|
|
607
|
-
*/
|
|
608
|
-
async importFromYaml(yamlContent, opts = {}) {
|
|
609
|
-
const catalog = loadPlanCatalogFromString(yamlContent, {
|
|
610
|
-
source: opts.source ?? "http-import",
|
|
611
|
-
crossFieldChecks: opts.crossFieldChecks ?? true
|
|
612
|
-
});
|
|
613
|
-
return this.importCatalog(catalog);
|
|
614
|
-
}
|
|
615
|
-
async importCatalog(catalog) {
|
|
616
|
-
const report = {
|
|
617
|
-
plansCreated: 0,
|
|
618
|
-
plansSkipped: 0,
|
|
619
|
-
planVersionsCreated: 0,
|
|
620
|
-
planVersionsSkipped: 0,
|
|
621
|
-
featureEntriesCreated: 0,
|
|
622
|
-
featureEntriesSkipped: 0,
|
|
623
|
-
warnings: []
|
|
624
|
-
};
|
|
625
|
-
for (const feature of catalog.features ?? []) {
|
|
626
|
-
const result = await this.sink.upsertFeatureCatalogEntry({
|
|
627
|
-
projectKey: catalog.projectKey,
|
|
628
|
-
featureKey: feature.key,
|
|
629
|
-
label: feature.label,
|
|
630
|
-
icon: feature.icon,
|
|
631
|
-
tier: feature.tier,
|
|
632
|
-
plannedOnly: feature.plannedOnly
|
|
633
|
-
});
|
|
634
|
-
if (result.created) report.featureEntriesCreated++;
|
|
635
|
-
else report.featureEntriesSkipped++;
|
|
636
|
-
}
|
|
637
|
-
for (const plan of catalog.plans ?? []) {
|
|
638
|
-
const planResult = await this.sink.upsertPlan({
|
|
639
|
-
projectKey: catalog.projectKey,
|
|
640
|
-
planKey: plan.id,
|
|
641
|
-
label: plan.name ?? plan.id,
|
|
642
|
-
description: plan.tagline ?? null
|
|
643
|
-
});
|
|
644
|
-
if (planResult.created) report.plansCreated++;
|
|
645
|
-
else report.plansSkipped++;
|
|
646
|
-
if (plan.monthlyNet === null || plan.monthlyNet === void 0) {
|
|
647
|
-
report.warnings.push(`Plan '${plan.id}' has no monthlyNet \u2014 skipped (on-request plans need a manual plan version).`);
|
|
648
|
-
continue;
|
|
649
|
-
}
|
|
650
|
-
const versionResult = await this.sink.upsertPlanVersion({
|
|
651
|
-
planKey: plan.id,
|
|
652
|
-
version: 1,
|
|
653
|
-
features: plan.features,
|
|
654
|
-
quotas: plan.quotas,
|
|
655
|
-
monthlyNet: plan.monthlyNet.toFixed(2),
|
|
656
|
-
yearlyNet: (plan.yearlyNet ?? plan.monthlyNet * 10).toFixed(2),
|
|
657
|
-
marketed: plan.marketed ?? true,
|
|
658
|
-
publish: true,
|
|
659
|
-
changeNote: IMPORT_CHANGE_NOTE
|
|
660
|
-
});
|
|
661
|
-
if (versionResult.created) report.planVersionsCreated++;
|
|
662
|
-
else report.planVersionsSkipped++;
|
|
663
|
-
}
|
|
664
|
-
return report;
|
|
665
|
-
}
|
|
666
|
-
};
|
|
667
|
-
PlanCatalogImporterService = _ts_decorate4([
|
|
668
|
-
Injectable3(),
|
|
669
|
-
_ts_param3(0, Inject3(PLAN_CATALOG_IMPORT_SINK_TOKEN)),
|
|
670
|
-
_ts_metadata3("design:type", Function),
|
|
671
|
-
_ts_metadata3("design:paramtypes", [
|
|
672
|
-
typeof PlanCatalogImportSink === "undefined" ? Object : PlanCatalogImportSink
|
|
673
|
-
])
|
|
674
|
-
], PlanCatalogImporterService);
|
|
675
|
-
|
|
676
|
-
// src/billing/plan-catalog-importer.module.ts
|
|
677
|
-
import { Module } from "@nestjs/common";
|
|
678
|
-
|
|
679
|
-
// src/billing/plan-catalog-importer.controller.ts
|
|
680
|
-
import { Body, Controller, Inject as Inject4, Post, UseGuards } from "@nestjs/common";
|
|
681
|
-
import { IsBoolean, IsOptional, IsString, MinLength } from "class-validator";
|
|
682
|
-
function _ts_decorate5(decorators, target, key, desc) {
|
|
683
|
-
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
684
|
-
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
685
|
-
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;
|
|
686
|
-
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
687
|
-
}
|
|
688
|
-
__name(_ts_decorate5, "_ts_decorate");
|
|
689
|
-
function _ts_metadata4(k, v) {
|
|
690
|
-
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
691
|
-
}
|
|
692
|
-
__name(_ts_metadata4, "_ts_metadata");
|
|
693
|
-
function _ts_param4(paramIndex, decorator) {
|
|
694
|
-
return function(target, key) {
|
|
695
|
-
decorator(target, key, paramIndex);
|
|
696
|
-
};
|
|
697
|
-
}
|
|
698
|
-
__name(_ts_param4, "_ts_param");
|
|
699
|
-
var PlanCatalogImportDto = class {
|
|
700
|
-
static {
|
|
701
|
-
__name(this, "PlanCatalogImportDto");
|
|
702
|
-
}
|
|
703
|
-
yamlContent;
|
|
704
|
-
crossFieldChecks;
|
|
705
|
-
};
|
|
706
|
-
_ts_decorate5([
|
|
707
|
-
IsString(),
|
|
708
|
-
MinLength(1),
|
|
709
|
-
_ts_metadata4("design:type", String)
|
|
710
|
-
], PlanCatalogImportDto.prototype, "yamlContent", void 0);
|
|
711
|
-
_ts_decorate5([
|
|
712
|
-
IsOptional(),
|
|
713
|
-
IsBoolean(),
|
|
714
|
-
_ts_metadata4("design:type", Boolean)
|
|
715
|
-
], PlanCatalogImportDto.prototype, "crossFieldChecks", void 0);
|
|
716
|
-
function buildPlanCatalogImporterController(guards) {
|
|
717
|
-
let GeneratedPlanCatalogImporterController = class GeneratedPlanCatalogImporterController {
|
|
718
|
-
static {
|
|
719
|
-
__name(this, "GeneratedPlanCatalogImporterController");
|
|
720
|
-
}
|
|
721
|
-
service;
|
|
722
|
-
constructor(service) {
|
|
723
|
-
this.service = service;
|
|
724
|
-
}
|
|
725
|
-
async import(dto) {
|
|
726
|
-
return this.service.importFromYaml(dto.yamlContent, {
|
|
727
|
-
crossFieldChecks: dto.crossFieldChecks
|
|
728
|
-
});
|
|
729
|
-
}
|
|
730
|
-
};
|
|
731
|
-
_ts_decorate5([
|
|
732
|
-
Post("import"),
|
|
733
|
-
_ts_param4(0, Body()),
|
|
734
|
-
_ts_metadata4("design:type", Function),
|
|
735
|
-
_ts_metadata4("design:paramtypes", [
|
|
736
|
-
typeof PlanCatalogImportDto === "undefined" ? Object : PlanCatalogImportDto
|
|
737
|
-
]),
|
|
738
|
-
_ts_metadata4("design:returntype", Promise)
|
|
739
|
-
], GeneratedPlanCatalogImporterController.prototype, "import", null);
|
|
740
|
-
GeneratedPlanCatalogImporterController = _ts_decorate5([
|
|
741
|
-
Controller("admin/billing/plan-catalog"),
|
|
742
|
-
UseGuards(...guards),
|
|
743
|
-
_ts_param4(0, Inject4(PlanCatalogImporterService)),
|
|
744
|
-
_ts_metadata4("design:type", Function),
|
|
745
|
-
_ts_metadata4("design:paramtypes", [
|
|
746
|
-
typeof PlanCatalogImporterService === "undefined" ? Object : PlanCatalogImporterService
|
|
747
|
-
])
|
|
748
|
-
], GeneratedPlanCatalogImporterController);
|
|
749
|
-
return GeneratedPlanCatalogImporterController;
|
|
750
|
-
}
|
|
751
|
-
__name(buildPlanCatalogImporterController, "buildPlanCatalogImporterController");
|
|
752
|
-
|
|
753
|
-
// src/billing/plan-catalog-importer.module.ts
|
|
754
|
-
function _ts_decorate6(decorators, target, key, desc) {
|
|
755
|
-
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
756
|
-
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
757
|
-
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;
|
|
758
|
-
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
759
|
-
}
|
|
760
|
-
__name(_ts_decorate6, "_ts_decorate");
|
|
761
|
-
var PlanCatalogImporterModule = class _PlanCatalogImporterModule {
|
|
762
|
-
static {
|
|
763
|
-
__name(this, "PlanCatalogImporterModule");
|
|
764
|
-
}
|
|
765
|
-
static forRoot(options) {
|
|
766
|
-
const providers = [
|
|
767
|
-
...options.extraProviders ?? [],
|
|
768
|
-
asProvider(PLAN_CATALOG_IMPORT_SINK_TOKEN, options.sink),
|
|
769
|
-
PlanCatalogImporterService
|
|
770
|
-
];
|
|
771
|
-
const controllers = [];
|
|
772
|
-
if (options.controller) {
|
|
773
|
-
controllers.push(buildPlanCatalogImporterController(options.controller.guards));
|
|
774
|
-
}
|
|
775
|
-
return {
|
|
776
|
-
module: _PlanCatalogImporterModule,
|
|
777
|
-
global: options.global ?? false,
|
|
778
|
-
imports: options.imports ?? [],
|
|
779
|
-
controllers,
|
|
780
|
-
providers,
|
|
781
|
-
exports: [
|
|
782
|
-
PlanCatalogImporterService
|
|
783
|
-
]
|
|
784
|
-
};
|
|
785
|
-
}
|
|
786
|
-
};
|
|
787
|
-
PlanCatalogImporterModule = _ts_decorate6([
|
|
788
|
-
Module({})
|
|
789
|
-
], PlanCatalogImporterModule);
|
|
790
|
-
|
|
791
115
|
// src/billing/feature-ui-registry.tokens.ts
|
|
792
116
|
var FEATURE_UI_REGISTRY_TOKEN = /* @__PURE__ */ Symbol.for("saas-platform/FeatureUiRegistry");
|
|
793
117
|
|
|
794
118
|
// src/billing/public-catalog.controller.ts
|
|
795
|
-
import { Controller
|
|
796
|
-
import { buildFeatureRequiresIndex
|
|
797
|
-
function
|
|
119
|
+
import { Controller, Get, Inject, Optional, Query } from "@nestjs/common";
|
|
120
|
+
import { buildFeatureRequiresIndex, collectUnsatisfiedRequires } from "@saasicat/types";
|
|
121
|
+
function _ts_decorate(decorators, target, key, desc) {
|
|
798
122
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
799
123
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
800
124
|
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;
|
|
801
125
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
802
126
|
}
|
|
803
|
-
__name(
|
|
804
|
-
function
|
|
127
|
+
__name(_ts_decorate, "_ts_decorate");
|
|
128
|
+
function _ts_metadata(k, v) {
|
|
805
129
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
806
130
|
}
|
|
807
|
-
__name(
|
|
808
|
-
function
|
|
131
|
+
__name(_ts_metadata, "_ts_metadata");
|
|
132
|
+
function _ts_param(paramIndex, decorator) {
|
|
809
133
|
return function(target, key) {
|
|
810
134
|
decorator(target, key, paramIndex);
|
|
811
135
|
};
|
|
812
136
|
}
|
|
813
|
-
__name(
|
|
137
|
+
__name(_ts_param, "_ts_param");
|
|
814
138
|
var PublicCatalogController = class {
|
|
815
139
|
static {
|
|
816
140
|
__name(this, "PublicCatalogController");
|
|
@@ -913,7 +237,7 @@ var PublicCatalogController = class {
|
|
|
913
237
|
const rows = await this.catalogEntryRepo.listFeatures({
|
|
914
238
|
projectKey: this.projectKey
|
|
915
239
|
});
|
|
916
|
-
return
|
|
240
|
+
return buildFeatureRequiresIndex(rows);
|
|
917
241
|
} catch {
|
|
918
242
|
return /* @__PURE__ */ new Map();
|
|
919
243
|
}
|
|
@@ -953,54 +277,54 @@ var PublicCatalogController = class {
|
|
|
953
277
|
quotas: live.quotas,
|
|
954
278
|
monthlyNet: live.monthlyNet,
|
|
955
279
|
yearlyNet: live.yearlyNet,
|
|
956
|
-
requiresFeatures:
|
|
280
|
+
requiresFeatures: collectUnsatisfiedRequires(features, requiresIndex),
|
|
957
281
|
marketing
|
|
958
282
|
};
|
|
959
283
|
}
|
|
960
284
|
};
|
|
961
|
-
|
|
285
|
+
_ts_decorate([
|
|
962
286
|
Get("plans"),
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
287
|
+
_ts_param(0, Query("lang")),
|
|
288
|
+
_ts_param(1, Query("locale")),
|
|
289
|
+
_ts_metadata("design:type", Function),
|
|
290
|
+
_ts_metadata("design:paramtypes", [
|
|
967
291
|
String,
|
|
968
292
|
void 0
|
|
969
293
|
]),
|
|
970
|
-
|
|
294
|
+
_ts_metadata("design:returntype", Promise)
|
|
971
295
|
], PublicCatalogController.prototype, "listPlans", null);
|
|
972
|
-
|
|
296
|
+
_ts_decorate([
|
|
973
297
|
Get("feature-registry"),
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
298
|
+
_ts_metadata("design:type", Function),
|
|
299
|
+
_ts_metadata("design:paramtypes", []),
|
|
300
|
+
_ts_metadata("design:returntype", Promise)
|
|
977
301
|
], PublicCatalogController.prototype, "listFeatureRegistry", null);
|
|
978
|
-
|
|
302
|
+
_ts_decorate([
|
|
979
303
|
Get("bundles"),
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
304
|
+
_ts_param(0, Query("lang")),
|
|
305
|
+
_ts_param(1, Query("locale")),
|
|
306
|
+
_ts_metadata("design:type", Function),
|
|
307
|
+
_ts_metadata("design:paramtypes", [
|
|
984
308
|
String,
|
|
985
309
|
void 0
|
|
986
310
|
]),
|
|
987
|
-
|
|
311
|
+
_ts_metadata("design:returntype", Promise)
|
|
988
312
|
], PublicCatalogController.prototype, "listBundles", null);
|
|
989
|
-
PublicCatalogController =
|
|
990
|
-
|
|
313
|
+
PublicCatalogController = _ts_decorate([
|
|
314
|
+
Controller("billing"),
|
|
991
315
|
SaaSiCatPublicRoute(),
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
316
|
+
_ts_param(0, Inject(PLAN_CATALOG_TOKEN)),
|
|
317
|
+
_ts_param(1, Inject(FEATURE_UI_REGISTRY_TOKEN)),
|
|
318
|
+
_ts_param(2, Optional()),
|
|
319
|
+
_ts_param(2, Inject(PUBLIC_CATALOG_PROJECT_KEY_TOKEN)),
|
|
320
|
+
_ts_param(3, Optional()),
|
|
321
|
+
_ts_param(3, Inject(PUBLIC_CATALOG_MARKETING_REPOSITORY_TOKEN)),
|
|
322
|
+
_ts_param(4, Optional()),
|
|
323
|
+
_ts_param(4, Inject(PUBLIC_CATALOG_BUNDLE_REPOSITORY_TOKEN)),
|
|
324
|
+
_ts_param(5, Optional()),
|
|
325
|
+
_ts_param(5, Inject(PUBLIC_CATALOG_CATALOG_ENTRY_REPOSITORY_TOKEN)),
|
|
326
|
+
_ts_metadata("design:type", Function),
|
|
327
|
+
_ts_metadata("design:paramtypes", [
|
|
1004
328
|
typeof PlanCatalog === "undefined" ? Object : PlanCatalog,
|
|
1005
329
|
typeof FeatureUiRegistry === "undefined" ? Object : FeatureUiRegistry,
|
|
1006
330
|
Object,
|
|
@@ -1011,14 +335,14 @@ PublicCatalogController = _ts_decorate7([
|
|
|
1011
335
|
], PublicCatalogController);
|
|
1012
336
|
|
|
1013
337
|
// src/billing/public-catalog.module.ts
|
|
1014
|
-
import { Module
|
|
1015
|
-
function
|
|
338
|
+
import { Module } from "@nestjs/common";
|
|
339
|
+
function _ts_decorate2(decorators, target, key, desc) {
|
|
1016
340
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
1017
341
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
1018
342
|
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;
|
|
1019
343
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
1020
344
|
}
|
|
1021
|
-
__name(
|
|
345
|
+
__name(_ts_decorate2, "_ts_decorate");
|
|
1022
346
|
var PublicCatalogModule = class _PublicCatalogModule {
|
|
1023
347
|
static {
|
|
1024
348
|
__name(this, "PublicCatalogModule");
|
|
@@ -1059,30 +383,30 @@ var PublicCatalogModule = class _PublicCatalogModule {
|
|
|
1059
383
|
};
|
|
1060
384
|
}
|
|
1061
385
|
};
|
|
1062
|
-
PublicCatalogModule =
|
|
1063
|
-
|
|
386
|
+
PublicCatalogModule = _ts_decorate2([
|
|
387
|
+
Module({})
|
|
1064
388
|
], PublicCatalogModule);
|
|
1065
389
|
|
|
1066
390
|
// src/billing/composed-tenant-auth.guard.ts
|
|
1067
|
-
import { ForbiddenException
|
|
1068
|
-
import { AUTH_ERROR_CODES
|
|
1069
|
-
function
|
|
391
|
+
import { ForbiddenException, Inject as Inject2, Injectable, Optional as Optional2 } from "@nestjs/common";
|
|
392
|
+
import { AUTH_ERROR_CODES } from "@saasicat/types";
|
|
393
|
+
function _ts_decorate3(decorators, target, key, desc) {
|
|
1070
394
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
1071
395
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
1072
396
|
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;
|
|
1073
397
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
1074
398
|
}
|
|
1075
|
-
__name(
|
|
1076
|
-
function
|
|
399
|
+
__name(_ts_decorate3, "_ts_decorate");
|
|
400
|
+
function _ts_metadata2(k, v) {
|
|
1077
401
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
1078
402
|
}
|
|
1079
|
-
__name(
|
|
1080
|
-
function
|
|
403
|
+
__name(_ts_metadata2, "_ts_metadata");
|
|
404
|
+
function _ts_param2(paramIndex, decorator) {
|
|
1081
405
|
return function(target, key) {
|
|
1082
406
|
decorator(target, key, paramIndex);
|
|
1083
407
|
};
|
|
1084
408
|
}
|
|
1085
|
-
__name(
|
|
409
|
+
__name(_ts_param2, "_ts_param");
|
|
1086
410
|
var ComposedTenantAuthGuard = class {
|
|
1087
411
|
static {
|
|
1088
412
|
__name(this, "ComposedTenantAuthGuard");
|
|
@@ -1093,8 +417,8 @@ var ComposedTenantAuthGuard = class {
|
|
|
1093
417
|
}
|
|
1094
418
|
async canActivate(context) {
|
|
1095
419
|
if (!this.guards || this.guards.length === 0) {
|
|
1096
|
-
throw new
|
|
1097
|
-
code:
|
|
420
|
+
throw new ForbiddenException({
|
|
421
|
+
code: AUTH_ERROR_CODES.AUTH_GUARDS_NOT_CONFIGURED,
|
|
1098
422
|
message: "TenantBillingModule.forRoot.authGuards is not configured."
|
|
1099
423
|
});
|
|
1100
424
|
}
|
|
@@ -1105,26 +429,26 @@ var ComposedTenantAuthGuard = class {
|
|
|
1105
429
|
return true;
|
|
1106
430
|
}
|
|
1107
431
|
};
|
|
1108
|
-
ComposedTenantAuthGuard =
|
|
1109
|
-
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
432
|
+
ComposedTenantAuthGuard = _ts_decorate3([
|
|
433
|
+
Injectable(),
|
|
434
|
+
_ts_param2(0, Optional2()),
|
|
435
|
+
_ts_param2(0, Inject2(TENANT_AUTH_GUARDS_TOKEN)),
|
|
436
|
+
_ts_metadata2("design:type", Function),
|
|
437
|
+
_ts_metadata2("design:paramtypes", [
|
|
1114
438
|
Object
|
|
1115
439
|
])
|
|
1116
440
|
], ComposedTenantAuthGuard);
|
|
1117
441
|
|
|
1118
442
|
// src/billing/tenant-admin.guard.ts
|
|
1119
|
-
import { ForbiddenException as
|
|
1120
|
-
import { AUTH_ERROR_CODES as
|
|
1121
|
-
function
|
|
443
|
+
import { ForbiddenException as ForbiddenException2, Injectable as Injectable2 } from "@nestjs/common";
|
|
444
|
+
import { AUTH_ERROR_CODES as AUTH_ERROR_CODES2 } from "@saasicat/types";
|
|
445
|
+
function _ts_decorate4(decorators, target, key, desc) {
|
|
1122
446
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
1123
447
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
1124
448
|
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;
|
|
1125
449
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
1126
450
|
}
|
|
1127
|
-
__name(
|
|
451
|
+
__name(_ts_decorate4, "_ts_decorate");
|
|
1128
452
|
var ADMIN_ROLES = /* @__PURE__ */ new Set([
|
|
1129
453
|
"TENANT_ADMIN",
|
|
1130
454
|
"SUPER_ADMIN"
|
|
@@ -1136,23 +460,23 @@ var TenantAdminGuard = class {
|
|
|
1136
460
|
canActivate(context) {
|
|
1137
461
|
const request = context.switchToHttp().getRequest();
|
|
1138
462
|
if (!request.user) {
|
|
1139
|
-
throw new
|
|
1140
|
-
code:
|
|
463
|
+
throw new ForbiddenException2({
|
|
464
|
+
code: AUTH_ERROR_CODES2.NOT_AUTHENTICATED,
|
|
1141
465
|
message: "Not authenticated"
|
|
1142
466
|
});
|
|
1143
467
|
}
|
|
1144
468
|
const role = request.user.platformRole ?? request.user.role;
|
|
1145
469
|
if (!role || !ADMIN_ROLES.has(role)) {
|
|
1146
|
-
throw new
|
|
1147
|
-
code:
|
|
470
|
+
throw new ForbiddenException2({
|
|
471
|
+
code: AUTH_ERROR_CODES2.TENANT_ADMIN_REQUIRED,
|
|
1148
472
|
message: "This action requires the TENANT_ADMIN role."
|
|
1149
473
|
});
|
|
1150
474
|
}
|
|
1151
475
|
return true;
|
|
1152
476
|
}
|
|
1153
477
|
};
|
|
1154
|
-
TenantAdminGuard =
|
|
1155
|
-
|
|
478
|
+
TenantAdminGuard = _ts_decorate4([
|
|
479
|
+
Injectable2()
|
|
1156
480
|
], TenantAdminGuard);
|
|
1157
481
|
|
|
1158
482
|
// src/billing/self-service-policy.ts
|
|
@@ -1183,25 +507,25 @@ function round2(n) {
|
|
|
1183
507
|
__name(round2, "round2");
|
|
1184
508
|
|
|
1185
509
|
// src/billing/plan-change-preview.service.ts
|
|
1186
|
-
import { Inject as
|
|
1187
|
-
import { BILLING_ERROR_CODES
|
|
1188
|
-
function
|
|
510
|
+
import { Inject as Inject3, Injectable as Injectable3, NotFoundException, Optional as Optional3 } from "@nestjs/common";
|
|
511
|
+
import { BILLING_ERROR_CODES } from "@saasicat/types";
|
|
512
|
+
function _ts_decorate5(decorators, target, key, desc) {
|
|
1189
513
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
1190
514
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
1191
515
|
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;
|
|
1192
516
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
1193
517
|
}
|
|
1194
|
-
__name(
|
|
1195
|
-
function
|
|
518
|
+
__name(_ts_decorate5, "_ts_decorate");
|
|
519
|
+
function _ts_metadata3(k, v) {
|
|
1196
520
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
1197
521
|
}
|
|
1198
|
-
__name(
|
|
1199
|
-
function
|
|
522
|
+
__name(_ts_metadata3, "_ts_metadata");
|
|
523
|
+
function _ts_param3(paramIndex, decorator) {
|
|
1200
524
|
return function(target, key) {
|
|
1201
525
|
decorator(target, key, paramIndex);
|
|
1202
526
|
};
|
|
1203
527
|
}
|
|
1204
|
-
__name(
|
|
528
|
+
__name(_ts_param3, "_ts_param");
|
|
1205
529
|
var PlanChangePreviewService = class {
|
|
1206
530
|
static {
|
|
1207
531
|
__name(this, "PlanChangePreviewService");
|
|
@@ -1224,7 +548,7 @@ var PlanChangePreviewService = class {
|
|
|
1224
548
|
const sub = await this.subscriptions.findForTenant(tenantId);
|
|
1225
549
|
if (!sub) {
|
|
1226
550
|
throw new NotFoundException({
|
|
1227
|
-
code:
|
|
551
|
+
code: BILLING_ERROR_CODES.SUBSCRIPTION_NOT_FOUND,
|
|
1228
552
|
message: `No subscription for tenant ${tenantId}`,
|
|
1229
553
|
params: {
|
|
1230
554
|
tenantId
|
|
@@ -1234,7 +558,7 @@ var PlanChangePreviewService = class {
|
|
|
1234
558
|
const targetPlanDef = findPlan(this.catalog, targetPlan);
|
|
1235
559
|
if (!targetPlanDef) {
|
|
1236
560
|
throw new NotFoundException({
|
|
1237
|
-
code:
|
|
561
|
+
code: BILLING_ERROR_CODES.PLAN_NOT_IN_CATALOG,
|
|
1238
562
|
message: `Plan "${targetPlan}" is not in the catalog (${this.catalog.projectKey})`,
|
|
1239
563
|
params: {
|
|
1240
564
|
planKey: targetPlan,
|
|
@@ -1401,18 +725,18 @@ var PlanChangePreviewService = class {
|
|
|
1401
725
|
});
|
|
1402
726
|
}
|
|
1403
727
|
};
|
|
1404
|
-
PlanChangePreviewService =
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
728
|
+
PlanChangePreviewService = _ts_decorate5([
|
|
729
|
+
Injectable3(),
|
|
730
|
+
_ts_param3(0, Inject3(PLAN_CATALOG_TOKEN)),
|
|
731
|
+
_ts_param3(1, Inject3(ENTITLEMENT_SERVICE_TOKEN)),
|
|
732
|
+
_ts_param3(2, Inject3(SUBSCRIPTION_USAGE_PORT_TOKEN)),
|
|
733
|
+
_ts_param3(3, Inject3(USAGE_SNAPSHOT_PORT_TOKEN)),
|
|
734
|
+
_ts_param3(4, Optional3()),
|
|
735
|
+
_ts_param3(4, Inject3(SELF_SERVICE_BLOCKED_PLANS_TOKEN)),
|
|
736
|
+
_ts_param3(5, Optional3()),
|
|
737
|
+
_ts_param3(5, Inject3(TRIAL_PROJECTION_PORT_TOKEN)),
|
|
738
|
+
_ts_metadata3("design:type", Function),
|
|
739
|
+
_ts_metadata3("design:paramtypes", [
|
|
1416
740
|
typeof PlanCatalog === "undefined" ? Object : PlanCatalog,
|
|
1417
741
|
typeof EntitlementService === "undefined" ? Object : EntitlementService,
|
|
1418
742
|
typeof SubscriptionUsagePort === "undefined" ? Object : SubscriptionUsagePort,
|
|
@@ -1430,32 +754,30 @@ function isFloatQuota(key) {
|
|
|
1430
754
|
}
|
|
1431
755
|
__name(isFloatQuota, "isFloatQuota");
|
|
1432
756
|
|
|
1433
|
-
// src/billing/pending-plan-materialization.service.ts
|
|
1434
|
-
import { Inject as Inject8, Injectable as Injectable7, Logger as Logger3, Optional as Optional6 } from "@nestjs/common";
|
|
1435
|
-
|
|
1436
757
|
// src/billing/contract-freeze.tokens.ts
|
|
1437
758
|
var CONTRACT_FREEZE_PORT_TOKEN = /* @__PURE__ */ Symbol.for("saas-platform/ContractFreezePort");
|
|
1438
759
|
var CONTRACT_FREEZE_SOURCE_PORT_TOKEN = /* @__PURE__ */ Symbol.for("saas-platform/ContractFreezeSourcePort");
|
|
1439
760
|
var CONTRACT_FREEZE_PROJECT_KEY_TOKEN = /* @__PURE__ */ Symbol.for("saas-platform/ContractFreezeProjectKey");
|
|
1440
761
|
|
|
1441
762
|
// src/billing/pending-plan-materialization.service.ts
|
|
1442
|
-
|
|
763
|
+
import { Inject as Inject4, Injectable as Injectable4, Logger, Optional as Optional4 } from "@nestjs/common";
|
|
764
|
+
function _ts_decorate6(decorators, target, key, desc) {
|
|
1443
765
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
1444
766
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
1445
767
|
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;
|
|
1446
768
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
1447
769
|
}
|
|
1448
|
-
__name(
|
|
1449
|
-
function
|
|
770
|
+
__name(_ts_decorate6, "_ts_decorate");
|
|
771
|
+
function _ts_metadata4(k, v) {
|
|
1450
772
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
1451
773
|
}
|
|
1452
|
-
__name(
|
|
1453
|
-
function
|
|
774
|
+
__name(_ts_metadata4, "_ts_metadata");
|
|
775
|
+
function _ts_param4(paramIndex, decorator) {
|
|
1454
776
|
return function(target, key) {
|
|
1455
777
|
decorator(target, key, paramIndex);
|
|
1456
778
|
};
|
|
1457
779
|
}
|
|
1458
|
-
__name(
|
|
780
|
+
__name(_ts_param4, "_ts_param");
|
|
1459
781
|
var PendingPlanMaterializationService = class _PendingPlanMaterializationService {
|
|
1460
782
|
static {
|
|
1461
783
|
__name(this, "PendingPlanMaterializationService");
|
|
@@ -1464,7 +786,7 @@ var PendingPlanMaterializationService = class _PendingPlanMaterializationService
|
|
|
1464
786
|
subscriptionWrite;
|
|
1465
787
|
entitlements;
|
|
1466
788
|
contractFreeze;
|
|
1467
|
-
logger = new
|
|
789
|
+
logger = new Logger(_PendingPlanMaterializationService.name);
|
|
1468
790
|
constructor(query, subscriptionWrite, entitlements, contractFreeze = null) {
|
|
1469
791
|
this.query = query;
|
|
1470
792
|
this.subscriptionWrite = subscriptionWrite;
|
|
@@ -1510,14 +832,14 @@ var PendingPlanMaterializationService = class _PendingPlanMaterializationService
|
|
|
1510
832
|
}
|
|
1511
833
|
}
|
|
1512
834
|
};
|
|
1513
|
-
PendingPlanMaterializationService =
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
835
|
+
PendingPlanMaterializationService = _ts_decorate6([
|
|
836
|
+
Injectable4(),
|
|
837
|
+
_ts_param4(0, Inject4(PENDING_PLAN_QUERY_PORT_TOKEN)),
|
|
838
|
+
_ts_param4(1, Inject4(SUBSCRIPTION_WRITE_PORT_TOKEN)),
|
|
839
|
+
_ts_param4(3, Optional4()),
|
|
840
|
+
_ts_param4(3, Inject4(CONTRACT_FREEZE_PORT_TOKEN)),
|
|
841
|
+
_ts_metadata4("design:type", Function),
|
|
842
|
+
_ts_metadata4("design:paramtypes", [
|
|
1521
843
|
typeof PendingPlanQueryPort === "undefined" ? Object : PendingPlanQueryPort,
|
|
1522
844
|
typeof TenantSubscriptionWritePort === "undefined" ? Object : TenantSubscriptionWritePort,
|
|
1523
845
|
typeof EntitlementService === "undefined" ? Object : EntitlementService,
|
|
@@ -1526,24 +848,24 @@ PendingPlanMaterializationService = _ts_decorate12([
|
|
|
1526
848
|
], PendingPlanMaterializationService);
|
|
1527
849
|
|
|
1528
850
|
// src/billing/subscription-contract-freeze.service.ts
|
|
1529
|
-
import { Inject as
|
|
1530
|
-
function
|
|
851
|
+
import { Inject as Inject5, Injectable as Injectable5 } from "@nestjs/common";
|
|
852
|
+
function _ts_decorate7(decorators, target, key, desc) {
|
|
1531
853
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
1532
854
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
1533
855
|
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;
|
|
1534
856
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
1535
857
|
}
|
|
1536
|
-
__name(
|
|
1537
|
-
function
|
|
858
|
+
__name(_ts_decorate7, "_ts_decorate");
|
|
859
|
+
function _ts_metadata5(k, v) {
|
|
1538
860
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
1539
861
|
}
|
|
1540
|
-
__name(
|
|
1541
|
-
function
|
|
862
|
+
__name(_ts_metadata5, "_ts_metadata");
|
|
863
|
+
function _ts_param5(paramIndex, decorator) {
|
|
1542
864
|
return function(target, key) {
|
|
1543
865
|
decorator(target, key, paramIndex);
|
|
1544
866
|
};
|
|
1545
867
|
}
|
|
1546
|
-
__name(
|
|
868
|
+
__name(_ts_param5, "_ts_param");
|
|
1547
869
|
var SubscriptionContractFreezeService = class {
|
|
1548
870
|
static {
|
|
1549
871
|
__name(this, "SubscriptionContractFreezeService");
|
|
@@ -1629,15 +951,15 @@ var SubscriptionContractFreezeService = class {
|
|
|
1629
951
|
this.entitlements.invalidateTenant(tenantId);
|
|
1630
952
|
}
|
|
1631
953
|
};
|
|
1632
|
-
SubscriptionContractFreezeService =
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
954
|
+
SubscriptionContractFreezeService = _ts_decorate7([
|
|
955
|
+
Injectable5(),
|
|
956
|
+
_ts_param5(0, Inject5(PLAN_CATALOG_TOKEN)),
|
|
957
|
+
_ts_param5(1, Inject5(ENTITLEMENT_SERVICE_TOKEN)),
|
|
958
|
+
_ts_param5(2, Inject5(SubscriptionContractService)),
|
|
959
|
+
_ts_param5(3, Inject5(CONTRACT_FREEZE_PROJECT_KEY_TOKEN)),
|
|
960
|
+
_ts_param5(4, Inject5(CONTRACT_FREEZE_SOURCE_PORT_TOKEN)),
|
|
961
|
+
_ts_metadata5("design:type", Function),
|
|
962
|
+
_ts_metadata5("design:paramtypes", [
|
|
1641
963
|
typeof PlanCatalog === "undefined" ? Object : PlanCatalog,
|
|
1642
964
|
typeof EntitlementService === "undefined" ? Object : EntitlementService,
|
|
1643
965
|
typeof SubscriptionContractService === "undefined" ? Object : SubscriptionContractService,
|
|
@@ -1650,29 +972,19 @@ function round22(value) {
|
|
|
1650
972
|
}
|
|
1651
973
|
__name(round22, "round2");
|
|
1652
974
|
|
|
1653
|
-
// src/billing/trial-carryover.ts
|
|
1654
|
-
var MS_PER_DAY = 864e5;
|
|
1655
|
-
function computeCarriedTrialEndsAt(currentTrialDays, newTrialDays, currentTrialEndsAt, now) {
|
|
1656
|
-
const daysRemaining = Math.max(0, Math.ceil((currentTrialEndsAt.getTime() - now.getTime()) / MS_PER_DAY));
|
|
1657
|
-
const usedDays = Math.max(0, currentTrialDays - daysRemaining);
|
|
1658
|
-
const newDays = Math.max(0, newTrialDays - usedDays);
|
|
1659
|
-
return new Date(now.getTime() + newDays * MS_PER_DAY);
|
|
1660
|
-
}
|
|
1661
|
-
__name(computeCarriedTrialEndsAt, "computeCarriedTrialEndsAt");
|
|
1662
|
-
|
|
1663
975
|
// src/billing/dto/tenant-billing.dto.ts
|
|
1664
|
-
import { IsBoolean
|
|
1665
|
-
function
|
|
976
|
+
import { IsBoolean, IsOptional, IsString, Matches } from "class-validator";
|
|
977
|
+
function _ts_decorate8(decorators, target, key, desc) {
|
|
1666
978
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
1667
979
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
1668
980
|
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;
|
|
1669
981
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
1670
982
|
}
|
|
1671
|
-
__name(
|
|
1672
|
-
function
|
|
983
|
+
__name(_ts_decorate8, "_ts_decorate");
|
|
984
|
+
function _ts_metadata6(k, v) {
|
|
1673
985
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
1674
986
|
}
|
|
1675
|
-
__name(
|
|
987
|
+
__name(_ts_metadata6, "_ts_metadata");
|
|
1676
988
|
var PLAN_OR_CYCLE_PATTERN = /^[A-Z][A-Z0-9_]*$/;
|
|
1677
989
|
var PreviewPlanChangeDto = class {
|
|
1678
990
|
static {
|
|
@@ -1681,19 +993,19 @@ var PreviewPlanChangeDto = class {
|
|
|
1681
993
|
plan;
|
|
1682
994
|
billingCycle;
|
|
1683
995
|
};
|
|
1684
|
-
|
|
1685
|
-
|
|
996
|
+
_ts_decorate8([
|
|
997
|
+
IsString(),
|
|
1686
998
|
Matches(PLAN_OR_CYCLE_PATTERN, {
|
|
1687
999
|
message: "plan must be SCREAMING_SNAKE_CASE"
|
|
1688
1000
|
}),
|
|
1689
|
-
|
|
1001
|
+
_ts_metadata6("design:type", String)
|
|
1690
1002
|
], PreviewPlanChangeDto.prototype, "plan", void 0);
|
|
1691
|
-
|
|
1692
|
-
|
|
1003
|
+
_ts_decorate8([
|
|
1004
|
+
IsString(),
|
|
1693
1005
|
Matches(PLAN_OR_CYCLE_PATTERN, {
|
|
1694
1006
|
message: "billingCycle must be SCREAMING_SNAKE_CASE (e.g. MONTHLY, YEARLY)"
|
|
1695
1007
|
}),
|
|
1696
|
-
|
|
1008
|
+
_ts_metadata6("design:type", String)
|
|
1697
1009
|
], PreviewPlanChangeDto.prototype, "billingCycle", void 0);
|
|
1698
1010
|
var ChangePlanDto = class extends PreviewPlanChangeDto {
|
|
1699
1011
|
static {
|
|
@@ -1702,10 +1014,10 @@ var ChangePlanDto = class extends PreviewPlanChangeDto {
|
|
|
1702
1014
|
/** Immediate change (true) vs. change at period end (false/undefined). */
|
|
1703
1015
|
effectiveImmediately;
|
|
1704
1016
|
};
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1017
|
+
_ts_decorate8([
|
|
1018
|
+
IsOptional(),
|
|
1019
|
+
IsBoolean(),
|
|
1020
|
+
_ts_metadata6("design:type", Boolean)
|
|
1709
1021
|
], ChangePlanDto.prototype, "effectiveImmediately", void 0);
|
|
1710
1022
|
var CancelSubscriptionDto = class {
|
|
1711
1023
|
static {
|
|
@@ -1714,25 +1026,25 @@ var CancelSubscriptionDto = class {
|
|
|
1714
1026
|
/** true = cancel immediately (status CANCELED). false/undefined = at period end. */
|
|
1715
1027
|
immediately;
|
|
1716
1028
|
};
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1029
|
+
_ts_decorate8([
|
|
1030
|
+
IsOptional(),
|
|
1031
|
+
IsBoolean(),
|
|
1032
|
+
_ts_metadata6("design:type", Boolean)
|
|
1721
1033
|
], CancelSubscriptionDto.prototype, "immediately", void 0);
|
|
1722
1034
|
|
|
1723
1035
|
// src/billing/dto/onboarding-subscription.dto.ts
|
|
1724
|
-
import { ArrayMaxSize, IsArray, IsOptional as
|
|
1725
|
-
function
|
|
1036
|
+
import { ArrayMaxSize, IsArray, IsOptional as IsOptional2, IsString as IsString2, IsUUID, Matches as Matches2 } from "class-validator";
|
|
1037
|
+
function _ts_decorate9(decorators, target, key, desc) {
|
|
1726
1038
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
1727
1039
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
1728
1040
|
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;
|
|
1729
1041
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
1730
1042
|
}
|
|
1731
|
-
__name(
|
|
1732
|
-
function
|
|
1043
|
+
__name(_ts_decorate9, "_ts_decorate");
|
|
1044
|
+
function _ts_metadata7(k, v) {
|
|
1733
1045
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
1734
1046
|
}
|
|
1735
|
-
__name(
|
|
1047
|
+
__name(_ts_metadata7, "_ts_metadata");
|
|
1736
1048
|
var PLAN_OR_CYCLE_PATTERN2 = /^[A-Z][A-Z0-9_]*$/;
|
|
1737
1049
|
var PROMO_CODE_PATTERN = /^[A-Z0-9_-]{4,32}$/i;
|
|
1738
1050
|
var CompleteOnboardingSubscriptionDto = class {
|
|
@@ -1752,62 +1064,58 @@ var CompleteOnboardingSubscriptionDto = class {
|
|
|
1752
1064
|
*/
|
|
1753
1065
|
bundleVersionIds;
|
|
1754
1066
|
};
|
|
1755
|
-
|
|
1756
|
-
|
|
1067
|
+
_ts_decorate9([
|
|
1068
|
+
IsString2(),
|
|
1757
1069
|
Matches2(PLAN_OR_CYCLE_PATTERN2, {
|
|
1758
1070
|
message: "plan must be SCREAMING_SNAKE_CASE"
|
|
1759
1071
|
}),
|
|
1760
|
-
|
|
1072
|
+
_ts_metadata7("design:type", String)
|
|
1761
1073
|
], CompleteOnboardingSubscriptionDto.prototype, "plan", void 0);
|
|
1762
|
-
|
|
1763
|
-
|
|
1074
|
+
_ts_decorate9([
|
|
1075
|
+
IsString2(),
|
|
1764
1076
|
Matches2(PLAN_OR_CYCLE_PATTERN2, {
|
|
1765
1077
|
message: "billingCycle must be SCREAMING_SNAKE_CASE (e.g. MONTHLY, YEARLY)"
|
|
1766
1078
|
}),
|
|
1767
|
-
|
|
1079
|
+
_ts_metadata7("design:type", String)
|
|
1768
1080
|
], CompleteOnboardingSubscriptionDto.prototype, "billingCycle", void 0);
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1081
|
+
_ts_decorate9([
|
|
1082
|
+
IsOptional2(),
|
|
1083
|
+
IsString2(),
|
|
1772
1084
|
Matches2(PROMO_CODE_PATTERN, {
|
|
1773
1085
|
message: 'promoCode must consist of A\u2013Z, 0\u20139, "-", "_" (4\u201332 characters)'
|
|
1774
1086
|
}),
|
|
1775
|
-
|
|
1087
|
+
_ts_metadata7("design:type", String)
|
|
1776
1088
|
], CompleteOnboardingSubscriptionDto.prototype, "promoCode", void 0);
|
|
1777
|
-
|
|
1778
|
-
|
|
1089
|
+
_ts_decorate9([
|
|
1090
|
+
IsOptional2(),
|
|
1779
1091
|
IsArray(),
|
|
1780
1092
|
ArrayMaxSize(10),
|
|
1781
1093
|
IsUUID("all", {
|
|
1782
1094
|
each: true
|
|
1783
1095
|
}),
|
|
1784
|
-
|
|
1096
|
+
_ts_metadata7("design:type", Array)
|
|
1785
1097
|
], CompleteOnboardingSubscriptionDto.prototype, "bundleVersionIds", void 0);
|
|
1786
1098
|
|
|
1787
|
-
// src/billing/tenant-billing.controller.ts
|
|
1788
|
-
import { BadRequestException, Body as Body2, Controller as Controller3, ForbiddenException as ForbiddenException4, Get as Get2, HttpCode, HttpStatus as HttpStatus2, Inject as Inject11, Logger as Logger4, NotFoundException as NotFoundException3, Optional as Optional8, Post as Post2, Req, UseGuards as UseGuards2 } from "@nestjs/common";
|
|
1789
|
-
import { AUTH_ERROR_CODES as AUTH_ERROR_CODES4, BILLING_ERROR_CODES as BILLING_ERROR_CODES4 } from "@saasicat/types";
|
|
1790
|
-
|
|
1791
1099
|
// src/billing/subscription-bundles.service.ts
|
|
1792
|
-
import { Inject as
|
|
1793
|
-
import { BILLING_ERROR_CODES as
|
|
1794
|
-
function
|
|
1100
|
+
import { Inject as Inject6, Injectable as Injectable6, NotFoundException as NotFoundException2, Optional as Optional5, UnprocessableEntityException } from "@nestjs/common";
|
|
1101
|
+
import { BILLING_ERROR_CODES as BILLING_ERROR_CODES2, CATALOG_ERROR_CODES } from "@saasicat/types";
|
|
1102
|
+
function _ts_decorate10(decorators, target, key, desc) {
|
|
1795
1103
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
1796
1104
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
1797
1105
|
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;
|
|
1798
1106
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
1799
1107
|
}
|
|
1800
|
-
__name(
|
|
1801
|
-
function
|
|
1108
|
+
__name(_ts_decorate10, "_ts_decorate");
|
|
1109
|
+
function _ts_metadata8(k, v) {
|
|
1802
1110
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
1803
1111
|
}
|
|
1804
|
-
__name(
|
|
1805
|
-
function
|
|
1112
|
+
__name(_ts_metadata8, "_ts_metadata");
|
|
1113
|
+
function _ts_param6(paramIndex, decorator) {
|
|
1806
1114
|
return function(target, key) {
|
|
1807
1115
|
decorator(target, key, paramIndex);
|
|
1808
1116
|
};
|
|
1809
1117
|
}
|
|
1810
|
-
__name(
|
|
1118
|
+
__name(_ts_param6, "_ts_param");
|
|
1811
1119
|
var SubscriptionBundlesService = class {
|
|
1812
1120
|
static {
|
|
1813
1121
|
__name(this, "SubscriptionBundlesService");
|
|
@@ -1866,7 +1174,7 @@ var SubscriptionBundlesService = class {
|
|
|
1866
1174
|
}
|
|
1867
1175
|
if (this.blockedBundles?.bundleKeys?.includes(bundleVersion.bundleKey)) {
|
|
1868
1176
|
throw new UnprocessableEntityException({
|
|
1869
|
-
code:
|
|
1177
|
+
code: BILLING_ERROR_CODES2.BUNDLE_NOT_SELF_SERVICE,
|
|
1870
1178
|
message: `Bundle '${bundleVersion.bundleKey}' is only activated via a special contract. Please contact the contract manager.`,
|
|
1871
1179
|
params: {
|
|
1872
1180
|
bundleKey: bundleVersion.bundleKey
|
|
@@ -1876,7 +1184,7 @@ var SubscriptionBundlesService = class {
|
|
|
1876
1184
|
const planIds = bundleVersion.compatibility?.planIds ?? [];
|
|
1877
1185
|
if (planIds.length > 0 && !planIds.includes(input.currentPlanKey)) {
|
|
1878
1186
|
throw new UnprocessableEntityException({
|
|
1879
|
-
code:
|
|
1187
|
+
code: BILLING_ERROR_CODES2.BUNDLE_INCOMPATIBLE_WITH_PLAN,
|
|
1880
1188
|
message: `BundleVersion '${input.bundleVersionId}' is not compatible with plan '${input.currentPlanKey}'. Allowed: [${planIds.join(", ")}].`,
|
|
1881
1189
|
params: {
|
|
1882
1190
|
bundleVersionId: input.bundleVersionId,
|
|
@@ -1888,7 +1196,7 @@ var SubscriptionBundlesService = class {
|
|
|
1888
1196
|
const active = await this.repo.listActiveBySubscription(input.subscriptionId);
|
|
1889
1197
|
if (active.some((b) => b.bundleVersionId === input.bundleVersionId)) {
|
|
1890
1198
|
throw new UnprocessableEntityException({
|
|
1891
|
-
code:
|
|
1199
|
+
code: BILLING_ERROR_CODES2.BUNDLE_ALREADY_SUBSCRIBED,
|
|
1892
1200
|
message: `Subscription '${input.subscriptionId}' has already actively booked this bundle.`,
|
|
1893
1201
|
params: {
|
|
1894
1202
|
subscriptionId: input.subscriptionId
|
|
@@ -1909,7 +1217,7 @@ var SubscriptionBundlesService = class {
|
|
|
1909
1217
|
const existing = await this.repo.findById(input.subscriptionBundleId);
|
|
1910
1218
|
if (!existing) {
|
|
1911
1219
|
throw new NotFoundException2({
|
|
1912
|
-
code:
|
|
1220
|
+
code: BILLING_ERROR_CODES2.SUBSCRIPTION_BUNDLE_NOT_FOUND,
|
|
1913
1221
|
message: `SubscriptionBundle '${input.subscriptionBundleId}' not found`,
|
|
1914
1222
|
params: {
|
|
1915
1223
|
subscriptionBundleId: input.subscriptionBundleId
|
|
@@ -1918,7 +1226,7 @@ var SubscriptionBundlesService = class {
|
|
|
1918
1226
|
}
|
|
1919
1227
|
if (existing.canceledAt !== null) {
|
|
1920
1228
|
throw new UnprocessableEntityException({
|
|
1921
|
-
code:
|
|
1229
|
+
code: BILLING_ERROR_CODES2.SUBSCRIPTION_BUNDLE_ALREADY_CANCELLED,
|
|
1922
1230
|
message: `SubscriptionBundle '${input.subscriptionBundleId}' is already cancelled.`,
|
|
1923
1231
|
params: {
|
|
1924
1232
|
subscriptionBundleId: input.subscriptionBundleId
|
|
@@ -1944,7 +1252,7 @@ var SubscriptionBundlesService = class {
|
|
|
1944
1252
|
const existing = await this.repo.findById(subscriptionBundleId);
|
|
1945
1253
|
if (!existing) {
|
|
1946
1254
|
throw new NotFoundException2({
|
|
1947
|
-
code:
|
|
1255
|
+
code: BILLING_ERROR_CODES2.SUBSCRIPTION_BUNDLE_NOT_FOUND,
|
|
1948
1256
|
message: `SubscriptionBundle '${subscriptionBundleId}' not found`,
|
|
1949
1257
|
params: {
|
|
1950
1258
|
subscriptionBundleId
|
|
@@ -1953,7 +1261,7 @@ var SubscriptionBundlesService = class {
|
|
|
1953
1261
|
}
|
|
1954
1262
|
if (existing.canceledAt === null) {
|
|
1955
1263
|
throw new UnprocessableEntityException({
|
|
1956
|
-
code:
|
|
1264
|
+
code: BILLING_ERROR_CODES2.SUBSCRIPTION_BUNDLE_NOT_CANCELLED,
|
|
1957
1265
|
message: `SubscriptionBundle '${subscriptionBundleId}' is not cancelled.`,
|
|
1958
1266
|
params: {
|
|
1959
1267
|
subscriptionBundleId
|
|
@@ -1962,23 +1270,23 @@ var SubscriptionBundlesService = class {
|
|
|
1962
1270
|
}
|
|
1963
1271
|
if (existing.canceledEffectiveAt !== null && existing.canceledEffectiveAt <= /* @__PURE__ */ new Date()) {
|
|
1964
1272
|
throw new UnprocessableEntityException({
|
|
1965
|
-
code:
|
|
1273
|
+
code: BILLING_ERROR_CODES2.SUBSCRIPTION_BUNDLE_CANCELLATION_EFFECTIVE,
|
|
1966
1274
|
message: "Cancellation already in effect \u2014 book the bundle again."
|
|
1967
1275
|
});
|
|
1968
1276
|
}
|
|
1969
1277
|
return this.repo.reactivate(subscriptionBundleId);
|
|
1970
1278
|
}
|
|
1971
1279
|
};
|
|
1972
|
-
SubscriptionBundlesService =
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1280
|
+
SubscriptionBundlesService = _ts_decorate10([
|
|
1281
|
+
Injectable6(),
|
|
1282
|
+
_ts_param6(0, Inject6(SUBSCRIPTION_BUNDLE_REPOSITORY_TOKEN)),
|
|
1283
|
+
_ts_param6(1, Inject6(BUNDLE_REPOSITORY_TOKEN)),
|
|
1284
|
+
_ts_param6(2, Optional5()),
|
|
1285
|
+
_ts_param6(2, Inject6(SUBSCRIPTION_BUNDLE_CONFIG_TOKEN)),
|
|
1286
|
+
_ts_param6(3, Optional5()),
|
|
1287
|
+
_ts_param6(3, Inject6(SELF_SERVICE_BLOCKED_BUNDLES_TOKEN)),
|
|
1288
|
+
_ts_metadata8("design:type", Function),
|
|
1289
|
+
_ts_metadata8("design:paramtypes", [
|
|
1982
1290
|
typeof SubscriptionBundleRepository === "undefined" ? Object : SubscriptionBundleRepository,
|
|
1983
1291
|
typeof BundleRepository === "undefined" ? Object : BundleRepository,
|
|
1984
1292
|
typeof SubscriptionBundleConfig === "undefined" ? Object : SubscriptionBundleConfig,
|
|
@@ -1999,23 +1307,25 @@ function addMonths(date, months) {
|
|
|
1999
1307
|
__name(addMonths, "addMonths");
|
|
2000
1308
|
|
|
2001
1309
|
// src/billing/tenant-billing.controller.ts
|
|
2002
|
-
|
|
1310
|
+
import { BadRequestException, Body, Controller as Controller2, ForbiddenException as ForbiddenException3, Get as Get2, HttpCode, HttpStatus, Inject as Inject7, Logger as Logger2, NotFoundException as NotFoundException3, Optional as Optional6, Post, Req, UseGuards } from "@nestjs/common";
|
|
1311
|
+
import { AUTH_ERROR_CODES as AUTH_ERROR_CODES3, BILLING_ERROR_CODES as BILLING_ERROR_CODES3 } from "@saasicat/types";
|
|
1312
|
+
function _ts_decorate11(decorators, target, key, desc) {
|
|
2003
1313
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
2004
1314
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
2005
1315
|
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;
|
|
2006
1316
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
2007
1317
|
}
|
|
2008
|
-
__name(
|
|
2009
|
-
function
|
|
1318
|
+
__name(_ts_decorate11, "_ts_decorate");
|
|
1319
|
+
function _ts_metadata9(k, v) {
|
|
2010
1320
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
2011
1321
|
}
|
|
2012
|
-
__name(
|
|
2013
|
-
function
|
|
1322
|
+
__name(_ts_metadata9, "_ts_metadata");
|
|
1323
|
+
function _ts_param7(paramIndex, decorator) {
|
|
2014
1324
|
return function(target, key) {
|
|
2015
1325
|
decorator(target, key, paramIndex);
|
|
2016
1326
|
};
|
|
2017
1327
|
}
|
|
2018
|
-
__name(
|
|
1328
|
+
__name(_ts_param7, "_ts_param");
|
|
2019
1329
|
var TenantBillingController = class _TenantBillingController {
|
|
2020
1330
|
static {
|
|
2021
1331
|
__name(this, "TenantBillingController");
|
|
@@ -2052,7 +1362,7 @@ var TenantBillingController = class _TenantBillingController {
|
|
|
2052
1362
|
this.contractFreeze = contractFreeze;
|
|
2053
1363
|
this.trialProjection = trialProjection;
|
|
2054
1364
|
}
|
|
2055
|
-
logger = new
|
|
1365
|
+
logger = new Logger2(_TenantBillingController.name);
|
|
2056
1366
|
// ---------------------------------------------------------------------
|
|
2057
1367
|
// Reads (Phase B) — all authenticated tenant users
|
|
2058
1368
|
// ---------------------------------------------------------------------
|
|
@@ -2070,7 +1380,7 @@ var TenantBillingController = class _TenantBillingController {
|
|
|
2070
1380
|
]);
|
|
2071
1381
|
if (!sub) {
|
|
2072
1382
|
throw new NotFoundException3({
|
|
2073
|
-
code:
|
|
1383
|
+
code: BILLING_ERROR_CODES3.SUBSCRIPTION_NOT_FOUND,
|
|
2074
1384
|
message: `No subscription for tenant ${tenantId}`,
|
|
2075
1385
|
params: {
|
|
2076
1386
|
tenantId
|
|
@@ -2124,8 +1434,8 @@ var TenantBillingController = class _TenantBillingController {
|
|
|
2124
1434
|
const userId = this.requireUserId(req);
|
|
2125
1435
|
const blockedTargets = this.blockedPlans?.asTarget ?? [];
|
|
2126
1436
|
if (blockedTargets.includes(dto.plan)) {
|
|
2127
|
-
throw new
|
|
2128
|
-
code:
|
|
1437
|
+
throw new ForbiddenException3({
|
|
1438
|
+
code: BILLING_ERROR_CODES3.PLAN_NOT_SELF_SERVICE,
|
|
2129
1439
|
message: `${dto.plan} is not activated via self-service.`,
|
|
2130
1440
|
params: {
|
|
2131
1441
|
planKey: dto.plan
|
|
@@ -2135,7 +1445,7 @@ var TenantBillingController = class _TenantBillingController {
|
|
|
2135
1445
|
const sub = await this.subscriptionUsage.findForTenant(tenantId);
|
|
2136
1446
|
if (!sub) {
|
|
2137
1447
|
throw new NotFoundException3({
|
|
2138
|
-
code:
|
|
1448
|
+
code: BILLING_ERROR_CODES3.SUBSCRIPTION_NOT_FOUND,
|
|
2139
1449
|
message: `No subscription for tenant ${tenantId}`,
|
|
2140
1450
|
params: {
|
|
2141
1451
|
tenantId
|
|
@@ -2145,7 +1455,7 @@ var TenantBillingController = class _TenantBillingController {
|
|
|
2145
1455
|
const blockers = await this.planPreview.assertChangeAllowed(tenantId, dto.plan, dto.billingCycle);
|
|
2146
1456
|
if (blockers.length > 0) {
|
|
2147
1457
|
throw new BadRequestException({
|
|
2148
|
-
code:
|
|
1458
|
+
code: BILLING_ERROR_CODES3.PLAN_CHANGE_BLOCKED,
|
|
2149
1459
|
message: "Plan change is blocked.",
|
|
2150
1460
|
blockers
|
|
2151
1461
|
});
|
|
@@ -2216,8 +1526,8 @@ var TenantBillingController = class _TenantBillingController {
|
|
|
2216
1526
|
const warnings = [];
|
|
2217
1527
|
const blockedTargets = this.blockedPlans?.asTarget ?? [];
|
|
2218
1528
|
if (blockedTargets.includes(dto.plan)) {
|
|
2219
|
-
throw new
|
|
2220
|
-
code:
|
|
1529
|
+
throw new ForbiddenException3({
|
|
1530
|
+
code: BILLING_ERROR_CODES3.PLAN_NOT_SELF_SERVICE,
|
|
2221
1531
|
message: `${dto.plan} is not activated via self-service.`,
|
|
2222
1532
|
params: {
|
|
2223
1533
|
planKey: dto.plan
|
|
@@ -2227,7 +1537,7 @@ var TenantBillingController = class _TenantBillingController {
|
|
|
2227
1537
|
const sub = await this.subscriptionUsage.findForTenant(tenantId);
|
|
2228
1538
|
if (!sub) {
|
|
2229
1539
|
throw new NotFoundException3({
|
|
2230
|
-
code:
|
|
1540
|
+
code: BILLING_ERROR_CODES3.SUBSCRIPTION_NOT_FOUND,
|
|
2231
1541
|
message: `No subscription for tenant ${tenantId}`,
|
|
2232
1542
|
params: {
|
|
2233
1543
|
tenantId
|
|
@@ -2237,7 +1547,7 @@ var TenantBillingController = class _TenantBillingController {
|
|
|
2237
1547
|
const blockers = await this.planPreview.assertChangeAllowed(tenantId, dto.plan, dto.billingCycle);
|
|
2238
1548
|
if (blockers.length > 0) {
|
|
2239
1549
|
throw new BadRequestException({
|
|
2240
|
-
code:
|
|
1550
|
+
code: BILLING_ERROR_CODES3.PLAN_CHANGE_BLOCKED,
|
|
2241
1551
|
message: "Plan change during onboarding is blocked.",
|
|
2242
1552
|
blockers
|
|
2243
1553
|
});
|
|
@@ -2274,7 +1584,7 @@ var TenantBillingController = class _TenantBillingController {
|
|
|
2274
1584
|
} catch (err) {
|
|
2275
1585
|
const reason = err instanceof Error ? err.message : null;
|
|
2276
1586
|
throw new BadRequestException({
|
|
2277
|
-
code:
|
|
1587
|
+
code: BILLING_ERROR_CODES3.ONBOARDING_CREATE_FAILED,
|
|
2278
1588
|
message: reason ? `Onboarding creation failed: ${reason}` : "Onboarding creation failed",
|
|
2279
1589
|
params: {
|
|
2280
1590
|
reason
|
|
@@ -2357,7 +1667,7 @@ var TenantBillingController = class _TenantBillingController {
|
|
|
2357
1667
|
const sub = await this.subscriptionUsage.findForTenant(tenantId);
|
|
2358
1668
|
if (!sub) {
|
|
2359
1669
|
throw new NotFoundException3({
|
|
2360
|
-
code:
|
|
1670
|
+
code: BILLING_ERROR_CODES3.SUBSCRIPTION_NOT_FOUND,
|
|
2361
1671
|
message: `No subscription for tenant ${tenantId}`,
|
|
2362
1672
|
params: {
|
|
2363
1673
|
tenantId
|
|
@@ -2366,7 +1676,7 @@ var TenantBillingController = class _TenantBillingController {
|
|
|
2366
1676
|
}
|
|
2367
1677
|
if (!sub.pendingPlanVersion) {
|
|
2368
1678
|
throw new BadRequestException({
|
|
2369
|
-
code:
|
|
1679
|
+
code: BILLING_ERROR_CODES3.NO_PENDING_PLAN_VERSION,
|
|
2370
1680
|
message: "There is no pending plan version awaiting confirmation."
|
|
2371
1681
|
});
|
|
2372
1682
|
}
|
|
@@ -2414,7 +1724,7 @@ var TenantBillingController = class _TenantBillingController {
|
|
|
2414
1724
|
const tenantId = resolver(req);
|
|
2415
1725
|
if (!tenantId) {
|
|
2416
1726
|
throw new NotFoundException3({
|
|
2417
|
-
code:
|
|
1727
|
+
code: AUTH_ERROR_CODES3.TENANT_CONTEXT_MISSING,
|
|
2418
1728
|
message: "No tenant ID found on the request"
|
|
2419
1729
|
});
|
|
2420
1730
|
}
|
|
@@ -2425,7 +1735,7 @@ var TenantBillingController = class _TenantBillingController {
|
|
|
2425
1735
|
const userId = resolver(req);
|
|
2426
1736
|
if (!userId) {
|
|
2427
1737
|
throw new NotFoundException3({
|
|
2428
|
-
code:
|
|
1738
|
+
code: AUTH_ERROR_CODES3.TENANT_CONTEXT_MISSING,
|
|
2429
1739
|
message: "No user ID found on the request"
|
|
2430
1740
|
});
|
|
2431
1741
|
}
|
|
@@ -2507,113 +1817,113 @@ var TenantBillingController = class _TenantBillingController {
|
|
|
2507
1817
|
}
|
|
2508
1818
|
}
|
|
2509
1819
|
};
|
|
2510
|
-
|
|
1820
|
+
_ts_decorate11([
|
|
2511
1821
|
Get2("entitlement"),
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
|
|
1822
|
+
_ts_param7(0, Req()),
|
|
1823
|
+
_ts_metadata9("design:type", Function),
|
|
1824
|
+
_ts_metadata9("design:paramtypes", [
|
|
2515
1825
|
typeof RequestLike === "undefined" ? Object : RequestLike
|
|
2516
1826
|
]),
|
|
2517
|
-
|
|
1827
|
+
_ts_metadata9("design:returntype", Promise)
|
|
2518
1828
|
], TenantBillingController.prototype, "getEntitlement", null);
|
|
2519
|
-
|
|
1829
|
+
_ts_decorate11([
|
|
2520
1830
|
Get2("usage"),
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
1831
|
+
_ts_param7(0, Req()),
|
|
1832
|
+
_ts_metadata9("design:type", Function),
|
|
1833
|
+
_ts_metadata9("design:paramtypes", [
|
|
2524
1834
|
typeof RequestLike === "undefined" ? Object : RequestLike
|
|
2525
1835
|
]),
|
|
2526
|
-
|
|
1836
|
+
_ts_metadata9("design:returntype", Promise)
|
|
2527
1837
|
], TenantBillingController.prototype, "getUsage", null);
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
HttpCode(
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
|
|
1838
|
+
_ts_decorate11([
|
|
1839
|
+
Post("plan/preview"),
|
|
1840
|
+
HttpCode(HttpStatus.OK),
|
|
1841
|
+
UseGuards(TenantAdminGuard),
|
|
1842
|
+
_ts_param7(0, Req()),
|
|
1843
|
+
_ts_param7(1, Body()),
|
|
1844
|
+
_ts_metadata9("design:type", Function),
|
|
1845
|
+
_ts_metadata9("design:paramtypes", [
|
|
2536
1846
|
typeof RequestLike === "undefined" ? Object : RequestLike,
|
|
2537
1847
|
typeof PreviewPlanChangeDto === "undefined" ? Object : PreviewPlanChangeDto
|
|
2538
1848
|
]),
|
|
2539
|
-
|
|
1849
|
+
_ts_metadata9("design:returntype", Promise)
|
|
2540
1850
|
], TenantBillingController.prototype, "previewPlanChange", null);
|
|
2541
|
-
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
|
|
2546
|
-
|
|
2547
|
-
|
|
1851
|
+
_ts_decorate11([
|
|
1852
|
+
Post("plan"),
|
|
1853
|
+
UseGuards(TenantAdminGuard),
|
|
1854
|
+
_ts_param7(0, Req()),
|
|
1855
|
+
_ts_param7(1, Body()),
|
|
1856
|
+
_ts_metadata9("design:type", Function),
|
|
1857
|
+
_ts_metadata9("design:paramtypes", [
|
|
2548
1858
|
typeof RequestLike === "undefined" ? Object : RequestLike,
|
|
2549
1859
|
typeof ChangePlanDto === "undefined" ? Object : ChangePlanDto
|
|
2550
1860
|
]),
|
|
2551
|
-
|
|
1861
|
+
_ts_metadata9("design:returntype", Promise)
|
|
2552
1862
|
], TenantBillingController.prototype, "changePlan", null);
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
1863
|
+
_ts_decorate11([
|
|
1864
|
+
Post("onboarding/initial-subscription"),
|
|
1865
|
+
UseGuards(TenantAdminGuard),
|
|
1866
|
+
_ts_param7(0, Req()),
|
|
1867
|
+
_ts_param7(1, Body()),
|
|
1868
|
+
_ts_metadata9("design:type", Function),
|
|
1869
|
+
_ts_metadata9("design:paramtypes", [
|
|
2560
1870
|
typeof RequestLike === "undefined" ? Object : RequestLike,
|
|
2561
1871
|
typeof CompleteOnboardingSubscriptionDto === "undefined" ? Object : CompleteOnboardingSubscriptionDto
|
|
2562
1872
|
]),
|
|
2563
|
-
|
|
1873
|
+
_ts_metadata9("design:returntype", Promise)
|
|
2564
1874
|
], TenantBillingController.prototype, "completeOnboardingSubscription", null);
|
|
2565
|
-
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
|
|
2569
|
-
|
|
2570
|
-
|
|
1875
|
+
_ts_decorate11([
|
|
1876
|
+
Post("subscription/accept-pending-version"),
|
|
1877
|
+
UseGuards(TenantAdminGuard),
|
|
1878
|
+
_ts_param7(0, Req()),
|
|
1879
|
+
_ts_metadata9("design:type", Function),
|
|
1880
|
+
_ts_metadata9("design:paramtypes", [
|
|
2571
1881
|
typeof RequestLike === "undefined" ? Object : RequestLike
|
|
2572
1882
|
]),
|
|
2573
|
-
|
|
1883
|
+
_ts_metadata9("design:returntype", Promise)
|
|
2574
1884
|
], TenantBillingController.prototype, "acceptPendingPlanVersion", null);
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
1885
|
+
_ts_decorate11([
|
|
1886
|
+
Post("cancel"),
|
|
1887
|
+
UseGuards(TenantAdminGuard),
|
|
1888
|
+
_ts_param7(0, Req()),
|
|
1889
|
+
_ts_param7(1, Body()),
|
|
1890
|
+
_ts_metadata9("design:type", Function),
|
|
1891
|
+
_ts_metadata9("design:paramtypes", [
|
|
2582
1892
|
typeof RequestLike === "undefined" ? Object : RequestLike,
|
|
2583
1893
|
typeof CancelSubscriptionDto === "undefined" ? Object : CancelSubscriptionDto
|
|
2584
1894
|
]),
|
|
2585
|
-
|
|
1895
|
+
_ts_metadata9("design:returntype", Promise)
|
|
2586
1896
|
], TenantBillingController.prototype, "cancelSubscription", null);
|
|
2587
|
-
TenantBillingController =
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
|
|
2600
|
-
|
|
2601
|
-
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
1897
|
+
TenantBillingController = _ts_decorate11([
|
|
1898
|
+
Controller2("billing"),
|
|
1899
|
+
UseGuards(ComposedTenantAuthGuard),
|
|
1900
|
+
_ts_param7(0, Inject7(ENTITLEMENT_SERVICE_TOKEN)),
|
|
1901
|
+
_ts_param7(1, Inject7(PlanChangePreviewService)),
|
|
1902
|
+
_ts_param7(2, Inject7(SUBSCRIPTION_USAGE_PORT_TOKEN)),
|
|
1903
|
+
_ts_param7(3, Inject7(USAGE_SNAPSHOT_PORT_TOKEN)),
|
|
1904
|
+
_ts_param7(4, Inject7(SUBSCRIPTION_WRITE_PORT_TOKEN)),
|
|
1905
|
+
_ts_param7(5, Optional6()),
|
|
1906
|
+
_ts_param7(5, Inject7(TENANT_ID_RESOLVER_TOKEN)),
|
|
1907
|
+
_ts_param7(6, Optional6()),
|
|
1908
|
+
_ts_param7(6, Inject7(USER_ID_RESOLVER_TOKEN)),
|
|
1909
|
+
_ts_param7(7, Optional6()),
|
|
1910
|
+
_ts_param7(7, Inject7(SELF_SERVICE_BLOCKED_PLANS_TOKEN)),
|
|
1911
|
+
_ts_param7(8, Optional6()),
|
|
1912
|
+
_ts_param7(8, Inject7(PromoCodesService)),
|
|
1913
|
+
_ts_param7(9, Optional6()),
|
|
1914
|
+
_ts_param7(9, Inject7(AdminAuditService)),
|
|
1915
|
+
_ts_param7(10, Optional6()),
|
|
1916
|
+
_ts_param7(10, Inject7(USER_EMAIL_RESOLVER_TOKEN)),
|
|
1917
|
+
_ts_param7(11, Optional6()),
|
|
1918
|
+
_ts_param7(11, Inject7(AUDIT_CONTEXT_RESOLVER_TOKEN)),
|
|
1919
|
+
_ts_param7(12, Optional6()),
|
|
1920
|
+
_ts_param7(12, Inject7(SubscriptionBundlesService)),
|
|
1921
|
+
_ts_param7(13, Optional6()),
|
|
1922
|
+
_ts_param7(13, Inject7(CONTRACT_FREEZE_PORT_TOKEN)),
|
|
1923
|
+
_ts_param7(14, Optional6()),
|
|
1924
|
+
_ts_param7(14, Inject7(TRIAL_PROJECTION_PORT_TOKEN)),
|
|
1925
|
+
_ts_metadata9("design:type", Function),
|
|
1926
|
+
_ts_metadata9("design:paramtypes", [
|
|
2617
1927
|
typeof EntitlementService === "undefined" ? Object : EntitlementService,
|
|
2618
1928
|
typeof PlanChangePreviewService === "undefined" ? Object : PlanChangePreviewService,
|
|
2619
1929
|
typeof SubscriptionUsagePort === "undefined" ? Object : SubscriptionUsagePort,
|
|
@@ -2633,14 +1943,14 @@ TenantBillingController = _ts_decorate17([
|
|
|
2633
1943
|
], TenantBillingController);
|
|
2634
1944
|
|
|
2635
1945
|
// src/billing/tenant-billing.module.ts
|
|
2636
|
-
import { Module as
|
|
2637
|
-
function
|
|
1946
|
+
import { Module as Module2 } from "@nestjs/common";
|
|
1947
|
+
function _ts_decorate12(decorators, target, key, desc) {
|
|
2638
1948
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
2639
1949
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
2640
1950
|
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;
|
|
2641
1951
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
2642
1952
|
}
|
|
2643
|
-
__name(
|
|
1953
|
+
__name(_ts_decorate12, "_ts_decorate");
|
|
2644
1954
|
var TenantBillingModule = class _TenantBillingModule {
|
|
2645
1955
|
static {
|
|
2646
1956
|
__name(this, "TenantBillingModule");
|
|
@@ -2729,91 +2039,30 @@ var TenantBillingModule = class _TenantBillingModule {
|
|
|
2729
2039
|
};
|
|
2730
2040
|
}
|
|
2731
2041
|
};
|
|
2732
|
-
TenantBillingModule =
|
|
2733
|
-
|
|
2042
|
+
TenantBillingModule = _ts_decorate12([
|
|
2043
|
+
Module2({})
|
|
2734
2044
|
], TenantBillingModule);
|
|
2735
2045
|
|
|
2736
|
-
// src/billing/configurator-catalog-builder.ts
|
|
2737
|
-
import { Injectable as Injectable10 } from "@nestjs/common";
|
|
2738
|
-
function _ts_decorate19(decorators, target, key, desc) {
|
|
2739
|
-
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
2740
|
-
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
2741
|
-
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;
|
|
2742
|
-
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
2743
|
-
}
|
|
2744
|
-
__name(_ts_decorate19, "_ts_decorate");
|
|
2745
|
-
var ConfiguratorCatalogBuilder = class {
|
|
2746
|
-
static {
|
|
2747
|
-
__name(this, "ConfiguratorCatalogBuilder");
|
|
2748
|
-
}
|
|
2749
|
-
async build(input) {
|
|
2750
|
-
const { sources, marketing } = input;
|
|
2751
|
-
const planRows = await sources.listLivePlans();
|
|
2752
|
-
const planMarketingByPlanId = new Map(marketing.listPlanMarketing().map((m) => [
|
|
2753
|
-
m.planId,
|
|
2754
|
-
m
|
|
2755
|
-
]));
|
|
2756
|
-
return {
|
|
2757
|
-
cycleDiscount: marketing.getCycleDiscount(),
|
|
2758
|
-
currency: marketing.getCurrency(),
|
|
2759
|
-
vatRate: marketing.getVatRate(),
|
|
2760
|
-
models: planRows.filter((row) => row.marketed).map((row) => buildModel(row, planMarketingByPlanId)).filter((m) => m !== null)
|
|
2761
|
-
};
|
|
2762
|
-
}
|
|
2763
|
-
};
|
|
2764
|
-
ConfiguratorCatalogBuilder = _ts_decorate19([
|
|
2765
|
-
Injectable10()
|
|
2766
|
-
], ConfiguratorCatalogBuilder);
|
|
2767
|
-
function buildModel(row, marketing) {
|
|
2768
|
-
const m = marketing.get(row.planId);
|
|
2769
|
-
if (!m) return null;
|
|
2770
|
-
return {
|
|
2771
|
-
id: row.planId.toLowerCase(),
|
|
2772
|
-
code: m.code,
|
|
2773
|
-
name: m.name,
|
|
2774
|
-
glyph: m.glyph,
|
|
2775
|
-
tagline: m.tagline,
|
|
2776
|
-
planId: row.planId,
|
|
2777
|
-
monthlyNet: row.monthlyNet,
|
|
2778
|
-
yearlyNet: row.yearlyNet,
|
|
2779
|
-
tags: m.tags,
|
|
2780
|
-
includedFeatureKeys: row.features,
|
|
2781
|
-
quotaBase: normalizeQuotas(row.quotas),
|
|
2782
|
-
...m.popular ? {
|
|
2783
|
-
popular: true
|
|
2784
|
-
} : {}
|
|
2785
|
-
};
|
|
2786
|
-
}
|
|
2787
|
-
__name(buildModel, "buildModel");
|
|
2788
|
-
function normalizeQuotas(quotas) {
|
|
2789
|
-
const out = {};
|
|
2790
|
-
for (const [k, v] of Object.entries(quotas)) {
|
|
2791
|
-
out[k] = v === -1 ? Number.MAX_SAFE_INTEGER : v;
|
|
2792
|
-
}
|
|
2793
|
-
return out;
|
|
2794
|
-
}
|
|
2795
|
-
__name(normalizeQuotas, "normalizeQuotas");
|
|
2796
|
-
|
|
2797
2046
|
// src/billing/subscription-bundle-preview.service.ts
|
|
2798
|
-
import { Inject as
|
|
2799
|
-
import { BILLING_ERROR_CODES as
|
|
2800
|
-
function
|
|
2047
|
+
import { Inject as Inject8, Injectable as Injectable7, NotFoundException as NotFoundException4, Optional as Optional7 } from "@nestjs/common";
|
|
2048
|
+
import { BILLING_ERROR_CODES as BILLING_ERROR_CODES4, CATALOG_ERROR_CODES as CATALOG_ERROR_CODES2, buildFeatureRequiresIndex as buildFeatureRequiresIndex2, collectUnsatisfiedRequires as collectUnsatisfiedRequires2 } from "@saasicat/types";
|
|
2049
|
+
function _ts_decorate13(decorators, target, key, desc) {
|
|
2801
2050
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
2802
2051
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
2803
2052
|
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;
|
|
2804
2053
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
2805
2054
|
}
|
|
2806
|
-
__name(
|
|
2807
|
-
function
|
|
2055
|
+
__name(_ts_decorate13, "_ts_decorate");
|
|
2056
|
+
function _ts_metadata10(k, v) {
|
|
2808
2057
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
2809
2058
|
}
|
|
2810
|
-
__name(
|
|
2811
|
-
function
|
|
2059
|
+
__name(_ts_metadata10, "_ts_metadata");
|
|
2060
|
+
function _ts_param8(paramIndex, decorator) {
|
|
2812
2061
|
return function(target, key) {
|
|
2813
2062
|
decorator(target, key, paramIndex);
|
|
2814
2063
|
};
|
|
2815
2064
|
}
|
|
2816
|
-
__name(
|
|
2065
|
+
__name(_ts_param8, "_ts_param");
|
|
2817
2066
|
var SubscriptionBundlePreviewService = class {
|
|
2818
2067
|
static {
|
|
2819
2068
|
__name(this, "SubscriptionBundlePreviewService");
|
|
@@ -2895,7 +2144,7 @@ var SubscriptionBundlePreviewService = class {
|
|
|
2895
2144
|
const existing = await this.subscriptionBundles.findById(input.subscriptionBundleId);
|
|
2896
2145
|
if (!existing || existing.subscriptionId !== ctx.subscriptionId) {
|
|
2897
2146
|
throw new NotFoundException4({
|
|
2898
|
-
code:
|
|
2147
|
+
code: BILLING_ERROR_CODES4.SUBSCRIPTION_BUNDLE_NOT_FOUND,
|
|
2899
2148
|
message: `SubscriptionBundle '${input.subscriptionBundleId}' not found`,
|
|
2900
2149
|
params: {
|
|
2901
2150
|
subscriptionBundleId: input.subscriptionBundleId
|
|
@@ -2916,7 +2165,7 @@ var SubscriptionBundlePreviewService = class {
|
|
|
2916
2165
|
const warnings = [];
|
|
2917
2166
|
if (existing.canceledAt !== null) {
|
|
2918
2167
|
blockers.push({
|
|
2919
|
-
code:
|
|
2168
|
+
code: BILLING_ERROR_CODES4.SUBSCRIPTION_BUNDLE_ALREADY_CANCELLED,
|
|
2920
2169
|
message: "This bundle booking is already cancelled."
|
|
2921
2170
|
});
|
|
2922
2171
|
}
|
|
@@ -3016,12 +2265,12 @@ var SubscriptionBundlePreviewService = class {
|
|
|
3016
2265
|
const entries = await this.catalogEntries.listFeatures({
|
|
3017
2266
|
projectKey
|
|
3018
2267
|
});
|
|
3019
|
-
const requiresIndex =
|
|
2268
|
+
const requiresIndex = buildFeatureRequiresIndex2(entries);
|
|
3020
2269
|
const covered = /* @__PURE__ */ new Set([
|
|
3021
2270
|
...planFeatures,
|
|
3022
2271
|
...activeBundleVersions.flatMap((bv) => bv.features ?? [])
|
|
3023
2272
|
]);
|
|
3024
|
-
return
|
|
2273
|
+
return collectUnsatisfiedRequires2(bundleVersion.features ?? [], requiresIndex).filter((key) => !covered.has(key));
|
|
3025
2274
|
}
|
|
3026
2275
|
/** `projectKey` lives on the bundle stem, not on the version. */
|
|
3027
2276
|
async resolveProjectKey(bundleVersion) {
|
|
@@ -3029,20 +2278,20 @@ var SubscriptionBundlePreviewService = class {
|
|
|
3029
2278
|
return stem?.projectKey ?? null;
|
|
3030
2279
|
}
|
|
3031
2280
|
};
|
|
3032
|
-
SubscriptionBundlePreviewService =
|
|
3033
|
-
|
|
3034
|
-
|
|
3035
|
-
|
|
3036
|
-
|
|
3037
|
-
|
|
3038
|
-
|
|
3039
|
-
|
|
3040
|
-
|
|
3041
|
-
|
|
3042
|
-
|
|
3043
|
-
|
|
3044
|
-
|
|
3045
|
-
|
|
2281
|
+
SubscriptionBundlePreviewService = _ts_decorate13([
|
|
2282
|
+
Injectable7(),
|
|
2283
|
+
_ts_param8(0, Inject8(SUBSCRIPTION_BUNDLE_REPOSITORY_TOKEN)),
|
|
2284
|
+
_ts_param8(1, Inject8(BUNDLE_REPOSITORY_TOKEN)),
|
|
2285
|
+
_ts_param8(2, Optional7()),
|
|
2286
|
+
_ts_param8(2, Inject8(PLAN_REPOSITORY_TOKEN)),
|
|
2287
|
+
_ts_param8(3, Optional7()),
|
|
2288
|
+
_ts_param8(3, Inject8(CATALOG_ENTRY_REPOSITORY_TOKEN)),
|
|
2289
|
+
_ts_param8(4, Optional7()),
|
|
2290
|
+
_ts_param8(4, Inject8(SELF_SERVICE_BLOCKED_BUNDLES_TOKEN)),
|
|
2291
|
+
_ts_param8(5, Optional7()),
|
|
2292
|
+
_ts_param8(5, Inject8(SUBSCRIPTION_BUNDLE_CONFIG_TOKEN)),
|
|
2293
|
+
_ts_metadata10("design:type", Function),
|
|
2294
|
+
_ts_metadata10("design:paramtypes", [
|
|
3046
2295
|
typeof SubscriptionBundleRepository === "undefined" ? Object : SubscriptionBundleRepository,
|
|
3047
2296
|
typeof BundleRepository === "undefined" ? Object : BundleRepository,
|
|
3048
2297
|
Object,
|
|
@@ -3075,26 +2324,23 @@ function toSnapshot(bundleVersion) {
|
|
|
3075
2324
|
}
|
|
3076
2325
|
__name(toSnapshot, "toSnapshot");
|
|
3077
2326
|
|
|
3078
|
-
// src/billing/subscription-bundles.module.ts
|
|
3079
|
-
import { Module as Module4 } from "@nestjs/common";
|
|
3080
|
-
|
|
3081
2327
|
// src/billing/tenant-subscription-bundles.controller.ts
|
|
3082
|
-
import { BadRequestException as BadRequestException2, Body as
|
|
3083
|
-
import { AUTH_ERROR_CODES as
|
|
2328
|
+
import { BadRequestException as BadRequestException2, Body as Body2, Controller as Controller3, Delete, Get as Get3, HttpCode as HttpCode2, HttpStatus as HttpStatus2, Inject as Inject9, Logger as Logger3, NotFoundException as NotFoundException5, Optional as Optional8, Param, ParseUUIDPipe, Post as Post2, Req as Req2, UseGuards as UseGuards2 } from "@nestjs/common";
|
|
2329
|
+
import { AUTH_ERROR_CODES as AUTH_ERROR_CODES4, BILLING_ERROR_CODES as BILLING_ERROR_CODES5 } from "@saasicat/types";
|
|
3084
2330
|
|
|
3085
2331
|
// src/billing/dto/subscription-bundles.dto.ts
|
|
3086
|
-
import { IsInt, IsOptional as
|
|
3087
|
-
function
|
|
2332
|
+
import { IsInt, IsOptional as IsOptional3, IsUUID as IsUUID2, Matches as Matches3, Max, Min } from "class-validator";
|
|
2333
|
+
function _ts_decorate14(decorators, target, key, desc) {
|
|
3088
2334
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3089
2335
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
3090
2336
|
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;
|
|
3091
2337
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
3092
2338
|
}
|
|
3093
|
-
__name(
|
|
3094
|
-
function
|
|
2339
|
+
__name(_ts_decorate14, "_ts_decorate");
|
|
2340
|
+
function _ts_metadata11(k, v) {
|
|
3095
2341
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
3096
2342
|
}
|
|
3097
|
-
__name(
|
|
2343
|
+
__name(_ts_metadata11, "_ts_metadata");
|
|
3098
2344
|
var ISO_DATE_PATTERN = /^\d{4}-\d{2}-\d{2}(T.*)?$/;
|
|
3099
2345
|
var AddSubscriptionBundleDto = class {
|
|
3100
2346
|
static {
|
|
@@ -3108,16 +2354,16 @@ var AddSubscriptionBundleDto = class {
|
|
|
3108
2354
|
*/
|
|
3109
2355
|
minimumTermMonths;
|
|
3110
2356
|
};
|
|
3111
|
-
|
|
2357
|
+
_ts_decorate14([
|
|
3112
2358
|
IsUUID2(),
|
|
3113
|
-
|
|
2359
|
+
_ts_metadata11("design:type", String)
|
|
3114
2360
|
], AddSubscriptionBundleDto.prototype, "bundleVersionId", void 0);
|
|
3115
|
-
|
|
3116
|
-
|
|
2361
|
+
_ts_decorate14([
|
|
2362
|
+
IsOptional3(),
|
|
3117
2363
|
IsInt(),
|
|
3118
2364
|
Min(0),
|
|
3119
2365
|
Max(120),
|
|
3120
|
-
|
|
2366
|
+
_ts_metadata11("design:type", Number)
|
|
3121
2367
|
], AddSubscriptionBundleDto.prototype, "minimumTermMonths", void 0);
|
|
3122
2368
|
var PreviewSubscriptionBundleDto = class {
|
|
3123
2369
|
static {
|
|
@@ -3130,22 +2376,22 @@ var PreviewSubscriptionBundleDto = class {
|
|
|
3130
2376
|
/** Add preview only — override analogous to `AddSubscriptionBundleDto`. */
|
|
3131
2377
|
minimumTermMonths;
|
|
3132
2378
|
};
|
|
3133
|
-
|
|
3134
|
-
|
|
2379
|
+
_ts_decorate14([
|
|
2380
|
+
IsOptional3(),
|
|
3135
2381
|
IsUUID2(),
|
|
3136
|
-
|
|
2382
|
+
_ts_metadata11("design:type", String)
|
|
3137
2383
|
], PreviewSubscriptionBundleDto.prototype, "bundleVersionId", void 0);
|
|
3138
|
-
|
|
3139
|
-
|
|
2384
|
+
_ts_decorate14([
|
|
2385
|
+
IsOptional3(),
|
|
3140
2386
|
IsUUID2(),
|
|
3141
|
-
|
|
2387
|
+
_ts_metadata11("design:type", String)
|
|
3142
2388
|
], PreviewSubscriptionBundleDto.prototype, "subscriptionBundleId", void 0);
|
|
3143
|
-
|
|
3144
|
-
|
|
2389
|
+
_ts_decorate14([
|
|
2390
|
+
IsOptional3(),
|
|
3145
2391
|
IsInt(),
|
|
3146
2392
|
Min(0),
|
|
3147
2393
|
Max(120),
|
|
3148
|
-
|
|
2394
|
+
_ts_metadata11("design:type", Number)
|
|
3149
2395
|
], PreviewSubscriptionBundleDto.prototype, "minimumTermMonths", void 0);
|
|
3150
2396
|
var CancelSubscriptionBundleDto = class {
|
|
3151
2397
|
static {
|
|
@@ -3158,32 +2404,32 @@ var CancelSubscriptionBundleDto = class {
|
|
|
3158
2404
|
*/
|
|
3159
2405
|
canceledAt;
|
|
3160
2406
|
};
|
|
3161
|
-
|
|
3162
|
-
|
|
2407
|
+
_ts_decorate14([
|
|
2408
|
+
IsOptional3(),
|
|
3163
2409
|
Matches3(ISO_DATE_PATTERN, {
|
|
3164
2410
|
message: "canceledAt must be an ISO date (YYYY-MM-DD)"
|
|
3165
2411
|
}),
|
|
3166
|
-
|
|
2412
|
+
_ts_metadata11("design:type", String)
|
|
3167
2413
|
], CancelSubscriptionBundleDto.prototype, "canceledAt", void 0);
|
|
3168
2414
|
|
|
3169
2415
|
// src/billing/tenant-subscription-bundles.controller.ts
|
|
3170
|
-
function
|
|
2416
|
+
function _ts_decorate15(decorators, target, key, desc) {
|
|
3171
2417
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3172
2418
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
3173
2419
|
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;
|
|
3174
2420
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
3175
2421
|
}
|
|
3176
|
-
__name(
|
|
3177
|
-
function
|
|
2422
|
+
__name(_ts_decorate15, "_ts_decorate");
|
|
2423
|
+
function _ts_metadata12(k, v) {
|
|
3178
2424
|
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
3179
2425
|
}
|
|
3180
|
-
__name(
|
|
3181
|
-
function
|
|
2426
|
+
__name(_ts_metadata12, "_ts_metadata");
|
|
2427
|
+
function _ts_param9(paramIndex, decorator) {
|
|
3182
2428
|
return function(target, key) {
|
|
3183
2429
|
decorator(target, key, paramIndex);
|
|
3184
2430
|
};
|
|
3185
2431
|
}
|
|
3186
|
-
__name(
|
|
2432
|
+
__name(_ts_param9, "_ts_param");
|
|
3187
2433
|
function buildTenantSubscriptionBundlesController(extraGuards = []) {
|
|
3188
2434
|
let GeneratedTenantSubscriptionBundlesController = class GeneratedTenantSubscriptionBundlesController2 {
|
|
3189
2435
|
static {
|
|
@@ -3194,7 +2440,7 @@ function buildTenantSubscriptionBundlesController(extraGuards = []) {
|
|
|
3194
2440
|
subscriptionUsage;
|
|
3195
2441
|
tenantIdResolver;
|
|
3196
2442
|
contractFreeze;
|
|
3197
|
-
logger = new
|
|
2443
|
+
logger = new Logger3("TenantSubscriptionBundlesController");
|
|
3198
2444
|
/** Keeps the "no contractFreeze hook" warning to one line per process. */
|
|
3199
2445
|
static warnedAboutMissingFreeze = false;
|
|
3200
2446
|
constructor(service, previewService, subscriptionUsage, tenantIdResolver, contractFreeze = null) {
|
|
@@ -3226,7 +2472,7 @@ function buildTenantSubscriptionBundlesController(extraGuards = []) {
|
|
|
3226
2472
|
const hasCancel = Boolean(dto.subscriptionBundleId);
|
|
3227
2473
|
if (hasAdd === hasCancel) {
|
|
3228
2474
|
throw new BadRequestException2({
|
|
3229
|
-
code:
|
|
2475
|
+
code: BILLING_ERROR_CODES5.BUNDLE_PREVIEW_ARGUMENT_AMBIGUOUS,
|
|
3230
2476
|
message: "Exactly one of bundleVersionId (add preview) or subscriptionBundleId (cancel preview) must be given."
|
|
3231
2477
|
});
|
|
3232
2478
|
}
|
|
@@ -3268,7 +2514,7 @@ function buildTenantSubscriptionBundlesController(extraGuards = []) {
|
|
|
3268
2514
|
}
|
|
3269
2515
|
requireSubscriptionPk(sub) {
|
|
3270
2516
|
if (!sub.id) {
|
|
3271
|
-
throw new NotFoundException5(codedError(
|
|
2517
|
+
throw new NotFoundException5(codedError(BILLING_ERROR_CODES5.SUBSCRIPTION_PK_MISSING));
|
|
3272
2518
|
}
|
|
3273
2519
|
return sub.id;
|
|
3274
2520
|
}
|
|
@@ -3276,7 +2522,7 @@ function buildTenantSubscriptionBundlesController(extraGuards = []) {
|
|
|
3276
2522
|
const tenantId = this.tenantIdResolver(req);
|
|
3277
2523
|
if (!tenantId) {
|
|
3278
2524
|
throw new NotFoundException5({
|
|
3279
|
-
code:
|
|
2525
|
+
code: AUTH_ERROR_CODES4.TENANT_CONTEXT_MISSING,
|
|
3280
2526
|
message: "No tenant ID found on the request"
|
|
3281
2527
|
});
|
|
3282
2528
|
}
|
|
@@ -3286,7 +2532,7 @@ function buildTenantSubscriptionBundlesController(extraGuards = []) {
|
|
|
3286
2532
|
const sub = await this.subscriptionUsage.findForTenant(tenantId);
|
|
3287
2533
|
if (!sub) {
|
|
3288
2534
|
throw new NotFoundException5({
|
|
3289
|
-
code:
|
|
2535
|
+
code: BILLING_ERROR_CODES5.SUBSCRIPTION_NOT_FOUND,
|
|
3290
2536
|
message: `No subscription for tenant ${tenantId}`,
|
|
3291
2537
|
params: {
|
|
3292
2538
|
tenantId
|
|
@@ -3314,75 +2560,75 @@ function buildTenantSubscriptionBundlesController(extraGuards = []) {
|
|
|
3314
2560
|
}
|
|
3315
2561
|
}
|
|
3316
2562
|
};
|
|
3317
|
-
|
|
2563
|
+
_ts_decorate15([
|
|
3318
2564
|
Get3(),
|
|
3319
|
-
|
|
3320
|
-
|
|
3321
|
-
|
|
2565
|
+
_ts_param9(0, Req2()),
|
|
2566
|
+
_ts_metadata12("design:type", Function),
|
|
2567
|
+
_ts_metadata12("design:paramtypes", [
|
|
3322
2568
|
typeof RequestLike === "undefined" ? Object : RequestLike
|
|
3323
2569
|
]),
|
|
3324
|
-
|
|
2570
|
+
_ts_metadata12("design:returntype", Promise)
|
|
3325
2571
|
], GeneratedTenantSubscriptionBundlesController.prototype, "list", null);
|
|
3326
|
-
|
|
3327
|
-
|
|
3328
|
-
|
|
3329
|
-
|
|
3330
|
-
|
|
3331
|
-
|
|
2572
|
+
_ts_decorate15([
|
|
2573
|
+
Post2(),
|
|
2574
|
+
_ts_param9(0, Req2()),
|
|
2575
|
+
_ts_param9(1, Body2()),
|
|
2576
|
+
_ts_metadata12("design:type", Function),
|
|
2577
|
+
_ts_metadata12("design:paramtypes", [
|
|
3332
2578
|
typeof RequestLike === "undefined" ? Object : RequestLike,
|
|
3333
2579
|
typeof AddSubscriptionBundleDto === "undefined" ? Object : AddSubscriptionBundleDto
|
|
3334
2580
|
]),
|
|
3335
|
-
|
|
2581
|
+
_ts_metadata12("design:returntype", Promise)
|
|
3336
2582
|
], GeneratedTenantSubscriptionBundlesController.prototype, "add", null);
|
|
3337
|
-
|
|
3338
|
-
|
|
3339
|
-
HttpCode2(
|
|
3340
|
-
|
|
3341
|
-
|
|
3342
|
-
|
|
3343
|
-
|
|
2583
|
+
_ts_decorate15([
|
|
2584
|
+
Post2("preview"),
|
|
2585
|
+
HttpCode2(HttpStatus2.OK),
|
|
2586
|
+
_ts_param9(0, Req2()),
|
|
2587
|
+
_ts_param9(1, Body2()),
|
|
2588
|
+
_ts_metadata12("design:type", Function),
|
|
2589
|
+
_ts_metadata12("design:paramtypes", [
|
|
3344
2590
|
typeof RequestLike === "undefined" ? Object : RequestLike,
|
|
3345
2591
|
typeof PreviewSubscriptionBundleDto === "undefined" ? Object : PreviewSubscriptionBundleDto
|
|
3346
2592
|
]),
|
|
3347
|
-
|
|
2593
|
+
_ts_metadata12("design:returntype", Promise)
|
|
3348
2594
|
], GeneratedTenantSubscriptionBundlesController.prototype, "preview", null);
|
|
3349
|
-
|
|
2595
|
+
_ts_decorate15([
|
|
3350
2596
|
Delete(":id"),
|
|
3351
|
-
HttpCode2(
|
|
3352
|
-
|
|
3353
|
-
|
|
3354
|
-
|
|
3355
|
-
|
|
3356
|
-
|
|
2597
|
+
HttpCode2(HttpStatus2.OK),
|
|
2598
|
+
_ts_param9(0, Req2()),
|
|
2599
|
+
_ts_param9(1, Param("id", new ParseUUIDPipe())),
|
|
2600
|
+
_ts_param9(2, Body2()),
|
|
2601
|
+
_ts_metadata12("design:type", Function),
|
|
2602
|
+
_ts_metadata12("design:paramtypes", [
|
|
3357
2603
|
typeof RequestLike === "undefined" ? Object : RequestLike,
|
|
3358
2604
|
String,
|
|
3359
2605
|
typeof CancelSubscriptionBundleDto === "undefined" ? Object : CancelSubscriptionBundleDto
|
|
3360
2606
|
]),
|
|
3361
|
-
|
|
2607
|
+
_ts_metadata12("design:returntype", Promise)
|
|
3362
2608
|
], GeneratedTenantSubscriptionBundlesController.prototype, "cancel", null);
|
|
3363
|
-
|
|
3364
|
-
|
|
3365
|
-
HttpCode2(
|
|
3366
|
-
|
|
3367
|
-
|
|
3368
|
-
|
|
3369
|
-
|
|
2609
|
+
_ts_decorate15([
|
|
2610
|
+
Post2(":id/reactivate"),
|
|
2611
|
+
HttpCode2(HttpStatus2.OK),
|
|
2612
|
+
_ts_param9(0, Req2()),
|
|
2613
|
+
_ts_param9(1, Param("id", new ParseUUIDPipe())),
|
|
2614
|
+
_ts_metadata12("design:type", Function),
|
|
2615
|
+
_ts_metadata12("design:paramtypes", [
|
|
3370
2616
|
typeof RequestLike === "undefined" ? Object : RequestLike,
|
|
3371
2617
|
String
|
|
3372
2618
|
]),
|
|
3373
|
-
|
|
2619
|
+
_ts_metadata12("design:returntype", Promise)
|
|
3374
2620
|
], GeneratedTenantSubscriptionBundlesController.prototype, "reactivate", null);
|
|
3375
|
-
GeneratedTenantSubscriptionBundlesController =
|
|
3376
|
-
|
|
3377
|
-
|
|
3378
|
-
|
|
3379
|
-
|
|
3380
|
-
|
|
3381
|
-
|
|
3382
|
-
|
|
3383
|
-
|
|
3384
|
-
|
|
3385
|
-
|
|
2621
|
+
GeneratedTenantSubscriptionBundlesController = _ts_decorate15([
|
|
2622
|
+
Controller3("billing/subscription-bundles"),
|
|
2623
|
+
UseGuards2(ComposedTenantAuthGuard, ...extraGuards),
|
|
2624
|
+
_ts_param9(0, Inject9(SubscriptionBundlesService)),
|
|
2625
|
+
_ts_param9(1, Inject9(SubscriptionBundlePreviewService)),
|
|
2626
|
+
_ts_param9(2, Inject9(SUBSCRIPTION_USAGE_PORT_TOKEN)),
|
|
2627
|
+
_ts_param9(3, Inject9(TENANT_ID_RESOLVER_TOKEN)),
|
|
2628
|
+
_ts_param9(4, Optional8()),
|
|
2629
|
+
_ts_param9(4, Inject9(CONTRACT_FREEZE_PORT_TOKEN)),
|
|
2630
|
+
_ts_metadata12("design:type", Function),
|
|
2631
|
+
_ts_metadata12("design:paramtypes", [
|
|
3386
2632
|
typeof SubscriptionBundlesService === "undefined" ? Object : SubscriptionBundlesService,
|
|
3387
2633
|
typeof SubscriptionBundlePreviewService === "undefined" ? Object : SubscriptionBundlePreviewService,
|
|
3388
2634
|
typeof SubscriptionUsagePort === "undefined" ? Object : SubscriptionUsagePort,
|
|
@@ -3395,13 +2641,14 @@ function buildTenantSubscriptionBundlesController(extraGuards = []) {
|
|
|
3395
2641
|
__name(buildTenantSubscriptionBundlesController, "buildTenantSubscriptionBundlesController");
|
|
3396
2642
|
|
|
3397
2643
|
// src/billing/subscription-bundles.module.ts
|
|
3398
|
-
|
|
2644
|
+
import { Module as Module3 } from "@nestjs/common";
|
|
2645
|
+
function _ts_decorate16(decorators, target, key, desc) {
|
|
3399
2646
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3400
2647
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
3401
2648
|
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;
|
|
3402
2649
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
3403
2650
|
}
|
|
3404
|
-
__name(
|
|
2651
|
+
__name(_ts_decorate16, "_ts_decorate");
|
|
3405
2652
|
var SubscriptionBundleModule = class _SubscriptionBundleModule {
|
|
3406
2653
|
static {
|
|
3407
2654
|
__name(this, "SubscriptionBundleModule");
|
|
@@ -3457,43 +2704,22 @@ var SubscriptionBundleModule = class _SubscriptionBundleModule {
|
|
|
3457
2704
|
};
|
|
3458
2705
|
}
|
|
3459
2706
|
};
|
|
3460
|
-
SubscriptionBundleModule =
|
|
3461
|
-
|
|
2707
|
+
SubscriptionBundleModule = _ts_decorate16([
|
|
2708
|
+
Module3({})
|
|
3462
2709
|
], SubscriptionBundleModule);
|
|
3463
2710
|
|
|
3464
2711
|
export {
|
|
3465
2712
|
periodEndAfter,
|
|
3466
2713
|
initialPeriodWindow,
|
|
3467
2714
|
periodEndWithMinLead,
|
|
3468
|
-
PublishValidationError,
|
|
3469
|
-
assertChangeNote,
|
|
3470
|
-
assertDraftPublishable,
|
|
3471
|
-
assertBaseVersionFresh,
|
|
3472
|
-
assertOptimisticLockHeld,
|
|
3473
|
-
decideRenewal,
|
|
3474
|
-
clearPendingPlanVersionFields,
|
|
3475
|
-
computeNextPeriod,
|
|
3476
2715
|
FEATURE_GUARD_MARKER,
|
|
3477
2716
|
isPlatformFeatureGuard,
|
|
3478
2717
|
REQUIRE_FEATURE_KEY,
|
|
3479
2718
|
RequireFeature,
|
|
3480
|
-
FEATURE_GUARD_CONFIG_TOKEN,
|
|
3481
|
-
UPSELL_OFFER_RESOLVER_TOKEN,
|
|
3482
|
-
UPSELL_OFFER_CURRENCY_TOKEN,
|
|
3483
|
-
FeatureGuard,
|
|
3484
2719
|
PUBLIC_CATALOG_PROJECT_KEY_TOKEN,
|
|
3485
2720
|
PUBLIC_CATALOG_BUNDLE_REPOSITORY_TOKEN,
|
|
3486
2721
|
PUBLIC_CATALOG_MARKETING_REPOSITORY_TOKEN,
|
|
3487
|
-
|
|
3488
|
-
LimitExceededFilter,
|
|
3489
|
-
PlanCatalogValidationError,
|
|
3490
|
-
loadPlanCatalogFromFile,
|
|
3491
|
-
loadPlanCatalogFromString,
|
|
3492
|
-
PLAN_CATALOG_IMPORT_SINK_TOKEN,
|
|
3493
|
-
PlanCatalogImporterService,
|
|
3494
|
-
PlanCatalogImportDto,
|
|
3495
|
-
buildPlanCatalogImporterController,
|
|
3496
|
-
PlanCatalogImporterModule,
|
|
2722
|
+
PUBLIC_CATALOG_CATALOG_ENTRY_REPOSITORY_TOKEN,
|
|
3497
2723
|
FEATURE_UI_REGISTRY_TOKEN,
|
|
3498
2724
|
PublicCatalogController,
|
|
3499
2725
|
PublicCatalogModule,
|
|
@@ -3508,7 +2734,6 @@ export {
|
|
|
3508
2734
|
CONTRACT_FREEZE_PROJECT_KEY_TOKEN,
|
|
3509
2735
|
PendingPlanMaterializationService,
|
|
3510
2736
|
SubscriptionContractFreezeService,
|
|
3511
|
-
computeCarriedTrialEndsAt,
|
|
3512
2737
|
PreviewPlanChangeDto,
|
|
3513
2738
|
ChangePlanDto,
|
|
3514
2739
|
CancelSubscriptionDto,
|
|
@@ -3518,7 +2743,6 @@ export {
|
|
|
3518
2743
|
addMonths,
|
|
3519
2744
|
TenantBillingController,
|
|
3520
2745
|
TenantBillingModule,
|
|
3521
|
-
ConfiguratorCatalogBuilder,
|
|
3522
2746
|
SubscriptionBundlePreviewService,
|
|
3523
2747
|
resolveBundlePriceNet,
|
|
3524
2748
|
buildTenantSubscriptionBundlesController,
|