@saasicat/nest 0.21.0 → 0.22.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/dist/_entries.cjs +409 -276
  2. package/dist/admin/index.js +1 -1
  3. package/dist/{aggregation-o0LMenvl.d.ts → aggregation-DP5zfKbU.d.ts} +3 -3
  4. package/dist/{aggregation-SKfXu09x.d.cts → aggregation-mZ7WZROK.d.cts} +3 -3
  5. package/dist/billing/index.d.cts +12 -10
  6. package/dist/billing/index.d.ts +12 -10
  7. package/dist/billing/index.js +6 -2
  8. package/dist/catalog/index.d.cts +10 -10
  9. package/dist/catalog/index.d.ts +10 -10
  10. package/dist/catalog/index.js +2 -2
  11. package/dist/{catalog.module-BKObceo0.d.ts → catalog.module-CQr1FpkI.d.ts} +6 -6
  12. package/dist/{catalog.module-Dw2Hrbyu.d.cts → catalog.module-D-_pQDNA.d.cts} +6 -6
  13. package/dist/{chunk-GC5AKN44.js → chunk-7X5MSAIL.js} +7 -7
  14. package/dist/{chunk-55QGAZRQ.js → chunk-7ZPFQXHM.js} +1 -1
  15. package/dist/{chunk-NZLAYCEX.js → chunk-A7FHAN2I.js} +17 -3
  16. package/dist/{chunk-ZH5PYEMI.js → chunk-LPCUHZWC.js} +180 -61
  17. package/dist/{chunk-3DRZ5GCP.js → chunk-MJ32VNZD.js} +1 -1
  18. package/dist/{chunk-AGOG5B77.js → chunk-NNNXXUPT.js} +1 -1
  19. package/dist/{chunk-FYWLPYBK.js → chunk-SN5UOC43.js} +3 -3
  20. package/dist/{define-saasicat-B20Ms8UC.d.ts → define-saasicat-BK6RRWWG.d.ts} +1 -1
  21. package/dist/{define-saasicat-Cf9DpEsY.d.cts → define-saasicat-D30I-WET.d.cts} +1 -1
  22. package/dist/discovery/index.d.cts +2 -2
  23. package/dist/discovery/index.d.ts +2 -2
  24. package/dist/{enforce-quota.interceptor-CUyfR4cQ.d.ts → enforce-quota.interceptor-B9QueAFf.d.ts} +4 -1
  25. package/dist/{enforce-quota.interceptor-Dtg5WdFj.d.cts → enforce-quota.interceptor-DY6CLjoP.d.cts} +4 -1
  26. package/dist/entitlement/index.d.cts +1 -1
  27. package/dist/entitlement/index.d.ts +1 -1
  28. package/dist/entitlement/index.js +1 -1
  29. package/dist/index.d.cts +8 -8
  30. package/dist/index.d.ts +8 -8
  31. package/dist/index.js +12 -8
  32. package/dist/{plan-versions.service-BB36Q1bg.d.ts → plan-versions.service-B-YoE4SZ.d.ts} +1 -1
  33. package/dist/{plan-versions.service-CUR2Whyr.d.cts → plan-versions.service-_saKzb50.d.cts} +1 -1
  34. package/dist/platform/index.d.cts +31 -13
  35. package/dist/platform/index.d.ts +31 -13
  36. package/dist/platform/index.js +8 -6
  37. package/dist/registration/index.d.cts +1 -1
  38. package/dist/registration/index.d.ts +1 -1
  39. package/dist/registration/index.js +1 -1
  40. package/dist/{saas-platform.module-BfaYfL-G.d.cts → saas-platform.module-CgalxzcT.d.cts} +2 -2
  41. package/dist/{saas-platform.module-DChhDrR-.d.ts → saas-platform.module-D1mUZPrz.d.ts} +2 -2
  42. package/dist/{subscription-bundles.module-BQmoozm5.d.ts → subscription-bundles.module-BDbODWvA.d.ts} +9 -1
  43. package/dist/{subscription-bundles.module-DCpV-Pb5.d.cts → subscription-bundles.module-Cfi-lFWF.d.cts} +9 -1
  44. package/dist/{tenant-billing.controller-DT5UrnDX.d.ts → tenant-billing.controller-BSlpFqVA.d.ts} +3 -3
  45. package/dist/{tenant-billing.controller-BIF-mstX.d.cts → tenant-billing.controller-DHSUrT_N.d.cts} +3 -3
  46. package/dist/testing/index.d.cts +5 -5
  47. package/dist/testing/index.d.ts +5 -5
  48. package/dist/testing/index.js +6 -6
  49. package/package.json +3 -3
  50. /package/dist/{chunk-EWPF57AG.js → chunk-FY4EJTV4.js} +0 -0
@@ -28,7 +28,7 @@ import {
28
28
  SUBSCRIPTION_BUNDLE_REPOSITORY_TOKEN,
29
29
  isLimitExceededError,
30
30
  toEffectiveLimitsSnapshot
31
- } from "./chunk-AGOG5B77.js";
31
+ } from "./chunk-NNNXXUPT.js";
32
32
  import {
33
33
  PLAN_CATALOG_TOKEN,
34
34
  findPlan,
@@ -174,6 +174,16 @@ function computeNextPeriod(sub, now) {
174
174
  }
175
175
  __name(computeNextPeriod, "computeNextPeriod");
176
176
 
177
+ // src/billing/feature-guard-marker.ts
178
+ var FEATURE_GUARD_MARKER = /* @__PURE__ */ Symbol.for("saasicat/nest/feature-guard");
179
+ function isPlatformFeatureGuard(target) {
180
+ if (target === null || typeof target !== "function" && typeof target !== "object") {
181
+ return false;
182
+ }
183
+ return target[FEATURE_GUARD_MARKER] === true;
184
+ }
185
+ __name(isPlatformFeatureGuard, "isPlatformFeatureGuard");
186
+
177
187
  // src/billing/require-feature.decorator.ts
178
188
  import { SetMetadata } from "@nestjs/common";
179
189
  var REQUIRE_FEATURE_KEY = "require-feature";
@@ -217,6 +227,8 @@ var FeatureGuard = class _FeatureGuard {
217
227
  entitlements;
218
228
  config;
219
229
  upsellResolver;
230
+ /** Lets `FeatureGuardCoverageCheck` recognise this guard across CJS entries. */
231
+ static [FEATURE_GUARD_MARKER] = true;
220
232
  logger = new Logger(_FeatureGuard.name);
221
233
  constructor(reflector, entitlements, config = null, upsellResolver = null) {
222
234
  this.reflector = reflector;
@@ -577,7 +589,7 @@ function _ts_param3(paramIndex, decorator) {
577
589
  }
578
590
  __name(_ts_param3, "_ts_param");
579
591
  var PLAN_CATALOG_IMPORT_SINK_TOKEN = /* @__PURE__ */ Symbol.for("saas-platform/PlanCatalogImportSink");
580
- var IMPORT_CHANGE_NOTE = "Initial import from saas.yaml (SPEC_V2 \xA711.1 M6 Pack 2c)";
592
+ var IMPORT_CHANGE_NOTE = "Initial import from saas.yaml";
581
593
  var PlanCatalogImporterService = class {
582
594
  static {
583
595
  __name(this, "PlanCatalogImporterService");
@@ -868,7 +880,7 @@ var PublicCatalogController = class {
868
880
  return merged;
869
881
  }
870
882
  /**
871
- * SPEC_V2 §11.1 M6 Pack 2c — public catalog endpoint for bundles
883
+ * — public catalog endpoint for bundles
872
884
  * (stem list with live versions). If a `MarketingProjection` with
873
885
  * `targetType=BUNDLE` + matching locale exists, it is merged in.
874
886
  */
@@ -3461,6 +3473,8 @@ export {
3461
3473
  decideRenewal,
3462
3474
  clearPendingPlanVersionFields,
3463
3475
  computeNextPeriod,
3476
+ FEATURE_GUARD_MARKER,
3477
+ isPlatformFeatureGuard,
3464
3478
  REQUIRE_FEATURE_KEY,
3465
3479
  RequireFeature,
3466
3480
  FEATURE_GUARD_CONFIG_TOKEN,
@@ -9,19 +9,21 @@ import {
9
9
  AdminStatsModule,
10
10
  MfaService,
11
11
  SuperAdminGuard
12
- } from "./chunk-FYWLPYBK.js";
12
+ } from "./chunk-SN5UOC43.js";
13
13
  import {
14
+ FEATURE_GUARD_MARKER,
14
15
  PublicCatalogModule,
15
16
  REQUIRE_FEATURE_KEY,
16
17
  SubscriptionBundleModule,
17
- TenantBillingModule
18
- } from "./chunk-NZLAYCEX.js";
18
+ TenantBillingModule,
19
+ isPlatformFeatureGuard
20
+ } from "./chunk-A7FHAN2I.js";
19
21
  import {
20
22
  SubscriptionContractModule
21
23
  } from "./chunk-B7NRY2LV.js";
22
24
  import {
23
25
  CatalogModule
24
- } from "./chunk-GC5AKN44.js";
26
+ } from "./chunk-7X5MSAIL.js";
25
27
  import {
26
28
  CheckoutOfferModule
27
29
  } from "./chunk-XTVAFJ3P.js";
@@ -34,7 +36,7 @@ import {
34
36
  import {
35
37
  EntitlementModule,
36
38
  LimitExceededError
37
- } from "./chunk-AGOG5B77.js";
39
+ } from "./chunk-NNNXXUPT.js";
38
40
  import {
39
41
  PLAN_CATALOG_TOKEN,
40
42
  PlanCatalogModule
@@ -445,10 +447,9 @@ StaticEntitlementService = _ts_decorate4([
445
447
  ])
446
448
  ], StaticEntitlementService);
447
449
 
448
- // src/platform/static-feature.guard.ts
449
- import { ForbiddenException as ForbiddenException2, Inject as Inject3, Injectable as Injectable3, Optional } from "@nestjs/common";
450
- import { Reflector } from "@nestjs/core";
451
- import { AUTH_ERROR_CODES, FEATURE_NOT_LICENSED } from "@saasicat/types";
450
+ // src/platform/feature-guard-coverage.check.ts
451
+ import { Inject as Inject3, Injectable as Injectable3, Logger } from "@nestjs/common";
452
+ import { DiscoveryService, MetadataScanner } from "@nestjs/core";
452
453
  function _ts_decorate5(decorators, target, key, desc) {
453
454
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
454
455
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
@@ -466,6 +467,115 @@ function _ts_param4(paramIndex, decorator) {
466
467
  };
467
468
  }
468
469
  __name(_ts_param4, "_ts_param");
470
+ var GUARDS_METADATA = "__guards__";
471
+ var METHOD_METADATA = "method";
472
+ var FeatureGuardCoverageCheck = class {
473
+ static {
474
+ __name(this, "FeatureGuardCoverageCheck");
475
+ }
476
+ discoveryService;
477
+ metadataScanner;
478
+ logger = new Logger("SaaSiCat");
479
+ constructor(discoveryService, metadataScanner) {
480
+ this.discoveryService = discoveryService;
481
+ this.metadataScanner = metadataScanner;
482
+ }
483
+ onApplicationBootstrap() {
484
+ const uncovered = this.findUncoveredRoutes();
485
+ if (uncovered.length === 0) return;
486
+ const list = uncovered.map((r) => ` ${r.controller}.${r.handler} \u2014 requires ${r.features.join(" or ")}`).join("\n");
487
+ this.logger.warn(`globalFeatureGuard is off and ${uncovered.length} annotated route(s) have no feature guard in front of them, so they serve unlicensed traffic:
488
+ ${list}
489
+ Bind one behind your auth guard \u2014 @UseGuards(JwtAuthGuard, StaticFeatureGuard), or FeatureGuard from @saasicat/nest/billing on the V3 entitlement path. A guard of your own that wraps either one is not recognised here; if that is what these routes use, they are covered.`);
490
+ }
491
+ /**
492
+ * Annotated handlers whose own guards and whose controller's guards contain
493
+ * no recognisable feature guard.
494
+ *
495
+ * Deliberately conservative in one direction only: an unrecognised wrapper
496
+ * is reported (and the message says so) rather than assumed safe, because
497
+ * the named route is cheap to check. The reverse — staying silent about a
498
+ * route with no guard at all — is the failure this exists to prevent.
499
+ */
500
+ findUncoveredRoutes() {
501
+ const uncovered = [];
502
+ for (const wrapper of this.discoveryService.getControllers()) {
503
+ const instance = wrapper.instance;
504
+ if (!instance || typeof instance !== "object") continue;
505
+ const ctor = instance.constructor;
506
+ if (!ctor) continue;
507
+ const classGuards = readGuards(ctor);
508
+ const prototype = Object.getPrototypeOf(instance);
509
+ for (const method of this.metadataScanner.getAllMethodNames(prototype)) {
510
+ const handler = instance[method];
511
+ if (typeof handler !== "function") continue;
512
+ if (Reflect.getMetadata(METHOD_METADATA, handler) === void 0) continue;
513
+ const features = readFeatures(handler) ?? readFeatures(ctor) ?? /* not annotated */
514
+ null;
515
+ if (!features || features.length === 0) continue;
516
+ const guards = [
517
+ ...classGuards,
518
+ ...readGuards(handler)
519
+ ];
520
+ if (guards.some(isPlatformFeatureGuard)) continue;
521
+ uncovered.push({
522
+ controller: ctor.name,
523
+ handler: method,
524
+ features
525
+ });
526
+ }
527
+ }
528
+ return uncovered;
529
+ }
530
+ };
531
+ FeatureGuardCoverageCheck = _ts_decorate5([
532
+ Injectable3(),
533
+ _ts_param4(0, Inject3(DiscoveryService)),
534
+ _ts_param4(1, Inject3(MetadataScanner)),
535
+ _ts_metadata4("design:type", Function),
536
+ _ts_metadata4("design:paramtypes", [
537
+ typeof DiscoveryService === "undefined" ? Object : DiscoveryService,
538
+ typeof MetadataScanner === "undefined" ? Object : MetadataScanner
539
+ ])
540
+ ], FeatureGuardCoverageCheck);
541
+ function readFeatures(target) {
542
+ const value = Reflect.getMetadata(REQUIRE_FEATURE_KEY, target);
543
+ return Array.isArray(value) ? value : null;
544
+ }
545
+ __name(readFeatures, "readFeatures");
546
+ function readGuards(target) {
547
+ const value = Reflect.getMetadata(GUARDS_METADATA, target);
548
+ if (!Array.isArray(value)) return [];
549
+ return value.flatMap((guard) => typeof guard === "function" ? [
550
+ guard
551
+ ] : [
552
+ guard,
553
+ guard?.constructor
554
+ ]);
555
+ }
556
+ __name(readGuards, "readGuards");
557
+
558
+ // src/platform/static-feature.guard.ts
559
+ import { ForbiddenException as ForbiddenException2, Inject as Inject4, Injectable as Injectable4, Optional } from "@nestjs/common";
560
+ import { Reflector } from "@nestjs/core";
561
+ import { AUTH_ERROR_CODES, FEATURE_NOT_LICENSED } from "@saasicat/types";
562
+ function _ts_decorate6(decorators, target, key, desc) {
563
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
564
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
565
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
566
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
567
+ }
568
+ __name(_ts_decorate6, "_ts_decorate");
569
+ function _ts_metadata5(k, v) {
570
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
571
+ }
572
+ __name(_ts_metadata5, "_ts_metadata");
573
+ function _ts_param5(paramIndex, decorator) {
574
+ return function(target, key) {
575
+ decorator(target, key, paramIndex);
576
+ };
577
+ }
578
+ __name(_ts_param5, "_ts_param");
469
579
  var STATIC_FEATURE_GUARD_CONFIG_TOKEN = /* @__PURE__ */ Symbol.for("saas-platform-nest/StaticFeatureGuardConfig");
470
580
  var StaticFeatureGuard = class {
471
581
  static {
@@ -474,6 +584,8 @@ var StaticFeatureGuard = class {
474
584
  reflector;
475
585
  entitlements;
476
586
  config;
587
+ /** Lets `FeatureGuardCoverageCheck` recognise this guard across CJS entries. */
588
+ static [FEATURE_GUARD_MARKER] = true;
477
589
  constructor(reflector, entitlements, config = null) {
478
590
  this.reflector = reflector;
479
591
  this.entitlements = entitlements;
@@ -517,14 +629,14 @@ var StaticFeatureGuard = class {
517
629
  return true;
518
630
  }
519
631
  };
520
- StaticFeatureGuard = _ts_decorate5([
521
- Injectable3(),
522
- _ts_param4(0, Inject3(Reflector)),
523
- _ts_param4(1, Inject3(StaticEntitlementService)),
524
- _ts_param4(2, Optional()),
525
- _ts_param4(2, Inject3(STATIC_FEATURE_GUARD_CONFIG_TOKEN)),
526
- _ts_metadata4("design:type", Function),
527
- _ts_metadata4("design:paramtypes", [
632
+ StaticFeatureGuard = _ts_decorate6([
633
+ Injectable4(),
634
+ _ts_param5(0, Inject4(Reflector)),
635
+ _ts_param5(1, Inject4(StaticEntitlementService)),
636
+ _ts_param5(2, Optional()),
637
+ _ts_param5(2, Inject4(STATIC_FEATURE_GUARD_CONFIG_TOKEN)),
638
+ _ts_metadata5("design:type", Function),
639
+ _ts_metadata5("design:paramtypes", [
528
640
  typeof Reflector === "undefined" ? Object : Reflector,
529
641
  typeof StaticEntitlementService === "undefined" ? Object : StaticEntitlementService,
530
642
  Object
@@ -532,27 +644,27 @@ StaticFeatureGuard = _ts_decorate5([
532
644
  ], StaticFeatureGuard);
533
645
 
534
646
  // src/platform/enforce-quota.interceptor.ts
535
- import { Inject as Inject4, Injectable as Injectable4, Optional as Optional2 } from "@nestjs/common";
647
+ import { Inject as Inject5, Injectable as Injectable5, Optional as Optional2 } from "@nestjs/common";
536
648
  import { Reflector as Reflector2 } from "@nestjs/core";
537
649
  import { from } from "rxjs";
538
650
  import { switchMap } from "rxjs/operators";
539
- function _ts_decorate6(decorators, target, key, desc) {
651
+ function _ts_decorate7(decorators, target, key, desc) {
540
652
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
541
653
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
542
654
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
543
655
  return c > 3 && r && Object.defineProperty(target, key, r), r;
544
656
  }
545
- __name(_ts_decorate6, "_ts_decorate");
546
- function _ts_metadata5(k, v) {
657
+ __name(_ts_decorate7, "_ts_decorate");
658
+ function _ts_metadata6(k, v) {
547
659
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
548
660
  }
549
- __name(_ts_metadata5, "_ts_metadata");
550
- function _ts_param5(paramIndex, decorator) {
661
+ __name(_ts_metadata6, "_ts_metadata");
662
+ function _ts_param6(paramIndex, decorator) {
551
663
  return function(target, key) {
552
664
  decorator(target, key, paramIndex);
553
665
  };
554
666
  }
555
- __name(_ts_param5, "_ts_param");
667
+ __name(_ts_param6, "_ts_param");
556
668
  var QUOTA_PROVIDERS_TOKEN = /* @__PURE__ */ Symbol.for("saas-platform-nest/QuotaProviders");
557
669
  var EnforceQuotaInterceptor = class {
558
670
  static {
@@ -595,14 +707,14 @@ var EnforceQuotaInterceptor = class {
595
707
  }
596
708
  }
597
709
  };
598
- EnforceQuotaInterceptor = _ts_decorate6([
599
- Injectable4(),
600
- _ts_param5(0, Inject4(Reflector2)),
601
- _ts_param5(1, Inject4(StaticEntitlementService)),
602
- _ts_param5(2, Optional2()),
603
- _ts_param5(2, Inject4(QUOTA_PROVIDERS_TOKEN)),
604
- _ts_metadata5("design:type", Function),
605
- _ts_metadata5("design:paramtypes", [
710
+ EnforceQuotaInterceptor = _ts_decorate7([
711
+ Injectable5(),
712
+ _ts_param6(0, Inject5(Reflector2)),
713
+ _ts_param6(1, Inject5(StaticEntitlementService)),
714
+ _ts_param6(2, Optional2()),
715
+ _ts_param6(2, Inject5(QUOTA_PROVIDERS_TOKEN)),
716
+ _ts_metadata6("design:type", Function),
717
+ _ts_metadata6("design:paramtypes", [
606
718
  typeof Reflector2 === "undefined" ? Object : Reflector2,
607
719
  typeof StaticEntitlementService === "undefined" ? Object : StaticEntitlementService,
608
720
  Object
@@ -650,18 +762,18 @@ var SubscriptionPlanResolver = class {
650
762
  };
651
763
 
652
764
  // src/platform/tenant-manifest.service.ts
653
- import { Injectable as Injectable5 } from "@nestjs/common";
654
- function _ts_decorate7(decorators, target, key, desc) {
765
+ import { Injectable as Injectable6 } from "@nestjs/common";
766
+ function _ts_decorate8(decorators, target, key, desc) {
655
767
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
656
768
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
657
769
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
658
770
  return c > 3 && r && Object.defineProperty(target, key, r), r;
659
771
  }
660
- __name(_ts_decorate7, "_ts_decorate");
661
- function _ts_metadata6(k, v) {
772
+ __name(_ts_decorate8, "_ts_decorate");
773
+ function _ts_metadata7(k, v) {
662
774
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
663
775
  }
664
- __name(_ts_metadata6, "_ts_metadata");
776
+ __name(_ts_metadata7, "_ts_metadata");
665
777
  var TenantManifestService = class {
666
778
  static {
667
779
  __name(this, "TenantManifestService");
@@ -707,10 +819,10 @@ var TenantManifestService = class {
707
819
  };
708
820
  }
709
821
  };
710
- TenantManifestService = _ts_decorate7([
711
- Injectable5(),
712
- _ts_metadata6("design:type", Function),
713
- _ts_metadata6("design:paramtypes", [
822
+ TenantManifestService = _ts_decorate8([
823
+ Injectable6(),
824
+ _ts_metadata7("design:type", Function),
825
+ _ts_metadata7("design:paramtypes", [
714
826
  typeof StaticEntitlementService === "undefined" ? Object : StaticEntitlementService
715
827
  ])
716
828
  ], TenantManifestService);
@@ -724,24 +836,24 @@ function isVisible(item, features) {
724
836
  __name(isVisible, "isVisible");
725
837
 
726
838
  // src/platform/tenant-manifest.controller.ts
727
- import { Controller as Controller2, Get as Get2, Inject as Inject5, Req, UseGuards } from "@nestjs/common";
728
- function _ts_decorate8(decorators, target, key, desc) {
839
+ import { Controller as Controller2, Get as Get2, Inject as Inject6, Req, UseGuards } from "@nestjs/common";
840
+ function _ts_decorate9(decorators, target, key, desc) {
729
841
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
730
842
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
731
843
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
732
844
  return c > 3 && r && Object.defineProperty(target, key, r), r;
733
845
  }
734
- __name(_ts_decorate8, "_ts_decorate");
735
- function _ts_metadata7(k, v) {
846
+ __name(_ts_decorate9, "_ts_decorate");
847
+ function _ts_metadata8(k, v) {
736
848
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
737
849
  }
738
- __name(_ts_metadata7, "_ts_metadata");
739
- function _ts_param6(paramIndex, decorator) {
850
+ __name(_ts_metadata8, "_ts_metadata");
851
+ function _ts_param7(paramIndex, decorator) {
740
852
  return function(target, key) {
741
853
  decorator(target, key, paramIndex);
742
854
  };
743
855
  }
744
- __name(_ts_param6, "_ts_param");
856
+ __name(_ts_param7, "_ts_param");
745
857
  function buildTenantManifestController(options) {
746
858
  const path = options.path ?? "tenant/manifest";
747
859
  let GeneratedTenantManifestController = class GeneratedTenantManifestController {
@@ -760,21 +872,21 @@ function buildTenantManifestController(options) {
760
872
  return this.svc.getManifest(tenantId);
761
873
  }
762
874
  };
763
- _ts_decorate8([
875
+ _ts_decorate9([
764
876
  Get2(),
765
- _ts_param6(0, Req()),
766
- _ts_metadata7("design:type", Function),
767
- _ts_metadata7("design:paramtypes", [
877
+ _ts_param7(0, Req()),
878
+ _ts_metadata8("design:type", Function),
879
+ _ts_metadata8("design:paramtypes", [
768
880
  typeof RequestWithUser === "undefined" ? Object : RequestWithUser
769
881
  ]),
770
- _ts_metadata7("design:returntype", Promise)
882
+ _ts_metadata8("design:returntype", Promise)
771
883
  ], GeneratedTenantManifestController.prototype, "get", null);
772
- GeneratedTenantManifestController = _ts_decorate8([
884
+ GeneratedTenantManifestController = _ts_decorate9([
773
885
  Controller2(path),
774
886
  UseGuards(...options.guards),
775
- _ts_param6(0, Inject5(TenantManifestService)),
776
- _ts_metadata7("design:type", Function),
777
- _ts_metadata7("design:paramtypes", [
887
+ _ts_param7(0, Inject6(TenantManifestService)),
888
+ _ts_metadata8("design:type", Function),
889
+ _ts_metadata8("design:paramtypes", [
778
890
  typeof TenantManifestService === "undefined" ? Object : TenantManifestService
779
891
  ])
780
892
  ], GeneratedTenantManifestController);
@@ -783,16 +895,17 @@ function buildTenantManifestController(options) {
783
895
  __name(buildTenantManifestController, "buildTenantManifestController");
784
896
 
785
897
  // src/platform/saas-platform.module.ts
786
- import { Module as Module2 } from "@nestjs/common";
898
+ import { Logger as Logger2, Module as Module2 } from "@nestjs/common";
787
899
  import { APP_GUARD, APP_INTERCEPTOR } from "@nestjs/core";
788
900
  import { assertPersistenceCapabilities } from "@saasicat/types";
789
- function _ts_decorate9(decorators, target, key, desc) {
901
+ function _ts_decorate10(decorators, target, key, desc) {
790
902
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
791
903
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
792
904
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
793
905
  return c > 3 && r && Object.defineProperty(target, key, r), r;
794
906
  }
795
- __name(_ts_decorate9, "_ts_decorate");
907
+ __name(_ts_decorate10, "_ts_decorate");
908
+ var PLATFORM_LOGGER = new Logger2("SaaSiCat");
796
909
  var PLATFORM_SUBSCRIPTION_REPOSITORY_TOKEN = /* @__PURE__ */ Symbol.for("saas-platform-nest/PlatformSubscriptionRepository");
797
910
  var STANDARD_MANIFEST_REGISTRATION_TOKEN = /* @__PURE__ */ Symbol.for("saas-platform-nest/StandardManifestRegistration");
798
911
  function buildStandardManifestContribution(catalog, adminResources, promoCodes) {
@@ -1257,6 +1370,11 @@ var SaasPlatformModule = class _SaasPlatformModule {
1257
1370
  useExisting: EnforceQuotaInterceptor
1258
1371
  });
1259
1372
  lightweightExports.push(PLAN_RESOLVER_PORT_TOKEN, StaticEntitlementService, StaticFeatureGuard, EnforceQuotaInterceptor, QUOTA_PROVIDERS_TOKEN);
1373
+ if (options.globalFeatureGuard === false) {
1374
+ lightweightProviders.push(FeatureGuardCoverageCheck);
1375
+ }
1376
+ } else {
1377
+ PLATFORM_LOGGER.warn("No plan resolver configured \u2014 @RequireFeature and @EnforceQuota are INERT. The platform registered neither StaticFeatureGuard nor EnforceQuotaInterceptor, so every annotated route serves unlicensed traffic and every quota is unlimited. Set one of: adapters.planResolver, defaultPlanId, or tenantBilling.");
1260
1378
  }
1261
1379
  const tenantControllers = [];
1262
1380
  if (options.tenantManifest) {
@@ -1318,7 +1436,7 @@ var SaasPlatformModule = class _SaasPlatformModule {
1318
1436
  };
1319
1437
  }
1320
1438
  };
1321
- SaasPlatformModule = _ts_decorate9([
1439
+ SaasPlatformModule = _ts_decorate10([
1322
1440
  Module2({})
1323
1441
  ], SaasPlatformModule);
1324
1442
 
@@ -1331,6 +1449,7 @@ export {
1331
1449
  PLAN_RESOLVER_PORT_TOKEN,
1332
1450
  StaticPlanResolver,
1333
1451
  StaticEntitlementService,
1452
+ FeatureGuardCoverageCheck,
1334
1453
  STATIC_FEATURE_GUARD_CONFIG_TOKEN,
1335
1454
  StaticFeatureGuard,
1336
1455
  QUOTA_PROVIDERS_TOKEN,
@@ -1405,7 +1405,7 @@ var SaveRegistrationConfigSelectionDto = class {
1405
1405
  billingCycle;
1406
1406
  appliedPromoCode;
1407
1407
  /**
1408
- * METAMODELL §17a — Bundle consistency. ID of the `CheckoutOffer` that was
1408
+ * — Bundle consistency. ID of the `CheckoutOffer` that was
1409
1409
  * created on the pricing page (`<app>/register?offer=<id>`). Passed
1410
1410
  * through unchanged in `configJson`; the ActivationOrchestrator freezes it
1411
1411
  * as `packageSnapshot` when the subscription is created and sets the offer
@@ -504,7 +504,7 @@ var EntitlementService = class {
504
504
  // ---------------------------------------------------------------------
505
505
  /**
506
506
  * Plan fallback for TRIAL/PENDING_SALES: returns the PlanVersion active
507
- * as of `asOf` (SPEC_V2 §4.2). If the repo does not implement
507
+ * as of `asOf`. If the repo does not implement
508
508
  * `findActive`, we fall back to `findLatestLive` (backward compat for
509
509
  * adapters without `validFrom` columns).
510
510
  */
@@ -575,7 +575,7 @@ var PLATFORM_CORE_MANIFEST_CONTRIBUTION = {
575
575
  enabled: true,
576
576
  requiredCapability: "dashboard.read"
577
577
  },
578
- // SPEC_V2 §3.3 — discovery snapshot of the running backend.
578
+ // — discovery snapshot of the running backend.
579
579
  // Apps must set `discovery.read` in their manifest capabilities
580
580
  // to `true` so that the NavBuilder wires the page into the
581
581
  // sidebar; otherwise it is filtered out automatically.
@@ -583,7 +583,7 @@ var PLATFORM_CORE_MANIFEST_CONTRIBUTION = {
583
583
  enabled: true,
584
584
  requiredCapability: "discovery.read"
585
585
  },
586
- // SPEC_V2 §11.1 M3 — Bundle editor in SuperAdmin.
586
+ // — Bundle editor in SuperAdmin.
587
587
  // Apps with a DB-driven catalog set `bundles.read = true`.
588
588
  bundles: {
589
589
  enabled: true,
@@ -593,7 +593,7 @@ var PLATFORM_CORE_MANIFEST_CONTRIBUTION = {
593
593
  enabled: true,
594
594
  requiredCapability: "plans.read"
595
595
  },
596
- // SPEC_V2 §11.1 M3 — marketing catalog (locale pivot).
596
+ // — marketing catalog (locale pivot).
597
597
  // Apps that market a public catalog set
598
598
  // `marketingProjections.read = true`.
599
599
  marketingCatalog: {
@@ -3,7 +3,7 @@ import { ExecutionContext } from '@nestjs/common';
3
3
  import { Reflector } from '@nestjs/core';
4
4
  import { SuperAdminProvisioningPort, SetupStatusResponse, SetupRequest, SetupResult, SetupConfirmMfaRequest, SetupConfirmMfaResponse } from '@saasicat/types';
5
5
  import { h as MfaService } from './admin-stats.service-Db2exT_d.js';
6
- import { f as SaasPlatformModuleOptions } from './saas-platform.module-DChhDrR-.js';
6
+ import { f as SaasPlatformModuleOptions } from './saas-platform.module-D1mUZPrz.js';
7
7
 
8
8
  /**
9
9
  * Shared metadata key for endpoints that intentionally run without application
@@ -3,7 +3,7 @@ import { ExecutionContext } from '@nestjs/common';
3
3
  import { Reflector } from '@nestjs/core';
4
4
  import { SuperAdminProvisioningPort, SetupStatusResponse, SetupRequest, SetupResult, SetupConfirmMfaRequest, SetupConfirmMfaResponse } from '@saasicat/types';
5
5
  import { h as MfaService } from './admin-stats.service-HUZIU448.cjs';
6
- import { f as SaasPlatformModuleOptions } from './saas-platform.module-BfaYfL-G.cjs';
6
+ import { f as SaasPlatformModuleOptions } from './saas-platform.module-CgalxzcT.cjs';
7
7
 
8
8
  /**
9
9
  * Shared metadata key for endpoints that intentionally run without application
@@ -16,7 +16,7 @@ interface ImplementsCapabilityOptions {
16
16
  /**
17
17
  * Aggregation wrapper: the feature key this capability belongs to.
18
18
  * Bundles are planned exclusively in the SuperAdmin UI and are
19
- * **deliberately not** part of the code decorator (SPEC_V2 §3.1).
19
+ * **deliberately not** part of the code decorator.
20
20
  */
21
21
  feature?: string;
22
22
  /**
@@ -109,7 +109,7 @@ interface ImplementsCapabilityMetadata extends ImplementsCapabilityOptions {
109
109
  * - `status` controls visibility/lifecycle (default `active`).
110
110
  * - `kind` declares the implementation kind (default `endpoint`).
111
111
  *
112
- * **Bundles are deliberately NOT declared in the decorator** (SPEC_V2 §3.1).
112
+ * **Bundles are deliberately NOT declared in the decorator**.
113
113
  * They are created exclusively in the SuperAdmin UI (DB table `bundles`),
114
114
  * by the admin grouping features there.
115
115
  *
@@ -16,7 +16,7 @@ interface ImplementsCapabilityOptions {
16
16
  /**
17
17
  * Aggregation wrapper: the feature key this capability belongs to.
18
18
  * Bundles are planned exclusively in the SuperAdmin UI and are
19
- * **deliberately not** part of the code decorator (SPEC_V2 §3.1).
19
+ * **deliberately not** part of the code decorator.
20
20
  */
21
21
  feature?: string;
22
22
  /**
@@ -109,7 +109,7 @@ interface ImplementsCapabilityMetadata extends ImplementsCapabilityOptions {
109
109
  * - `status` controls visibility/lifecycle (default `active`).
110
110
  * - `kind` declares the implementation kind (default `endpoint`).
111
111
  *
112
- * **Bundles are deliberately NOT declared in the decorator** (SPEC_V2 §3.1).
112
+ * **Bundles are deliberately NOT declared in the decorator**.
113
113
  * They are created exclusively in the SuperAdmin UI (DB table `bundles`),
114
114
  * by the admin grouping features there.
115
115
  *
@@ -1,8 +1,9 @@
1
1
  import { CanActivate, ExecutionContext, NestInterceptor, CallHandler } from '@nestjs/common';
2
2
  import { Reflector } from '@nestjs/core';
3
+ import { F as FEATURE_GUARD_MARKER } from './subscription-bundles.module-BDbODWvA.js';
3
4
  import { Observable } from 'rxjs';
4
5
  import { PlanCatalog, QuotaProvider } from '@saasicat/types';
5
- import { p as PlanResolverPort } from './saas-platform.module-DChhDrR-.js';
6
+ import { p as PlanResolverPort } from './saas-platform.module-D1mUZPrz.js';
6
7
 
7
8
  interface StaticEntitlementSnapshot {
8
9
  planId: string | null;
@@ -43,6 +44,8 @@ declare class StaticFeatureGuard implements CanActivate {
43
44
  private readonly reflector;
44
45
  private readonly entitlements;
45
46
  private readonly config;
47
+ /** Lets `FeatureGuardCoverageCheck` recognise this guard across CJS entries. */
48
+ static readonly [FEATURE_GUARD_MARKER] = true;
46
49
  constructor(reflector: Reflector, entitlements: StaticEntitlementService, config?: StaticFeatureGuardConfig | null);
47
50
  canActivate(context: ExecutionContext): Promise<boolean>;
48
51
  }
@@ -1,8 +1,9 @@
1
1
  import { CanActivate, ExecutionContext, NestInterceptor, CallHandler } from '@nestjs/common';
2
2
  import { Reflector } from '@nestjs/core';
3
+ import { F as FEATURE_GUARD_MARKER } from './subscription-bundles.module-Cfi-lFWF.cjs';
3
4
  import { Observable } from 'rxjs';
4
5
  import { PlanCatalog, QuotaProvider } from '@saasicat/types';
5
- import { p as PlanResolverPort } from './saas-platform.module-BfaYfL-G.cjs';
6
+ import { p as PlanResolverPort } from './saas-platform.module-CgalxzcT.cjs';
6
7
 
7
8
  interface StaticEntitlementSnapshot {
8
9
  planId: string | null;
@@ -43,6 +44,8 @@ declare class StaticFeatureGuard implements CanActivate {
43
44
  private readonly reflector;
44
45
  private readonly entitlements;
45
46
  private readonly config;
47
+ /** Lets `FeatureGuardCoverageCheck` recognise this guard across CJS entries. */
48
+ static readonly [FEATURE_GUARD_MARKER] = true;
46
49
  constructor(reflector: Reflector, entitlements: StaticEntitlementService, config?: StaticFeatureGuardConfig | null);
47
50
  canActivate(context: ExecutionContext): Promise<boolean>;
48
51
  }
@@ -1,4 +1,4 @@
1
- export { C as CustomLimitsShape, E as EffectiveLimits, a as EffectiveLimitsSnapshot, b as EnforceLimitInput, c as EntitlementService, P as PlanVersionSnapshot, S as SubscriptionBundleSnapshot, d as SubscriptionLimitsInput, e as aggregateContractLineItemEntitlements, f as aggregateLimits, g as aggregateSubscriptionBundleQuotas, h as applyCustomLimits, i as collectSubscriptionBundleFeatures, j as contractBundleVersionIds, k as contractLimits, l as filterActiveSubscriptionBundles, m as filterPlannedOnlyFeatures, n as hasAnyFeature, o as hasFeature, p as mergeSubscriptionBundlesIntoLimits, t as toEffectiveLimitsSnapshot } from '../aggregation-SKfXu09x.cjs';
1
+ export { C as CustomLimitsShape, E as EffectiveLimits, a as EffectiveLimitsSnapshot, b as EnforceLimitInput, c as EntitlementService, P as PlanVersionSnapshot, S as SubscriptionBundleSnapshot, d as SubscriptionLimitsInput, e as aggregateContractLineItemEntitlements, f as aggregateLimits, g as aggregateSubscriptionBundleQuotas, h as applyCustomLimits, i as collectSubscriptionBundleFeatures, j as contractBundleVersionIds, k as contractLimits, l as filterActiveSubscriptionBundles, m as filterPlannedOnlyFeatures, n as hasAnyFeature, o as hasFeature, p as mergeSubscriptionBundlesIntoLimits, t as toEffectiveLimitsSnapshot } from '../aggregation-mZ7WZROK.cjs';
2
2
  import { DiscoveredFeature, SubscriptionRepository, PlanVersionRepository, TransactionRunner, SubscriptionContractRepository, SubscriptionBundleRepository, BundleRepository } from '@saasicat/types';
3
3
  import { E as EntitlementResolutionConfig } from '../plan-resolution-CFCoUkrE.cjs';
4
4
  export { a as EntitlementResolutionInput, r as resolveEntitlementPlan } from '../plan-resolution-CFCoUkrE.cjs';
@@ -1,4 +1,4 @@
1
- export { C as CustomLimitsShape, E as EffectiveLimits, a as EffectiveLimitsSnapshot, b as EnforceLimitInput, c as EntitlementService, P as PlanVersionSnapshot, S as SubscriptionBundleSnapshot, d as SubscriptionLimitsInput, e as aggregateContractLineItemEntitlements, f as aggregateLimits, g as aggregateSubscriptionBundleQuotas, h as applyCustomLimits, i as collectSubscriptionBundleFeatures, j as contractBundleVersionIds, k as contractLimits, l as filterActiveSubscriptionBundles, m as filterPlannedOnlyFeatures, n as hasAnyFeature, o as hasFeature, p as mergeSubscriptionBundlesIntoLimits, t as toEffectiveLimitsSnapshot } from '../aggregation-o0LMenvl.js';
1
+ export { C as CustomLimitsShape, E as EffectiveLimits, a as EffectiveLimitsSnapshot, b as EnforceLimitInput, c as EntitlementService, P as PlanVersionSnapshot, S as SubscriptionBundleSnapshot, d as SubscriptionLimitsInput, e as aggregateContractLineItemEntitlements, f as aggregateLimits, g as aggregateSubscriptionBundleQuotas, h as applyCustomLimits, i as collectSubscriptionBundleFeatures, j as contractBundleVersionIds, k as contractLimits, l as filterActiveSubscriptionBundles, m as filterPlannedOnlyFeatures, n as hasAnyFeature, o as hasFeature, p as mergeSubscriptionBundlesIntoLimits, t as toEffectiveLimitsSnapshot } from '../aggregation-DP5zfKbU.js';
2
2
  import { DiscoveredFeature, SubscriptionRepository, PlanVersionRepository, TransactionRunner, SubscriptionContractRepository, SubscriptionBundleRepository, BundleRepository } from '@saasicat/types';
3
3
  import { E as EntitlementResolutionConfig } from '../plan-resolution-CFCoUkrE.js';
4
4
  export { a as EntitlementResolutionInput, r as resolveEntitlementPlan } from '../plan-resolution-CFCoUkrE.js';
@@ -19,7 +19,7 @@ import {
19
19
  mergeSubscriptionBundlesIntoLimits,
20
20
  resolveEntitlementPlan,
21
21
  toEffectiveLimitsSnapshot
22
- } from "../chunk-AGOG5B77.js";
22
+ } from "../chunk-NNNXXUPT.js";
23
23
  import "../chunk-DQKCK7DX.js";
24
24
  import "../chunk-NYLON2VC.js";
25
25
  import "../chunk-EBJJNTW6.js";