@saasicat/nest 0.27.0 → 1.0.0-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/.build-stamp +1 -0
- package/dist/_entries.cjs +460 -460
- package/dist/admin/index.d.cts +6 -6
- package/dist/admin/index.d.ts +6 -6
- package/dist/admin/index.js +3 -3
- package/dist/{admin-audit.service-9IqXMlZm.d.cts → admin-audit.service-4P3Djdxk.d.cts} +1 -1
- package/dist/{admin-audit.service-9IqXMlZm.d.ts → admin-audit.service-4P3Djdxk.d.ts} +1 -1
- package/dist/{admin-resources.module-DGgGSdzN.d.cts → admin-resources.module-CpvzcfCc.d.cts} +2 -2
- package/dist/{admin-resources.module-BY5r_1MG.d.ts → admin-resources.module-DF5_Q7RD.d.ts} +2 -2
- package/dist/{admin-stats.service-HUZIU448.d.cts → admin-stats.service-DfKupywR.d.cts} +3 -3
- package/dist/{admin-stats.service-Db2exT_d.d.ts → admin-stats.service-TYiSUwIR.d.ts} +3 -3
- package/dist/{aggregation-DP5zfKbU.d.ts → aggregation-B3CD0v_d.d.cts} +2 -2
- package/dist/{aggregation-mZ7WZROK.d.cts → aggregation-BFzW07DE.d.ts} +2 -2
- package/dist/billing/index.d.cts +13 -13
- package/dist/billing/index.d.ts +13 -13
- package/dist/billing/index.js +15 -15
- package/dist/catalog/index.d.cts +17 -5
- package/dist/catalog/index.d.ts +17 -5
- package/dist/catalog/index.js +12 -10
- package/dist/{catalog.module-D-_pQDNA.d.cts → catalog.module-BDDO6iwq.d.cts} +1 -1
- package/dist/{catalog.module-CQr1FpkI.d.ts → catalog.module-BTnMsE6u.d.ts} +1 -1
- package/dist/checkout-offer/index.d.cts +3 -3
- package/dist/checkout-offer/index.d.ts +3 -3
- package/dist/checkout-offer/index.js +2 -2
- package/dist/{checkout-offer.module-Ca3_TieR.d.ts → checkout-offer.module-CMtiQJTT.d.ts} +1 -1
- package/dist/{checkout-offer.module-DmlpPevf.d.cts → checkout-offer.module-CVpWrzbe.d.cts} +1 -1
- package/dist/{checkout-offer.service-BX51dljL.d.ts → checkout-offer.service-BLOv2HOo.d.cts} +1 -1
- package/dist/{checkout-offer.service-BX51dljL.d.cts → checkout-offer.service-BLOv2HOo.d.ts} +1 -1
- package/dist/{chunk-EBJJNTW6.js → chunk-57V6ZTI6.js} +1 -1
- package/dist/{chunk-37HEKVDH.js → chunk-7TVZI3KY.js} +11 -11
- package/dist/chunk-AOQJEYOL.js +20 -0
- package/dist/{chunk-3E6ONOMG.js → chunk-AU3OOREM.js} +2 -2
- package/dist/{chunk-H4DOTO7S.js → chunk-BGS4CWV2.js} +5 -5
- package/dist/{chunk-YYUXKLXK.js → chunk-I7GTA3RX.js} +2 -2
- package/dist/{chunk-7ZPFQXHM.js → chunk-IQTQLQD3.js} +5 -5
- package/dist/{chunk-CJFAOD7K.js → chunk-KFT5AIIH.js} +2 -2
- package/dist/{chunk-XTVAFJ3P.js → chunk-L23MLBEC.js} +7 -7
- package/dist/{chunk-SN5UOC43.js → chunk-LTT736P3.js} +15 -15
- package/dist/{chunk-WPUVJRIN.js → chunk-N3L3AICU.js} +11 -11
- package/dist/{chunk-MJ32VNZD.js → chunk-NARZ2WWK.js} +22 -22
- package/dist/{chunk-E56W4U2P.js → chunk-O2J2HDXA.js} +4 -4
- package/dist/{chunk-WKVBNTYC.js → chunk-OUDSQ3PU.js} +6 -6
- package/dist/{chunk-F4B2NJUZ.js → chunk-PK6C5R7B.js} +15 -15
- package/dist/{chunk-L4SUWH5B.js → chunk-QUZU2M33.js} +2 -2
- package/dist/{chunk-NYLON2VC.js → chunk-VBRYPU7V.js} +2 -2
- package/dist/{chunk-2JTISFUZ.js → chunk-VG2NU3CG.js} +11 -11
- package/dist/{chunk-7X5MSAIL.js → chunk-VNADKD5U.js} +23 -23
- package/dist/{chunk-UHD6FJBQ.js → chunk-W6YEIY4R.js} +46 -46
- package/dist/{chunk-5ZXBXYXU.js → chunk-WXYJHZCN.js} +3 -3
- package/dist/{chunk-6WL6VQ7Z.js → chunk-XBYAFEOR.js} +2 -2
- package/dist/{chunk-EHKMPP6J.js → chunk-XMA4XYC5.js} +40 -40
- package/dist/{chunk-B6IWLV7R.js → chunk-YZPVQUIW.js} +8 -8
- package/dist/{define-saasicat-CFxut1VR.d.cts → define-saasicat-B5RmWiD2.d.cts} +8 -8
- package/dist/{define-saasicat-3ois8t8s.d.ts → define-saasicat-DN-dRObd.d.ts} +8 -8
- package/dist/discovery/index.d.cts +4 -4
- package/dist/discovery/index.d.ts +4 -4
- package/dist/discovery/index.js +7 -7
- package/dist/{discovery.scanner-DLgEvuoy.d.cts → discovery.scanner-9cMqF95o.d.cts} +1 -1
- package/dist/{discovery.scanner-DLgEvuoy.d.ts → discovery.scanner-9cMqF95o.d.ts} +1 -1
- package/dist/{enforce-quota.interceptor-N80KC34N.d.cts → enforce-quota.interceptor-CnieZsdB.d.cts} +3 -3
- package/dist/{enforce-quota.interceptor-CYDNvAQz.d.ts → enforce-quota.interceptor-Cseo35Ki.d.ts} +3 -3
- package/dist/entitlement/index.d.cts +4 -4
- package/dist/entitlement/index.d.ts +4 -4
- package/dist/entitlement/index.js +8 -8
- package/dist/index.d.cts +23 -23
- package/dist/index.d.ts +23 -23
- package/dist/index.js +137 -136
- package/dist/{module-options-klrPnWGF.d.cts → module-options-CjeSSaBf.d.cts} +35 -35
- package/dist/{module-options-ByJL7FZm.d.ts → module-options-DtcJqwjv.d.ts} +35 -35
- package/dist/{plan-resolution-CFCoUkrE.d.cts → plan-resolution-Cgo_TR1H.d.cts} +1 -1
- package/dist/{plan-resolution-CFCoUkrE.d.ts → plan-resolution-Cgo_TR1H.d.ts} +1 -1
- package/dist/{plan-versions.service-B-YoE4SZ.d.ts → plan-versions.service-DChhbK6h.d.ts} +2 -2
- package/dist/{plan-versions.service-_saKzb50.d.cts → plan-versions.service-TPEtbN0r.d.cts} +2 -2
- package/dist/platform/index.d.cts +29 -29
- package/dist/platform/index.d.ts +29 -29
- package/dist/platform/index.js +32 -33
- package/dist/promo/index.d.cts +4 -4
- package/dist/promo/index.d.ts +4 -4
- package/dist/promo/index.js +4 -4
- package/dist/{module-BE17XFLg.d.ts → promo.module-BUKcUWDf.d.ts} +2 -2
- package/dist/{module-CHMIyWlf.d.cts → promo.module-BY2YHHLn.d.cts} +2 -2
- package/dist/{service-D48clObR.d.cts → promo.service-2qFgqF-a.d.cts} +1 -1
- package/dist/{service-D48clObR.d.ts → promo.service-2qFgqF-a.d.ts} +1 -1
- package/dist/registration/index.d.cts +3 -3
- package/dist/registration/index.d.ts +3 -3
- package/dist/registration/index.js +2 -2
- package/dist/subscription-contract/index.d.cts +3 -3
- package/dist/subscription-contract/index.d.ts +3 -3
- package/dist/subscription-contract/index.js +3 -3
- package/dist/{subscription-contract.module-B2uNvUJL.d.cts → subscription-contract.module-CEK8HS5-.d.cts} +1 -1
- package/dist/{subscription-contract.module-edyhBr4n.d.ts → subscription-contract.module-fDFdQ0jm.d.ts} +1 -1
- package/dist/{subscription-contract.service--cm47ZJJ.d.cts → subscription-contract.service-hD87MKyg.d.cts} +1 -1
- package/dist/{subscription-contract.service--cm47ZJJ.d.ts → subscription-contract.service-hD87MKyg.d.ts} +1 -1
- package/dist/{tenant-billing.controller-CAMMdfn1.d.cts → tenant-billing.controller-B6UTheK_.d.cts} +5 -5
- package/dist/{tenant-billing.controller-CYYK0CpT.d.ts → tenant-billing.controller-DpgHCT9r.d.ts} +5 -5
- package/dist/{tenant-billing.module-BxJS6fX4.d.cts → tenant-billing.module-BznC3XtW.d.cts} +1 -1
- package/dist/{tenant-billing.module-B0stLoJn.d.ts → tenant-billing.module-wUbsQSFG.d.ts} +1 -1
- package/dist/testing/index.d.cts +19 -19
- package/dist/testing/index.d.ts +19 -19
- package/dist/testing/index.js +33 -33
- package/package.json +5 -5
- package/dist/chunk-L4KTQ6CL.js +0 -20
package/dist/_entries.cjs
CHANGED
|
@@ -80,14 +80,14 @@ __export(admin_exports, {
|
|
|
80
80
|
buildAdminStatsController: () => buildAdminStatsController
|
|
81
81
|
});
|
|
82
82
|
|
|
83
|
-
// src/admin/tokens.ts
|
|
84
|
-
var MFA_PORT_TOKEN = /* @__PURE__ */ Symbol.for("
|
|
85
|
-
var AUDIT_PORT_TOKEN = /* @__PURE__ */ Symbol.for("
|
|
86
|
-
var RLS_BYPASS_PORT_TOKEN = /* @__PURE__ */ Symbol.for("
|
|
83
|
+
// src/admin/admin.tokens.ts
|
|
84
|
+
var MFA_PORT_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/nest/MfaPort");
|
|
85
|
+
var AUDIT_PORT_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/nest/AuditPort");
|
|
86
|
+
var RLS_BYPASS_PORT_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/nest/RlsBypassPort");
|
|
87
87
|
|
|
88
88
|
// src/admin/super-admin.guard.ts
|
|
89
89
|
var import_common = require("@nestjs/common");
|
|
90
|
-
var
|
|
90
|
+
var import_core = require("@saasicat/core");
|
|
91
91
|
function _ts_decorate(decorators, target, key, desc) {
|
|
92
92
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
93
93
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
@@ -103,14 +103,14 @@ var SuperAdminGuard = class {
|
|
|
103
103
|
const request = context.switchToHttp().getRequest();
|
|
104
104
|
if (!request.user) {
|
|
105
105
|
throw new import_common.ForbiddenException({
|
|
106
|
-
code:
|
|
106
|
+
code: import_core.AUTH_ERROR_CODES.NOT_AUTHENTICATED,
|
|
107
107
|
message: "Not authenticated"
|
|
108
108
|
});
|
|
109
109
|
}
|
|
110
110
|
const role = request.user.platformRole ?? request.user.role;
|
|
111
111
|
if (role !== "SUPER_ADMIN") {
|
|
112
112
|
throw new import_common.ForbiddenException({
|
|
113
|
-
code:
|
|
113
|
+
code: import_core.AUTH_ERROR_CODES.SUPER_ADMIN_REQUIRED,
|
|
114
114
|
message: "Only the SUPER_ADMIN role is allowed"
|
|
115
115
|
});
|
|
116
116
|
}
|
|
@@ -123,13 +123,13 @@ SuperAdminGuard = _ts_decorate([
|
|
|
123
123
|
|
|
124
124
|
// src/admin/mfa.guard.ts
|
|
125
125
|
var import_common3 = require("@nestjs/common");
|
|
126
|
-
var
|
|
127
|
-
var
|
|
126
|
+
var import_core3 = require("@nestjs/core");
|
|
127
|
+
var import_core4 = require("@saasicat/core");
|
|
128
128
|
|
|
129
129
|
// src/errors/coded-error.ts
|
|
130
|
-
var
|
|
130
|
+
var import_core2 = require("@saasicat/core");
|
|
131
131
|
function codedError(code, params) {
|
|
132
|
-
const message = (0,
|
|
132
|
+
const message = (0, import_core2.formatErrorMessage)(import_core2.ERROR_MESSAGES_EN[code], params ?? {});
|
|
133
133
|
return params ? {
|
|
134
134
|
code,
|
|
135
135
|
message,
|
|
@@ -141,7 +141,7 @@ function codedError(code, params) {
|
|
|
141
141
|
}
|
|
142
142
|
__name(codedError, "codedError");
|
|
143
143
|
|
|
144
|
-
// src/admin/mfa.ts
|
|
144
|
+
// src/admin/mfa.service.ts
|
|
145
145
|
var import_common2 = require("@nestjs/common");
|
|
146
146
|
var import_otplib = require("otplib");
|
|
147
147
|
function _ts_decorate2(decorators, target, key, desc) {
|
|
@@ -261,7 +261,7 @@ function _ts_param2(paramIndex, decorator) {
|
|
|
261
261
|
};
|
|
262
262
|
}
|
|
263
263
|
__name(_ts_param2, "_ts_param");
|
|
264
|
-
var REQUIRE_MFA_KEY = "
|
|
264
|
+
var REQUIRE_MFA_KEY = "saasicat/nest/require-mfa";
|
|
265
265
|
var RequireMfa = /* @__PURE__ */ __name(() => (0, import_common3.SetMetadata)(REQUIRE_MFA_KEY, true), "RequireMfa");
|
|
266
266
|
var MfaGuard = class _MfaGuard {
|
|
267
267
|
static {
|
|
@@ -287,7 +287,7 @@ var MfaGuard = class _MfaGuard {
|
|
|
287
287
|
const user = request.user;
|
|
288
288
|
if (!user) {
|
|
289
289
|
throw new import_common3.UnauthorizedException({
|
|
290
|
-
...codedError(
|
|
290
|
+
...codedError(import_core4.AUTH_ERROR_CODES.NOT_AUTHENTICATED),
|
|
291
291
|
// `reason` is superseded by `code` and will be removed.
|
|
292
292
|
reason: "NOT_AUTHENTICATED"
|
|
293
293
|
});
|
|
@@ -295,7 +295,7 @@ var MfaGuard = class _MfaGuard {
|
|
|
295
295
|
const enabled = await this.mfaService.isEnabled(user.id);
|
|
296
296
|
if (!enabled) {
|
|
297
297
|
throw new import_common3.UnauthorizedException({
|
|
298
|
-
code:
|
|
298
|
+
code: import_core4.AUTH_ERROR_CODES.MFA_NOT_SET_UP,
|
|
299
299
|
// `reason` is superseded by `code` and will be removed.
|
|
300
300
|
reason: "MFA_NOT_SET_UP",
|
|
301
301
|
message: "Run the MFA setup via the CLI first."
|
|
@@ -305,7 +305,7 @@ var MfaGuard = class _MfaGuard {
|
|
|
305
305
|
const code = Array.isArray(headerVal) ? headerVal[0] : headerVal;
|
|
306
306
|
if (!code) {
|
|
307
307
|
throw new import_common3.UnauthorizedException({
|
|
308
|
-
code:
|
|
308
|
+
code: import_core4.AUTH_ERROR_CODES.MFA_REQUIRED,
|
|
309
309
|
// `reason` is superseded by `code` and will be removed.
|
|
310
310
|
reason: "MFA_REQUIRED",
|
|
311
311
|
message: "TOTP code required in the X-Mfa-Code header."
|
|
@@ -317,7 +317,7 @@ var MfaGuard = class _MfaGuard {
|
|
|
317
317
|
});
|
|
318
318
|
if (!valid) {
|
|
319
319
|
throw new import_common3.UnauthorizedException({
|
|
320
|
-
code:
|
|
320
|
+
code: import_core4.AUTH_ERROR_CODES.MFA_FAILED,
|
|
321
321
|
// `reason` is superseded by `code` and will be removed.
|
|
322
322
|
reason: "MFA_FAILED",
|
|
323
323
|
message: "Invalid TOTP code."
|
|
@@ -328,10 +328,10 @@ var MfaGuard = class _MfaGuard {
|
|
|
328
328
|
};
|
|
329
329
|
MfaGuard = _ts_decorate3([
|
|
330
330
|
(0, import_common3.Injectable)(),
|
|
331
|
-
_ts_param2(0, (0, import_common3.Inject)(
|
|
331
|
+
_ts_param2(0, (0, import_common3.Inject)(import_core3.Reflector)),
|
|
332
332
|
_ts_metadata2("design:type", Function),
|
|
333
333
|
_ts_metadata2("design:paramtypes", [
|
|
334
|
-
typeof
|
|
334
|
+
typeof import_core3.Reflector === "undefined" ? Object : import_core3.Reflector,
|
|
335
335
|
typeof MfaService === "undefined" ? Object : MfaService
|
|
336
336
|
])
|
|
337
337
|
], MfaGuard);
|
|
@@ -455,7 +455,7 @@ AdminBypassRlsInterceptor = _ts_decorate5([
|
|
|
455
455
|
])
|
|
456
456
|
], AdminBypassRlsInterceptor);
|
|
457
457
|
|
|
458
|
-
// src/admin/module.ts
|
|
458
|
+
// src/admin/admin.module.ts
|
|
459
459
|
var import_common6 = require("@nestjs/common");
|
|
460
460
|
|
|
461
461
|
// src/core/di.ts
|
|
@@ -475,7 +475,7 @@ function asProvider(token, impl) {
|
|
|
475
475
|
}
|
|
476
476
|
__name(asProvider, "asProvider");
|
|
477
477
|
|
|
478
|
-
// src/admin/module.ts
|
|
478
|
+
// src/admin/admin.module.ts
|
|
479
479
|
function _ts_decorate6(decorators, target, key, desc) {
|
|
480
480
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
481
481
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
@@ -521,7 +521,7 @@ AdminModule = _ts_decorate6([
|
|
|
521
521
|
], AdminModule);
|
|
522
522
|
|
|
523
523
|
// src/admin/admin-manifest.config.ts
|
|
524
|
-
var ADMIN_MANIFEST_CONFIG = /* @__PURE__ */ Symbol.for("
|
|
524
|
+
var ADMIN_MANIFEST_CONFIG = /* @__PURE__ */ Symbol.for("saasicat/nest/AdminManifestConfig");
|
|
525
525
|
|
|
526
526
|
// src/admin/admin-manifest.service.ts
|
|
527
527
|
var import_common7 = require("@nestjs/common");
|
|
@@ -543,7 +543,7 @@ function _ts_param5(paramIndex, decorator) {
|
|
|
543
543
|
};
|
|
544
544
|
}
|
|
545
545
|
__name(_ts_param5, "_ts_param");
|
|
546
|
-
var PLATFORM_CORE_CONTRIBUTION_TOKEN = /* @__PURE__ */ Symbol.for("
|
|
546
|
+
var PLATFORM_CORE_CONTRIBUTION_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/nest/PlatformCoreContribution");
|
|
547
547
|
var AdminManifestService = class _AdminManifestService {
|
|
548
548
|
static {
|
|
549
549
|
__name(this, "AdminManifestService");
|
|
@@ -1149,10 +1149,10 @@ AdminManifestModule = _ts_decorate9([
|
|
|
1149
1149
|
], AdminManifestModule);
|
|
1150
1150
|
|
|
1151
1151
|
// src/admin/admin-stats.tokens.ts
|
|
1152
|
-
var SUBSCRIPTION_STATS_PORT_TOKEN = /* @__PURE__ */ Symbol.for("
|
|
1153
|
-
var PROMO_CODE_STATS_PORT_TOKEN = /* @__PURE__ */ Symbol.for("
|
|
1154
|
-
var AUDIT_STATS_PORT_TOKEN = /* @__PURE__ */ Symbol.for("
|
|
1155
|
-
var ADMIN_STATS_AUDIT_WINDOW_DAYS_TOKEN = /* @__PURE__ */ Symbol.for("
|
|
1152
|
+
var SUBSCRIPTION_STATS_PORT_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/nest/SubscriptionStatsPort");
|
|
1153
|
+
var PROMO_CODE_STATS_PORT_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/nest/PromoCodeStatsPort");
|
|
1154
|
+
var AUDIT_STATS_PORT_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/nest/AuditStatsPort");
|
|
1155
|
+
var ADMIN_STATS_AUDIT_WINDOW_DAYS_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/nest/AdminStatsAuditWindowDays");
|
|
1156
1156
|
|
|
1157
1157
|
// src/admin/admin-stats.service.ts
|
|
1158
1158
|
var import_common11 = require("@nestjs/common");
|
|
@@ -1353,7 +1353,7 @@ AdminStatsModule = _ts_decorate12([
|
|
|
1353
1353
|
// src/admin/admin-resources.module.ts
|
|
1354
1354
|
var import_common14 = require("@nestjs/common");
|
|
1355
1355
|
var import_class_validator = require("class-validator");
|
|
1356
|
-
var
|
|
1356
|
+
var import_core5 = require("@saasicat/core");
|
|
1357
1357
|
function _ts_decorate13(decorators, target, key, desc) {
|
|
1358
1358
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
1359
1359
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
@@ -1371,7 +1371,7 @@ function _ts_param10(paramIndex, decorator) {
|
|
|
1371
1371
|
};
|
|
1372
1372
|
}
|
|
1373
1373
|
__name(_ts_param10, "_ts_param");
|
|
1374
|
-
var ADMIN_RESOURCES_PORT_TOKEN = /* @__PURE__ */ Symbol.for("
|
|
1374
|
+
var ADMIN_RESOURCES_PORT_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/nest/AdminResourcesPort");
|
|
1375
1375
|
var SuspendTenantDto = class {
|
|
1376
1376
|
static {
|
|
1377
1377
|
__name(this, "SuspendTenantDto");
|
|
@@ -1401,7 +1401,7 @@ var AdminResourcesService = class {
|
|
|
1401
1401
|
const tenant = await this.resources.getTenantDetail(slug);
|
|
1402
1402
|
if (!tenant) {
|
|
1403
1403
|
throw new import_common14.NotFoundException({
|
|
1404
|
-
code:
|
|
1404
|
+
code: import_core5.BILLING_ERROR_CODES.TENANT_NOT_FOUND,
|
|
1405
1405
|
message: `Tenant ${slug} not found`,
|
|
1406
1406
|
params: {
|
|
1407
1407
|
slug
|
|
@@ -1435,7 +1435,7 @@ var AdminResourcesService = class {
|
|
|
1435
1435
|
const result = await this.resources.setTenantActive(slug, active, subscriptionStatus);
|
|
1436
1436
|
if (!result) {
|
|
1437
1437
|
throw new import_common14.NotFoundException({
|
|
1438
|
-
code:
|
|
1438
|
+
code: import_core5.BILLING_ERROR_CODES.TENANT_NOT_FOUND,
|
|
1439
1439
|
message: `Tenant ${slug} not found`,
|
|
1440
1440
|
params: {
|
|
1441
1441
|
slug
|
|
@@ -1621,6 +1621,7 @@ AdminResourcesModule = _ts_decorate13([
|
|
|
1621
1621
|
var billing_exports = {};
|
|
1622
1622
|
__export(billing_exports, {
|
|
1623
1623
|
AUDIT_CONTEXT_RESOLVER_TOKEN: () => AUDIT_CONTEXT_RESOLVER_TOKEN,
|
|
1624
|
+
BILLING_FEATURE_UI_REGISTRY_TOKEN: () => BILLING_FEATURE_UI_REGISTRY_TOKEN,
|
|
1624
1625
|
CONTRACT_FREEZE_PORT_TOKEN: () => CONTRACT_FREEZE_PORT_TOKEN,
|
|
1625
1626
|
CONTRACT_FREEZE_PROJECT_KEY_TOKEN: () => CONTRACT_FREEZE_PROJECT_KEY_TOKEN,
|
|
1626
1627
|
CONTRACT_FREEZE_SOURCE_PORT_TOKEN: () => CONTRACT_FREEZE_SOURCE_PORT_TOKEN,
|
|
@@ -1632,7 +1633,6 @@ __export(billing_exports, {
|
|
|
1632
1633
|
ConfiguratorCatalogBuilder: () => ConfiguratorCatalogBuilder,
|
|
1633
1634
|
FEATURE_GUARD_CONFIG_TOKEN: () => FEATURE_GUARD_CONFIG_TOKEN,
|
|
1634
1635
|
FEATURE_GUARD_MARKER: () => FEATURE_GUARD_MARKER,
|
|
1635
|
-
FEATURE_UI_REGISTRY_TOKEN: () => FEATURE_UI_REGISTRY_TOKEN2,
|
|
1636
1636
|
FeatureGuard: () => FeatureGuard,
|
|
1637
1637
|
LimitExceededFilter: () => LimitExceededFilter,
|
|
1638
1638
|
PENDING_PLAN_QUERY_PORT_TOKEN: () => PENDING_PLAN_QUERY_PORT_TOKEN,
|
|
@@ -1684,8 +1684,8 @@ __export(billing_exports, {
|
|
|
1684
1684
|
buildPlanCatalogFromSnapshot: () => buildPlanCatalogFromSnapshot,
|
|
1685
1685
|
buildPlanCatalogImporterController: () => buildPlanCatalogImporterController,
|
|
1686
1686
|
buildTenantSubscriptionBundlesController: () => buildTenantSubscriptionBundlesController,
|
|
1687
|
-
classifyBundleVersionDiff: () =>
|
|
1688
|
-
classifyPlanDiff: () =>
|
|
1687
|
+
classifyBundleVersionDiff: () => import_core6.classifyBundleVersionDiff,
|
|
1688
|
+
classifyPlanDiff: () => import_core6.classifyPlanDiff,
|
|
1689
1689
|
clearPendingPlanVersionFields: () => clearPendingPlanVersionFields,
|
|
1690
1690
|
computeCarriedTrialEndsAt: () => computeCarriedTrialEndsAt,
|
|
1691
1691
|
computeNextPeriod: () => computeNextPeriod,
|
|
@@ -1747,7 +1747,7 @@ function periodEndWithMinLead(startedAt, cycle, now, minLeadDays = 42) {
|
|
|
1747
1747
|
__name(periodEndWithMinLead, "periodEndWithMinLead");
|
|
1748
1748
|
|
|
1749
1749
|
// src/billing/version-diff.ts
|
|
1750
|
-
var
|
|
1750
|
+
var import_core6 = require("@saasicat/core");
|
|
1751
1751
|
|
|
1752
1752
|
// src/billing/version-publish.ts
|
|
1753
1753
|
var PublishValidationError = class extends Error {
|
|
@@ -1847,26 +1847,26 @@ var REQUIRE_FEATURE_KEY = "require-feature";
|
|
|
1847
1847
|
var RequireFeature = /* @__PURE__ */ __name((...features) => (0, import_common15.SetMetadata)(REQUIRE_FEATURE_KEY, features), "RequireFeature");
|
|
1848
1848
|
|
|
1849
1849
|
// src/billing/feature-guard.tokens.ts
|
|
1850
|
-
var FEATURE_GUARD_CONFIG_TOKEN = /* @__PURE__ */ Symbol.for("
|
|
1850
|
+
var FEATURE_GUARD_CONFIG_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/nest/FeatureGuardConfig");
|
|
1851
1851
|
|
|
1852
1852
|
// src/billing/feature.guard.ts
|
|
1853
1853
|
var import_common18 = require("@nestjs/common");
|
|
1854
|
-
var
|
|
1855
|
-
var
|
|
1854
|
+
var import_core8 = require("@nestjs/core");
|
|
1855
|
+
var import_core9 = require("@saasicat/core");
|
|
1856
1856
|
|
|
1857
|
-
// src/entitlement/service.ts
|
|
1857
|
+
// src/entitlement/entitlement.service.ts
|
|
1858
1858
|
var import_common17 = require("@nestjs/common");
|
|
1859
|
-
var
|
|
1859
|
+
var import_core7 = require("@saasicat/core");
|
|
1860
1860
|
|
|
1861
|
-
// src/catalog/tokens.ts
|
|
1862
|
-
var PLAN_REPOSITORY_TOKEN = /* @__PURE__ */ Symbol.for("
|
|
1863
|
-
var BUNDLE_REPOSITORY_TOKEN = /* @__PURE__ */ Symbol.for("
|
|
1864
|
-
var MARKETING_PROJECTION_REPOSITORY_TOKEN = /* @__PURE__ */ Symbol.for("
|
|
1865
|
-
var CATALOG_ENTRY_REPOSITORY_TOKEN = /* @__PURE__ */ Symbol.for("
|
|
1866
|
-
var PROMOTION_REPOSITORY_TOKEN = /* @__PURE__ */ Symbol.for("
|
|
1867
|
-
var MARKETING_SETTINGS_REPOSITORY_TOKEN = /* @__PURE__ */ Symbol.for("
|
|
1868
|
-
var CATALOG_SERVICE_CONFIG_TOKEN = /* @__PURE__ */ Symbol.for("
|
|
1869
|
-
var
|
|
1861
|
+
// src/catalog/catalog.tokens.ts
|
|
1862
|
+
var PLAN_REPOSITORY_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/nest/PlanRepository");
|
|
1863
|
+
var BUNDLE_REPOSITORY_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/nest/BundleRepository");
|
|
1864
|
+
var MARKETING_PROJECTION_REPOSITORY_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/nest/MarketingProjectionRepository");
|
|
1865
|
+
var CATALOG_ENTRY_REPOSITORY_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/nest/CatalogEntryRepository");
|
|
1866
|
+
var PROMOTION_REPOSITORY_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/nest/PromotionRepository");
|
|
1867
|
+
var MARKETING_SETTINGS_REPOSITORY_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/nest/MarketingSettingsRepository");
|
|
1868
|
+
var CATALOG_SERVICE_CONFIG_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/nest/CatalogServiceConfig");
|
|
1869
|
+
var CATALOG_FEATURE_UI_REGISTRY_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/nest/CatalogFeatureUiRegistry");
|
|
1870
1870
|
|
|
1871
1871
|
// src/billing/plan-catalog.module.ts
|
|
1872
1872
|
var import_common16 = require("@nestjs/common");
|
|
@@ -1996,18 +1996,18 @@ PlanCatalogModule = _ts_decorate14([
|
|
|
1996
1996
|
], PlanCatalogModule);
|
|
1997
1997
|
|
|
1998
1998
|
// src/billing/subscription-bundles.tokens.ts
|
|
1999
|
-
var SUBSCRIPTION_BUNDLE_REPOSITORY_TOKEN = /* @__PURE__ */ Symbol.for("
|
|
2000
|
-
var SUBSCRIPTION_BUNDLE_CONFIG_TOKEN = /* @__PURE__ */ Symbol.for("
|
|
1999
|
+
var SUBSCRIPTION_BUNDLE_REPOSITORY_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/nest/SubscriptionBundleRepository");
|
|
2000
|
+
var SUBSCRIPTION_BUNDLE_CONFIG_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/nest/SubscriptionBundleConfig");
|
|
2001
2001
|
|
|
2002
|
-
// src/subscription-contract/tokens.ts
|
|
2003
|
-
var SUBSCRIPTION_CONTRACT_REPOSITORY_TOKEN = /* @__PURE__ */ Symbol.for("
|
|
2002
|
+
// src/subscription-contract/subscription-contract.tokens.ts
|
|
2003
|
+
var SUBSCRIPTION_CONTRACT_REPOSITORY_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/nest/SubscriptionContractRepository");
|
|
2004
2004
|
|
|
2005
|
-
// src/discovery/tokens.ts
|
|
2005
|
+
// src/discovery/discovery.tokens.ts
|
|
2006
2006
|
var IMPLEMENTS_CAPABILITY_KEY = "discovery:implements-capability";
|
|
2007
2007
|
var REQUIRES_CAPABILITY_KEY = "discovery:requires-capability";
|
|
2008
2008
|
var DEFINES_QUOTA_KEY = "discovery:defines-quota";
|
|
2009
2009
|
var ENFORCE_QUOTA_KEY = "discovery:enforce-quota";
|
|
2010
|
-
var DISCOVERY_SNAPSHOT_TOKEN = /* @__PURE__ */ Symbol.for("
|
|
2010
|
+
var DISCOVERY_SNAPSHOT_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/nest/DiscoverySnapshot");
|
|
2011
2011
|
|
|
2012
2012
|
// src/promo/math.ts
|
|
2013
2013
|
function round2(n) {
|
|
@@ -2354,14 +2354,14 @@ function resolveEntitlementPlan(input, config, now) {
|
|
|
2354
2354
|
}
|
|
2355
2355
|
__name(resolveEntitlementPlan, "resolveEntitlementPlan");
|
|
2356
2356
|
|
|
2357
|
-
// src/entitlement/tokens.ts
|
|
2358
|
-
var ENTITLEMENT_SERVICE_TOKEN = /* @__PURE__ */ Symbol.for("
|
|
2359
|
-
var SUBSCRIPTION_REPOSITORY_TOKEN = /* @__PURE__ */ Symbol.for("
|
|
2360
|
-
var PLAN_VERSION_REPOSITORY_TOKEN = /* @__PURE__ */ Symbol.for("
|
|
2361
|
-
var TRANSACTION_RUNNER_TOKEN = /* @__PURE__ */ Symbol.for("
|
|
2362
|
-
var ENTITLEMENT_RESOLUTION_CONFIG_TOKEN = /* @__PURE__ */ Symbol.for("
|
|
2357
|
+
// src/entitlement/entitlement.tokens.ts
|
|
2358
|
+
var ENTITLEMENT_SERVICE_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/nest/EntitlementService");
|
|
2359
|
+
var SUBSCRIPTION_REPOSITORY_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/nest/SubscriptionRepository");
|
|
2360
|
+
var PLAN_VERSION_REPOSITORY_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/nest/PlanVersionRepository");
|
|
2361
|
+
var TRANSACTION_RUNNER_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/nest/TransactionRunner");
|
|
2362
|
+
var ENTITLEMENT_RESOLUTION_CONFIG_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/nest/EntitlementResolutionConfig");
|
|
2363
2363
|
|
|
2364
|
-
// src/entitlement/service.ts
|
|
2364
|
+
// src/entitlement/entitlement.service.ts
|
|
2365
2365
|
function _ts_decorate15(decorators, target, key, desc) {
|
|
2366
2366
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
2367
2367
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
@@ -2423,7 +2423,7 @@ var EntitlementService = class {
|
|
|
2423
2423
|
const sub = await this.subscriptions.findByTenantId(tenantId);
|
|
2424
2424
|
if (!sub) {
|
|
2425
2425
|
throw new import_common17.NotFoundException({
|
|
2426
|
-
code:
|
|
2426
|
+
code: import_core7.BILLING_ERROR_CODES.SUBSCRIPTION_NOT_FOUND,
|
|
2427
2427
|
message: `No subscription for tenant ${tenantId}`,
|
|
2428
2428
|
params: {
|
|
2429
2429
|
tenantId
|
|
@@ -2524,7 +2524,7 @@ var EntitlementService = class {
|
|
|
2524
2524
|
const sub = await this.subscriptions.findByTenantIdLocked(input.tenantId, tx);
|
|
2525
2525
|
if (!sub) {
|
|
2526
2526
|
throw new import_common17.NotFoundException({
|
|
2527
|
-
code:
|
|
2527
|
+
code: import_core7.BILLING_ERROR_CODES.SUBSCRIPTION_NOT_FOUND,
|
|
2528
2528
|
message: `No subscription for tenant ${input.tenantId}`,
|
|
2529
2529
|
params: {
|
|
2530
2530
|
tenantId: input.tenantId
|
|
@@ -2534,7 +2534,7 @@ var EntitlementService = class {
|
|
|
2534
2534
|
const limits = await this.deriveLimits(sub, now, tx);
|
|
2535
2535
|
const max = limits.quotas[input.dimension];
|
|
2536
2536
|
if (max === void 0) {
|
|
2537
|
-
throw new import_common17.InternalServerErrorException(codedError(
|
|
2537
|
+
throw new import_common17.InternalServerErrorException(codedError(import_core7.BILLING_ERROR_CODES.QUOTA_DIMENSION_UNKNOWN, {
|
|
2538
2538
|
dimension: input.dimension,
|
|
2539
2539
|
projectKey: this.catalog.projectKey
|
|
2540
2540
|
}));
|
|
@@ -2560,7 +2560,7 @@ var EntitlementService = class {
|
|
|
2560
2560
|
if (!v) {
|
|
2561
2561
|
const asOfDate = asOf.toISOString().slice(0, 10);
|
|
2562
2562
|
throw new import_common17.NotFoundException({
|
|
2563
|
-
code:
|
|
2563
|
+
code: import_core7.BILLING_ERROR_CODES.NO_ACTIVE_PLAN_VERSION,
|
|
2564
2564
|
message: `No plan version for ${planId} active as of ${asOfDate} \u2014 neither the validFrom window is satisfied nor is a latest-live version available.`,
|
|
2565
2565
|
params: {
|
|
2566
2566
|
planId,
|
|
@@ -2625,8 +2625,8 @@ EntitlementService = _ts_decorate15([
|
|
|
2625
2625
|
], EntitlementService);
|
|
2626
2626
|
|
|
2627
2627
|
// src/billing/upsell.tokens.ts
|
|
2628
|
-
var UPSELL_OFFER_RESOLVER_TOKEN = /* @__PURE__ */ Symbol.for("
|
|
2629
|
-
var UPSELL_OFFER_CURRENCY_TOKEN = /* @__PURE__ */ Symbol.for("
|
|
2628
|
+
var UPSELL_OFFER_RESOLVER_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/nest/UpsellOfferResolver");
|
|
2629
|
+
var UPSELL_OFFER_CURRENCY_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/nest/UpsellOfferCurrency");
|
|
2630
2630
|
|
|
2631
2631
|
// src/billing/feature.guard.ts
|
|
2632
2632
|
function _ts_decorate16(decorators, target, key, desc) {
|
|
@@ -2673,7 +2673,7 @@ var FeatureGuard = class _FeatureGuard {
|
|
|
2673
2673
|
const user = request.user;
|
|
2674
2674
|
if (!user) {
|
|
2675
2675
|
throw new import_common18.ForbiddenException({
|
|
2676
|
-
code:
|
|
2676
|
+
code: import_core9.AUTH_ERROR_CODES.NOT_AUTHENTICATED,
|
|
2677
2677
|
message: "Not authenticated"
|
|
2678
2678
|
});
|
|
2679
2679
|
}
|
|
@@ -2682,7 +2682,7 @@ var FeatureGuard = class _FeatureGuard {
|
|
|
2682
2682
|
const tenantId = this.config?.tenantIdResolver ? this.config.tenantIdResolver(request) : request.tenantId ?? user.tenantId;
|
|
2683
2683
|
if (!tenantId) {
|
|
2684
2684
|
throw new import_common18.ForbiddenException({
|
|
2685
|
-
code:
|
|
2685
|
+
code: import_core9.AUTH_ERROR_CODES.NO_TENANT_ASSIGNED,
|
|
2686
2686
|
message: "No tenant assigned"
|
|
2687
2687
|
});
|
|
2688
2688
|
}
|
|
@@ -2702,7 +2702,7 @@ var FeatureGuard = class _FeatureGuard {
|
|
|
2702
2702
|
* empty, the same degradation a failing resolver produces.
|
|
2703
2703
|
*
|
|
2704
2704
|
* Deliberately 403 + `code` field instead of 402 — rationale in
|
|
2705
|
-
* `@saasicat/
|
|
2705
|
+
* `@saasicat/core` upsell.types.ts (402 is reserved / inconsistently
|
|
2706
2706
|
* supported; SPA interceptors must not treat the 403 as an auth error, the
|
|
2707
2707
|
* distinction runs through `code`).
|
|
2708
2708
|
*
|
|
@@ -2711,7 +2711,7 @@ var FeatureGuard = class _FeatureGuard {
|
|
|
2711
2711
|
*/
|
|
2712
2712
|
async buildNotLicensedException(required, tenantId) {
|
|
2713
2713
|
const body = {
|
|
2714
|
-
code:
|
|
2714
|
+
code: import_core9.FEATURE_NOT_LICENSED,
|
|
2715
2715
|
featureKey: required[0],
|
|
2716
2716
|
featureKeys: required,
|
|
2717
2717
|
offers: this.upsellResolver ? await this.resolveOffersSafe(required, tenantId) : [],
|
|
@@ -2734,7 +2734,7 @@ var FeatureGuard = class _FeatureGuard {
|
|
|
2734
2734
|
};
|
|
2735
2735
|
FeatureGuard = _ts_decorate16([
|
|
2736
2736
|
(0, import_common18.Injectable)(),
|
|
2737
|
-
_ts_param12(0, (0, import_common18.Inject)(
|
|
2737
|
+
_ts_param12(0, (0, import_common18.Inject)(import_core8.Reflector)),
|
|
2738
2738
|
_ts_param12(1, (0, import_common18.Inject)(ENTITLEMENT_SERVICE_TOKEN)),
|
|
2739
2739
|
_ts_param12(2, (0, import_common18.Optional)()),
|
|
2740
2740
|
_ts_param12(2, (0, import_common18.Inject)(FEATURE_GUARD_CONFIG_TOKEN)),
|
|
@@ -2742,7 +2742,7 @@ FeatureGuard = _ts_decorate16([
|
|
|
2742
2742
|
_ts_param12(3, (0, import_common18.Inject)(UPSELL_OFFER_RESOLVER_TOKEN)),
|
|
2743
2743
|
_ts_metadata12("design:type", Function),
|
|
2744
2744
|
_ts_metadata12("design:paramtypes", [
|
|
2745
|
-
typeof
|
|
2745
|
+
typeof import_core8.Reflector === "undefined" ? Object : import_core8.Reflector,
|
|
2746
2746
|
typeof EntitlementService === "undefined" ? Object : EntitlementService,
|
|
2747
2747
|
Object,
|
|
2748
2748
|
Object
|
|
@@ -2751,13 +2751,13 @@ FeatureGuard = _ts_decorate16([
|
|
|
2751
2751
|
|
|
2752
2752
|
// src/billing/catalog-bundle-upsell-resolver.ts
|
|
2753
2753
|
var import_common19 = require("@nestjs/common");
|
|
2754
|
-
var
|
|
2754
|
+
var import_core10 = require("@saasicat/core");
|
|
2755
2755
|
|
|
2756
2756
|
// src/billing/public-catalog.tokens.ts
|
|
2757
|
-
var PUBLIC_CATALOG_PROJECT_KEY_TOKEN = /* @__PURE__ */ Symbol.for("
|
|
2758
|
-
var PUBLIC_CATALOG_BUNDLE_REPOSITORY_TOKEN = /* @__PURE__ */ Symbol.for("
|
|
2759
|
-
var PUBLIC_CATALOG_MARKETING_REPOSITORY_TOKEN = /* @__PURE__ */ Symbol.for("
|
|
2760
|
-
var PUBLIC_CATALOG_CATALOG_ENTRY_REPOSITORY_TOKEN = /* @__PURE__ */ Symbol.for("
|
|
2757
|
+
var PUBLIC_CATALOG_PROJECT_KEY_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/nest/PublicCatalogProjectKey");
|
|
2758
|
+
var PUBLIC_CATALOG_BUNDLE_REPOSITORY_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/nest/PublicCatalogBundleRepository");
|
|
2759
|
+
var PUBLIC_CATALOG_MARKETING_REPOSITORY_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/nest/PublicCatalogMarketingRepository");
|
|
2760
|
+
var PUBLIC_CATALOG_CATALOG_ENTRY_REPOSITORY_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/nest/PublicCatalogCatalogEntryRepository");
|
|
2761
2761
|
|
|
2762
2762
|
// src/billing/catalog-bundle-upsell-resolver.ts
|
|
2763
2763
|
function _ts_decorate17(decorators, target, key, desc) {
|
|
@@ -2821,7 +2821,7 @@ var CatalogBundleUpsellResolver = class {
|
|
|
2821
2821
|
const rows = await this.catalogEntryRepo.listFeatures({
|
|
2822
2822
|
projectKey: this.projectKey
|
|
2823
2823
|
});
|
|
2824
|
-
return (0,
|
|
2824
|
+
return (0, import_core10.collectUnsatisfiedRequires)(featureKeys, (0, import_core10.buildFeatureRequiresIndex)(rows));
|
|
2825
2825
|
}
|
|
2826
2826
|
/** Only published-and-live AND marketed — non-marketed bundles are not an offer. */
|
|
2827
2827
|
async listLiveMarketedBundles() {
|
|
@@ -2879,8 +2879,8 @@ __name(compareRankedOffers, "compareRankedOffers");
|
|
|
2879
2879
|
|
|
2880
2880
|
// src/billing/limit-exceeded.filter.ts
|
|
2881
2881
|
var import_common20 = require("@nestjs/common");
|
|
2882
|
-
var
|
|
2883
|
-
var
|
|
2882
|
+
var import_core11 = require("@nestjs/core");
|
|
2883
|
+
var import_core12 = require("@saasicat/core");
|
|
2884
2884
|
function _ts_decorate18(decorators, target, key, desc) {
|
|
2885
2885
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
2886
2886
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
@@ -2888,7 +2888,7 @@ function _ts_decorate18(decorators, target, key, desc) {
|
|
|
2888
2888
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
2889
2889
|
}
|
|
2890
2890
|
__name(_ts_decorate18, "_ts_decorate");
|
|
2891
|
-
var LimitExceededFilter = class _LimitExceededFilter extends
|
|
2891
|
+
var LimitExceededFilter = class _LimitExceededFilter extends import_core11.BaseExceptionFilter {
|
|
2892
2892
|
static {
|
|
2893
2893
|
__name(this, "LimitExceededFilter");
|
|
2894
2894
|
}
|
|
@@ -2905,10 +2905,10 @@ var LimitExceededFilter = class _LimitExceededFilter extends import_core3.BaseEx
|
|
|
2905
2905
|
response.status(import_common20.HttpStatus.PAYMENT_REQUIRED).send({
|
|
2906
2906
|
statusCode: import_common20.HttpStatus.PAYMENT_REQUIRED,
|
|
2907
2907
|
error: "PaymentRequired",
|
|
2908
|
-
code:
|
|
2908
|
+
code: import_core12.BILLING_ERROR_CODES.LIMIT_EXCEEDED,
|
|
2909
2909
|
// Deprecated: superseded by `code`, kept until consumers have
|
|
2910
2910
|
// migrated. Same value, only under the older field name.
|
|
2911
|
-
reason:
|
|
2911
|
+
reason: import_core12.BILLING_ERROR_CODES.LIMIT_EXCEEDED,
|
|
2912
2912
|
dimension: exception.dimension,
|
|
2913
2913
|
used: exception.used,
|
|
2914
2914
|
max: exception.max,
|
|
@@ -3015,7 +3015,7 @@ function _ts_param14(paramIndex, decorator) {
|
|
|
3015
3015
|
};
|
|
3016
3016
|
}
|
|
3017
3017
|
__name(_ts_param14, "_ts_param");
|
|
3018
|
-
var PLAN_CATALOG_IMPORT_SINK_TOKEN = /* @__PURE__ */ Symbol.for("
|
|
3018
|
+
var PLAN_CATALOG_IMPORT_SINK_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/nest/PlanCatalogImportSink");
|
|
3019
3019
|
var IMPORT_CHANGE_NOTE = "Initial import from saas.yaml";
|
|
3020
3020
|
var PlanCatalogImporterService = class {
|
|
3021
3021
|
static {
|
|
@@ -3216,11 +3216,11 @@ PlanCatalogImporterModule = _ts_decorate21([
|
|
|
3216
3216
|
], PlanCatalogImporterModule);
|
|
3217
3217
|
|
|
3218
3218
|
// src/billing/feature-ui-registry.tokens.ts
|
|
3219
|
-
var
|
|
3219
|
+
var BILLING_FEATURE_UI_REGISTRY_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/nest/BillingFeatureUiRegistry");
|
|
3220
3220
|
|
|
3221
3221
|
// src/billing/public-catalog.controller.ts
|
|
3222
3222
|
var import_common24 = require("@nestjs/common");
|
|
3223
|
-
var
|
|
3223
|
+
var import_core13 = require("@saasicat/core");
|
|
3224
3224
|
function _ts_decorate22(decorators, target, key, desc) {
|
|
3225
3225
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3226
3226
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
@@ -3340,7 +3340,7 @@ var PublicCatalogController = class {
|
|
|
3340
3340
|
const rows = await this.catalogEntryRepo.listFeatures({
|
|
3341
3341
|
projectKey: this.projectKey
|
|
3342
3342
|
});
|
|
3343
|
-
return (0,
|
|
3343
|
+
return (0, import_core13.buildFeatureRequiresIndex)(rows);
|
|
3344
3344
|
} catch {
|
|
3345
3345
|
return /* @__PURE__ */ new Map();
|
|
3346
3346
|
}
|
|
@@ -3380,7 +3380,7 @@ var PublicCatalogController = class {
|
|
|
3380
3380
|
quotas: live.quotas,
|
|
3381
3381
|
monthlyNet: live.monthlyNet,
|
|
3382
3382
|
yearlyNet: live.yearlyNet,
|
|
3383
|
-
requiresFeatures: (0,
|
|
3383
|
+
requiresFeatures: (0, import_core13.collectUnsatisfiedRequires)(features, requiresIndex),
|
|
3384
3384
|
marketing
|
|
3385
3385
|
};
|
|
3386
3386
|
}
|
|
@@ -3417,7 +3417,7 @@ PublicCatalogController = _ts_decorate22([
|
|
|
3417
3417
|
(0, import_common24.Controller)("billing"),
|
|
3418
3418
|
SaaSiCatPublicRoute(),
|
|
3419
3419
|
_ts_param16(0, (0, import_common24.Inject)(PLAN_CATALOG_TOKEN)),
|
|
3420
|
-
_ts_param16(1, (0, import_common24.Inject)(
|
|
3420
|
+
_ts_param16(1, (0, import_common24.Inject)(BILLING_FEATURE_UI_REGISTRY_TOKEN)),
|
|
3421
3421
|
_ts_param16(2, (0, import_common24.Optional)()),
|
|
3422
3422
|
_ts_param16(2, (0, import_common24.Inject)(PUBLIC_CATALOG_PROJECT_KEY_TOKEN)),
|
|
3423
3423
|
_ts_param16(3, (0, import_common24.Optional)()),
|
|
@@ -3454,7 +3454,7 @@ var PublicCatalogModule = class _PublicCatalogModule {
|
|
|
3454
3454
|
const providers = [
|
|
3455
3455
|
...options.extraProviders ?? [],
|
|
3456
3456
|
{
|
|
3457
|
-
provide:
|
|
3457
|
+
provide: BILLING_FEATURE_UI_REGISTRY_TOKEN,
|
|
3458
3458
|
useValue: options.featureUiRegistry
|
|
3459
3459
|
}
|
|
3460
3460
|
];
|
|
@@ -3481,7 +3481,7 @@ var PublicCatalogModule = class _PublicCatalogModule {
|
|
|
3481
3481
|
],
|
|
3482
3482
|
providers,
|
|
3483
3483
|
exports: [
|
|
3484
|
-
|
|
3484
|
+
BILLING_FEATURE_UI_REGISTRY_TOKEN
|
|
3485
3485
|
]
|
|
3486
3486
|
};
|
|
3487
3487
|
}
|
|
@@ -3491,20 +3491,20 @@ PublicCatalogModule = _ts_decorate23([
|
|
|
3491
3491
|
], PublicCatalogModule);
|
|
3492
3492
|
|
|
3493
3493
|
// src/billing/tenant-billing.tokens.ts
|
|
3494
|
-
var TENANT_AUTH_GUARDS_TOKEN = /* @__PURE__ */ Symbol.for("
|
|
3495
|
-
var TENANT_ID_RESOLVER_TOKEN = /* @__PURE__ */ Symbol.for("
|
|
3496
|
-
var USER_ID_RESOLVER_TOKEN = /* @__PURE__ */ Symbol.for("
|
|
3497
|
-
var USER_EMAIL_RESOLVER_TOKEN = /* @__PURE__ */ Symbol.for("
|
|
3498
|
-
var AUDIT_CONTEXT_RESOLVER_TOKEN = /* @__PURE__ */ Symbol.for("
|
|
3499
|
-
var SUBSCRIPTION_USAGE_PORT_TOKEN = /* @__PURE__ */ Symbol.for("
|
|
3500
|
-
var USAGE_SNAPSHOT_PORT_TOKEN = /* @__PURE__ */ Symbol.for("
|
|
3501
|
-
var SUBSCRIPTION_WRITE_PORT_TOKEN = /* @__PURE__ */ Symbol.for("
|
|
3502
|
-
var TRIAL_PROJECTION_PORT_TOKEN = /* @__PURE__ */ Symbol.for("
|
|
3503
|
-
var PENDING_PLAN_QUERY_PORT_TOKEN = /* @__PURE__ */ Symbol.for("
|
|
3494
|
+
var TENANT_AUTH_GUARDS_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/nest/TenantAuthGuards");
|
|
3495
|
+
var TENANT_ID_RESOLVER_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/nest/TenantIdResolver");
|
|
3496
|
+
var USER_ID_RESOLVER_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/nest/UserIdResolver");
|
|
3497
|
+
var USER_EMAIL_RESOLVER_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/nest/UserEmailResolver");
|
|
3498
|
+
var AUDIT_CONTEXT_RESOLVER_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/nest/AuditContextResolver");
|
|
3499
|
+
var SUBSCRIPTION_USAGE_PORT_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/nest/SubscriptionUsagePort");
|
|
3500
|
+
var USAGE_SNAPSHOT_PORT_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/nest/UsageSnapshotPort");
|
|
3501
|
+
var SUBSCRIPTION_WRITE_PORT_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/nest/TenantSubscriptionWritePort");
|
|
3502
|
+
var TRIAL_PROJECTION_PORT_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/nest/TrialProjectionPort");
|
|
3503
|
+
var PENDING_PLAN_QUERY_PORT_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/nest/PendingPlanQueryPort");
|
|
3504
3504
|
|
|
3505
3505
|
// src/billing/composed-tenant-auth.guard.ts
|
|
3506
3506
|
var import_common26 = require("@nestjs/common");
|
|
3507
|
-
var
|
|
3507
|
+
var import_core14 = require("@saasicat/core");
|
|
3508
3508
|
function _ts_decorate24(decorators, target, key, desc) {
|
|
3509
3509
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3510
3510
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
@@ -3533,7 +3533,7 @@ var ComposedTenantAuthGuard = class {
|
|
|
3533
3533
|
async canActivate(context) {
|
|
3534
3534
|
if (!this.guards || this.guards.length === 0) {
|
|
3535
3535
|
throw new import_common26.ForbiddenException({
|
|
3536
|
-
code:
|
|
3536
|
+
code: import_core14.AUTH_ERROR_CODES.AUTH_GUARDS_NOT_CONFIGURED,
|
|
3537
3537
|
message: "TenantBillingModule.forRoot.authGuards is not configured."
|
|
3538
3538
|
});
|
|
3539
3539
|
}
|
|
@@ -3556,7 +3556,7 @@ ComposedTenantAuthGuard = _ts_decorate24([
|
|
|
3556
3556
|
|
|
3557
3557
|
// src/billing/tenant-admin.guard.ts
|
|
3558
3558
|
var import_common27 = require("@nestjs/common");
|
|
3559
|
-
var
|
|
3559
|
+
var import_core15 = require("@saasicat/core");
|
|
3560
3560
|
function _ts_decorate25(decorators, target, key, desc) {
|
|
3561
3561
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3562
3562
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
@@ -3576,14 +3576,14 @@ var TenantAdminGuard = class {
|
|
|
3576
3576
|
const request = context.switchToHttp().getRequest();
|
|
3577
3577
|
if (!request.user) {
|
|
3578
3578
|
throw new import_common27.ForbiddenException({
|
|
3579
|
-
code:
|
|
3579
|
+
code: import_core15.AUTH_ERROR_CODES.NOT_AUTHENTICATED,
|
|
3580
3580
|
message: "Not authenticated"
|
|
3581
3581
|
});
|
|
3582
3582
|
}
|
|
3583
3583
|
const role = request.user.platformRole ?? request.user.role;
|
|
3584
3584
|
if (!role || !ADMIN_ROLES.has(role)) {
|
|
3585
3585
|
throw new import_common27.ForbiddenException({
|
|
3586
|
-
code:
|
|
3586
|
+
code: import_core15.AUTH_ERROR_CODES.TENANT_ADMIN_REQUIRED,
|
|
3587
3587
|
message: "This action requires the TENANT_ADMIN role."
|
|
3588
3588
|
});
|
|
3589
3589
|
}
|
|
@@ -3595,8 +3595,8 @@ TenantAdminGuard = _ts_decorate25([
|
|
|
3595
3595
|
], TenantAdminGuard);
|
|
3596
3596
|
|
|
3597
3597
|
// src/billing/self-service-policy.ts
|
|
3598
|
-
var SELF_SERVICE_BLOCKED_PLANS_TOKEN = /* @__PURE__ */ Symbol.for("
|
|
3599
|
-
var SELF_SERVICE_BLOCKED_BUNDLES_TOKEN = /* @__PURE__ */ Symbol.for("
|
|
3598
|
+
var SELF_SERVICE_BLOCKED_PLANS_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/nest/SelfServiceBlockedPlans");
|
|
3599
|
+
var SELF_SERVICE_BLOCKED_BUNDLES_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/nest/SelfServiceBlockedBundles");
|
|
3600
3600
|
|
|
3601
3601
|
// src/billing/proration.ts
|
|
3602
3602
|
var DAY_MS2 = 864e5;
|
|
@@ -3623,7 +3623,7 @@ __name(round22, "round2");
|
|
|
3623
3623
|
|
|
3624
3624
|
// src/billing/plan-change-preview.service.ts
|
|
3625
3625
|
var import_common28 = require("@nestjs/common");
|
|
3626
|
-
var
|
|
3626
|
+
var import_core16 = require("@saasicat/core");
|
|
3627
3627
|
function _ts_decorate26(decorators, target, key, desc) {
|
|
3628
3628
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3629
3629
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
@@ -3663,7 +3663,7 @@ var PlanChangePreviewService = class {
|
|
|
3663
3663
|
const sub = await this.subscriptions.findForTenant(tenantId);
|
|
3664
3664
|
if (!sub) {
|
|
3665
3665
|
throw new import_common28.NotFoundException({
|
|
3666
|
-
code:
|
|
3666
|
+
code: import_core16.BILLING_ERROR_CODES.SUBSCRIPTION_NOT_FOUND,
|
|
3667
3667
|
message: `No subscription for tenant ${tenantId}`,
|
|
3668
3668
|
params: {
|
|
3669
3669
|
tenantId
|
|
@@ -3673,7 +3673,7 @@ var PlanChangePreviewService = class {
|
|
|
3673
3673
|
const targetPlanDef = findPlan(this.catalog, targetPlan);
|
|
3674
3674
|
if (!targetPlanDef) {
|
|
3675
3675
|
throw new import_common28.NotFoundException({
|
|
3676
|
-
code:
|
|
3676
|
+
code: import_core16.BILLING_ERROR_CODES.PLAN_NOT_IN_CATALOG,
|
|
3677
3677
|
message: `Plan "${targetPlan}" is not in the catalog (${this.catalog.projectKey})`,
|
|
3678
3678
|
params: {
|
|
3679
3679
|
planKey: targetPlan,
|
|
@@ -3873,9 +3873,9 @@ __name(isFloatQuota, "isFloatQuota");
|
|
|
3873
3873
|
var import_common29 = require("@nestjs/common");
|
|
3874
3874
|
|
|
3875
3875
|
// src/billing/contract-freeze.tokens.ts
|
|
3876
|
-
var CONTRACT_FREEZE_PORT_TOKEN = /* @__PURE__ */ Symbol.for("
|
|
3877
|
-
var CONTRACT_FREEZE_SOURCE_PORT_TOKEN = /* @__PURE__ */ Symbol.for("
|
|
3878
|
-
var CONTRACT_FREEZE_PROJECT_KEY_TOKEN = /* @__PURE__ */ Symbol.for("
|
|
3876
|
+
var CONTRACT_FREEZE_PORT_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/nest/ContractFreezePort");
|
|
3877
|
+
var CONTRACT_FREEZE_SOURCE_PORT_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/nest/ContractFreezeSourcePort");
|
|
3878
|
+
var CONTRACT_FREEZE_PROJECT_KEY_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/nest/ContractFreezeProjectKey");
|
|
3879
3879
|
|
|
3880
3880
|
// src/billing/pending-plan-materialization.service.ts
|
|
3881
3881
|
function _ts_decorate27(decorators, target, key, desc) {
|
|
@@ -4051,7 +4051,7 @@ function cloneJsonValue(value) {
|
|
|
4051
4051
|
__name(cloneJsonValue, "cloneJsonValue");
|
|
4052
4052
|
|
|
4053
4053
|
// src/subscription-contract/subscription-contract.service.ts
|
|
4054
|
-
var
|
|
4054
|
+
var import_core17 = require("@saasicat/core");
|
|
4055
4055
|
function _ts_decorate28(decorators, target, key, desc) {
|
|
4056
4056
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4057
4057
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
@@ -4084,7 +4084,7 @@ var SubscriptionContractService = class {
|
|
|
4084
4084
|
const row = await this.repo.findById(contractId);
|
|
4085
4085
|
if (!row) {
|
|
4086
4086
|
throw new import_common30.NotFoundException({
|
|
4087
|
-
code:
|
|
4087
|
+
code: import_core17.CONTRACT_ERROR_CODES.SUBSCRIPTION_CONTRACT_NOT_FOUND,
|
|
4088
4088
|
message: `SubscriptionContract '${contractId}' not found`,
|
|
4089
4089
|
params: {
|
|
4090
4090
|
contractId
|
|
@@ -4100,7 +4100,7 @@ var SubscriptionContractService = class {
|
|
|
4100
4100
|
const contract = await this.repo.findActiveByTenantId(tenantId, asOf);
|
|
4101
4101
|
if (!contract) {
|
|
4102
4102
|
throw new import_common30.NotFoundException({
|
|
4103
|
-
code:
|
|
4103
|
+
code: import_core17.CONTRACT_ERROR_CODES.NO_ACTIVE_SUBSCRIPTION_CONTRACT,
|
|
4104
4104
|
message: `No active subscription contract for tenant ${tenantId}`,
|
|
4105
4105
|
params: {
|
|
4106
4106
|
tenantId,
|
|
@@ -4140,7 +4140,7 @@ var SubscriptionContractService = class {
|
|
|
4140
4140
|
createDataFromOffer(offer, options) {
|
|
4141
4141
|
if (offer.status !== "consumed") {
|
|
4142
4142
|
throw new import_common30.ConflictException({
|
|
4143
|
-
code:
|
|
4143
|
+
code: import_core17.CONTRACT_ERROR_CODES.CHECKOUT_OFFER_NOT_CONSUMED,
|
|
4144
4144
|
message: `CheckoutOffer '${offer.id}' must be consumed before the contract is created`,
|
|
4145
4145
|
params: {
|
|
4146
4146
|
offerId: offer.id,
|
|
@@ -4179,7 +4179,7 @@ var SubscriptionContractService = class {
|
|
|
4179
4179
|
const source = offer.lineItems ?? [];
|
|
4180
4180
|
if (source.length === 0) {
|
|
4181
4181
|
throw new import_common30.UnprocessableEntityException({
|
|
4182
|
-
code:
|
|
4182
|
+
code: import_core17.CONTRACT_ERROR_CODES.CHECKOUT_OFFER_LINE_ITEMS_REQUIRED,
|
|
4183
4183
|
message: "A checkout offer can yield only one contract, and only once its line items are frozen."
|
|
4184
4184
|
});
|
|
4185
4185
|
}
|
|
@@ -4218,7 +4218,7 @@ var SubscriptionContractService = class {
|
|
|
4218
4218
|
const date = value instanceof Date ? new Date(value) : new Date(value);
|
|
4219
4219
|
if (Number.isNaN(date.getTime())) {
|
|
4220
4220
|
throw new import_common30.UnprocessableEntityException({
|
|
4221
|
-
code:
|
|
4221
|
+
code: import_core17.CONTRACT_ERROR_CODES.SUBSCRIPTION_CONTRACT_INVALID_DATE,
|
|
4222
4222
|
message: `${field} must be a valid date.`,
|
|
4223
4223
|
params: {
|
|
4224
4224
|
field
|
|
@@ -4242,20 +4242,20 @@ var SubscriptionContractService = class {
|
|
|
4242
4242
|
assertCreateData(data) {
|
|
4243
4243
|
if (data.lineItems.length === 0) {
|
|
4244
4244
|
throw new import_common30.UnprocessableEntityException({
|
|
4245
|
-
code:
|
|
4245
|
+
code: import_core17.CONTRACT_ERROR_CODES.SUBSCRIPTION_CONTRACT_LINE_ITEMS_REQUIRED,
|
|
4246
4246
|
message: "A subscription contract requires at least one line item."
|
|
4247
4247
|
});
|
|
4248
4248
|
}
|
|
4249
4249
|
if (data.effectiveUntil && data.effectiveUntil <= data.effectiveFrom) {
|
|
4250
4250
|
throw new import_common30.UnprocessableEntityException({
|
|
4251
|
-
code:
|
|
4251
|
+
code: import_core17.CONTRACT_ERROR_CODES.SUBSCRIPTION_CONTRACT_INVALID_WINDOW,
|
|
4252
4252
|
message: "effectiveUntil must be after effectiveFrom."
|
|
4253
4253
|
});
|
|
4254
4254
|
}
|
|
4255
4255
|
const planLineItems = data.lineItems.filter((item) => item.kind === "plan");
|
|
4256
4256
|
if (planLineItems.length !== 1) {
|
|
4257
4257
|
throw new import_common30.UnprocessableEntityException({
|
|
4258
|
-
code:
|
|
4258
|
+
code: import_core17.CONTRACT_ERROR_CODES.SUBSCRIPTION_CONTRACT_PLAN_LINE_ITEM_REQUIRED,
|
|
4259
4259
|
message: "A subscription contract requires exactly one plan base item."
|
|
4260
4260
|
});
|
|
4261
4261
|
}
|
|
@@ -4263,7 +4263,7 @@ var SubscriptionContractService = class {
|
|
|
4263
4263
|
assertTerminable(existing, data) {
|
|
4264
4264
|
if (existing.status === "terminated" || existing.status === "superseded") {
|
|
4265
4265
|
throw new import_common30.ConflictException({
|
|
4266
|
-
code:
|
|
4266
|
+
code: import_core17.CONTRACT_ERROR_CODES.SUBSCRIPTION_CONTRACT_ALREADY_CLOSED,
|
|
4267
4267
|
message: `SubscriptionContract '${existing.id}' is already closed`,
|
|
4268
4268
|
params: {
|
|
4269
4269
|
contractId: existing.id,
|
|
@@ -4273,7 +4273,7 @@ var SubscriptionContractService = class {
|
|
|
4273
4273
|
}
|
|
4274
4274
|
if (data.effectiveUntil <= existing.effectiveFrom) {
|
|
4275
4275
|
throw new import_common30.UnprocessableEntityException({
|
|
4276
|
-
code:
|
|
4276
|
+
code: import_core17.CONTRACT_ERROR_CODES.SUBSCRIPTION_CONTRACT_TERMINATION_BEFORE_START,
|
|
4277
4277
|
message: "effectiveUntil must be after the effectiveFrom of the contract."
|
|
4278
4278
|
});
|
|
4279
4279
|
}
|
|
@@ -4634,21 +4634,21 @@ _ts_decorate31([
|
|
|
4634
4634
|
|
|
4635
4635
|
// src/billing/tenant-billing.controller.ts
|
|
4636
4636
|
var import_common34 = require("@nestjs/common");
|
|
4637
|
-
var
|
|
4637
|
+
var import_core20 = require("@saasicat/core");
|
|
4638
4638
|
|
|
4639
|
-
// src/promo/service.ts
|
|
4639
|
+
// src/promo/promo.service.ts
|
|
4640
4640
|
var import_common32 = require("@nestjs/common");
|
|
4641
|
-
var
|
|
4641
|
+
var import_core18 = require("@saasicat/core");
|
|
4642
4642
|
|
|
4643
|
-
// src/promo/tokens.ts
|
|
4644
|
-
var PROMO_CODE_REPOSITORY_TOKEN = /* @__PURE__ */ Symbol.for("
|
|
4645
|
-
var PROMO_CODE_REDEMPTION_REPOSITORY_TOKEN = /* @__PURE__ */ Symbol.for("
|
|
4646
|
-
var PROMO_CODE_VALIDATION_LOG_REPOSITORY_TOKEN = /* @__PURE__ */ Symbol.for("
|
|
4647
|
-
var PROMO_FIRST_TIME_CUSTOMER_CHECK_TOKEN = /* @__PURE__ */ Symbol.for("
|
|
4648
|
-
var PROMO_SUBSCRIPTION_LOOKUP_TOKEN = /* @__PURE__ */ Symbol.for("
|
|
4649
|
-
var PROMO_REVENUE_DEDUCTION_AGGREGATOR_TOKEN = /* @__PURE__ */ Symbol.for("
|
|
4650
|
-
var PROMO_TRANSACTION_RUNNER_TOKEN = /* @__PURE__ */ Symbol.for("
|
|
4651
|
-
var PROMO_SERVICE_CONFIG_TOKEN = /* @__PURE__ */ Symbol.for("
|
|
4643
|
+
// src/promo/promo.tokens.ts
|
|
4644
|
+
var PROMO_CODE_REPOSITORY_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/nest/PromoCodeRepository");
|
|
4645
|
+
var PROMO_CODE_REDEMPTION_REPOSITORY_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/nest/PromoCodeRedemptionRepository");
|
|
4646
|
+
var PROMO_CODE_VALIDATION_LOG_REPOSITORY_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/nest/PromoCodeValidationLogRepository");
|
|
4647
|
+
var PROMO_FIRST_TIME_CUSTOMER_CHECK_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/nest/PromoFirstTimeCustomerCheck");
|
|
4648
|
+
var PROMO_SUBSCRIPTION_LOOKUP_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/nest/PromoSubscriptionLookup");
|
|
4649
|
+
var PROMO_REVENUE_DEDUCTION_AGGREGATOR_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/nest/PromoRevenueDeductionAggregator");
|
|
4650
|
+
var PROMO_TRANSACTION_RUNNER_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/nest/PromoTransactionRunner");
|
|
4651
|
+
var PROMO_SERVICE_CONFIG_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/nest/PromoServiceConfig");
|
|
4652
4652
|
|
|
4653
4653
|
// src/promo/calculator.ts
|
|
4654
4654
|
function computeDiscountGross(plan, code) {
|
|
@@ -4724,7 +4724,7 @@ function buildLabel(code, cycle, options = {}) {
|
|
|
4724
4724
|
}
|
|
4725
4725
|
__name(buildLabel, "buildLabel");
|
|
4726
4726
|
|
|
4727
|
-
// src/promo/service.ts
|
|
4727
|
+
// src/promo/promo.service.ts
|
|
4728
4728
|
function _ts_decorate32(decorators, target, key, desc) {
|
|
4729
4729
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
4730
4730
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
@@ -4751,7 +4751,7 @@ var DURATION_MIN = 1;
|
|
|
4751
4751
|
var DURATION_MAX = 24;
|
|
4752
4752
|
function notRedeemable(reason) {
|
|
4753
4753
|
return new import_common32.BadRequestException({
|
|
4754
|
-
code:
|
|
4754
|
+
code: import_core18.PROMO_ERROR_CODES.PROMO_CODE_NOT_REDEEMABLE,
|
|
4755
4755
|
message: `Code cannot be redeemed: ${reason}`,
|
|
4756
4756
|
params: {
|
|
4757
4757
|
reason
|
|
@@ -4788,7 +4788,7 @@ var PromoCodesService = class {
|
|
|
4788
4788
|
const code = input.code.trim().toUpperCase();
|
|
4789
4789
|
if (!CODE_PATTERN.test(code)) {
|
|
4790
4790
|
throw new import_common32.BadRequestException({
|
|
4791
|
-
code:
|
|
4791
|
+
code: import_core18.PROMO_ERROR_CODES.PROMO_CODE_FORMAT_INVALID,
|
|
4792
4792
|
message: 'The code may only contain upper-case letters, digits, "-" and "_" (4\u201332 characters).',
|
|
4793
4793
|
params: {
|
|
4794
4794
|
promoCode: code,
|
|
@@ -4800,7 +4800,7 @@ var PromoCodesService = class {
|
|
|
4800
4800
|
if (input.valueType === "PERCENT") {
|
|
4801
4801
|
if (!(input.value > PERCENT_MIN_EXCLUSIVE && input.value <= PERCENT_MAX)) {
|
|
4802
4802
|
throw new import_common32.BadRequestException({
|
|
4803
|
-
code:
|
|
4803
|
+
code: import_core18.PROMO_ERROR_CODES.PROMO_PERCENT_OUT_OF_RANGE,
|
|
4804
4804
|
message: "The percentage must be between 0 and 100.",
|
|
4805
4805
|
params: {
|
|
4806
4806
|
value: input.value,
|
|
@@ -4811,7 +4811,7 @@ var PromoCodesService = class {
|
|
|
4811
4811
|
}
|
|
4812
4812
|
} else if (!(input.value > 0)) {
|
|
4813
4813
|
throw new import_common32.BadRequestException({
|
|
4814
|
-
code:
|
|
4814
|
+
code: import_core18.PROMO_ERROR_CODES.PROMO_AMOUNT_NOT_POSITIVE,
|
|
4815
4815
|
message: "The amount must be positive.",
|
|
4816
4816
|
params: {
|
|
4817
4817
|
value: input.value,
|
|
@@ -4822,7 +4822,7 @@ var PromoCodesService = class {
|
|
|
4822
4822
|
if (input.durationType === "ONCE") {
|
|
4823
4823
|
if (input.durationValue != null) {
|
|
4824
4824
|
throw new import_common32.BadRequestException({
|
|
4825
|
-
code:
|
|
4825
|
+
code: import_core18.PROMO_ERROR_CODES.PROMO_ONE_OFF_WITH_DURATION,
|
|
4826
4826
|
message: "A one-off discount must not set a duration.",
|
|
4827
4827
|
params: {
|
|
4828
4828
|
durationValue: input.durationValue
|
|
@@ -4833,7 +4833,7 @@ var PromoCodesService = class {
|
|
|
4833
4833
|
const v = input.durationValue;
|
|
4834
4834
|
if (v == null || v < DURATION_MIN || v > DURATION_MAX) {
|
|
4835
4835
|
throw new import_common32.BadRequestException({
|
|
4836
|
-
code:
|
|
4836
|
+
code: import_core18.PROMO_ERROR_CODES.PROMO_DURATION_INVALID,
|
|
4837
4837
|
message: "Invalid duration (at most 24 months or billing periods).",
|
|
4838
4838
|
params: {
|
|
4839
4839
|
durationValue: v ?? null,
|
|
@@ -4845,7 +4845,7 @@ var PromoCodesService = class {
|
|
|
4845
4845
|
}
|
|
4846
4846
|
if (input.validFrom && input.validUntil && input.validFrom >= input.validUntil) {
|
|
4847
4847
|
throw new import_common32.BadRequestException({
|
|
4848
|
-
code:
|
|
4848
|
+
code: import_core18.PROMO_ERROR_CODES.PROMO_VALIDITY_WINDOW_INVALID,
|
|
4849
4849
|
message: "Invalid validity window.",
|
|
4850
4850
|
params: {
|
|
4851
4851
|
validFrom: input.validFrom.toISOString(),
|
|
@@ -4858,7 +4858,7 @@ var PromoCodesService = class {
|
|
|
4858
4858
|
for (const p of plans) {
|
|
4859
4859
|
if (blocked.includes(p)) {
|
|
4860
4860
|
throw new import_common32.BadRequestException({
|
|
4861
|
-
code:
|
|
4861
|
+
code: import_core18.PROMO_ERROR_CODES.PROMO_PLAN_NOT_DISCOUNTABLE,
|
|
4862
4862
|
message: `${p}-Plan cannot be discounted.`,
|
|
4863
4863
|
params: {
|
|
4864
4864
|
plan: p
|
|
@@ -4868,7 +4868,7 @@ var PromoCodesService = class {
|
|
|
4868
4868
|
}
|
|
4869
4869
|
if (input.minimumPlanAmountGross != null && input.minimumPlanAmountGross <= 0) {
|
|
4870
4870
|
throw new import_common32.BadRequestException({
|
|
4871
|
-
code:
|
|
4871
|
+
code: import_core18.PROMO_ERROR_CODES.PROMO_MIN_AMOUNT_NOT_POSITIVE,
|
|
4872
4872
|
message: "The minimum plan gross amount must be positive.",
|
|
4873
4873
|
params: {
|
|
4874
4874
|
value: input.minimumPlanAmountGross,
|
|
@@ -4880,7 +4880,7 @@ var PromoCodesService = class {
|
|
|
4880
4880
|
const lowestApplicableGross = this.lowestApplicablePlanGross(plans);
|
|
4881
4881
|
if (lowestApplicableGross != null && input.value >= lowestApplicableGross) {
|
|
4882
4882
|
throw new import_common32.BadRequestException({
|
|
4883
|
-
code:
|
|
4883
|
+
code: import_core18.PROMO_ERROR_CODES.PROMO_WOULD_PRODUCE_ZERO_INVOICE,
|
|
4884
4884
|
message: "For absolute amounts the discount must stay below the lowest applicable plan price, or allowZeroInvoice must be enabled.",
|
|
4885
4885
|
params: {
|
|
4886
4886
|
value: input.value,
|
|
@@ -4892,7 +4892,7 @@ var PromoCodesService = class {
|
|
|
4892
4892
|
const exists = await this.promoRepo.findByCode(code);
|
|
4893
4893
|
if (exists) {
|
|
4894
4894
|
throw new import_common32.BadRequestException({
|
|
4895
|
-
code:
|
|
4895
|
+
code: import_core18.PROMO_ERROR_CODES.PROMO_CODE_ALREADY_EXISTS,
|
|
4896
4896
|
message: "The code already exists.",
|
|
4897
4897
|
params: {
|
|
4898
4898
|
promoCode: code
|
|
@@ -4908,7 +4908,7 @@ var PromoCodesService = class {
|
|
|
4908
4908
|
const existing = await this.promoRepo.findById(id);
|
|
4909
4909
|
if (!existing) {
|
|
4910
4910
|
throw new import_common32.NotFoundException({
|
|
4911
|
-
code:
|
|
4911
|
+
code: import_core18.PROMO_ERROR_CODES.PROMO_CODE_NOT_FOUND,
|
|
4912
4912
|
message: "Code not found",
|
|
4913
4913
|
params: {
|
|
4914
4914
|
promoCodeId: id,
|
|
@@ -4919,7 +4919,7 @@ var PromoCodesService = class {
|
|
|
4919
4919
|
if (input.maxRedemptions != null && existing.maxRedemptions != null) {
|
|
4920
4920
|
if (input.maxRedemptions < existing.maxRedemptions) {
|
|
4921
4921
|
throw new import_common32.BadRequestException({
|
|
4922
|
-
code:
|
|
4922
|
+
code: import_core18.PROMO_ERROR_CODES.PROMO_MAX_REDEMPTIONS_LOWERED,
|
|
4923
4923
|
message: "maxRedemptions cannot be lowered.",
|
|
4924
4924
|
params: {
|
|
4925
4925
|
current: existing.maxRedemptions,
|
|
@@ -4934,7 +4934,7 @@ var PromoCodesService = class {
|
|
|
4934
4934
|
const redemptions = await this.redemptionRepo.countByPromoCode(id);
|
|
4935
4935
|
if (redemptions > 0) {
|
|
4936
4936
|
throw new import_common32.BadRequestException({
|
|
4937
|
-
code:
|
|
4937
|
+
code: import_core18.PROMO_ERROR_CODES.PROMO_CODE_HAS_REDEMPTIONS,
|
|
4938
4938
|
message: "The code already has redemptions \u2014 it cannot be soft-deleted. Pause it instead.",
|
|
4939
4939
|
params: {
|
|
4940
4940
|
promoCodeId: id,
|
|
@@ -4953,7 +4953,7 @@ var PromoCodesService = class {
|
|
|
4953
4953
|
const code = await this.promoRepo.findById(id);
|
|
4954
4954
|
if (!code || code.deletedAt) {
|
|
4955
4955
|
throw new import_common32.NotFoundException({
|
|
4956
|
-
code:
|
|
4956
|
+
code: import_core18.PROMO_ERROR_CODES.PROMO_CODE_NOT_FOUND,
|
|
4957
4957
|
message: "Code not found",
|
|
4958
4958
|
params: {
|
|
4959
4959
|
promoCodeId: id,
|
|
@@ -5089,7 +5089,7 @@ var PromoCodesService = class {
|
|
|
5089
5089
|
const promo = await this.promoRepo.findByCode(code, tx);
|
|
5090
5090
|
if (!promo || promo.deletedAt) {
|
|
5091
5091
|
throw new import_common32.BadRequestException({
|
|
5092
|
-
code:
|
|
5092
|
+
code: import_core18.PROMO_ERROR_CODES.PROMO_CODE_NOT_FOUND,
|
|
5093
5093
|
// The lookup runs on the code string, so there is no id to report.
|
|
5094
5094
|
message: "Code not found",
|
|
5095
5095
|
params: {
|
|
@@ -5101,7 +5101,7 @@ var PromoCodesService = class {
|
|
|
5101
5101
|
const sub = await this.subscriptionLookup.findById(input.subscriptionId, tx);
|
|
5102
5102
|
if (!sub) {
|
|
5103
5103
|
throw new import_common32.NotFoundException({
|
|
5104
|
-
code:
|
|
5104
|
+
code: import_core18.BILLING_ERROR_CODES.SUBSCRIPTION_NOT_FOUND,
|
|
5105
5105
|
message: "Subscription not found",
|
|
5106
5106
|
params: {
|
|
5107
5107
|
tenantId: input.tenantId
|
|
@@ -5110,7 +5110,7 @@ var PromoCodesService = class {
|
|
|
5110
5110
|
}
|
|
5111
5111
|
if (sub.tenantId !== input.tenantId) {
|
|
5112
5112
|
throw new import_common32.BadRequestException({
|
|
5113
|
-
code:
|
|
5113
|
+
code: import_core18.BILLING_ERROR_CODES.SUBSCRIPTION_TENANT_MISMATCH,
|
|
5114
5114
|
message: "Subscription does not belong to the tenant",
|
|
5115
5115
|
params: {
|
|
5116
5116
|
subscriptionId: sub.id,
|
|
@@ -5243,7 +5243,7 @@ PromoCodesService = _ts_decorate32([
|
|
|
5243
5243
|
|
|
5244
5244
|
// src/billing/subscription-bundles.service.ts
|
|
5245
5245
|
var import_common33 = require("@nestjs/common");
|
|
5246
|
-
var
|
|
5246
|
+
var import_core19 = require("@saasicat/core");
|
|
5247
5247
|
function _ts_decorate33(decorators, target, key, desc) {
|
|
5248
5248
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
5249
5249
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
@@ -5292,7 +5292,7 @@ var SubscriptionBundlesService = class {
|
|
|
5292
5292
|
const bundleVersion = await this.bundles.findVersionById(input.bundleVersionId);
|
|
5293
5293
|
if (!bundleVersion) {
|
|
5294
5294
|
throw new import_common33.NotFoundException({
|
|
5295
|
-
code:
|
|
5295
|
+
code: import_core19.CATALOG_ERROR_CODES.BUNDLE_VERSION_NOT_FOUND,
|
|
5296
5296
|
message: `BundleVersion '${input.bundleVersionId}' not found`,
|
|
5297
5297
|
params: {
|
|
5298
5298
|
bundleVersionId: input.bundleVersionId
|
|
@@ -5301,7 +5301,7 @@ var SubscriptionBundlesService = class {
|
|
|
5301
5301
|
}
|
|
5302
5302
|
if (bundleVersion.publishedAt === null) {
|
|
5303
5303
|
throw new import_common33.UnprocessableEntityException({
|
|
5304
|
-
code:
|
|
5304
|
+
code: import_core19.CATALOG_ERROR_CODES.BUNDLE_VERSION_NOT_PUBLISHED,
|
|
5305
5305
|
message: `BundleVersion '${input.bundleVersionId}' is not published and cannot be booked.`,
|
|
5306
5306
|
params: {
|
|
5307
5307
|
bundleVersionId: input.bundleVersionId
|
|
@@ -5310,7 +5310,7 @@ var SubscriptionBundlesService = class {
|
|
|
5310
5310
|
}
|
|
5311
5311
|
if (bundleVersion.supersededAt !== null) {
|
|
5312
5312
|
throw new import_common33.UnprocessableEntityException({
|
|
5313
|
-
code:
|
|
5313
|
+
code: import_core19.CATALOG_ERROR_CODES.BUNDLE_VERSION_SUPERSEDED,
|
|
5314
5314
|
message: `BundleVersion '${input.bundleVersionId}' has been superseded by a newer version.`,
|
|
5315
5315
|
params: {
|
|
5316
5316
|
bundleVersionId: input.bundleVersionId
|
|
@@ -5319,7 +5319,7 @@ var SubscriptionBundlesService = class {
|
|
|
5319
5319
|
}
|
|
5320
5320
|
if (this.blockedBundles?.bundleKeys?.includes(bundleVersion.bundleKey)) {
|
|
5321
5321
|
throw new import_common33.UnprocessableEntityException({
|
|
5322
|
-
code:
|
|
5322
|
+
code: import_core19.BILLING_ERROR_CODES.BUNDLE_NOT_SELF_SERVICE,
|
|
5323
5323
|
message: `Bundle '${bundleVersion.bundleKey}' is only activated via a special contract. Please contact the contract manager.`,
|
|
5324
5324
|
params: {
|
|
5325
5325
|
bundleKey: bundleVersion.bundleKey
|
|
@@ -5329,7 +5329,7 @@ var SubscriptionBundlesService = class {
|
|
|
5329
5329
|
const planIds = bundleVersion.compatibility?.planIds ?? [];
|
|
5330
5330
|
if (planIds.length > 0 && !planIds.includes(input.currentPlanKey)) {
|
|
5331
5331
|
throw new import_common33.UnprocessableEntityException({
|
|
5332
|
-
code:
|
|
5332
|
+
code: import_core19.BILLING_ERROR_CODES.BUNDLE_INCOMPATIBLE_WITH_PLAN,
|
|
5333
5333
|
message: `BundleVersion '${input.bundleVersionId}' is not compatible with plan '${input.currentPlanKey}'. Allowed: [${planIds.join(", ")}].`,
|
|
5334
5334
|
params: {
|
|
5335
5335
|
bundleVersionId: input.bundleVersionId,
|
|
@@ -5341,7 +5341,7 @@ var SubscriptionBundlesService = class {
|
|
|
5341
5341
|
const active = await this.repo.listActiveBySubscription(input.subscriptionId);
|
|
5342
5342
|
if (active.some((b) => b.bundleVersionId === input.bundleVersionId)) {
|
|
5343
5343
|
throw new import_common33.UnprocessableEntityException({
|
|
5344
|
-
code:
|
|
5344
|
+
code: import_core19.BILLING_ERROR_CODES.BUNDLE_ALREADY_SUBSCRIBED,
|
|
5345
5345
|
message: `Subscription '${input.subscriptionId}' has already actively booked this bundle.`,
|
|
5346
5346
|
params: {
|
|
5347
5347
|
subscriptionId: input.subscriptionId
|
|
@@ -5362,7 +5362,7 @@ var SubscriptionBundlesService = class {
|
|
|
5362
5362
|
const existing = await this.repo.findById(input.subscriptionBundleId);
|
|
5363
5363
|
if (!existing) {
|
|
5364
5364
|
throw new import_common33.NotFoundException({
|
|
5365
|
-
code:
|
|
5365
|
+
code: import_core19.BILLING_ERROR_CODES.SUBSCRIPTION_BUNDLE_NOT_FOUND,
|
|
5366
5366
|
message: `SubscriptionBundle '${input.subscriptionBundleId}' not found`,
|
|
5367
5367
|
params: {
|
|
5368
5368
|
subscriptionBundleId: input.subscriptionBundleId
|
|
@@ -5371,7 +5371,7 @@ var SubscriptionBundlesService = class {
|
|
|
5371
5371
|
}
|
|
5372
5372
|
if (existing.canceledAt !== null) {
|
|
5373
5373
|
throw new import_common33.UnprocessableEntityException({
|
|
5374
|
-
code:
|
|
5374
|
+
code: import_core19.BILLING_ERROR_CODES.SUBSCRIPTION_BUNDLE_ALREADY_CANCELLED,
|
|
5375
5375
|
message: `SubscriptionBundle '${input.subscriptionBundleId}' is already cancelled.`,
|
|
5376
5376
|
params: {
|
|
5377
5377
|
subscriptionBundleId: input.subscriptionBundleId
|
|
@@ -5397,7 +5397,7 @@ var SubscriptionBundlesService = class {
|
|
|
5397
5397
|
const existing = await this.repo.findById(subscriptionBundleId);
|
|
5398
5398
|
if (!existing) {
|
|
5399
5399
|
throw new import_common33.NotFoundException({
|
|
5400
|
-
code:
|
|
5400
|
+
code: import_core19.BILLING_ERROR_CODES.SUBSCRIPTION_BUNDLE_NOT_FOUND,
|
|
5401
5401
|
message: `SubscriptionBundle '${subscriptionBundleId}' not found`,
|
|
5402
5402
|
params: {
|
|
5403
5403
|
subscriptionBundleId
|
|
@@ -5406,7 +5406,7 @@ var SubscriptionBundlesService = class {
|
|
|
5406
5406
|
}
|
|
5407
5407
|
if (existing.canceledAt === null) {
|
|
5408
5408
|
throw new import_common33.UnprocessableEntityException({
|
|
5409
|
-
code:
|
|
5409
|
+
code: import_core19.BILLING_ERROR_CODES.SUBSCRIPTION_BUNDLE_NOT_CANCELLED,
|
|
5410
5410
|
message: `SubscriptionBundle '${subscriptionBundleId}' is not cancelled.`,
|
|
5411
5411
|
params: {
|
|
5412
5412
|
subscriptionBundleId
|
|
@@ -5415,7 +5415,7 @@ var SubscriptionBundlesService = class {
|
|
|
5415
5415
|
}
|
|
5416
5416
|
if (existing.canceledEffectiveAt !== null && existing.canceledEffectiveAt <= /* @__PURE__ */ new Date()) {
|
|
5417
5417
|
throw new import_common33.UnprocessableEntityException({
|
|
5418
|
-
code:
|
|
5418
|
+
code: import_core19.BILLING_ERROR_CODES.SUBSCRIPTION_BUNDLE_CANCELLATION_EFFECTIVE,
|
|
5419
5419
|
message: "Cancellation already in effect \u2014 book the bundle again."
|
|
5420
5420
|
});
|
|
5421
5421
|
}
|
|
@@ -5523,7 +5523,7 @@ var TenantBillingController = class _TenantBillingController {
|
|
|
5523
5523
|
]);
|
|
5524
5524
|
if (!sub) {
|
|
5525
5525
|
throw new import_common34.NotFoundException({
|
|
5526
|
-
code:
|
|
5526
|
+
code: import_core20.BILLING_ERROR_CODES.SUBSCRIPTION_NOT_FOUND,
|
|
5527
5527
|
message: `No subscription for tenant ${tenantId}`,
|
|
5528
5528
|
params: {
|
|
5529
5529
|
tenantId
|
|
@@ -5578,7 +5578,7 @@ var TenantBillingController = class _TenantBillingController {
|
|
|
5578
5578
|
const blockedTargets = this.blockedPlans?.asTarget ?? [];
|
|
5579
5579
|
if (blockedTargets.includes(dto.plan)) {
|
|
5580
5580
|
throw new import_common34.ForbiddenException({
|
|
5581
|
-
code:
|
|
5581
|
+
code: import_core20.BILLING_ERROR_CODES.PLAN_NOT_SELF_SERVICE,
|
|
5582
5582
|
message: `${dto.plan} is not activated via self-service.`,
|
|
5583
5583
|
params: {
|
|
5584
5584
|
planKey: dto.plan
|
|
@@ -5588,7 +5588,7 @@ var TenantBillingController = class _TenantBillingController {
|
|
|
5588
5588
|
const sub = await this.subscriptionUsage.findForTenant(tenantId);
|
|
5589
5589
|
if (!sub) {
|
|
5590
5590
|
throw new import_common34.NotFoundException({
|
|
5591
|
-
code:
|
|
5591
|
+
code: import_core20.BILLING_ERROR_CODES.SUBSCRIPTION_NOT_FOUND,
|
|
5592
5592
|
message: `No subscription for tenant ${tenantId}`,
|
|
5593
5593
|
params: {
|
|
5594
5594
|
tenantId
|
|
@@ -5598,7 +5598,7 @@ var TenantBillingController = class _TenantBillingController {
|
|
|
5598
5598
|
const blockers = await this.planPreview.assertChangeAllowed(tenantId, dto.plan, dto.billingCycle);
|
|
5599
5599
|
if (blockers.length > 0) {
|
|
5600
5600
|
throw new import_common34.BadRequestException({
|
|
5601
|
-
code:
|
|
5601
|
+
code: import_core20.BILLING_ERROR_CODES.PLAN_CHANGE_BLOCKED,
|
|
5602
5602
|
message: "Plan change is blocked.",
|
|
5603
5603
|
blockers
|
|
5604
5604
|
});
|
|
@@ -5670,7 +5670,7 @@ var TenantBillingController = class _TenantBillingController {
|
|
|
5670
5670
|
const blockedTargets = this.blockedPlans?.asTarget ?? [];
|
|
5671
5671
|
if (blockedTargets.includes(dto.plan)) {
|
|
5672
5672
|
throw new import_common34.ForbiddenException({
|
|
5673
|
-
code:
|
|
5673
|
+
code: import_core20.BILLING_ERROR_CODES.PLAN_NOT_SELF_SERVICE,
|
|
5674
5674
|
message: `${dto.plan} is not activated via self-service.`,
|
|
5675
5675
|
params: {
|
|
5676
5676
|
planKey: dto.plan
|
|
@@ -5680,7 +5680,7 @@ var TenantBillingController = class _TenantBillingController {
|
|
|
5680
5680
|
const sub = await this.subscriptionUsage.findForTenant(tenantId);
|
|
5681
5681
|
if (!sub) {
|
|
5682
5682
|
throw new import_common34.NotFoundException({
|
|
5683
|
-
code:
|
|
5683
|
+
code: import_core20.BILLING_ERROR_CODES.SUBSCRIPTION_NOT_FOUND,
|
|
5684
5684
|
message: `No subscription for tenant ${tenantId}`,
|
|
5685
5685
|
params: {
|
|
5686
5686
|
tenantId
|
|
@@ -5690,7 +5690,7 @@ var TenantBillingController = class _TenantBillingController {
|
|
|
5690
5690
|
const blockers = await this.planPreview.assertChangeAllowed(tenantId, dto.plan, dto.billingCycle);
|
|
5691
5691
|
if (blockers.length > 0) {
|
|
5692
5692
|
throw new import_common34.BadRequestException({
|
|
5693
|
-
code:
|
|
5693
|
+
code: import_core20.BILLING_ERROR_CODES.PLAN_CHANGE_BLOCKED,
|
|
5694
5694
|
message: "Plan change during onboarding is blocked.",
|
|
5695
5695
|
blockers
|
|
5696
5696
|
});
|
|
@@ -5727,7 +5727,7 @@ var TenantBillingController = class _TenantBillingController {
|
|
|
5727
5727
|
} catch (err) {
|
|
5728
5728
|
const reason = err instanceof Error ? err.message : null;
|
|
5729
5729
|
throw new import_common34.BadRequestException({
|
|
5730
|
-
code:
|
|
5730
|
+
code: import_core20.BILLING_ERROR_CODES.ONBOARDING_CREATE_FAILED,
|
|
5731
5731
|
message: reason ? `Onboarding creation failed: ${reason}` : "Onboarding creation failed",
|
|
5732
5732
|
params: {
|
|
5733
5733
|
reason
|
|
@@ -5810,7 +5810,7 @@ var TenantBillingController = class _TenantBillingController {
|
|
|
5810
5810
|
const sub = await this.subscriptionUsage.findForTenant(tenantId);
|
|
5811
5811
|
if (!sub) {
|
|
5812
5812
|
throw new import_common34.NotFoundException({
|
|
5813
|
-
code:
|
|
5813
|
+
code: import_core20.BILLING_ERROR_CODES.SUBSCRIPTION_NOT_FOUND,
|
|
5814
5814
|
message: `No subscription for tenant ${tenantId}`,
|
|
5815
5815
|
params: {
|
|
5816
5816
|
tenantId
|
|
@@ -5819,7 +5819,7 @@ var TenantBillingController = class _TenantBillingController {
|
|
|
5819
5819
|
}
|
|
5820
5820
|
if (!sub.pendingPlanVersion) {
|
|
5821
5821
|
throw new import_common34.BadRequestException({
|
|
5822
|
-
code:
|
|
5822
|
+
code: import_core20.BILLING_ERROR_CODES.NO_PENDING_PLAN_VERSION,
|
|
5823
5823
|
message: "There is no pending plan version awaiting confirmation."
|
|
5824
5824
|
});
|
|
5825
5825
|
}
|
|
@@ -5867,7 +5867,7 @@ var TenantBillingController = class _TenantBillingController {
|
|
|
5867
5867
|
const tenantId = resolver(req);
|
|
5868
5868
|
if (!tenantId) {
|
|
5869
5869
|
throw new import_common34.NotFoundException({
|
|
5870
|
-
code:
|
|
5870
|
+
code: import_core20.AUTH_ERROR_CODES.TENANT_CONTEXT_MISSING,
|
|
5871
5871
|
message: "No tenant ID found on the request"
|
|
5872
5872
|
});
|
|
5873
5873
|
}
|
|
@@ -5878,7 +5878,7 @@ var TenantBillingController = class _TenantBillingController {
|
|
|
5878
5878
|
const userId = resolver(req);
|
|
5879
5879
|
if (!userId) {
|
|
5880
5880
|
throw new import_common34.NotFoundException({
|
|
5881
|
-
code:
|
|
5881
|
+
code: import_core20.AUTH_ERROR_CODES.TENANT_CONTEXT_MISSING,
|
|
5882
5882
|
message: "No user ID found on the request"
|
|
5883
5883
|
});
|
|
5884
5884
|
}
|
|
@@ -6249,7 +6249,7 @@ __name(normalizeQuotas, "normalizeQuotas");
|
|
|
6249
6249
|
|
|
6250
6250
|
// src/billing/subscription-bundle-preview.service.ts
|
|
6251
6251
|
var import_common37 = require("@nestjs/common");
|
|
6252
|
-
var
|
|
6252
|
+
var import_core21 = require("@saasicat/core");
|
|
6253
6253
|
function _ts_decorate37(decorators, target, key, desc) {
|
|
6254
6254
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
6255
6255
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
@@ -6289,7 +6289,7 @@ var SubscriptionBundlePreviewService = class {
|
|
|
6289
6289
|
const bundleVersion = await this.bundles.findVersionById(input.bundleVersionId);
|
|
6290
6290
|
if (!bundleVersion) {
|
|
6291
6291
|
throw new import_common37.NotFoundException({
|
|
6292
|
-
code:
|
|
6292
|
+
code: import_core21.CATALOG_ERROR_CODES.BUNDLE_VERSION_NOT_FOUND,
|
|
6293
6293
|
message: `BundleVersion '${input.bundleVersionId}' not found`,
|
|
6294
6294
|
params: {
|
|
6295
6295
|
bundleVersionId: input.bundleVersionId
|
|
@@ -6348,7 +6348,7 @@ var SubscriptionBundlePreviewService = class {
|
|
|
6348
6348
|
const existing = await this.subscriptionBundles.findById(input.subscriptionBundleId);
|
|
6349
6349
|
if (!existing || existing.subscriptionId !== ctx.subscriptionId) {
|
|
6350
6350
|
throw new import_common37.NotFoundException({
|
|
6351
|
-
code:
|
|
6351
|
+
code: import_core21.BILLING_ERROR_CODES.SUBSCRIPTION_BUNDLE_NOT_FOUND,
|
|
6352
6352
|
message: `SubscriptionBundle '${input.subscriptionBundleId}' not found`,
|
|
6353
6353
|
params: {
|
|
6354
6354
|
subscriptionBundleId: input.subscriptionBundleId
|
|
@@ -6358,7 +6358,7 @@ var SubscriptionBundlePreviewService = class {
|
|
|
6358
6358
|
const bundleVersion = await this.bundles.findVersionById(existing.bundleVersionId);
|
|
6359
6359
|
if (!bundleVersion) {
|
|
6360
6360
|
throw new import_common37.NotFoundException({
|
|
6361
|
-
code:
|
|
6361
|
+
code: import_core21.CATALOG_ERROR_CODES.BUNDLE_VERSION_NOT_FOUND,
|
|
6362
6362
|
message: `BundleVersion '${existing.bundleVersionId}' not found`,
|
|
6363
6363
|
params: {
|
|
6364
6364
|
bundleVersionId: existing.bundleVersionId
|
|
@@ -6369,7 +6369,7 @@ var SubscriptionBundlePreviewService = class {
|
|
|
6369
6369
|
const warnings = [];
|
|
6370
6370
|
if (existing.canceledAt !== null) {
|
|
6371
6371
|
blockers.push({
|
|
6372
|
-
code:
|
|
6372
|
+
code: import_core21.BILLING_ERROR_CODES.SUBSCRIPTION_BUNDLE_ALREADY_CANCELLED,
|
|
6373
6373
|
message: "This bundle booking is already cancelled."
|
|
6374
6374
|
});
|
|
6375
6375
|
}
|
|
@@ -6469,12 +6469,12 @@ var SubscriptionBundlePreviewService = class {
|
|
|
6469
6469
|
const entries = await this.catalogEntries.listFeatures({
|
|
6470
6470
|
projectKey
|
|
6471
6471
|
});
|
|
6472
|
-
const requiresIndex = (0,
|
|
6472
|
+
const requiresIndex = (0, import_core21.buildFeatureRequiresIndex)(entries);
|
|
6473
6473
|
const covered = /* @__PURE__ */ new Set([
|
|
6474
6474
|
...planFeatures,
|
|
6475
6475
|
...activeBundleVersions.flatMap((bv) => bv.features ?? [])
|
|
6476
6476
|
]);
|
|
6477
|
-
return (0,
|
|
6477
|
+
return (0, import_core21.collectUnsatisfiedRequires)(bundleVersion.features ?? [], requiresIndex).filter((key) => !covered.has(key));
|
|
6478
6478
|
}
|
|
6479
6479
|
/** `projectKey` lives on the bundle stem, not on the version. */
|
|
6480
6480
|
async resolveProjectKey(bundleVersion) {
|
|
@@ -6533,7 +6533,7 @@ var import_common39 = require("@nestjs/common");
|
|
|
6533
6533
|
|
|
6534
6534
|
// src/billing/tenant-subscription-bundles.controller.ts
|
|
6535
6535
|
var import_common38 = require("@nestjs/common");
|
|
6536
|
-
var
|
|
6536
|
+
var import_core22 = require("@saasicat/core");
|
|
6537
6537
|
|
|
6538
6538
|
// src/billing/dto/subscription-bundles.dto.ts
|
|
6539
6539
|
var import_class_validator5 = require("class-validator");
|
|
@@ -6679,7 +6679,7 @@ function buildTenantSubscriptionBundlesController(extraGuards = []) {
|
|
|
6679
6679
|
const hasCancel = Boolean(dto.subscriptionBundleId);
|
|
6680
6680
|
if (hasAdd === hasCancel) {
|
|
6681
6681
|
throw new import_common38.BadRequestException({
|
|
6682
|
-
code:
|
|
6682
|
+
code: import_core22.BILLING_ERROR_CODES.BUNDLE_PREVIEW_ARGUMENT_AMBIGUOUS,
|
|
6683
6683
|
message: "Exactly one of bundleVersionId (add preview) or subscriptionBundleId (cancel preview) must be given."
|
|
6684
6684
|
});
|
|
6685
6685
|
}
|
|
@@ -6721,7 +6721,7 @@ function buildTenantSubscriptionBundlesController(extraGuards = []) {
|
|
|
6721
6721
|
}
|
|
6722
6722
|
requireSubscriptionPk(sub) {
|
|
6723
6723
|
if (!sub.id) {
|
|
6724
|
-
throw new import_common38.NotFoundException(codedError(
|
|
6724
|
+
throw new import_common38.NotFoundException(codedError(import_core22.BILLING_ERROR_CODES.SUBSCRIPTION_PK_MISSING));
|
|
6725
6725
|
}
|
|
6726
6726
|
return sub.id;
|
|
6727
6727
|
}
|
|
@@ -6729,7 +6729,7 @@ function buildTenantSubscriptionBundlesController(extraGuards = []) {
|
|
|
6729
6729
|
const tenantId = this.tenantIdResolver(req);
|
|
6730
6730
|
if (!tenantId) {
|
|
6731
6731
|
throw new import_common38.NotFoundException({
|
|
6732
|
-
code:
|
|
6732
|
+
code: import_core22.AUTH_ERROR_CODES.TENANT_CONTEXT_MISSING,
|
|
6733
6733
|
message: "No tenant ID found on the request"
|
|
6734
6734
|
});
|
|
6735
6735
|
}
|
|
@@ -6739,7 +6739,7 @@ function buildTenantSubscriptionBundlesController(extraGuards = []) {
|
|
|
6739
6739
|
const sub = await this.subscriptionUsage.findForTenant(tenantId);
|
|
6740
6740
|
if (!sub) {
|
|
6741
6741
|
throw new import_common38.NotFoundException({
|
|
6742
|
-
code:
|
|
6742
|
+
code: import_core22.BILLING_ERROR_CODES.SUBSCRIPTION_NOT_FOUND,
|
|
6743
6743
|
message: `No subscription for tenant ${tenantId}`,
|
|
6744
6744
|
params: {
|
|
6745
6745
|
tenantId
|
|
@@ -6921,6 +6921,7 @@ __export(catalog_exports, {
|
|
|
6921
6921
|
BUNDLE_REPOSITORY_TOKEN: () => BUNDLE_REPOSITORY_TOKEN,
|
|
6922
6922
|
BundlesService: () => BundlesService,
|
|
6923
6923
|
CATALOG_ENTRY_REPOSITORY_TOKEN: () => CATALOG_ENTRY_REPOSITORY_TOKEN,
|
|
6924
|
+
CATALOG_FEATURE_UI_REGISTRY_TOKEN: () => CATALOG_FEATURE_UI_REGISTRY_TOKEN,
|
|
6924
6925
|
CATALOG_SERVICE_CONFIG_TOKEN: () => CATALOG_SERVICE_CONFIG_TOKEN,
|
|
6925
6926
|
CatalogEntriesService: () => CatalogEntriesService,
|
|
6926
6927
|
CatalogModule: () => CatalogModule,
|
|
@@ -6982,14 +6983,14 @@ __export(catalog_exports, {
|
|
|
6982
6983
|
|
|
6983
6984
|
// src/catalog/bundles.service.ts
|
|
6984
6985
|
var import_common41 = require("@nestjs/common");
|
|
6985
|
-
var
|
|
6986
|
+
var import_core24 = require("@saasicat/core");
|
|
6986
6987
|
|
|
6987
6988
|
// src/discovery/discovery.scanner.ts
|
|
6988
6989
|
var import_node_crypto2 = require("crypto");
|
|
6989
6990
|
var import_node_fs2 = require("fs");
|
|
6990
6991
|
var import_node_path2 = require("path");
|
|
6991
6992
|
var import_common40 = require("@nestjs/common");
|
|
6992
|
-
var
|
|
6993
|
+
var import_core23 = require("@nestjs/core");
|
|
6993
6994
|
function _ts_decorate41(decorators, target, key, desc) {
|
|
6994
6995
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
6995
6996
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
@@ -7011,8 +7012,8 @@ var DEFAULT_APP_INFO = {
|
|
|
7011
7012
|
key: "unknown",
|
|
7012
7013
|
version: "0.0.0"
|
|
7013
7014
|
};
|
|
7014
|
-
var DISCOVERY_APP_INFO_TOKEN = /* @__PURE__ */ Symbol.for("
|
|
7015
|
-
var DISCOVERY_SNAPSHOT_PATH_TOKEN = /* @__PURE__ */ Symbol.for("
|
|
7015
|
+
var DISCOVERY_APP_INFO_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/nest/DiscoveryAppInfo");
|
|
7016
|
+
var DISCOVERY_SNAPSHOT_PATH_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/nest/DiscoverySnapshotPath");
|
|
7016
7017
|
var DiscoveryScanner = class _DiscoveryScanner {
|
|
7017
7018
|
static {
|
|
7018
7019
|
__name(this, "DiscoveryScanner");
|
|
@@ -7174,18 +7175,18 @@ var DiscoveryScanner = class _DiscoveryScanner {
|
|
|
7174
7175
|
};
|
|
7175
7176
|
DiscoveryScanner = _ts_decorate41([
|
|
7176
7177
|
(0, import_common40.Injectable)(),
|
|
7177
|
-
_ts_param27(0, (0, import_common40.Inject)(
|
|
7178
|
-
_ts_param27(1, (0, import_common40.Inject)(
|
|
7179
|
-
_ts_param27(2, (0, import_common40.Inject)(
|
|
7178
|
+
_ts_param27(0, (0, import_common40.Inject)(import_core23.DiscoveryService)),
|
|
7179
|
+
_ts_param27(1, (0, import_common40.Inject)(import_core23.MetadataScanner)),
|
|
7180
|
+
_ts_param27(2, (0, import_common40.Inject)(import_core23.Reflector)),
|
|
7180
7181
|
_ts_param27(3, (0, import_common40.Optional)()),
|
|
7181
7182
|
_ts_param27(3, (0, import_common40.Inject)(DISCOVERY_APP_INFO_TOKEN)),
|
|
7182
7183
|
_ts_param27(4, (0, import_common40.Optional)()),
|
|
7183
7184
|
_ts_param27(4, (0, import_common40.Inject)(DISCOVERY_SNAPSHOT_PATH_TOKEN)),
|
|
7184
7185
|
_ts_metadata30("design:type", Function),
|
|
7185
7186
|
_ts_metadata30("design:paramtypes", [
|
|
7186
|
-
typeof
|
|
7187
|
-
typeof
|
|
7188
|
-
typeof
|
|
7187
|
+
typeof import_core23.DiscoveryService === "undefined" ? Object : import_core23.DiscoveryService,
|
|
7188
|
+
typeof import_core23.MetadataScanner === "undefined" ? Object : import_core23.MetadataScanner,
|
|
7189
|
+
typeof import_core23.Reflector === "undefined" ? Object : import_core23.Reflector,
|
|
7189
7190
|
typeof DiscoveryAppInfo === "undefined" ? Object : DiscoveryAppInfo,
|
|
7190
7191
|
Object
|
|
7191
7192
|
])
|
|
@@ -7506,7 +7507,7 @@ var BundlesService = class _BundlesService {
|
|
|
7506
7507
|
const bundle2 = await this.repo.findById(bundleId);
|
|
7507
7508
|
if (!bundle2) {
|
|
7508
7509
|
throw new import_common41.NotFoundException({
|
|
7509
|
-
code:
|
|
7510
|
+
code: import_core24.CATALOG_ERROR_CODES.BUNDLE_NOT_FOUND,
|
|
7510
7511
|
message: `Bundle '${bundleId}' not found`,
|
|
7511
7512
|
params: {
|
|
7512
7513
|
bundleId
|
|
@@ -7523,7 +7524,7 @@ var BundlesService = class _BundlesService {
|
|
|
7523
7524
|
const existing = await this.repo.findByKey(data.projectKey, data.bundleKey);
|
|
7524
7525
|
if (existing) {
|
|
7525
7526
|
throw new import_common41.UnprocessableEntityException({
|
|
7526
|
-
code:
|
|
7527
|
+
code: import_core24.CATALOG_ERROR_CODES.BUNDLE_ALREADY_EXISTS,
|
|
7527
7528
|
message: `Bundle '${data.bundleKey}' already exists in project '${data.projectKey}'`,
|
|
7528
7529
|
params: {
|
|
7529
7530
|
bundleKey: data.bundleKey,
|
|
@@ -7537,7 +7538,7 @@ var BundlesService = class _BundlesService {
|
|
|
7537
7538
|
const existing = await this.repo.findById(bundleId);
|
|
7538
7539
|
if (!existing) {
|
|
7539
7540
|
throw new import_common41.NotFoundException({
|
|
7540
|
-
code:
|
|
7541
|
+
code: import_core24.CATALOG_ERROR_CODES.BUNDLE_NOT_FOUND,
|
|
7541
7542
|
message: `Bundle '${bundleId}' not found`,
|
|
7542
7543
|
params: {
|
|
7543
7544
|
bundleId
|
|
@@ -7550,7 +7551,7 @@ var BundlesService = class _BundlesService {
|
|
|
7550
7551
|
const existing = await this.repo.findById(bundleId);
|
|
7551
7552
|
if (!existing) {
|
|
7552
7553
|
throw new import_common41.NotFoundException({
|
|
7553
|
-
code:
|
|
7554
|
+
code: import_core24.CATALOG_ERROR_CODES.BUNDLE_NOT_FOUND,
|
|
7554
7555
|
message: `Bundle '${bundleId}' not found`,
|
|
7555
7556
|
params: {
|
|
7556
7557
|
bundleId
|
|
@@ -7569,7 +7570,7 @@ var BundlesService = class _BundlesService {
|
|
|
7569
7570
|
const existing = await this.repo.findVersionById(versionId);
|
|
7570
7571
|
if (!existing) {
|
|
7571
7572
|
throw new import_common41.NotFoundException({
|
|
7572
|
-
code:
|
|
7573
|
+
code: import_core24.CATALOG_ERROR_CODES.BUNDLE_VERSION_NOT_FOUND,
|
|
7573
7574
|
message: `BundleVersion '${versionId}' not found`,
|
|
7574
7575
|
params: {
|
|
7575
7576
|
bundleVersionId: versionId
|
|
@@ -7578,7 +7579,7 @@ var BundlesService = class _BundlesService {
|
|
|
7578
7579
|
}
|
|
7579
7580
|
if (existing.publishedAt !== null) {
|
|
7580
7581
|
throw new import_common41.UnprocessableEntityException({
|
|
7581
|
-
code:
|
|
7582
|
+
code: import_core24.CATALOG_ERROR_CODES.BUNDLE_VERSION_ALREADY_PUBLISHED,
|
|
7582
7583
|
message: `BundleVersion '${versionId}' is already published and cannot be discarded.`,
|
|
7583
7584
|
params: {
|
|
7584
7585
|
versionId
|
|
@@ -7587,7 +7588,7 @@ var BundlesService = class _BundlesService {
|
|
|
7587
7588
|
}
|
|
7588
7589
|
if (typeof this.repo.deleteDraft !== "function") {
|
|
7589
7590
|
throw new import_common41.UnprocessableEntityException({
|
|
7590
|
-
code:
|
|
7591
|
+
code: import_core24.CATALOG_ERROR_CODES.BUNDLE_VERSION_DISCARD_NOT_IMPLEMENTED,
|
|
7591
7592
|
message: "Discard is not implemented in the current repository. Implement BundleRepository.deleteDraft."
|
|
7592
7593
|
});
|
|
7593
7594
|
}
|
|
@@ -7603,7 +7604,7 @@ var BundlesService = class _BundlesService {
|
|
|
7603
7604
|
const version = await this.repo.findVersionById(versionId);
|
|
7604
7605
|
if (!version) {
|
|
7605
7606
|
throw new import_common41.NotFoundException({
|
|
7606
|
-
code:
|
|
7607
|
+
code: import_core24.CATALOG_ERROR_CODES.BUNDLE_VERSION_NOT_FOUND,
|
|
7607
7608
|
message: `BundleVersion '${versionId}' not found`,
|
|
7608
7609
|
params: {
|
|
7609
7610
|
bundleVersionId: versionId
|
|
@@ -7651,7 +7652,7 @@ var BundlesService = class _BundlesService {
|
|
|
7651
7652
|
const bundle2 = await this.repo.findById(data.bundleId);
|
|
7652
7653
|
if (!bundle2) {
|
|
7653
7654
|
throw new import_common41.NotFoundException({
|
|
7654
|
-
code:
|
|
7655
|
+
code: import_core24.CATALOG_ERROR_CODES.BUNDLE_NOT_FOUND,
|
|
7655
7656
|
message: `Bundle '${data.bundleId}' not found`,
|
|
7656
7657
|
params: {
|
|
7657
7658
|
bundleId: data.bundleId
|
|
@@ -7661,7 +7662,7 @@ var BundlesService = class _BundlesService {
|
|
|
7661
7662
|
const existingDraft = await this.repo.findCurrentDraft(data.bundleId);
|
|
7662
7663
|
if (existingDraft) {
|
|
7663
7664
|
throw new import_common41.UnprocessableEntityException({
|
|
7664
|
-
code:
|
|
7665
|
+
code: import_core24.CATALOG_ERROR_CODES.BUNDLE_DRAFT_ALREADY_EXISTS,
|
|
7665
7666
|
message: `Bundle '${bundle2.bundleKey}' already has a draft version v${existingDraft.version}; publish or discard it first`,
|
|
7666
7667
|
params: {
|
|
7667
7668
|
bundleKey: bundle2.bundleKey,
|
|
@@ -7700,7 +7701,7 @@ var BundlesService = class _BundlesService {
|
|
|
7700
7701
|
const existing = await this.repo.findVersionById(versionId);
|
|
7701
7702
|
if (!existing) {
|
|
7702
7703
|
throw new import_common41.NotFoundException({
|
|
7703
|
-
code:
|
|
7704
|
+
code: import_core24.CATALOG_ERROR_CODES.BUNDLE_VERSION_NOT_FOUND,
|
|
7704
7705
|
message: `BundleVersion '${versionId}' not found`,
|
|
7705
7706
|
params: {
|
|
7706
7707
|
bundleVersionId: versionId
|
|
@@ -7710,10 +7711,10 @@ var BundlesService = class _BundlesService {
|
|
|
7710
7711
|
const [annotated] = await this.annotateEditability([
|
|
7711
7712
|
existing
|
|
7712
7713
|
]);
|
|
7713
|
-
const { editable } = (0,
|
|
7714
|
+
const { editable } = (0, import_core24.isVersionEditable)(annotated);
|
|
7714
7715
|
if (!editable) {
|
|
7715
7716
|
throw new import_common41.UnprocessableEntityException({
|
|
7716
|
-
code:
|
|
7717
|
+
code: import_core24.CATALOG_ERROR_CODES.BUNDLE_VERSION_NOT_EDITABLE,
|
|
7717
7718
|
message: `BundleVersion '${versionId}' is not editable. Only drafts and published versions are editable that are latest-in-chain, bind no subscription yet, and whose validFrom lies in the future.`,
|
|
7718
7719
|
params: {
|
|
7719
7720
|
versionId
|
|
@@ -7749,7 +7750,7 @@ var BundlesService = class _BundlesService {
|
|
|
7749
7750
|
const draft = await this.repo.findVersionById(versionId);
|
|
7750
7751
|
if (!draft) {
|
|
7751
7752
|
throw new import_common41.NotFoundException({
|
|
7752
|
-
code:
|
|
7753
|
+
code: import_core24.CATALOG_ERROR_CODES.BUNDLE_VERSION_NOT_FOUND,
|
|
7753
7754
|
message: `BundleVersion '${versionId}' not found`,
|
|
7754
7755
|
params: {
|
|
7755
7756
|
bundleVersionId: versionId
|
|
@@ -7758,7 +7759,7 @@ var BundlesService = class _BundlesService {
|
|
|
7758
7759
|
}
|
|
7759
7760
|
if (draft.publishedAt !== null) {
|
|
7760
7761
|
throw new import_common41.UnprocessableEntityException({
|
|
7761
|
-
code:
|
|
7762
|
+
code: import_core24.CATALOG_ERROR_CODES.BUNDLE_VERSION_ALREADY_PUBLISHED,
|
|
7762
7763
|
message: `BundleVersion '${versionId}' is already published`,
|
|
7763
7764
|
params: {
|
|
7764
7765
|
versionId
|
|
@@ -7776,7 +7777,7 @@ var BundlesService = class _BundlesService {
|
|
|
7776
7777
|
const explicitZero = /* @__PURE__ */ __name((v) => v !== null && v !== void 0 && Number.parseFloat(String(v)) <= 0, "explicitZero");
|
|
7777
7778
|
if (explicitZero(draft.monthlyNet) || explicitZero(draft.yearlyNet)) {
|
|
7778
7779
|
throw new import_common41.UnprocessableEntityException({
|
|
7779
|
-
code:
|
|
7780
|
+
code: import_core24.CATALOG_ERROR_CODES.BUNDLE_VERSION_ZERO_PRICE,
|
|
7780
7781
|
message: "A bundle version cannot be published with an explicit price of 0.00 (guard against seed placeholders). For free bundles leave it null, or set allowZeroPrice.",
|
|
7781
7782
|
monthlyNet: draft.monthlyNet,
|
|
7782
7783
|
yearlyNet: draft.yearlyNet
|
|
@@ -7787,14 +7788,14 @@ var BundlesService = class _BundlesService {
|
|
|
7787
7788
|
const validFromInput = publishMeta.validFrom ?? draft.validFrom;
|
|
7788
7789
|
if (!validFromInput) {
|
|
7789
7790
|
throw new import_common41.UnprocessableEntityException({
|
|
7790
|
-
code:
|
|
7791
|
+
code: import_core24.CATALOG_ERROR_CODES.BUNDLE_VERSION_VALID_FROM_REQUIRED,
|
|
7791
7792
|
message: "validFrom must be set when publishing (on the draft or the publish call).."
|
|
7792
7793
|
});
|
|
7793
7794
|
}
|
|
7794
7795
|
const validFrom = new Date(validFromInput);
|
|
7795
7796
|
if (Number.isNaN(validFrom.getTime())) {
|
|
7796
7797
|
throw new import_common41.UnprocessableEntityException({
|
|
7797
|
-
code:
|
|
7798
|
+
code: import_core24.CATALOG_ERROR_CODES.BUNDLE_VERSION_VALID_FROM_INVALID,
|
|
7798
7799
|
message: `validFrom '${validFromInput}' is not a valid date`,
|
|
7799
7800
|
params: {
|
|
7800
7801
|
validFrom: validFromInput
|
|
@@ -7805,7 +7806,7 @@ var BundlesService = class _BundlesService {
|
|
|
7805
7806
|
const prevFrom = new Date(previous.validFrom);
|
|
7806
7807
|
if (validFrom <= prevFrom) {
|
|
7807
7808
|
throw new import_common41.UnprocessableEntityException({
|
|
7808
|
-
code:
|
|
7809
|
+
code: import_core24.CATALOG_ERROR_CODES.BUNDLE_VERSION_VALID_FROM_NOT_AFTER_PREVIOUS,
|
|
7809
7810
|
message: `validFrom (${validFrom.toISOString()}) must be strictly after the validFrom of the previous version (${previous.validFrom}).`,
|
|
7810
7811
|
params: {
|
|
7811
7812
|
validFrom: validFrom.toISOString(),
|
|
@@ -7819,7 +7820,7 @@ var BundlesService = class _BundlesService {
|
|
|
7819
7820
|
const requiredStart = new Date(prevUntil.getTime() + dayMs);
|
|
7820
7821
|
if (validFrom.getTime() !== requiredStart.getTime()) {
|
|
7821
7822
|
throw new import_common41.UnprocessableEntityException({
|
|
7822
|
-
code:
|
|
7823
|
+
code: import_core24.CATALOG_ERROR_CODES.BUNDLE_VERSION_VALID_FROM_NOT_GAPLESS,
|
|
7823
7824
|
message: `The predecessor has validUntil=${previous.validUntil.slice(0, 10)} \u2014 the successor must start seamlessly on the next day (${requiredStart.toISOString().slice(0, 10)}). Received: ${validFrom.toISOString().slice(0, 10)}.`,
|
|
7824
7825
|
params: {
|
|
7825
7826
|
received: validFrom.toISOString().slice(0, 10)
|
|
@@ -7834,7 +7835,7 @@ var BundlesService = class _BundlesService {
|
|
|
7834
7835
|
const validUntil = validUntilInput ? new Date(validUntilInput) : null;
|
|
7835
7836
|
if (validUntil && Number.isNaN(validUntil.getTime())) {
|
|
7836
7837
|
throw new import_common41.UnprocessableEntityException({
|
|
7837
|
-
code:
|
|
7838
|
+
code: import_core24.CATALOG_ERROR_CODES.BUNDLE_VERSION_VALID_UNTIL_INVALID,
|
|
7838
7839
|
message: `validUntil '${validUntilInput}' is not a valid date`,
|
|
7839
7840
|
params: {
|
|
7840
7841
|
validUntil: validUntilInput
|
|
@@ -7843,7 +7844,7 @@ var BundlesService = class _BundlesService {
|
|
|
7843
7844
|
}
|
|
7844
7845
|
if (validUntil && validUntil <= validFrom) {
|
|
7845
7846
|
throw new import_common41.UnprocessableEntityException({
|
|
7846
|
-
code:
|
|
7847
|
+
code: import_core24.CATALOG_ERROR_CODES.BUNDLE_VERSION_VALID_UNTIL_BEFORE_FROM,
|
|
7847
7848
|
message: `validUntil (${validUntil.toISOString()}) must be strictly after validFrom (${validFrom.toISOString()}).`,
|
|
7848
7849
|
params: {
|
|
7849
7850
|
validUntil: validUntil.toISOString(),
|
|
@@ -7851,7 +7852,7 @@ var BundlesService = class _BundlesService {
|
|
|
7851
7852
|
}
|
|
7852
7853
|
});
|
|
7853
7854
|
}
|
|
7854
|
-
const diff = previous ? (0,
|
|
7855
|
+
const diff = previous ? (0, import_core6.classifyBundleVersionDiff)({
|
|
7855
7856
|
features: previous.features,
|
|
7856
7857
|
quotas: previous.quotas,
|
|
7857
7858
|
monthlyNet: previous.monthlyNet,
|
|
@@ -7867,7 +7868,7 @@ var BundlesService = class _BundlesService {
|
|
|
7867
7868
|
};
|
|
7868
7869
|
if (!diff.nonRegressive && !publishMeta.forceRegressive) {
|
|
7869
7870
|
throw new import_common41.UnprocessableEntityException({
|
|
7870
|
-
code:
|
|
7871
|
+
code: import_core24.CATALOG_ERROR_CODES.BUNDLE_VERSION_REGRESSION,
|
|
7871
7872
|
message: "This bundle version is regressive (feature removed / quota lowered / price raised). Publishing requires an explicit `forceRegressive: true` (UI confirmation dialog with MFA).",
|
|
7872
7873
|
changes: diff.changes
|
|
7873
7874
|
});
|
|
@@ -7907,7 +7908,7 @@ var BundlesService = class _BundlesService {
|
|
|
7907
7908
|
const hasHardBlockingWarning = blocking.some((w) => w.code === "BUNDLE_PLAN_KEY_UNKNOWN");
|
|
7908
7909
|
if (this.mode === "blocking" || hasHardBlockingWarning) {
|
|
7909
7910
|
throw new import_common41.UnprocessableEntityException({
|
|
7910
|
-
code:
|
|
7911
|
+
code: import_core24.CATALOG_ERROR_CODES.STRICT_MODE_VIOLATIONS,
|
|
7911
7912
|
message: "The strict-mode check found drift against the discovery snapshot.",
|
|
7912
7913
|
warnings
|
|
7913
7914
|
});
|
|
@@ -7921,7 +7922,7 @@ var BundlesService = class _BundlesService {
|
|
|
7921
7922
|
if (!validFromInput) {
|
|
7922
7923
|
if (existing.publishedAt !== null) {
|
|
7923
7924
|
throw new import_common41.UnprocessableEntityException({
|
|
7924
|
-
code:
|
|
7925
|
+
code: import_core24.CATALOG_ERROR_CODES.BUNDLE_VERSION_VALID_FROM_REQUIRED,
|
|
7925
7926
|
message: "Published bundle versions must keep a validFrom. Set a new future date, or edit the draft before publishing."
|
|
7926
7927
|
});
|
|
7927
7928
|
}
|
|
@@ -7930,7 +7931,7 @@ var BundlesService = class _BundlesService {
|
|
|
7930
7931
|
const validFrom = this.parseRequiredBundleDate(validFromInput, "validFrom", "BUNDLE_VERSION_VALID_FROM_INVALID");
|
|
7931
7932
|
if (existing.publishedAt !== null && validFrom.getTime() <= Date.now()) {
|
|
7932
7933
|
throw new import_common41.UnprocessableEntityException({
|
|
7933
|
-
code:
|
|
7934
|
+
code: import_core24.CATALOG_ERROR_CODES.BUNDLE_VERSION_VALID_FROM_NOT_FUTURE,
|
|
7934
7935
|
message: `validFrom (${validFrom.toISOString()}) must, for a published-but-future bundle version, still lie in the future.`,
|
|
7935
7936
|
params: {
|
|
7936
7937
|
validFrom: validFrom.toISOString()
|
|
@@ -7939,7 +7940,7 @@ var BundlesService = class _BundlesService {
|
|
|
7939
7940
|
}
|
|
7940
7941
|
if (validUntil && validUntil <= validFrom) {
|
|
7941
7942
|
throw new import_common41.UnprocessableEntityException({
|
|
7942
|
-
code:
|
|
7943
|
+
code: import_core24.CATALOG_ERROR_CODES.BUNDLE_VERSION_VALID_UNTIL_BEFORE_FROM,
|
|
7943
7944
|
message: `validUntil (${validUntil.toISOString()}) must be strictly after validFrom (${validFrom.toISOString()}).`,
|
|
7944
7945
|
params: {
|
|
7945
7946
|
validUntil: validUntil.toISOString(),
|
|
@@ -7953,7 +7954,7 @@ var BundlesService = class _BundlesService {
|
|
|
7953
7954
|
if (Number.isNaN(previousValidFrom.getTime())) return;
|
|
7954
7955
|
if (validFrom <= previousValidFrom) {
|
|
7955
7956
|
throw new import_common41.UnprocessableEntityException({
|
|
7956
|
-
code:
|
|
7957
|
+
code: import_core24.CATALOG_ERROR_CODES.BUNDLE_VERSION_VALID_FROM_NOT_AFTER_PREVIOUS,
|
|
7957
7958
|
message: `validFrom (${validFrom.toISOString()}) must be strictly after the validFrom of the previous version (${previous.validFrom}).`,
|
|
7958
7959
|
params: {
|
|
7959
7960
|
validFrom: validFrom.toISOString(),
|
|
@@ -7968,7 +7969,7 @@ var BundlesService = class _BundlesService {
|
|
|
7968
7969
|
const requiredStart = new Date(previousValidUntil.getTime() + dayMs);
|
|
7969
7970
|
if (validFrom.getTime() !== requiredStart.getTime()) {
|
|
7970
7971
|
throw new import_common41.UnprocessableEntityException({
|
|
7971
|
-
code:
|
|
7972
|
+
code: import_core24.CATALOG_ERROR_CODES.BUNDLE_VERSION_VALID_FROM_NOT_GAPLESS,
|
|
7972
7973
|
message: `The predecessor has validUntil=${previous.validUntil.slice(0, 10)} \u2014 the successor must start seamlessly on the next day (${requiredStart.toISOString().slice(0, 10)}). Received: ${validFrom.toISOString().slice(0, 10)}.`,
|
|
7973
7974
|
params: {
|
|
7974
7975
|
received: validFrom.toISOString().slice(0, 10)
|
|
@@ -8031,7 +8032,7 @@ BundlesService = _ts_decorate42([
|
|
|
8031
8032
|
|
|
8032
8033
|
// src/catalog/marketing-projections.service.ts
|
|
8033
8034
|
var import_common42 = require("@nestjs/common");
|
|
8034
|
-
var
|
|
8035
|
+
var import_core25 = require("@saasicat/core");
|
|
8035
8036
|
function _ts_decorate43(decorators, target, key, desc) {
|
|
8036
8037
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
8037
8038
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
@@ -8064,7 +8065,7 @@ var MarketingProjectionsService = class {
|
|
|
8064
8065
|
const row = await this.repo.findById(id);
|
|
8065
8066
|
if (!row) {
|
|
8066
8067
|
throw new import_common42.NotFoundException({
|
|
8067
|
-
code:
|
|
8068
|
+
code: import_core25.CATALOG_ERROR_CODES.MARKETING_PROJECTION_NOT_FOUND,
|
|
8068
8069
|
message: `MarketingProjection '${id}' not found`,
|
|
8069
8070
|
params: {
|
|
8070
8071
|
projectionId: id
|
|
@@ -8078,7 +8079,7 @@ var MarketingProjectionsService = class {
|
|
|
8078
8079
|
const existing = await this.repo.findByTarget(data.targetType, data.targetVersionId, locale);
|
|
8079
8080
|
if (existing) {
|
|
8080
8081
|
throw new import_common42.ConflictException({
|
|
8081
|
-
code:
|
|
8082
|
+
code: import_core25.CATALOG_ERROR_CODES.MARKETING_PROJECTION_ALREADY_EXISTS,
|
|
8082
8083
|
message: `Marketing projection for ${data.targetType}/${data.targetVersionId}/${locale} already exists \u2014 use PATCH to edit it`,
|
|
8083
8084
|
params: {
|
|
8084
8085
|
targetType: data.targetType,
|
|
@@ -8096,7 +8097,7 @@ var MarketingProjectionsService = class {
|
|
|
8096
8097
|
const existing = await this.repo.findById(id);
|
|
8097
8098
|
if (!existing) {
|
|
8098
8099
|
throw new import_common42.NotFoundException({
|
|
8099
|
-
code:
|
|
8100
|
+
code: import_core25.CATALOG_ERROR_CODES.MARKETING_PROJECTION_NOT_FOUND,
|
|
8100
8101
|
message: `MarketingProjection '${id}' not found`,
|
|
8101
8102
|
params: {
|
|
8102
8103
|
projectionId: id
|
|
@@ -8109,7 +8110,7 @@ var MarketingProjectionsService = class {
|
|
|
8109
8110
|
const existing = await this.repo.findById(id);
|
|
8110
8111
|
if (!existing) {
|
|
8111
8112
|
throw new import_common42.NotFoundException({
|
|
8112
|
-
code:
|
|
8113
|
+
code: import_core25.CATALOG_ERROR_CODES.MARKETING_PROJECTION_NOT_FOUND,
|
|
8113
8114
|
message: `MarketingProjection '${id}' not found`,
|
|
8114
8115
|
params: {
|
|
8115
8116
|
projectionId: id
|
|
@@ -8130,7 +8131,7 @@ MarketingProjectionsService = _ts_decorate43([
|
|
|
8130
8131
|
|
|
8131
8132
|
// src/catalog/catalog-entries.service.ts
|
|
8132
8133
|
var import_common43 = require("@nestjs/common");
|
|
8133
|
-
var
|
|
8134
|
+
var import_core26 = require("@saasicat/core");
|
|
8134
8135
|
|
|
8135
8136
|
// src/catalog/approval-signature.ts
|
|
8136
8137
|
function featureApprovalSignature(featureKey, snapshot) {
|
|
@@ -8281,7 +8282,7 @@ var CatalogEntriesService = class _CatalogEntriesService {
|
|
|
8281
8282
|
const existing = await this.repo.findFeature(projectKey, featureKey);
|
|
8282
8283
|
if (!existing) {
|
|
8283
8284
|
throw new import_common43.NotFoundException({
|
|
8284
|
-
code:
|
|
8285
|
+
code: import_core26.CATALOG_ERROR_CODES.FEATURE_NOT_FOUND,
|
|
8285
8286
|
message: `Feature '${featureKey}' not found in project '${projectKey}'`,
|
|
8286
8287
|
params: {
|
|
8287
8288
|
featureKey,
|
|
@@ -8296,7 +8297,7 @@ var CatalogEntriesService = class _CatalogEntriesService {
|
|
|
8296
8297
|
const existing = await this.repo.findQuota(projectKey, quotaKey);
|
|
8297
8298
|
if (!existing) {
|
|
8298
8299
|
throw new import_common43.NotFoundException({
|
|
8299
|
-
code:
|
|
8300
|
+
code: import_core26.CATALOG_ERROR_CODES.QUOTA_NOT_FOUND,
|
|
8300
8301
|
message: `Quota '${quotaKey}' not found in project '${projectKey}'`,
|
|
8301
8302
|
params: {
|
|
8302
8303
|
quotaKey,
|
|
@@ -8308,7 +8309,7 @@ var CatalogEntriesService = class _CatalogEntriesService {
|
|
|
8308
8309
|
const discovered = snapshot.quotas.find((q) => q.quotaKey === quotaKey);
|
|
8309
8310
|
if (!discovered) {
|
|
8310
8311
|
throw new import_common43.UnprocessableEntityException({
|
|
8311
|
-
code:
|
|
8312
|
+
code: import_core26.CATALOG_ERROR_CODES.QUOTA_NOT_IN_DISCOVERY_SNAPSHOT,
|
|
8312
8313
|
message: `Quota '${quotaKey}' is not in the discovery snapshot \u2014 a quota that is not declared in code cannot be approved`,
|
|
8313
8314
|
params: {
|
|
8314
8315
|
quotaKey
|
|
@@ -8321,7 +8322,7 @@ var CatalogEntriesService = class _CatalogEntriesService {
|
|
|
8321
8322
|
resolveReviewUpdate(existing, target, reviewedBy, signatureOf) {
|
|
8322
8323
|
if (!REVIEW_TRANSITIONS[existing.discoveryStatus].includes(target)) {
|
|
8323
8324
|
throw new import_common43.UnprocessableEntityException({
|
|
8324
|
-
code:
|
|
8325
|
+
code: import_core26.CATALOG_ERROR_CODES.DISCOVERY_STATUS_TRANSITION_INVALID,
|
|
8325
8326
|
message: `Transition '${existing.discoveryStatus}' \u2192 '${target}' is not allowed`,
|
|
8326
8327
|
params: {
|
|
8327
8328
|
from: existing.discoveryStatus,
|
|
@@ -8333,7 +8334,7 @@ var CatalogEntriesService = class _CatalogEntriesService {
|
|
|
8333
8334
|
const snapshot = resolveDiscoverySnapshot(this.snapshot, this.scanner);
|
|
8334
8335
|
if (!snapshot) {
|
|
8335
8336
|
throw new import_common43.UnprocessableEntityException({
|
|
8336
|
-
code:
|
|
8337
|
+
code: import_core26.CATALOG_ERROR_CODES.DISCOVERY_NOT_INITIALIZED,
|
|
8337
8338
|
message: "Approval requires a discovery snapshot \u2014 discovery is not initialised (#25)"
|
|
8338
8339
|
});
|
|
8339
8340
|
}
|
|
@@ -8562,7 +8563,7 @@ CatalogEntriesService = _ts_decorate44([
|
|
|
8562
8563
|
_ts_param30(3, (0, import_common43.Optional)()),
|
|
8563
8564
|
_ts_param30(3, (0, import_common43.Inject)(DiscoveryScanner)),
|
|
8564
8565
|
_ts_param30(4, (0, import_common43.Optional)()),
|
|
8565
|
-
_ts_param30(4, (0, import_common43.Inject)(
|
|
8566
|
+
_ts_param30(4, (0, import_common43.Inject)(CATALOG_FEATURE_UI_REGISTRY_TOKEN)),
|
|
8566
8567
|
_ts_metadata33("design:type", Function),
|
|
8567
8568
|
_ts_metadata33("design:paramtypes", [
|
|
8568
8569
|
typeof CatalogEntryRepository === "undefined" ? Object : CatalogEntryRepository,
|
|
@@ -9035,7 +9036,7 @@ __name(buildCatalogEntriesController, "buildCatalogEntriesController");
|
|
|
9035
9036
|
|
|
9036
9037
|
// src/catalog/promotions.service.ts
|
|
9037
9038
|
var import_common46 = require("@nestjs/common");
|
|
9038
|
-
var
|
|
9039
|
+
var import_core27 = require("@saasicat/core");
|
|
9039
9040
|
function _ts_decorate48(decorators, target, key, desc) {
|
|
9040
9041
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
9041
9042
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
@@ -9070,7 +9071,7 @@ var PromotionsService = class {
|
|
|
9070
9071
|
const row = await this.repo.findById(id);
|
|
9071
9072
|
if (!row) {
|
|
9072
9073
|
throw new import_common46.NotFoundException({
|
|
9073
|
-
code:
|
|
9074
|
+
code: import_core27.CATALOG_ERROR_CODES.PROMOTION_NOT_FOUND,
|
|
9074
9075
|
message: `Promotion '${id}' not found`,
|
|
9075
9076
|
params: {
|
|
9076
9077
|
promotionId: id
|
|
@@ -9086,7 +9087,7 @@ var PromotionsService = class {
|
|
|
9086
9087
|
const existing = await this.repo.findById(id);
|
|
9087
9088
|
if (!existing) {
|
|
9088
9089
|
throw new import_common46.NotFoundException({
|
|
9089
|
-
code:
|
|
9090
|
+
code: import_core27.CATALOG_ERROR_CODES.PROMOTION_NOT_FOUND,
|
|
9090
9091
|
message: `Promotion '${id}' not found`,
|
|
9091
9092
|
params: {
|
|
9092
9093
|
promotionId: id
|
|
@@ -9099,7 +9100,7 @@ var PromotionsService = class {
|
|
|
9099
9100
|
const existing = await this.repo.findById(id);
|
|
9100
9101
|
if (!existing) {
|
|
9101
9102
|
throw new import_common46.NotFoundException({
|
|
9102
|
-
code:
|
|
9103
|
+
code: import_core27.CATALOG_ERROR_CODES.PROMOTION_NOT_FOUND,
|
|
9103
9104
|
message: `Promotion '${id}' not found`,
|
|
9104
9105
|
params: {
|
|
9105
9106
|
promotionId: id
|
|
@@ -9658,7 +9659,7 @@ __name(buildMarketingSettingsController, "buildMarketingSettingsController");
|
|
|
9658
9659
|
|
|
9659
9660
|
// src/catalog/public-marketing-catalog.service.ts
|
|
9660
9661
|
var import_common50 = require("@nestjs/common");
|
|
9661
|
-
var
|
|
9662
|
+
var import_core28 = require("@saasicat/core");
|
|
9662
9663
|
function _ts_decorate54(decorators, target, key, desc) {
|
|
9663
9664
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
9664
9665
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
@@ -9761,7 +9762,7 @@ var PublicMarketingCatalogService = class {
|
|
|
9761
9762
|
});
|
|
9762
9763
|
}
|
|
9763
9764
|
out.sort((a, b) => b.priority - a.priority);
|
|
9764
|
-
const requiresIndex = (0,
|
|
9765
|
+
const requiresIndex = (0, import_core28.buildFeatureRequiresIndex)([
|
|
9765
9766
|
...labelMeta.features
|
|
9766
9767
|
].map(([featureKey, meta]) => ({
|
|
9767
9768
|
featureKey,
|
|
@@ -9815,7 +9816,7 @@ var PublicMarketingCatalogService = class {
|
|
|
9815
9816
|
const features = [
|
|
9816
9817
|
...bv.features ?? []
|
|
9817
9818
|
];
|
|
9818
|
-
const requiresFeatures = (0,
|
|
9819
|
+
const requiresFeatures = (0, import_core28.collectUnsatisfiedRequires)(features, requiresIndex);
|
|
9819
9820
|
return {
|
|
9820
9821
|
bundleKey: bv.bundleKey,
|
|
9821
9822
|
label: marketing?.displayLabel || bv.label,
|
|
@@ -9959,12 +9960,12 @@ var PublicMarketingCatalogService = class {
|
|
|
9959
9960
|
};
|
|
9960
9961
|
}
|
|
9961
9962
|
resolvePromo(promotions, targetKey, targetType, locale, monthlyNet, yearlyNet, asOf) {
|
|
9962
|
-
const monthlyPromo = (0,
|
|
9963
|
-
const yearlyPromo = (0,
|
|
9963
|
+
const monthlyPromo = (0, import_core28.pickActivePromo)(promotions, targetKey, locale, "monthly", asOf, targetType);
|
|
9964
|
+
const yearlyPromo = (0, import_core28.pickActivePromo)(promotions, targetKey, locale, "yearly", asOf, targetType);
|
|
9964
9965
|
const promo = monthlyPromo ?? yearlyPromo;
|
|
9965
9966
|
if (!promo) return null;
|
|
9966
|
-
const monthlyResult = (0,
|
|
9967
|
-
const yearlyResult = (0,
|
|
9967
|
+
const monthlyResult = (0, import_core28.applyPromo)(monthlyPromo, monthlyNet);
|
|
9968
|
+
const yearlyResult = (0, import_core28.applyPromo)(yearlyPromo, yearlyNet);
|
|
9968
9969
|
const i18n = promo.i18n?.[locale] ?? promo.i18n?.[DEFAULT_LOCALE] ?? {};
|
|
9969
9970
|
return {
|
|
9970
9971
|
type: promo.type,
|
|
@@ -10071,7 +10072,7 @@ __name(parseAsOf, "parseAsOf");
|
|
|
10071
10072
|
|
|
10072
10073
|
// src/catalog/plans.service.ts
|
|
10073
10074
|
var import_common52 = require("@nestjs/common");
|
|
10074
|
-
var
|
|
10075
|
+
var import_core29 = require("@saasicat/core");
|
|
10075
10076
|
function _ts_decorate56(decorators, target, key, desc) {
|
|
10076
10077
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
10077
10078
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
@@ -10120,7 +10121,7 @@ var PlansService = class {
|
|
|
10120
10121
|
const plan = await this.repo.findById(planId);
|
|
10121
10122
|
if (!plan) {
|
|
10122
10123
|
throw new import_common52.NotFoundException({
|
|
10123
|
-
code:
|
|
10124
|
+
code: import_core29.CATALOG_ERROR_CODES.PLAN_NOT_FOUND,
|
|
10124
10125
|
message: `Plan '${planId}' not found`,
|
|
10125
10126
|
params: {
|
|
10126
10127
|
planId
|
|
@@ -10133,7 +10134,7 @@ var PlansService = class {
|
|
|
10133
10134
|
const existing = await this.repo.findByKey(data.projectKey, data.planKey);
|
|
10134
10135
|
if (existing) {
|
|
10135
10136
|
throw new import_common52.UnprocessableEntityException({
|
|
10136
|
-
code:
|
|
10137
|
+
code: import_core29.CATALOG_ERROR_CODES.PLAN_ALREADY_EXISTS,
|
|
10137
10138
|
message: `Plan '${data.planKey}' already exists in project '${data.projectKey}'`,
|
|
10138
10139
|
params: {
|
|
10139
10140
|
planKey: data.planKey,
|
|
@@ -10147,7 +10148,7 @@ var PlansService = class {
|
|
|
10147
10148
|
const existing = await this.repo.findById(planId);
|
|
10148
10149
|
if (!existing) {
|
|
10149
10150
|
throw new import_common52.NotFoundException({
|
|
10150
|
-
code:
|
|
10151
|
+
code: import_core29.CATALOG_ERROR_CODES.PLAN_NOT_FOUND,
|
|
10151
10152
|
message: `Plan '${planId}' not found`,
|
|
10152
10153
|
params: {
|
|
10153
10154
|
planId
|
|
@@ -10160,7 +10161,7 @@ var PlansService = class {
|
|
|
10160
10161
|
const existing = await this.repo.findById(planId);
|
|
10161
10162
|
if (!existing) {
|
|
10162
10163
|
throw new import_common52.NotFoundException({
|
|
10163
|
-
code:
|
|
10164
|
+
code: import_core29.CATALOG_ERROR_CODES.PLAN_NOT_FOUND,
|
|
10164
10165
|
message: `Plan '${planId}' not found`,
|
|
10165
10166
|
params: {
|
|
10166
10167
|
planId
|
|
@@ -10185,7 +10186,7 @@ var PlansService = class {
|
|
|
10185
10186
|
const existing = await this.repo.findById(planId);
|
|
10186
10187
|
if (!existing) {
|
|
10187
10188
|
throw new import_common52.NotFoundException({
|
|
10188
|
-
code:
|
|
10189
|
+
code: import_core29.CATALOG_ERROR_CODES.PLAN_NOT_FOUND,
|
|
10189
10190
|
message: `Plan '${planId}' not found`,
|
|
10190
10191
|
params: {
|
|
10191
10192
|
planId
|
|
@@ -10196,7 +10197,7 @@ var PlansService = class {
|
|
|
10196
10197
|
await this.assertNoDrafts(existing.planKey);
|
|
10197
10198
|
if (typeof this.repo.hardDelete !== "function") {
|
|
10198
10199
|
throw new import_common52.UnprocessableEntityException({
|
|
10199
|
-
code:
|
|
10200
|
+
code: import_core29.CATALOG_ERROR_CODES.PLAN_HARD_DELETE_NOT_IMPLEMENTED,
|
|
10200
10201
|
message: "Hard delete is not implemented in the current repository. Implement PlanRepository.hardDelete."
|
|
10201
10202
|
});
|
|
10202
10203
|
}
|
|
@@ -10217,7 +10218,7 @@ var PlansService = class {
|
|
|
10217
10218
|
const live = published.filter((v) => v.supersededAt === null).length;
|
|
10218
10219
|
const superseded = published.length - live;
|
|
10219
10220
|
throw new import_common52.UnprocessableEntityException({
|
|
10220
|
-
code:
|
|
10221
|
+
code: import_core29.CATALOG_ERROR_CODES.PLAN_HAS_PUBLISHED_VERSIONS,
|
|
10221
10222
|
message: `Plan '${planKey}' cannot be ${op === "hard-delete" ? "deleted" : "archived"} \u2014 it has ${published.length} published version(s) (${live} live, ${superseded} superseded). Existing subscriptions reference those versions (contract protection P1), so the plan record must be preserved.`,
|
|
10222
10223
|
params: {
|
|
10223
10224
|
planKey,
|
|
@@ -10234,7 +10235,7 @@ var PlansService = class {
|
|
|
10234
10235
|
const drafts = versions.filter((v) => v.publishedAt === null);
|
|
10235
10236
|
if (drafts.length === 0) return;
|
|
10236
10237
|
throw new import_common52.UnprocessableEntityException({
|
|
10237
|
-
code:
|
|
10238
|
+
code: import_core29.CATALOG_ERROR_CODES.PLAN_HAS_DRAFTS,
|
|
10238
10239
|
message: `Plan '${planKey}' still has ${drafts.length} open draft version(s). Discard them first (DELETE /admin/catalog/plan-versions/:id) or publish them.`,
|
|
10239
10240
|
params: {
|
|
10240
10241
|
planKey
|
|
@@ -10257,7 +10258,7 @@ PlansService = _ts_decorate56([
|
|
|
10257
10258
|
|
|
10258
10259
|
// src/catalog/plan-versions.service.ts
|
|
10259
10260
|
var import_common53 = require("@nestjs/common");
|
|
10260
|
-
var
|
|
10261
|
+
var import_core30 = require("@saasicat/core");
|
|
10261
10262
|
function _ts_decorate57(decorators, target, key, desc) {
|
|
10262
10263
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
10263
10264
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
@@ -10327,7 +10328,7 @@ var PlanVersionsService = class _PlanVersionsService {
|
|
|
10327
10328
|
const existing = await this.repo.findVersionById(versionId);
|
|
10328
10329
|
if (!existing) {
|
|
10329
10330
|
throw new import_common53.NotFoundException({
|
|
10330
|
-
code:
|
|
10331
|
+
code: import_core30.CATALOG_ERROR_CODES.PLAN_VERSION_NOT_FOUND,
|
|
10331
10332
|
message: `PlanVersion '${versionId}' not found`,
|
|
10332
10333
|
params: {
|
|
10333
10334
|
versionId
|
|
@@ -10336,7 +10337,7 @@ var PlanVersionsService = class _PlanVersionsService {
|
|
|
10336
10337
|
}
|
|
10337
10338
|
if (existing.publishedAt !== null) {
|
|
10338
10339
|
throw new import_common53.UnprocessableEntityException({
|
|
10339
|
-
code:
|
|
10340
|
+
code: import_core30.CATALOG_ERROR_CODES.PLAN_VERSION_ALREADY_PUBLISHED,
|
|
10340
10341
|
message: `PlanVersion '${versionId}' is already published and cannot be discarded.`,
|
|
10341
10342
|
params: {
|
|
10342
10343
|
versionId
|
|
@@ -10345,7 +10346,7 @@ var PlanVersionsService = class _PlanVersionsService {
|
|
|
10345
10346
|
}
|
|
10346
10347
|
if (typeof this.repo.deletePlanVersionDraft !== "function") {
|
|
10347
10348
|
throw new import_common53.UnprocessableEntityException({
|
|
10348
|
-
code:
|
|
10349
|
+
code: import_core30.CATALOG_ERROR_CODES.PLAN_VERSION_DISCARD_NOT_IMPLEMENTED,
|
|
10349
10350
|
message: "Discard is not implemented in the current repository. Implement PlanRepository.deletePlanVersionDraft."
|
|
10350
10351
|
});
|
|
10351
10352
|
}
|
|
@@ -10360,7 +10361,7 @@ var PlanVersionsService = class _PlanVersionsService {
|
|
|
10360
10361
|
const plan = await this.repo.findById(planUuid);
|
|
10361
10362
|
if (!plan) {
|
|
10362
10363
|
throw new import_common53.NotFoundException({
|
|
10363
|
-
code:
|
|
10364
|
+
code: import_core30.CATALOG_ERROR_CODES.PLAN_NOT_FOUND,
|
|
10364
10365
|
message: `Plan '${planUuid}' not found`,
|
|
10365
10366
|
params: {
|
|
10366
10367
|
planId: planUuid
|
|
@@ -10374,7 +10375,7 @@ var PlanVersionsService = class _PlanVersionsService {
|
|
|
10374
10375
|
const version = await this.repo.findVersionById(versionId);
|
|
10375
10376
|
if (!version) {
|
|
10376
10377
|
throw new import_common53.NotFoundException({
|
|
10377
|
-
code:
|
|
10378
|
+
code: import_core30.CATALOG_ERROR_CODES.PLAN_VERSION_NOT_FOUND,
|
|
10378
10379
|
message: `PlanVersion '${versionId}' not found`,
|
|
10379
10380
|
params: {
|
|
10380
10381
|
versionId
|
|
@@ -10418,7 +10419,7 @@ var PlanVersionsService = class _PlanVersionsService {
|
|
|
10418
10419
|
const plan = await this.repo.findById(data.planId);
|
|
10419
10420
|
if (!plan) {
|
|
10420
10421
|
throw new import_common53.NotFoundException({
|
|
10421
|
-
code:
|
|
10422
|
+
code: import_core30.CATALOG_ERROR_CODES.PLAN_NOT_FOUND,
|
|
10422
10423
|
message: `Plan '${data.planId}' not found`,
|
|
10423
10424
|
params: {
|
|
10424
10425
|
planId: data.planId
|
|
@@ -10429,7 +10430,7 @@ var PlanVersionsService = class _PlanVersionsService {
|
|
|
10429
10430
|
const existingDraft = await this.repo.findCurrentDraft(planKey);
|
|
10430
10431
|
if (existingDraft) {
|
|
10431
10432
|
throw new import_common53.UnprocessableEntityException({
|
|
10432
|
-
code:
|
|
10433
|
+
code: import_core30.CATALOG_ERROR_CODES.PLAN_DRAFT_ALREADY_EXISTS,
|
|
10433
10434
|
message: `Plan '${planKey}' already has a draft version v${existingDraft.version}; publish or discard it first`,
|
|
10434
10435
|
params: {
|
|
10435
10436
|
planKey,
|
|
@@ -10461,7 +10462,7 @@ var PlanVersionsService = class _PlanVersionsService {
|
|
|
10461
10462
|
const existing = await this.repo.findVersionById(versionId);
|
|
10462
10463
|
if (!existing) {
|
|
10463
10464
|
throw new import_common53.NotFoundException({
|
|
10464
|
-
code:
|
|
10465
|
+
code: import_core30.CATALOG_ERROR_CODES.PLAN_VERSION_NOT_FOUND,
|
|
10465
10466
|
message: `PlanVersion '${versionId}' not found`,
|
|
10466
10467
|
params: {
|
|
10467
10468
|
versionId
|
|
@@ -10471,10 +10472,10 @@ var PlanVersionsService = class _PlanVersionsService {
|
|
|
10471
10472
|
const [annotated] = await this.annotateEditability([
|
|
10472
10473
|
existing
|
|
10473
10474
|
]);
|
|
10474
|
-
const { editable } = (0,
|
|
10475
|
+
const { editable } = (0, import_core30.isVersionEditable)(annotated);
|
|
10475
10476
|
if (!editable) {
|
|
10476
10477
|
throw new import_common53.UnprocessableEntityException({
|
|
10477
|
-
code:
|
|
10478
|
+
code: import_core30.CATALOG_ERROR_CODES.PLAN_VERSION_NOT_EDITABLE,
|
|
10478
10479
|
message: `PlanVersion '${versionId}' is not editable. Only drafts and published versions are editable that are latest-in-chain, bind no subscription yet, and whose validFrom lies in the future.`,
|
|
10479
10480
|
params: {
|
|
10480
10481
|
versionId
|
|
@@ -10497,7 +10498,7 @@ var PlanVersionsService = class _PlanVersionsService {
|
|
|
10497
10498
|
const draft = await this.repo.findVersionById(versionId);
|
|
10498
10499
|
if (!draft) {
|
|
10499
10500
|
throw new import_common53.NotFoundException({
|
|
10500
|
-
code:
|
|
10501
|
+
code: import_core30.CATALOG_ERROR_CODES.PLAN_VERSION_NOT_FOUND,
|
|
10501
10502
|
message: `PlanVersion '${versionId}' not found`,
|
|
10502
10503
|
params: {
|
|
10503
10504
|
versionId
|
|
@@ -10506,7 +10507,7 @@ var PlanVersionsService = class _PlanVersionsService {
|
|
|
10506
10507
|
}
|
|
10507
10508
|
if (draft.publishedAt !== null) {
|
|
10508
10509
|
throw new import_common53.UnprocessableEntityException({
|
|
10509
|
-
code:
|
|
10510
|
+
code: import_core30.CATALOG_ERROR_CODES.PLAN_VERSION_ALREADY_PUBLISHED,
|
|
10510
10511
|
message: `PlanVersion '${versionId}' is already published`,
|
|
10511
10512
|
params: {
|
|
10512
10513
|
versionId
|
|
@@ -10523,7 +10524,7 @@ var PlanVersionsService = class _PlanVersionsService {
|
|
|
10523
10524
|
const yearly = Number.parseFloat(String(draft.yearlyNet ?? "0"));
|
|
10524
10525
|
if (monthly <= 0 || yearly <= 0) {
|
|
10525
10526
|
throw new import_common53.UnprocessableEntityException({
|
|
10526
|
-
code:
|
|
10527
|
+
code: import_core30.CATALOG_ERROR_CODES.PLAN_VERSION_ZERO_PRICE,
|
|
10527
10528
|
message: "A plan version cannot be published with a price of 0.00 (guard against seed placeholder). For deliberately free special contracts, set allowZeroPrice.",
|
|
10528
10529
|
monthlyNet: String(draft.monthlyNet),
|
|
10529
10530
|
yearlyNet: String(draft.yearlyNet)
|
|
@@ -10534,14 +10535,14 @@ var PlanVersionsService = class _PlanVersionsService {
|
|
|
10534
10535
|
const validFromInput = publishMeta.validFrom ?? draft.validFrom;
|
|
10535
10536
|
if (!validFromInput) {
|
|
10536
10537
|
throw new import_common53.UnprocessableEntityException({
|
|
10537
|
-
code:
|
|
10538
|
+
code: import_core30.CATALOG_ERROR_CODES.PLAN_VERSION_VALID_FROM_REQUIRED,
|
|
10538
10539
|
message: "validFrom must be set when publishing (on the draft or the publish call).."
|
|
10539
10540
|
});
|
|
10540
10541
|
}
|
|
10541
10542
|
const validFrom = new Date(validFromInput);
|
|
10542
10543
|
if (Number.isNaN(validFrom.getTime())) {
|
|
10543
10544
|
throw new import_common53.UnprocessableEntityException({
|
|
10544
|
-
code:
|
|
10545
|
+
code: import_core30.CATALOG_ERROR_CODES.PLAN_VERSION_VALID_FROM_INVALID,
|
|
10545
10546
|
message: `validFrom '${validFromInput}' is not a valid date`,
|
|
10546
10547
|
params: {
|
|
10547
10548
|
validFrom: validFromInput
|
|
@@ -10552,7 +10553,7 @@ var PlanVersionsService = class _PlanVersionsService {
|
|
|
10552
10553
|
const prevFrom = new Date(previous.validFrom);
|
|
10553
10554
|
if (validFrom <= prevFrom) {
|
|
10554
10555
|
throw new import_common53.UnprocessableEntityException({
|
|
10555
|
-
code:
|
|
10556
|
+
code: import_core30.CATALOG_ERROR_CODES.PLAN_VERSION_VALID_FROM_NOT_AFTER_PREVIOUS,
|
|
10556
10557
|
message: `validFrom (${validFrom.toISOString()}) must be strictly after the validFrom of the previous version (${previous.validFrom}).`,
|
|
10557
10558
|
params: {
|
|
10558
10559
|
validFrom: validFrom.toISOString(),
|
|
@@ -10566,7 +10567,7 @@ var PlanVersionsService = class _PlanVersionsService {
|
|
|
10566
10567
|
const requiredStart = new Date(prevUntil.getTime() + dayMs);
|
|
10567
10568
|
if (validFrom.getTime() !== requiredStart.getTime()) {
|
|
10568
10569
|
throw new import_common53.UnprocessableEntityException({
|
|
10569
|
-
code:
|
|
10570
|
+
code: import_core30.CATALOG_ERROR_CODES.PLAN_VERSION_VALID_FROM_NOT_GAPLESS,
|
|
10570
10571
|
message: `The predecessor has validUntil=${previous.validUntil.slice(0, 10)} \u2014 the successor must start seamlessly on the next day (${requiredStart.toISOString().slice(0, 10)}). Received: ${validFrom.toISOString().slice(0, 10)}.`,
|
|
10571
10572
|
params: {
|
|
10572
10573
|
received: validFrom.toISOString().slice(0, 10)
|
|
@@ -10581,7 +10582,7 @@ var PlanVersionsService = class _PlanVersionsService {
|
|
|
10581
10582
|
const validUntil = validUntilInput ? new Date(validUntilInput) : null;
|
|
10582
10583
|
if (validUntil && Number.isNaN(validUntil.getTime())) {
|
|
10583
10584
|
throw new import_common53.UnprocessableEntityException({
|
|
10584
|
-
code:
|
|
10585
|
+
code: import_core30.CATALOG_ERROR_CODES.PLAN_VERSION_VALID_UNTIL_INVALID,
|
|
10585
10586
|
message: `validUntil '${validUntilInput}' is not a valid date`,
|
|
10586
10587
|
params: {
|
|
10587
10588
|
validUntil: validUntilInput
|
|
@@ -10590,7 +10591,7 @@ var PlanVersionsService = class _PlanVersionsService {
|
|
|
10590
10591
|
}
|
|
10591
10592
|
if (validUntil && validUntil <= validFrom) {
|
|
10592
10593
|
throw new import_common53.UnprocessableEntityException({
|
|
10593
|
-
code:
|
|
10594
|
+
code: import_core30.CATALOG_ERROR_CODES.PLAN_VERSION_VALID_UNTIL_BEFORE_FROM,
|
|
10594
10595
|
message: `validUntil (${validUntil.toISOString()}) must be strictly after validFrom (${validFrom.toISOString()}).`,
|
|
10595
10596
|
params: {
|
|
10596
10597
|
validUntil: validUntil.toISOString(),
|
|
@@ -10606,13 +10607,13 @@ var PlanVersionsService = class _PlanVersionsService {
|
|
|
10606
10607
|
monthlyNet: v.monthlyNet,
|
|
10607
10608
|
yearlyNet: v.yearlyNet
|
|
10608
10609
|
}), "fieldsFor");
|
|
10609
|
-
const diff = previous ? (0,
|
|
10610
|
+
const diff = previous ? (0, import_core6.classifyPlanDiff)(fieldsFor(previous), fieldsFor(draft)) : {
|
|
10610
10611
|
changes: [],
|
|
10611
10612
|
nonRegressive: true
|
|
10612
10613
|
};
|
|
10613
10614
|
if (!diff.nonRegressive && !publishMeta.forceRegressive) {
|
|
10614
10615
|
throw new import_common53.UnprocessableEntityException({
|
|
10615
|
-
code:
|
|
10616
|
+
code: import_core30.CATALOG_ERROR_CODES.PLAN_VERSION_REGRESSION,
|
|
10616
10617
|
message: "This plan version is regressive (feature removed / quota lowered / price raised). Publishing requires an explicit `forceRegressive: true` (UI confirmation dialog with MFA).",
|
|
10617
10618
|
changes: diff.changes
|
|
10618
10619
|
});
|
|
@@ -10649,7 +10650,7 @@ var PlanVersionsService = class _PlanVersionsService {
|
|
|
10649
10650
|
const existing = await this.repo.findVersionById(versionId);
|
|
10650
10651
|
if (!existing) {
|
|
10651
10652
|
throw new import_common53.NotFoundException({
|
|
10652
|
-
code:
|
|
10653
|
+
code: import_core30.CATALOG_ERROR_CODES.PLAN_VERSION_NOT_FOUND,
|
|
10653
10654
|
message: `PlanVersion '${versionId}' not found`,
|
|
10654
10655
|
params: {
|
|
10655
10656
|
versionId
|
|
@@ -10658,7 +10659,7 @@ var PlanVersionsService = class _PlanVersionsService {
|
|
|
10658
10659
|
}
|
|
10659
10660
|
if (existing.publishedAt === null) {
|
|
10660
10661
|
throw new import_common53.UnprocessableEntityException({
|
|
10661
|
-
code:
|
|
10662
|
+
code: import_core30.CATALOG_ERROR_CODES.PLAN_VERSION_NOT_PUBLISHED,
|
|
10662
10663
|
message: `PlanVersion '${versionId}' is not published and cannot be terminated.`,
|
|
10663
10664
|
params: {
|
|
10664
10665
|
versionId
|
|
@@ -10667,7 +10668,7 @@ var PlanVersionsService = class _PlanVersionsService {
|
|
|
10667
10668
|
}
|
|
10668
10669
|
if (existing.supersededAt !== null) {
|
|
10669
10670
|
throw new import_common53.UnprocessableEntityException({
|
|
10670
|
-
code:
|
|
10671
|
+
code: import_core30.CATALOG_ERROR_CODES.PLAN_VERSION_SUPERSEDED,
|
|
10671
10672
|
message: `PlanVersion '${versionId}' has already been superseded by a newer version (supersededAt) and cannot be terminated.`,
|
|
10672
10673
|
params: {
|
|
10673
10674
|
versionId
|
|
@@ -10676,13 +10677,13 @@ var PlanVersionsService = class _PlanVersionsService {
|
|
|
10676
10677
|
}
|
|
10677
10678
|
if (Number.isNaN(endsAt.getTime())) {
|
|
10678
10679
|
throw new import_common53.UnprocessableEntityException({
|
|
10679
|
-
code:
|
|
10680
|
+
code: import_core30.CATALOG_ERROR_CODES.PLAN_TERMINATE_INVALID_DATE,
|
|
10680
10681
|
message: "endsAt is not a valid date."
|
|
10681
10682
|
});
|
|
10682
10683
|
}
|
|
10683
10684
|
if (endsAt.getTime() <= Date.now()) {
|
|
10684
10685
|
throw new import_common53.UnprocessableEntityException({
|
|
10685
|
-
code:
|
|
10686
|
+
code: import_core30.CATALOG_ERROR_CODES.PLAN_TERMINATE_DATE_NOT_FUTURE,
|
|
10686
10687
|
message: `endsAt (${endsAt.toISOString()}) must lie strictly in the future.`,
|
|
10687
10688
|
params: {
|
|
10688
10689
|
endsAt: endsAt.toISOString()
|
|
@@ -10691,7 +10692,7 @@ var PlanVersionsService = class _PlanVersionsService {
|
|
|
10691
10692
|
}
|
|
10692
10693
|
if (typeof this.repo.terminate !== "function") {
|
|
10693
10694
|
throw new import_common53.UnprocessableEntityException({
|
|
10694
|
-
code:
|
|
10695
|
+
code: import_core30.CATALOG_ERROR_CODES.PLAN_TERMINATE_NOT_IMPLEMENTED,
|
|
10695
10696
|
message: "Terminate is not implemented in the current repository. Implement PlanRepository.terminate."
|
|
10696
10697
|
});
|
|
10697
10698
|
}
|
|
@@ -10710,7 +10711,7 @@ var PlanVersionsService = class _PlanVersionsService {
|
|
|
10710
10711
|
if (blockingStrictModeWarnings(warnings).length === 0) return;
|
|
10711
10712
|
if (this.mode === "blocking") {
|
|
10712
10713
|
throw new import_common53.UnprocessableEntityException({
|
|
10713
|
-
code:
|
|
10714
|
+
code: import_core30.CATALOG_ERROR_CODES.STRICT_MODE_VIOLATIONS,
|
|
10714
10715
|
message: "The strict-mode check found drift against the discovery snapshot.",
|
|
10715
10716
|
warnings
|
|
10716
10717
|
});
|
|
@@ -12381,7 +12382,7 @@ var CatalogModule = class _CatalogModule {
|
|
|
12381
12382
|
}
|
|
12382
12383
|
},
|
|
12383
12384
|
{
|
|
12384
|
-
provide:
|
|
12385
|
+
provide: CATALOG_FEATURE_UI_REGISTRY_TOKEN,
|
|
12385
12386
|
useValue: options.featureUiRegistry ?? null
|
|
12386
12387
|
},
|
|
12387
12388
|
BundlesService,
|
|
@@ -12657,10 +12658,10 @@ __export(checkout_offer_exports, {
|
|
|
12657
12658
|
|
|
12658
12659
|
// src/checkout-offer/checkout-offer.service.ts
|
|
12659
12660
|
var import_common58 = require("@nestjs/common");
|
|
12660
|
-
var
|
|
12661
|
+
var import_core31 = require("@saasicat/core");
|
|
12661
12662
|
|
|
12662
|
-
// src/checkout-offer/tokens.ts
|
|
12663
|
-
var CHECKOUT_OFFER_REPOSITORY_TOKEN = /* @__PURE__ */ Symbol.for("
|
|
12663
|
+
// src/checkout-offer/checkout-offer.tokens.ts
|
|
12664
|
+
var CHECKOUT_OFFER_REPOSITORY_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/nest/CheckoutOfferRepository");
|
|
12664
12665
|
|
|
12665
12666
|
// src/checkout-offer/checkout-offer.service.ts
|
|
12666
12667
|
function _ts_decorate66(decorators, target, key, desc) {
|
|
@@ -12701,7 +12702,7 @@ var CheckoutOfferService = class {
|
|
|
12701
12702
|
const row = await this.repo.findById(id);
|
|
12702
12703
|
if (!row) {
|
|
12703
12704
|
throw new import_common58.NotFoundException({
|
|
12704
|
-
code:
|
|
12705
|
+
code: import_core31.CONTRACT_ERROR_CODES.CHECKOUT_OFFER_NOT_FOUND,
|
|
12705
12706
|
message: `CheckoutOffer '${id}' not found`,
|
|
12706
12707
|
params: {
|
|
12707
12708
|
offerId: id
|
|
@@ -12760,18 +12761,18 @@ var CheckoutOfferService = class {
|
|
|
12760
12761
|
const entries = await this.catalogEntries.listFeatures({
|
|
12761
12762
|
projectKey: input.projectKey
|
|
12762
12763
|
});
|
|
12763
|
-
const requiresIndex = (0,
|
|
12764
|
+
const requiresIndex = (0, import_core31.buildFeatureRequiresIndex)(entries);
|
|
12764
12765
|
if (requiresIndex.size === 0) return;
|
|
12765
12766
|
const selected = /* @__PURE__ */ new Set([
|
|
12766
12767
|
...await this.resolvePlanFeatures(input),
|
|
12767
12768
|
...await this.resolveBundleFeatures(input)
|
|
12768
12769
|
]);
|
|
12769
|
-
const missingRequires = (0,
|
|
12770
|
+
const missingRequires = (0, import_core31.collectUnsatisfiedRequires)([
|
|
12770
12771
|
...selected
|
|
12771
12772
|
], requiresIndex);
|
|
12772
12773
|
if (missingRequires.length > 0) {
|
|
12773
12774
|
throw new import_common58.UnprocessableEntityException({
|
|
12774
|
-
code:
|
|
12775
|
+
code: import_core31.CONTRACT_ERROR_CODES.CHECKOUT_OFFER_FEATURE_DEPENDENCY_UNSATISFIED,
|
|
12775
12776
|
message: `The selected plan does not cover all feature dependencies: [${missingRequires.join(", ")}] are missing from the plan + selected bundles.`,
|
|
12776
12777
|
missingRequires
|
|
12777
12778
|
});
|
|
@@ -12852,7 +12853,7 @@ var CheckoutOfferService = class {
|
|
|
12852
12853
|
}
|
|
12853
12854
|
if (violations.length > 0) {
|
|
12854
12855
|
throw new import_common58.UnprocessableEntityException({
|
|
12855
|
-
code:
|
|
12856
|
+
code: import_core31.CONTRACT_ERROR_CODES.CHECKOUT_OFFER_BUNDLE_VERSION_NOT_BOOKABLE,
|
|
12856
12857
|
message: "At least one bundle version from the checkout offer is no longer bookable.",
|
|
12857
12858
|
violations
|
|
12858
12859
|
});
|
|
@@ -12907,14 +12908,14 @@ var CheckoutOfferService = class {
|
|
|
12907
12908
|
const hasPlan = lineItems.some((item) => item.kind === "plan");
|
|
12908
12909
|
if (!hasPlan) {
|
|
12909
12910
|
throw new import_common58.UnprocessableEntityException({
|
|
12910
|
-
code:
|
|
12911
|
+
code: import_core31.CONTRACT_ERROR_CODES.CHECKOUT_OFFER_PLAN_LINE_ITEM_REQUIRED,
|
|
12911
12912
|
message: "A checkout offer requires a frozen plan line item."
|
|
12912
12913
|
});
|
|
12913
12914
|
}
|
|
12914
12915
|
const missingBundleVersionIds = input.bundleVersionIds.filter((versionId) => !lineItems.some((item) => item.kind === "bundle" && item.sourceVersionId === versionId));
|
|
12915
12916
|
if (missingBundleVersionIds.length > 0) {
|
|
12916
12917
|
throw new import_common58.UnprocessableEntityException({
|
|
12917
|
-
code:
|
|
12918
|
+
code: import_core31.CONTRACT_ERROR_CODES.CHECKOUT_OFFER_BUNDLE_LINE_ITEMS_REQUIRED,
|
|
12918
12919
|
message: "Every selected bundle version requires a frozen bundle line item.",
|
|
12919
12920
|
bundleVersionIds: missingBundleVersionIds
|
|
12920
12921
|
});
|
|
@@ -12948,7 +12949,7 @@ var CheckoutOfferService = class {
|
|
|
12948
12949
|
assertOpen(existing, action) {
|
|
12949
12950
|
if (existing.status === "consumed") {
|
|
12950
12951
|
throw new import_common58.ConflictException({
|
|
12951
|
-
code:
|
|
12952
|
+
code: import_core31.CONTRACT_ERROR_CODES.CHECKOUT_OFFER_ALREADY_CONSUMED,
|
|
12952
12953
|
message: `Checkout offer '${existing.id}' has already been consumed and cannot be ${action}`,
|
|
12953
12954
|
params: {
|
|
12954
12955
|
offerId: existing.id,
|
|
@@ -12958,7 +12959,7 @@ var CheckoutOfferService = class {
|
|
|
12958
12959
|
}
|
|
12959
12960
|
if (existing.status === "expired") {
|
|
12960
12961
|
throw new import_common58.ConflictException({
|
|
12961
|
-
code:
|
|
12962
|
+
code: import_core31.CONTRACT_ERROR_CODES.CHECKOUT_OFFER_EXPIRED,
|
|
12962
12963
|
message: `Checkout offer '${existing.id}' has expired and cannot be ${action}`,
|
|
12963
12964
|
params: {
|
|
12964
12965
|
offerId: existing.id,
|
|
@@ -12969,7 +12970,7 @@ var CheckoutOfferService = class {
|
|
|
12969
12970
|
}
|
|
12970
12971
|
if (this.isExpired(existing)) {
|
|
12971
12972
|
throw new import_common58.ConflictException({
|
|
12972
|
-
code:
|
|
12973
|
+
code: import_core31.CONTRACT_ERROR_CODES.CHECKOUT_OFFER_EXPIRED,
|
|
12973
12974
|
message: `CheckoutOffer '${existing.id}' has expired and cannot be ${action}`,
|
|
12974
12975
|
params: {
|
|
12975
12976
|
offerId: existing.id,
|
|
@@ -12994,7 +12995,7 @@ var CheckoutOfferService = class {
|
|
|
12994
12995
|
if (!value) return false;
|
|
12995
12996
|
const validUntil = new Date(value).getTime();
|
|
12996
12997
|
if (Number.isNaN(validUntil)) return true;
|
|
12997
|
-
return validUntil < (0,
|
|
12998
|
+
return validUntil < (0, import_core31.startOfUtcDay)(new Date(nowMs)).getTime();
|
|
12998
12999
|
}
|
|
12999
13000
|
};
|
|
13000
13001
|
CheckoutOfferService = _ts_decorate66([
|
|
@@ -13387,7 +13388,7 @@ var EnforceQuota = /* @__PURE__ */ __name((quotaKey, options = {}) => (0, import
|
|
|
13387
13388
|
|
|
13388
13389
|
// src/discovery/discovery.module.ts
|
|
13389
13390
|
var import_common63 = require("@nestjs/common");
|
|
13390
|
-
var
|
|
13391
|
+
var import_core32 = require("@nestjs/core");
|
|
13391
13392
|
|
|
13392
13393
|
// src/discovery/discovery.controller.ts
|
|
13393
13394
|
var import_common62 = require("@nestjs/common");
|
|
@@ -13511,7 +13512,7 @@ var DiscoveryModule = class _DiscoveryModule {
|
|
|
13511
13512
|
return {
|
|
13512
13513
|
module: _DiscoveryModule,
|
|
13513
13514
|
imports: [
|
|
13514
|
-
|
|
13515
|
+
import_core32.DiscoveryModule,
|
|
13515
13516
|
...options.imports ?? []
|
|
13516
13517
|
],
|
|
13517
13518
|
controllers,
|
|
@@ -13529,11 +13530,11 @@ DiscoveryModule = _ts_decorate71([
|
|
|
13529
13530
|
], DiscoveryModule);
|
|
13530
13531
|
|
|
13531
13532
|
// src/discovery/headless-scan.ts
|
|
13532
|
-
var
|
|
13533
|
+
var import_core33 = require("@nestjs/core");
|
|
13533
13534
|
async function runHeadlessDiscoveryScan(appModule, options = {}) {
|
|
13534
13535
|
const exit = options.exit ?? ((code) => process.exit(code));
|
|
13535
13536
|
try {
|
|
13536
|
-
const app = await
|
|
13537
|
+
const app = await import_core33.NestFactory.createApplicationContext(appModule, {
|
|
13537
13538
|
logger: options.logger ?? [
|
|
13538
13539
|
"error",
|
|
13539
13540
|
"warn",
|
|
@@ -13594,7 +13595,7 @@ __export(entitlement_exports, {
|
|
|
13594
13595
|
toEffectiveLimitsSnapshot: () => toEffectiveLimitsSnapshot
|
|
13595
13596
|
});
|
|
13596
13597
|
|
|
13597
|
-
// src/entitlement/module.ts
|
|
13598
|
+
// src/entitlement/entitlement.module.ts
|
|
13598
13599
|
var import_common64 = require("@nestjs/common");
|
|
13599
13600
|
function _ts_decorate72(decorators, target, key, desc) {
|
|
13600
13601
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
@@ -13694,9 +13695,8 @@ __export(platform_exports, {
|
|
|
13694
13695
|
SAASICAT_PUBLIC_ROUTE_KEY: () => SAASICAT_PUBLIC_ROUTE_KEY,
|
|
13695
13696
|
STATIC_FEATURE_GUARD_CONFIG_TOKEN: () => STATIC_FEATURE_GUARD_CONFIG_TOKEN,
|
|
13696
13697
|
SaaSiCatConfigurationError: () => SaaSiCatConfigurationError,
|
|
13697
|
-
SaaSiCatModule: () =>
|
|
13698
|
+
SaaSiCatModule: () => SaaSiCatModule,
|
|
13698
13699
|
SaaSiCatPublicRoute: () => SaaSiCatPublicRoute,
|
|
13699
|
-
SaasPlatformModule: () => SaasPlatformModule,
|
|
13700
13700
|
SetupModule: () => SetupModule,
|
|
13701
13701
|
SetupService: () => SetupService,
|
|
13702
13702
|
StaticEntitlementService: () => StaticEntitlementService,
|
|
@@ -13722,13 +13722,13 @@ __export(platform_exports, {
|
|
|
13722
13722
|
isSaaSiCatPublicRoute: () => isSaaSiCatPublicRoute
|
|
13723
13723
|
});
|
|
13724
13724
|
|
|
13725
|
-
// src/platform/
|
|
13725
|
+
// src/platform/saasicat.module.ts
|
|
13726
13726
|
var import_common80 = require("@nestjs/common");
|
|
13727
|
-
var
|
|
13727
|
+
var import_core42 = require("@nestjs/core");
|
|
13728
13728
|
|
|
13729
13729
|
// src/platform/enforcement-chain.check.ts
|
|
13730
13730
|
var import_common65 = require("@nestjs/common");
|
|
13731
|
-
var
|
|
13731
|
+
var import_core34 = require("@nestjs/core");
|
|
13732
13732
|
function _ts_decorate73(decorators, target, key, desc) {
|
|
13733
13733
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
13734
13734
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
@@ -13748,7 +13748,7 @@ function _ts_param47(paramIndex, decorator) {
|
|
|
13748
13748
|
__name(_ts_param47, "_ts_param");
|
|
13749
13749
|
var GUARDS_METADATA = "__guards__";
|
|
13750
13750
|
var METHOD_METADATA = "method";
|
|
13751
|
-
var ENFORCEMENT_CHAIN_STATE_TOKEN = /* @__PURE__ */ Symbol.for("
|
|
13751
|
+
var ENFORCEMENT_CHAIN_STATE_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/nest/EnforcementChainState");
|
|
13752
13752
|
var EnforcementChainCheck = class {
|
|
13753
13753
|
static {
|
|
13754
13754
|
__name(this, "EnforcementChainCheck");
|
|
@@ -13836,14 +13836,14 @@ Two things this cannot see, and the way out of each: a guard of your own that wr
|
|
|
13836
13836
|
};
|
|
13837
13837
|
EnforcementChainCheck = _ts_decorate73([
|
|
13838
13838
|
(0, import_common65.Injectable)(),
|
|
13839
|
-
_ts_param47(0, (0, import_common65.Inject)(
|
|
13840
|
-
_ts_param47(1, (0, import_common65.Inject)(
|
|
13839
|
+
_ts_param47(0, (0, import_common65.Inject)(import_core34.DiscoveryService)),
|
|
13840
|
+
_ts_param47(1, (0, import_common65.Inject)(import_core34.MetadataScanner)),
|
|
13841
13841
|
_ts_param47(2, (0, import_common65.Optional)()),
|
|
13842
13842
|
_ts_param47(2, (0, import_common65.Inject)(ENFORCEMENT_CHAIN_STATE_TOKEN)),
|
|
13843
13843
|
_ts_metadata58("design:type", Function),
|
|
13844
13844
|
_ts_metadata58("design:paramtypes", [
|
|
13845
|
-
typeof
|
|
13846
|
-
typeof
|
|
13845
|
+
typeof import_core34.DiscoveryService === "undefined" ? Object : import_core34.DiscoveryService,
|
|
13846
|
+
typeof import_core34.MetadataScanner === "undefined" ? Object : import_core34.MetadataScanner,
|
|
13847
13847
|
typeof EnforcementChainState === "undefined" ? Object : EnforcementChainState
|
|
13848
13848
|
])
|
|
13849
13849
|
], EnforcementChainCheck);
|
|
@@ -13879,7 +13879,7 @@ function readGuards(target) {
|
|
|
13879
13879
|
__name(readGuards, "readGuards");
|
|
13880
13880
|
|
|
13881
13881
|
// src/platform/validation/rules.ts
|
|
13882
|
-
var
|
|
13882
|
+
var import_core35 = require("@saasicat/core");
|
|
13883
13883
|
var DOCS_BASE = "https://github.com/uelker70/saasicat/blob/main/docs/reference/options.md";
|
|
13884
13884
|
var headingSlug = /* @__PURE__ */ __name((text) => text.trim().toLowerCase().replace(/[^a-z0-9 -]/g, "").replace(/ /g, "-"), "headingSlug");
|
|
13885
13885
|
var docsUrlFor = /* @__PURE__ */ __name((id) => `${DOCS_BASE}#${headingSlug(id)}`, "docsUrlFor");
|
|
@@ -13994,10 +13994,10 @@ var RULE_SPECS = [
|
|
|
13994
13994
|
// shared helper keeps the class, the code and the wording identical to
|
|
13995
13995
|
// what a consumer catches today.
|
|
13996
13996
|
error: /* @__PURE__ */ __name((c) => {
|
|
13997
|
-
(0,
|
|
13997
|
+
(0, import_core35.assertPersistenceCapabilities)(bundle(c).capabilities, {
|
|
13998
13998
|
transactions: true,
|
|
13999
13999
|
pessimisticLocking: true
|
|
14000
|
-
}, "
|
|
14000
|
+
}, "SaaSiCatModule entitlement (transactional enforceLimit)");
|
|
14001
14001
|
throw new Error("persistence capabilities check did not fail as expected");
|
|
14002
14002
|
}, "error")
|
|
14003
14003
|
},
|
|
@@ -14172,13 +14172,13 @@ var import_class_validator14 = require("class-validator");
|
|
|
14172
14172
|
|
|
14173
14173
|
// src/setup/setup.service.ts
|
|
14174
14174
|
var import_common66 = require("@nestjs/common");
|
|
14175
|
-
var
|
|
14175
|
+
var import_core36 = require("@saasicat/core");
|
|
14176
14176
|
var import_node_crypto3 = require("crypto");
|
|
14177
14177
|
var import_qrcode = __toESM(require("qrcode"), 1);
|
|
14178
14178
|
|
|
14179
|
-
// src/setup/tokens.ts
|
|
14180
|
-
var SETUP_PROVISIONING_PORT_TOKEN = /* @__PURE__ */ Symbol.for("
|
|
14181
|
-
var SETUP_CONFIG_TOKEN = /* @__PURE__ */ Symbol.for("
|
|
14179
|
+
// src/setup/setup.tokens.ts
|
|
14180
|
+
var SETUP_PROVISIONING_PORT_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/nest/SetupProvisioningPort");
|
|
14181
|
+
var SETUP_CONFIG_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/nest/SetupConfig");
|
|
14182
14182
|
|
|
14183
14183
|
// src/setup/setup.service.ts
|
|
14184
14184
|
function _ts_decorate74(decorators, target, key, desc) {
|
|
@@ -14228,7 +14228,7 @@ var SetupService = class {
|
|
|
14228
14228
|
await this.assertNoSuperAdmin();
|
|
14229
14229
|
const email = req.email.trim().toLowerCase();
|
|
14230
14230
|
if (!email.includes("@")) {
|
|
14231
|
-
throw new import_common66.BadRequestException(codedError(
|
|
14231
|
+
throw new import_common66.BadRequestException(codedError(import_core36.SETUP_ERROR_CODES.INVALID_EMAIL));
|
|
14232
14232
|
}
|
|
14233
14233
|
const generated = !req.password;
|
|
14234
14234
|
const password = req.password ?? (0, import_node_crypto3.randomBytes)(GENERATED_PASSWORD_BYTES).toString("base64url");
|
|
@@ -14239,9 +14239,9 @@ var SetupService = class {
|
|
|
14239
14239
|
password
|
|
14240
14240
|
});
|
|
14241
14241
|
} catch (err) {
|
|
14242
|
-
if ((0,
|
|
14242
|
+
if ((0, import_core36.isPlatformUserExistsError)(err)) {
|
|
14243
14243
|
throw new import_common66.ConflictException({
|
|
14244
|
-
code:
|
|
14244
|
+
code: import_core36.SETUP_ERROR_CODES.EMAIL_EXISTS,
|
|
14245
14245
|
message: err.message
|
|
14246
14246
|
});
|
|
14247
14247
|
}
|
|
@@ -14277,7 +14277,7 @@ var SetupService = class {
|
|
|
14277
14277
|
const expected = process.env[this.config.setupTokenEnvVar]?.trim();
|
|
14278
14278
|
if (!expected) {
|
|
14279
14279
|
throw new import_common66.ForbiddenException({
|
|
14280
|
-
code:
|
|
14280
|
+
code: import_core36.SETUP_ERROR_CODES.SETUP_DISABLED,
|
|
14281
14281
|
message: `${this.config.setupTokenEnvVar} is not set \u2014 setup is disabled.`,
|
|
14282
14282
|
params: {
|
|
14283
14283
|
envVar: this.config.setupTokenEnvVar
|
|
@@ -14285,12 +14285,12 @@ var SetupService = class {
|
|
|
14285
14285
|
});
|
|
14286
14286
|
}
|
|
14287
14287
|
if (!token || !timingSafeEqualStr(token, expected)) {
|
|
14288
|
-
throw new import_common66.UnauthorizedException(codedError(
|
|
14288
|
+
throw new import_common66.UnauthorizedException(codedError(import_core36.SETUP_ERROR_CODES.INVALID_SETUP_TOKEN));
|
|
14289
14289
|
}
|
|
14290
14290
|
}
|
|
14291
14291
|
async assertNoSuperAdmin() {
|
|
14292
14292
|
if (await this.users.countSuperAdmins() > 0) {
|
|
14293
|
-
throw new import_common66.ConflictException(codedError(
|
|
14293
|
+
throw new import_common66.ConflictException(codedError(import_core36.SETUP_ERROR_CODES.SETUP_ALREADY_DONE));
|
|
14294
14294
|
}
|
|
14295
14295
|
}
|
|
14296
14296
|
};
|
|
@@ -14555,10 +14555,10 @@ function composeSubscriptionContract({ options, persistence }) {
|
|
|
14555
14555
|
}
|
|
14556
14556
|
__name(composeSubscriptionContract, "composeSubscriptionContract");
|
|
14557
14557
|
|
|
14558
|
-
// src/promo/module.ts
|
|
14558
|
+
// src/promo/promo.module.ts
|
|
14559
14559
|
var import_common74 = require("@nestjs/common");
|
|
14560
14560
|
|
|
14561
|
-
// src/promo/expirer.ts
|
|
14561
|
+
// src/promo/promo-code-expirer.service.ts
|
|
14562
14562
|
var import_common70 = require("@nestjs/common");
|
|
14563
14563
|
var import_schedule = require("@nestjs/schedule");
|
|
14564
14564
|
function _ts_decorate78(decorators, target, key, desc) {
|
|
@@ -14618,12 +14618,12 @@ PromoCodeExpirer = _ts_decorate78([
|
|
|
14618
14618
|
])
|
|
14619
14619
|
], PromoCodeExpirer);
|
|
14620
14620
|
|
|
14621
|
-
// src/promo/controller.ts
|
|
14621
|
+
// src/promo/promo.controller.ts
|
|
14622
14622
|
var import_common72 = require("@nestjs/common");
|
|
14623
14623
|
|
|
14624
14624
|
// src/promo/rate-limit.guard.ts
|
|
14625
14625
|
var import_common71 = require("@nestjs/common");
|
|
14626
|
-
var
|
|
14626
|
+
var import_core37 = require("@saasicat/core");
|
|
14627
14627
|
function _ts_decorate79(decorators, target, key, desc) {
|
|
14628
14628
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
14629
14629
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
@@ -14637,7 +14637,7 @@ var SESSION_WINDOW_MS = 60 * 6e4;
|
|
|
14637
14637
|
var SESSION_LIMIT = 50;
|
|
14638
14638
|
function rateLimited(windowMs) {
|
|
14639
14639
|
return new import_common71.HttpException({
|
|
14640
|
-
...codedError(
|
|
14640
|
+
...codedError(import_core37.REGISTRATION_ERROR_CODES.RATE_LIMITED, {
|
|
14641
14641
|
retryAfterSeconds: Math.ceil(windowMs / 1e3)
|
|
14642
14642
|
}),
|
|
14643
14643
|
retryAfterSeconds: Math.ceil(windowMs / 1e3),
|
|
@@ -14750,7 +14750,7 @@ _ts_decorate80([
|
|
|
14750
14750
|
_ts_metadata62("design:type", String)
|
|
14751
14751
|
], PreviewPromoCodeDto.prototype, "email", void 0);
|
|
14752
14752
|
|
|
14753
|
-
// src/promo/controller.ts
|
|
14753
|
+
// src/promo/promo.controller.ts
|
|
14754
14754
|
function _ts_decorate81(decorators, target, key, desc) {
|
|
14755
14755
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
14756
14756
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
@@ -14810,7 +14810,7 @@ PromoCodePublicController = _ts_decorate81([
|
|
|
14810
14810
|
])
|
|
14811
14811
|
], PromoCodePublicController);
|
|
14812
14812
|
|
|
14813
|
-
// src/promo/admin
|
|
14813
|
+
// src/promo/promo-admin.controller.ts
|
|
14814
14814
|
var import_common73 = require("@nestjs/common");
|
|
14815
14815
|
|
|
14816
14816
|
// src/promo/dto/promo-admin.dto.ts
|
|
@@ -15066,7 +15066,7 @@ _ts_decorate82([
|
|
|
15066
15066
|
_ts_metadata64("design:type", Object)
|
|
15067
15067
|
], UpdatePromoCodeDto.prototype, "revenueDeductionAccount", void 0);
|
|
15068
15068
|
|
|
15069
|
-
// src/promo/admin
|
|
15069
|
+
// src/promo/promo-admin.controller.ts
|
|
15070
15070
|
function _ts_decorate83(decorators, target, key, desc) {
|
|
15071
15071
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
15072
15072
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
@@ -15232,7 +15232,7 @@ function parseDate(value) {
|
|
|
15232
15232
|
}
|
|
15233
15233
|
__name(parseDate, "parseDate");
|
|
15234
15234
|
|
|
15235
|
-
// src/promo/module.ts
|
|
15235
|
+
// src/promo/promo.module.ts
|
|
15236
15236
|
function _ts_decorate84(decorators, target, key, desc) {
|
|
15237
15237
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
15238
15238
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
@@ -15433,8 +15433,8 @@ function composeFeatures(ctx) {
|
|
|
15433
15433
|
__name(composeFeatures, "composeFeatures");
|
|
15434
15434
|
|
|
15435
15435
|
// src/platform/compose/manifest.ts
|
|
15436
|
-
var PLATFORM_SUBSCRIPTION_REPOSITORY_TOKEN = /* @__PURE__ */ Symbol.for("
|
|
15437
|
-
var STANDARD_MANIFEST_REGISTRATION_TOKEN = /* @__PURE__ */ Symbol.for("
|
|
15436
|
+
var PLATFORM_SUBSCRIPTION_REPOSITORY_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/nest/PlatformSubscriptionRepository");
|
|
15437
|
+
var STANDARD_MANIFEST_REGISTRATION_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/nest/StandardManifestRegistration");
|
|
15438
15438
|
function buildStandardManifestContribution(catalog, adminResources, promoCodes) {
|
|
15439
15439
|
const capabilities = {
|
|
15440
15440
|
"discovery.read": true
|
|
@@ -15505,7 +15505,7 @@ function buildMinimalManifestConfig() {
|
|
|
15505
15505
|
appVersion: "0.0.0"
|
|
15506
15506
|
},
|
|
15507
15507
|
planCatalogSnapshot: {
|
|
15508
|
-
source: "
|
|
15508
|
+
source: "saasicat-module",
|
|
15509
15509
|
hash: "sha256-quickstart",
|
|
15510
15510
|
currency: catalog.currency,
|
|
15511
15511
|
vatRate: catalog.vatRate,
|
|
@@ -15656,7 +15656,7 @@ var import_common76 = require("@nestjs/common");
|
|
|
15656
15656
|
var import_common75 = require("@nestjs/common");
|
|
15657
15657
|
|
|
15658
15658
|
// src/platform/plan-resolver.port.ts
|
|
15659
|
-
var PLAN_RESOLVER_PORT_TOKEN = /* @__PURE__ */ Symbol.for("
|
|
15659
|
+
var PLAN_RESOLVER_PORT_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/nest/PlanResolverPort");
|
|
15660
15660
|
var StaticPlanResolver = class {
|
|
15661
15661
|
static {
|
|
15662
15662
|
__name(this, "StaticPlanResolver");
|
|
@@ -15909,11 +15909,11 @@ function composeTenantManifest(ctx) {
|
|
|
15909
15909
|
__name(composeTenantManifest, "composeTenantManifest");
|
|
15910
15910
|
|
|
15911
15911
|
// src/platform/compose/enforcement-runtime.ts
|
|
15912
|
-
var
|
|
15912
|
+
var import_core41 = require("@nestjs/core");
|
|
15913
15913
|
|
|
15914
15914
|
// src/platform/enforce-quota.interceptor.ts
|
|
15915
15915
|
var import_common78 = require("@nestjs/common");
|
|
15916
|
-
var
|
|
15916
|
+
var import_core38 = require("@nestjs/core");
|
|
15917
15917
|
var import_rxjs2 = require("rxjs");
|
|
15918
15918
|
var import_operators2 = require("rxjs/operators");
|
|
15919
15919
|
function _ts_decorate88(decorators, target, key, desc) {
|
|
@@ -15933,7 +15933,7 @@ function _ts_param55(paramIndex, decorator) {
|
|
|
15933
15933
|
};
|
|
15934
15934
|
}
|
|
15935
15935
|
__name(_ts_param55, "_ts_param");
|
|
15936
|
-
var QUOTA_PROVIDERS_TOKEN = /* @__PURE__ */ Symbol.for("
|
|
15936
|
+
var QUOTA_PROVIDERS_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/nest/QuotaProviders");
|
|
15937
15937
|
var EnforceQuotaInterceptor = class {
|
|
15938
15938
|
static {
|
|
15939
15939
|
__name(this, "EnforceQuotaInterceptor");
|
|
@@ -15977,13 +15977,13 @@ var EnforceQuotaInterceptor = class {
|
|
|
15977
15977
|
};
|
|
15978
15978
|
EnforceQuotaInterceptor = _ts_decorate88([
|
|
15979
15979
|
(0, import_common78.Injectable)(),
|
|
15980
|
-
_ts_param55(0, (0, import_common78.Inject)(
|
|
15980
|
+
_ts_param55(0, (0, import_common78.Inject)(import_core38.Reflector)),
|
|
15981
15981
|
_ts_param55(1, (0, import_common78.Inject)(StaticEntitlementService)),
|
|
15982
15982
|
_ts_param55(2, (0, import_common78.Optional)()),
|
|
15983
15983
|
_ts_param55(2, (0, import_common78.Inject)(QUOTA_PROVIDERS_TOKEN)),
|
|
15984
15984
|
_ts_metadata69("design:type", Function),
|
|
15985
15985
|
_ts_metadata69("design:paramtypes", [
|
|
15986
|
-
typeof
|
|
15986
|
+
typeof import_core38.Reflector === "undefined" ? Object : import_core38.Reflector,
|
|
15987
15987
|
typeof StaticEntitlementService === "undefined" ? Object : StaticEntitlementService,
|
|
15988
15988
|
Object
|
|
15989
15989
|
])
|
|
@@ -15991,8 +15991,8 @@ EnforceQuotaInterceptor = _ts_decorate88([
|
|
|
15991
15991
|
|
|
15992
15992
|
// src/platform/static-feature.guard.ts
|
|
15993
15993
|
var import_common79 = require("@nestjs/common");
|
|
15994
|
-
var
|
|
15995
|
-
var
|
|
15994
|
+
var import_core39 = require("@nestjs/core");
|
|
15995
|
+
var import_core40 = require("@saasicat/core");
|
|
15996
15996
|
function _ts_decorate89(decorators, target, key, desc) {
|
|
15997
15997
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
15998
15998
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
@@ -16010,7 +16010,7 @@ function _ts_param56(paramIndex, decorator) {
|
|
|
16010
16010
|
};
|
|
16011
16011
|
}
|
|
16012
16012
|
__name(_ts_param56, "_ts_param");
|
|
16013
|
-
var STATIC_FEATURE_GUARD_CONFIG_TOKEN = /* @__PURE__ */ Symbol.for("
|
|
16013
|
+
var STATIC_FEATURE_GUARD_CONFIG_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/nest/StaticFeatureGuardConfig");
|
|
16014
16014
|
var StaticFeatureGuard = class {
|
|
16015
16015
|
static {
|
|
16016
16016
|
__name(this, "StaticFeatureGuard");
|
|
@@ -16035,7 +16035,7 @@ var StaticFeatureGuard = class {
|
|
|
16035
16035
|
const user = request.user;
|
|
16036
16036
|
if (!user) {
|
|
16037
16037
|
throw new import_common79.ForbiddenException({
|
|
16038
|
-
code:
|
|
16038
|
+
code: import_core40.AUTH_ERROR_CODES.NOT_AUTHENTICATED,
|
|
16039
16039
|
message: "Not authenticated"
|
|
16040
16040
|
});
|
|
16041
16041
|
}
|
|
@@ -16044,7 +16044,7 @@ var StaticFeatureGuard = class {
|
|
|
16044
16044
|
const tenantId = this.config?.tenantIdResolver ? this.config.tenantIdResolver(request) : request.tenantId ?? user.tenantId;
|
|
16045
16045
|
if (!tenantId) {
|
|
16046
16046
|
throw new import_common79.ForbiddenException({
|
|
16047
|
-
code:
|
|
16047
|
+
code: import_core40.AUTH_ERROR_CODES.NO_TENANT_ASSIGNED,
|
|
16048
16048
|
message: "No tenant assigned"
|
|
16049
16049
|
});
|
|
16050
16050
|
}
|
|
@@ -16052,7 +16052,7 @@ var StaticFeatureGuard = class {
|
|
|
16052
16052
|
const allowed = required.some((f) => snap.features.includes(f));
|
|
16053
16053
|
if (!allowed) {
|
|
16054
16054
|
const body = {
|
|
16055
|
-
code:
|
|
16055
|
+
code: import_core40.FEATURE_NOT_LICENSED,
|
|
16056
16056
|
featureKey: required[0],
|
|
16057
16057
|
featureKeys: required,
|
|
16058
16058
|
offers: [],
|
|
@@ -16065,13 +16065,13 @@ var StaticFeatureGuard = class {
|
|
|
16065
16065
|
};
|
|
16066
16066
|
StaticFeatureGuard = _ts_decorate89([
|
|
16067
16067
|
(0, import_common79.Injectable)(),
|
|
16068
|
-
_ts_param56(0, (0, import_common79.Inject)(
|
|
16068
|
+
_ts_param56(0, (0, import_common79.Inject)(import_core39.Reflector)),
|
|
16069
16069
|
_ts_param56(1, (0, import_common79.Inject)(StaticEntitlementService)),
|
|
16070
16070
|
_ts_param56(2, (0, import_common79.Optional)()),
|
|
16071
16071
|
_ts_param56(2, (0, import_common79.Inject)(STATIC_FEATURE_GUARD_CONFIG_TOKEN)),
|
|
16072
16072
|
_ts_metadata70("design:type", Function),
|
|
16073
16073
|
_ts_metadata70("design:paramtypes", [
|
|
16074
|
-
typeof
|
|
16074
|
+
typeof import_core39.Reflector === "undefined" ? Object : import_core39.Reflector,
|
|
16075
16075
|
typeof StaticEntitlementService === "undefined" ? Object : StaticEntitlementService,
|
|
16076
16076
|
Object
|
|
16077
16077
|
])
|
|
@@ -16135,7 +16135,7 @@ function composeEnforcementRuntime(ctx, resolution) {
|
|
|
16135
16135
|
},
|
|
16136
16136
|
...options.globalFeatureGuard === false ? [] : [
|
|
16137
16137
|
{
|
|
16138
|
-
provide:
|
|
16138
|
+
provide: import_core41.APP_GUARD,
|
|
16139
16139
|
useExisting: StaticFeatureGuard
|
|
16140
16140
|
}
|
|
16141
16141
|
],
|
|
@@ -16143,7 +16143,7 @@ function composeEnforcementRuntime(ctx, resolution) {
|
|
|
16143
16143
|
// guards, so it sees the authenticated request even when the app binds
|
|
16144
16144
|
// its own guard chain.
|
|
16145
16145
|
{
|
|
16146
|
-
provide:
|
|
16146
|
+
provide: import_core41.APP_INTERCEPTOR,
|
|
16147
16147
|
useExisting: EnforceQuotaInterceptor
|
|
16148
16148
|
}
|
|
16149
16149
|
);
|
|
@@ -16179,7 +16179,7 @@ function planResolverProvider(ctx, resolution) {
|
|
|
16179
16179
|
}
|
|
16180
16180
|
__name(planResolverProvider, "planResolverProvider");
|
|
16181
16181
|
|
|
16182
|
-
// src/platform/
|
|
16182
|
+
// src/platform/saasicat.module.ts
|
|
16183
16183
|
function _ts_decorate90(decorators, target, key, desc) {
|
|
16184
16184
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
16185
16185
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
@@ -16195,9 +16195,9 @@ function enforcementChainState(state) {
|
|
|
16195
16195
|
};
|
|
16196
16196
|
}
|
|
16197
16197
|
__name(enforcementChainState, "enforcementChainState");
|
|
16198
|
-
var
|
|
16198
|
+
var SaaSiCatModule = class _SaaSiCatModule {
|
|
16199
16199
|
static {
|
|
16200
|
-
__name(this, "
|
|
16200
|
+
__name(this, "SaaSiCatModule");
|
|
16201
16201
|
}
|
|
16202
16202
|
static forRoot(options) {
|
|
16203
16203
|
const explicit = options.adapters ?? {};
|
|
@@ -16282,12 +16282,12 @@ var SaasPlatformModule = class _SaasPlatformModule {
|
|
|
16282
16282
|
globalGuardOptedOut: options.globalFeatureGuard === false
|
|
16283
16283
|
}));
|
|
16284
16284
|
}
|
|
16285
|
-
if (options.enforcementChainCheck !== false) imports.push(
|
|
16285
|
+
if (options.enforcementChainCheck !== false) imports.push(import_core42.DiscoveryModule);
|
|
16286
16286
|
const tenantManifest = composeTenantManifest(composition);
|
|
16287
16287
|
lightweightProviders.push(...tenantManifest.providers);
|
|
16288
16288
|
lightweightExports.push(...tenantManifest.exports);
|
|
16289
16289
|
return {
|
|
16290
|
-
module:
|
|
16290
|
+
module: _SaaSiCatModule,
|
|
16291
16291
|
imports,
|
|
16292
16292
|
providers: lightweightProviders,
|
|
16293
16293
|
controllers: tenantManifest.controllers,
|
|
@@ -16296,9 +16296,9 @@ var SaasPlatformModule = class _SaasPlatformModule {
|
|
|
16296
16296
|
};
|
|
16297
16297
|
}
|
|
16298
16298
|
};
|
|
16299
|
-
|
|
16299
|
+
SaaSiCatModule = _ts_decorate90([
|
|
16300
16300
|
(0, import_common80.Module)({})
|
|
16301
|
-
],
|
|
16301
|
+
], SaaSiCatModule);
|
|
16302
16302
|
|
|
16303
16303
|
// src/platform/define-saasicat.ts
|
|
16304
16304
|
function defineSaaSiCat(options) {
|
|
@@ -16409,28 +16409,28 @@ function slugify(name) {
|
|
|
16409
16409
|
}
|
|
16410
16410
|
__name(slugify, "slugify");
|
|
16411
16411
|
|
|
16412
|
-
// src/registration/tokens.ts
|
|
16413
|
-
var PENDING_REGISTRATION_REPOSITORY_TOKEN = /* @__PURE__ */ Symbol.for("
|
|
16414
|
-
var REGISTRATION_OTP_DELIVERY_TOKEN = /* @__PURE__ */ Symbol.for("
|
|
16415
|
-
var USER_ACCOUNT_LOOKUP_TOKEN = /* @__PURE__ */ Symbol.for("
|
|
16416
|
-
var SLUG_AVAILABILITY_CHECK_TOKEN = /* @__PURE__ */ Symbol.for("
|
|
16417
|
-
var PASSWORD_HASHER_TOKEN = /* @__PURE__ */ Symbol.for("
|
|
16418
|
-
var PLAN_CATALOG_LOOKUP_TOKEN = /* @__PURE__ */ Symbol.for("
|
|
16419
|
-
var PAYMENT_PROVIDER_TOKEN = /* @__PURE__ */ Symbol.for("
|
|
16420
|
-
var PAYMENT_EVENT_LOG_TOKEN = /* @__PURE__ */ Symbol.for("
|
|
16421
|
-
var ACTIVATION_ORCHESTRATOR_TOKEN = /* @__PURE__ */ Symbol.for("
|
|
16422
|
-
var REGISTRATION_AUDIT_LOGGER_TOKEN = /* @__PURE__ */ Symbol.for("
|
|
16423
|
-
var REGISTRATION_RESUME_TOKEN_SIGNER_TOKEN = /* @__PURE__ */ Symbol.for("
|
|
16424
|
-
var REGISTRATION_RESUME_DELIVERY_TOKEN = /* @__PURE__ */ Symbol.for("
|
|
16425
|
-
var REGISTRATION_RESUME_BASE_URL_TOKEN = /* @__PURE__ */ Symbol.for("
|
|
16426
|
-
var REGISTRATION_CONFIGURATOR_LOOKUP_TOKEN = /* @__PURE__ */ Symbol.for("
|
|
16427
|
-
var REGISTRATION_PROMO_PREVIEW_TOKEN = /* @__PURE__ */ Symbol.for("
|
|
16428
|
-
var REGISTRATION_CONFIG_TOKEN = /* @__PURE__ */ Symbol.for("
|
|
16412
|
+
// src/registration/registration.tokens.ts
|
|
16413
|
+
var PENDING_REGISTRATION_REPOSITORY_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/nest/PendingRegistrationRepository");
|
|
16414
|
+
var REGISTRATION_OTP_DELIVERY_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/nest/RegistrationOtpDelivery");
|
|
16415
|
+
var USER_ACCOUNT_LOOKUP_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/nest/UserAccountLookup");
|
|
16416
|
+
var SLUG_AVAILABILITY_CHECK_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/nest/SlugAvailabilityCheck");
|
|
16417
|
+
var PASSWORD_HASHER_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/nest/PasswordHasher");
|
|
16418
|
+
var PLAN_CATALOG_LOOKUP_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/nest/PlanCatalogLookup");
|
|
16419
|
+
var PAYMENT_PROVIDER_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/nest/PaymentProvider");
|
|
16420
|
+
var PAYMENT_EVENT_LOG_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/nest/PaymentEventLog");
|
|
16421
|
+
var ACTIVATION_ORCHESTRATOR_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/nest/ActivationOrchestrator");
|
|
16422
|
+
var REGISTRATION_AUDIT_LOGGER_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/nest/RegistrationAuditLogger");
|
|
16423
|
+
var REGISTRATION_RESUME_TOKEN_SIGNER_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/nest/RegistrationResumeTokenSigner");
|
|
16424
|
+
var REGISTRATION_RESUME_DELIVERY_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/nest/RegistrationResumeDelivery");
|
|
16425
|
+
var REGISTRATION_RESUME_BASE_URL_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/nest/RegistrationResumeBaseUrl");
|
|
16426
|
+
var REGISTRATION_CONFIGURATOR_LOOKUP_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/nest/RegistrationConfiguratorLookup");
|
|
16427
|
+
var REGISTRATION_PROMO_PREVIEW_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/nest/RegistrationPromoPreview");
|
|
16428
|
+
var REGISTRATION_CONFIG_TOKEN = /* @__PURE__ */ Symbol.for("saasicat/nest/RegistrationConfig");
|
|
16429
16429
|
|
|
16430
16430
|
// src/registration/pending-registration.service.ts
|
|
16431
16431
|
var import_common81 = require("@nestjs/common");
|
|
16432
|
-
var
|
|
16433
|
-
var
|
|
16432
|
+
var import_core43 = require("@saasicat/core");
|
|
16433
|
+
var import_core44 = require("@saasicat/core");
|
|
16434
16434
|
|
|
16435
16435
|
// src/registration/pricing.ts
|
|
16436
16436
|
function round24(value) {
|
|
@@ -16558,20 +16558,20 @@ var PendingRegistrationService = class _PendingRegistrationService {
|
|
|
16558
16558
|
async selectPlan(input, context) {
|
|
16559
16559
|
const pending = await this.repo.findById(input.pendingRegistrationId);
|
|
16560
16560
|
if (!pending) {
|
|
16561
|
-
throw new import_common81.NotFoundException(codedError(
|
|
16561
|
+
throw new import_common81.NotFoundException(codedError(import_core43.REGISTRATION_ERROR_CODES.PENDING_REGISTRATION_NOT_FOUND));
|
|
16562
16562
|
}
|
|
16563
16563
|
if (pending.expiresAt.getTime() < Date.now()) {
|
|
16564
|
-
throw new import_common81.BadRequestException(codedError(
|
|
16564
|
+
throw new import_common81.BadRequestException(codedError(import_core43.REGISTRATION_ERROR_CODES.PENDING_REGISTRATION_EXPIRED));
|
|
16565
16565
|
}
|
|
16566
16566
|
if (pending.status !== "EMAIL_VERIFIED" && pending.status !== "PLAN_SELECTED" && pending.status !== "CHECKOUT_STARTED") {
|
|
16567
|
-
throw new import_common81.BadRequestException(codedError(
|
|
16567
|
+
throw new import_common81.BadRequestException(codedError(import_core43.REGISTRATION_ERROR_CODES.INVALID_REGISTRATION_STATE));
|
|
16568
16568
|
}
|
|
16569
16569
|
const plan = await this.planCatalog.findPublicSignupPlan(input.planId);
|
|
16570
16570
|
if (!plan) {
|
|
16571
|
-
throw new import_common81.BadRequestException(codedError(
|
|
16571
|
+
throw new import_common81.BadRequestException(codedError(import_core43.REGISTRATION_ERROR_CODES.PLAN_NOT_AVAILABLE));
|
|
16572
16572
|
}
|
|
16573
16573
|
const now = /* @__PURE__ */ new Date();
|
|
16574
|
-
const expiresAt = new Date(now.getTime() +
|
|
16574
|
+
const expiresAt = new Date(now.getTime() + import_core44.PENDING_ONBOARDING_TTL_DAYS * 24 * 60 * 60 * 1e3);
|
|
16575
16575
|
const updated = await this.repo.update(pending.id, {
|
|
16576
16576
|
status: "PLAN_SELECTED",
|
|
16577
16577
|
currentStep: 4,
|
|
@@ -16584,27 +16584,27 @@ var PendingRegistrationService = class _PendingRegistrationService {
|
|
|
16584
16584
|
return {
|
|
16585
16585
|
pendingRegistrationId: updated.id,
|
|
16586
16586
|
status: updated.status,
|
|
16587
|
-
nextStep:
|
|
16587
|
+
nextStep: import_core44.REGISTRATION_STEP_BY_STATUS[updated.status],
|
|
16588
16588
|
selectedPlanId: updated.selectedPlanId ?? plan.id
|
|
16589
16589
|
};
|
|
16590
16590
|
}
|
|
16591
16591
|
async startCheckout(input, context) {
|
|
16592
16592
|
const pending = await this.repo.findById(input.pendingRegistrationId);
|
|
16593
16593
|
if (!pending) {
|
|
16594
|
-
throw new import_common81.NotFoundException(codedError(
|
|
16594
|
+
throw new import_common81.NotFoundException(codedError(import_core43.REGISTRATION_ERROR_CODES.PENDING_REGISTRATION_NOT_FOUND));
|
|
16595
16595
|
}
|
|
16596
16596
|
if (pending.expiresAt.getTime() < Date.now()) {
|
|
16597
|
-
throw new import_common81.BadRequestException(codedError(
|
|
16597
|
+
throw new import_common81.BadRequestException(codedError(import_core43.REGISTRATION_ERROR_CODES.PENDING_REGISTRATION_EXPIRED));
|
|
16598
16598
|
}
|
|
16599
16599
|
if (pending.status !== "PLAN_SELECTED" && pending.status !== "CHECKOUT_STARTED") {
|
|
16600
|
-
throw new import_common81.BadRequestException(codedError(
|
|
16600
|
+
throw new import_common81.BadRequestException(codedError(import_core43.REGISTRATION_ERROR_CODES.PLAN_NOT_SELECTED));
|
|
16601
16601
|
}
|
|
16602
16602
|
if (!pending.selectedPlanId) {
|
|
16603
|
-
throw new import_common81.BadRequestException(codedError(
|
|
16603
|
+
throw new import_common81.BadRequestException(codedError(import_core43.REGISTRATION_ERROR_CODES.PLAN_NOT_SELECTED));
|
|
16604
16604
|
}
|
|
16605
16605
|
const plan = await this.planCatalog.findPublicSignupPlan(pending.selectedPlanId);
|
|
16606
16606
|
if (!plan) {
|
|
16607
|
-
throw new import_common81.BadRequestException(codedError(
|
|
16607
|
+
throw new import_common81.BadRequestException(codedError(import_core43.REGISTRATION_ERROR_CODES.PLAN_NOT_AVAILABLE));
|
|
16608
16608
|
}
|
|
16609
16609
|
const session = await this.paymentProvider.createCheckoutSession({
|
|
16610
16610
|
pendingRegistrationId: pending.id,
|
|
@@ -16614,7 +16614,7 @@ var PendingRegistrationService = class _PendingRegistrationService {
|
|
|
16614
16614
|
cancelUrl: input.cancelUrl
|
|
16615
16615
|
});
|
|
16616
16616
|
const now = /* @__PURE__ */ new Date();
|
|
16617
|
-
const expiresAt = new Date(now.getTime() +
|
|
16617
|
+
const expiresAt = new Date(now.getTime() + import_core44.PENDING_CHECKOUT_TTL_DAYS * 24 * 60 * 60 * 1e3);
|
|
16618
16618
|
const updated = await this.repo.update(pending.id, {
|
|
16619
16619
|
status: "CHECKOUT_STARTED",
|
|
16620
16620
|
currentStep: 4,
|
|
@@ -16629,7 +16629,7 @@ var PendingRegistrationService = class _PendingRegistrationService {
|
|
|
16629
16629
|
return {
|
|
16630
16630
|
pendingRegistrationId: updated.id,
|
|
16631
16631
|
status: updated.status,
|
|
16632
|
-
nextStep:
|
|
16632
|
+
nextStep: import_core44.REGISTRATION_STEP_BY_STATUS[updated.status],
|
|
16633
16633
|
checkoutSessionId: session.sessionId,
|
|
16634
16634
|
checkoutUrl: session.checkoutUrl
|
|
16635
16635
|
};
|
|
@@ -16785,8 +16785,8 @@ var PendingRegistrationService = class _PendingRegistrationService {
|
|
|
16785
16785
|
const code = generateOtpCode();
|
|
16786
16786
|
const otpHash = hashOtpCode(code);
|
|
16787
16787
|
const now = /* @__PURE__ */ new Date();
|
|
16788
|
-
const otpExpiresAt = new Date(now.getTime() +
|
|
16789
|
-
const expiresAt = new Date(now.getTime() +
|
|
16788
|
+
const otpExpiresAt = new Date(now.getTime() + import_core44.OTP_TTL_MINUTES * 60 * 1e3);
|
|
16789
|
+
const expiresAt = new Date(now.getTime() + import_core44.PENDING_EMAIL_TTL_HOURS * 60 * 60 * 1e3);
|
|
16790
16790
|
const pending = await this.repo.create({
|
|
16791
16791
|
tenantName: input.tenantName.trim(),
|
|
16792
16792
|
tenantSlug: slug,
|
|
@@ -16813,12 +16813,12 @@ var PendingRegistrationService = class _PendingRegistrationService {
|
|
|
16813
16813
|
await this.record("OTP_VERIFY_FAILED", null, context, {
|
|
16814
16814
|
reason: "unknown_email"
|
|
16815
16815
|
});
|
|
16816
|
-
throw new import_common81.BadRequestException(codedError(
|
|
16816
|
+
throw new import_common81.BadRequestException(codedError(import_core43.REGISTRATION_ERROR_CODES.OTP_INVALID));
|
|
16817
16817
|
}
|
|
16818
16818
|
if (pending.status !== "PENDING_EMAIL_VERIFICATION") {
|
|
16819
16819
|
return {
|
|
16820
16820
|
status: pending.status,
|
|
16821
|
-
nextStep:
|
|
16821
|
+
nextStep: import_core44.REGISTRATION_STEP_BY_STATUS[pending.status],
|
|
16822
16822
|
pendingRegistrationId: pending.id
|
|
16823
16823
|
};
|
|
16824
16824
|
}
|
|
@@ -16826,33 +16826,33 @@ var PendingRegistrationService = class _PendingRegistrationService {
|
|
|
16826
16826
|
await this.record("OTP_VERIFY_FAILED", pending.id, context, {
|
|
16827
16827
|
reason: "no_otp_set"
|
|
16828
16828
|
});
|
|
16829
|
-
throw new import_common81.BadRequestException(codedError(
|
|
16829
|
+
throw new import_common81.BadRequestException(codedError(import_core43.REGISTRATION_ERROR_CODES.OTP_INVALID));
|
|
16830
16830
|
}
|
|
16831
16831
|
if (pending.otpExpiresAt.getTime() < Date.now()) {
|
|
16832
16832
|
await this.record("OTP_VERIFY_FAILED", pending.id, context, {
|
|
16833
16833
|
reason: "expired"
|
|
16834
16834
|
});
|
|
16835
|
-
throw new import_common81.BadRequestException(codedError(
|
|
16835
|
+
throw new import_common81.BadRequestException(codedError(import_core43.REGISTRATION_ERROR_CODES.OTP_EXPIRED));
|
|
16836
16836
|
}
|
|
16837
16837
|
const maxAttempts = resolveOtpVerifyMaxAttempts();
|
|
16838
16838
|
if (pending.otpAttemptCount >= maxAttempts) {
|
|
16839
16839
|
await this.record("OTP_VERIFY_FAILED", pending.id, context, {
|
|
16840
16840
|
reason: "locked"
|
|
16841
16841
|
});
|
|
16842
|
-
throw new import_common81.BadRequestException(codedError(
|
|
16842
|
+
throw new import_common81.BadRequestException(codedError(import_core43.REGISTRATION_ERROR_CODES.OTP_LOCKED));
|
|
16843
16843
|
}
|
|
16844
16844
|
const attemptCount = await this.repo.incrementOtpAttemptCount(pending.id);
|
|
16845
16845
|
if (attemptCount > maxAttempts) {
|
|
16846
16846
|
await this.record("OTP_VERIFY_FAILED", pending.id, context, {
|
|
16847
16847
|
reason: "locked"
|
|
16848
16848
|
});
|
|
16849
|
-
throw new import_common81.BadRequestException(codedError(
|
|
16849
|
+
throw new import_common81.BadRequestException(codedError(import_core43.REGISTRATION_ERROR_CODES.OTP_LOCKED));
|
|
16850
16850
|
}
|
|
16851
16851
|
if (!verifyOtpCode(pending.otpHash, code)) {
|
|
16852
16852
|
await this.record("OTP_VERIFY_FAILED", pending.id, context, {
|
|
16853
16853
|
reason: "wrong_code"
|
|
16854
16854
|
});
|
|
16855
|
-
throw new import_common81.BadRequestException(codedError(
|
|
16855
|
+
throw new import_common81.BadRequestException(codedError(import_core43.REGISTRATION_ERROR_CODES.OTP_INVALID));
|
|
16856
16856
|
}
|
|
16857
16857
|
const now = /* @__PURE__ */ new Date();
|
|
16858
16858
|
const updated = await this.repo.update(pending.id, {
|
|
@@ -16861,12 +16861,12 @@ var PendingRegistrationService = class _PendingRegistrationService {
|
|
|
16861
16861
|
emailVerifiedAt: now,
|
|
16862
16862
|
otpHash: null,
|
|
16863
16863
|
otpExpiresAt: null,
|
|
16864
|
-
expiresAt: new Date(now.getTime() +
|
|
16864
|
+
expiresAt: new Date(now.getTime() + import_core44.PENDING_ONBOARDING_TTL_DAYS * 24 * 60 * 60 * 1e3)
|
|
16865
16865
|
});
|
|
16866
16866
|
await this.record("OTP_VERIFIED", updated.id, context);
|
|
16867
16867
|
return {
|
|
16868
16868
|
status: updated.status,
|
|
16869
|
-
nextStep:
|
|
16869
|
+
nextStep: import_core44.REGISTRATION_STEP_BY_STATUS[updated.status],
|
|
16870
16870
|
pendingRegistrationId: updated.id
|
|
16871
16871
|
};
|
|
16872
16872
|
}
|
|
@@ -16891,15 +16891,15 @@ var PendingRegistrationService = class _PendingRegistrationService {
|
|
|
16891
16891
|
}
|
|
16892
16892
|
async regenerateOtp(pending) {
|
|
16893
16893
|
const now = /* @__PURE__ */ new Date();
|
|
16894
|
-
const windowMs =
|
|
16894
|
+
const windowMs = import_core44.OTP_RATE_LIMIT_WINDOW_MINUTES * 60 * 1e3;
|
|
16895
16895
|
const withinWindow = pending.lastOtpSentAt !== null && now.getTime() - pending.lastOtpSentAt.getTime() < windowMs;
|
|
16896
|
-
if (withinWindow && pending.otpSendCount >=
|
|
16896
|
+
if (withinWindow && pending.otpSendCount >= import_core44.OTP_RATE_LIMIT_MAX_SENDS) {
|
|
16897
16897
|
this.logger.warn(`OTP rate limit reached for ${pending.email} \u2014 send is being skipped.`);
|
|
16898
16898
|
return;
|
|
16899
16899
|
}
|
|
16900
16900
|
const code = generateOtpCode();
|
|
16901
16901
|
const otpHash = hashOtpCode(code);
|
|
16902
|
-
const otpExpiresAt = new Date(now.getTime() +
|
|
16902
|
+
const otpExpiresAt = new Date(now.getTime() + import_core44.OTP_TTL_MINUTES * 60 * 1e3);
|
|
16903
16903
|
const otpSendCount = withinWindow ? pending.otpSendCount + 1 : 1;
|
|
16904
16904
|
await this.repo.update(pending.id, {
|
|
16905
16905
|
otpHash,
|
|
@@ -16936,7 +16936,7 @@ var PendingRegistrationService = class _PendingRegistrationService {
|
|
|
16936
16936
|
}
|
|
16937
16937
|
const token = await this.resumeTokenSigner.sign({
|
|
16938
16938
|
pendingRegistrationId: pending.id,
|
|
16939
|
-
ttlMinutes:
|
|
16939
|
+
ttlMinutes: import_core43.REGISTRATION_RESUME_TTL_MINUTES
|
|
16940
16940
|
});
|
|
16941
16941
|
const base = (this.resumeBaseUrl ?? "http://localhost").replace(/\/+$/, "");
|
|
16942
16942
|
const url = `${base}/login?resume=${encodeURIComponent(token)}`;
|
|
@@ -16963,20 +16963,20 @@ var PendingRegistrationService = class _PendingRegistrationService {
|
|
|
16963
16963
|
*/
|
|
16964
16964
|
async resumeWithToken(input, context) {
|
|
16965
16965
|
if (!this.resumeTokenSigner) {
|
|
16966
|
-
throw new import_common81.BadRequestException(codedError(
|
|
16966
|
+
throw new import_common81.BadRequestException(codedError(import_core43.REGISTRATION_ERROR_CODES.RESUME_NOT_CONFIGURED));
|
|
16967
16967
|
}
|
|
16968
16968
|
let decoded;
|
|
16969
16969
|
try {
|
|
16970
16970
|
decoded = await this.resumeTokenSigner.verify(input.token);
|
|
16971
16971
|
} catch {
|
|
16972
|
-
throw new import_common81.BadRequestException(codedError(
|
|
16972
|
+
throw new import_common81.BadRequestException(codedError(import_core43.REGISTRATION_ERROR_CODES.RESUME_TOKEN_INVALID));
|
|
16973
16973
|
}
|
|
16974
16974
|
const pending = await this.repo.findById(decoded.pendingRegistrationId);
|
|
16975
16975
|
if (!pending) {
|
|
16976
|
-
throw new import_common81.BadRequestException(codedError(
|
|
16976
|
+
throw new import_common81.BadRequestException(codedError(import_core43.REGISTRATION_ERROR_CODES.RESUME_TOKEN_INVALID));
|
|
16977
16977
|
}
|
|
16978
16978
|
if (pending.expiresAt.getTime() < Date.now()) {
|
|
16979
|
-
throw new import_common81.BadRequestException(codedError(
|
|
16979
|
+
throw new import_common81.BadRequestException(codedError(import_core43.REGISTRATION_ERROR_CODES.PENDING_REGISTRATION_EXPIRED));
|
|
16980
16980
|
}
|
|
16981
16981
|
await this.record("REGISTRATION_NEUTRAL_REPLAY", pending.id, context, {
|
|
16982
16982
|
via: "resume_token",
|
|
@@ -16985,7 +16985,7 @@ var PendingRegistrationService = class _PendingRegistrationService {
|
|
|
16985
16985
|
return {
|
|
16986
16986
|
pendingRegistrationId: pending.id,
|
|
16987
16987
|
status: pending.status,
|
|
16988
|
-
nextStep:
|
|
16988
|
+
nextStep: import_core44.REGISTRATION_STEP_BY_STATUS[pending.status],
|
|
16989
16989
|
snapshot: toSnapshot2(pending)
|
|
16990
16990
|
};
|
|
16991
16991
|
}
|
|
@@ -17004,7 +17004,7 @@ var PendingRegistrationService = class _PendingRegistrationService {
|
|
|
17004
17004
|
/** Returns the (app-specific) configurator catalog. */
|
|
17005
17005
|
async getConfiguratorCatalog() {
|
|
17006
17006
|
if (!this.configuratorLookup) {
|
|
17007
|
-
throw new import_common81.BadRequestException(codedError(
|
|
17007
|
+
throw new import_common81.BadRequestException(codedError(import_core43.REGISTRATION_ERROR_CODES.CONFIGURATOR_NOT_CONFIGURED));
|
|
17008
17008
|
}
|
|
17009
17009
|
return this.configuratorLookup.getCatalog();
|
|
17010
17010
|
}
|
|
@@ -17021,22 +17021,22 @@ var PendingRegistrationService = class _PendingRegistrationService {
|
|
|
17021
17021
|
*/
|
|
17022
17022
|
async saveConfiguration(input, context) {
|
|
17023
17023
|
if (!this.configuratorLookup) {
|
|
17024
|
-
throw new import_common81.BadRequestException(codedError(
|
|
17024
|
+
throw new import_common81.BadRequestException(codedError(import_core43.REGISTRATION_ERROR_CODES.CONFIGURATOR_NOT_CONFIGURED));
|
|
17025
17025
|
}
|
|
17026
17026
|
const pending = await this.repo.findById(input.pendingRegistrationId);
|
|
17027
17027
|
if (!pending) {
|
|
17028
|
-
throw new import_common81.NotFoundException(codedError(
|
|
17028
|
+
throw new import_common81.NotFoundException(codedError(import_core43.REGISTRATION_ERROR_CODES.PENDING_REGISTRATION_NOT_FOUND));
|
|
17029
17029
|
}
|
|
17030
17030
|
if (pending.expiresAt.getTime() < Date.now()) {
|
|
17031
|
-
throw new import_common81.BadRequestException(codedError(
|
|
17031
|
+
throw new import_common81.BadRequestException(codedError(import_core43.REGISTRATION_ERROR_CODES.PENDING_REGISTRATION_EXPIRED));
|
|
17032
17032
|
}
|
|
17033
17033
|
if (pending.status !== "EMAIL_VERIFIED" && pending.status !== "PLAN_SELECTED" && pending.status !== "CHECKOUT_STARTED") {
|
|
17034
|
-
throw new import_common81.BadRequestException(codedError(
|
|
17034
|
+
throw new import_common81.BadRequestException(codedError(import_core43.REGISTRATION_ERROR_CODES.INVALID_REGISTRATION_STATE));
|
|
17035
17035
|
}
|
|
17036
17036
|
const catalog = await this.configuratorLookup.getCatalog();
|
|
17037
17037
|
const model = catalog.models.find((m) => m.id === input.selection.modelId);
|
|
17038
17038
|
if (!model) {
|
|
17039
|
-
throw new import_common81.BadRequestException(codedError(
|
|
17039
|
+
throw new import_common81.BadRequestException(codedError(import_core43.REGISTRATION_ERROR_CODES.MODEL_NOT_AVAILABLE));
|
|
17040
17040
|
}
|
|
17041
17041
|
let promoEval;
|
|
17042
17042
|
if (input.selection.appliedPromoCode && this.promoPreview) {
|
|
@@ -17068,7 +17068,7 @@ var PendingRegistrationService = class _PendingRegistrationService {
|
|
|
17068
17068
|
};
|
|
17069
17069
|
}
|
|
17070
17070
|
const now = /* @__PURE__ */ new Date();
|
|
17071
|
-
const expiresAt = new Date(now.getTime() +
|
|
17071
|
+
const expiresAt = new Date(now.getTime() + import_core44.PENDING_ONBOARDING_TTL_DAYS * 24 * 60 * 60 * 1e3);
|
|
17072
17072
|
const updated = await this.repo.update(pending.id, {
|
|
17073
17073
|
status: "PLAN_SELECTED",
|
|
17074
17074
|
currentStep: 4,
|
|
@@ -17087,7 +17087,7 @@ var PendingRegistrationService = class _PendingRegistrationService {
|
|
|
17087
17087
|
return {
|
|
17088
17088
|
pendingRegistrationId: updated.id,
|
|
17089
17089
|
status: updated.status,
|
|
17090
|
-
nextStep:
|
|
17090
|
+
nextStep: import_core44.REGISTRATION_STEP_BY_STATUS[updated.status],
|
|
17091
17091
|
selection: input.selection,
|
|
17092
17092
|
breakdown
|
|
17093
17093
|
};
|
|
@@ -17100,20 +17100,20 @@ var PendingRegistrationService = class _PendingRegistrationService {
|
|
|
17100
17100
|
*/
|
|
17101
17101
|
async previewConfigPromo(pendingRegistrationId, code) {
|
|
17102
17102
|
if (!this.configuratorLookup) {
|
|
17103
|
-
throw new import_common81.BadRequestException(codedError(
|
|
17103
|
+
throw new import_common81.BadRequestException(codedError(import_core43.REGISTRATION_ERROR_CODES.CONFIGURATOR_NOT_CONFIGURED));
|
|
17104
17104
|
}
|
|
17105
17105
|
const pending = await this.repo.findById(pendingRegistrationId);
|
|
17106
17106
|
if (!pending) {
|
|
17107
|
-
throw new import_common81.NotFoundException(codedError(
|
|
17107
|
+
throw new import_common81.NotFoundException(codedError(import_core43.REGISTRATION_ERROR_CODES.PENDING_REGISTRATION_NOT_FOUND));
|
|
17108
17108
|
}
|
|
17109
17109
|
const config = pending.configJson;
|
|
17110
17110
|
if (!config) {
|
|
17111
|
-
throw new import_common81.BadRequestException(codedError(
|
|
17111
|
+
throw new import_common81.BadRequestException(codedError(import_core43.REGISTRATION_ERROR_CODES.CONFIG_NOT_SAVED));
|
|
17112
17112
|
}
|
|
17113
17113
|
const catalog = await this.configuratorLookup.getCatalog();
|
|
17114
17114
|
const model = catalog.models.find((m) => m.id === config.modelId);
|
|
17115
17115
|
if (!model) {
|
|
17116
|
-
throw new import_common81.BadRequestException(codedError(
|
|
17116
|
+
throw new import_common81.BadRequestException(codedError(import_core43.REGISTRATION_ERROR_CODES.MODEL_NOT_AVAILABLE));
|
|
17117
17117
|
}
|
|
17118
17118
|
let promoEval;
|
|
17119
17119
|
if (code && this.promoPreview) {
|
|
@@ -17221,9 +17221,9 @@ function normalizeEmail(value) {
|
|
|
17221
17221
|
__name(normalizeEmail, "normalizeEmail");
|
|
17222
17222
|
function resolveOtpVerifyMaxAttempts() {
|
|
17223
17223
|
const raw = process.env.SAAS_PLATFORM_OTP_VERIFY_MAX_ATTEMPTS;
|
|
17224
|
-
if (!raw) return
|
|
17224
|
+
if (!raw) return import_core44.OTP_VERIFY_MAX_ATTEMPTS;
|
|
17225
17225
|
const parsed = Number.parseInt(raw, 10);
|
|
17226
|
-
return Number.isInteger(parsed) && parsed > 0 ? parsed :
|
|
17226
|
+
return Number.isInteger(parsed) && parsed > 0 ? parsed : import_core44.OTP_VERIFY_MAX_ATTEMPTS;
|
|
17227
17227
|
}
|
|
17228
17228
|
__name(resolveOtpVerifyMaxAttempts, "resolveOtpVerifyMaxAttempts");
|
|
17229
17229
|
function toSnapshot2(pending) {
|
|
@@ -17318,7 +17318,7 @@ RegistrationCleanupCron = _ts_decorate92([
|
|
|
17318
17318
|
|
|
17319
17319
|
// src/registration/ip-rate-limit.guard.ts
|
|
17320
17320
|
var import_common83 = require("@nestjs/common");
|
|
17321
|
-
var
|
|
17321
|
+
var import_core45 = require("@saasicat/core");
|
|
17322
17322
|
function _ts_decorate93(decorators, target, key, desc) {
|
|
17323
17323
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
17324
17324
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
@@ -17347,7 +17347,7 @@ var BaseIpRateLimitGuard = class {
|
|
|
17347
17347
|
const key = ipFingerprint2(req);
|
|
17348
17348
|
if (this.exceeded(key)) {
|
|
17349
17349
|
throw new import_common83.HttpException({
|
|
17350
|
-
...codedError(
|
|
17350
|
+
...codedError(import_core45.REGISTRATION_ERROR_CODES.RATE_LIMITED, {
|
|
17351
17351
|
retryAfterSeconds: Math.ceil(this.options.windowMs / 1e3)
|
|
17352
17352
|
}),
|
|
17353
17353
|
retryAfterSeconds: Math.ceil(this.options.windowMs / 1e3),
|
|
@@ -17387,7 +17387,7 @@ function ipFingerprint2(req) {
|
|
|
17387
17387
|
}
|
|
17388
17388
|
__name(ipFingerprint2, "ipFingerprint");
|
|
17389
17389
|
|
|
17390
|
-
// src/registration/module.ts
|
|
17390
|
+
// src/registration/registration.module.ts
|
|
17391
17391
|
var import_common84 = require("@nestjs/common");
|
|
17392
17392
|
function _ts_decorate94(decorators, target, key, desc) {
|
|
17393
17393
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
@@ -17884,10 +17884,12 @@ __export(src_exports, {
|
|
|
17884
17884
|
AdminStatsController: () => AdminStatsController,
|
|
17885
17885
|
AdminStatsModule: () => AdminStatsModule,
|
|
17886
17886
|
AdminStatsService: () => AdminStatsService,
|
|
17887
|
+
BILLING_FEATURE_UI_REGISTRY_TOKEN: () => BILLING_FEATURE_UI_REGISTRY_TOKEN,
|
|
17887
17888
|
BUNDLE_REPOSITORY_TOKEN: () => BUNDLE_REPOSITORY_TOKEN,
|
|
17888
17889
|
BaseIpRateLimitGuard: () => BaseIpRateLimitGuard,
|
|
17889
17890
|
BundlesService: () => BundlesService,
|
|
17890
17891
|
CATALOG_ENTRY_REPOSITORY_TOKEN: () => CATALOG_ENTRY_REPOSITORY_TOKEN,
|
|
17892
|
+
CATALOG_FEATURE_UI_REGISTRY_TOKEN: () => CATALOG_FEATURE_UI_REGISTRY_TOKEN,
|
|
17891
17893
|
CATALOG_SERVICE_CONFIG_TOKEN: () => CATALOG_SERVICE_CONFIG_TOKEN,
|
|
17892
17894
|
CHECKOUT_OFFER_REPOSITORY_TOKEN: () => CHECKOUT_OFFER_REPOSITORY_TOKEN,
|
|
17893
17895
|
CONTRACT_FREEZE_PORT_TOKEN: () => CONTRACT_FREEZE_PORT_TOKEN,
|
|
@@ -17929,7 +17931,6 @@ __export(src_exports, {
|
|
|
17929
17931
|
EntitlementService: () => EntitlementService,
|
|
17930
17932
|
FEATURE_GUARD_CONFIG_TOKEN: () => FEATURE_GUARD_CONFIG_TOKEN,
|
|
17931
17933
|
FEATURE_GUARD_MARKER: () => FEATURE_GUARD_MARKER,
|
|
17932
|
-
FEATURE_UI_REGISTRY_TOKEN: () => FEATURE_UI_REGISTRY_TOKEN2,
|
|
17933
17934
|
FeatureGuard: () => FeatureGuard,
|
|
17934
17935
|
IMPLEMENTS_CAPABILITY_KEY: () => IMPLEMENTS_CAPABILITY_KEY,
|
|
17935
17936
|
ImplementsCapability: () => ImplementsCapability,
|
|
@@ -18031,9 +18032,8 @@ __export(src_exports, {
|
|
|
18031
18032
|
SUBSCRIPTION_STATS_PORT_TOKEN: () => SUBSCRIPTION_STATS_PORT_TOKEN,
|
|
18032
18033
|
SUBSCRIPTION_USAGE_PORT_TOKEN: () => SUBSCRIPTION_USAGE_PORT_TOKEN,
|
|
18033
18034
|
SUBSCRIPTION_WRITE_PORT_TOKEN: () => SUBSCRIPTION_WRITE_PORT_TOKEN,
|
|
18034
|
-
SaaSiCatModule: () =>
|
|
18035
|
+
SaaSiCatModule: () => SaaSiCatModule,
|
|
18035
18036
|
SaaSiCatPublicRoute: () => SaaSiCatPublicRoute,
|
|
18036
|
-
SaasPlatformModule: () => SaasPlatformModule,
|
|
18037
18037
|
SaveRegistrationConfigDto: () => SaveRegistrationConfigDto,
|
|
18038
18038
|
SaveRegistrationConfigSelectionDto: () => SaveRegistrationConfigSelectionDto,
|
|
18039
18039
|
SelectRegistrationPlanDto: () => SelectRegistrationPlanDto,
|
|
@@ -18104,8 +18104,8 @@ __export(src_exports, {
|
|
|
18104
18104
|
buildPublicMarketingCatalogController: () => buildPublicMarketingCatalogController,
|
|
18105
18105
|
buildReplacedByIndex: () => buildReplacedByIndex,
|
|
18106
18106
|
buildTenantSubscriptionBundlesController: () => buildTenantSubscriptionBundlesController,
|
|
18107
|
-
classifyBundleVersionDiff: () =>
|
|
18108
|
-
classifyPlanDiff: () =>
|
|
18107
|
+
classifyBundleVersionDiff: () => import_core6.classifyBundleVersionDiff,
|
|
18108
|
+
classifyPlanDiff: () => import_core6.classifyPlanDiff,
|
|
18109
18109
|
clearPendingPlanVersionFields: () => clearPendingPlanVersionFields,
|
|
18110
18110
|
codedError: () => codedError,
|
|
18111
18111
|
collectSubscriptionBundleFeatures: () => collectSubscriptionBundleFeatures,
|
|
@@ -18207,11 +18207,11 @@ __export(testing_exports, {
|
|
|
18207
18207
|
StubAuditPort: () => StubAuditPort,
|
|
18208
18208
|
StubMfaPort: () => StubMfaPort,
|
|
18209
18209
|
StubRlsBypassPort: () => StubRlsBypassPort,
|
|
18210
|
-
|
|
18210
|
+
createSaaSiCatTestModule: () => createSaaSiCatTestModule
|
|
18211
18211
|
});
|
|
18212
18212
|
|
|
18213
18213
|
// src/testing/fake-repositories.ts
|
|
18214
|
-
var
|
|
18214
|
+
var import_core46 = require("@saasicat/core");
|
|
18215
18215
|
var FakeSubscriptionRepository = class {
|
|
18216
18216
|
static {
|
|
18217
18217
|
__name(this, "FakeSubscriptionRepository");
|
|
@@ -18518,7 +18518,7 @@ var FakeTransactionRunner = class _FakeTransactionRunner {
|
|
|
18518
18518
|
__name(this, "FakeTransactionRunner");
|
|
18519
18519
|
}
|
|
18520
18520
|
/** Sentinel value passed through as the TransactionContext. */
|
|
18521
|
-
static TX_SENTINEL = /* @__PURE__ */ Symbol.for("FakeTransactionRunner.tx");
|
|
18521
|
+
static TX_SENTINEL = /* @__PURE__ */ Symbol.for("saasicat/nest/FakeTransactionRunner.tx");
|
|
18522
18522
|
runCount = 0;
|
|
18523
18523
|
async run(fn) {
|
|
18524
18524
|
this.runCount += 1;
|
|
@@ -18967,7 +18967,7 @@ var FakePlanRepository = class {
|
|
|
18967
18967
|
}
|
|
18968
18968
|
async findActivePlanVersion(planKey, asOf = /* @__PURE__ */ new Date()) {
|
|
18969
18969
|
const t = asOf.getTime();
|
|
18970
|
-
const dayStart = (0,
|
|
18970
|
+
const dayStart = (0, import_core46.startOfUtcDay)(asOf).getTime();
|
|
18971
18971
|
const matches = [
|
|
18972
18972
|
...this.versions.values()
|
|
18973
18973
|
].filter((v) => {
|
|
@@ -19099,7 +19099,7 @@ var FakePlanRepository = class {
|
|
|
19099
19099
|
}
|
|
19100
19100
|
};
|
|
19101
19101
|
|
|
19102
|
-
// src/testing/create-
|
|
19102
|
+
// src/testing/create-saasicat-test-module.ts
|
|
19103
19103
|
var import_common85 = require("@nestjs/common");
|
|
19104
19104
|
function _ts_decorate104(decorators, target, key, desc) {
|
|
19105
19105
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
@@ -19141,17 +19141,17 @@ var StubRlsBypassPort = class {
|
|
|
19141
19141
|
return fn();
|
|
19142
19142
|
}
|
|
19143
19143
|
};
|
|
19144
|
-
function
|
|
19144
|
+
function createSaaSiCatTestModule(options) {
|
|
19145
19145
|
const defaultPlanId = options.defaultPlanId ?? options.planCatalog.plans?.[0]?.id;
|
|
19146
|
-
let
|
|
19146
|
+
let SaaSiCatTestHost = class SaaSiCatTestHost {
|
|
19147
19147
|
static {
|
|
19148
|
-
__name(this, "
|
|
19148
|
+
__name(this, "SaaSiCatTestHost");
|
|
19149
19149
|
}
|
|
19150
19150
|
};
|
|
19151
|
-
|
|
19151
|
+
SaaSiCatTestHost = _ts_decorate104([
|
|
19152
19152
|
(0, import_common85.Module)({
|
|
19153
19153
|
imports: [
|
|
19154
|
-
|
|
19154
|
+
SaaSiCatModule.forRoot({
|
|
19155
19155
|
planCatalog: options.planCatalog,
|
|
19156
19156
|
controller: {
|
|
19157
19157
|
guards: []
|
|
@@ -19166,12 +19166,12 @@ function createSaasPlatformTestModule(options) {
|
|
|
19166
19166
|
})
|
|
19167
19167
|
]
|
|
19168
19168
|
})
|
|
19169
|
-
],
|
|
19169
|
+
], SaaSiCatTestHost);
|
|
19170
19170
|
return {
|
|
19171
|
-
module:
|
|
19171
|
+
module: SaaSiCatTestHost
|
|
19172
19172
|
};
|
|
19173
19173
|
}
|
|
19174
|
-
__name(
|
|
19174
|
+
__name(createSaaSiCatTestModule, "createSaaSiCatTestModule");
|
|
19175
19175
|
// Annotate the CommonJS export names for ESM import in node:
|
|
19176
19176
|
0 && (module.exports = {
|
|
19177
19177
|
adminNs,
|