@saasicat/nest 0.2.0 → 0.3.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.
@@ -406,6 +406,7 @@ __name(buildTenantManifestController, "buildTenantManifestController");
406
406
  // src/platform/saas-platform.module.ts
407
407
  import { Module } from "@nestjs/common";
408
408
  import { APP_GUARD, APP_INTERCEPTOR } from "@nestjs/core";
409
+ import { assertPersistenceCapabilities } from "@saasicat/types";
409
410
  function _ts_decorate6(decorators, target, key, desc) {
410
411
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
411
412
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
@@ -450,30 +451,59 @@ var SaasPlatformModule = class _SaasPlatformModule {
450
451
  __name(this, "SaasPlatformModule");
451
452
  }
452
453
  static forRoot(options) {
453
- if (!options.planCatalog && !options.adapters.planCatalogReadSink) {
454
- throw new Error("SaasPlatformModule.forRoot: entweder `planCatalog` (Quickstart) oder `adapters.planCatalogReadSink` (DB-Hydration) muss gesetzt sein.");
454
+ const explicit = options.adapters ?? {};
455
+ const persistence = options.persistence;
456
+ const adapters = {
457
+ mfa: explicit.mfa ?? persistence?.core.mfa,
458
+ audit: explicit.audit ?? persistence?.core.audit,
459
+ rlsBypass: explicit.rlsBypass ?? persistence?.core.rlsBypass,
460
+ planCatalogReadSink: explicit.planCatalogReadSink ?? persistence?.planCatalogReadSink,
461
+ planResolver: explicit.planResolver,
462
+ subscriptionRepository: explicit.subscriptionRepository ?? persistence?.entitlement?.subscriptionRepository,
463
+ planVersionRepository: explicit.planVersionRepository ?? persistence?.entitlement?.planVersionRepository,
464
+ transactionRunner: explicit.transactionRunner ?? persistence?.core.transactionRunner
465
+ };
466
+ const missingCore = [
467
+ "mfa",
468
+ "audit",
469
+ "rlsBypass"
470
+ ].filter((key) => adapters[key] === void 0);
471
+ if (missingCore.length) {
472
+ throw new Error(`SaasPlatformModule.forRoot: adapters missing (provide them via \`adapters\` or a \`persistence\` bundle): ${missingCore.join(", ")}`);
473
+ }
474
+ if (!options.planCatalog && (!adapters.planCatalogReadSink || !options.dbCatalog)) {
475
+ 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 }).");
455
476
  }
456
477
  if (options.entitlement) {
457
478
  const missing = [];
458
- if (!options.adapters.subscriptionRepository) missing.push("subscriptionRepository");
459
- if (!options.adapters.planVersionRepository) missing.push("planVersionRepository");
460
- if (!options.adapters.transactionRunner) missing.push("transactionRunner");
479
+ if (!adapters.subscriptionRepository) missing.push("subscriptionRepository");
480
+ if (!adapters.planVersionRepository) missing.push("planVersionRepository");
481
+ if (!adapters.transactionRunner) missing.push("transactionRunner");
461
482
  if (missing.length) {
462
- throw new Error(`SaasPlatformModule.forRoot: entitlement aktiv, aber Adapter fehlen: ${missing.join(", ")}`);
483
+ throw new Error(`SaasPlatformModule.forRoot: entitlement active, but adapters are missing: ${missing.join(", ")}`);
484
+ }
485
+ if (persistence) {
486
+ assertPersistenceCapabilities(persistence.capabilities, {
487
+ transactions: true,
488
+ pessimisticLocking: true
489
+ }, "SaasPlatformModule entitlement (transactional enforceLimit)");
463
490
  }
464
491
  }
492
+ const dbCatalog = options.dbCatalog;
465
493
  const planCatalogModule = options.planCatalog ? PlanCatalogModule.forRootWithCatalog(options.planCatalog, {
466
494
  global: true
467
495
  }) : PlanCatalogModule.forRoot({
468
- projectKey: "",
469
- currency: "",
470
- vatRate: 0,
471
- sink: options.adapters.planCatalogReadSink,
496
+ projectKey: dbCatalog.projectKey,
497
+ app: dbCatalog.app,
498
+ currency: dbCatalog.currency,
499
+ vatRate: dbCatalog.vatRate,
500
+ marketing: dbCatalog.marketing,
501
+ sink: adapters.planCatalogReadSink,
472
502
  imports: options.imports
473
503
  });
474
504
  const appInfo = options.app ?? {
475
- key: options.planCatalog?.projectKey ?? "app",
476
- version: options.planCatalog?.app?.version ?? "0.0.0"
505
+ key: options.planCatalog?.projectKey ?? options.dbCatalog?.projectKey ?? "app",
506
+ version: options.planCatalog?.app?.version ?? options.dbCatalog?.app?.version ?? "0.0.0"
477
507
  };
478
508
  const imports = [
479
509
  planCatalogModule,
@@ -486,9 +516,9 @@ var SaasPlatformModule = class _SaasPlatformModule {
486
516
  snapshotPath: options.discoverySnapshotPath === void 0 ? "var/discovery-snapshot.json" : options.discoverySnapshotPath
487
517
  }),
488
518
  AdminModule.forRoot({
489
- mfaPort: options.adapters.mfa,
490
- auditPort: options.adapters.audit,
491
- rlsBypassPort: options.adapters.rlsBypass,
519
+ mfaPort: adapters.mfa,
520
+ auditPort: adapters.audit,
521
+ rlsBypassPort: adapters.rlsBypass,
492
522
  global: true
493
523
  }),
494
524
  AdminManifestModule.forRoot({
@@ -499,18 +529,21 @@ var SaasPlatformModule = class _SaasPlatformModule {
499
529
  ];
500
530
  if (options.entitlement) {
501
531
  imports.push(EntitlementModule.forRoot({
502
- subscriptionRepository: options.adapters.subscriptionRepository,
503
- planVersionRepository: options.adapters.planVersionRepository,
504
- transactionRunner: options.adapters.transactionRunner,
505
- resolutionConfig: options.entitlement.resolutionConfig
532
+ subscriptionRepository: adapters.subscriptionRepository,
533
+ planVersionRepository: adapters.planVersionRepository,
534
+ transactionRunner: adapters.transactionRunner,
535
+ resolutionConfig: options.entitlement.resolutionConfig,
536
+ subscriptionContractRepository: persistence?.entitlement?.subscriptionContractRepository,
537
+ subscriptionBundleRepository: persistence?.entitlement?.subscriptionBundleRepository,
538
+ bundleRepository: persistence?.entitlement?.bundleRepository
506
539
  }));
507
540
  }
508
541
  const lightweightProviders = [];
509
542
  const lightweightExports = [];
510
- const hasResolver = !!options.adapters.planResolver;
543
+ const hasResolver = !!adapters.planResolver;
511
544
  const hasFallback = !!options.defaultPlanId;
512
545
  if (hasResolver || hasFallback) {
513
- lightweightProviders.push(hasResolver ? asProvider(PLAN_RESOLVER_PORT_TOKEN, options.adapters.planResolver) : {
546
+ lightweightProviders.push(hasResolver ? asProvider(PLAN_RESOLVER_PORT_TOKEN, adapters.planResolver) : {
514
547
  provide: PLAN_RESOLVER_PORT_TOKEN,
515
548
  useValue: new StaticPlanResolver(options.defaultPlanId)
516
549
  }, StaticEntitlementService, StaticFeatureGuard, EnforceQuotaInterceptor, ...options.quotaProviders ?? [], {
package/dist/index.d.cts CHANGED
@@ -4,7 +4,7 @@ export { PROMO_CODE_REDEMPTION_REPOSITORY_TOKEN, PROMO_CODE_REPOSITORY_TOKEN, PR
4
4
  export { P as PreviewInput, a as PreviewInvalid, b as PreviewReason, c as PreviewResult, d as PreviewValid, e as PromoCodeStats, f as PromoCodesService, g as PromoServiceConfig, R as RedeemInput } from './service-DX8KbGXl.cjs';
5
5
  export { AUDIT_CONTEXT_RESOLVER_TOKEN, AddBundleToSubscriptionInput, AjvErrorLike, AuditContextResolver, AuthGuardList, BundlePreviewSnapshot, CONTRACT_FREEZE_PORT_TOKEN, CONTRACT_FREEZE_PROJECT_KEY_TOKEN, CONTRACT_FREEZE_SOURCE_PORT_TOKEN, CancelBundleFromSubscriptionInput, CancelSubscriptionDto, CatalogBundleUpsellResolver, ChangePlanDto, CompleteOnboardingSubscriptionDto, ComposedTenantAuthGuard, ConfiguratorCatalogBuilder, ContractFreezeBundleSnapshot, ContractFreezePort, ContractFreezeSourcePort, DuePendingPlanChange, FEATURE_GUARD_CONFIG_TOKEN, FEATURE_UI_REGISTRY_TOKEN, FeatureGuard, FeatureGuardConfig, LimitExceededFilter, LimitsCheckRow, LoadPlanCatalogOptions, MarketingFields, NextPeriodWindow, PENDING_PLAN_QUERY_PORT_TOKEN, PLAN_CATALOG_IMPORT_SINK_TOKEN, PLAN_CATALOG_READ_SINK_TOKEN, PLAN_CATALOG_TOKEN, PUBLIC_CATALOG_BUNDLE_REPOSITORY_TOKEN, PUBLIC_CATALOG_BUSINESS_TYPE_REPOSITORY_TOKEN, PUBLIC_CATALOG_MARKETING_REPOSITORY_TOKEN, PUBLIC_CATALOG_PROJECT_KEY_TOKEN, PendingPlanMaterializationService, PendingPlanQueryPort, PeriodRollInput, PlanCatalogBuildSettings, PlanCatalogImportDto, PlanCatalogImporterControllerConfig, PlanCatalogImporterModule, PlanCatalogImporterModuleOptions, PlanCatalogImporterService, PlanCatalogModule, PlanCatalogModuleOptions, PlanCatalogValidationError, PlanChangeContext, PlanChangePreviewDto, PlanChangePreviewIssue, PlanChangePreviewService, PlanChangeType, PlanResponseEntry, PlanSnapshotDto, PreviewPlanChangeDto, ProrationDto, ProrationInput, PublicBundleEntry, PublicBusinessTypeEntry, PublicCatalogController, PublicCatalogModule, PublicCatalogModuleOptions, PublishValidationError, PublishablePlanVersion, REQUIRE_FEATURE_KEY, RedundantFeatureHint, RenewalDecision, RenewalSubInput, RequireFeature, SELF_SERVICE_BLOCKED_BUNDLES_TOKEN, SELF_SERVICE_BLOCKED_PLANS_TOKEN, SUBSCRIPTION_BUNDLE_CONFIG_TOKEN, SUBSCRIPTION_BUNDLE_REPOSITORY_TOKEN, SUBSCRIPTION_USAGE_PORT_TOKEN, SUBSCRIPTION_WRITE_PORT_TOKEN, SelfServiceBlockedBundles, SelfServiceBlockedPlans, SubscriptionBundleAddPreviewDto, SubscriptionBundleCancelPreviewDto, SubscriptionBundleConfig, SubscriptionBundleControllerOptions, SubscriptionBundleModule, SubscriptionBundleModuleOptions, SubscriptionBundlePreviewContext, SubscriptionBundlePreviewIssue, SubscriptionBundlePreviewService, SubscriptionBundlesService, SubscriptionContractFreezeService, TENANT_AUTH_GUARDS_TOKEN, TENANT_ID_RESOLVER_TOKEN, TRIAL_PROJECTION_PORT_TOKEN, TenantAdminGuard, TenantBillingController, TenantBillingModule, TenantBillingModuleOptions, TenantIdResolver, TrialProjectionInput, TrialProjectionPort, UPSELL_OFFER_CURRENCY_TOKEN, UPSELL_OFFER_RESOLVER_TOKEN, USAGE_SNAPSHOT_PORT_TOKEN, USER_EMAIL_RESOLVER_TOKEN, USER_ID_RESOLVER_TOKEN, UsageResponse, UserEmailResolver, UserIdResolver, addMonths, assertBaseVersionFresh, assertChangeNote, assertDraftPublishable, assertOptimisticLockHeld, buildPlanCatalogFromSnapshot, buildPlanCatalogImporterController, buildTenantSubscriptionBundlesController, clearPendingPlanVersionFields, computeCarriedTrialEndsAt, computeNextPeriod, computeProration, decideRenewal, findPlan, getActiveFeatureKeys, getMarketedPlans, getPlanOrThrow, getPlanPriceGross, getPlanPriceNet, getPlanQuota, initialPeriodWindow, isFeatureInPlan, isFeaturePlannedOnly, loadPlanCatalogFromFile, loadPlanCatalogFromString, periodEndAfter, periodEndWithMinLead, resolveBundleCancelEffectiveAt, resolveBundlePriceNet } from './billing/index.cjs';
6
6
  import { SuperAdminProvisioningPort, SetupStatusResponse, SetupRequest, SetupResult, SetupConfirmMfaRequest, SetupConfirmMfaResponse } from '@saasicat/types';
7
- export { BundleVersionFields, ChangeDirection, DiffResult, DiscoveredCapability, DiscoveredFeature, DiscoveredQuota, DiscoverySnapshot, PlanVersionFields, VersionChange, VersionChangeDirection, classifyBundleVersionDiff, classifyPlanDiff } from '@saasicat/types';
7
+ export { BundleVersionFields, ChangeDirection, DiffResult, DiscoveredCapability, DiscoveredFeature, DiscoveredQuota, DiscoverySnapshot, PasswordHasher, PlanVersionFields, VersionChange, VersionChangeDirection, classifyBundleVersionDiff, classifyPlanDiff } from '@saasicat/types';
8
8
  export { B as BundleVersionSnapshot, a as BusinessTypeVersionSnapshot, C as CustomLimitsShape, E as EffectiveLimits, b as EffectiveLimitsSnapshot, c as EnforceLimitInput, d as EntitlementService, L as LimitExceededError, P as PlanVersionSnapshot, S as SubscriptionBundleSnapshot, e as SubscriptionLimitsInput, f as aggregateBusinessTypeQuotas, g as aggregateContractLineItemEntitlements, h as aggregateLimits, i as aggregateSubscriptionBundleQuotas, j as applyCustomLimits, k as collectBusinessTypeFeatures, l as collectSubscriptionBundleFeatures, m as filterActiveSubscriptionBundles, n as filterPlannedOnlyFeatures, o as hasAnyFeature, p as hasFeature, t as toEffectiveLimitsSnapshot } from './aggregation-CJ3qQf92.cjs';
9
9
  export { ENTITLEMENT_RESOLUTION_CONFIG_TOKEN, EntitlementModule, EntitlementModuleOptions, PLAN_VERSION_REPOSITORY_TOKEN, ReplacedByIndex, SUBSCRIPTION_REPOSITORY_TOKEN, TRANSACTION_RUNNER_TOKEN, buildReplacedByIndex, expandReplacedFeatures } from './entitlement/index.cjs';
10
10
  export { E as EntitlementResolutionConfig, a as EntitlementResolutionInput, r as resolveEntitlementPlan } from './plan-resolution-CFCoUkrE.cjs';
@@ -14,7 +14,7 @@ export { A as AdminAuditService } from './admin-audit.service-9IqXMlZm.cjs';
14
14
  export { a as ADMIN_MANIFEST_CONFIG, A as AdminManifestConfig } from './admin-manifest.config-DyrQNT7M.cjs';
15
15
  import { DynamicModule } from '@nestjs/common';
16
16
  export { Type as NestType } from '@nestjs/common';
17
- export { ACTIVATION_ORCHESTRATOR_TOKEN, BaseIpRateLimitGuard, ContinueRegistrationDto, PASSWORD_HASHER_TOKEN, PAYMENT_EVENT_LOG_TOKEN, PAYMENT_PROVIDER_TOKEN, PENDING_REGISTRATION_REPOSITORY_TOKEN, PLAN_CATALOG_LOOKUP_TOKEN, PasswordHasher, PaymentWebhookDto, PendingRegistrationService, PreviewRegistrationPromoDto, PromoEvaluation, REGISTRATION_AUDIT_LOGGER_TOKEN, REGISTRATION_BUSINESS_TYPE_LOOKUP_TOKEN, REGISTRATION_CONFIGURATOR_LOOKUP_TOKEN, REGISTRATION_CONFIG_TOKEN, REGISTRATION_OTP_DELIVERY_TOKEN, REGISTRATION_PROMO_PREVIEW_TOKEN, REGISTRATION_RESUME_BASE_URL_TOKEN, REGISTRATION_RESUME_DELIVERY_TOKEN, REGISTRATION_RESUME_TOKEN_SIGNER_TOKEN, RegisterStartDto, RegistrationCleanupCron, RegistrationModule, RegistrationModuleOptions, ResendRegistrationOtpDto, SLUG_AVAILABILITY_CHECK_TOKEN, SaveRegistrationConfigDto, SaveRegistrationConfigSelectionDto, SelectRegistrationPlanDto, StartRegistrationCheckoutDto, USER_ACCOUNT_LOOKUP_TOKEN, VerifyRegistrationOtpDto, computeBreakdown, generateOtpCode, hashOtpCode, resolveModel, slugify, verifyOtpCode } from './registration/index.cjs';
17
+ export { ACTIVATION_ORCHESTRATOR_TOKEN, BaseIpRateLimitGuard, ContinueRegistrationDto, PASSWORD_HASHER_TOKEN, PAYMENT_EVENT_LOG_TOKEN, PAYMENT_PROVIDER_TOKEN, PENDING_REGISTRATION_REPOSITORY_TOKEN, PLAN_CATALOG_LOOKUP_TOKEN, PaymentWebhookDto, PendingRegistrationService, PreviewRegistrationPromoDto, PromoEvaluation, REGISTRATION_AUDIT_LOGGER_TOKEN, REGISTRATION_BUSINESS_TYPE_LOOKUP_TOKEN, REGISTRATION_CONFIGURATOR_LOOKUP_TOKEN, REGISTRATION_CONFIG_TOKEN, REGISTRATION_OTP_DELIVERY_TOKEN, REGISTRATION_PROMO_PREVIEW_TOKEN, REGISTRATION_RESUME_BASE_URL_TOKEN, REGISTRATION_RESUME_DELIVERY_TOKEN, REGISTRATION_RESUME_TOKEN_SIGNER_TOKEN, RegisterStartDto, RegistrationCleanupCron, RegistrationModule, RegistrationModuleOptions, ResendRegistrationOtpDto, SLUG_AVAILABILITY_CHECK_TOKEN, SaveRegistrationConfigDto, SaveRegistrationConfigSelectionDto, SelectRegistrationPlanDto, StartRegistrationCheckoutDto, USER_ACCOUNT_LOOKUP_TOKEN, VerifyRegistrationOtpDto, computeBreakdown, generateOtpCode, hashOtpCode, resolveModel, slugify, verifyOtpCode } from './registration/index.cjs';
18
18
  export { DEFINES_QUOTA_KEY, DISCOVERY_SNAPSHOT_TOKEN, DefinesQuota, DefinesQuotaOptions, DiscoveryControllerConfig, DiscoveryModule, DiscoveryModuleOptions, DiscoverySnapshotNotFoundError, ENFORCE_QUOTA_KEY, EnforceQuota, EnforceQuotaMetadata, EnforceQuotaOptions, HeadlessScanOptions, IMPLEMENTS_CAPABILITY_KEY, ImplementsCapability, ImplementsCapabilityMetadata, ImplementsCapabilityOptions, REQUIRES_CAPABILITY_KEY, RequiresCapability, RequiresCapabilityKeys, buildDiscoveryController, loadDiscoverySnapshotFromFile, runHeadlessDiscoveryScan } from './discovery/index.cjs';
19
19
  export { a as DISCOVERY_APP_INFO_TOKEN, b as DISCOVERY_SNAPSHOT_PATH_TOKEN, D as DiscoveryAppInfo, c as DiscoveryScanner, d as computeSnapshotHash } from './discovery.scanner-CUYLKlYT.cjs';
20
20
  export { ADVISORY_STRICT_MODE_CODES, BUNDLE_REPOSITORY_TOKEN, BUSINESS_TYPE_REPOSITORY_TOKEN, BundlesService, BusinessTypeBundleInputDto, BusinessTypesService, CATALOG_ENTRY_REPOSITORY_TOKEN, CATALOG_SERVICE_CONFIG_TOKEN, CatalogControllerConfig, CatalogEntriesService, CatalogModule, CatalogModuleOptions, CatalogServiceConfig, CreateBundleDto, CreateBundleVersionDraftDto, CreateBusinessTypeDto, CreateBusinessTypeVersionDraftDto, CreateMarketingProjectionDto, CreatePlanDto, CreatePlanVersionDraftDto, CreatePromotionDto, ListCatalogEntriesQueryDto, ListMarketingProjectionsQueryDto, ListMarketingSettingsQueryDto, ListPromotionsQueryDto, MARKETING_PROJECTION_REPOSITORY_TOKEN, MARKETING_SETTINGS_REPOSITORY_TOKEN, MarketingProjectionsService, MarketingSettingsService, PLAN_REPOSITORY_TOKEN, PROMOTION_REPOSITORY_TOKEN, PlanVersionsService, PlansService, PreflightFinding, PreflightInput, PreflightReport, PromotionsService, PublicMarketingCatalogService, PublishBundleVersionDto, PublishBusinessTypeVersionDto, PublishPlanVersionDto, ReviewCatalogEntryDto, SeedBundleDraft, SeedGateFinding, SeedGateInput, SeedGateMode, SeedGateReport, SeedGateRunOptions, SeedPlanDraft, SyncDiscoveryDto, UpdateBundleDto, UpdateBundleVersionDraftDto, UpdateBusinessTypeDto, UpdateBusinessTypeVersionDraftDto, UpdateCatalogEntryI18nDto, UpdateMarketingProjectionDto, UpdateMarketingSettingsDto, UpdatePlanDto, UpdatePlanVersionDraftDto, UpdatePromotionDto, blockingStrictModeWarnings, buildBundleVersionsController, buildBundlesController, buildBusinessTypeVersionsController, buildBusinessTypesController, buildCatalogEntriesController, buildMarketingProjectionsController, buildMarketingSettingsController, buildPlanVersionsController, buildPlansController, buildPromotionsController, buildPublicMarketingCatalogController, featureApprovalSignature, formatPreflightReport, formatSeedGateReport, loadApprovedCatalogKeys, preflightExitCode, quotaApprovalSignature, runPreflight, runSeedGateFromFile, seedGateExitCode, validateBundleDraft, validateBusinessTypeDraft, validatePlanDraft, validateSeedAgainstSnapshot } from './catalog/index.cjs';
package/dist/index.d.ts CHANGED
@@ -4,7 +4,7 @@ export { PROMO_CODE_REDEMPTION_REPOSITORY_TOKEN, PROMO_CODE_REPOSITORY_TOKEN, PR
4
4
  export { P as PreviewInput, a as PreviewInvalid, b as PreviewReason, c as PreviewResult, d as PreviewValid, e as PromoCodeStats, f as PromoCodesService, g as PromoServiceConfig, R as RedeemInput } from './service-DX8KbGXl.js';
5
5
  export { AUDIT_CONTEXT_RESOLVER_TOKEN, AddBundleToSubscriptionInput, AjvErrorLike, AuditContextResolver, AuthGuardList, BundlePreviewSnapshot, CONTRACT_FREEZE_PORT_TOKEN, CONTRACT_FREEZE_PROJECT_KEY_TOKEN, CONTRACT_FREEZE_SOURCE_PORT_TOKEN, CancelBundleFromSubscriptionInput, CancelSubscriptionDto, CatalogBundleUpsellResolver, ChangePlanDto, CompleteOnboardingSubscriptionDto, ComposedTenantAuthGuard, ConfiguratorCatalogBuilder, ContractFreezeBundleSnapshot, ContractFreezePort, ContractFreezeSourcePort, DuePendingPlanChange, FEATURE_GUARD_CONFIG_TOKEN, FEATURE_UI_REGISTRY_TOKEN, FeatureGuard, FeatureGuardConfig, LimitExceededFilter, LimitsCheckRow, LoadPlanCatalogOptions, MarketingFields, NextPeriodWindow, PENDING_PLAN_QUERY_PORT_TOKEN, PLAN_CATALOG_IMPORT_SINK_TOKEN, PLAN_CATALOG_READ_SINK_TOKEN, PLAN_CATALOG_TOKEN, PUBLIC_CATALOG_BUNDLE_REPOSITORY_TOKEN, PUBLIC_CATALOG_BUSINESS_TYPE_REPOSITORY_TOKEN, PUBLIC_CATALOG_MARKETING_REPOSITORY_TOKEN, PUBLIC_CATALOG_PROJECT_KEY_TOKEN, PendingPlanMaterializationService, PendingPlanQueryPort, PeriodRollInput, PlanCatalogBuildSettings, PlanCatalogImportDto, PlanCatalogImporterControllerConfig, PlanCatalogImporterModule, PlanCatalogImporterModuleOptions, PlanCatalogImporterService, PlanCatalogModule, PlanCatalogModuleOptions, PlanCatalogValidationError, PlanChangeContext, PlanChangePreviewDto, PlanChangePreviewIssue, PlanChangePreviewService, PlanChangeType, PlanResponseEntry, PlanSnapshotDto, PreviewPlanChangeDto, ProrationDto, ProrationInput, PublicBundleEntry, PublicBusinessTypeEntry, PublicCatalogController, PublicCatalogModule, PublicCatalogModuleOptions, PublishValidationError, PublishablePlanVersion, REQUIRE_FEATURE_KEY, RedundantFeatureHint, RenewalDecision, RenewalSubInput, RequireFeature, SELF_SERVICE_BLOCKED_BUNDLES_TOKEN, SELF_SERVICE_BLOCKED_PLANS_TOKEN, SUBSCRIPTION_BUNDLE_CONFIG_TOKEN, SUBSCRIPTION_BUNDLE_REPOSITORY_TOKEN, SUBSCRIPTION_USAGE_PORT_TOKEN, SUBSCRIPTION_WRITE_PORT_TOKEN, SelfServiceBlockedBundles, SelfServiceBlockedPlans, SubscriptionBundleAddPreviewDto, SubscriptionBundleCancelPreviewDto, SubscriptionBundleConfig, SubscriptionBundleControllerOptions, SubscriptionBundleModule, SubscriptionBundleModuleOptions, SubscriptionBundlePreviewContext, SubscriptionBundlePreviewIssue, SubscriptionBundlePreviewService, SubscriptionBundlesService, SubscriptionContractFreezeService, TENANT_AUTH_GUARDS_TOKEN, TENANT_ID_RESOLVER_TOKEN, TRIAL_PROJECTION_PORT_TOKEN, TenantAdminGuard, TenantBillingController, TenantBillingModule, TenantBillingModuleOptions, TenantIdResolver, TrialProjectionInput, TrialProjectionPort, UPSELL_OFFER_CURRENCY_TOKEN, UPSELL_OFFER_RESOLVER_TOKEN, USAGE_SNAPSHOT_PORT_TOKEN, USER_EMAIL_RESOLVER_TOKEN, USER_ID_RESOLVER_TOKEN, UsageResponse, UserEmailResolver, UserIdResolver, addMonths, assertBaseVersionFresh, assertChangeNote, assertDraftPublishable, assertOptimisticLockHeld, buildPlanCatalogFromSnapshot, buildPlanCatalogImporterController, buildTenantSubscriptionBundlesController, clearPendingPlanVersionFields, computeCarriedTrialEndsAt, computeNextPeriod, computeProration, decideRenewal, findPlan, getActiveFeatureKeys, getMarketedPlans, getPlanOrThrow, getPlanPriceGross, getPlanPriceNet, getPlanQuota, initialPeriodWindow, isFeatureInPlan, isFeaturePlannedOnly, loadPlanCatalogFromFile, loadPlanCatalogFromString, periodEndAfter, periodEndWithMinLead, resolveBundleCancelEffectiveAt, resolveBundlePriceNet } from './billing/index.js';
6
6
  import { SuperAdminProvisioningPort, SetupStatusResponse, SetupRequest, SetupResult, SetupConfirmMfaRequest, SetupConfirmMfaResponse } from '@saasicat/types';
7
- export { BundleVersionFields, ChangeDirection, DiffResult, DiscoveredCapability, DiscoveredFeature, DiscoveredQuota, DiscoverySnapshot, PlanVersionFields, VersionChange, VersionChangeDirection, classifyBundleVersionDiff, classifyPlanDiff } from '@saasicat/types';
7
+ export { BundleVersionFields, ChangeDirection, DiffResult, DiscoveredCapability, DiscoveredFeature, DiscoveredQuota, DiscoverySnapshot, PasswordHasher, PlanVersionFields, VersionChange, VersionChangeDirection, classifyBundleVersionDiff, classifyPlanDiff } from '@saasicat/types';
8
8
  export { B as BundleVersionSnapshot, a as BusinessTypeVersionSnapshot, C as CustomLimitsShape, E as EffectiveLimits, b as EffectiveLimitsSnapshot, c as EnforceLimitInput, d as EntitlementService, L as LimitExceededError, P as PlanVersionSnapshot, S as SubscriptionBundleSnapshot, e as SubscriptionLimitsInput, f as aggregateBusinessTypeQuotas, g as aggregateContractLineItemEntitlements, h as aggregateLimits, i as aggregateSubscriptionBundleQuotas, j as applyCustomLimits, k as collectBusinessTypeFeatures, l as collectSubscriptionBundleFeatures, m as filterActiveSubscriptionBundles, n as filterPlannedOnlyFeatures, o as hasAnyFeature, p as hasFeature, t as toEffectiveLimitsSnapshot } from './aggregation-Dvz9e8X2.js';
9
9
  export { ENTITLEMENT_RESOLUTION_CONFIG_TOKEN, EntitlementModule, EntitlementModuleOptions, PLAN_VERSION_REPOSITORY_TOKEN, ReplacedByIndex, SUBSCRIPTION_REPOSITORY_TOKEN, TRANSACTION_RUNNER_TOKEN, buildReplacedByIndex, expandReplacedFeatures } from './entitlement/index.js';
10
10
  export { E as EntitlementResolutionConfig, a as EntitlementResolutionInput, r as resolveEntitlementPlan } from './plan-resolution-CFCoUkrE.js';
@@ -14,7 +14,7 @@ export { A as AdminAuditService } from './admin-audit.service-9IqXMlZm.js';
14
14
  export { a as ADMIN_MANIFEST_CONFIG, A as AdminManifestConfig } from './admin-manifest.config-DyrQNT7M.js';
15
15
  import { DynamicModule } from '@nestjs/common';
16
16
  export { Type as NestType } from '@nestjs/common';
17
- export { ACTIVATION_ORCHESTRATOR_TOKEN, BaseIpRateLimitGuard, ContinueRegistrationDto, PASSWORD_HASHER_TOKEN, PAYMENT_EVENT_LOG_TOKEN, PAYMENT_PROVIDER_TOKEN, PENDING_REGISTRATION_REPOSITORY_TOKEN, PLAN_CATALOG_LOOKUP_TOKEN, PasswordHasher, PaymentWebhookDto, PendingRegistrationService, PreviewRegistrationPromoDto, PromoEvaluation, REGISTRATION_AUDIT_LOGGER_TOKEN, REGISTRATION_BUSINESS_TYPE_LOOKUP_TOKEN, REGISTRATION_CONFIGURATOR_LOOKUP_TOKEN, REGISTRATION_CONFIG_TOKEN, REGISTRATION_OTP_DELIVERY_TOKEN, REGISTRATION_PROMO_PREVIEW_TOKEN, REGISTRATION_RESUME_BASE_URL_TOKEN, REGISTRATION_RESUME_DELIVERY_TOKEN, REGISTRATION_RESUME_TOKEN_SIGNER_TOKEN, RegisterStartDto, RegistrationCleanupCron, RegistrationModule, RegistrationModuleOptions, ResendRegistrationOtpDto, SLUG_AVAILABILITY_CHECK_TOKEN, SaveRegistrationConfigDto, SaveRegistrationConfigSelectionDto, SelectRegistrationPlanDto, StartRegistrationCheckoutDto, USER_ACCOUNT_LOOKUP_TOKEN, VerifyRegistrationOtpDto, computeBreakdown, generateOtpCode, hashOtpCode, resolveModel, slugify, verifyOtpCode } from './registration/index.js';
17
+ export { ACTIVATION_ORCHESTRATOR_TOKEN, BaseIpRateLimitGuard, ContinueRegistrationDto, PASSWORD_HASHER_TOKEN, PAYMENT_EVENT_LOG_TOKEN, PAYMENT_PROVIDER_TOKEN, PENDING_REGISTRATION_REPOSITORY_TOKEN, PLAN_CATALOG_LOOKUP_TOKEN, PaymentWebhookDto, PendingRegistrationService, PreviewRegistrationPromoDto, PromoEvaluation, REGISTRATION_AUDIT_LOGGER_TOKEN, REGISTRATION_BUSINESS_TYPE_LOOKUP_TOKEN, REGISTRATION_CONFIGURATOR_LOOKUP_TOKEN, REGISTRATION_CONFIG_TOKEN, REGISTRATION_OTP_DELIVERY_TOKEN, REGISTRATION_PROMO_PREVIEW_TOKEN, REGISTRATION_RESUME_BASE_URL_TOKEN, REGISTRATION_RESUME_DELIVERY_TOKEN, REGISTRATION_RESUME_TOKEN_SIGNER_TOKEN, RegisterStartDto, RegistrationCleanupCron, RegistrationModule, RegistrationModuleOptions, ResendRegistrationOtpDto, SLUG_AVAILABILITY_CHECK_TOKEN, SaveRegistrationConfigDto, SaveRegistrationConfigSelectionDto, SelectRegistrationPlanDto, StartRegistrationCheckoutDto, USER_ACCOUNT_LOOKUP_TOKEN, VerifyRegistrationOtpDto, computeBreakdown, generateOtpCode, hashOtpCode, resolveModel, slugify, verifyOtpCode } from './registration/index.js';
18
18
  export { DEFINES_QUOTA_KEY, DISCOVERY_SNAPSHOT_TOKEN, DefinesQuota, DefinesQuotaOptions, DiscoveryControllerConfig, DiscoveryModule, DiscoveryModuleOptions, DiscoverySnapshotNotFoundError, ENFORCE_QUOTA_KEY, EnforceQuota, EnforceQuotaMetadata, EnforceQuotaOptions, HeadlessScanOptions, IMPLEMENTS_CAPABILITY_KEY, ImplementsCapability, ImplementsCapabilityMetadata, ImplementsCapabilityOptions, REQUIRES_CAPABILITY_KEY, RequiresCapability, RequiresCapabilityKeys, buildDiscoveryController, loadDiscoverySnapshotFromFile, runHeadlessDiscoveryScan } from './discovery/index.js';
19
19
  export { a as DISCOVERY_APP_INFO_TOKEN, b as DISCOVERY_SNAPSHOT_PATH_TOKEN, D as DiscoveryAppInfo, c as DiscoveryScanner, d as computeSnapshotHash } from './discovery.scanner-CUYLKlYT.js';
20
20
  export { ADVISORY_STRICT_MODE_CODES, BUNDLE_REPOSITORY_TOKEN, BUSINESS_TYPE_REPOSITORY_TOKEN, BundlesService, BusinessTypeBundleInputDto, BusinessTypesService, CATALOG_ENTRY_REPOSITORY_TOKEN, CATALOG_SERVICE_CONFIG_TOKEN, CatalogControllerConfig, CatalogEntriesService, CatalogModule, CatalogModuleOptions, CatalogServiceConfig, CreateBundleDto, CreateBundleVersionDraftDto, CreateBusinessTypeDto, CreateBusinessTypeVersionDraftDto, CreateMarketingProjectionDto, CreatePlanDto, CreatePlanVersionDraftDto, CreatePromotionDto, ListCatalogEntriesQueryDto, ListMarketingProjectionsQueryDto, ListMarketingSettingsQueryDto, ListPromotionsQueryDto, MARKETING_PROJECTION_REPOSITORY_TOKEN, MARKETING_SETTINGS_REPOSITORY_TOKEN, MarketingProjectionsService, MarketingSettingsService, PLAN_REPOSITORY_TOKEN, PROMOTION_REPOSITORY_TOKEN, PlanVersionsService, PlansService, PreflightFinding, PreflightInput, PreflightReport, PromotionsService, PublicMarketingCatalogService, PublishBundleVersionDto, PublishBusinessTypeVersionDto, PublishPlanVersionDto, ReviewCatalogEntryDto, SeedBundleDraft, SeedGateFinding, SeedGateInput, SeedGateMode, SeedGateReport, SeedGateRunOptions, SeedPlanDraft, SyncDiscoveryDto, UpdateBundleDto, UpdateBundleVersionDraftDto, UpdateBusinessTypeDto, UpdateBusinessTypeVersionDraftDto, UpdateCatalogEntryI18nDto, UpdateMarketingProjectionDto, UpdateMarketingSettingsDto, UpdatePlanDto, UpdatePlanVersionDraftDto, UpdatePromotionDto, blockingStrictModeWarnings, buildBundleVersionsController, buildBundlesController, buildBusinessTypeVersionsController, buildBusinessTypesController, buildCatalogEntriesController, buildMarketingProjectionsController, buildMarketingSettingsController, buildPlanVersionsController, buildPlansController, buildPromotionsController, buildPublicMarketingCatalogController, featureApprovalSignature, formatPreflightReport, formatSeedGateReport, loadApprovedCatalogKeys, preflightExitCode, quotaApprovalSignature, runPreflight, runSeedGateFromFile, seedGateExitCode, validateBundleDraft, validateBusinessTypeDraft, validatePlanDraft, validateSeedAgainstSnapshot } from './catalog/index.js';
@@ -47,6 +47,7 @@ module.exports = __toCommonJS(platform_exports);
47
47
  // src/platform/saas-platform.module.ts
48
48
  var import_common22 = require("@nestjs/common");
49
49
  var import_core6 = require("@nestjs/core");
50
+ var import_types = require("@saasicat/types");
50
51
 
51
52
  // src/core/di.ts
52
53
  function asProvider(token, impl) {
@@ -2649,30 +2650,59 @@ var SaasPlatformModule = class _SaasPlatformModule {
2649
2650
  __name(this, "SaasPlatformModule");
2650
2651
  }
2651
2652
  static forRoot(options) {
2652
- if (!options.planCatalog && !options.adapters.planCatalogReadSink) {
2653
- throw new Error("SaasPlatformModule.forRoot: entweder `planCatalog` (Quickstart) oder `adapters.planCatalogReadSink` (DB-Hydration) muss gesetzt sein.");
2653
+ const explicit = options.adapters ?? {};
2654
+ const persistence = options.persistence;
2655
+ const adapters = {
2656
+ mfa: explicit.mfa ?? persistence?.core.mfa,
2657
+ audit: explicit.audit ?? persistence?.core.audit,
2658
+ rlsBypass: explicit.rlsBypass ?? persistence?.core.rlsBypass,
2659
+ planCatalogReadSink: explicit.planCatalogReadSink ?? persistence?.planCatalogReadSink,
2660
+ planResolver: explicit.planResolver,
2661
+ subscriptionRepository: explicit.subscriptionRepository ?? persistence?.entitlement?.subscriptionRepository,
2662
+ planVersionRepository: explicit.planVersionRepository ?? persistence?.entitlement?.planVersionRepository,
2663
+ transactionRunner: explicit.transactionRunner ?? persistence?.core.transactionRunner
2664
+ };
2665
+ const missingCore = [
2666
+ "mfa",
2667
+ "audit",
2668
+ "rlsBypass"
2669
+ ].filter((key) => adapters[key] === void 0);
2670
+ if (missingCore.length) {
2671
+ throw new Error(`SaasPlatformModule.forRoot: adapters missing (provide them via \`adapters\` or a \`persistence\` bundle): ${missingCore.join(", ")}`);
2672
+ }
2673
+ if (!options.planCatalog && (!adapters.planCatalogReadSink || !options.dbCatalog)) {
2674
+ 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 }).");
2654
2675
  }
2655
2676
  if (options.entitlement) {
2656
2677
  const missing = [];
2657
- if (!options.adapters.subscriptionRepository) missing.push("subscriptionRepository");
2658
- if (!options.adapters.planVersionRepository) missing.push("planVersionRepository");
2659
- if (!options.adapters.transactionRunner) missing.push("transactionRunner");
2678
+ if (!adapters.subscriptionRepository) missing.push("subscriptionRepository");
2679
+ if (!adapters.planVersionRepository) missing.push("planVersionRepository");
2680
+ if (!adapters.transactionRunner) missing.push("transactionRunner");
2660
2681
  if (missing.length) {
2661
- throw new Error(`SaasPlatformModule.forRoot: entitlement aktiv, aber Adapter fehlen: ${missing.join(", ")}`);
2682
+ throw new Error(`SaasPlatformModule.forRoot: entitlement active, but adapters are missing: ${missing.join(", ")}`);
2683
+ }
2684
+ if (persistence) {
2685
+ (0, import_types.assertPersistenceCapabilities)(persistence.capabilities, {
2686
+ transactions: true,
2687
+ pessimisticLocking: true
2688
+ }, "SaasPlatformModule entitlement (transactional enforceLimit)");
2662
2689
  }
2663
2690
  }
2691
+ const dbCatalog = options.dbCatalog;
2664
2692
  const planCatalogModule = options.planCatalog ? PlanCatalogModule.forRootWithCatalog(options.planCatalog, {
2665
2693
  global: true
2666
2694
  }) : PlanCatalogModule.forRoot({
2667
- projectKey: "",
2668
- currency: "",
2669
- vatRate: 0,
2670
- sink: options.adapters.planCatalogReadSink,
2695
+ projectKey: dbCatalog.projectKey,
2696
+ app: dbCatalog.app,
2697
+ currency: dbCatalog.currency,
2698
+ vatRate: dbCatalog.vatRate,
2699
+ marketing: dbCatalog.marketing,
2700
+ sink: adapters.planCatalogReadSink,
2671
2701
  imports: options.imports
2672
2702
  });
2673
2703
  const appInfo = options.app ?? {
2674
- key: options.planCatalog?.projectKey ?? "app",
2675
- version: options.planCatalog?.app?.version ?? "0.0.0"
2704
+ key: options.planCatalog?.projectKey ?? options.dbCatalog?.projectKey ?? "app",
2705
+ version: options.planCatalog?.app?.version ?? options.dbCatalog?.app?.version ?? "0.0.0"
2676
2706
  };
2677
2707
  const imports = [
2678
2708
  planCatalogModule,
@@ -2685,9 +2715,9 @@ var SaasPlatformModule = class _SaasPlatformModule {
2685
2715
  snapshotPath: options.discoverySnapshotPath === void 0 ? "var/discovery-snapshot.json" : options.discoverySnapshotPath
2686
2716
  }),
2687
2717
  AdminModule.forRoot({
2688
- mfaPort: options.adapters.mfa,
2689
- auditPort: options.adapters.audit,
2690
- rlsBypassPort: options.adapters.rlsBypass,
2718
+ mfaPort: adapters.mfa,
2719
+ auditPort: adapters.audit,
2720
+ rlsBypassPort: adapters.rlsBypass,
2691
2721
  global: true
2692
2722
  }),
2693
2723
  AdminManifestModule.forRoot({
@@ -2698,18 +2728,21 @@ var SaasPlatformModule = class _SaasPlatformModule {
2698
2728
  ];
2699
2729
  if (options.entitlement) {
2700
2730
  imports.push(EntitlementModule.forRoot({
2701
- subscriptionRepository: options.adapters.subscriptionRepository,
2702
- planVersionRepository: options.adapters.planVersionRepository,
2703
- transactionRunner: options.adapters.transactionRunner,
2704
- resolutionConfig: options.entitlement.resolutionConfig
2731
+ subscriptionRepository: adapters.subscriptionRepository,
2732
+ planVersionRepository: adapters.planVersionRepository,
2733
+ transactionRunner: adapters.transactionRunner,
2734
+ resolutionConfig: options.entitlement.resolutionConfig,
2735
+ subscriptionContractRepository: persistence?.entitlement?.subscriptionContractRepository,
2736
+ subscriptionBundleRepository: persistence?.entitlement?.subscriptionBundleRepository,
2737
+ bundleRepository: persistence?.entitlement?.bundleRepository
2705
2738
  }));
2706
2739
  }
2707
2740
  const lightweightProviders = [];
2708
2741
  const lightweightExports = [];
2709
- const hasResolver = !!options.adapters.planResolver;
2742
+ const hasResolver = !!adapters.planResolver;
2710
2743
  const hasFallback = !!options.defaultPlanId;
2711
2744
  if (hasResolver || hasFallback) {
2712
- lightweightProviders.push(hasResolver ? asProvider(PLAN_RESOLVER_PORT_TOKEN, options.adapters.planResolver) : {
2745
+ lightweightProviders.push(hasResolver ? asProvider(PLAN_RESOLVER_PORT_TOKEN, adapters.planResolver) : {
2713
2746
  provide: PLAN_RESOLVER_PORT_TOKEN,
2714
2747
  useValue: new StaticPlanResolver(options.defaultPlanId)
2715
2748
  }, StaticEntitlementService, StaticFeatureGuard, EnforceQuotaInterceptor, ...options.quotaProviders ?? [], {
@@ -1,5 +1,5 @@
1
- import { P as PlanResolverPort } from '../saas-platform.module-CgZ2omgg.cjs';
2
- export { a as PLAN_RESOLVER_PORT_TOKEN, b as SaasPlatformAdapters, c as SaasPlatformModule, S as SaasPlatformModuleOptions, d as StaticPlanResolver, T as TenantManifestControllerOptions, e as buildTenantManifestController } from '../saas-platform.module-CgZ2omgg.cjs';
1
+ import { P as PlanResolverPort } from '../saas-platform.module-C7-H9eYB.cjs';
2
+ export { a as PLAN_RESOLVER_PORT_TOKEN, S as SaasPlatformAdapters, b as SaasPlatformModule, c as SaasPlatformModuleOptions, d as StaticPlanResolver, T as TenantManifestControllerOptions, e as buildTenantManifestController } from '../saas-platform.module-C7-H9eYB.cjs';
3
3
  import { PlanCatalog, QuotaProvider } from '@saasicat/types';
4
4
  import { CanActivate, ExecutionContext, NestInterceptor, CallHandler } from '@nestjs/common';
5
5
  import { Reflector } from '@nestjs/core';
@@ -1,5 +1,5 @@
1
- import { P as PlanResolverPort } from '../saas-platform.module-DT9TnCzk.js';
2
- export { a as PLAN_RESOLVER_PORT_TOKEN, b as SaasPlatformAdapters, c as SaasPlatformModule, S as SaasPlatformModuleOptions, d as StaticPlanResolver, T as TenantManifestControllerOptions, e as buildTenantManifestController } from '../saas-platform.module-DT9TnCzk.js';
1
+ import { P as PlanResolverPort } from '../saas-platform.module-k1DQg4De.js';
2
+ export { a as PLAN_RESOLVER_PORT_TOKEN, S as SaasPlatformAdapters, b as SaasPlatformModule, c as SaasPlatformModuleOptions, d as StaticPlanResolver, T as TenantManifestControllerOptions, e as buildTenantManifestController } from '../saas-platform.module-k1DQg4De.js';
3
3
  import { PlanCatalog, QuotaProvider } from '@saasicat/types';
4
4
  import { CanActivate, ExecutionContext, NestInterceptor, CallHandler } from '@nestjs/common';
5
5
  import { Reflector } from '@nestjs/core';
@@ -9,7 +9,7 @@ import {
9
9
  StaticPlanResolver,
10
10
  TenantManifestService,
11
11
  buildTenantManifestController
12
- } from "../chunk-QJVPRD3R.js";
12
+ } from "../chunk-47JT54VW.js";
13
13
  import "../chunk-P6MYZMXQ.js";
14
14
  import "../chunk-Q53N43LQ.js";
15
15
  import "../chunk-E56W4U2P.js";
@@ -1,4 +1,5 @@
1
- import { PendingRegistrationRepository, RegistrationOtpDelivery, UserAccountLookup, SlugAvailabilityCheck, PlanCatalogLookup, PaymentProvider, PaymentEventLog, ActivationOrchestrator, RegistrationAuditLogger, RegistrationResumeTokenSigner, RegistrationResumeDelivery, RegistrationConfiguratorLookup, RegistrationPromoPreview, RegistrationBusinessTypeLookup, PublicSignupPlan, SelectPlanInput, RegistrationAuditContext, SelectPlanResult, StartCheckoutInput, StartCheckoutResult, HandlePaymentEventInput, HandlePaymentEventResult, CleanupResult, StartRegistrationInput, StartRegistrationResult, VerifyRegistrationOtpResult, ResumeRegistrationInput, ResumeRegistrationResult, ConfiguratorCatalog, SaveRegistrationConfigInput, SaveRegistrationConfigResult, ConfiguratorPriceBreakdown, RegistrationConfigSelection } from '@saasicat/types';
1
+ import { PendingRegistrationRepository, RegistrationOtpDelivery, UserAccountLookup, SlugAvailabilityCheck, PasswordHasher, PlanCatalogLookup, PaymentProvider, PaymentEventLog, ActivationOrchestrator, RegistrationAuditLogger, RegistrationResumeTokenSigner, RegistrationResumeDelivery, RegistrationConfiguratorLookup, RegistrationPromoPreview, RegistrationBusinessTypeLookup, PublicSignupPlan, SelectPlanInput, RegistrationAuditContext, SelectPlanResult, StartCheckoutInput, StartCheckoutResult, HandlePaymentEventInput, HandlePaymentEventResult, CleanupResult, StartRegistrationInput, StartRegistrationResult, VerifyRegistrationOtpResult, ResumeRegistrationInput, ResumeRegistrationResult, ConfiguratorCatalog, SaveRegistrationConfigInput, SaveRegistrationConfigResult, ConfiguratorPriceBreakdown, RegistrationConfigSelection } from '@saasicat/types';
2
+ export { PasswordHasher } from '@saasicat/types';
2
3
  import { CanActivate, ExecutionContext, Type, DynamicModule, ForwardReference, Provider } from '@nestjs/common';
3
4
  import { P as ProviderSpec } from '../di-CcNeq9v-.cjs';
4
5
  export { CronExpression } from '@nestjs/schedule';
@@ -39,10 +40,6 @@ declare const REGISTRATION_PROMO_PREVIEW_TOKEN: unique symbol;
39
40
  declare const REGISTRATION_BUSINESS_TYPE_LOOKUP_TOKEN: unique symbol;
40
41
  /** Optionally injectable configuration — falls back to default TTLs from saas-platform-types. */
41
42
  declare const REGISTRATION_CONFIG_TOKEN: unique symbol;
42
- interface PasswordHasher {
43
- hash(plain: string): Promise<string>;
44
- verify(hash: string, plain: string): Promise<boolean>;
45
- }
46
43
 
47
44
  /**
48
45
  * Orchestrates step 1 (capture registration data) and step 2 (OTP verification)
@@ -441,4 +438,4 @@ declare function resolveModel(catalog: ConfiguratorCatalog, modelId: string): {
441
438
  yearlyNet: number;
442
439
  };
443
440
 
444
- export { ACTIVATION_ORCHESTRATOR_TOKEN, BaseIpRateLimitGuard, ContinueRegistrationDto, PASSWORD_HASHER_TOKEN, PAYMENT_EVENT_LOG_TOKEN, PAYMENT_PROVIDER_TOKEN, PENDING_REGISTRATION_REPOSITORY_TOKEN, PLAN_CATALOG_LOOKUP_TOKEN, type PasswordHasher, PaymentWebhookDto, PendingRegistrationService, PreviewRegistrationPromoDto, type PromoEvaluation, REGISTRATION_AUDIT_LOGGER_TOKEN, REGISTRATION_BUSINESS_TYPE_LOOKUP_TOKEN, REGISTRATION_CONFIGURATOR_LOOKUP_TOKEN, REGISTRATION_CONFIG_TOKEN, REGISTRATION_OTP_DELIVERY_TOKEN, REGISTRATION_PROMO_PREVIEW_TOKEN, REGISTRATION_RESUME_BASE_URL_TOKEN, REGISTRATION_RESUME_DELIVERY_TOKEN, REGISTRATION_RESUME_TOKEN_SIGNER_TOKEN, RegisterStartDto, RegistrationCleanupCron, RegistrationModule, type RegistrationModuleOptions, ResendRegistrationOtpDto, SLUG_AVAILABILITY_CHECK_TOKEN, SaveRegistrationConfigDto, SaveRegistrationConfigSelectionDto, SelectRegistrationPlanDto, StartRegistrationCheckoutDto, USER_ACCOUNT_LOOKUP_TOKEN, VerifyRegistrationOtpDto, computeBreakdown, generateOtpCode, hashOtpCode, resolveModel, slugify, verifyOtpCode };
441
+ export { ACTIVATION_ORCHESTRATOR_TOKEN, BaseIpRateLimitGuard, ContinueRegistrationDto, PASSWORD_HASHER_TOKEN, PAYMENT_EVENT_LOG_TOKEN, PAYMENT_PROVIDER_TOKEN, PENDING_REGISTRATION_REPOSITORY_TOKEN, PLAN_CATALOG_LOOKUP_TOKEN, PaymentWebhookDto, PendingRegistrationService, PreviewRegistrationPromoDto, type PromoEvaluation, REGISTRATION_AUDIT_LOGGER_TOKEN, REGISTRATION_BUSINESS_TYPE_LOOKUP_TOKEN, REGISTRATION_CONFIGURATOR_LOOKUP_TOKEN, REGISTRATION_CONFIG_TOKEN, REGISTRATION_OTP_DELIVERY_TOKEN, REGISTRATION_PROMO_PREVIEW_TOKEN, REGISTRATION_RESUME_BASE_URL_TOKEN, REGISTRATION_RESUME_DELIVERY_TOKEN, REGISTRATION_RESUME_TOKEN_SIGNER_TOKEN, RegisterStartDto, RegistrationCleanupCron, RegistrationModule, type RegistrationModuleOptions, ResendRegistrationOtpDto, SLUG_AVAILABILITY_CHECK_TOKEN, SaveRegistrationConfigDto, SaveRegistrationConfigSelectionDto, SelectRegistrationPlanDto, StartRegistrationCheckoutDto, USER_ACCOUNT_LOOKUP_TOKEN, VerifyRegistrationOtpDto, computeBreakdown, generateOtpCode, hashOtpCode, resolveModel, slugify, verifyOtpCode };
@@ -1,4 +1,5 @@
1
- import { PendingRegistrationRepository, RegistrationOtpDelivery, UserAccountLookup, SlugAvailabilityCheck, PlanCatalogLookup, PaymentProvider, PaymentEventLog, ActivationOrchestrator, RegistrationAuditLogger, RegistrationResumeTokenSigner, RegistrationResumeDelivery, RegistrationConfiguratorLookup, RegistrationPromoPreview, RegistrationBusinessTypeLookup, PublicSignupPlan, SelectPlanInput, RegistrationAuditContext, SelectPlanResult, StartCheckoutInput, StartCheckoutResult, HandlePaymentEventInput, HandlePaymentEventResult, CleanupResult, StartRegistrationInput, StartRegistrationResult, VerifyRegistrationOtpResult, ResumeRegistrationInput, ResumeRegistrationResult, ConfiguratorCatalog, SaveRegistrationConfigInput, SaveRegistrationConfigResult, ConfiguratorPriceBreakdown, RegistrationConfigSelection } from '@saasicat/types';
1
+ import { PendingRegistrationRepository, RegistrationOtpDelivery, UserAccountLookup, SlugAvailabilityCheck, PasswordHasher, PlanCatalogLookup, PaymentProvider, PaymentEventLog, ActivationOrchestrator, RegistrationAuditLogger, RegistrationResumeTokenSigner, RegistrationResumeDelivery, RegistrationConfiguratorLookup, RegistrationPromoPreview, RegistrationBusinessTypeLookup, PublicSignupPlan, SelectPlanInput, RegistrationAuditContext, SelectPlanResult, StartCheckoutInput, StartCheckoutResult, HandlePaymentEventInput, HandlePaymentEventResult, CleanupResult, StartRegistrationInput, StartRegistrationResult, VerifyRegistrationOtpResult, ResumeRegistrationInput, ResumeRegistrationResult, ConfiguratorCatalog, SaveRegistrationConfigInput, SaveRegistrationConfigResult, ConfiguratorPriceBreakdown, RegistrationConfigSelection } from '@saasicat/types';
2
+ export { PasswordHasher } from '@saasicat/types';
2
3
  import { CanActivate, ExecutionContext, Type, DynamicModule, ForwardReference, Provider } from '@nestjs/common';
3
4
  import { P as ProviderSpec } from '../di-CcNeq9v-.js';
4
5
  export { CronExpression } from '@nestjs/schedule';
@@ -39,10 +40,6 @@ declare const REGISTRATION_PROMO_PREVIEW_TOKEN: unique symbol;
39
40
  declare const REGISTRATION_BUSINESS_TYPE_LOOKUP_TOKEN: unique symbol;
40
41
  /** Optionally injectable configuration — falls back to default TTLs from saas-platform-types. */
41
42
  declare const REGISTRATION_CONFIG_TOKEN: unique symbol;
42
- interface PasswordHasher {
43
- hash(plain: string): Promise<string>;
44
- verify(hash: string, plain: string): Promise<boolean>;
45
- }
46
43
 
47
44
  /**
48
45
  * Orchestrates step 1 (capture registration data) and step 2 (OTP verification)
@@ -441,4 +438,4 @@ declare function resolveModel(catalog: ConfiguratorCatalog, modelId: string): {
441
438
  yearlyNet: number;
442
439
  };
443
440
 
444
- export { ACTIVATION_ORCHESTRATOR_TOKEN, BaseIpRateLimitGuard, ContinueRegistrationDto, PASSWORD_HASHER_TOKEN, PAYMENT_EVENT_LOG_TOKEN, PAYMENT_PROVIDER_TOKEN, PENDING_REGISTRATION_REPOSITORY_TOKEN, PLAN_CATALOG_LOOKUP_TOKEN, type PasswordHasher, PaymentWebhookDto, PendingRegistrationService, PreviewRegistrationPromoDto, type PromoEvaluation, REGISTRATION_AUDIT_LOGGER_TOKEN, REGISTRATION_BUSINESS_TYPE_LOOKUP_TOKEN, REGISTRATION_CONFIGURATOR_LOOKUP_TOKEN, REGISTRATION_CONFIG_TOKEN, REGISTRATION_OTP_DELIVERY_TOKEN, REGISTRATION_PROMO_PREVIEW_TOKEN, REGISTRATION_RESUME_BASE_URL_TOKEN, REGISTRATION_RESUME_DELIVERY_TOKEN, REGISTRATION_RESUME_TOKEN_SIGNER_TOKEN, RegisterStartDto, RegistrationCleanupCron, RegistrationModule, type RegistrationModuleOptions, ResendRegistrationOtpDto, SLUG_AVAILABILITY_CHECK_TOKEN, SaveRegistrationConfigDto, SaveRegistrationConfigSelectionDto, SelectRegistrationPlanDto, StartRegistrationCheckoutDto, USER_ACCOUNT_LOOKUP_TOKEN, VerifyRegistrationOtpDto, computeBreakdown, generateOtpCode, hashOtpCode, resolveModel, slugify, verifyOtpCode };
441
+ export { ACTIVATION_ORCHESTRATOR_TOKEN, BaseIpRateLimitGuard, ContinueRegistrationDto, PASSWORD_HASHER_TOKEN, PAYMENT_EVENT_LOG_TOKEN, PAYMENT_PROVIDER_TOKEN, PENDING_REGISTRATION_REPOSITORY_TOKEN, PLAN_CATALOG_LOOKUP_TOKEN, PaymentWebhookDto, PendingRegistrationService, PreviewRegistrationPromoDto, type PromoEvaluation, REGISTRATION_AUDIT_LOGGER_TOKEN, REGISTRATION_BUSINESS_TYPE_LOOKUP_TOKEN, REGISTRATION_CONFIGURATOR_LOOKUP_TOKEN, REGISTRATION_CONFIG_TOKEN, REGISTRATION_OTP_DELIVERY_TOKEN, REGISTRATION_PROMO_PREVIEW_TOKEN, REGISTRATION_RESUME_BASE_URL_TOKEN, REGISTRATION_RESUME_DELIVERY_TOKEN, REGISTRATION_RESUME_TOKEN_SIGNER_TOKEN, RegisterStartDto, RegistrationCleanupCron, RegistrationModule, type RegistrationModuleOptions, ResendRegistrationOtpDto, SLUG_AVAILABILITY_CHECK_TOKEN, SaveRegistrationConfigDto, SaveRegistrationConfigSelectionDto, SelectRegistrationPlanDto, StartRegistrationCheckoutDto, USER_ACCOUNT_LOOKUP_TOKEN, VerifyRegistrationOtpDto, computeBreakdown, generateOtpCode, hashOtpCode, resolveModel, slugify, verifyOtpCode };
@@ -1,5 +1,5 @@
1
1
  import { Type, CanActivate, DynamicModule, ForwardReference, FactoryProvider } from '@nestjs/common';
2
- import { MfaPort, AuditPort, RlsBypassPort, PlanCatalogReadSink, SubscriptionRepository, PlanVersionRepository, TransactionRunner, PlanCatalog, QuotaProvider } from '@saasicat/types';
2
+ import { MfaPort, AuditPort, RlsBypassPort, PlanCatalogReadSink, SubscriptionRepository, PlanVersionRepository, TransactionRunner, PlanCatalog, SaasicatPersistenceAdapter, QuotaProvider } from '@saasicat/types';
3
3
  import { P as ProviderSpec } from './di-CcNeq9v-.cjs';
4
4
  import { A as AdminManifestConfig } from './admin-manifest.config-DyrQNT7M.cjs';
5
5
  import { D as DiscoveryAppInfo } from './discovery.scanner-CUYLKlYT.cjs';
@@ -75,14 +75,38 @@ interface SaasPlatformAdapters {
75
75
  interface SaasPlatformModuleOptions {
76
76
  /**
77
77
  * Plan catalog. Either as an already-loaded object (quickstart, comes
78
- * directly from `loadPlanCatalogFromFile('config/saas.yaml')`) or as a
79
- * sink reference in `adapters.planCatalogReadSink` for DB hydration.
78
+ * directly from `loadPlanCatalogFromFile('config/saas.yaml')`) or via DB
79
+ * hydration: a sink reference in `adapters.planCatalogReadSink` /
80
+ * `persistence.planCatalogReadSink` **plus** the `dbCatalog` identity.
80
81
  */
81
82
  planCatalog?: PlanCatalog;
82
83
  /**
83
- * Adapter bindings.
84
+ * App identity for the DB-hydration path — required when `planCatalog`
85
+ * is omitted. The read sink only loads plans/features (filtered by
86
+ * `projectKey`); branding, currency and VAT cannot come from the
87
+ * database and must be supplied here.
88
+ */
89
+ dbCatalog?: {
90
+ projectKey: string;
91
+ currency: string;
92
+ vatRate: number;
93
+ app?: PlanCatalog['app'];
94
+ marketing?: PlanCatalog['marketing'];
95
+ };
96
+ /**
97
+ * Aggregate persistence bundle from an adapter package (e.g.
98
+ * `prismaPersistence({ client: PrismaService })` from
99
+ * `@saasicat/adapter-prisma`). Fills every port the bundle ships;
100
+ * individual `adapters` entries override bundle slices. The declared
101
+ * `capabilities` are validated fail-fast against the enabled feature set
102
+ * (e.g. `entitlement: true` requires transactions + pessimistic locking).
84
103
  */
85
- adapters: SaasPlatformAdapters;
104
+ persistence?: SaasicatPersistenceAdapter;
105
+ /**
106
+ * Individual adapter bindings. Optional when `persistence` provides the
107
+ * respective port; explicit entries take precedence over the bundle.
108
+ */
109
+ adapters?: SaasPlatformAdapters;
86
110
  /**
87
111
  * Class-level guards for the platform controllers (`GET /admin/discovery`
88
112
  * and `GET /admin/manifest`). REQUIRED — otherwise the platform throws at
@@ -158,23 +182,22 @@ interface SaasPlatformModuleOptions {
158
182
  * Entitlement) into a single `forRoot({...})` call. Reduces AppModule
159
183
  * boilerplate and eliminates the ordering trap.
160
184
  *
161
- * Quickstart path:
185
+ * Quickstart path (Prisma + PostgreSQL on the canonical schema):
162
186
  *
163
187
  * ```ts
164
188
  * SaasPlatformModule.forRoot({
165
189
  * planCatalog: loadPlanCatalogFromFile({ path: 'config/saas.yaml' }),
166
190
  * controller: { guards: [JwtAuthGuard] },
167
191
  * imports: [AuthModule],
168
- * adapters: {
169
- * mfa: PrismaMfaAdapter, // from @saasicat/prisma
170
- * audit: PrismaAuditAdapter,
171
- * rlsBypass: AsyncLocalRlsBypassAdapter,
172
- * },
192
+ * persistence: prismaPersistence({ client: PrismaService }), // @saasicat/adapter-prisma
173
193
  * })
174
194
  * ```
195
+ *
196
+ * Individual `adapters` entries stay supported (custom schema / other ORM)
197
+ * and override bundle slices field by field.
175
198
  */
176
199
  declare class SaasPlatformModule {
177
200
  static forRoot(options: SaasPlatformModuleOptions): DynamicModule;
178
201
  }
179
202
 
180
- export { type PlanResolverPort as P, type SaasPlatformModuleOptions as S, type TenantManifestControllerOptions as T, PLAN_RESOLVER_PORT_TOKEN as a, type SaasPlatformAdapters as b, SaasPlatformModule as c, StaticPlanResolver as d, buildTenantManifestController as e };
203
+ export { type PlanResolverPort as P, type SaasPlatformAdapters as S, type TenantManifestControllerOptions as T, PLAN_RESOLVER_PORT_TOKEN as a, SaasPlatformModule as b, type SaasPlatformModuleOptions as c, StaticPlanResolver as d, buildTenantManifestController as e };
@@ -1,5 +1,5 @@
1
1
  import { Type, CanActivate, DynamicModule, ForwardReference, FactoryProvider } from '@nestjs/common';
2
- import { MfaPort, AuditPort, RlsBypassPort, PlanCatalogReadSink, SubscriptionRepository, PlanVersionRepository, TransactionRunner, PlanCatalog, QuotaProvider } from '@saasicat/types';
2
+ import { MfaPort, AuditPort, RlsBypassPort, PlanCatalogReadSink, SubscriptionRepository, PlanVersionRepository, TransactionRunner, PlanCatalog, SaasicatPersistenceAdapter, QuotaProvider } from '@saasicat/types';
3
3
  import { P as ProviderSpec } from './di-CcNeq9v-.js';
4
4
  import { A as AdminManifestConfig } from './admin-manifest.config-DyrQNT7M.js';
5
5
  import { D as DiscoveryAppInfo } from './discovery.scanner-CUYLKlYT.js';
@@ -75,14 +75,38 @@ interface SaasPlatformAdapters {
75
75
  interface SaasPlatformModuleOptions {
76
76
  /**
77
77
  * Plan catalog. Either as an already-loaded object (quickstart, comes
78
- * directly from `loadPlanCatalogFromFile('config/saas.yaml')`) or as a
79
- * sink reference in `adapters.planCatalogReadSink` for DB hydration.
78
+ * directly from `loadPlanCatalogFromFile('config/saas.yaml')`) or via DB
79
+ * hydration: a sink reference in `adapters.planCatalogReadSink` /
80
+ * `persistence.planCatalogReadSink` **plus** the `dbCatalog` identity.
80
81
  */
81
82
  planCatalog?: PlanCatalog;
82
83
  /**
83
- * Adapter bindings.
84
+ * App identity for the DB-hydration path — required when `planCatalog`
85
+ * is omitted. The read sink only loads plans/features (filtered by
86
+ * `projectKey`); branding, currency and VAT cannot come from the
87
+ * database and must be supplied here.
88
+ */
89
+ dbCatalog?: {
90
+ projectKey: string;
91
+ currency: string;
92
+ vatRate: number;
93
+ app?: PlanCatalog['app'];
94
+ marketing?: PlanCatalog['marketing'];
95
+ };
96
+ /**
97
+ * Aggregate persistence bundle from an adapter package (e.g.
98
+ * `prismaPersistence({ client: PrismaService })` from
99
+ * `@saasicat/adapter-prisma`). Fills every port the bundle ships;
100
+ * individual `adapters` entries override bundle slices. The declared
101
+ * `capabilities` are validated fail-fast against the enabled feature set
102
+ * (e.g. `entitlement: true` requires transactions + pessimistic locking).
84
103
  */
85
- adapters: SaasPlatformAdapters;
104
+ persistence?: SaasicatPersistenceAdapter;
105
+ /**
106
+ * Individual adapter bindings. Optional when `persistence` provides the
107
+ * respective port; explicit entries take precedence over the bundle.
108
+ */
109
+ adapters?: SaasPlatformAdapters;
86
110
  /**
87
111
  * Class-level guards for the platform controllers (`GET /admin/discovery`
88
112
  * and `GET /admin/manifest`). REQUIRED — otherwise the platform throws at
@@ -158,23 +182,22 @@ interface SaasPlatformModuleOptions {
158
182
  * Entitlement) into a single `forRoot({...})` call. Reduces AppModule
159
183
  * boilerplate and eliminates the ordering trap.
160
184
  *
161
- * Quickstart path:
185
+ * Quickstart path (Prisma + PostgreSQL on the canonical schema):
162
186
  *
163
187
  * ```ts
164
188
  * SaasPlatformModule.forRoot({
165
189
  * planCatalog: loadPlanCatalogFromFile({ path: 'config/saas.yaml' }),
166
190
  * controller: { guards: [JwtAuthGuard] },
167
191
  * imports: [AuthModule],
168
- * adapters: {
169
- * mfa: PrismaMfaAdapter, // from @saasicat/prisma
170
- * audit: PrismaAuditAdapter,
171
- * rlsBypass: AsyncLocalRlsBypassAdapter,
172
- * },
192
+ * persistence: prismaPersistence({ client: PrismaService }), // @saasicat/adapter-prisma
173
193
  * })
174
194
  * ```
195
+ *
196
+ * Individual `adapters` entries stay supported (custom schema / other ORM)
197
+ * and override bundle slices field by field.
175
198
  */
176
199
  declare class SaasPlatformModule {
177
200
  static forRoot(options: SaasPlatformModuleOptions): DynamicModule;
178
201
  }
179
202
 
180
- export { type PlanResolverPort as P, type SaasPlatformModuleOptions as S, type TenantManifestControllerOptions as T, PLAN_RESOLVER_PORT_TOKEN as a, type SaasPlatformAdapters as b, SaasPlatformModule as c, StaticPlanResolver as d, buildTenantManifestController as e };
203
+ export { type PlanResolverPort as P, type SaasPlatformAdapters as S, type TenantManifestControllerOptions as T, PLAN_RESOLVER_PORT_TOKEN as a, SaasPlatformModule as b, type SaasPlatformModuleOptions as c, StaticPlanResolver as d, buildTenantManifestController as e };
@@ -1141,6 +1141,7 @@ var import_common23 = require("@nestjs/common");
1141
1141
  // src/platform/saas-platform.module.ts
1142
1142
  var import_common22 = require("@nestjs/common");
1143
1143
  var import_core6 = require("@nestjs/core");
1144
+ var import_types2 = require("@saasicat/types");
1144
1145
 
1145
1146
  // src/core/di.ts
1146
1147
  function asProvider(token, impl) {
@@ -3743,30 +3744,59 @@ var SaasPlatformModule = class _SaasPlatformModule {
3743
3744
  __name(this, "SaasPlatformModule");
3744
3745
  }
3745
3746
  static forRoot(options) {
3746
- if (!options.planCatalog && !options.adapters.planCatalogReadSink) {
3747
- throw new Error("SaasPlatformModule.forRoot: entweder `planCatalog` (Quickstart) oder `adapters.planCatalogReadSink` (DB-Hydration) muss gesetzt sein.");
3747
+ const explicit = options.adapters ?? {};
3748
+ const persistence = options.persistence;
3749
+ const adapters = {
3750
+ mfa: explicit.mfa ?? persistence?.core.mfa,
3751
+ audit: explicit.audit ?? persistence?.core.audit,
3752
+ rlsBypass: explicit.rlsBypass ?? persistence?.core.rlsBypass,
3753
+ planCatalogReadSink: explicit.planCatalogReadSink ?? persistence?.planCatalogReadSink,
3754
+ planResolver: explicit.planResolver,
3755
+ subscriptionRepository: explicit.subscriptionRepository ?? persistence?.entitlement?.subscriptionRepository,
3756
+ planVersionRepository: explicit.planVersionRepository ?? persistence?.entitlement?.planVersionRepository,
3757
+ transactionRunner: explicit.transactionRunner ?? persistence?.core.transactionRunner
3758
+ };
3759
+ const missingCore = [
3760
+ "mfa",
3761
+ "audit",
3762
+ "rlsBypass"
3763
+ ].filter((key) => adapters[key] === void 0);
3764
+ if (missingCore.length) {
3765
+ throw new Error(`SaasPlatformModule.forRoot: adapters missing (provide them via \`adapters\` or a \`persistence\` bundle): ${missingCore.join(", ")}`);
3766
+ }
3767
+ if (!options.planCatalog && (!adapters.planCatalogReadSink || !options.dbCatalog)) {
3768
+ 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 }).");
3748
3769
  }
3749
3770
  if (options.entitlement) {
3750
3771
  const missing = [];
3751
- if (!options.adapters.subscriptionRepository) missing.push("subscriptionRepository");
3752
- if (!options.adapters.planVersionRepository) missing.push("planVersionRepository");
3753
- if (!options.adapters.transactionRunner) missing.push("transactionRunner");
3772
+ if (!adapters.subscriptionRepository) missing.push("subscriptionRepository");
3773
+ if (!adapters.planVersionRepository) missing.push("planVersionRepository");
3774
+ if (!adapters.transactionRunner) missing.push("transactionRunner");
3754
3775
  if (missing.length) {
3755
- throw new Error(`SaasPlatformModule.forRoot: entitlement aktiv, aber Adapter fehlen: ${missing.join(", ")}`);
3776
+ throw new Error(`SaasPlatformModule.forRoot: entitlement active, but adapters are missing: ${missing.join(", ")}`);
3777
+ }
3778
+ if (persistence) {
3779
+ (0, import_types2.assertPersistenceCapabilities)(persistence.capabilities, {
3780
+ transactions: true,
3781
+ pessimisticLocking: true
3782
+ }, "SaasPlatformModule entitlement (transactional enforceLimit)");
3756
3783
  }
3757
3784
  }
3785
+ const dbCatalog = options.dbCatalog;
3758
3786
  const planCatalogModule = options.planCatalog ? PlanCatalogModule.forRootWithCatalog(options.planCatalog, {
3759
3787
  global: true
3760
3788
  }) : PlanCatalogModule.forRoot({
3761
- projectKey: "",
3762
- currency: "",
3763
- vatRate: 0,
3764
- sink: options.adapters.planCatalogReadSink,
3789
+ projectKey: dbCatalog.projectKey,
3790
+ app: dbCatalog.app,
3791
+ currency: dbCatalog.currency,
3792
+ vatRate: dbCatalog.vatRate,
3793
+ marketing: dbCatalog.marketing,
3794
+ sink: adapters.planCatalogReadSink,
3765
3795
  imports: options.imports
3766
3796
  });
3767
3797
  const appInfo = options.app ?? {
3768
- key: options.planCatalog?.projectKey ?? "app",
3769
- version: options.planCatalog?.app?.version ?? "0.0.0"
3798
+ key: options.planCatalog?.projectKey ?? options.dbCatalog?.projectKey ?? "app",
3799
+ version: options.planCatalog?.app?.version ?? options.dbCatalog?.app?.version ?? "0.0.0"
3770
3800
  };
3771
3801
  const imports = [
3772
3802
  planCatalogModule,
@@ -3779,9 +3809,9 @@ var SaasPlatformModule = class _SaasPlatformModule {
3779
3809
  snapshotPath: options.discoverySnapshotPath === void 0 ? "var/discovery-snapshot.json" : options.discoverySnapshotPath
3780
3810
  }),
3781
3811
  AdminModule.forRoot({
3782
- mfaPort: options.adapters.mfa,
3783
- auditPort: options.adapters.audit,
3784
- rlsBypassPort: options.adapters.rlsBypass,
3812
+ mfaPort: adapters.mfa,
3813
+ auditPort: adapters.audit,
3814
+ rlsBypassPort: adapters.rlsBypass,
3785
3815
  global: true
3786
3816
  }),
3787
3817
  AdminManifestModule.forRoot({
@@ -3792,18 +3822,21 @@ var SaasPlatformModule = class _SaasPlatformModule {
3792
3822
  ];
3793
3823
  if (options.entitlement) {
3794
3824
  imports.push(EntitlementModule.forRoot({
3795
- subscriptionRepository: options.adapters.subscriptionRepository,
3796
- planVersionRepository: options.adapters.planVersionRepository,
3797
- transactionRunner: options.adapters.transactionRunner,
3798
- resolutionConfig: options.entitlement.resolutionConfig
3825
+ subscriptionRepository: adapters.subscriptionRepository,
3826
+ planVersionRepository: adapters.planVersionRepository,
3827
+ transactionRunner: adapters.transactionRunner,
3828
+ resolutionConfig: options.entitlement.resolutionConfig,
3829
+ subscriptionContractRepository: persistence?.entitlement?.subscriptionContractRepository,
3830
+ subscriptionBundleRepository: persistence?.entitlement?.subscriptionBundleRepository,
3831
+ bundleRepository: persistence?.entitlement?.bundleRepository
3799
3832
  }));
3800
3833
  }
3801
3834
  const lightweightProviders = [];
3802
3835
  const lightweightExports = [];
3803
- const hasResolver = !!options.adapters.planResolver;
3836
+ const hasResolver = !!adapters.planResolver;
3804
3837
  const hasFallback = !!options.defaultPlanId;
3805
3838
  if (hasResolver || hasFallback) {
3806
- lightweightProviders.push(hasResolver ? asProvider(PLAN_RESOLVER_PORT_TOKEN, options.adapters.planResolver) : {
3839
+ lightweightProviders.push(hasResolver ? asProvider(PLAN_RESOLVER_PORT_TOKEN, adapters.planResolver) : {
3807
3840
  provide: PLAN_RESOLVER_PORT_TOKEN,
3808
3841
  useValue: new StaticPlanResolver(options.defaultPlanId)
3809
3842
  }, StaticEntitlementService, StaticFeatureGuard, EnforceQuotaInterceptor, ...options.quotaProviders ?? [], {
@@ -1,6 +1,6 @@
1
1
  import { BundleRepository, BundleRow, BundleVersionRow, BundleListFilter, CreateBundleData, UpdateBundleData, CreateBundleVersionDraftData, UpdateBundleVersionDraftData, VersionChange, BusinessTypeRepository, BusinessTypeRow, BusinessTypeVersionRow, BusinessTypeListFilter, CreateBusinessTypeData, UpdateBusinessTypeData, CreateBusinessTypeVersionDraftData, UpdateBusinessTypeVersionDraftData, MarketingProjectionRepository, MarketingProjectionRow, MarketingProjectionFilter, CreateMarketingProjectionData, UpdateMarketingProjectionData, PlanRepository, PlanRow, PlanVersionRow, PlanListFilter, CreatePlanData, UpdatePlanData, CreatePlanVersionDraftData, UpdatePlanVersionDraftData, PlanVersionRepository, PlanVersionRecord, TransactionContext, SubscriptionBundleRepository, SubscriptionBundleRecord, CreateSubscriptionBundleData, CancelSubscriptionBundleData, SubscriptionContractRepository, SubscriptionContractFilter, SubscriptionContractRecord, CreateSubscriptionContractData, TerminateSubscriptionContractData, SubscriptionRepository, SubscriptionRecord, TransactionRunner, PlanCatalog, QuotaProvider } from '@saasicat/types';
2
2
  import { Type, DynamicModule } from '@nestjs/common';
3
- import { S as SaasPlatformModuleOptions } from '../saas-platform.module-CgZ2omgg.cjs';
3
+ import { S as SaasPlatformAdapters } from '../saas-platform.module-C7-H9eYB.cjs';
4
4
  import '../di-CcNeq9v-.cjs';
5
5
  import '../admin-manifest.config-DyrQNT7M.cjs';
6
6
  import '../discovery.scanner-CUYLKlYT.cjs';
@@ -263,11 +263,7 @@ interface CreateSaasPlatformTestModuleOptions {
263
263
  /** QuotaProvider classes for the `EnforceQuotaInterceptor`. */
264
264
  quotaProviders?: Array<Type<QuotaProvider>>;
265
265
  /** Overrides — if the test needs a different adapter. */
266
- overrides?: Partial<{
267
- mfa: SaasPlatformModuleOptions['adapters']['mfa'];
268
- audit: SaasPlatformModuleOptions['adapters']['audit'];
269
- rlsBypass: SaasPlatformModuleOptions['adapters']['rlsBypass'];
270
- }>;
266
+ overrides?: Partial<Pick<SaasPlatformAdapters, 'mfa' | 'audit' | 'rlsBypass'>>;
271
267
  }
272
268
  /**
273
269
  * Returns a `DynamicModule` that sets up the SaasPlatformModule with stub
@@ -1,6 +1,6 @@
1
1
  import { BundleRepository, BundleRow, BundleVersionRow, BundleListFilter, CreateBundleData, UpdateBundleData, CreateBundleVersionDraftData, UpdateBundleVersionDraftData, VersionChange, BusinessTypeRepository, BusinessTypeRow, BusinessTypeVersionRow, BusinessTypeListFilter, CreateBusinessTypeData, UpdateBusinessTypeData, CreateBusinessTypeVersionDraftData, UpdateBusinessTypeVersionDraftData, MarketingProjectionRepository, MarketingProjectionRow, MarketingProjectionFilter, CreateMarketingProjectionData, UpdateMarketingProjectionData, PlanRepository, PlanRow, PlanVersionRow, PlanListFilter, CreatePlanData, UpdatePlanData, CreatePlanVersionDraftData, UpdatePlanVersionDraftData, PlanVersionRepository, PlanVersionRecord, TransactionContext, SubscriptionBundleRepository, SubscriptionBundleRecord, CreateSubscriptionBundleData, CancelSubscriptionBundleData, SubscriptionContractRepository, SubscriptionContractFilter, SubscriptionContractRecord, CreateSubscriptionContractData, TerminateSubscriptionContractData, SubscriptionRepository, SubscriptionRecord, TransactionRunner, PlanCatalog, QuotaProvider } from '@saasicat/types';
2
2
  import { Type, DynamicModule } from '@nestjs/common';
3
- import { S as SaasPlatformModuleOptions } from '../saas-platform.module-DT9TnCzk.js';
3
+ import { S as SaasPlatformAdapters } from '../saas-platform.module-k1DQg4De.js';
4
4
  import '../di-CcNeq9v-.js';
5
5
  import '../admin-manifest.config-DyrQNT7M.js';
6
6
  import '../discovery.scanner-CUYLKlYT.js';
@@ -263,11 +263,7 @@ interface CreateSaasPlatformTestModuleOptions {
263
263
  /** QuotaProvider classes for the `EnforceQuotaInterceptor`. */
264
264
  quotaProviders?: Array<Type<QuotaProvider>>;
265
265
  /** Overrides — if the test needs a different adapter. */
266
- overrides?: Partial<{
267
- mfa: SaasPlatformModuleOptions['adapters']['mfa'];
268
- audit: SaasPlatformModuleOptions['adapters']['audit'];
269
- rlsBypass: SaasPlatformModuleOptions['adapters']['rlsBypass'];
270
- }>;
266
+ overrides?: Partial<Pick<SaasPlatformAdapters, 'mfa' | 'audit' | 'rlsBypass'>>;
271
267
  }
272
268
  /**
273
269
  * Returns a `DynamicModule` that sets up the SaasPlatformModule with stub
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  SaasPlatformModule
3
- } from "../chunk-QJVPRD3R.js";
3
+ } from "../chunk-47JT54VW.js";
4
4
  import "../chunk-P6MYZMXQ.js";
5
5
  import "../chunk-Q53N43LQ.js";
6
6
  import "../chunk-E56W4U2P.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@saasicat/nest",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "NestJS implementation of the SaaS platform: billing, promo codes, admin backend, audit, MFA, adapter ports.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -137,8 +137,8 @@
137
137
  "js-yaml": "^4.1.0",
138
138
  "otplib": "^13.4.1",
139
139
  "qrcode": "^1.5.4",
140
- "@saasicat/spec": "^0.2.0",
141
- "@saasicat/types": "^0.2.0"
140
+ "@saasicat/spec": "^0.3.0",
141
+ "@saasicat/types": "^0.3.0"
142
142
  },
143
143
  "peerDependencies": {
144
144
  "@nestjs/common": "^11.0.0",