@saasicat/nest 0.18.1 → 0.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_entries.cjs +1341 -590
- package/dist/admin/index.js +2 -1
- package/dist/billing/index.d.cts +10 -6
- package/dist/billing/index.d.ts +10 -6
- package/dist/billing/index.js +7 -6
- package/dist/catalog/index.js +4 -4
- package/dist/checkout-offer/index.js +2 -2
- package/dist/{chunk-RZVSKKXX.js → chunk-3DRZ5GCP.js} +56 -105
- package/dist/{chunk-GLLCB4BP.js → chunk-4O6R6ARQ.js} +23 -13
- package/dist/{chunk-7RRWI5LH.js → chunk-55QGAZRQ.js} +10 -10
- package/dist/{chunk-Z3FWN3HJ.js → chunk-5ZXBXYXU.js} +3 -3
- package/dist/{chunk-V34AA7C7.js → chunk-6WL6VQ7Z.js} +1 -1
- package/dist/{chunk-ABB2CRAS.js → chunk-74SCJ4HF.js} +1 -1
- package/dist/{chunk-EXOLOJFZ.js → chunk-AGOG5B77.js} +36 -9
- package/dist/{chunk-32EMXPU2.js → chunk-B7NRY2LV.js} +48 -17
- package/dist/{chunk-MDIZUVIK.js → chunk-BSK6YBLI.js} +1 -1
- package/dist/{chunk-R2QOSVAA.js → chunk-DQKCK7DX.js} +1 -1
- package/dist/chunk-EBJJNTW6.js +22 -0
- package/dist/{chunk-PLJEAUFU.js → chunk-FYWLPYBK.js} +79 -39
- package/dist/{chunk-P3DP6GJE.js → chunk-GC5AKN44.js} +487 -160
- package/dist/{chunk-5KH2O4SF.js → chunk-NZLAYCEX.js} +286 -110
- package/dist/{chunk-E7AJ42AB.js → chunk-VQQWF7MW.js} +172 -28
- package/dist/{chunk-GJBXOCRZ.js → chunk-XTVAFJ3P.js} +46 -17
- package/dist/{chunk-BOADBIGB.js → chunk-YYUXKLXK.js} +2 -2
- package/dist/{chunk-YITTE646.js → chunk-ZH5PYEMI.js} +41 -23
- package/dist/{define-saasicat-Rc0rXrYG.d.ts → define-saasicat-B20Ms8UC.d.ts} +1 -1
- package/dist/{define-saasicat-CeDBX9ji.d.cts → define-saasicat-Cf9DpEsY.d.cts} +1 -1
- package/dist/discovery/index.d.cts +2 -2
- package/dist/discovery/index.d.ts +2 -2
- package/dist/discovery/index.js +4 -4
- package/dist/{enforce-quota.interceptor-CmbWX39L.d.ts → enforce-quota.interceptor-CUyfR4cQ.d.ts} +1 -1
- package/dist/{enforce-quota.interceptor-DMw-bPyk.d.cts → enforce-quota.interceptor-Dtg5WdFj.d.cts} +1 -1
- package/dist/entitlement/index.js +3 -2
- package/dist/index.d.cts +27 -8
- package/dist/index.d.ts +27 -8
- package/dist/index.js +21 -17
- package/dist/{module-DgYJur6f.d.ts → module-BE17XFLg.d.ts} +1 -1
- package/dist/{module-CSN8j8Tp.d.cts → module-CHMIyWlf.d.cts} +1 -1
- package/dist/platform/index.d.cts +8 -8
- package/dist/platform/index.d.ts +8 -8
- package/dist/platform/index.js +14 -13
- package/dist/promo/index.d.cts +3 -3
- package/dist/promo/index.d.ts +3 -3
- package/dist/promo/index.js +4 -3
- package/dist/registration/index.js +2 -1
- package/dist/{saas-platform.module-D3rUTiho.d.cts → saas-platform.module-BfaYfL-G.d.cts} +1 -1
- package/dist/{saas-platform.module-DLhoqKNA.d.ts → saas-platform.module-DChhDrR-.d.ts} +1 -1
- package/dist/{service-DX8KbGXl.d.cts → service-D48clObR.d.cts} +3 -3
- package/dist/{service-DX8KbGXl.d.ts → service-D48clObR.d.ts} +3 -3
- package/dist/subscription-contract/index.js +2 -2
- package/dist/{tenant-billing.controller-CG4CaFUP.d.cts → tenant-billing.controller-BIF-mstX.d.cts} +2 -2
- package/dist/{tenant-billing.controller-BwZRnJ3q.d.ts → tenant-billing.controller-DT5UrnDX.d.ts} +2 -2
- package/dist/testing/index.d.cts +5 -5
- package/dist/testing/index.d.ts +5 -5
- package/dist/testing/index.js +34 -33
- package/package.json +3 -3
package/dist/admin/index.js
CHANGED
|
@@ -25,7 +25,7 @@ import {
|
|
|
25
25
|
SuperAdminGuard,
|
|
26
26
|
SuspendTenantDto,
|
|
27
27
|
buildAdminStatsController
|
|
28
|
-
} from "../chunk-
|
|
28
|
+
} from "../chunk-FYWLPYBK.js";
|
|
29
29
|
import {
|
|
30
30
|
AUDIT_PORT_TOKEN,
|
|
31
31
|
AdminAuditService,
|
|
@@ -33,6 +33,7 @@ import {
|
|
|
33
33
|
RLS_BYPASS_PORT_TOKEN
|
|
34
34
|
} from "../chunk-E56W4U2P.js";
|
|
35
35
|
import "../chunk-YSC46BGM.js";
|
|
36
|
+
import "../chunk-EBJJNTW6.js";
|
|
36
37
|
import "../chunk-SABTXESR.js";
|
|
37
38
|
import "../chunk-SHUYVCID.js";
|
|
38
39
|
export {
|
package/dist/billing/index.d.cts
CHANGED
|
@@ -8,10 +8,10 @@ import { c as EntitlementService } from '../aggregation-SKfXu09x.cjs';
|
|
|
8
8
|
import { P as ProviderSpec } from '../di-CcNeq9v-.cjs';
|
|
9
9
|
import { f as ContractFreezePort, g as ContractFreezeSourcePort } from '../subscription-bundles.module-DCpV-Pb5.cjs';
|
|
10
10
|
export { A as AUDIT_CONTEXT_RESOLVER_TOKEN, a as AuditContextResolver, b as AuthGuardList, C as CONTRACT_FREEZE_PORT_TOKEN, c as CONTRACT_FREEZE_PROJECT_KEY_TOKEN, d as CONTRACT_FREEZE_SOURCE_PORT_TOKEN, e as ContractFreezeBundleSnapshot, D as DuePendingPlanChange, P as PENDING_PLAN_QUERY_PORT_TOKEN, h as PendingPlanQueryPort, S as SELF_SERVICE_BLOCKED_BUNDLES_TOKEN, i as SELF_SERVICE_BLOCKED_PLANS_TOKEN, j as SUBSCRIPTION_USAGE_PORT_TOKEN, k as SUBSCRIPTION_WRITE_PORT_TOKEN, l as SelfServiceBlockedBundles, m as SelfServiceBlockedPlans, n as SubscriptionBundleControllerOptions, o as SubscriptionBundleModule, p as SubscriptionBundleModuleOptions, T as TENANT_AUTH_GUARDS_TOKEN, q as TENANT_ID_RESOLVER_TOKEN, r as TRIAL_PROJECTION_PORT_TOKEN, s as TenantBillingModule, t as TenantBillingModuleOptions, u as TenantIdResolver, v as TrialProjectionInput, w as TrialProjectionPort, U as USAGE_SNAPSHOT_PORT_TOKEN, x as USER_EMAIL_RESOLVER_TOKEN, y as USER_ID_RESOLVER_TOKEN, z as UserEmailResolver, B as UserIdResolver } from '../subscription-bundles.module-DCpV-Pb5.cjs';
|
|
11
|
-
export { A as AddBundleToSubscriptionInput, B as BundlePreviewSnapshot, C as CancelBundleFromSubscriptionInput, a as CancelSubscriptionDto, b as ChangePlanDto, c as CompleteOnboardingSubscriptionDto, d as ComposedTenantAuthGuard, L as LimitsCheckRow, P as PendingPlanMaterializationService, e as PlanChangeContext, f as PlanChangePreviewDto, g as PlanChangePreviewIssue, h as PlanChangePreviewService, i as PlanChangeType, j as PlanSnapshotDto, k as PreviewPlanChangeDto, l as ProrationDto, m as ProrationInput, R as RedundantFeatureHint, S as SubscriptionBundleAddPreviewDto, n as SubscriptionBundleCancelPreviewDto, o as SubscriptionBundleConfig, p as SubscriptionBundlePreviewContext, q as SubscriptionBundlePreviewIssue, r as SubscriptionBundlePreviewService, s as SubscriptionBundlesService, T as TenantAdminGuard, t as TenantBillingController, U as UsageResponse, u as addMonths, v as computeProration, w as resolveBundleCancelEffectiveAt, x as resolveBundlePriceNet } from '../tenant-billing.controller-
|
|
11
|
+
export { A as AddBundleToSubscriptionInput, B as BundlePreviewSnapshot, C as CancelBundleFromSubscriptionInput, a as CancelSubscriptionDto, b as ChangePlanDto, c as CompleteOnboardingSubscriptionDto, d as ComposedTenantAuthGuard, L as LimitsCheckRow, P as PendingPlanMaterializationService, e as PlanChangeContext, f as PlanChangePreviewDto, g as PlanChangePreviewIssue, h as PlanChangePreviewService, i as PlanChangeType, j as PlanSnapshotDto, k as PreviewPlanChangeDto, l as ProrationDto, m as ProrationInput, R as RedundantFeatureHint, S as SubscriptionBundleAddPreviewDto, n as SubscriptionBundleCancelPreviewDto, o as SubscriptionBundleConfig, p as SubscriptionBundlePreviewContext, q as SubscriptionBundlePreviewIssue, r as SubscriptionBundlePreviewService, s as SubscriptionBundlesService, T as TenantAdminGuard, t as TenantBillingController, U as UsageResponse, u as addMonths, v as computeProration, w as resolveBundleCancelEffectiveAt, x as resolveBundlePriceNet } from '../tenant-billing.controller-BIF-mstX.cjs';
|
|
12
12
|
import { S as SubscriptionContractService } from '../subscription-contract.service--cm47ZJJ.cjs';
|
|
13
13
|
import '../plan-resolution-CFCoUkrE.cjs';
|
|
14
|
-
import '../service-
|
|
14
|
+
import '../service-D48clObR.cjs';
|
|
15
15
|
import '../admin-audit.service-9IqXMlZm.cjs';
|
|
16
16
|
|
|
17
17
|
/**
|
|
@@ -197,15 +197,19 @@ declare class FeatureGuard implements CanActivate {
|
|
|
197
197
|
constructor(reflector: Reflector, entitlements: EntitlementService, config?: FeatureGuardConfig | null, upsellResolver?: UpsellOfferResolver | null);
|
|
198
198
|
canActivate(context: ExecutionContext): Promise<boolean>;
|
|
199
199
|
/**
|
|
200
|
-
* Upsell response (#36):
|
|
201
|
-
*
|
|
202
|
-
*
|
|
203
|
-
*
|
|
200
|
+
* Upsell response (#36): the 403 body is always the full
|
|
201
|
+
* `FeatureNotLicensedBody`, so a consumer that matches on `code` can read
|
|
202
|
+
* `featureKey`/`offers` unconditionally. Without a registered
|
|
203
|
+
* `UpsellOfferResolver` there is simply nothing to offer — `offers` is
|
|
204
|
+
* empty, the same degradation a failing resolver produces.
|
|
204
205
|
*
|
|
205
206
|
* Deliberately 403 + `code` field instead of 402 — rationale in
|
|
206
207
|
* `@saasicat/types` upsell.types.ts (402 is reserved / inconsistently
|
|
207
208
|
* supported; SPA interceptors must not treat the 403 as an auth error, the
|
|
208
209
|
* distinction runs through `code`).
|
|
210
|
+
*
|
|
211
|
+
* The message must keep starting with the word `Feature` — consumers
|
|
212
|
+
* classify the response by that prefix.
|
|
209
213
|
*/
|
|
210
214
|
private buildNotLicensedException;
|
|
211
215
|
/**
|
package/dist/billing/index.d.ts
CHANGED
|
@@ -8,10 +8,10 @@ import { c as EntitlementService } from '../aggregation-o0LMenvl.js';
|
|
|
8
8
|
import { P as ProviderSpec } from '../di-CcNeq9v-.js';
|
|
9
9
|
import { f as ContractFreezePort, g as ContractFreezeSourcePort } from '../subscription-bundles.module-BQmoozm5.js';
|
|
10
10
|
export { A as AUDIT_CONTEXT_RESOLVER_TOKEN, a as AuditContextResolver, b as AuthGuardList, C as CONTRACT_FREEZE_PORT_TOKEN, c as CONTRACT_FREEZE_PROJECT_KEY_TOKEN, d as CONTRACT_FREEZE_SOURCE_PORT_TOKEN, e as ContractFreezeBundleSnapshot, D as DuePendingPlanChange, P as PENDING_PLAN_QUERY_PORT_TOKEN, h as PendingPlanQueryPort, S as SELF_SERVICE_BLOCKED_BUNDLES_TOKEN, i as SELF_SERVICE_BLOCKED_PLANS_TOKEN, j as SUBSCRIPTION_USAGE_PORT_TOKEN, k as SUBSCRIPTION_WRITE_PORT_TOKEN, l as SelfServiceBlockedBundles, m as SelfServiceBlockedPlans, n as SubscriptionBundleControllerOptions, o as SubscriptionBundleModule, p as SubscriptionBundleModuleOptions, T as TENANT_AUTH_GUARDS_TOKEN, q as TENANT_ID_RESOLVER_TOKEN, r as TRIAL_PROJECTION_PORT_TOKEN, s as TenantBillingModule, t as TenantBillingModuleOptions, u as TenantIdResolver, v as TrialProjectionInput, w as TrialProjectionPort, U as USAGE_SNAPSHOT_PORT_TOKEN, x as USER_EMAIL_RESOLVER_TOKEN, y as USER_ID_RESOLVER_TOKEN, z as UserEmailResolver, B as UserIdResolver } from '../subscription-bundles.module-BQmoozm5.js';
|
|
11
|
-
export { A as AddBundleToSubscriptionInput, B as BundlePreviewSnapshot, C as CancelBundleFromSubscriptionInput, a as CancelSubscriptionDto, b as ChangePlanDto, c as CompleteOnboardingSubscriptionDto, d as ComposedTenantAuthGuard, L as LimitsCheckRow, P as PendingPlanMaterializationService, e as PlanChangeContext, f as PlanChangePreviewDto, g as PlanChangePreviewIssue, h as PlanChangePreviewService, i as PlanChangeType, j as PlanSnapshotDto, k as PreviewPlanChangeDto, l as ProrationDto, m as ProrationInput, R as RedundantFeatureHint, S as SubscriptionBundleAddPreviewDto, n as SubscriptionBundleCancelPreviewDto, o as SubscriptionBundleConfig, p as SubscriptionBundlePreviewContext, q as SubscriptionBundlePreviewIssue, r as SubscriptionBundlePreviewService, s as SubscriptionBundlesService, T as TenantAdminGuard, t as TenantBillingController, U as UsageResponse, u as addMonths, v as computeProration, w as resolveBundleCancelEffectiveAt, x as resolveBundlePriceNet } from '../tenant-billing.controller-
|
|
11
|
+
export { A as AddBundleToSubscriptionInput, B as BundlePreviewSnapshot, C as CancelBundleFromSubscriptionInput, a as CancelSubscriptionDto, b as ChangePlanDto, c as CompleteOnboardingSubscriptionDto, d as ComposedTenantAuthGuard, L as LimitsCheckRow, P as PendingPlanMaterializationService, e as PlanChangeContext, f as PlanChangePreviewDto, g as PlanChangePreviewIssue, h as PlanChangePreviewService, i as PlanChangeType, j as PlanSnapshotDto, k as PreviewPlanChangeDto, l as ProrationDto, m as ProrationInput, R as RedundantFeatureHint, S as SubscriptionBundleAddPreviewDto, n as SubscriptionBundleCancelPreviewDto, o as SubscriptionBundleConfig, p as SubscriptionBundlePreviewContext, q as SubscriptionBundlePreviewIssue, r as SubscriptionBundlePreviewService, s as SubscriptionBundlesService, T as TenantAdminGuard, t as TenantBillingController, U as UsageResponse, u as addMonths, v as computeProration, w as resolveBundleCancelEffectiveAt, x as resolveBundlePriceNet } from '../tenant-billing.controller-DT5UrnDX.js';
|
|
12
12
|
import { S as SubscriptionContractService } from '../subscription-contract.service--cm47ZJJ.js';
|
|
13
13
|
import '../plan-resolution-CFCoUkrE.js';
|
|
14
|
-
import '../service-
|
|
14
|
+
import '../service-D48clObR.js';
|
|
15
15
|
import '../admin-audit.service-9IqXMlZm.js';
|
|
16
16
|
|
|
17
17
|
/**
|
|
@@ -197,15 +197,19 @@ declare class FeatureGuard implements CanActivate {
|
|
|
197
197
|
constructor(reflector: Reflector, entitlements: EntitlementService, config?: FeatureGuardConfig | null, upsellResolver?: UpsellOfferResolver | null);
|
|
198
198
|
canActivate(context: ExecutionContext): Promise<boolean>;
|
|
199
199
|
/**
|
|
200
|
-
* Upsell response (#36):
|
|
201
|
-
*
|
|
202
|
-
*
|
|
203
|
-
*
|
|
200
|
+
* Upsell response (#36): the 403 body is always the full
|
|
201
|
+
* `FeatureNotLicensedBody`, so a consumer that matches on `code` can read
|
|
202
|
+
* `featureKey`/`offers` unconditionally. Without a registered
|
|
203
|
+
* `UpsellOfferResolver` there is simply nothing to offer — `offers` is
|
|
204
|
+
* empty, the same degradation a failing resolver produces.
|
|
204
205
|
*
|
|
205
206
|
* Deliberately 403 + `code` field instead of 402 — rationale in
|
|
206
207
|
* `@saasicat/types` upsell.types.ts (402 is reserved / inconsistently
|
|
207
208
|
* supported; SPA interceptors must not treat the 403 as an auth error, the
|
|
208
209
|
* distinction runs through `code`).
|
|
210
|
+
*
|
|
211
|
+
* The message must keep starting with the word `Feature` — consumers
|
|
212
|
+
* classify the response by that prefix.
|
|
209
213
|
*/
|
|
210
214
|
private buildNotLicensedException;
|
|
211
215
|
/**
|
package/dist/billing/index.js
CHANGED
|
@@ -58,9 +58,9 @@ import {
|
|
|
58
58
|
periodEndWithMinLead,
|
|
59
59
|
resolveBundleCancelEffectiveAt,
|
|
60
60
|
resolveBundlePriceNet
|
|
61
|
-
} from "../chunk-
|
|
62
|
-
import "../chunk-
|
|
63
|
-
import "../chunk-
|
|
61
|
+
} from "../chunk-NZLAYCEX.js";
|
|
62
|
+
import "../chunk-VQQWF7MW.js";
|
|
63
|
+
import "../chunk-B7NRY2LV.js";
|
|
64
64
|
import {
|
|
65
65
|
AUDIT_CONTEXT_RESOLVER_TOKEN,
|
|
66
66
|
PENDING_PLAN_QUERY_PORT_TOKEN,
|
|
@@ -76,12 +76,12 @@ import {
|
|
|
76
76
|
classifyPlanDiff
|
|
77
77
|
} from "../chunk-WPUVJRIN.js";
|
|
78
78
|
import "../chunk-E56W4U2P.js";
|
|
79
|
-
import "../chunk-
|
|
79
|
+
import "../chunk-BSK6YBLI.js";
|
|
80
80
|
import "../chunk-YSC46BGM.js";
|
|
81
81
|
import {
|
|
82
82
|
SUBSCRIPTION_BUNDLE_CONFIG_TOKEN,
|
|
83
83
|
SUBSCRIPTION_BUNDLE_REPOSITORY_TOKEN
|
|
84
|
-
} from "../chunk-
|
|
84
|
+
} from "../chunk-AGOG5B77.js";
|
|
85
85
|
import {
|
|
86
86
|
PLAN_CATALOG_READ_SINK_TOKEN,
|
|
87
87
|
PLAN_CATALOG_TOKEN,
|
|
@@ -96,8 +96,9 @@ import {
|
|
|
96
96
|
getPlanQuota,
|
|
97
97
|
isFeatureInPlan,
|
|
98
98
|
isFeaturePlannedOnly
|
|
99
|
-
} from "../chunk-
|
|
99
|
+
} from "../chunk-DQKCK7DX.js";
|
|
100
100
|
import "../chunk-NYLON2VC.js";
|
|
101
|
+
import "../chunk-EBJJNTW6.js";
|
|
101
102
|
import "../chunk-WKVBNTYC.js";
|
|
102
103
|
import "../chunk-L4KTQ6CL.js";
|
|
103
104
|
import "../chunk-SABTXESR.js";
|
package/dist/catalog/index.js
CHANGED
|
@@ -6,8 +6,8 @@ import {
|
|
|
6
6
|
runSeedGateFromFile,
|
|
7
7
|
seedGateExitCode,
|
|
8
8
|
validateSeedAgainstSnapshot
|
|
9
|
-
} from "../chunk-
|
|
10
|
-
import "../chunk-
|
|
9
|
+
} from "../chunk-55QGAZRQ.js";
|
|
10
|
+
import "../chunk-74SCJ4HF.js";
|
|
11
11
|
import {
|
|
12
12
|
ADVISORY_STRICT_MODE_CODES,
|
|
13
13
|
BundlesService,
|
|
@@ -56,11 +56,11 @@ import {
|
|
|
56
56
|
quotaApprovalSignature,
|
|
57
57
|
validateBundleDraft,
|
|
58
58
|
validatePlanDraft
|
|
59
|
-
} from "../chunk-
|
|
59
|
+
} from "../chunk-GC5AKN44.js";
|
|
60
60
|
import "../chunk-WPUVJRIN.js";
|
|
61
61
|
import "../chunk-E56W4U2P.js";
|
|
62
62
|
import "../chunk-YSC46BGM.js";
|
|
63
|
-
import "../chunk-
|
|
63
|
+
import "../chunk-5ZXBXYXU.js";
|
|
64
64
|
import "../chunk-WKVBNTYC.js";
|
|
65
65
|
import {
|
|
66
66
|
BUNDLE_REPOSITORY_TOKEN,
|
|
@@ -6,8 +6,8 @@ import {
|
|
|
6
6
|
CreateCheckoutOfferDto,
|
|
7
7
|
UpdateCheckoutOfferDto,
|
|
8
8
|
buildCheckoutOfferController
|
|
9
|
-
} from "../chunk-
|
|
10
|
-
import "../chunk-
|
|
9
|
+
} from "../chunk-XTVAFJ3P.js";
|
|
10
|
+
import "../chunk-BSK6YBLI.js";
|
|
11
11
|
import "../chunk-YSC46BGM.js";
|
|
12
12
|
import "../chunk-L4KTQ6CL.js";
|
|
13
13
|
import "../chunk-SABTXESR.js";
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import {
|
|
2
|
+
codedError
|
|
3
|
+
} from "./chunk-EBJJNTW6.js";
|
|
1
4
|
import {
|
|
2
5
|
asProvider
|
|
3
6
|
} from "./chunk-SABTXESR.js";
|
|
@@ -54,7 +57,7 @@ var REGISTRATION_CONFIG_TOKEN = /* @__PURE__ */ Symbol.for("saas-platform/Regist
|
|
|
54
57
|
|
|
55
58
|
// src/registration/pending-registration.service.ts
|
|
56
59
|
import { BadRequestException, Inject, Injectable, Logger, NotFoundException, Optional } from "@nestjs/common";
|
|
57
|
-
import { REGISTRATION_RESUME_TTL_MINUTES } from "@saasicat/types";
|
|
60
|
+
import { REGISTRATION_ERROR_CODES, REGISTRATION_RESUME_TTL_MINUTES } from "@saasicat/types";
|
|
58
61
|
import { OTP_RATE_LIMIT_MAX_SENDS, OTP_RATE_LIMIT_WINDOW_MINUTES, OTP_TTL_MINUTES, OTP_VERIFY_MAX_ATTEMPTS, PENDING_CHECKOUT_TTL_DAYS, PENDING_EMAIL_TTL_HOURS, PENDING_ONBOARDING_TTL_DAYS, REGISTRATION_STEP_BY_STATUS } from "@saasicat/types";
|
|
59
62
|
|
|
60
63
|
// src/registration/pricing.ts
|
|
@@ -173,7 +176,7 @@ var PendingRegistrationService = class _PendingRegistrationService {
|
|
|
173
176
|
});
|
|
174
177
|
} catch (error) {
|
|
175
178
|
const message = error instanceof Error ? error.message : String(error);
|
|
176
|
-
this.logger.warn(`Audit
|
|
179
|
+
this.logger.warn(`Audit log write failed (${eventType}): ${message}`);
|
|
177
180
|
}
|
|
178
181
|
}
|
|
179
182
|
/** Public signup plan list for step 3 (frontend `usePublicPlans()`). */
|
|
@@ -183,25 +186,17 @@ var PendingRegistrationService = class _PendingRegistrationService {
|
|
|
183
186
|
async selectPlan(input, context) {
|
|
184
187
|
const pending = await this.repo.findById(input.pendingRegistrationId);
|
|
185
188
|
if (!pending) {
|
|
186
|
-
throw new NotFoundException(
|
|
187
|
-
code: "PENDING_REGISTRATION_NOT_FOUND"
|
|
188
|
-
});
|
|
189
|
+
throw new NotFoundException(codedError(REGISTRATION_ERROR_CODES.PENDING_REGISTRATION_NOT_FOUND));
|
|
189
190
|
}
|
|
190
191
|
if (pending.expiresAt.getTime() < Date.now()) {
|
|
191
|
-
throw new BadRequestException(
|
|
192
|
-
code: "PENDING_REGISTRATION_EXPIRED"
|
|
193
|
-
});
|
|
192
|
+
throw new BadRequestException(codedError(REGISTRATION_ERROR_CODES.PENDING_REGISTRATION_EXPIRED));
|
|
194
193
|
}
|
|
195
194
|
if (pending.status !== "EMAIL_VERIFIED" && pending.status !== "PLAN_SELECTED" && pending.status !== "CHECKOUT_STARTED") {
|
|
196
|
-
throw new BadRequestException(
|
|
197
|
-
code: "INVALID_REGISTRATION_STATE"
|
|
198
|
-
});
|
|
195
|
+
throw new BadRequestException(codedError(REGISTRATION_ERROR_CODES.INVALID_REGISTRATION_STATE));
|
|
199
196
|
}
|
|
200
197
|
const plan = await this.planCatalog.findPublicSignupPlan(input.planId);
|
|
201
198
|
if (!plan) {
|
|
202
|
-
throw new BadRequestException(
|
|
203
|
-
code: "PLAN_NOT_AVAILABLE"
|
|
204
|
-
});
|
|
199
|
+
throw new BadRequestException(codedError(REGISTRATION_ERROR_CODES.PLAN_NOT_AVAILABLE));
|
|
205
200
|
}
|
|
206
201
|
const now = /* @__PURE__ */ new Date();
|
|
207
202
|
const expiresAt = new Date(now.getTime() + PENDING_ONBOARDING_TTL_DAYS * 24 * 60 * 60 * 1e3);
|
|
@@ -224,30 +219,20 @@ var PendingRegistrationService = class _PendingRegistrationService {
|
|
|
224
219
|
async startCheckout(input, context) {
|
|
225
220
|
const pending = await this.repo.findById(input.pendingRegistrationId);
|
|
226
221
|
if (!pending) {
|
|
227
|
-
throw new NotFoundException(
|
|
228
|
-
code: "PENDING_REGISTRATION_NOT_FOUND"
|
|
229
|
-
});
|
|
222
|
+
throw new NotFoundException(codedError(REGISTRATION_ERROR_CODES.PENDING_REGISTRATION_NOT_FOUND));
|
|
230
223
|
}
|
|
231
224
|
if (pending.expiresAt.getTime() < Date.now()) {
|
|
232
|
-
throw new BadRequestException(
|
|
233
|
-
code: "PENDING_REGISTRATION_EXPIRED"
|
|
234
|
-
});
|
|
225
|
+
throw new BadRequestException(codedError(REGISTRATION_ERROR_CODES.PENDING_REGISTRATION_EXPIRED));
|
|
235
226
|
}
|
|
236
227
|
if (pending.status !== "PLAN_SELECTED" && pending.status !== "CHECKOUT_STARTED") {
|
|
237
|
-
throw new BadRequestException(
|
|
238
|
-
code: "PLAN_NOT_SELECTED"
|
|
239
|
-
});
|
|
228
|
+
throw new BadRequestException(codedError(REGISTRATION_ERROR_CODES.PLAN_NOT_SELECTED));
|
|
240
229
|
}
|
|
241
230
|
if (!pending.selectedPlanId) {
|
|
242
|
-
throw new BadRequestException(
|
|
243
|
-
code: "PLAN_NOT_SELECTED"
|
|
244
|
-
});
|
|
231
|
+
throw new BadRequestException(codedError(REGISTRATION_ERROR_CODES.PLAN_NOT_SELECTED));
|
|
245
232
|
}
|
|
246
233
|
const plan = await this.planCatalog.findPublicSignupPlan(pending.selectedPlanId);
|
|
247
234
|
if (!plan) {
|
|
248
|
-
throw new BadRequestException(
|
|
249
|
-
code: "PLAN_NOT_AVAILABLE"
|
|
250
|
-
});
|
|
235
|
+
throw new BadRequestException(codedError(REGISTRATION_ERROR_CODES.PLAN_NOT_AVAILABLE));
|
|
251
236
|
}
|
|
252
237
|
const session = await this.paymentProvider.createCheckoutSession({
|
|
253
238
|
pendingRegistrationId: pending.id,
|
|
@@ -298,7 +283,7 @@ var PendingRegistrationService = class _PendingRegistrationService {
|
|
|
298
283
|
rawPayload: input.rawPayload
|
|
299
284
|
});
|
|
300
285
|
if (!claimed) {
|
|
301
|
-
this.logger.warn(`
|
|
286
|
+
this.logger.warn(`Idempotency: payment event ${input.eventId} already processed \u2014 duplicate discarded.`);
|
|
302
287
|
await this.record("PAYMENT_DUPLICATE_IGNORED", null, context, {
|
|
303
288
|
eventId: input.eventId,
|
|
304
289
|
sessionId: input.sessionId
|
|
@@ -348,7 +333,7 @@ var PendingRegistrationService = class _PendingRegistrationService {
|
|
|
348
333
|
tenantId: result.tenantId,
|
|
349
334
|
subscriptionId: result.subscriptionId
|
|
350
335
|
});
|
|
351
|
-
this.logger.log(`
|
|
336
|
+
this.logger.log(`Activation succeeded: pending=${pending.id} \u2192 user=${result.userId} tenant=${result.tenantId} subscription=${result.subscriptionId}`);
|
|
352
337
|
return {
|
|
353
338
|
activated: true,
|
|
354
339
|
result
|
|
@@ -376,11 +361,11 @@ var PendingRegistrationService = class _PendingRegistrationService {
|
|
|
376
361
|
await this.repo.delete(pending.id);
|
|
377
362
|
} catch (error) {
|
|
378
363
|
const message = error instanceof Error ? error.message : String(error);
|
|
379
|
-
this.logger.warn(`Cleanup:
|
|
364
|
+
this.logger.warn(`Cleanup: pending registration ${pending.id} could not be deleted (${message}).`);
|
|
380
365
|
}
|
|
381
366
|
}
|
|
382
367
|
if (expired.length > 0) {
|
|
383
|
-
this.logger.log(`Cleanup: ${expired.length}
|
|
368
|
+
this.logger.log(`Cleanup: ${expired.length} expired PendingRegistrations deleted.`);
|
|
384
369
|
}
|
|
385
370
|
return {
|
|
386
371
|
deleted: expired.length,
|
|
@@ -390,7 +375,7 @@ var PendingRegistrationService = class _PendingRegistrationService {
|
|
|
390
375
|
async start(input, context) {
|
|
391
376
|
const email = normalizeEmail(input.email);
|
|
392
377
|
if (await this.userLookup.hasActiveUser(email)) {
|
|
393
|
-
this.logger.log(`register/start
|
|
378
|
+
this.logger.log(`register/start ignored for an active account (${email}).`);
|
|
394
379
|
await this.record("REGISTRATION_NEUTRAL_ACTIVE_USER", null, context);
|
|
395
380
|
return {
|
|
396
381
|
neutral: true
|
|
@@ -456,9 +441,7 @@ var PendingRegistrationService = class _PendingRegistrationService {
|
|
|
456
441
|
await this.record("OTP_VERIFY_FAILED", null, context, {
|
|
457
442
|
reason: "unknown_email"
|
|
458
443
|
});
|
|
459
|
-
throw new BadRequestException(
|
|
460
|
-
code: "OTP_INVALID"
|
|
461
|
-
});
|
|
444
|
+
throw new BadRequestException(codedError(REGISTRATION_ERROR_CODES.OTP_INVALID));
|
|
462
445
|
}
|
|
463
446
|
if (pending.status !== "PENDING_EMAIL_VERIFICATION") {
|
|
464
447
|
return {
|
|
@@ -471,43 +454,33 @@ var PendingRegistrationService = class _PendingRegistrationService {
|
|
|
471
454
|
await this.record("OTP_VERIFY_FAILED", pending.id, context, {
|
|
472
455
|
reason: "no_otp_set"
|
|
473
456
|
});
|
|
474
|
-
throw new BadRequestException(
|
|
475
|
-
code: "OTP_INVALID"
|
|
476
|
-
});
|
|
457
|
+
throw new BadRequestException(codedError(REGISTRATION_ERROR_CODES.OTP_INVALID));
|
|
477
458
|
}
|
|
478
459
|
if (pending.otpExpiresAt.getTime() < Date.now()) {
|
|
479
460
|
await this.record("OTP_VERIFY_FAILED", pending.id, context, {
|
|
480
461
|
reason: "expired"
|
|
481
462
|
});
|
|
482
|
-
throw new BadRequestException(
|
|
483
|
-
code: "OTP_EXPIRED"
|
|
484
|
-
});
|
|
463
|
+
throw new BadRequestException(codedError(REGISTRATION_ERROR_CODES.OTP_EXPIRED));
|
|
485
464
|
}
|
|
486
465
|
const maxAttempts = resolveOtpVerifyMaxAttempts();
|
|
487
466
|
if (pending.otpAttemptCount >= maxAttempts) {
|
|
488
467
|
await this.record("OTP_VERIFY_FAILED", pending.id, context, {
|
|
489
468
|
reason: "locked"
|
|
490
469
|
});
|
|
491
|
-
throw new BadRequestException(
|
|
492
|
-
code: "OTP_LOCKED"
|
|
493
|
-
});
|
|
470
|
+
throw new BadRequestException(codedError(REGISTRATION_ERROR_CODES.OTP_LOCKED));
|
|
494
471
|
}
|
|
495
472
|
const attemptCount = await this.repo.incrementOtpAttemptCount(pending.id);
|
|
496
473
|
if (attemptCount > maxAttempts) {
|
|
497
474
|
await this.record("OTP_VERIFY_FAILED", pending.id, context, {
|
|
498
475
|
reason: "locked"
|
|
499
476
|
});
|
|
500
|
-
throw new BadRequestException(
|
|
501
|
-
code: "OTP_LOCKED"
|
|
502
|
-
});
|
|
477
|
+
throw new BadRequestException(codedError(REGISTRATION_ERROR_CODES.OTP_LOCKED));
|
|
503
478
|
}
|
|
504
479
|
if (!verifyOtpCode(pending.otpHash, code)) {
|
|
505
480
|
await this.record("OTP_VERIFY_FAILED", pending.id, context, {
|
|
506
481
|
reason: "wrong_code"
|
|
507
482
|
});
|
|
508
|
-
throw new BadRequestException(
|
|
509
|
-
code: "OTP_INVALID"
|
|
510
|
-
});
|
|
483
|
+
throw new BadRequestException(codedError(REGISTRATION_ERROR_CODES.OTP_INVALID));
|
|
511
484
|
}
|
|
512
485
|
const now = /* @__PURE__ */ new Date();
|
|
513
486
|
const updated = await this.repo.update(pending.id, {
|
|
@@ -549,7 +522,7 @@ var PendingRegistrationService = class _PendingRegistrationService {
|
|
|
549
522
|
const windowMs = OTP_RATE_LIMIT_WINDOW_MINUTES * 60 * 1e3;
|
|
550
523
|
const withinWindow = pending.lastOtpSentAt !== null && now.getTime() - pending.lastOtpSentAt.getTime() < windowMs;
|
|
551
524
|
if (withinWindow && pending.otpSendCount >= OTP_RATE_LIMIT_MAX_SENDS) {
|
|
552
|
-
this.logger.warn(`OTP
|
|
525
|
+
this.logger.warn(`OTP rate limit reached for ${pending.email} \u2014 send is being skipped.`);
|
|
553
526
|
return;
|
|
554
527
|
}
|
|
555
528
|
const code = generateOtpCode();
|
|
@@ -577,7 +550,7 @@ var PendingRegistrationService = class _PendingRegistrationService {
|
|
|
577
550
|
});
|
|
578
551
|
} catch (error) {
|
|
579
552
|
const message = error instanceof Error ? error.message : String(error);
|
|
580
|
-
this.logger.error(`OTP
|
|
553
|
+
this.logger.error(`OTP email to ${pending.email} failed: ${message}`);
|
|
581
554
|
}
|
|
582
555
|
}
|
|
583
556
|
/**
|
|
@@ -604,7 +577,7 @@ var PendingRegistrationService = class _PendingRegistrationService {
|
|
|
604
577
|
});
|
|
605
578
|
} catch (error) {
|
|
606
579
|
const message = error instanceof Error ? error.message : String(error);
|
|
607
|
-
this.logger.error(`Resume
|
|
580
|
+
this.logger.error(`Resume email to ${pending.email} failed: ${message}`);
|
|
608
581
|
}
|
|
609
582
|
}
|
|
610
583
|
/**
|
|
@@ -618,28 +591,20 @@ var PendingRegistrationService = class _PendingRegistrationService {
|
|
|
618
591
|
*/
|
|
619
592
|
async resumeWithToken(input, context) {
|
|
620
593
|
if (!this.resumeTokenSigner) {
|
|
621
|
-
throw new BadRequestException(
|
|
622
|
-
code: "RESUME_NOT_CONFIGURED"
|
|
623
|
-
});
|
|
594
|
+
throw new BadRequestException(codedError(REGISTRATION_ERROR_CODES.RESUME_NOT_CONFIGURED));
|
|
624
595
|
}
|
|
625
596
|
let decoded;
|
|
626
597
|
try {
|
|
627
598
|
decoded = await this.resumeTokenSigner.verify(input.token);
|
|
628
599
|
} catch {
|
|
629
|
-
throw new BadRequestException(
|
|
630
|
-
code: "RESUME_TOKEN_INVALID"
|
|
631
|
-
});
|
|
600
|
+
throw new BadRequestException(codedError(REGISTRATION_ERROR_CODES.RESUME_TOKEN_INVALID));
|
|
632
601
|
}
|
|
633
602
|
const pending = await this.repo.findById(decoded.pendingRegistrationId);
|
|
634
603
|
if (!pending) {
|
|
635
|
-
throw new BadRequestException(
|
|
636
|
-
code: "RESUME_TOKEN_INVALID"
|
|
637
|
-
});
|
|
604
|
+
throw new BadRequestException(codedError(REGISTRATION_ERROR_CODES.RESUME_TOKEN_INVALID));
|
|
638
605
|
}
|
|
639
606
|
if (pending.expiresAt.getTime() < Date.now()) {
|
|
640
|
-
throw new BadRequestException(
|
|
641
|
-
code: "PENDING_REGISTRATION_EXPIRED"
|
|
642
|
-
});
|
|
607
|
+
throw new BadRequestException(codedError(REGISTRATION_ERROR_CODES.PENDING_REGISTRATION_EXPIRED));
|
|
643
608
|
}
|
|
644
609
|
await this.record("REGISTRATION_NEUTRAL_REPLAY", pending.id, context, {
|
|
645
610
|
via: "resume_token",
|
|
@@ -667,9 +632,7 @@ var PendingRegistrationService = class _PendingRegistrationService {
|
|
|
667
632
|
/** Returns the (app-specific) configurator catalog. */
|
|
668
633
|
async getConfiguratorCatalog() {
|
|
669
634
|
if (!this.configuratorLookup) {
|
|
670
|
-
throw new BadRequestException(
|
|
671
|
-
code: "CONFIGURATOR_NOT_CONFIGURED"
|
|
672
|
-
});
|
|
635
|
+
throw new BadRequestException(codedError(REGISTRATION_ERROR_CODES.CONFIGURATOR_NOT_CONFIGURED));
|
|
673
636
|
}
|
|
674
637
|
return this.configuratorLookup.getCatalog();
|
|
675
638
|
}
|
|
@@ -686,32 +649,22 @@ var PendingRegistrationService = class _PendingRegistrationService {
|
|
|
686
649
|
*/
|
|
687
650
|
async saveConfiguration(input, context) {
|
|
688
651
|
if (!this.configuratorLookup) {
|
|
689
|
-
throw new BadRequestException(
|
|
690
|
-
code: "CONFIGURATOR_NOT_CONFIGURED"
|
|
691
|
-
});
|
|
652
|
+
throw new BadRequestException(codedError(REGISTRATION_ERROR_CODES.CONFIGURATOR_NOT_CONFIGURED));
|
|
692
653
|
}
|
|
693
654
|
const pending = await this.repo.findById(input.pendingRegistrationId);
|
|
694
655
|
if (!pending) {
|
|
695
|
-
throw new NotFoundException(
|
|
696
|
-
code: "PENDING_REGISTRATION_NOT_FOUND"
|
|
697
|
-
});
|
|
656
|
+
throw new NotFoundException(codedError(REGISTRATION_ERROR_CODES.PENDING_REGISTRATION_NOT_FOUND));
|
|
698
657
|
}
|
|
699
658
|
if (pending.expiresAt.getTime() < Date.now()) {
|
|
700
|
-
throw new BadRequestException(
|
|
701
|
-
code: "PENDING_REGISTRATION_EXPIRED"
|
|
702
|
-
});
|
|
659
|
+
throw new BadRequestException(codedError(REGISTRATION_ERROR_CODES.PENDING_REGISTRATION_EXPIRED));
|
|
703
660
|
}
|
|
704
661
|
if (pending.status !== "EMAIL_VERIFIED" && pending.status !== "PLAN_SELECTED" && pending.status !== "CHECKOUT_STARTED") {
|
|
705
|
-
throw new BadRequestException(
|
|
706
|
-
code: "INVALID_REGISTRATION_STATE"
|
|
707
|
-
});
|
|
662
|
+
throw new BadRequestException(codedError(REGISTRATION_ERROR_CODES.INVALID_REGISTRATION_STATE));
|
|
708
663
|
}
|
|
709
664
|
const catalog = await this.configuratorLookup.getCatalog();
|
|
710
665
|
const model = catalog.models.find((m) => m.id === input.selection.modelId);
|
|
711
666
|
if (!model) {
|
|
712
|
-
throw new BadRequestException(
|
|
713
|
-
code: "MODEL_NOT_AVAILABLE"
|
|
714
|
-
});
|
|
667
|
+
throw new BadRequestException(codedError(REGISTRATION_ERROR_CODES.MODEL_NOT_AVAILABLE));
|
|
715
668
|
}
|
|
716
669
|
let promoEval;
|
|
717
670
|
if (input.selection.appliedPromoCode && this.promoPreview) {
|
|
@@ -775,28 +728,20 @@ var PendingRegistrationService = class _PendingRegistrationService {
|
|
|
775
728
|
*/
|
|
776
729
|
async previewConfigPromo(pendingRegistrationId, code) {
|
|
777
730
|
if (!this.configuratorLookup) {
|
|
778
|
-
throw new BadRequestException(
|
|
779
|
-
code: "CONFIGURATOR_NOT_CONFIGURED"
|
|
780
|
-
});
|
|
731
|
+
throw new BadRequestException(codedError(REGISTRATION_ERROR_CODES.CONFIGURATOR_NOT_CONFIGURED));
|
|
781
732
|
}
|
|
782
733
|
const pending = await this.repo.findById(pendingRegistrationId);
|
|
783
734
|
if (!pending) {
|
|
784
|
-
throw new NotFoundException(
|
|
785
|
-
code: "PENDING_REGISTRATION_NOT_FOUND"
|
|
786
|
-
});
|
|
735
|
+
throw new NotFoundException(codedError(REGISTRATION_ERROR_CODES.PENDING_REGISTRATION_NOT_FOUND));
|
|
787
736
|
}
|
|
788
737
|
const config = pending.configJson;
|
|
789
738
|
if (!config) {
|
|
790
|
-
throw new BadRequestException(
|
|
791
|
-
code: "CONFIG_NOT_SAVED"
|
|
792
|
-
});
|
|
739
|
+
throw new BadRequestException(codedError(REGISTRATION_ERROR_CODES.CONFIG_NOT_SAVED));
|
|
793
740
|
}
|
|
794
741
|
const catalog = await this.configuratorLookup.getCatalog();
|
|
795
742
|
const model = catalog.models.find((m) => m.id === config.modelId);
|
|
796
743
|
if (!model) {
|
|
797
|
-
throw new BadRequestException(
|
|
798
|
-
code: "MODEL_NOT_AVAILABLE"
|
|
799
|
-
});
|
|
744
|
+
throw new BadRequestException(codedError(REGISTRATION_ERROR_CODES.MODEL_NOT_AVAILABLE));
|
|
800
745
|
}
|
|
801
746
|
let promoEval;
|
|
802
747
|
if (code && this.promoPreview) {
|
|
@@ -854,7 +799,7 @@ var PendingRegistrationService = class _PendingRegistrationService {
|
|
|
854
799
|
return candidate;
|
|
855
800
|
}
|
|
856
801
|
}
|
|
857
|
-
throw new Error(`
|
|
802
|
+
throw new Error(`Could not find a free slug for "${tenantName}".`);
|
|
858
803
|
}
|
|
859
804
|
};
|
|
860
805
|
PendingRegistrationService = _ts_decorate([
|
|
@@ -979,7 +924,7 @@ var RegistrationCleanupCron = class _RegistrationCleanupCron {
|
|
|
979
924
|
}
|
|
980
925
|
}
|
|
981
926
|
if (totalDeleted > 0) {
|
|
982
|
-
this.logger.log(`
|
|
927
|
+
this.logger.log(`Pending registration cleanup finished: ${totalDeleted} deleted in ${iterations} batches.`);
|
|
983
928
|
}
|
|
984
929
|
}
|
|
985
930
|
};
|
|
@@ -1001,6 +946,7 @@ RegistrationCleanupCron = _ts_decorate2([
|
|
|
1001
946
|
|
|
1002
947
|
// src/registration/ip-rate-limit.guard.ts
|
|
1003
948
|
import { HttpException, HttpStatus, Injectable as Injectable3 } from "@nestjs/common";
|
|
949
|
+
import { REGISTRATION_ERROR_CODES as REGISTRATION_ERROR_CODES2 } from "@saasicat/types";
|
|
1004
950
|
function _ts_decorate3(decorators, target, key, desc) {
|
|
1005
951
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
1006
952
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
@@ -1029,9 +975,14 @@ var BaseIpRateLimitGuard = class {
|
|
|
1029
975
|
const key = ipFingerprint(req);
|
|
1030
976
|
if (this.exceeded(key)) {
|
|
1031
977
|
throw new HttpException({
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
978
|
+
...codedError(REGISTRATION_ERROR_CODES2.RATE_LIMITED, {
|
|
979
|
+
retryAfterSeconds: Math.ceil(this.options.windowMs / 1e3)
|
|
980
|
+
}),
|
|
981
|
+
retryAfterSeconds: Math.ceil(this.options.windowMs / 1e3),
|
|
982
|
+
// Superseded by `code`. Note this carries the limiter name,
|
|
983
|
+
// not the code — the two emitters of RATE_LIMITED disagree
|
|
984
|
+
// on what `reason` means, which is why it is going away.
|
|
985
|
+
reason: this.options.name
|
|
1035
986
|
}, HttpStatus.TOO_MANY_REQUESTS);
|
|
1036
987
|
}
|
|
1037
988
|
return true;
|
|
@@ -1173,7 +1124,7 @@ _ts_decorate5([
|
|
|
1173
1124
|
IsOptional(),
|
|
1174
1125
|
IsString(),
|
|
1175
1126
|
Matches(/^[a-z0-9-]+$/, {
|
|
1176
|
-
message: "tenantSlug
|
|
1127
|
+
message: "tenantSlug may only contain lower-case letters, digits and hyphens."
|
|
1177
1128
|
}),
|
|
1178
1129
|
MaxLength(60),
|
|
1179
1130
|
_ts_metadata4("design:type", String)
|
|
@@ -1209,7 +1160,7 @@ _ts_decorate5([
|
|
|
1209
1160
|
], RegisterStartDto.prototype, "password", void 0);
|
|
1210
1161
|
_ts_decorate5([
|
|
1211
1162
|
Equals(true, {
|
|
1212
|
-
message: "
|
|
1163
|
+
message: "The terms of service, privacy policy and data processing agreement must be accepted."
|
|
1213
1164
|
}),
|
|
1214
1165
|
_ts_metadata4("design:type", Boolean)
|
|
1215
1166
|
], RegisterStartDto.prototype, "termsAccepted", void 0);
|
|
@@ -1249,7 +1200,7 @@ _ts_decorate6([
|
|
|
1249
1200
|
_ts_decorate6([
|
|
1250
1201
|
IsString2(),
|
|
1251
1202
|
Matches2(/^\d{6}$/, {
|
|
1252
|
-
message: "OTP
|
|
1203
|
+
message: "The OTP must be 6 digits."
|
|
1253
1204
|
}),
|
|
1254
1205
|
_ts_metadata5("design:type", String)
|
|
1255
1206
|
], VerifyRegistrationOtpDto.prototype, "otp", void 0);
|