@saasicat/nest 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +202 -0
- package/README.md +53 -0
- package/dist/admin/index.cjs +1283 -0
- package/dist/admin/index.d.cts +225 -0
- package/dist/admin/index.d.ts +225 -0
- package/dist/admin/index.js +58 -0
- package/dist/admin-audit.service-9IqXMlZm.d.cts +30 -0
- package/dist/admin-audit.service-9IqXMlZm.d.ts +30 -0
- package/dist/admin-manifest.config-DyrQNT7M.d.cts +10 -0
- package/dist/admin-manifest.config-DyrQNT7M.d.ts +10 -0
- package/dist/aggregation-CJ3qQf92.d.cts +288 -0
- package/dist/aggregation-Dvz9e8X2.d.ts +288 -0
- package/dist/billing/index.cjs +5205 -0
- package/dist/billing/index.d.cts +1326 -0
- package/dist/billing/index.d.ts +1326 -0
- package/dist/billing/index.js +197 -0
- package/dist/catalog/index.cjs +6449 -0
- package/dist/catalog/index.d.cts +1073 -0
- package/dist/catalog/index.d.ts +1073 -0
- package/dist/catalog/index.js +158 -0
- package/dist/checkout-offer/index.cjs +807 -0
- package/dist/checkout-offer/index.d.cts +120 -0
- package/dist/checkout-offer/index.d.ts +120 -0
- package/dist/checkout-offer/index.js +20 -0
- package/dist/chunk-2FR6ZL7R.js +0 -0
- package/dist/chunk-2PNX2QL2.js +347 -0
- package/dist/chunk-2VNZYRDV.js +326 -0
- package/dist/chunk-7MLGHWKO.js +12 -0
- package/dist/chunk-ABB2CRAS.js +31 -0
- package/dist/chunk-AJ3EPELS.js +157 -0
- package/dist/chunk-E56W4U2P.js +90 -0
- package/dist/chunk-HRU3CP57.js +71 -0
- package/dist/chunk-L4SUWH5B.js +14 -0
- package/dist/chunk-M6CZQYPY.js +314 -0
- package/dist/chunk-MDIZUVIK.js +87 -0
- package/dist/chunk-MV6LW5UB.js +217 -0
- package/dist/chunk-NYLON2VC.js +6 -0
- package/dist/chunk-P6MYZMXQ.js +951 -0
- package/dist/chunk-Q53N43LQ.js +13 -0
- package/dist/chunk-QJVPRD3R.js +573 -0
- package/dist/chunk-RIGLQ4BV.js +3367 -0
- package/dist/chunk-SABTXESR.js +24 -0
- package/dist/chunk-SHUYVCID.js +6 -0
- package/dist/chunk-SYEVGPFC.js +686 -0
- package/dist/chunk-V7HUZ6UQ.js +5923 -0
- package/dist/chunk-WPUVJRIN.js +29 -0
- package/dist/chunk-XCZ3TTFK.js +22 -0
- package/dist/chunk-XSGU2Y2O.js +1611 -0
- package/dist/chunk-YNEW3L63.js +190 -0
- package/dist/chunk-YXGHPILG.js +614 -0
- package/dist/chunk-ZL4LLE2Z.js +465 -0
- package/dist/di-CcNeq9v-.d.cts +16 -0
- package/dist/di-CcNeq9v-.d.ts +16 -0
- package/dist/discovery/index.cjs +588 -0
- package/dist/discovery/index.d.cts +299 -0
- package/dist/discovery/index.d.ts +299 -0
- package/dist/discovery/index.js +49 -0
- package/dist/discovery.scanner-CUYLKlYT.d.cts +59 -0
- package/dist/discovery.scanner-CUYLKlYT.d.ts +59 -0
- package/dist/entitlement/index.cjs +805 -0
- package/dist/entitlement/index.d.cts +60 -0
- package/dist/entitlement/index.d.ts +60 -0
- package/dist/entitlement/index.js +57 -0
- package/dist/index.cjs +15918 -0
- package/dist/index.d.cts +85 -0
- package/dist/index.d.ts +85 -0
- package/dist/index.js +956 -0
- package/dist/plan-resolution-CFCoUkrE.d.cts +41 -0
- package/dist/plan-resolution-CFCoUkrE.d.ts +41 -0
- package/dist/platform/index.cjs +2772 -0
- package/dist/platform/index.d.cts +118 -0
- package/dist/platform/index.d.ts +118 -0
- package/dist/platform/index.js +37 -0
- package/dist/promo/index.cjs +995 -0
- package/dist/promo/index.d.cts +121 -0
- package/dist/promo/index.d.ts +121 -0
- package/dist/promo/index.js +58 -0
- package/dist/registration/index.cjs +1687 -0
- package/dist/registration/index.d.cts +444 -0
- package/dist/registration/index.d.ts +444 -0
- package/dist/registration/index.js +82 -0
- package/dist/saas-platform.module-CgZ2omgg.d.cts +180 -0
- package/dist/saas-platform.module-DT9TnCzk.d.ts +180 -0
- package/dist/service-DX8KbGXl.d.cts +109 -0
- package/dist/service-DX8KbGXl.d.ts +109 -0
- package/dist/subscription-contract/index.cjs +471 -0
- package/dist/subscription-contract/index.d.cts +17 -0
- package/dist/subscription-contract/index.d.ts +17 -0
- package/dist/subscription-contract/index.js +21 -0
- package/dist/subscription-contract.service--cm47ZJJ.d.cts +39 -0
- package/dist/subscription-contract.service--cm47ZJJ.d.ts +39 -0
- package/dist/testing/index.cjs +3942 -0
- package/dist/testing/index.d.cts +279 -0
- package/dist/testing/index.d.ts +279 -0
- package/dist/testing/index.js +1195 -0
- package/package.json +185 -0
|
@@ -0,0 +1,1073 @@
|
|
|
1
|
+
import { BundleRepository, DiscoverySnapshot, SubscriptionRepository, PlanRepository, CatalogEntryRepository, BundleRow, BundleVersionRow, CreateBundleData, UpdateBundleData, CreateBundleVersionDraftData, BundleVersionMutationResult, UpdateBundleVersionDraftData, PublishBundleVersionData, BusinessTypeRepository, BusinessTypeRow, BusinessTypeVersionRow, CreateBusinessTypeData, UpdateBusinessTypeData, CreateBusinessTypeVersionDraftData, BusinessTypeVersionMutationResult, UpdateBusinessTypeVersionDraftData, PublishBusinessTypeVersionData, MarketingProjectionRepository, MarketingProjectionFilter, MarketingProjectionRow, CreateMarketingProjectionData, UpdateMarketingProjectionData, FeatureUiRegistry, CapabilityCatalogEntryRow, FeatureCatalogEntryRow, QuotaCatalogEntryRow, ReviewCatalogEntryData, CatalogEntryI18n, UpdateCatalogEntryBaseData, SyncDiscoveryResult, PromotionRepository, PromotionRow, CreatePromotionData, UpdatePromotionData, MarketingSettingsRepository, MarketingSettingsRow, UpdateMarketingSettingsData, PublicMarketingCatalogResponse, PlanRow, CreatePlanData, UpdatePlanData, PlanVersionRow, CreatePlanVersionDraftData, PlanVersionMutationResult, UpdatePlanVersionDraftData, PublishPlanVersionData, StrictModeWarningCode, StrictModeWarning, ApprovedCatalogKeys, DiscoveredQuota, DiscoveryStatus, PromotionType, PromotionValue, PromotionTargetType, PromotionBillingCycle, PromotionI18n } from '@saasicat/types';
|
|
2
|
+
import { c as DiscoveryScanner } from '../discovery.scanner-CUYLKlYT.js';
|
|
3
|
+
import { OnApplicationBootstrap, Type, CanActivate, DynamicModule, ForwardReference, Provider } from '@nestjs/common';
|
|
4
|
+
import { P as ProviderSpec } from '../di-CcNeq9v-.js';
|
|
5
|
+
import '@nestjs/core';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Configuration for the mutating operations.
|
|
9
|
+
*/
|
|
10
|
+
interface CatalogServiceConfig {
|
|
11
|
+
/** Active mode for the strict-mode check. Default `'blocking'` (#12). */
|
|
12
|
+
strictModeCheckMode?: 'warn-only' | 'blocking';
|
|
13
|
+
/**
|
|
14
|
+
* Discovery→Catalog auto-sync at boot (#12). Default `true` — runs when a
|
|
15
|
+
* `DiscoverySnapshot` is available. Set to `false` to disable the boot
|
|
16
|
+
* sync; the manual `POST /admin/catalog/discovery/sync` is unaffected.
|
|
17
|
+
*/
|
|
18
|
+
autoSyncDiscoveryAtBoot?: boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Feature keys the catalog is deliberately allowed to carry WITHOUT them
|
|
21
|
+
* existing in the discovery snapshot (= in code via @ImplementsCapability) —
|
|
22
|
+
* marketed non-code features such as support SLAs (e.g. PRIORITY_SUPPORT).
|
|
23
|
+
* The strict-mode check does NOT report them as BUNDLE_/PLAN_FEATURE_UNKNOWN.
|
|
24
|
+
* Use sparingly: this is the only legitimate exception to "code is the
|
|
25
|
+
* source of truth"; not-yet-built features do NOT belong here but should be
|
|
26
|
+
* removed from the catalog until they are implemented.
|
|
27
|
+
*/
|
|
28
|
+
marketedOnlyFeatures?: string[];
|
|
29
|
+
}
|
|
30
|
+
declare class BundlesService {
|
|
31
|
+
private readonly repo;
|
|
32
|
+
private readonly snapshot;
|
|
33
|
+
private readonly subscriptions;
|
|
34
|
+
private readonly planRepo;
|
|
35
|
+
private readonly scanner;
|
|
36
|
+
private readonly catalogEntries;
|
|
37
|
+
private readonly logger;
|
|
38
|
+
private mode;
|
|
39
|
+
private readonly marketedOnly;
|
|
40
|
+
constructor(repo: BundleRepository, snapshot?: DiscoverySnapshot | null, config?: CatalogServiceConfig, subscriptions?: SubscriptionRepository | null, planRepo?: PlanRepository | null, scanner?: DiscoveryScanner | null, catalogEntries?: CatalogEntryRepository | null);
|
|
41
|
+
listBundles(projectKey: string): Promise<BundleRow[]>;
|
|
42
|
+
getBundle(bundleId: string): Promise<{
|
|
43
|
+
bundle: BundleRow;
|
|
44
|
+
versions: BundleVersionRow[];
|
|
45
|
+
}>;
|
|
46
|
+
createBundle(data: CreateBundleData): Promise<BundleRow>;
|
|
47
|
+
updateBundle(bundleId: string, data: UpdateBundleData): Promise<BundleRow>;
|
|
48
|
+
softDeleteBundle(bundleId: string): Promise<void>;
|
|
49
|
+
/**
|
|
50
|
+
* Hard-deletes a draft BundleVersion (`publishedAt === null`) from the
|
|
51
|
+
* DB. Published versions stay immutable (contract-protection P1) — the
|
|
52
|
+
* service throws 422 with code `BUNDLE_VERSION_ALREADY_PUBLISHED`.
|
|
53
|
+
*/
|
|
54
|
+
discardBundleDraft(versionId: string): Promise<void>;
|
|
55
|
+
listBundleVersions(bundleId: string): Promise<BundleVersionRow[]>;
|
|
56
|
+
getBundleVersion(versionId: string): Promise<BundleVersionRow>;
|
|
57
|
+
/**
|
|
58
|
+
* Annotates each BundleVersion with `isLatestInChain` (highest version
|
|
59
|
+
* number in the chain) + `subscriptionCount` so that UI and backend make
|
|
60
|
+
* the same editability decision. `subscriptionCount` stays `undefined`
|
|
61
|
+
* when no SubscriptionRepository is registered or the method was not
|
|
62
|
+
* implemented — `isVersionEditable` interprets that fail-closed
|
|
63
|
+
* (= frozen).
|
|
64
|
+
*/
|
|
65
|
+
private annotateEditability;
|
|
66
|
+
/**
|
|
67
|
+
* Creates a new draft BundleVersion. Throws when a draft already exists
|
|
68
|
+
* for the same bundle (repository constraint).
|
|
69
|
+
*
|
|
70
|
+
* The strict-mode check runs on the input; in `warn-only` warnings are
|
|
71
|
+
* returned, in `blocking` the service throws HTTP 422.
|
|
72
|
+
*/
|
|
73
|
+
createBundleDraft(data: CreateBundleVersionDraftData): Promise<BundleVersionMutationResult>;
|
|
74
|
+
/**
|
|
75
|
+
* Updates a draft version or — as a deliberate relaxation of
|
|
76
|
+
* contract-protection P1 — a published-but-future BundleVersion that is
|
|
77
|
+
* latest-in-chain and does not yet bind any subscription. Once
|
|
78
|
+
* `validFrom` is reached or a booking references it, the version freezes
|
|
79
|
+
* again. The concrete decision is made by the `isVersionEditable` helper,
|
|
80
|
+
* which is mirrored by the UI.
|
|
81
|
+
*/
|
|
82
|
+
updateBundleDraft(versionId: string, data: UpdateBundleVersionDraftData): Promise<BundleVersionMutationResult>;
|
|
83
|
+
/**
|
|
84
|
+
* Publishes a draft version atomically. Steps:
|
|
85
|
+
* 1. Strict check on the draft definition (warn-only or blocking)
|
|
86
|
+
* 2. Enforce validFrom requirement + ordering against the predecessor
|
|
87
|
+
* (SPEC_V2 §4.2 + §11.1 M6 Pack 2c, analogous to PlanVersion)
|
|
88
|
+
* 3. Compute the diff against the predecessor version (latest live) →
|
|
89
|
+
* `publishedChanges` + `nonRegressive` via `classifyBundleVersionDiff`
|
|
90
|
+
* 4. Call Repository.publishDraft with the diff result + validity dates
|
|
91
|
+
* (transaction; auto-succession sets the previous validUntil)
|
|
92
|
+
*/
|
|
93
|
+
publishBundleVersion(versionId: string, publishMeta: PublishBundleVersionData): Promise<BundleVersionMutationResult>;
|
|
94
|
+
private runStrictCheck;
|
|
95
|
+
private gateOrPass;
|
|
96
|
+
private assertBundleVersionWindowUpdate;
|
|
97
|
+
private findPreviousBundleVersion;
|
|
98
|
+
private parseOptionalBundleDate;
|
|
99
|
+
private parseRequiredBundleDate;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
declare class BusinessTypesService {
|
|
103
|
+
private readonly repo;
|
|
104
|
+
private readonly bundleRepo;
|
|
105
|
+
private readonly snapshot;
|
|
106
|
+
private readonly scanner;
|
|
107
|
+
private readonly catalogEntries;
|
|
108
|
+
private readonly mode;
|
|
109
|
+
constructor(repo: BusinessTypeRepository, bundleRepo: BundleRepository, snapshot?: DiscoverySnapshot | null, config?: CatalogServiceConfig, scanner?: DiscoveryScanner | null, catalogEntries?: CatalogEntryRepository | null);
|
|
110
|
+
listBusinessTypes(projectKey: string): Promise<BusinessTypeRow[]>;
|
|
111
|
+
getBusinessType(businessTypeId: string): Promise<{
|
|
112
|
+
businessType: BusinessTypeRow;
|
|
113
|
+
versions: BusinessTypeVersionRow[];
|
|
114
|
+
}>;
|
|
115
|
+
createBusinessType(data: CreateBusinessTypeData): Promise<BusinessTypeRow>;
|
|
116
|
+
updateBusinessType(businessTypeId: string, data: UpdateBusinessTypeData): Promise<BusinessTypeRow>;
|
|
117
|
+
softDeleteBusinessType(businessTypeId: string): Promise<void>;
|
|
118
|
+
listBusinessTypeVersions(businessTypeId: string): Promise<BusinessTypeVersionRow[]>;
|
|
119
|
+
getBusinessTypeVersion(versionId: string): Promise<BusinessTypeVersionRow>;
|
|
120
|
+
createBusinessTypeDraft(data: CreateBusinessTypeVersionDraftData): Promise<BusinessTypeVersionMutationResult>;
|
|
121
|
+
updateBusinessTypeDraft(versionId: string, data: UpdateBusinessTypeVersionDraftData): Promise<BusinessTypeVersionMutationResult>;
|
|
122
|
+
publishBusinessTypeVersion(versionId: string, publishMeta: PublishBusinessTypeVersionData): Promise<BusinessTypeVersionMutationResult>;
|
|
123
|
+
/**
|
|
124
|
+
* Loads the referenced BundleVersions and verifies that all exist
|
|
125
|
+
* and are published (live or superseded — both allowed, because
|
|
126
|
+
* BusinessTypeBundle holds the concrete version). Throws NotFound for
|
|
127
|
+
* missing ones, UnprocessableEntity for non-published ones.
|
|
128
|
+
*/
|
|
129
|
+
private loadAndAssertBundles;
|
|
130
|
+
private runStrictCheck;
|
|
131
|
+
private gateOrPass;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
declare class MarketingProjectionsService {
|
|
135
|
+
private readonly repo;
|
|
136
|
+
constructor(repo: MarketingProjectionRepository);
|
|
137
|
+
list(filter: MarketingProjectionFilter): Promise<MarketingProjectionRow[]>;
|
|
138
|
+
getById(id: string): Promise<MarketingProjectionRow>;
|
|
139
|
+
create(data: CreateMarketingProjectionData): Promise<MarketingProjectionRow>;
|
|
140
|
+
update(id: string, data: UpdateMarketingProjectionData): Promise<MarketingProjectionRow>;
|
|
141
|
+
delete(id: string): Promise<void>;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
declare class CatalogEntriesService implements OnApplicationBootstrap {
|
|
145
|
+
private readonly repo;
|
|
146
|
+
private readonly snapshot;
|
|
147
|
+
private readonly scanner;
|
|
148
|
+
private readonly featureUiRegistry;
|
|
149
|
+
private readonly logger;
|
|
150
|
+
private readonly autoSyncAtBoot;
|
|
151
|
+
constructor(repo: CatalogEntryRepository, snapshot?: DiscoverySnapshot | null, config?: CatalogServiceConfig, scanner?: DiscoveryScanner | null, featureUiRegistry?: FeatureUiRegistry | null);
|
|
152
|
+
/**
|
|
153
|
+
* Mirrors the discovery snapshot into the catalog entries at boot
|
|
154
|
+
* (discovery-as-SSOT, #12). Runs only when a snapshot is available and
|
|
155
|
+
* the kill switch `autoSyncDiscoveryAtBoot` is not set to `false`. A
|
|
156
|
+
* sync error deliberately does not abort the boot — the manual endpoint
|
|
157
|
+
* `POST /admin/catalog/discovery/sync` remains as a fallback.
|
|
158
|
+
*/
|
|
159
|
+
onApplicationBootstrap(): Promise<void>;
|
|
160
|
+
listCapabilities(projectKey: string, codeStatus?: string): Promise<CapabilityCatalogEntryRow[]>;
|
|
161
|
+
listFeatures(projectKey: string, discoveryStatus?: string): Promise<FeatureCatalogEntryRow[]>;
|
|
162
|
+
listQuotas(projectKey: string, discoveryStatus?: string): Promise<QuotaCatalogEntryRow[]>;
|
|
163
|
+
/**
|
|
164
|
+
* Approval transition of a feature (#20). Validates the state machine;
|
|
165
|
+
* `approved` persists the approval signature from the current
|
|
166
|
+
* snapshot, `pending` (revoke/reactivate) deletes it, `outdated`/
|
|
167
|
+
* `obsolete` keep the last approval as history.
|
|
168
|
+
*/
|
|
169
|
+
reviewFeature(projectKey: string, featureKey: string, data: ReviewCatalogEntryData, reviewedBy: string | null): Promise<FeatureCatalogEntryRow>;
|
|
170
|
+
/** Approval transition of a quota — same state machine as features (#20). */
|
|
171
|
+
reviewQuota(projectKey: string, quotaKey: string, data: ReviewCatalogEntryData, reviewedBy: string | null): Promise<QuotaCatalogEntryRow>;
|
|
172
|
+
private resolveReviewUpdate;
|
|
173
|
+
setFeatureI18n(projectKey: string, featureKey: string, i18n: CatalogEntryI18n): Promise<FeatureCatalogEntryRow>;
|
|
174
|
+
setQuotaI18n(projectKey: string, quotaKey: string, i18n: CatalogEntryI18n): Promise<QuotaCatalogEntryRow>;
|
|
175
|
+
/** Sets the editable default-locale label/description of a feature. */
|
|
176
|
+
setFeatureBase(projectKey: string, featureKey: string, data: UpdateCatalogEntryBaseData): Promise<FeatureCatalogEntryRow>;
|
|
177
|
+
/** Sets the editable default-locale label/description of a quota. */
|
|
178
|
+
setQuotaBase(projectKey: string, quotaKey: string, data: UpdateCatalogEntryBaseData): Promise<QuotaCatalogEntryRow>;
|
|
179
|
+
/**
|
|
180
|
+
* Synchronizes the catalog entries from a discovery snapshot.
|
|
181
|
+
* Idempotent — can run against the same snapshot any number of times.
|
|
182
|
+
*/
|
|
183
|
+
syncFromSnapshot(snapshot: DiscoverySnapshot): Promise<SyncDiscoveryResult>;
|
|
184
|
+
/**
|
|
185
|
+
* `replaced` semantics (#39): if a key disappears from the snapshot AND
|
|
186
|
+
* another snapshot key claims it via `replaces`, the old entry gets
|
|
187
|
+
* the successor pointer — `obsolete` (from `retireMissing`)
|
|
188
|
+
* + `successorKey` instead of a bare `obsolete`. If a key reappears in
|
|
189
|
+
* the code, an existing pointer is deleted. A missing key
|
|
190
|
+
* without a claimant remains untouched (deleted without replacement).
|
|
191
|
+
*/
|
|
192
|
+
private applySuccessorPointers;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
declare function buildCatalogEntriesController(guards: Array<Type<CanActivate>>): Type;
|
|
196
|
+
|
|
197
|
+
declare class PromotionsService {
|
|
198
|
+
private readonly repo;
|
|
199
|
+
constructor(repo: PromotionRepository);
|
|
200
|
+
list(projectKey: string): Promise<PromotionRow[]>;
|
|
201
|
+
getById(id: string): Promise<PromotionRow>;
|
|
202
|
+
create(data: CreatePromotionData): Promise<PromotionRow>;
|
|
203
|
+
update(id: string, data: UpdatePromotionData): Promise<PromotionRow>;
|
|
204
|
+
delete(id: string): Promise<void>;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
declare function buildPromotionsController(guards: Array<Type<CanActivate>>): Type;
|
|
208
|
+
|
|
209
|
+
declare class MarketingSettingsService {
|
|
210
|
+
private readonly repo;
|
|
211
|
+
constructor(repo: MarketingSettingsRepository);
|
|
212
|
+
/** Returns the stored config or `null` (in which case the full pool applies). */
|
|
213
|
+
get(projectKey: string): Promise<MarketingSettingsRow | null>;
|
|
214
|
+
upsert(projectKey: string, data: UpdateMarketingSettingsData): Promise<MarketingSettingsRow>;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
declare function buildMarketingSettingsController(guards: Array<Type<CanActivate>>): Type;
|
|
218
|
+
|
|
219
|
+
declare class PublicMarketingCatalogService {
|
|
220
|
+
private readonly planRepo;
|
|
221
|
+
private readonly marketingRepo;
|
|
222
|
+
private readonly promotionRepo;
|
|
223
|
+
private readonly catalogEntryRepo;
|
|
224
|
+
private readonly bundleRepo;
|
|
225
|
+
constructor(planRepo: PlanRepository, marketingRepo: MarketingProjectionRepository, promotionRepo: PromotionRepository, catalogEntryRepo?: CatalogEntryRepository | null, bundleRepo?: BundleRepository | null);
|
|
226
|
+
getCatalog(projectKey: string, locale: string, currency: string, vatRate: number, asOf?: Date): Promise<PublicMarketingCatalogResponse>;
|
|
227
|
+
/**
|
|
228
|
+
* Loads all published-and-live bundle versions for a project and
|
|
229
|
+
* filters on `marketed === true`. Without a registered
|
|
230
|
+
* `BundleRepository` (apps without the SuperAdmin bundle editor) the
|
|
231
|
+
* list is empty — the public catalog stays plan-only.
|
|
232
|
+
*/
|
|
233
|
+
private loadMarketedBundles;
|
|
234
|
+
/**
|
|
235
|
+
* Maps BundleVersionRow → PublicMarketingBundle. Locale resolution
|
|
236
|
+
* runs via `MarketingProjectionRepository.findByTarget('BUNDLE',
|
|
237
|
+
* bundleVersionId, locale)` — on a miss it falls back to
|
|
238
|
+
* `DEFAULT_LOCALE`. If the fallback is missing too, label/description
|
|
239
|
+
* come directly from the bundle root (denormalized in `BundleVersionRow`).
|
|
240
|
+
*
|
|
241
|
+
* If the marketing projection is `visible === false`, the bundle is
|
|
242
|
+
* hidden from the public response (preparation phase).
|
|
243
|
+
*/
|
|
244
|
+
private toPublicBundle;
|
|
245
|
+
/**
|
|
246
|
+
* Labels for bundle features ∪ their requires (#48): `comparison.features`
|
|
247
|
+
* only covers the plan-feature union — bundle-only features would
|
|
248
|
+
* otherwise get no label in the public payload. Curated keys only;
|
|
249
|
+
* without a CatalogEntryRepository the map stays empty (frontends fall
|
|
250
|
+
* back to the key).
|
|
251
|
+
*/
|
|
252
|
+
private resolveBundleFeatureLabels;
|
|
253
|
+
/** Loads the translated feature/quota labels (+ sortOrder) for a locale. */
|
|
254
|
+
private loadLabelMeta;
|
|
255
|
+
/**
|
|
256
|
+
* Resolves the displayed label of a top feature: the `label` override
|
|
257
|
+
* wins; otherwise the translated label of the referenced `key`.
|
|
258
|
+
*/
|
|
259
|
+
private resolveTopFeature;
|
|
260
|
+
/** Row definitions of the comparison matrix (feature/quota union + labels). */
|
|
261
|
+
private buildComparison;
|
|
262
|
+
private resolvePromo;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
declare function buildPublicMarketingCatalogController(guards: Array<Type<CanActivate>>, projectKey: string, currency: string, vatRate: number): Type;
|
|
266
|
+
|
|
267
|
+
declare class PlansService {
|
|
268
|
+
private readonly repo;
|
|
269
|
+
private readonly subscriptions;
|
|
270
|
+
constructor(repo: PlanRepository, subscriptions?: SubscriptionRepository | null);
|
|
271
|
+
/**
|
|
272
|
+
* Platform-wide count of active (ACTIVE/TRIAL) subscriptions per `planKey`,
|
|
273
|
+
* across versions and across all tenants (RLS-exempt). Plans without a
|
|
274
|
+
* subscription are absent from the map. Returns `{}` when no
|
|
275
|
+
* `SubscriptionRepository` is registered or it does not implement
|
|
276
|
+
* `countActiveByPlanKey`.
|
|
277
|
+
*/
|
|
278
|
+
getTenantCounts(projectKey: string): Promise<Record<string, number>>;
|
|
279
|
+
listPlans(projectKey: string, opts?: {
|
|
280
|
+
onlyPublished?: boolean;
|
|
281
|
+
}): Promise<PlanRow[]>;
|
|
282
|
+
getPlan(planId: string): Promise<PlanRow>;
|
|
283
|
+
createPlan(data: CreatePlanData): Promise<PlanRow>;
|
|
284
|
+
updatePlan(planId: string, data: UpdatePlanData): Promise<PlanRow>;
|
|
285
|
+
softDeletePlan(planId: string): Promise<void>;
|
|
286
|
+
/**
|
|
287
|
+
* Hard-deletes the plan master record. Only allowed for plans without
|
|
288
|
+
* `PlanVersion` entries — published versions are immutable under
|
|
289
|
+
* contract protection P1 (existing subscriptions reference them). The
|
|
290
|
+
* caller must discard drafts beforehand via `DELETE plan-versions/:id`.
|
|
291
|
+
*
|
|
292
|
+
* If the repository does not implement `hardDelete`, the endpoint
|
|
293
|
+
* responds with 422 `PLAN_HARD_DELETE_NOT_IMPLEMENTED` — consumers can
|
|
294
|
+
* then fall back to `softDelete`.
|
|
295
|
+
*/
|
|
296
|
+
hardDeletePlan(planId: string): Promise<void>;
|
|
297
|
+
/**
|
|
298
|
+
* Platform invariant (contract protection P1): once a plan has ever had a
|
|
299
|
+
* published version, its plan master record is retained — regardless of
|
|
300
|
+
* whether the version has since been superseded. Subscriptions still
|
|
301
|
+
* reference it via the version, and the audit log must be able to resolve
|
|
302
|
+
* the plan.
|
|
303
|
+
*/
|
|
304
|
+
private assertNoPublishedVersions;
|
|
305
|
+
private assertNoDrafts;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
declare class PlanVersionsService {
|
|
309
|
+
private readonly repo;
|
|
310
|
+
private readonly snapshot;
|
|
311
|
+
private readonly subscriptions;
|
|
312
|
+
private readonly scanner;
|
|
313
|
+
private readonly catalogEntries;
|
|
314
|
+
private readonly logger;
|
|
315
|
+
private mode;
|
|
316
|
+
private readonly marketedOnly;
|
|
317
|
+
constructor(repo: PlanRepository, snapshot?: DiscoverySnapshot | null, config?: CatalogServiceConfig, subscriptions?: SubscriptionRepository | null, scanner?: DiscoveryScanner | null, catalogEntries?: CatalogEntryRepository | null);
|
|
318
|
+
/**
|
|
319
|
+
* Discards a draft version. Allowed only while the version has not yet
|
|
320
|
+
* been published — published versions are preserved immutably,
|
|
321
|
+
* because existing subscriptions reference them (contract protection P1).
|
|
322
|
+
*
|
|
323
|
+
* If the repository does not implement the method, the endpoint
|
|
324
|
+
* responds with 501 Not Implemented (consumers without the editor stack
|
|
325
|
+
* should not register `PlanVersionsService` anyway).
|
|
326
|
+
*/
|
|
327
|
+
discardPlanDraft(versionId: string): Promise<void>;
|
|
328
|
+
/**
|
|
329
|
+
* @param planUuid UUID of the plan root (Plan.id) — resolved to planKey
|
|
330
|
+
* before the repo call (lifecycle methods work with planKey because
|
|
331
|
+
* PlanVersion.planId is a string in the schema).
|
|
332
|
+
*/
|
|
333
|
+
listPlanVersions(planUuid: string): Promise<PlanVersionRow[]>;
|
|
334
|
+
getPlanVersion(versionId: string): Promise<PlanVersionRow>;
|
|
335
|
+
/**
|
|
336
|
+
* Annotates each version with `isLatestInChain` (highest version number
|
|
337
|
+
* in the root) + `subscriptionCount` so that UI and backend make the same
|
|
338
|
+
* editability decision. `subscriptionCount` stays
|
|
339
|
+
* `undefined` when no SubscriptionRepository is registered —
|
|
340
|
+
* `isVersionEditable` interprets that fail-closed (= frozen).
|
|
341
|
+
*/
|
|
342
|
+
private annotateEditability;
|
|
343
|
+
/**
|
|
344
|
+
* @param data.planId — the plan UUID from the controller. Resolved to
|
|
345
|
+
* planKey before the repo call.
|
|
346
|
+
*/
|
|
347
|
+
createPlanDraft(data: CreatePlanVersionDraftData): Promise<PlanVersionMutationResult>;
|
|
348
|
+
updatePlanDraft(versionId: string, data: UpdatePlanVersionDraftData): Promise<PlanVersionMutationResult>;
|
|
349
|
+
publishPlanVersion(versionId: string, publishMeta: PublishPlanVersionData): Promise<PlanVersionMutationResult>;
|
|
350
|
+
/**
|
|
351
|
+
* Terminates a **live** PlanVersion by setting `endsAt`.
|
|
352
|
+
* Unlike auto-succession (validUntil), this is an explicit
|
|
353
|
+
* user action: the version is not replaced by a successor version
|
|
354
|
+
* but expires on the chosen date. Existing subscriptions
|
|
355
|
+
* (P1) stay bound — this only affects new bookings.
|
|
356
|
+
*
|
|
357
|
+
* Idempotent — a second call with a different date overwrites.
|
|
358
|
+
*
|
|
359
|
+
* Preconditions:
|
|
360
|
+
* - Version must be live (`publishedAt != null && supersededAt == null`).
|
|
361
|
+
* - `endsAt` must lie in the future (`endsAt > now`).
|
|
362
|
+
*
|
|
363
|
+
* If the repository does not implement the method, the endpoint
|
|
364
|
+
* responds with 422 `PLAN_TERMINATE_NOT_IMPLEMENTED`.
|
|
365
|
+
*/
|
|
366
|
+
terminatePlanVersion(versionId: string, endsAt: Date): Promise<PlanVersionRow>;
|
|
367
|
+
private runStrictCheck;
|
|
368
|
+
private gateOrPass;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
/**
|
|
372
|
+
* Builds the controller class at boot time with the guards configured by the
|
|
373
|
+
* consumer. Pattern analogous to `buildDiscoveryController`.
|
|
374
|
+
*/
|
|
375
|
+
declare function buildBundlesController(guards: Array<Type<CanActivate>>): Type;
|
|
376
|
+
/**
|
|
377
|
+
* Second controller with the version-specific endpoints. Deliberately
|
|
378
|
+
* separate, because they do not go through `bundles/:id/versions/:vid` but
|
|
379
|
+
* through stable version IDs (`/admin/catalog/bundle-versions/:id`) — this
|
|
380
|
+
* way the UI can work with a version-ID reference without a bundle lookup.
|
|
381
|
+
*/
|
|
382
|
+
declare function buildBundleVersionsController(guards: Array<Type<CanActivate>>): Type;
|
|
383
|
+
|
|
384
|
+
declare function buildBusinessTypesController(guards: Array<Type<CanActivate>>): Type;
|
|
385
|
+
declare function buildBusinessTypeVersionsController(guards: Array<Type<CanActivate>>): Type;
|
|
386
|
+
|
|
387
|
+
declare function buildMarketingProjectionsController(guards: Array<Type<CanActivate>>): Type;
|
|
388
|
+
|
|
389
|
+
declare function buildPlansController(guards: Array<Type<CanActivate>>): Type;
|
|
390
|
+
/**
|
|
391
|
+
* Version-specific endpoints. Stable by version ID — the UI does not need
|
|
392
|
+
* to know the plan master.
|
|
393
|
+
*/
|
|
394
|
+
declare function buildPlanVersionsController(guards: Array<Type<CanActivate>>): Type;
|
|
395
|
+
|
|
396
|
+
interface CatalogControllerConfig {
|
|
397
|
+
/**
|
|
398
|
+
* Class-level guards for `BundlesController` and `BundleVersionsController`.
|
|
399
|
+
* REQUIRED — otherwise `forRoot()` throws at boot. Pass `[]` explicitly
|
|
400
|
+
* if the endpoints should intentionally be auth-free.
|
|
401
|
+
*/
|
|
402
|
+
guards: Array<Type<CanActivate>>;
|
|
403
|
+
}
|
|
404
|
+
interface CatalogModuleOptions {
|
|
405
|
+
/** Adapter for `bundles` + `bundle_versions` persistence. */
|
|
406
|
+
bundleRepository: ProviderSpec<BundleRepository>;
|
|
407
|
+
/**
|
|
408
|
+
* Adapter for `business_types` + `business_type_versions` +
|
|
409
|
+
* `business_type_bundles` persistence. Optional — if omitted,
|
|
410
|
+
* BusinessTypesService + controller are not registered.
|
|
411
|
+
*/
|
|
412
|
+
businessTypeRepository?: ProviderSpec<BusinessTypeRepository>;
|
|
413
|
+
/**
|
|
414
|
+
* Adapter for `marketing_projections` persistence. Optional — if
|
|
415
|
+
* omitted, MarketingProjectionsService + controller are not
|
|
416
|
+
* registered.
|
|
417
|
+
*/
|
|
418
|
+
marketingProjectionRepository?: ProviderSpec<MarketingProjectionRepository>;
|
|
419
|
+
/**
|
|
420
|
+
* Adapter for `capability_/feature_/quota_catalog_entries` persistence
|
|
421
|
+
* (discovery review, SPEC_V2 §6.3). Optional — if omitted,
|
|
422
|
+
* CatalogEntriesService + controller are not registered.
|
|
423
|
+
*/
|
|
424
|
+
catalogEntryRepository?: ProviderSpec<CatalogEntryRepository>;
|
|
425
|
+
/**
|
|
426
|
+
* Adapter for `promotions` persistence (SPEC_V2 §9a). Optional — if
|
|
427
|
+
* omitted, PromotionsService + controller are not registered.
|
|
428
|
+
*/
|
|
429
|
+
promotionRepository?: ProviderSpec<PromotionRepository>;
|
|
430
|
+
/**
|
|
431
|
+
* Adapter for `marketing_settings` persistence (SPEC_V2 §6.5 —
|
|
432
|
+
* `activeLocales`). Optional.
|
|
433
|
+
*/
|
|
434
|
+
marketingSettingsRepository?: ProviderSpec<MarketingSettingsRepository>;
|
|
435
|
+
/**
|
|
436
|
+
* Auth-free pricing-page endpoint `GET /public/marketing-catalog`
|
|
437
|
+
* (SPEC_V2 §9). Registered only when plan-, marketingProjection-
|
|
438
|
+
* and promotionRepository are set. `guards` is usually `[]`.
|
|
439
|
+
*/
|
|
440
|
+
publicMarketingCatalog?: {
|
|
441
|
+
guards: Array<Type<CanActivate>>;
|
|
442
|
+
projectKey: string;
|
|
443
|
+
currency: string;
|
|
444
|
+
vatRate: number;
|
|
445
|
+
};
|
|
446
|
+
/**
|
|
447
|
+
* SPEC_V2 §11.1 M6 (Pack 1) — adapter for `plans` master-record persistence.
|
|
448
|
+
* Optional; if omitted, PlansService + controller are not
|
|
449
|
+
* registered (apps without a need for the plan editor stay unchanged).
|
|
450
|
+
*/
|
|
451
|
+
planRepository?: ProviderSpec<PlanRepository>;
|
|
452
|
+
/**
|
|
453
|
+
* Controller mount for `/admin/catalog/bundles` + `/admin/catalog/bundle-versions`
|
|
454
|
+
* + (if businessTypeRepository is set) `/admin/catalog/business-types` +
|
|
455
|
+
* `/admin/catalog/business-type-versions`. If omitted, the
|
|
456
|
+
* endpoints are not registered — but the services remain usable via DI.
|
|
457
|
+
*/
|
|
458
|
+
controller?: CatalogControllerConfig;
|
|
459
|
+
/**
|
|
460
|
+
* Strict-mode mode. `blocking` (default, #12) throws HTTP 422 on
|
|
461
|
+
* violations and requires a DiscoverySnapshot; `warn-only` returns them
|
|
462
|
+
* only as a warning (transition until 100% discovery coverage).
|
|
463
|
+
*/
|
|
464
|
+
strictModeCheckMode?: 'warn-only' | 'blocking';
|
|
465
|
+
/**
|
|
466
|
+
* Discovery→catalog auto-sync at boot (#12). Default `true` — as soon as a
|
|
467
|
+
* `catalogEntryRepository` is wired and a DiscoverySnapshot is available,
|
|
468
|
+
* `CatalogEntriesService` mirrors the discovery into the DB at startup. `false`
|
|
469
|
+
* disables the boot sync; the manual sync endpoint remains usable.
|
|
470
|
+
*/
|
|
471
|
+
autoSyncDiscoveryAtBoot?: boolean;
|
|
472
|
+
/**
|
|
473
|
+
* Feature keys the catalog is deliberately allowed to carry without them
|
|
474
|
+
* existing in the discovery snapshot (marketed non-code features such as
|
|
475
|
+
* support SLAs, e.g. `['PRIORITY_SUPPORT']`). The strict-mode check excludes
|
|
476
|
+
* them from BUNDLE_/PLAN_FEATURE_UNKNOWN. Use sparingly.
|
|
477
|
+
*/
|
|
478
|
+
marketedOnlyFeatures?: string[];
|
|
479
|
+
/**
|
|
480
|
+
* Optional consumer-curated FeatureUiRegistry (label/description/icon
|
|
481
|
+
* per feature — the same one passed to `PublicCatalogModule.forRoot`). The
|
|
482
|
+
* discovery auto-sync seeds EMPTY `FeatureCatalogEntry` fields
|
|
483
|
+
* (label/description/icon) from it at boot; SuperAdmin edits stay untouched. This
|
|
484
|
+
* makes `FeatureCatalogEntry` the SSOT for UI metadata (SPEC_V2 §6.3 / #12).
|
|
485
|
+
*/
|
|
486
|
+
featureUiRegistry?: FeatureUiRegistry;
|
|
487
|
+
/**
|
|
488
|
+
* Modules whose providers must be visible in the DI scope of this
|
|
489
|
+
* DynamicModule — typically: `AuthModule`/`PlatformAdminModule`, because the
|
|
490
|
+
* controller guards come from there.
|
|
491
|
+
*/
|
|
492
|
+
imports?: Array<Type<unknown> | DynamicModule | Promise<DynamicModule> | ForwardReference>;
|
|
493
|
+
/** Additional providers registered in the DynamicModule itself. */
|
|
494
|
+
extraProviders?: Provider[];
|
|
495
|
+
/** Register the module globally — default `false`. */
|
|
496
|
+
global?: boolean;
|
|
497
|
+
}
|
|
498
|
+
declare class CatalogModule {
|
|
499
|
+
static forRoot(options: CatalogModuleOptions): DynamicModule;
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
/** Repository for `plans` (SPEC_V2 §11.1 M6 — Plan master CRUD). */
|
|
503
|
+
declare const PLAN_REPOSITORY_TOKEN: unique symbol;
|
|
504
|
+
/** Repository for `bundles` + `bundle_versions`. */
|
|
505
|
+
declare const BUNDLE_REPOSITORY_TOKEN: unique symbol;
|
|
506
|
+
/** Repository for `business_types` + `business_type_versions` + `business_type_bundles`. */
|
|
507
|
+
declare const BUSINESS_TYPE_REPOSITORY_TOKEN: unique symbol;
|
|
508
|
+
/** Repository for `marketing_projections`. */
|
|
509
|
+
declare const MARKETING_PROJECTION_REPOSITORY_TOKEN: unique symbol;
|
|
510
|
+
/**
|
|
511
|
+
* Repository for `capability_catalog_entries`, `feature_catalog_entries`
|
|
512
|
+
* and `quota_catalog_entries` (Discovery review, SPEC_V2 §6.3).
|
|
513
|
+
*/
|
|
514
|
+
declare const CATALOG_ENTRY_REPOSITORY_TOKEN: unique symbol;
|
|
515
|
+
/** Repository for `promotions` (time-scheduled price campaigns, SPEC_V2 §9a). */
|
|
516
|
+
declare const PROMOTION_REPOSITORY_TOKEN: unique symbol;
|
|
517
|
+
/** Repository for `marketing_settings` (activeLocales, SPEC_V2 §6.5). */
|
|
518
|
+
declare const MARKETING_SETTINGS_REPOSITORY_TOKEN: unique symbol;
|
|
519
|
+
/**
|
|
520
|
+
* Service configuration: current app identity, strict mode.
|
|
521
|
+
* Provided by CatalogModule.forRoot().
|
|
522
|
+
*/
|
|
523
|
+
declare const CATALOG_SERVICE_CONFIG_TOKEN: unique symbol;
|
|
524
|
+
|
|
525
|
+
/**
|
|
526
|
+
* Advisory warnings (#35): they inform but never block — not even in
|
|
527
|
+
* `strictModeCheckMode: 'blocking'`, Seed-Gate, or Preflight. Reason: a
|
|
528
|
+
* `requires` feature may be satisfied outside the checked draft
|
|
529
|
+
* (e.g. the Plan covers a Bundle's dependency), which the draft check
|
|
530
|
+
* cannot know without booking context.
|
|
531
|
+
*/
|
|
532
|
+
declare const ADVISORY_STRICT_MODE_CODES: ReadonlySet<StrictModeWarningCode>;
|
|
533
|
+
/** Returns only the warnings that are allowed to gate in blocking paths. */
|
|
534
|
+
declare function blockingStrictModeWarnings(warnings: StrictModeWarning[]): StrictModeWarning[];
|
|
535
|
+
/**
|
|
536
|
+
* Validates a Bundle draft definition against the current discovery snapshot.
|
|
537
|
+
* Returns a (possibly empty) list of warnings.
|
|
538
|
+
*
|
|
539
|
+
* Checked:
|
|
540
|
+
* - **Feature existence** (`BUNDLE_FEATURE_UNKNOWN`): every `features[i]`
|
|
541
|
+
* must exist as a `DiscoveredFeature` in the snapshot. Code is the
|
|
542
|
+
* source of truth for features (via @ImplementsCapability). Keys in
|
|
543
|
+
* `marketedOnlyFeatures` are deliberately exempt — marketed
|
|
544
|
+
* non-code features (e.g. support SLAs) that never have a Capability.
|
|
545
|
+
* - **Quota existence** (`QUOTA_MISSING`): every `quotas` key must exist
|
|
546
|
+
* as a `DiscoveredQuota` in the snapshot (provided the app uses quotas
|
|
547
|
+
* at all — empty quotas are allowed).
|
|
548
|
+
* - **Plan key existence** (`BUNDLE_PLAN_KEY_UNKNOWN`, optional via
|
|
549
|
+
* `knownPlanKeys`): every `compatibility.planIds[i]` must be an
|
|
550
|
+
* existing PlanKey in the current Project. Called by the
|
|
551
|
+
* BundlesService once the plan list is available;
|
|
552
|
+
* `knownPlanKeys = null` skips the check (e.g. when the PlanRepository
|
|
553
|
+
* is not registered).
|
|
554
|
+
* - **Approved gate** (`BUNDLE_FEATURE_NOT_APPROVED`/`QUOTA_NOT_APPROVED`,
|
|
555
|
+
* optional via `approved`, #20 Slice 5): only approved features/quotas
|
|
556
|
+
* (`discoveryStatus = 'approved'`) are sellable. `approved = null`
|
|
557
|
+
* skips the approval part; marketed-only features are exempt.
|
|
558
|
+
* - **Feature dependencies** (`BUNDLE_FEATURE_DEPENDENCY_UNSATISFIED`, #35,
|
|
559
|
+
* advisory): `requires` features that are not in the Bundle itself.
|
|
560
|
+
*
|
|
561
|
+
* **Not** checked (belongs in other validations):
|
|
562
|
+
* - Pricing (purely business, no discovery relation)
|
|
563
|
+
* - Compatibility.businessTypeKeys whitelists (BUNDLE_COMPATIBILITY code,
|
|
564
|
+
* only checked at BusinessType publish)
|
|
565
|
+
* - Disjointness (BUNDLE_DISJOINTNESS, also a BusinessType concern)
|
|
566
|
+
*/
|
|
567
|
+
declare function validateBundleDraft(draft: {
|
|
568
|
+
features: string[];
|
|
569
|
+
quotas: Record<string, number>;
|
|
570
|
+
compatibility?: {
|
|
571
|
+
planIds?: string[];
|
|
572
|
+
businessTypeKeys?: string[];
|
|
573
|
+
};
|
|
574
|
+
}, snapshot: DiscoverySnapshot, knownPlanKeys?: Set<string> | null, marketedOnlyFeatures?: ReadonlySet<string>, approved?: ApprovedCatalogKeys | null): StrictModeWarning[];
|
|
575
|
+
/**
|
|
576
|
+
* Validates a BusinessType draft definition against the discovery snapshot
|
|
577
|
+
* and the referenced BundleVersions. Three violations:
|
|
578
|
+
*
|
|
579
|
+
* - **BUNDLE_DISJOINTNESS** (GESCHAEFTSTYP_SPEC §6.3): two Bundles in
|
|
580
|
+
* the composition activate the same feature. Hard block at publish.
|
|
581
|
+
* - **BUNDLE_COMPATIBILITY** (GESCHAEFTSTYP_SPEC §6.4): a Bundle has set
|
|
582
|
+
* a `compatibility.businessTypeKeys` whitelist, but the target
|
|
583
|
+
* businessTypeKey is not included. Soft warning (no
|
|
584
|
+
* hard block, but an audit marker on override).
|
|
585
|
+
* - **QUOTA_MISSING**: QuotaOverride keys that do not exist in discovery
|
|
586
|
+
* (analogous to the Bundle strict check).
|
|
587
|
+
*
|
|
588
|
+
* Bundle existence and published status are checked in the service before
|
|
589
|
+
* this check (NotFoundException on a missing version, no warning).
|
|
590
|
+
*/
|
|
591
|
+
declare function validateBusinessTypeDraft(draft: {
|
|
592
|
+
businessTypeKey: string;
|
|
593
|
+
quotaOverrides: Record<string, number>;
|
|
594
|
+
}, bundles: BundleVersionRow[], snapshot: DiscoverySnapshot, approved?: ApprovedCatalogKeys | null): StrictModeWarning[];
|
|
595
|
+
/**
|
|
596
|
+
* Validates a PlanVersion draft definition against the discovery snapshot
|
|
597
|
+
* (SPEC_V2 §8.2 Pack 3a). Returns a (possibly empty) list of
|
|
598
|
+
* warnings.
|
|
599
|
+
*
|
|
600
|
+
* Checked:
|
|
601
|
+
* - **Feature existence** (`PLAN_FEATURE_UNKNOWN`): every `features[i]`
|
|
602
|
+
* must exist as a `DiscoveredFeature` in the snapshot. Code is the
|
|
603
|
+
* source of truth for features (via @ImplementsCapability). Keys in
|
|
604
|
+
* `marketedOnlyFeatures` are deliberately exempt — marketed
|
|
605
|
+
* non-code features (e.g. support SLAs) that never have a Capability.
|
|
606
|
+
* - **Quota existence** (`QUOTA_MISSING`): every `quotas` key must exist
|
|
607
|
+
* as a `DiscoveredQuota` (via `@DefinesQuota`) in the snapshot.
|
|
608
|
+
* - **Approved gate** (`PLAN_FEATURE_NOT_APPROVED`/`QUOTA_NOT_APPROVED`,
|
|
609
|
+
* optional via `approved`, #20 Slice 5): only approved features/quotas
|
|
610
|
+
* are sellable. `approved = null` skips the approval part.
|
|
611
|
+
* - **Feature dependencies** (`PLAN_FEATURE_DEPENDENCY_UNSATISFIED`, #35,
|
|
612
|
+
* advisory): `requires` features that are not in the Plan itself —
|
|
613
|
+
* may be covered at the Tenant by booked Bundles.
|
|
614
|
+
*
|
|
615
|
+
* **Not** checked (belongs in other validations):
|
|
616
|
+
* - Pricing (purely business)
|
|
617
|
+
* - Marketing fields (separately in §8.2 item 6)
|
|
618
|
+
*/
|
|
619
|
+
declare function validatePlanDraft(draft: {
|
|
620
|
+
features: string[];
|
|
621
|
+
quotas: Record<string, number>;
|
|
622
|
+
}, snapshot: DiscoverySnapshot, marketedOnlyFeatures?: ReadonlySet<string>, approved?: ApprovedCatalogKeys | null): StrictModeWarning[];
|
|
623
|
+
|
|
624
|
+
/**
|
|
625
|
+
* Signature of a feature's capability set: `capabilityKey@codeStatus`,
|
|
626
|
+
* sorted and `|`-separated. `internal` capabilities do not count (they also
|
|
627
|
+
* do not appear in the catalog).
|
|
628
|
+
*
|
|
629
|
+
* `requires`/`replaces` (#35/#39) are only included when they are set —
|
|
630
|
+
* this keeps existing signatures without that metadata byte-identical;
|
|
631
|
+
* otherwise the platform upgrade would flip every approved entry to
|
|
632
|
+
* `outdated` even though nothing in the code changed.
|
|
633
|
+
*/
|
|
634
|
+
declare function featureApprovalSignature(featureKey: string, snapshot: DiscoverySnapshot): string;
|
|
635
|
+
/**
|
|
636
|
+
* Signature of the code-derived quota facts:
|
|
637
|
+
* `unit|enforcementMode|usageProvider|featureKey`. `enforcementMode` is the
|
|
638
|
+
* catalog view of the policy (`hardCap` → `hard`, otherwise `soft`) —
|
|
639
|
+
* identical to the derivation in the sync. `replaces` (#39) is only appended
|
|
640
|
+
* when set (same stability rationale as `featureApprovalSignature`).
|
|
641
|
+
*/
|
|
642
|
+
declare function quotaApprovalSignature(quota: DiscoveredQuota): string;
|
|
643
|
+
|
|
644
|
+
declare function loadApprovedCatalogKeys(repo: CatalogEntryRepository | null, projectKey: string): Promise<ApprovedCatalogKeys | null>;
|
|
645
|
+
|
|
646
|
+
interface PreflightInput {
|
|
647
|
+
snapshot: DiscoverySnapshot;
|
|
648
|
+
/** All live PlanVersions (publishedAt != null AND supersededAt = null). */
|
|
649
|
+
planVersions: PlanVersionRow[];
|
|
650
|
+
/** All live BundleVersions. */
|
|
651
|
+
bundleVersions: BundleVersionRow[];
|
|
652
|
+
/** All live BusinessTypeVersions. */
|
|
653
|
+
businessTypeVersions: BusinessTypeVersionRow[];
|
|
654
|
+
/**
|
|
655
|
+
* Approved gate (#20 Slice 5): approved feature/quota keys from the
|
|
656
|
+
* catalog entries (`loadApprovedCatalogKeys`). Omitted/`null` →
|
|
657
|
+
* existence checks only.
|
|
658
|
+
*/
|
|
659
|
+
approved?: ApprovedCatalogKeys | null;
|
|
660
|
+
}
|
|
661
|
+
interface PreflightFinding {
|
|
662
|
+
/** `plan` / `bundle` / `business-type`. */
|
|
663
|
+
kind: 'plan' | 'bundle' | 'business-type';
|
|
664
|
+
/** ID of the specific version the violation is attached to. */
|
|
665
|
+
versionId: string;
|
|
666
|
+
/** Human-readable key for the UI: `STARTER` or `BANKING` or `SPORT_VEREIN`. */
|
|
667
|
+
entityKey: string;
|
|
668
|
+
/** Version number. */
|
|
669
|
+
version: number;
|
|
670
|
+
warning: StrictModeWarning;
|
|
671
|
+
}
|
|
672
|
+
interface PreflightReport {
|
|
673
|
+
/** `'ok'` if no findings; otherwise `'error'`. */
|
|
674
|
+
overall: 'ok' | 'error';
|
|
675
|
+
/** Aggregated statistics: how many violations per kind. */
|
|
676
|
+
counts: {
|
|
677
|
+
planFindings: number;
|
|
678
|
+
bundleFindings: number;
|
|
679
|
+
businessTypeFindings: number;
|
|
680
|
+
total: number;
|
|
681
|
+
};
|
|
682
|
+
findings: PreflightFinding[];
|
|
683
|
+
}
|
|
684
|
+
/**
|
|
685
|
+
* Runs all three strict checks against the discovery snapshot.
|
|
686
|
+
* Collects findings by entity type and returns a sorted report
|
|
687
|
+
* (deterministic for test stability).
|
|
688
|
+
*/
|
|
689
|
+
declare function runPreflight(input: PreflightInput): PreflightReport;
|
|
690
|
+
/**
|
|
691
|
+
* Formats the report output for CLI stdout. Returns a multi-line string.
|
|
692
|
+
*/
|
|
693
|
+
declare function formatPreflightReport(report: PreflightReport): string;
|
|
694
|
+
/** Exit code for the CLI wrapping: 0 on OK, 4 on violations. */
|
|
695
|
+
declare function preflightExitCode(report: PreflightReport): number;
|
|
696
|
+
|
|
697
|
+
interface SeedPlanDraft {
|
|
698
|
+
planKey: string;
|
|
699
|
+
features: string[];
|
|
700
|
+
quotas?: Record<string, number>;
|
|
701
|
+
}
|
|
702
|
+
interface SeedBundleDraft {
|
|
703
|
+
bundleKey: string;
|
|
704
|
+
features: string[];
|
|
705
|
+
quotas?: Record<string, number>;
|
|
706
|
+
}
|
|
707
|
+
interface SeedGateInput {
|
|
708
|
+
snapshot: DiscoverySnapshot;
|
|
709
|
+
/** Plan drafts to seed (before persisting). */
|
|
710
|
+
plans?: SeedPlanDraft[];
|
|
711
|
+
/** Bundle drafts to seed (before persisting). */
|
|
712
|
+
bundles?: SeedBundleDraft[];
|
|
713
|
+
/**
|
|
714
|
+
* Approved gate (#20 Slice 5): approved feature/quota keys from the
|
|
715
|
+
* catalog entries (`loadApprovedCatalogKeys`). Omitted/`null` →
|
|
716
|
+
* existence checks only (e.g. first seed, before any catalog entries exist).
|
|
717
|
+
*/
|
|
718
|
+
approved?: ApprovedCatalogKeys | null;
|
|
719
|
+
}
|
|
720
|
+
interface SeedGateFinding {
|
|
721
|
+
kind: 'plan' | 'bundle';
|
|
722
|
+
/** Human-readable key: `STARTER` or `BANKING`. */
|
|
723
|
+
entityKey: string;
|
|
724
|
+
warning: StrictModeWarning;
|
|
725
|
+
}
|
|
726
|
+
interface SeedGateReport {
|
|
727
|
+
/** `'ok'` if no findings; otherwise `'error'`. */
|
|
728
|
+
overall: 'ok' | 'error';
|
|
729
|
+
counts: {
|
|
730
|
+
planFindings: number;
|
|
731
|
+
bundleFindings: number;
|
|
732
|
+
total: number;
|
|
733
|
+
};
|
|
734
|
+
findings: SeedGateFinding[];
|
|
735
|
+
}
|
|
736
|
+
/**
|
|
737
|
+
* Validates seeded plan/bundle drafts against the DiscoverySnapshot.
|
|
738
|
+
* Collects findings and returns a deterministically sorted report.
|
|
739
|
+
*/
|
|
740
|
+
declare function validateSeedAgainstSnapshot(input: SeedGateInput): SeedGateReport;
|
|
741
|
+
/** Formats the report output for CLI/seed stdout. Returns a multi-line string. */
|
|
742
|
+
declare function formatSeedGateReport(report: SeedGateReport): string;
|
|
743
|
+
/** Exit code for CLI/seed wrapping: 0 on OK, 4 on violations (analogous to Preflight). */
|
|
744
|
+
declare function seedGateExitCode(report: SeedGateReport): number;
|
|
745
|
+
|
|
746
|
+
type SeedGateMode = 'report-only' | 'blocking';
|
|
747
|
+
interface SeedGateRunOptions {
|
|
748
|
+
/** Path of the snapshot file persisted by the scanner. */
|
|
749
|
+
snapshotPath: string;
|
|
750
|
+
plans?: SeedPlanDraft[];
|
|
751
|
+
bundles?: SeedBundleDraft[];
|
|
752
|
+
/** Approved gate (#20 Slice 5) — `null`/omitted = existence checks only. */
|
|
753
|
+
approved?: ApprovedCatalogKeys | null;
|
|
754
|
+
/** Default `'report-only'`; consumers map their env variable onto this. */
|
|
755
|
+
mode?: SeedGateMode;
|
|
756
|
+
/** Log sinks — default `console.log`/`console.warn`/`console.error`. */
|
|
757
|
+
log?: (line: string) => void;
|
|
758
|
+
warn?: (line: string) => void;
|
|
759
|
+
error?: (line: string) => void;
|
|
760
|
+
/** Exit function in the blocking case — default `process.exit`. Injectable in tests. */
|
|
761
|
+
exit?: (code: number) => never;
|
|
762
|
+
}
|
|
763
|
+
/**
|
|
764
|
+
* Loads the snapshot, validates the seed drafts and prints the report.
|
|
765
|
+
* Returns the report — or `null` if the snapshot is missing and the mode
|
|
766
|
+
* is report-only (gate skipped). In blocking mode the function does not
|
|
767
|
+
* return on violations or a missing snapshot (exit 4).
|
|
768
|
+
*/
|
|
769
|
+
declare function runSeedGateFromFile(options: SeedGateRunOptions): SeedGateReport | null;
|
|
770
|
+
|
|
771
|
+
declare class CreateBundleDto {
|
|
772
|
+
projectKey: string;
|
|
773
|
+
bundleKey: string;
|
|
774
|
+
label: string;
|
|
775
|
+
description?: string;
|
|
776
|
+
icon?: string;
|
|
777
|
+
sortOrder?: number;
|
|
778
|
+
/** Locale translations { "en": { label, description }, … }. */
|
|
779
|
+
i18n?: Record<string, {
|
|
780
|
+
label?: string;
|
|
781
|
+
description?: string;
|
|
782
|
+
}>;
|
|
783
|
+
}
|
|
784
|
+
declare class UpdateBundleDto {
|
|
785
|
+
label?: string;
|
|
786
|
+
description?: string | null;
|
|
787
|
+
icon?: string | null;
|
|
788
|
+
sortOrder?: number;
|
|
789
|
+
/** Locale translations { "en": { label, description }, … }. */
|
|
790
|
+
i18n?: Record<string, {
|
|
791
|
+
label?: string;
|
|
792
|
+
description?: string;
|
|
793
|
+
}>;
|
|
794
|
+
}
|
|
795
|
+
declare class CreateBundleVersionDraftDto {
|
|
796
|
+
features: string[];
|
|
797
|
+
quotas?: Record<string, number>;
|
|
798
|
+
compatibility?: {
|
|
799
|
+
businessTypeKeys?: string[];
|
|
800
|
+
planIds?: string[];
|
|
801
|
+
};
|
|
802
|
+
pricingOverrides?: Array<{
|
|
803
|
+
businessTypeKey?: string;
|
|
804
|
+
planId?: string;
|
|
805
|
+
monthlyNet?: string | null;
|
|
806
|
+
yearlyNet?: string | null;
|
|
807
|
+
}>;
|
|
808
|
+
monthlyNet?: string | null;
|
|
809
|
+
yearlyNet?: string | null;
|
|
810
|
+
marketed?: boolean;
|
|
811
|
+
changeNote?: string;
|
|
812
|
+
baseVersionId?: string | null;
|
|
813
|
+
validFrom?: string | null;
|
|
814
|
+
validUntil?: string | null;
|
|
815
|
+
}
|
|
816
|
+
declare class UpdateBundleVersionDraftDto {
|
|
817
|
+
features?: string[];
|
|
818
|
+
quotas?: Record<string, number>;
|
|
819
|
+
compatibility?: {
|
|
820
|
+
businessTypeKeys?: string[];
|
|
821
|
+
planIds?: string[];
|
|
822
|
+
};
|
|
823
|
+
pricingOverrides?: Array<{
|
|
824
|
+
businessTypeKey?: string;
|
|
825
|
+
planId?: string;
|
|
826
|
+
monthlyNet?: string | null;
|
|
827
|
+
yearlyNet?: string | null;
|
|
828
|
+
}>;
|
|
829
|
+
monthlyNet?: string | null;
|
|
830
|
+
yearlyNet?: string | null;
|
|
831
|
+
marketed?: boolean;
|
|
832
|
+
changeNote?: string;
|
|
833
|
+
validFrom?: string | null;
|
|
834
|
+
validUntil?: string | null;
|
|
835
|
+
}
|
|
836
|
+
declare class PublishBundleVersionDto {
|
|
837
|
+
forceRegressive?: boolean;
|
|
838
|
+
/**
|
|
839
|
+
* Allows a deliberately free bundle (explicit price 0.00) and lifts the
|
|
840
|
+
* zero-price gate (otherwise 422 BUNDLE_VERSION_ZERO_PRICE). Default: gate
|
|
841
|
+
* active (protection against seed placeholders).
|
|
842
|
+
*/
|
|
843
|
+
allowZeroPrice?: boolean;
|
|
844
|
+
/**
|
|
845
|
+
* Required on publish if the draft carries no `validFrom`
|
|
846
|
+
* (SPEC_V2 §4.2 + §11.1 M6 Pack 2c, analogous to PublishPlanVersionDto).
|
|
847
|
+
* Service strictly checks > `validFrom` of the predecessor version.
|
|
848
|
+
*/
|
|
849
|
+
validFrom?: string | null;
|
|
850
|
+
validUntil?: string | null;
|
|
851
|
+
}
|
|
852
|
+
|
|
853
|
+
declare class CreateBusinessTypeDto {
|
|
854
|
+
projectKey: string;
|
|
855
|
+
businessTypeKey: string;
|
|
856
|
+
label: string;
|
|
857
|
+
description?: string;
|
|
858
|
+
icon?: string;
|
|
859
|
+
sortOrder?: number;
|
|
860
|
+
}
|
|
861
|
+
declare class UpdateBusinessTypeDto {
|
|
862
|
+
label?: string;
|
|
863
|
+
description?: string | null;
|
|
864
|
+
icon?: string | null;
|
|
865
|
+
sortOrder?: number;
|
|
866
|
+
}
|
|
867
|
+
declare class BusinessTypeBundleInputDto {
|
|
868
|
+
bundleVersionId: string;
|
|
869
|
+
sortOrder?: number;
|
|
870
|
+
}
|
|
871
|
+
declare class CreateBusinessTypeVersionDraftDto {
|
|
872
|
+
bundles: BusinessTypeBundleInputDto[];
|
|
873
|
+
quotaOverrides?: Record<string, number>;
|
|
874
|
+
monthlyNet?: string | null;
|
|
875
|
+
yearlyNet?: string | null;
|
|
876
|
+
marketed?: boolean;
|
|
877
|
+
changeNote?: string;
|
|
878
|
+
baseVersionId?: string | null;
|
|
879
|
+
}
|
|
880
|
+
declare class UpdateBusinessTypeVersionDraftDto {
|
|
881
|
+
bundles?: BusinessTypeBundleInputDto[];
|
|
882
|
+
quotaOverrides?: Record<string, number>;
|
|
883
|
+
monthlyNet?: string | null;
|
|
884
|
+
yearlyNet?: string | null;
|
|
885
|
+
marketed?: boolean;
|
|
886
|
+
changeNote?: string;
|
|
887
|
+
}
|
|
888
|
+
declare class PublishBusinessTypeVersionDto {
|
|
889
|
+
forceRegressive?: boolean;
|
|
890
|
+
}
|
|
891
|
+
|
|
892
|
+
declare class MarketingTopFeatureDto {
|
|
893
|
+
/** Optional feature/quota key reference (auto-translation of the label). */
|
|
894
|
+
key?: string;
|
|
895
|
+
/** Free text or override; empty + `key` set = auto label. */
|
|
896
|
+
label: string;
|
|
897
|
+
/** Optional bold addendum — may be empty. */
|
|
898
|
+
strong: string;
|
|
899
|
+
}
|
|
900
|
+
declare class CreateMarketingProjectionDto {
|
|
901
|
+
projectKey: string;
|
|
902
|
+
targetType: 'PLAN' | 'BUNDLE' | 'BUSINESS_TYPE';
|
|
903
|
+
targetVersionId: string;
|
|
904
|
+
locale?: string;
|
|
905
|
+
displayLabel: string;
|
|
906
|
+
description: string;
|
|
907
|
+
visible?: boolean;
|
|
908
|
+
badge?: string;
|
|
909
|
+
topFeatures?: MarketingTopFeatureDto[];
|
|
910
|
+
trialEnabled?: boolean;
|
|
911
|
+
trialDays?: number;
|
|
912
|
+
priceTag?: string | null;
|
|
913
|
+
ctaLabel?: string | null;
|
|
914
|
+
priority?: number;
|
|
915
|
+
highlight?: boolean;
|
|
916
|
+
}
|
|
917
|
+
declare class UpdateMarketingProjectionDto {
|
|
918
|
+
displayLabel?: string;
|
|
919
|
+
description?: string;
|
|
920
|
+
visible?: boolean;
|
|
921
|
+
badge?: string;
|
|
922
|
+
topFeatures?: MarketingTopFeatureDto[];
|
|
923
|
+
trialEnabled?: boolean;
|
|
924
|
+
trialDays?: number;
|
|
925
|
+
priceTag?: string | null;
|
|
926
|
+
ctaLabel?: string | null;
|
|
927
|
+
priority?: number;
|
|
928
|
+
highlight?: boolean;
|
|
929
|
+
}
|
|
930
|
+
declare class ListMarketingProjectionsQueryDto {
|
|
931
|
+
projectKey: string;
|
|
932
|
+
targetType?: 'PLAN' | 'BUNDLE' | 'BUSINESS_TYPE';
|
|
933
|
+
targetVersionId?: string;
|
|
934
|
+
locale?: string;
|
|
935
|
+
}
|
|
936
|
+
|
|
937
|
+
declare class ListCatalogEntriesQueryDto {
|
|
938
|
+
projectKey: string;
|
|
939
|
+
/** Filter for features/quotas (approval lifecycle). */
|
|
940
|
+
discoveryStatus?: string;
|
|
941
|
+
/** Filter for capabilities (read-only code facts). */
|
|
942
|
+
codeStatus?: string;
|
|
943
|
+
}
|
|
944
|
+
/**
|
|
945
|
+
* Body of `PATCH …/{features,quotas}/:key/review` — target status of the
|
|
946
|
+
* approval state machine (#20). Allowed transitions are validated by the service.
|
|
947
|
+
*/
|
|
948
|
+
declare class ReviewCatalogEntryDto {
|
|
949
|
+
discoveryStatus: DiscoveryStatus;
|
|
950
|
+
}
|
|
951
|
+
/** Body of `PATCH …/{features,quotas}/:key/i18n`. */
|
|
952
|
+
declare class UpdateCatalogEntryI18nDto {
|
|
953
|
+
i18n: CatalogEntryI18n;
|
|
954
|
+
}
|
|
955
|
+
/**
|
|
956
|
+
* Body of `POST …/discovery/sync` — the discovery snapshot the UI
|
|
957
|
+
* previously loaded from `GET /admin/discovery`. Validated by the service
|
|
958
|
+
* against `projectKey`; deep validation is not needed because the
|
|
959
|
+
* SuperAdmin guard secures the source.
|
|
960
|
+
*/
|
|
961
|
+
declare class SyncDiscoveryDto {
|
|
962
|
+
snapshot: DiscoverySnapshot;
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
declare class ListPromotionsQueryDto {
|
|
966
|
+
projectKey: string;
|
|
967
|
+
}
|
|
968
|
+
declare class CreatePromotionDto {
|
|
969
|
+
projectKey: string;
|
|
970
|
+
internalLabel: string;
|
|
971
|
+
type: PromotionType;
|
|
972
|
+
/** Type-dependent: number | { price, months }. */
|
|
973
|
+
value: PromotionValue;
|
|
974
|
+
appliesTo?: string[];
|
|
975
|
+
targetType?: PromotionTargetType;
|
|
976
|
+
billingCycle?: PromotionBillingCycle;
|
|
977
|
+
validFrom: string;
|
|
978
|
+
validTo: string;
|
|
979
|
+
priority?: number;
|
|
980
|
+
onlyLocales?: string[] | null;
|
|
981
|
+
requiresCoupon?: boolean;
|
|
982
|
+
codes?: string[];
|
|
983
|
+
color?: string;
|
|
984
|
+
i18n?: PromotionI18n;
|
|
985
|
+
}
|
|
986
|
+
declare class UpdatePromotionDto {
|
|
987
|
+
internalLabel?: string;
|
|
988
|
+
type?: PromotionType;
|
|
989
|
+
value?: PromotionValue;
|
|
990
|
+
appliesTo?: string[];
|
|
991
|
+
targetType?: PromotionTargetType;
|
|
992
|
+
billingCycle?: PromotionBillingCycle;
|
|
993
|
+
validFrom?: string;
|
|
994
|
+
validTo?: string;
|
|
995
|
+
priority?: number;
|
|
996
|
+
onlyLocales?: string[] | null;
|
|
997
|
+
requiresCoupon?: boolean;
|
|
998
|
+
codes?: string[];
|
|
999
|
+
color?: string;
|
|
1000
|
+
i18n?: PromotionI18n;
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
declare class ListMarketingSettingsQueryDto {
|
|
1004
|
+
projectKey: string;
|
|
1005
|
+
}
|
|
1006
|
+
/** Body of `PUT /admin/catalog/marketing-settings`. */
|
|
1007
|
+
declare class UpdateMarketingSettingsDto {
|
|
1008
|
+
projectKey: string;
|
|
1009
|
+
activeLocales: string[];
|
|
1010
|
+
}
|
|
1011
|
+
|
|
1012
|
+
declare class CreatePlanDto {
|
|
1013
|
+
projectKey: string;
|
|
1014
|
+
planKey: string;
|
|
1015
|
+
label: string;
|
|
1016
|
+
description?: string;
|
|
1017
|
+
icon?: string;
|
|
1018
|
+
sortOrder?: number;
|
|
1019
|
+
}
|
|
1020
|
+
declare class UpdatePlanDto {
|
|
1021
|
+
label?: string;
|
|
1022
|
+
description?: string | null;
|
|
1023
|
+
icon?: string | null;
|
|
1024
|
+
sortOrder?: number;
|
|
1025
|
+
}
|
|
1026
|
+
|
|
1027
|
+
declare class CreatePlanVersionDraftDto {
|
|
1028
|
+
features: string[];
|
|
1029
|
+
/**
|
|
1030
|
+
* Persisted bundle selection (bundleKeys, SCREAMING_SNAKE_CASE).
|
|
1031
|
+
* Optional + defaults to empty — see `PlanVersionRow.bundles`.
|
|
1032
|
+
*/
|
|
1033
|
+
bundles?: string[];
|
|
1034
|
+
quotas: Record<string, number>;
|
|
1035
|
+
monthlyNet: string;
|
|
1036
|
+
yearlyNet: string;
|
|
1037
|
+
marketed?: boolean;
|
|
1038
|
+
changeNote?: string;
|
|
1039
|
+
baseVersionId?: string | null;
|
|
1040
|
+
/** Optional in the draft (required at publish). ISO date string. SPEC_V2 §4.2. */
|
|
1041
|
+
validFrom?: string | null;
|
|
1042
|
+
/** Optional; null = unlimited. ISO date string. */
|
|
1043
|
+
validUntil?: string | null;
|
|
1044
|
+
}
|
|
1045
|
+
declare class UpdatePlanVersionDraftDto {
|
|
1046
|
+
features?: string[];
|
|
1047
|
+
/** Persisted bundle selection (bundleKeys). See `PlanVersionRow.bundles`. */
|
|
1048
|
+
bundles?: string[];
|
|
1049
|
+
quotas?: Record<string, number>;
|
|
1050
|
+
monthlyNet?: string;
|
|
1051
|
+
yearlyNet?: string;
|
|
1052
|
+
marketed?: boolean;
|
|
1053
|
+
changeNote?: string;
|
|
1054
|
+
validFrom?: string | null;
|
|
1055
|
+
validUntil?: string | null;
|
|
1056
|
+
}
|
|
1057
|
+
declare class PublishPlanVersionDto {
|
|
1058
|
+
forceRegressive?: boolean;
|
|
1059
|
+
/**
|
|
1060
|
+
* Deliberately allows free special contracts (price 0.00) and thereby lifts
|
|
1061
|
+
* the zero-price gate (otherwise 422 PLAN_VERSION_ZERO_PRICE). Default:
|
|
1062
|
+
* gate active (protection against seed placeholders).
|
|
1063
|
+
*/
|
|
1064
|
+
allowZeroPrice?: boolean;
|
|
1065
|
+
/**
|
|
1066
|
+
* Required at publish (on the DTO or draft). The service strictly checks
|
|
1067
|
+
* `validFrom > predecessor.validFrom`. SPEC_V2 §4.2.
|
|
1068
|
+
*/
|
|
1069
|
+
validFrom?: string | null;
|
|
1070
|
+
validUntil?: string | null;
|
|
1071
|
+
}
|
|
1072
|
+
|
|
1073
|
+
export { ADVISORY_STRICT_MODE_CODES, BUNDLE_REPOSITORY_TOKEN, BUSINESS_TYPE_REPOSITORY_TOKEN, BundlesService, BusinessTypeBundleInputDto, BusinessTypesService, CATALOG_ENTRY_REPOSITORY_TOKEN, CATALOG_SERVICE_CONFIG_TOKEN, type CatalogControllerConfig, CatalogEntriesService, CatalogModule, type CatalogModuleOptions, type 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, type PreflightFinding, type PreflightInput, type PreflightReport, PromotionsService, PublicMarketingCatalogService, PublishBundleVersionDto, PublishBusinessTypeVersionDto, PublishPlanVersionDto, ReviewCatalogEntryDto, type SeedBundleDraft, type SeedGateFinding, type SeedGateInput, type SeedGateMode, type SeedGateReport, type SeedGateRunOptions, type 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 };
|