@saasicat/nest 0.18.0 → 0.19.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 +1309 -519
- package/dist/admin/index.js +1 -1
- package/dist/billing/index.d.cts +7 -4
- package/dist/billing/index.d.ts +7 -4
- package/dist/billing/index.js +6 -6
- package/dist/catalog/index.js +4 -4
- package/dist/checkout-offer/index.js +2 -2
- package/dist/{chunk-Z3FWN3HJ.js → chunk-5ZXBXYXU.js} +3 -3
- package/dist/{chunk-RZVSKKXX.js → chunk-6WA4X5U3.js} +46 -45
- package/dist/{chunk-V34AA7C7.js → chunk-6WL6VQ7Z.js} +1 -1
- package/dist/{chunk-ABB2CRAS.js → chunk-74SCJ4HF.js} +1 -1
- package/dist/{chunk-PLJEAUFU.js → chunk-7JIHG53V.js} +76 -39
- package/dist/{chunk-7RRWI5LH.js → chunk-AFK2IE2L.js} +10 -10
- 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-GLLCB4BP.js → chunk-EUU3B6NB.js} +17 -13
- package/dist/{chunk-EXOLOJFZ.js → chunk-F6DCLVBB.js} +29 -8
- package/dist/{chunk-5KH2O4SF.js → chunk-I77VS3YH.js} +287 -105
- package/dist/{chunk-YITTE646.js → chunk-KUDKD7ZG.js} +34 -14
- package/dist/{chunk-P3DP6GJE.js → chunk-LXUBCLRK.js} +486 -160
- package/dist/{chunk-GJBXOCRZ.js → chunk-ORWIGSNN.js} +45 -17
- package/dist/{chunk-E7AJ42AB.js → chunk-QLJHIIOY.js} +168 -28
- package/dist/{chunk-BOADBIGB.js → chunk-YYUXKLXK.js} +2 -2
- package/dist/{define-saasicat-Rc0rXrYG.d.ts → define-saasicat-CqkhnHn-.d.ts} +1 -1
- package/dist/{define-saasicat-CeDBX9ji.d.cts → define-saasicat-D8c6Bs4T.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-DMw-bPyk.d.cts → enforce-quota.interceptor-Dk0eEtzV.d.cts} +1 -1
- package/dist/{enforce-quota.interceptor-CmbWX39L.d.ts → enforce-quota.interceptor-Dp8wTYro.d.ts} +1 -1
- package/dist/entitlement/index.js +2 -2
- package/dist/index.d.cts +6 -6
- package/dist/index.d.ts +6 -6
- package/dist/index.js +17 -17
- package/dist/{module-DgYJur6f.d.ts → module-BwD-wAor.d.ts} +1 -1
- package/dist/{module-CSN8j8Tp.d.cts → module-DsDkbawm.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 +13 -13
- package/dist/promo/index.d.cts +3 -3
- package/dist/promo/index.d.ts +3 -3
- package/dist/promo/index.js +3 -3
- package/dist/registration/index.js +1 -1
- package/dist/{saas-platform.module-DLhoqKNA.d.ts → saas-platform.module-BQmrDGVU.d.ts} +1 -1
- package/dist/{saas-platform.module-D3rUTiho.d.cts → saas-platform.module-DducnQ9s.d.cts} +1 -1
- package/dist/{service-DX8KbGXl.d.cts → service-DPZ2W1E-.d.cts} +2 -2
- package/dist/{service-DX8KbGXl.d.ts → service-DPZ2W1E-.d.ts} +2 -2
- package/dist/subscription-contract/index.js +2 -2
- package/dist/{tenant-billing.controller-BwZRnJ3q.d.ts → tenant-billing.controller-b1G1yB09.d.ts} +2 -2
- package/dist/{tenant-billing.controller-CG4CaFUP.d.cts → tenant-billing.controller-m42YQ_Ei.d.cts} +2 -2
- package/dist/testing/index.d.cts +5 -5
- package/dist/testing/index.d.ts +5 -5
- package/dist/testing/index.js +33 -33
- package/package.json +3 -3
package/dist/admin/index.js
CHANGED
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-m42YQ_Ei.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-DPZ2W1E-.cjs';
|
|
15
15
|
import '../admin-audit.service-9IqXMlZm.cjs';
|
|
16
16
|
|
|
17
17
|
/**
|
|
@@ -199,13 +199,16 @@ declare class FeatureGuard implements CanActivate {
|
|
|
199
199
|
/**
|
|
200
200
|
* Upsell response (#36): with a registered `UpsellOfferResolver` the 403
|
|
201
201
|
* becomes machine-readable (`FeatureNotLicensedBody`), so consumer UIs can
|
|
202
|
-
* render a purchase offer. Without a resolver the
|
|
203
|
-
*
|
|
202
|
+
* render a purchase offer. Without a resolver the body carries the same
|
|
203
|
+
* `code` but no offers.
|
|
204
204
|
*
|
|
205
205
|
* Deliberately 403 + `code` field instead of 402 — rationale in
|
|
206
206
|
* `@saasicat/types` upsell.types.ts (402 is reserved / inconsistently
|
|
207
207
|
* supported; SPA interceptors must not treat the 403 as an auth error, the
|
|
208
208
|
* distinction runs through `code`).
|
|
209
|
+
*
|
|
210
|
+
* The message must keep starting with the word `Feature` — consumers
|
|
211
|
+
* classify the response by that prefix.
|
|
209
212
|
*/
|
|
210
213
|
private buildNotLicensedException;
|
|
211
214
|
/**
|
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-b1G1yB09.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-DPZ2W1E-.js';
|
|
15
15
|
import '../admin-audit.service-9IqXMlZm.js';
|
|
16
16
|
|
|
17
17
|
/**
|
|
@@ -199,13 +199,16 @@ declare class FeatureGuard implements CanActivate {
|
|
|
199
199
|
/**
|
|
200
200
|
* Upsell response (#36): with a registered `UpsellOfferResolver` the 403
|
|
201
201
|
* becomes machine-readable (`FeatureNotLicensedBody`), so consumer UIs can
|
|
202
|
-
* render a purchase offer. Without a resolver the
|
|
203
|
-
*
|
|
202
|
+
* render a purchase offer. Without a resolver the body carries the same
|
|
203
|
+
* `code` but no offers.
|
|
204
204
|
*
|
|
205
205
|
* Deliberately 403 + `code` field instead of 402 — rationale in
|
|
206
206
|
* `@saasicat/types` upsell.types.ts (402 is reserved / inconsistently
|
|
207
207
|
* supported; SPA interceptors must not treat the 403 as an auth error, the
|
|
208
208
|
* distinction runs through `code`).
|
|
209
|
+
*
|
|
210
|
+
* The message must keep starting with the word `Feature` — consumers
|
|
211
|
+
* classify the response by that prefix.
|
|
209
212
|
*/
|
|
210
213
|
private buildNotLicensedException;
|
|
211
214
|
/**
|
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-I77VS3YH.js";
|
|
62
|
+
import "../chunk-QLJHIIOY.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-F6DCLVBB.js";
|
|
85
85
|
import {
|
|
86
86
|
PLAN_CATALOG_READ_SINK_TOKEN,
|
|
87
87
|
PLAN_CATALOG_TOKEN,
|
|
@@ -96,7 +96,7 @@ 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
101
|
import "../chunk-WKVBNTYC.js";
|
|
102
102
|
import "../chunk-L4KTQ6CL.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-AFK2IE2L.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-LXUBCLRK.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-ORWIGSNN.js";
|
|
10
|
+
import "../chunk-BSK6YBLI.js";
|
|
11
11
|
import "../chunk-YSC46BGM.js";
|
|
12
12
|
import "../chunk-L4KTQ6CL.js";
|
|
13
13
|
import "../chunk-SABTXESR.js";
|
|
@@ -74,7 +74,7 @@ var DiscoveryScanner = class _DiscoveryScanner {
|
|
|
74
74
|
writeFileSync(path, JSON.stringify(snapshot, null, 2) + "\n", "utf-8");
|
|
75
75
|
this.logger.log(`Discovery snapshot persisted to ${path}`);
|
|
76
76
|
} catch (err) {
|
|
77
|
-
this.logger.warn(`
|
|
77
|
+
this.logger.warn(`The discovery snapshot could not be written to ${path}: ${err.message}`);
|
|
78
78
|
}
|
|
79
79
|
}
|
|
80
80
|
/**
|
|
@@ -159,7 +159,7 @@ var DiscoveryScanner = class _DiscoveryScanner {
|
|
|
159
159
|
registerCapability(target, meta, declaredAt) {
|
|
160
160
|
const existing = target.get(meta.capabilityKey);
|
|
161
161
|
if (existing) {
|
|
162
|
-
this.logger.warn(`Capability '${meta.capabilityKey}'
|
|
162
|
+
this.logger.warn(`Capability '${meta.capabilityKey}' is declared in several places (${existing.declaredAt} and ${declaredAt}); the first declaration wins`);
|
|
163
163
|
return;
|
|
164
164
|
}
|
|
165
165
|
target.set(meta.capabilityKey, {
|
|
@@ -180,7 +180,7 @@ var DiscoveryScanner = class _DiscoveryScanner {
|
|
|
180
180
|
registerQuota(target, opts, declaredAt) {
|
|
181
181
|
const existing = target.get(opts.key);
|
|
182
182
|
if (existing) {
|
|
183
|
-
this.logger.warn(`Quota '${opts.key}'
|
|
183
|
+
this.logger.warn(`Quota '${opts.key}' is defined in several places (${existing.declaredAt} and ${declaredAt}); the first definition wins`);
|
|
184
184
|
return;
|
|
185
185
|
}
|
|
186
186
|
target.set(opts.key, {
|
|
@@ -54,7 +54,7 @@ var REGISTRATION_CONFIG_TOKEN = /* @__PURE__ */ Symbol.for("saas-platform/Regist
|
|
|
54
54
|
|
|
55
55
|
// src/registration/pending-registration.service.ts
|
|
56
56
|
import { BadRequestException, Inject, Injectable, Logger, NotFoundException, Optional } from "@nestjs/common";
|
|
57
|
-
import { REGISTRATION_RESUME_TTL_MINUTES } from "@saasicat/types";
|
|
57
|
+
import { REGISTRATION_ERROR_CODES, REGISTRATION_RESUME_TTL_MINUTES } from "@saasicat/types";
|
|
58
58
|
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
59
|
|
|
60
60
|
// src/registration/pricing.ts
|
|
@@ -173,7 +173,7 @@ var PendingRegistrationService = class _PendingRegistrationService {
|
|
|
173
173
|
});
|
|
174
174
|
} catch (error) {
|
|
175
175
|
const message = error instanceof Error ? error.message : String(error);
|
|
176
|
-
this.logger.warn(`Audit
|
|
176
|
+
this.logger.warn(`Audit log write failed (${eventType}): ${message}`);
|
|
177
177
|
}
|
|
178
178
|
}
|
|
179
179
|
/** Public signup plan list for step 3 (frontend `usePublicPlans()`). */
|
|
@@ -184,23 +184,23 @@ var PendingRegistrationService = class _PendingRegistrationService {
|
|
|
184
184
|
const pending = await this.repo.findById(input.pendingRegistrationId);
|
|
185
185
|
if (!pending) {
|
|
186
186
|
throw new NotFoundException({
|
|
187
|
-
code:
|
|
187
|
+
code: REGISTRATION_ERROR_CODES.PENDING_REGISTRATION_NOT_FOUND
|
|
188
188
|
});
|
|
189
189
|
}
|
|
190
190
|
if (pending.expiresAt.getTime() < Date.now()) {
|
|
191
191
|
throw new BadRequestException({
|
|
192
|
-
code:
|
|
192
|
+
code: REGISTRATION_ERROR_CODES.PENDING_REGISTRATION_EXPIRED
|
|
193
193
|
});
|
|
194
194
|
}
|
|
195
195
|
if (pending.status !== "EMAIL_VERIFIED" && pending.status !== "PLAN_SELECTED" && pending.status !== "CHECKOUT_STARTED") {
|
|
196
196
|
throw new BadRequestException({
|
|
197
|
-
code:
|
|
197
|
+
code: REGISTRATION_ERROR_CODES.INVALID_REGISTRATION_STATE
|
|
198
198
|
});
|
|
199
199
|
}
|
|
200
200
|
const plan = await this.planCatalog.findPublicSignupPlan(input.planId);
|
|
201
201
|
if (!plan) {
|
|
202
202
|
throw new BadRequestException({
|
|
203
|
-
code:
|
|
203
|
+
code: REGISTRATION_ERROR_CODES.PLAN_NOT_AVAILABLE
|
|
204
204
|
});
|
|
205
205
|
}
|
|
206
206
|
const now = /* @__PURE__ */ new Date();
|
|
@@ -225,28 +225,28 @@ var PendingRegistrationService = class _PendingRegistrationService {
|
|
|
225
225
|
const pending = await this.repo.findById(input.pendingRegistrationId);
|
|
226
226
|
if (!pending) {
|
|
227
227
|
throw new NotFoundException({
|
|
228
|
-
code:
|
|
228
|
+
code: REGISTRATION_ERROR_CODES.PENDING_REGISTRATION_NOT_FOUND
|
|
229
229
|
});
|
|
230
230
|
}
|
|
231
231
|
if (pending.expiresAt.getTime() < Date.now()) {
|
|
232
232
|
throw new BadRequestException({
|
|
233
|
-
code:
|
|
233
|
+
code: REGISTRATION_ERROR_CODES.PENDING_REGISTRATION_EXPIRED
|
|
234
234
|
});
|
|
235
235
|
}
|
|
236
236
|
if (pending.status !== "PLAN_SELECTED" && pending.status !== "CHECKOUT_STARTED") {
|
|
237
237
|
throw new BadRequestException({
|
|
238
|
-
code:
|
|
238
|
+
code: REGISTRATION_ERROR_CODES.PLAN_NOT_SELECTED
|
|
239
239
|
});
|
|
240
240
|
}
|
|
241
241
|
if (!pending.selectedPlanId) {
|
|
242
242
|
throw new BadRequestException({
|
|
243
|
-
code:
|
|
243
|
+
code: REGISTRATION_ERROR_CODES.PLAN_NOT_SELECTED
|
|
244
244
|
});
|
|
245
245
|
}
|
|
246
246
|
const plan = await this.planCatalog.findPublicSignupPlan(pending.selectedPlanId);
|
|
247
247
|
if (!plan) {
|
|
248
248
|
throw new BadRequestException({
|
|
249
|
-
code:
|
|
249
|
+
code: REGISTRATION_ERROR_CODES.PLAN_NOT_AVAILABLE
|
|
250
250
|
});
|
|
251
251
|
}
|
|
252
252
|
const session = await this.paymentProvider.createCheckoutSession({
|
|
@@ -298,7 +298,7 @@ var PendingRegistrationService = class _PendingRegistrationService {
|
|
|
298
298
|
rawPayload: input.rawPayload
|
|
299
299
|
});
|
|
300
300
|
if (!claimed) {
|
|
301
|
-
this.logger.warn(`
|
|
301
|
+
this.logger.warn(`Idempotency: payment event ${input.eventId} already processed \u2014 duplicate discarded.`);
|
|
302
302
|
await this.record("PAYMENT_DUPLICATE_IGNORED", null, context, {
|
|
303
303
|
eventId: input.eventId,
|
|
304
304
|
sessionId: input.sessionId
|
|
@@ -348,7 +348,7 @@ var PendingRegistrationService = class _PendingRegistrationService {
|
|
|
348
348
|
tenantId: result.tenantId,
|
|
349
349
|
subscriptionId: result.subscriptionId
|
|
350
350
|
});
|
|
351
|
-
this.logger.log(`
|
|
351
|
+
this.logger.log(`Activation succeeded: pending=${pending.id} \u2192 user=${result.userId} tenant=${result.tenantId} subscription=${result.subscriptionId}`);
|
|
352
352
|
return {
|
|
353
353
|
activated: true,
|
|
354
354
|
result
|
|
@@ -376,11 +376,11 @@ var PendingRegistrationService = class _PendingRegistrationService {
|
|
|
376
376
|
await this.repo.delete(pending.id);
|
|
377
377
|
} catch (error) {
|
|
378
378
|
const message = error instanceof Error ? error.message : String(error);
|
|
379
|
-
this.logger.warn(`Cleanup:
|
|
379
|
+
this.logger.warn(`Cleanup: pending registration ${pending.id} could not be deleted (${message}).`);
|
|
380
380
|
}
|
|
381
381
|
}
|
|
382
382
|
if (expired.length > 0) {
|
|
383
|
-
this.logger.log(`Cleanup: ${expired.length}
|
|
383
|
+
this.logger.log(`Cleanup: ${expired.length} expired PendingRegistrations deleted.`);
|
|
384
384
|
}
|
|
385
385
|
return {
|
|
386
386
|
deleted: expired.length,
|
|
@@ -390,7 +390,7 @@ var PendingRegistrationService = class _PendingRegistrationService {
|
|
|
390
390
|
async start(input, context) {
|
|
391
391
|
const email = normalizeEmail(input.email);
|
|
392
392
|
if (await this.userLookup.hasActiveUser(email)) {
|
|
393
|
-
this.logger.log(`register/start
|
|
393
|
+
this.logger.log(`register/start ignored for an active account (${email}).`);
|
|
394
394
|
await this.record("REGISTRATION_NEUTRAL_ACTIVE_USER", null, context);
|
|
395
395
|
return {
|
|
396
396
|
neutral: true
|
|
@@ -457,7 +457,7 @@ var PendingRegistrationService = class _PendingRegistrationService {
|
|
|
457
457
|
reason: "unknown_email"
|
|
458
458
|
});
|
|
459
459
|
throw new BadRequestException({
|
|
460
|
-
code:
|
|
460
|
+
code: REGISTRATION_ERROR_CODES.OTP_INVALID
|
|
461
461
|
});
|
|
462
462
|
}
|
|
463
463
|
if (pending.status !== "PENDING_EMAIL_VERIFICATION") {
|
|
@@ -472,7 +472,7 @@ var PendingRegistrationService = class _PendingRegistrationService {
|
|
|
472
472
|
reason: "no_otp_set"
|
|
473
473
|
});
|
|
474
474
|
throw new BadRequestException({
|
|
475
|
-
code:
|
|
475
|
+
code: REGISTRATION_ERROR_CODES.OTP_INVALID
|
|
476
476
|
});
|
|
477
477
|
}
|
|
478
478
|
if (pending.otpExpiresAt.getTime() < Date.now()) {
|
|
@@ -480,7 +480,7 @@ var PendingRegistrationService = class _PendingRegistrationService {
|
|
|
480
480
|
reason: "expired"
|
|
481
481
|
});
|
|
482
482
|
throw new BadRequestException({
|
|
483
|
-
code:
|
|
483
|
+
code: REGISTRATION_ERROR_CODES.OTP_EXPIRED
|
|
484
484
|
});
|
|
485
485
|
}
|
|
486
486
|
const maxAttempts = resolveOtpVerifyMaxAttempts();
|
|
@@ -489,7 +489,7 @@ var PendingRegistrationService = class _PendingRegistrationService {
|
|
|
489
489
|
reason: "locked"
|
|
490
490
|
});
|
|
491
491
|
throw new BadRequestException({
|
|
492
|
-
code:
|
|
492
|
+
code: REGISTRATION_ERROR_CODES.OTP_LOCKED
|
|
493
493
|
});
|
|
494
494
|
}
|
|
495
495
|
const attemptCount = await this.repo.incrementOtpAttemptCount(pending.id);
|
|
@@ -498,7 +498,7 @@ var PendingRegistrationService = class _PendingRegistrationService {
|
|
|
498
498
|
reason: "locked"
|
|
499
499
|
});
|
|
500
500
|
throw new BadRequestException({
|
|
501
|
-
code:
|
|
501
|
+
code: REGISTRATION_ERROR_CODES.OTP_LOCKED
|
|
502
502
|
});
|
|
503
503
|
}
|
|
504
504
|
if (!verifyOtpCode(pending.otpHash, code)) {
|
|
@@ -506,7 +506,7 @@ var PendingRegistrationService = class _PendingRegistrationService {
|
|
|
506
506
|
reason: "wrong_code"
|
|
507
507
|
});
|
|
508
508
|
throw new BadRequestException({
|
|
509
|
-
code:
|
|
509
|
+
code: REGISTRATION_ERROR_CODES.OTP_INVALID
|
|
510
510
|
});
|
|
511
511
|
}
|
|
512
512
|
const now = /* @__PURE__ */ new Date();
|
|
@@ -549,7 +549,7 @@ var PendingRegistrationService = class _PendingRegistrationService {
|
|
|
549
549
|
const windowMs = OTP_RATE_LIMIT_WINDOW_MINUTES * 60 * 1e3;
|
|
550
550
|
const withinWindow = pending.lastOtpSentAt !== null && now.getTime() - pending.lastOtpSentAt.getTime() < windowMs;
|
|
551
551
|
if (withinWindow && pending.otpSendCount >= OTP_RATE_LIMIT_MAX_SENDS) {
|
|
552
|
-
this.logger.warn(`OTP
|
|
552
|
+
this.logger.warn(`OTP rate limit reached for ${pending.email} \u2014 send is being skipped.`);
|
|
553
553
|
return;
|
|
554
554
|
}
|
|
555
555
|
const code = generateOtpCode();
|
|
@@ -577,7 +577,7 @@ var PendingRegistrationService = class _PendingRegistrationService {
|
|
|
577
577
|
});
|
|
578
578
|
} catch (error) {
|
|
579
579
|
const message = error instanceof Error ? error.message : String(error);
|
|
580
|
-
this.logger.error(`OTP
|
|
580
|
+
this.logger.error(`OTP email to ${pending.email} failed: ${message}`);
|
|
581
581
|
}
|
|
582
582
|
}
|
|
583
583
|
/**
|
|
@@ -604,7 +604,7 @@ var PendingRegistrationService = class _PendingRegistrationService {
|
|
|
604
604
|
});
|
|
605
605
|
} catch (error) {
|
|
606
606
|
const message = error instanceof Error ? error.message : String(error);
|
|
607
|
-
this.logger.error(`Resume
|
|
607
|
+
this.logger.error(`Resume email to ${pending.email} failed: ${message}`);
|
|
608
608
|
}
|
|
609
609
|
}
|
|
610
610
|
/**
|
|
@@ -619,7 +619,7 @@ var PendingRegistrationService = class _PendingRegistrationService {
|
|
|
619
619
|
async resumeWithToken(input, context) {
|
|
620
620
|
if (!this.resumeTokenSigner) {
|
|
621
621
|
throw new BadRequestException({
|
|
622
|
-
code:
|
|
622
|
+
code: REGISTRATION_ERROR_CODES.RESUME_NOT_CONFIGURED
|
|
623
623
|
});
|
|
624
624
|
}
|
|
625
625
|
let decoded;
|
|
@@ -627,18 +627,18 @@ var PendingRegistrationService = class _PendingRegistrationService {
|
|
|
627
627
|
decoded = await this.resumeTokenSigner.verify(input.token);
|
|
628
628
|
} catch {
|
|
629
629
|
throw new BadRequestException({
|
|
630
|
-
code:
|
|
630
|
+
code: REGISTRATION_ERROR_CODES.RESUME_TOKEN_INVALID
|
|
631
631
|
});
|
|
632
632
|
}
|
|
633
633
|
const pending = await this.repo.findById(decoded.pendingRegistrationId);
|
|
634
634
|
if (!pending) {
|
|
635
635
|
throw new BadRequestException({
|
|
636
|
-
code:
|
|
636
|
+
code: REGISTRATION_ERROR_CODES.RESUME_TOKEN_INVALID
|
|
637
637
|
});
|
|
638
638
|
}
|
|
639
639
|
if (pending.expiresAt.getTime() < Date.now()) {
|
|
640
640
|
throw new BadRequestException({
|
|
641
|
-
code:
|
|
641
|
+
code: REGISTRATION_ERROR_CODES.PENDING_REGISTRATION_EXPIRED
|
|
642
642
|
});
|
|
643
643
|
}
|
|
644
644
|
await this.record("REGISTRATION_NEUTRAL_REPLAY", pending.id, context, {
|
|
@@ -668,7 +668,7 @@ var PendingRegistrationService = class _PendingRegistrationService {
|
|
|
668
668
|
async getConfiguratorCatalog() {
|
|
669
669
|
if (!this.configuratorLookup) {
|
|
670
670
|
throw new BadRequestException({
|
|
671
|
-
code:
|
|
671
|
+
code: REGISTRATION_ERROR_CODES.CONFIGURATOR_NOT_CONFIGURED
|
|
672
672
|
});
|
|
673
673
|
}
|
|
674
674
|
return this.configuratorLookup.getCatalog();
|
|
@@ -687,30 +687,30 @@ var PendingRegistrationService = class _PendingRegistrationService {
|
|
|
687
687
|
async saveConfiguration(input, context) {
|
|
688
688
|
if (!this.configuratorLookup) {
|
|
689
689
|
throw new BadRequestException({
|
|
690
|
-
code:
|
|
690
|
+
code: REGISTRATION_ERROR_CODES.CONFIGURATOR_NOT_CONFIGURED
|
|
691
691
|
});
|
|
692
692
|
}
|
|
693
693
|
const pending = await this.repo.findById(input.pendingRegistrationId);
|
|
694
694
|
if (!pending) {
|
|
695
695
|
throw new NotFoundException({
|
|
696
|
-
code:
|
|
696
|
+
code: REGISTRATION_ERROR_CODES.PENDING_REGISTRATION_NOT_FOUND
|
|
697
697
|
});
|
|
698
698
|
}
|
|
699
699
|
if (pending.expiresAt.getTime() < Date.now()) {
|
|
700
700
|
throw new BadRequestException({
|
|
701
|
-
code:
|
|
701
|
+
code: REGISTRATION_ERROR_CODES.PENDING_REGISTRATION_EXPIRED
|
|
702
702
|
});
|
|
703
703
|
}
|
|
704
704
|
if (pending.status !== "EMAIL_VERIFIED" && pending.status !== "PLAN_SELECTED" && pending.status !== "CHECKOUT_STARTED") {
|
|
705
705
|
throw new BadRequestException({
|
|
706
|
-
code:
|
|
706
|
+
code: REGISTRATION_ERROR_CODES.INVALID_REGISTRATION_STATE
|
|
707
707
|
});
|
|
708
708
|
}
|
|
709
709
|
const catalog = await this.configuratorLookup.getCatalog();
|
|
710
710
|
const model = catalog.models.find((m) => m.id === input.selection.modelId);
|
|
711
711
|
if (!model) {
|
|
712
712
|
throw new BadRequestException({
|
|
713
|
-
code:
|
|
713
|
+
code: REGISTRATION_ERROR_CODES.MODEL_NOT_AVAILABLE
|
|
714
714
|
});
|
|
715
715
|
}
|
|
716
716
|
let promoEval;
|
|
@@ -776,26 +776,26 @@ var PendingRegistrationService = class _PendingRegistrationService {
|
|
|
776
776
|
async previewConfigPromo(pendingRegistrationId, code) {
|
|
777
777
|
if (!this.configuratorLookup) {
|
|
778
778
|
throw new BadRequestException({
|
|
779
|
-
code:
|
|
779
|
+
code: REGISTRATION_ERROR_CODES.CONFIGURATOR_NOT_CONFIGURED
|
|
780
780
|
});
|
|
781
781
|
}
|
|
782
782
|
const pending = await this.repo.findById(pendingRegistrationId);
|
|
783
783
|
if (!pending) {
|
|
784
784
|
throw new NotFoundException({
|
|
785
|
-
code:
|
|
785
|
+
code: REGISTRATION_ERROR_CODES.PENDING_REGISTRATION_NOT_FOUND
|
|
786
786
|
});
|
|
787
787
|
}
|
|
788
788
|
const config = pending.configJson;
|
|
789
789
|
if (!config) {
|
|
790
790
|
throw new BadRequestException({
|
|
791
|
-
code:
|
|
791
|
+
code: REGISTRATION_ERROR_CODES.CONFIG_NOT_SAVED
|
|
792
792
|
});
|
|
793
793
|
}
|
|
794
794
|
const catalog = await this.configuratorLookup.getCatalog();
|
|
795
795
|
const model = catalog.models.find((m) => m.id === config.modelId);
|
|
796
796
|
if (!model) {
|
|
797
797
|
throw new BadRequestException({
|
|
798
|
-
code:
|
|
798
|
+
code: REGISTRATION_ERROR_CODES.MODEL_NOT_AVAILABLE
|
|
799
799
|
});
|
|
800
800
|
}
|
|
801
801
|
let promoEval;
|
|
@@ -854,7 +854,7 @@ var PendingRegistrationService = class _PendingRegistrationService {
|
|
|
854
854
|
return candidate;
|
|
855
855
|
}
|
|
856
856
|
}
|
|
857
|
-
throw new Error(`
|
|
857
|
+
throw new Error(`Could not find a free slug for "${tenantName}".`);
|
|
858
858
|
}
|
|
859
859
|
};
|
|
860
860
|
PendingRegistrationService = _ts_decorate([
|
|
@@ -979,7 +979,7 @@ var RegistrationCleanupCron = class _RegistrationCleanupCron {
|
|
|
979
979
|
}
|
|
980
980
|
}
|
|
981
981
|
if (totalDeleted > 0) {
|
|
982
|
-
this.logger.log(`
|
|
982
|
+
this.logger.log(`Pending registration cleanup finished: ${totalDeleted} deleted in ${iterations} batches.`);
|
|
983
983
|
}
|
|
984
984
|
}
|
|
985
985
|
};
|
|
@@ -1001,6 +1001,7 @@ RegistrationCleanupCron = _ts_decorate2([
|
|
|
1001
1001
|
|
|
1002
1002
|
// src/registration/ip-rate-limit.guard.ts
|
|
1003
1003
|
import { HttpException, HttpStatus, Injectable as Injectable3 } from "@nestjs/common";
|
|
1004
|
+
import { REGISTRATION_ERROR_CODES as REGISTRATION_ERROR_CODES2 } from "@saasicat/types";
|
|
1004
1005
|
function _ts_decorate3(decorators, target, key, desc) {
|
|
1005
1006
|
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
1006
1007
|
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
@@ -1029,7 +1030,7 @@ var BaseIpRateLimitGuard = class {
|
|
|
1029
1030
|
const key = ipFingerprint(req);
|
|
1030
1031
|
if (this.exceeded(key)) {
|
|
1031
1032
|
throw new HttpException({
|
|
1032
|
-
code:
|
|
1033
|
+
code: REGISTRATION_ERROR_CODES2.RATE_LIMITED,
|
|
1033
1034
|
reason: this.options.name,
|
|
1034
1035
|
retryAfterSeconds: Math.ceil(this.options.windowMs / 1e3)
|
|
1035
1036
|
}, HttpStatus.TOO_MANY_REQUESTS);
|
|
@@ -1173,7 +1174,7 @@ _ts_decorate5([
|
|
|
1173
1174
|
IsOptional(),
|
|
1174
1175
|
IsString(),
|
|
1175
1176
|
Matches(/^[a-z0-9-]+$/, {
|
|
1176
|
-
message: "tenantSlug
|
|
1177
|
+
message: "tenantSlug may only contain lower-case letters, digits and hyphens."
|
|
1177
1178
|
}),
|
|
1178
1179
|
MaxLength(60),
|
|
1179
1180
|
_ts_metadata4("design:type", String)
|
|
@@ -1209,7 +1210,7 @@ _ts_decorate5([
|
|
|
1209
1210
|
], RegisterStartDto.prototype, "password", void 0);
|
|
1210
1211
|
_ts_decorate5([
|
|
1211
1212
|
Equals(true, {
|
|
1212
|
-
message: "
|
|
1213
|
+
message: "The terms of service, privacy policy and data processing agreement must be accepted."
|
|
1213
1214
|
}),
|
|
1214
1215
|
_ts_metadata4("design:type", Boolean)
|
|
1215
1216
|
], RegisterStartDto.prototype, "termsAccepted", void 0);
|
|
@@ -1249,7 +1250,7 @@ _ts_decorate6([
|
|
|
1249
1250
|
_ts_decorate6([
|
|
1250
1251
|
IsString2(),
|
|
1251
1252
|
Matches2(/^\d{6}$/, {
|
|
1252
|
-
message: "OTP
|
|
1253
|
+
message: "The OTP must be 6 digits."
|
|
1253
1254
|
}),
|
|
1254
1255
|
_ts_metadata5("design:type", String)
|
|
1255
1256
|
], VerifyRegistrationOtpDto.prototype, "otp", void 0);
|
|
@@ -11,7 +11,7 @@ var DiscoverySnapshotNotFoundError = class extends Error {
|
|
|
11
11
|
}
|
|
12
12
|
path;
|
|
13
13
|
constructor(path) {
|
|
14
|
-
super(`Discovery
|
|
14
|
+
super(`Discovery snapshot file not found: ${path}. Boot the app first with DISCOVERY_SNAPSHOT_PATH or DiscoveryModule.forRoot({ snapshotPath: '\u2026' }) so that the scanner writes the file on the OnApplicationBootstrap hook.`), this.path = path;
|
|
15
15
|
this.name = "DiscoverySnapshotNotFoundError";
|
|
16
16
|
}
|
|
17
17
|
};
|