@saasicat/nest 0.7.0 → 0.9.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/admin/index.cjs +262 -7
- package/dist/admin/index.d.cts +6 -4
- package/dist/admin/index.d.ts +6 -4
- package/dist/admin/index.js +12 -4
- package/dist/{admin-manifest.service-Cp6uwvmt.d.cts → admin-manifest.service-BMeSLRW4.d.ts} +1 -1
- package/dist/{admin-manifest.service-UGgzR1x-.d.ts → admin-manifest.service-StAQe6QO.d.cts} +1 -1
- package/dist/admin-resources.module-BybEjZs-.d.cts +40 -0
- package/dist/admin-resources.module-CUCLlUAi.d.ts +40 -0
- package/dist/billing/index.cjs +3 -1
- package/dist/billing/index.d.cts +5 -287
- package/dist/billing/index.d.ts +5 -287
- package/dist/billing/index.js +5 -8
- package/dist/catalog/index.d.cts +4 -101
- package/dist/catalog/index.d.ts +4 -101
- package/dist/catalog/index.js +12 -10
- package/dist/catalog.module-BKObceo0.d.ts +103 -0
- package/dist/catalog.module-Dw2Hrbyu.d.cts +103 -0
- package/dist/{chunk-U6HT27J7.js → chunk-3M6VLT5N.js} +257 -6
- package/dist/chunk-7K5PT2LX.js +211 -0
- package/dist/{chunk-RZU4HIAN.js → chunk-GW2I3JZD.js} +25 -22
- package/dist/{chunk-6LP7CDS2.js → chunk-HXAWPPFW.js} +10 -5
- package/dist/chunk-OFBDEO45.js +755 -0
- package/dist/{chunk-5DDCSGZC.js → chunk-PBQRPDO2.js} +142 -354
- package/dist/{chunk-SD3TT2BR.js → chunk-WGVTXSYW.js} +1 -1
- package/dist/{chunk-A2QBXDJC.js → chunk-ZZMAHX22.js} +343 -16
- package/dist/{enforce-quota.interceptor-Dj1Kusr5.d.ts → enforce-quota.interceptor-B3CL5MSw.d.ts} +94 -12
- package/dist/{enforce-quota.interceptor-cv7r80VM.d.cts → enforce-quota.interceptor-SqrQVF91.d.cts} +94 -12
- package/dist/entitlement/index.cjs +1 -0
- package/dist/entitlement/index.d.cts +3 -1
- package/dist/entitlement/index.d.ts +3 -1
- package/dist/entitlement/index.js +1 -2
- package/dist/index.cjs +3503 -2811
- package/dist/index.d.cts +9 -6
- package/dist/index.d.ts +9 -6
- package/dist/index.js +75 -61
- package/dist/module-B5m080F0.d.ts +39 -0
- package/dist/module-DeH_Jkcq.d.cts +39 -0
- package/dist/platform/index.cjs +11113 -971
- package/dist/platform/index.d.cts +41 -7
- package/dist/platform/index.d.ts +41 -7
- package/dist/platform/index.js +26 -6
- package/dist/promo/index.cjs +530 -5
- package/dist/promo/index.d.cts +47 -30
- package/dist/promo/index.d.ts +47 -30
- package/dist/promo/index.js +9 -1
- package/dist/{service-DX8KbGXl.d.cts → service-DlhMnYjW.d.cts} +1 -1
- package/dist/{service-DX8KbGXl.d.ts → service-DlhMnYjW.d.ts} +1 -1
- package/dist/subscription-bundles.module-BQmoozm5.d.ts +291 -0
- package/dist/subscription-bundles.module-DCpV-Pb5.d.cts +291 -0
- package/dist/testing/index.cjs +11101 -973
- package/dist/testing/index.d.cts +9 -4
- package/dist/testing/index.d.ts +9 -4
- package/dist/testing/index.js +10 -4
- package/package.json +4 -4
- package/dist/admin-manifest.config-DyrQNT7M.d.cts +0 -10
- package/dist/admin-manifest.config-DyrQNT7M.d.ts +0 -10
- package/dist/chunk-52UTQRD3.js +0 -326
- package/dist/chunk-Q53N43LQ.js +0 -13
- /package/dist/{chunk-2FR6ZL7R.js → chunk-HWGIMNWR.js} +0 -0
|
@@ -1,17 +1,29 @@
|
|
|
1
|
+
import {
|
|
2
|
+
PromoCodesModule
|
|
3
|
+
} from "./chunk-OFBDEO45.js";
|
|
1
4
|
import {
|
|
2
5
|
AdminManifestModule,
|
|
3
|
-
|
|
4
|
-
|
|
6
|
+
AdminManifestService,
|
|
7
|
+
AdminModule,
|
|
8
|
+
AdminResourcesModule,
|
|
9
|
+
SuperAdminGuard
|
|
10
|
+
} from "./chunk-3M6VLT5N.js";
|
|
11
|
+
import {
|
|
12
|
+
PublicCatalogModule,
|
|
13
|
+
REQUIRE_FEATURE_KEY,
|
|
14
|
+
SubscriptionBundleModule,
|
|
15
|
+
TenantBillingModule
|
|
16
|
+
} from "./chunk-HXAWPPFW.js";
|
|
5
17
|
import {
|
|
6
|
-
|
|
7
|
-
} from "./chunk-
|
|
18
|
+
CatalogModule
|
|
19
|
+
} from "./chunk-PBQRPDO2.js";
|
|
8
20
|
import {
|
|
9
21
|
DiscoveryModule
|
|
10
22
|
} from "./chunk-AJ3EPELS.js";
|
|
11
23
|
import {
|
|
12
24
|
EntitlementModule,
|
|
13
25
|
LimitExceededError
|
|
14
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-GW2I3JZD.js";
|
|
15
27
|
import {
|
|
16
28
|
PLAN_CATALOG_TOKEN,
|
|
17
29
|
PlanCatalogModule
|
|
@@ -269,6 +281,46 @@ EnforceQuotaInterceptor = _ts_decorate3([
|
|
|
269
281
|
])
|
|
270
282
|
], EnforceQuotaInterceptor);
|
|
271
283
|
|
|
284
|
+
// src/platform/quota-providers-usage-snapshot.ts
|
|
285
|
+
var QuotaProvidersUsageSnapshot = class {
|
|
286
|
+
static {
|
|
287
|
+
__name(this, "QuotaProvidersUsageSnapshot");
|
|
288
|
+
}
|
|
289
|
+
providers;
|
|
290
|
+
constructor(providers) {
|
|
291
|
+
this.providers = providers;
|
|
292
|
+
}
|
|
293
|
+
async snapshot(tenantId) {
|
|
294
|
+
const entries = await Promise.all(this.providers.map(async (provider) => [
|
|
295
|
+
provider.key,
|
|
296
|
+
await provider.count(tenantId)
|
|
297
|
+
]));
|
|
298
|
+
return Object.fromEntries(entries);
|
|
299
|
+
}
|
|
300
|
+
};
|
|
301
|
+
|
|
302
|
+
// src/platform/subscription-plan-resolver.ts
|
|
303
|
+
var DEFAULT_ACTIVE_STATUSES = /* @__PURE__ */ new Set([
|
|
304
|
+
"ACTIVE",
|
|
305
|
+
"TRIAL"
|
|
306
|
+
]);
|
|
307
|
+
var SubscriptionPlanResolver = class {
|
|
308
|
+
static {
|
|
309
|
+
__name(this, "SubscriptionPlanResolver");
|
|
310
|
+
}
|
|
311
|
+
subscriptions;
|
|
312
|
+
activeStatuses;
|
|
313
|
+
constructor(subscriptions, activeStatuses = DEFAULT_ACTIVE_STATUSES) {
|
|
314
|
+
this.subscriptions = subscriptions;
|
|
315
|
+
this.activeStatuses = activeStatuses;
|
|
316
|
+
}
|
|
317
|
+
async getPlanIdForTenant(tenantId) {
|
|
318
|
+
const subscription = await this.subscriptions.findByTenantId(tenantId);
|
|
319
|
+
if (!subscription || !this.activeStatuses.has(subscription.status)) return null;
|
|
320
|
+
return subscription.plan;
|
|
321
|
+
}
|
|
322
|
+
};
|
|
323
|
+
|
|
272
324
|
// src/platform/tenant-manifest.service.ts
|
|
273
325
|
import { Injectable as Injectable4 } from "@nestjs/common";
|
|
274
326
|
function _ts_decorate4(decorators, target, key, desc) {
|
|
@@ -413,6 +465,75 @@ function _ts_decorate6(decorators, target, key, desc) {
|
|
|
413
465
|
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
414
466
|
}
|
|
415
467
|
__name(_ts_decorate6, "_ts_decorate");
|
|
468
|
+
var PLATFORM_SUBSCRIPTION_REPOSITORY_TOKEN = /* @__PURE__ */ Symbol.for("saas-platform-nest/PlatformSubscriptionRepository");
|
|
469
|
+
var STANDARD_MANIFEST_REGISTRATION_TOKEN = /* @__PURE__ */ Symbol.for("saas-platform-nest/StandardManifestRegistration");
|
|
470
|
+
function buildStandardManifestContribution(catalog, adminResources, promoCodes) {
|
|
471
|
+
const capabilities = {
|
|
472
|
+
"discovery.read": true
|
|
473
|
+
};
|
|
474
|
+
if (catalog && catalog.adminControllers !== false) {
|
|
475
|
+
Object.assign(capabilities, {
|
|
476
|
+
"plans.read": true,
|
|
477
|
+
"plans.publish": true,
|
|
478
|
+
"bundles.read": true,
|
|
479
|
+
"bundles.write": true,
|
|
480
|
+
"bundles.publish": true,
|
|
481
|
+
"marketingProjections.read": true,
|
|
482
|
+
"marketingProjections.write": true
|
|
483
|
+
});
|
|
484
|
+
}
|
|
485
|
+
const navigation = {};
|
|
486
|
+
if (adminResources) {
|
|
487
|
+
Object.assign(capabilities, {
|
|
488
|
+
"tenants.read": true,
|
|
489
|
+
"tenants.suspend": true,
|
|
490
|
+
"tenants.reactivate": true,
|
|
491
|
+
"users.read": true,
|
|
492
|
+
"audit.read": true,
|
|
493
|
+
"subscriptions.read": true
|
|
494
|
+
});
|
|
495
|
+
navigation.standardPages = {
|
|
496
|
+
subscriptions: {
|
|
497
|
+
enabled: true,
|
|
498
|
+
requiredCapability: "subscriptions.read"
|
|
499
|
+
}
|
|
500
|
+
};
|
|
501
|
+
}
|
|
502
|
+
if (promoCodes) {
|
|
503
|
+
Object.assign(capabilities, {
|
|
504
|
+
"promoCodes.read": true,
|
|
505
|
+
"promoCodes.write": true,
|
|
506
|
+
"promoCodes.delete": true
|
|
507
|
+
});
|
|
508
|
+
navigation.standardPages = {
|
|
509
|
+
...navigation.standardPages ?? {},
|
|
510
|
+
promoCodes: {
|
|
511
|
+
enabled: true,
|
|
512
|
+
requiredCapability: "promoCodes.read"
|
|
513
|
+
}
|
|
514
|
+
};
|
|
515
|
+
}
|
|
516
|
+
return {
|
|
517
|
+
capabilities,
|
|
518
|
+
navigation: navigation.standardPages ? navigation : void 0
|
|
519
|
+
};
|
|
520
|
+
}
|
|
521
|
+
__name(buildStandardManifestContribution, "buildStandardManifestContribution");
|
|
522
|
+
function normalizeTenantAuthGuards(guards) {
|
|
523
|
+
if (!Array.isArray(guards)) return guards;
|
|
524
|
+
return {
|
|
525
|
+
useFactory: /* @__PURE__ */ __name((...instances) => instances, "useFactory"),
|
|
526
|
+
inject: guards
|
|
527
|
+
};
|
|
528
|
+
}
|
|
529
|
+
__name(normalizeTenantAuthGuards, "normalizeTenantAuthGuards");
|
|
530
|
+
function quotaUsageSnapshotProvider(quotaProviders) {
|
|
531
|
+
return {
|
|
532
|
+
useFactory: /* @__PURE__ */ __name((...providers) => new QuotaProvidersUsageSnapshot(providers), "useFactory"),
|
|
533
|
+
inject: quotaProviders
|
|
534
|
+
};
|
|
535
|
+
}
|
|
536
|
+
__name(quotaUsageSnapshotProvider, "quotaUsageSnapshotProvider");
|
|
416
537
|
function buildMinimalManifestConfig() {
|
|
417
538
|
return {
|
|
418
539
|
useFactory: /* @__PURE__ */ __name((catalog) => ({
|
|
@@ -452,6 +573,12 @@ var SaasPlatformModule = class _SaasPlatformModule {
|
|
|
452
573
|
static forRoot(options) {
|
|
453
574
|
const explicit = options.adapters ?? {};
|
|
454
575
|
const persistence = options.persistence;
|
|
576
|
+
const catalogConfig = options.catalog || null;
|
|
577
|
+
const tenantBillingConfig = options.tenantBilling || null;
|
|
578
|
+
const subscriptionBundlesConfig = options.subscriptionBundles || null;
|
|
579
|
+
const adminResourcesConfig = options.adminResources || null;
|
|
580
|
+
const promoCodesConfig = options.promoCodes || null;
|
|
581
|
+
const requiresFullEntitlement = Boolean(options.entitlement || tenantBillingConfig || subscriptionBundlesConfig);
|
|
455
582
|
const adapters = {
|
|
456
583
|
mfa: explicit.mfa ?? persistence?.core.mfa,
|
|
457
584
|
audit: explicit.audit ?? persistence?.core.audit,
|
|
@@ -476,13 +603,52 @@ var SaasPlatformModule = class _SaasPlatformModule {
|
|
|
476
603
|
if (!options.planCatalog && (!adapters.planCatalogReadSink || !options.dbCatalog)) {
|
|
477
604
|
throw new Error("SaasPlatformModule.forRoot: either set `planCatalog` (quickstart YAML path) or, for DB hydration, BOTH a planCatalogReadSink (`adapters`/`persistence`) AND `dbCatalog` ({ projectKey, currency, vatRate }).");
|
|
478
605
|
}
|
|
479
|
-
if (
|
|
606
|
+
if (catalogConfig && !persistence?.catalog) {
|
|
607
|
+
throw new Error("SaasPlatformModule.forRoot: catalog is enabled, but `persistence.catalog` is missing. Use a complete persistence bundle or wire CatalogModule directly.");
|
|
608
|
+
}
|
|
609
|
+
if (adminResourcesConfig && adminResourcesConfig !== true && !adminResourcesConfig.resources && !persistence?.adminResources) {
|
|
610
|
+
throw new Error("SaasPlatformModule.forRoot: adminResources is enabled, but `persistence.adminResources` is missing.");
|
|
611
|
+
}
|
|
612
|
+
if (promoCodesConfig && (!persistence?.promo || !adapters.transactionRunner)) {
|
|
613
|
+
throw new Error("SaasPlatformModule.forRoot: promoCodes requires `persistence.promo` and a transactionRunner.");
|
|
614
|
+
}
|
|
615
|
+
if (promoCodesConfig && promoCodesConfig !== true && promoCodesConfig.includePublicController !== false && !promoCodesConfig.firstTimeCustomerCheck) {
|
|
616
|
+
throw new Error("SaasPlatformModule.forRoot: public promo preview requires `firstTimeCustomerCheck`.");
|
|
617
|
+
}
|
|
618
|
+
if (adminResourcesConfig === true && !persistence?.adminResources) {
|
|
619
|
+
throw new Error("SaasPlatformModule.forRoot: adminResources is enabled, but `persistence.adminResources` is missing.");
|
|
620
|
+
}
|
|
621
|
+
if (tenantBillingConfig && !persistence?.tenantBilling) {
|
|
622
|
+
const missing = [
|
|
623
|
+
!tenantBillingConfig.subscriptionUsagePort && "subscriptionUsagePort",
|
|
624
|
+
!tenantBillingConfig.subscriptionWritePort && "subscriptionWritePort"
|
|
625
|
+
].filter(Boolean);
|
|
626
|
+
if (missing.length) {
|
|
627
|
+
throw new Error(`SaasPlatformModule.forRoot: tenantBilling is enabled, but adapters are missing: ${missing.join(", ")}`);
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
if (subscriptionBundlesConfig && !tenantBillingConfig) {
|
|
631
|
+
throw new Error("SaasPlatformModule.forRoot: subscriptionBundles requires tenantBilling so auth and subscription usage can be shared.");
|
|
632
|
+
}
|
|
633
|
+
if (subscriptionBundlesConfig) {
|
|
634
|
+
const missing = [];
|
|
635
|
+
if (!persistence?.entitlement?.subscriptionBundleRepository) {
|
|
636
|
+
missing.push("subscriptionBundleRepository");
|
|
637
|
+
}
|
|
638
|
+
if (!persistence?.catalog?.bundleRepository) {
|
|
639
|
+
missing.push("bundleRepository");
|
|
640
|
+
}
|
|
641
|
+
if (missing.length) {
|
|
642
|
+
throw new Error(`SaasPlatformModule.forRoot: subscriptionBundles is enabled, but persistence adapters are missing: ${missing.join(", ")}`);
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
if (requiresFullEntitlement) {
|
|
480
646
|
const missing = [];
|
|
481
647
|
if (!adapters.subscriptionRepository) missing.push("subscriptionRepository");
|
|
482
648
|
if (!adapters.planVersionRepository) missing.push("planVersionRepository");
|
|
483
649
|
if (!adapters.transactionRunner) missing.push("transactionRunner");
|
|
484
650
|
if (missing.length) {
|
|
485
|
-
throw new Error(`SaasPlatformModule.forRoot: entitlement active, but adapters are missing: ${missing.join(", ")}`);
|
|
651
|
+
throw new Error(`SaasPlatformModule.forRoot: entitlement active or required by the standard stack, but adapters are missing: ${missing.join(", ")}`);
|
|
486
652
|
}
|
|
487
653
|
if (persistence) {
|
|
488
654
|
assertPersistenceCapabilities(persistence.capabilities, {
|
|
@@ -508,6 +674,9 @@ var SaasPlatformModule = class _SaasPlatformModule {
|
|
|
508
674
|
version: options.planCatalog?.app?.version ?? options.dbCatalog?.app?.version ?? "0.0.0"
|
|
509
675
|
};
|
|
510
676
|
const imports = [
|
|
677
|
+
// Make injected client/auth providers visible to the high-level
|
|
678
|
+
// module's own quota providers and automatic plan resolver too.
|
|
679
|
+
...options.imports ?? [],
|
|
511
680
|
planCatalogModule,
|
|
512
681
|
DiscoveryModule.forRoot({
|
|
513
682
|
app: appInfo,
|
|
@@ -521,12 +690,14 @@ var SaasPlatformModule = class _SaasPlatformModule {
|
|
|
521
690
|
mfaPort,
|
|
522
691
|
auditPort,
|
|
523
692
|
rlsBypassPort,
|
|
693
|
+
imports: options.imports,
|
|
524
694
|
global: true
|
|
525
695
|
}),
|
|
526
696
|
AdminManifestModule.forRoot({
|
|
527
697
|
config: options.adminManifestConfig ?? buildMinimalManifestConfig(),
|
|
528
698
|
guards: options.controller.guards,
|
|
529
699
|
reloadGuards: options.reloadGuards,
|
|
700
|
+
imports: options.imports,
|
|
530
701
|
// Global like AdminModule above: apps register their manifest
|
|
531
702
|
// contribution by injecting AdminManifestService into one of
|
|
532
703
|
// their own modules (handbook §6.6). Re-exporting the module
|
|
@@ -534,26 +705,163 @@ var SaasPlatformModule = class _SaasPlatformModule {
|
|
|
534
705
|
global: true
|
|
535
706
|
})
|
|
536
707
|
];
|
|
537
|
-
if (
|
|
708
|
+
if (requiresFullEntitlement) {
|
|
538
709
|
imports.push(EntitlementModule.forRoot({
|
|
539
710
|
subscriptionRepository: adapters.subscriptionRepository,
|
|
540
711
|
planVersionRepository: adapters.planVersionRepository,
|
|
541
712
|
transactionRunner: adapters.transactionRunner,
|
|
542
|
-
resolutionConfig: options.entitlement.resolutionConfig,
|
|
713
|
+
resolutionConfig: options.entitlement ? options.entitlement.resolutionConfig : void 0,
|
|
543
714
|
subscriptionContractRepository: persistence?.entitlement?.subscriptionContractRepository,
|
|
544
715
|
subscriptionBundleRepository: persistence?.entitlement?.subscriptionBundleRepository,
|
|
545
|
-
bundleRepository: persistence?.entitlement?.bundleRepository
|
|
716
|
+
bundleRepository: persistence?.entitlement?.bundleRepository,
|
|
717
|
+
imports: options.imports,
|
|
718
|
+
global: Boolean(tenantBillingConfig || subscriptionBundlesConfig)
|
|
719
|
+
}));
|
|
720
|
+
}
|
|
721
|
+
if (catalogConfig) {
|
|
722
|
+
const catalog = persistence?.catalog;
|
|
723
|
+
imports.push(CatalogModule.forRoot({
|
|
724
|
+
planRepository: catalog.planRepository,
|
|
725
|
+
bundleRepository: catalog.bundleRepository,
|
|
726
|
+
catalogEntryRepository: catalog.catalogEntryRepository,
|
|
727
|
+
marketingProjectionRepository: catalog.marketingProjectionRepository,
|
|
728
|
+
promotionRepository: catalog.promotionRepository,
|
|
729
|
+
marketingSettingsRepository: catalog.marketingSettingsRepository,
|
|
730
|
+
controller: catalogConfig.adminControllers === false ? void 0 : {
|
|
731
|
+
guards: options.controller.guards
|
|
732
|
+
},
|
|
733
|
+
imports: catalogConfig.imports ?? options.imports,
|
|
734
|
+
extraProviders: catalogConfig.extraProviders,
|
|
735
|
+
strictModeCheckMode: catalogConfig.strictModeCheckMode,
|
|
736
|
+
autoSyncDiscoveryAtBoot: catalogConfig.autoSyncDiscoveryAtBoot,
|
|
737
|
+
marketedOnlyFeatures: catalogConfig.marketedOnlyFeatures,
|
|
738
|
+
featureUiRegistry: catalogConfig.featureUiRegistry,
|
|
739
|
+
publicMarketingCatalog: catalogConfig.publicMarketingCatalog
|
|
740
|
+
}));
|
|
741
|
+
if (catalogConfig.publicCatalog !== false) {
|
|
742
|
+
imports.push(PublicCatalogModule.forRoot({
|
|
743
|
+
featureUiRegistry: catalogConfig.featureUiRegistry,
|
|
744
|
+
projectKey: appInfo.key,
|
|
745
|
+
bundleRepository: catalog.bundleRepository,
|
|
746
|
+
marketingRepository: catalog.marketingProjectionRepository,
|
|
747
|
+
catalogEntryRepository: catalog.catalogEntryRepository,
|
|
748
|
+
imports: catalogConfig.imports ?? options.imports
|
|
749
|
+
}));
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
if (adminResourcesConfig) {
|
|
753
|
+
const config = adminResourcesConfig === true ? {} : adminResourcesConfig;
|
|
754
|
+
imports.push(AdminResourcesModule.forRoot({
|
|
755
|
+
resources: config.resources ?? persistence?.adminResources?.resources,
|
|
756
|
+
guards: config.guards ?? [
|
|
757
|
+
...options.controller.guards,
|
|
758
|
+
SuperAdminGuard
|
|
759
|
+
],
|
|
760
|
+
imports: config.imports ?? options.imports
|
|
761
|
+
}));
|
|
762
|
+
}
|
|
763
|
+
if (promoCodesConfig) {
|
|
764
|
+
const config = promoCodesConfig === true ? {} : promoCodesConfig;
|
|
765
|
+
const promo = persistence?.promo;
|
|
766
|
+
const { firstTimeCustomerCheck, adminGuards, imports: promoImports, includePublicController, ...promoOptions } = config;
|
|
767
|
+
imports.push(PromoCodesModule.forRoot({
|
|
768
|
+
...promoOptions,
|
|
769
|
+
promoCodeRepository: promo.promoCodeRepository,
|
|
770
|
+
redemptionRepository: promo.redemptionRepository,
|
|
771
|
+
validationLogRepository: promo.validationLogRepository,
|
|
772
|
+
subscriptionLookup: promo.subscriptionLookup,
|
|
773
|
+
revenueAggregator: promo.revenueAggregator,
|
|
774
|
+
transactionRunner: adapters.transactionRunner,
|
|
775
|
+
firstTimeCustomerCheck: firstTimeCustomerCheck ?? {
|
|
776
|
+
hasExistingCustomerForEmail: /* @__PURE__ */ __name(async () => false, "hasExistingCustomerForEmail")
|
|
777
|
+
},
|
|
778
|
+
includePublicController: includePublicController ?? false,
|
|
779
|
+
adminController: {
|
|
780
|
+
guards: adminGuards ?? [
|
|
781
|
+
...options.controller.guards,
|
|
782
|
+
SuperAdminGuard
|
|
783
|
+
]
|
|
784
|
+
},
|
|
785
|
+
imports: promoImports ?? options.imports
|
|
786
|
+
}));
|
|
787
|
+
}
|
|
788
|
+
let sharedTenantAuthGuards;
|
|
789
|
+
let sharedSubscriptionUsagePort;
|
|
790
|
+
let quotaProvidersHostedByTenantBilling = false;
|
|
791
|
+
if (tenantBillingConfig) {
|
|
792
|
+
const tenantSlice = persistence?.tenantBilling;
|
|
793
|
+
const { authGuards, subscriptionUsagePort, usageSnapshotPort, subscriptionWritePort, imports: tenantImports, extraProviders, extraExports, ...tenantOptions } = tenantBillingConfig;
|
|
794
|
+
const quotaProviders = options.quotaProviders ?? [];
|
|
795
|
+
quotaProvidersHostedByTenantBilling = quotaProviders.length > 0;
|
|
796
|
+
sharedTenantAuthGuards = normalizeTenantAuthGuards(authGuards);
|
|
797
|
+
sharedSubscriptionUsagePort = subscriptionUsagePort ?? tenantSlice?.subscriptionUsagePort;
|
|
798
|
+
const resolvedUsageSnapshotPort = usageSnapshotPort ?? tenantSlice?.usageSnapshotPort ?? quotaUsageSnapshotProvider(options.quotaProviders ?? []);
|
|
799
|
+
imports.push(TenantBillingModule.forRoot({
|
|
800
|
+
...tenantOptions,
|
|
801
|
+
authGuards: sharedTenantAuthGuards,
|
|
802
|
+
subscriptionUsagePort: sharedSubscriptionUsagePort,
|
|
803
|
+
usageSnapshotPort: resolvedUsageSnapshotPort,
|
|
804
|
+
subscriptionWritePort: subscriptionWritePort ?? tenantSlice?.subscriptionWritePort,
|
|
805
|
+
imports: tenantImports ?? options.imports,
|
|
806
|
+
extraProviders: [
|
|
807
|
+
...quotaProviders,
|
|
808
|
+
...extraProviders ?? []
|
|
809
|
+
],
|
|
810
|
+
extraExports: [
|
|
811
|
+
...quotaProviders,
|
|
812
|
+
...extraExports ?? []
|
|
813
|
+
]
|
|
814
|
+
}));
|
|
815
|
+
}
|
|
816
|
+
if (subscriptionBundlesConfig) {
|
|
817
|
+
const config = subscriptionBundlesConfig === true ? {} : subscriptionBundlesConfig;
|
|
818
|
+
const { controller, imports: bundleImports, extraProviders, ...bundleOptions } = config;
|
|
819
|
+
imports.push(SubscriptionBundleModule.forRoot({
|
|
820
|
+
...bundleOptions,
|
|
821
|
+
subscriptionBundleRepository: persistence?.entitlement?.subscriptionBundleRepository,
|
|
822
|
+
bundleRepository: persistence?.catalog?.bundleRepository,
|
|
823
|
+
controller: controller === false ? void 0 : {
|
|
824
|
+
...controller ?? {},
|
|
825
|
+
authGuards: sharedTenantAuthGuards,
|
|
826
|
+
subscriptionUsagePort: sharedSubscriptionUsagePort
|
|
827
|
+
},
|
|
828
|
+
imports: bundleImports ?? tenantBillingConfig?.imports ?? options.imports,
|
|
829
|
+
extraProviders
|
|
546
830
|
}));
|
|
547
831
|
}
|
|
548
832
|
const lightweightProviders = [];
|
|
549
833
|
const lightweightExports = [];
|
|
550
|
-
|
|
834
|
+
if (options.autoManifest !== false) {
|
|
835
|
+
const contribution = buildStandardManifestContribution(catalogConfig, adminResourcesConfig, promoCodesConfig);
|
|
836
|
+
lightweightProviders.push({
|
|
837
|
+
provide: STANDARD_MANIFEST_REGISTRATION_TOKEN,
|
|
838
|
+
useFactory: /* @__PURE__ */ __name((manifest) => {
|
|
839
|
+
manifest.register(contribution);
|
|
840
|
+
return contribution;
|
|
841
|
+
}, "useFactory"),
|
|
842
|
+
inject: [
|
|
843
|
+
AdminManifestService
|
|
844
|
+
]
|
|
845
|
+
});
|
|
846
|
+
}
|
|
847
|
+
const hasExplicitResolver = !!adapters.planResolver;
|
|
848
|
+
const hasSubscriptionResolver = Boolean(tenantBillingConfig && adapters.subscriptionRepository);
|
|
849
|
+
const hasResolver = hasExplicitResolver || hasSubscriptionResolver;
|
|
551
850
|
const hasFallback = !!options.defaultPlanId;
|
|
552
851
|
if (hasResolver || hasFallback) {
|
|
553
|
-
|
|
852
|
+
if (hasSubscriptionResolver && !hasExplicitResolver) {
|
|
853
|
+
lightweightProviders.push(asProvider(PLATFORM_SUBSCRIPTION_REPOSITORY_TOKEN, adapters.subscriptionRepository));
|
|
854
|
+
}
|
|
855
|
+
lightweightProviders.push(hasExplicitResolver ? asProvider(PLAN_RESOLVER_PORT_TOKEN, adapters.planResolver) : hasSubscriptionResolver ? {
|
|
856
|
+
provide: PLAN_RESOLVER_PORT_TOKEN,
|
|
857
|
+
useFactory: /* @__PURE__ */ __name((subscriptions) => new SubscriptionPlanResolver(subscriptions), "useFactory"),
|
|
858
|
+
inject: [
|
|
859
|
+
PLATFORM_SUBSCRIPTION_REPOSITORY_TOKEN
|
|
860
|
+
]
|
|
861
|
+
} : {
|
|
554
862
|
provide: PLAN_RESOLVER_PORT_TOKEN,
|
|
555
863
|
useValue: new StaticPlanResolver(options.defaultPlanId)
|
|
556
|
-
}, StaticEntitlementService, StaticFeatureGuard, EnforceQuotaInterceptor, ...options.quotaProviders ?? [], {
|
|
864
|
+
}, StaticEntitlementService, StaticFeatureGuard, EnforceQuotaInterceptor, ...quotaProvidersHostedByTenantBilling ? [] : options.quotaProviders ?? [], {
|
|
557
865
|
provide: QUOTA_PROVIDERS_TOKEN,
|
|
558
866
|
useFactory: /* @__PURE__ */ __name((...providers) => providers, "useFactory"),
|
|
559
867
|
inject: options.quotaProviders ?? []
|
|
@@ -569,11 +877,13 @@ var SaasPlatformModule = class _SaasPlatformModule {
|
|
|
569
877
|
const tenantControllers = [];
|
|
570
878
|
if (options.tenantManifest) {
|
|
571
879
|
if (!hasResolver && !hasFallback) {
|
|
572
|
-
throw new Error("SaasPlatformModule.forRoot: tenantManifest
|
|
880
|
+
throw new Error("SaasPlatformModule.forRoot: tenantManifest requires defaultPlanId, adapters.planResolver or tenantBilling so it can resolve features.");
|
|
573
881
|
}
|
|
574
882
|
lightweightProviders.push(TenantManifestService);
|
|
575
883
|
lightweightExports.push(TenantManifestService);
|
|
576
|
-
tenantControllers.push(buildTenantManifestController(options.tenantManifest
|
|
884
|
+
tenantControllers.push(buildTenantManifestController(options.tenantManifest === true ? {
|
|
885
|
+
guards: Array.isArray(tenantBillingConfig?.authGuards) ? tenantBillingConfig.authGuards : options.controller.guards
|
|
886
|
+
} : options.tenantManifest));
|
|
577
887
|
}
|
|
578
888
|
return {
|
|
579
889
|
module: _SaasPlatformModule,
|
|
@@ -588,9 +898,24 @@ var SaasPlatformModule = class _SaasPlatformModule {
|
|
|
588
898
|
// imported module's token directly is an UnknownExportException
|
|
589
899
|
// at boot — the module export below already carries it.
|
|
590
900
|
AdminManifestModule,
|
|
591
|
-
...
|
|
901
|
+
...requiresFullEntitlement ? [
|
|
592
902
|
EntitlementModule
|
|
593
903
|
] : [],
|
|
904
|
+
...catalogConfig ? [
|
|
905
|
+
CatalogModule
|
|
906
|
+
] : [],
|
|
907
|
+
...tenantBillingConfig ? [
|
|
908
|
+
TenantBillingModule
|
|
909
|
+
] : [],
|
|
910
|
+
...subscriptionBundlesConfig ? [
|
|
911
|
+
SubscriptionBundleModule
|
|
912
|
+
] : [],
|
|
913
|
+
...adminResourcesConfig ? [
|
|
914
|
+
AdminResourcesModule
|
|
915
|
+
] : [],
|
|
916
|
+
...promoCodesConfig ? [
|
|
917
|
+
PromoCodesModule
|
|
918
|
+
] : [],
|
|
594
919
|
...lightweightExports
|
|
595
920
|
],
|
|
596
921
|
global: true
|
|
@@ -609,6 +934,8 @@ export {
|
|
|
609
934
|
StaticFeatureGuard,
|
|
610
935
|
QUOTA_PROVIDERS_TOKEN,
|
|
611
936
|
EnforceQuotaInterceptor,
|
|
937
|
+
QuotaProvidersUsageSnapshot,
|
|
938
|
+
SubscriptionPlanResolver,
|
|
612
939
|
TenantManifestService,
|
|
613
940
|
buildTenantManifestController,
|
|
614
941
|
SaasPlatformModule
|
package/dist/{enforce-quota.interceptor-Dj1Kusr5.d.ts → enforce-quota.interceptor-B3CL5MSw.d.ts}
RENAMED
|
@@ -1,9 +1,12 @@
|
|
|
1
|
-
import { Type, CanActivate, DynamicModule, ForwardReference, FactoryProvider, ExecutionContext, NestInterceptor, CallHandler } from '@nestjs/common';
|
|
2
|
-
import { MfaPort, AuditPort, RlsBypassPort, PlanCatalogReadSink, SubscriptionRepository, PlanVersionRepository, TransactionRunner,
|
|
1
|
+
import { Type, CanActivate, DynamicModule, ForwardReference, FactoryProvider, Provider, ExecutionContext, NestInterceptor, CallHandler } from '@nestjs/common';
|
|
2
|
+
import { PlanCatalog, SaasicatPersistenceAdapter, MfaPort, AuditPort, RlsBypassPort, PlanCatalogReadSink, SubscriptionRepository, PlanVersionRepository, TransactionRunner, QuotaProvider, FeatureUiRegistry, SubscriptionUsagePort, UsageSnapshotPort, TenantSubscriptionWritePort, AdminResourcesPort, FirstTimeCustomerCheck } from '@saasicat/types';
|
|
3
3
|
import { P as ProviderSpec } from './di-CcNeq9v-.js';
|
|
4
|
-
import { A as AdminManifestConfig } from './admin-
|
|
5
|
-
import { b as DiscoveryAppInfo } from './discovery.scanner-DLgEvuoy.js';
|
|
4
|
+
import { A as AdminManifestConfig, d as AdminResourcesModuleOptions } from './admin-resources.module-CUCLlUAi.js';
|
|
6
5
|
import { E as EntitlementResolutionConfig } from './plan-resolution-CFCoUkrE.js';
|
|
6
|
+
import { a as PromoCodesModuleOptions } from './module-B5m080F0.js';
|
|
7
|
+
import { b as DiscoveryAppInfo } from './discovery.scanner-DLgEvuoy.js';
|
|
8
|
+
import { b as CatalogModuleOptions } from './catalog.module-BKObceo0.js';
|
|
9
|
+
import { t as TenantBillingModuleOptions, p as SubscriptionBundleModuleOptions, n as SubscriptionBundleControllerOptions } from './subscription-bundles.module-BQmoozm5.js';
|
|
7
10
|
import { Reflector } from '@nestjs/core';
|
|
8
11
|
import { Observable } from 'rxjs';
|
|
9
12
|
|
|
@@ -67,8 +70,8 @@ interface SaasPlatformAdapters {
|
|
|
67
70
|
* Optional — resolver `tenantId → planId`. The quickstart path uses this
|
|
68
71
|
* together with the `StaticEntitlementService` to automatically check
|
|
69
72
|
* `@RequireFeature` and `@EnforceQuota` against the plan catalog limit.
|
|
70
|
-
* If not set, `
|
|
71
|
-
*
|
|
73
|
+
* If not set, `tenantBilling` derives the resolver from the subscription
|
|
74
|
+
* repository. Lightweight setups can instead set `defaultPlanId`.
|
|
72
75
|
*/
|
|
73
76
|
planResolver?: ProviderSpec<PlanResolverPort>;
|
|
74
77
|
/**
|
|
@@ -79,6 +82,50 @@ interface SaasPlatformAdapters {
|
|
|
79
82
|
planVersionRepository?: ProviderSpec<PlanVersionRepository>;
|
|
80
83
|
transactionRunner?: ProviderSpec<TransactionRunner>;
|
|
81
84
|
}
|
|
85
|
+
type PlatformImports = Array<Type<unknown> | DynamicModule | Promise<DynamicModule> | ForwardReference>;
|
|
86
|
+
interface SaasPlatformCatalogOptions extends Pick<CatalogModuleOptions, 'strictModeCheckMode' | 'autoSyncDiscoveryAtBoot' | 'marketedOnlyFeatures' | 'publicMarketingCatalog' | 'extraProviders'> {
|
|
87
|
+
/** Labels/icons used by discovery review and the public catalog. */
|
|
88
|
+
featureUiRegistry: FeatureUiRegistry;
|
|
89
|
+
/** Mount the SuperAdmin catalog controllers. Default `true`. */
|
|
90
|
+
adminControllers?: boolean;
|
|
91
|
+
/** Mount `/billing/plans|bundles|feature-registry`. Default `true`. */
|
|
92
|
+
publicCatalog?: boolean;
|
|
93
|
+
/** Override the top-level module imports for catalog adapter factories. */
|
|
94
|
+
imports?: PlatformImports;
|
|
95
|
+
}
|
|
96
|
+
type SaasPlatformTenantAuthGuards = Array<Type<CanActivate>> | ProviderSpec<ReadonlyArray<CanActivate>>;
|
|
97
|
+
interface SaasPlatformTenantBillingOptions extends Omit<TenantBillingModuleOptions, 'authGuards' | 'subscriptionUsagePort' | 'usageSnapshotPort' | 'subscriptionWritePort' | 'global'> {
|
|
98
|
+
/**
|
|
99
|
+
* Tenant guards as classes (the common path) or as a custom provider
|
|
100
|
+
* factory. Guard classes are resolved from `imports`.
|
|
101
|
+
*/
|
|
102
|
+
authGuards: SaasPlatformTenantAuthGuards;
|
|
103
|
+
/** Optional overrides; otherwise the persistence bundle supplies them. */
|
|
104
|
+
subscriptionUsagePort?: ProviderSpec<SubscriptionUsagePort>;
|
|
105
|
+
usageSnapshotPort?: ProviderSpec<UsageSnapshotPort>;
|
|
106
|
+
subscriptionWritePort?: ProviderSpec<TenantSubscriptionWritePort>;
|
|
107
|
+
}
|
|
108
|
+
interface SaasPlatformSubscriptionBundlesOptions extends Omit<SubscriptionBundleModuleOptions, 'subscriptionBundleRepository' | 'bundleRepository' | 'controller' | 'imports' | 'extraProviders' | 'global'> {
|
|
109
|
+
/** Default mounts the tenant controller and reuses tenant-billing auth. */
|
|
110
|
+
controller?: false | Omit<SubscriptionBundleControllerOptions, 'authGuards' | 'subscriptionUsagePort'>;
|
|
111
|
+
imports?: PlatformImports;
|
|
112
|
+
extraProviders?: Provider[];
|
|
113
|
+
}
|
|
114
|
+
interface SaasPlatformAdminResourcesOptions extends Omit<AdminResourcesModuleOptions, 'resources' | 'guards' | 'global'> {
|
|
115
|
+
/** Override the default controller guards + `SuperAdminGuard` chain. */
|
|
116
|
+
guards?: Array<Type<CanActivate>>;
|
|
117
|
+
/** Custom schema override; the persistence bundle supplies the default. */
|
|
118
|
+
resources?: ProviderSpec<AdminResourcesPort>;
|
|
119
|
+
}
|
|
120
|
+
interface SaasPlatformPromoCodesOptions extends Omit<PromoCodesModuleOptions, 'promoCodeRepository' | 'redemptionRepository' | 'validationLogRepository' | 'subscriptionLookup' | 'revenueAggregator' | 'transactionRunner' | 'firstTimeCustomerCheck' | 'adminController' | 'global'> {
|
|
121
|
+
/**
|
|
122
|
+
* Required when the public preview/redeem flow is enabled. Admin-only
|
|
123
|
+
* setups do not need an app-specific customer-history check.
|
|
124
|
+
*/
|
|
125
|
+
firstTimeCustomerCheck?: ProviderSpec<FirstTimeCustomerCheck>;
|
|
126
|
+
/** Override the default controller guards + `SuperAdminGuard` chain. */
|
|
127
|
+
adminGuards?: Array<Type<CanActivate>>;
|
|
128
|
+
}
|
|
82
129
|
interface SaasPlatformModuleOptions {
|
|
83
130
|
/**
|
|
84
131
|
* Plan catalog. Either as an already-loaded object (quickstart, comes
|
|
@@ -135,7 +182,7 @@ interface SaasPlatformModuleOptions {
|
|
|
135
182
|
* Modules whose providers must be visible in the DI scope (typically:
|
|
136
183
|
* `AuthModule` with the `JwtAuthGuard`).
|
|
137
184
|
*/
|
|
138
|
-
imports?:
|
|
185
|
+
imports?: PlatformImports;
|
|
139
186
|
/**
|
|
140
187
|
* App identity for the DiscoveryScanner. If omitted, `planCatalog.app` is
|
|
141
188
|
* used (recommendation: simply declare it in the YAML).
|
|
@@ -154,10 +201,17 @@ interface SaasPlatformModuleOptions {
|
|
|
154
201
|
*/
|
|
155
202
|
adminManifestConfig?: AdminManifestConfig | Pick<FactoryProvider<AdminManifestConfig>, 'useFactory' | 'inject'>;
|
|
156
203
|
/**
|
|
157
|
-
*
|
|
204
|
+
* Infer manifest capabilities for platform endpoints mounted by this
|
|
205
|
+
* module. Default `true`; set `false` only when the app owns the complete
|
|
206
|
+
* manifest capability policy.
|
|
207
|
+
*/
|
|
208
|
+
autoManifest?: boolean;
|
|
209
|
+
/**
|
|
210
|
+
* Default `false`. When set, `EntitlementModule.forRoot({...})` is called
|
|
158
211
|
* with the repositories from `adapters` — only meaningful if the app
|
|
159
212
|
* implements the V3 contract path (`subscriptionRepository` & co. must then
|
|
160
|
-
* be set).
|
|
213
|
+
* be set). `tenantBilling` and `subscriptionBundles` enable it
|
|
214
|
+
* automatically.
|
|
161
215
|
*/
|
|
162
216
|
entitlement?: false | {
|
|
163
217
|
resolutionConfig?: EntitlementResolutionConfig;
|
|
@@ -177,12 +231,40 @@ interface SaasPlatformModuleOptions {
|
|
|
177
231
|
* `QUOTA_PROVIDERS_TOKEN`.
|
|
178
232
|
*/
|
|
179
233
|
quotaProviders?: Array<Type<QuotaProvider>>;
|
|
234
|
+
/**
|
|
235
|
+
* Standard DB-backed catalog stack. Repositories are taken from
|
|
236
|
+
* `persistence.catalog`; no consumer forwarding module is needed.
|
|
237
|
+
*/
|
|
238
|
+
catalog?: false | SaasPlatformCatalogOptions;
|
|
239
|
+
/**
|
|
240
|
+
* Standard tenant self-service stack. Subscription read/write adapters
|
|
241
|
+
* come from `persistence.tenantBilling`; usage is derived from
|
|
242
|
+
* `quotaProviders` unless explicitly overridden.
|
|
243
|
+
*/
|
|
244
|
+
tenantBilling?: false | SaasPlatformTenantBillingOptions;
|
|
245
|
+
/**
|
|
246
|
+
* Add-on bundle service and tenant controller. `true` uses defaults and
|
|
247
|
+
* reuses tenant-billing auth/usage; an object customizes policy.
|
|
248
|
+
*/
|
|
249
|
+
subscriptionBundles?: false | true | SaasPlatformSubscriptionBundlesOptions;
|
|
250
|
+
/**
|
|
251
|
+
* Standard SuperAdmin Tenant/User/Audit/Subscription endpoints. `true`
|
|
252
|
+
* uses `persistence.adminResources` and the standard guard chain.
|
|
253
|
+
*/
|
|
254
|
+
adminResources?: false | true | SaasPlatformAdminResourcesOptions;
|
|
255
|
+
/**
|
|
256
|
+
* Promo-code domain and SuperAdmin CRUD. `true` enables the admin API
|
|
257
|
+
* without the public preview endpoint; pass an object to enable preview.
|
|
258
|
+
*/
|
|
259
|
+
promoCodes?: false | true | SaasPlatformPromoCodesOptions;
|
|
180
260
|
/**
|
|
181
261
|
* Enable the tenant manifest — the app UI gets a filtered manifest per
|
|
182
262
|
* tenant with features, quotas and visible navigation. Requires that
|
|
183
|
-
* `defaultPlanId
|
|
263
|
+
* `defaultPlanId`, `adapters.planResolver` or `tenantBilling` is set.
|
|
264
|
+
* `true` reuses tenant-billing guard classes when available, otherwise
|
|
265
|
+
* `controller.guards`.
|
|
184
266
|
*/
|
|
185
|
-
tenantManifest?: TenantManifestControllerOptions;
|
|
267
|
+
tenantManifest?: true | TenantManifestControllerOptions;
|
|
186
268
|
}
|
|
187
269
|
/**
|
|
188
270
|
* Bundles PlanCatalog + Discovery + Admin + AdminManifest (+ optionally
|
|
@@ -260,4 +342,4 @@ declare class EnforceQuotaInterceptor implements NestInterceptor {
|
|
|
260
342
|
private check;
|
|
261
343
|
}
|
|
262
344
|
|
|
263
|
-
export { EnforceQuotaInterceptor as E, PLAN_RESOLVER_PORT_TOKEN as P, QUOTA_PROVIDERS_TOKEN as Q,
|
|
345
|
+
export { EnforceQuotaInterceptor as E, PLAN_RESOLVER_PORT_TOKEN as P, QUOTA_PROVIDERS_TOKEN as Q, type SaasPlatformAdapters as S, type TenantManifestControllerOptions as T, StaticEntitlementService as a, StaticFeatureGuard as b, StaticPlanResolver as c, type SaasPlatformModuleOptions as d, type PlanResolverPort as e, STATIC_FEATURE_GUARD_CONFIG_TOKEN as f, SaasPlatformModule as g, type SaasPlatformAdminResourcesOptions as h, type SaasPlatformCatalogOptions as i, type SaasPlatformPromoCodesOptions as j, type SaasPlatformSubscriptionBundlesOptions as k, type SaasPlatformTenantAuthGuards as l, type SaasPlatformTenantBillingOptions as m, type StaticEntitlementSnapshot as n, type StaticFeatureGuardConfig as o, buildTenantManifestController as p };
|