@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,13 @@
|
|
|
1
|
+
import {
|
|
2
|
+
__name
|
|
3
|
+
} from "./chunk-SHUYVCID.js";
|
|
4
|
+
|
|
5
|
+
// src/billing/require-feature.decorator.ts
|
|
6
|
+
import { SetMetadata } from "@nestjs/common";
|
|
7
|
+
var REQUIRE_FEATURE_KEY = "require-feature";
|
|
8
|
+
var RequireFeature = /* @__PURE__ */ __name((...features) => SetMetadata(REQUIRE_FEATURE_KEY, features), "RequireFeature");
|
|
9
|
+
|
|
10
|
+
export {
|
|
11
|
+
REQUIRE_FEATURE_KEY,
|
|
12
|
+
RequireFeature
|
|
13
|
+
};
|
|
@@ -0,0 +1,573 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ADMIN_MANIFEST_CONFIG,
|
|
3
|
+
AdminManifestModule,
|
|
4
|
+
AdminModule
|
|
5
|
+
} from "./chunk-P6MYZMXQ.js";
|
|
6
|
+
import {
|
|
7
|
+
REQUIRE_FEATURE_KEY
|
|
8
|
+
} from "./chunk-Q53N43LQ.js";
|
|
9
|
+
import {
|
|
10
|
+
DiscoveryModule
|
|
11
|
+
} from "./chunk-AJ3EPELS.js";
|
|
12
|
+
import {
|
|
13
|
+
EntitlementModule,
|
|
14
|
+
LimitExceededError
|
|
15
|
+
} from "./chunk-YXGHPILG.js";
|
|
16
|
+
import {
|
|
17
|
+
PLAN_CATALOG_TOKEN,
|
|
18
|
+
PlanCatalogModule
|
|
19
|
+
} from "./chunk-MV6LW5UB.js";
|
|
20
|
+
import {
|
|
21
|
+
asProvider
|
|
22
|
+
} from "./chunk-SABTXESR.js";
|
|
23
|
+
import {
|
|
24
|
+
ENFORCE_QUOTA_KEY
|
|
25
|
+
} from "./chunk-L4SUWH5B.js";
|
|
26
|
+
import {
|
|
27
|
+
__name
|
|
28
|
+
} from "./chunk-SHUYVCID.js";
|
|
29
|
+
|
|
30
|
+
// src/platform/plan-resolver.port.ts
|
|
31
|
+
var PLAN_RESOLVER_PORT_TOKEN = /* @__PURE__ */ Symbol.for("saas-platform-nest/PlanResolverPort");
|
|
32
|
+
var StaticPlanResolver = class {
|
|
33
|
+
static {
|
|
34
|
+
__name(this, "StaticPlanResolver");
|
|
35
|
+
}
|
|
36
|
+
planId;
|
|
37
|
+
constructor(planId) {
|
|
38
|
+
this.planId = planId;
|
|
39
|
+
}
|
|
40
|
+
async getPlanIdForTenant() {
|
|
41
|
+
return this.planId;
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
// src/platform/static-entitlement.service.ts
|
|
46
|
+
import { Inject, Injectable } from "@nestjs/common";
|
|
47
|
+
function _ts_decorate(decorators, target, key, desc) {
|
|
48
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
49
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
50
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
51
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
52
|
+
}
|
|
53
|
+
__name(_ts_decorate, "_ts_decorate");
|
|
54
|
+
function _ts_metadata(k, v) {
|
|
55
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
56
|
+
}
|
|
57
|
+
__name(_ts_metadata, "_ts_metadata");
|
|
58
|
+
function _ts_param(paramIndex, decorator) {
|
|
59
|
+
return function(target, key) {
|
|
60
|
+
decorator(target, key, paramIndex);
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
__name(_ts_param, "_ts_param");
|
|
64
|
+
var StaticEntitlementService = class {
|
|
65
|
+
static {
|
|
66
|
+
__name(this, "StaticEntitlementService");
|
|
67
|
+
}
|
|
68
|
+
catalog;
|
|
69
|
+
resolver;
|
|
70
|
+
constructor(catalog, resolver) {
|
|
71
|
+
this.catalog = catalog;
|
|
72
|
+
this.resolver = resolver;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Returns the effective features + quotas of a tenant from the
|
|
76
|
+
* plan catalog. When the plan is missing: an empty snapshot (no feature,
|
|
77
|
+
* all quotas at 0).
|
|
78
|
+
*/
|
|
79
|
+
async snapshot(tenantId) {
|
|
80
|
+
const planId = await this.resolver.getPlanIdForTenant(tenantId);
|
|
81
|
+
if (!planId) {
|
|
82
|
+
return {
|
|
83
|
+
planId: null,
|
|
84
|
+
features: [],
|
|
85
|
+
quotas: {}
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
const plan = this.findPlan(planId);
|
|
89
|
+
if (!plan) {
|
|
90
|
+
return {
|
|
91
|
+
planId,
|
|
92
|
+
features: [],
|
|
93
|
+
quotas: {}
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
return {
|
|
97
|
+
planId,
|
|
98
|
+
features: plan.features ?? [],
|
|
99
|
+
quotas: plan.quotas ?? {}
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
/** Convenience helper for tests / synchronous checks in the UI manifest. */
|
|
103
|
+
async hasFeature(tenantId, featureKey) {
|
|
104
|
+
const snap = await this.snapshot(tenantId);
|
|
105
|
+
return snap.features.includes(featureKey);
|
|
106
|
+
}
|
|
107
|
+
async quotaLimit(tenantId, quotaKey) {
|
|
108
|
+
const snap = await this.snapshot(tenantId);
|
|
109
|
+
const value = snap.quotas[quotaKey];
|
|
110
|
+
return value === void 0 ? null : value;
|
|
111
|
+
}
|
|
112
|
+
findPlan(planId) {
|
|
113
|
+
return (this.catalog.plans ?? []).find((p) => p.id === planId);
|
|
114
|
+
}
|
|
115
|
+
};
|
|
116
|
+
StaticEntitlementService = _ts_decorate([
|
|
117
|
+
Injectable(),
|
|
118
|
+
_ts_param(0, Inject(PLAN_CATALOG_TOKEN)),
|
|
119
|
+
_ts_param(1, Inject(PLAN_RESOLVER_PORT_TOKEN)),
|
|
120
|
+
_ts_metadata("design:type", Function),
|
|
121
|
+
_ts_metadata("design:paramtypes", [
|
|
122
|
+
typeof PlanCatalog === "undefined" ? Object : PlanCatalog,
|
|
123
|
+
typeof PlanResolverPort === "undefined" ? Object : PlanResolverPort
|
|
124
|
+
])
|
|
125
|
+
], StaticEntitlementService);
|
|
126
|
+
|
|
127
|
+
// src/platform/static-feature.guard.ts
|
|
128
|
+
import { ForbiddenException, Inject as Inject2, Injectable as Injectable2, Optional } from "@nestjs/common";
|
|
129
|
+
import { Reflector } from "@nestjs/core";
|
|
130
|
+
function _ts_decorate2(decorators, target, key, desc) {
|
|
131
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
132
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
133
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
134
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
135
|
+
}
|
|
136
|
+
__name(_ts_decorate2, "_ts_decorate");
|
|
137
|
+
function _ts_metadata2(k, v) {
|
|
138
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
139
|
+
}
|
|
140
|
+
__name(_ts_metadata2, "_ts_metadata");
|
|
141
|
+
function _ts_param2(paramIndex, decorator) {
|
|
142
|
+
return function(target, key) {
|
|
143
|
+
decorator(target, key, paramIndex);
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
__name(_ts_param2, "_ts_param");
|
|
147
|
+
var STATIC_FEATURE_GUARD_CONFIG_TOKEN = /* @__PURE__ */ Symbol.for("saas-platform-nest/StaticFeatureGuardConfig");
|
|
148
|
+
var StaticFeatureGuard = class {
|
|
149
|
+
static {
|
|
150
|
+
__name(this, "StaticFeatureGuard");
|
|
151
|
+
}
|
|
152
|
+
reflector;
|
|
153
|
+
entitlements;
|
|
154
|
+
config;
|
|
155
|
+
constructor(reflector, entitlements, config = null) {
|
|
156
|
+
this.reflector = reflector;
|
|
157
|
+
this.entitlements = entitlements;
|
|
158
|
+
this.config = config;
|
|
159
|
+
}
|
|
160
|
+
async canActivate(context) {
|
|
161
|
+
const required = this.reflector.getAllAndOverride(REQUIRE_FEATURE_KEY, [
|
|
162
|
+
context.getHandler(),
|
|
163
|
+
context.getClass()
|
|
164
|
+
]);
|
|
165
|
+
if (!required || required.length === 0) return true;
|
|
166
|
+
const request = context.switchToHttp().getRequest();
|
|
167
|
+
const user = request.user;
|
|
168
|
+
if (!user) throw new ForbiddenException("Nicht authentifiziert");
|
|
169
|
+
const role = this.config?.userRoleResolver ? this.config.userRoleResolver(user) : user.role ?? user.platformRole;
|
|
170
|
+
if (role === "SUPER_ADMIN") return true;
|
|
171
|
+
const tenantId = this.config?.tenantIdResolver ? this.config.tenantIdResolver(request) : request.tenantId ?? user.tenantId;
|
|
172
|
+
if (!tenantId) throw new ForbiddenException("Kein Mandant zugeordnet");
|
|
173
|
+
const snap = await this.entitlements.snapshot(tenantId);
|
|
174
|
+
const allowed = required.some((f) => snap.features.includes(f));
|
|
175
|
+
if (!allowed) {
|
|
176
|
+
throw new ForbiddenException(`Feature ${required.join(" / ")} nicht im aktuellen Plan enthalten.`);
|
|
177
|
+
}
|
|
178
|
+
return true;
|
|
179
|
+
}
|
|
180
|
+
};
|
|
181
|
+
StaticFeatureGuard = _ts_decorate2([
|
|
182
|
+
Injectable2(),
|
|
183
|
+
_ts_param2(0, Inject2(Reflector)),
|
|
184
|
+
_ts_param2(1, Inject2(StaticEntitlementService)),
|
|
185
|
+
_ts_param2(2, Optional()),
|
|
186
|
+
_ts_param2(2, Inject2(STATIC_FEATURE_GUARD_CONFIG_TOKEN)),
|
|
187
|
+
_ts_metadata2("design:type", Function),
|
|
188
|
+
_ts_metadata2("design:paramtypes", [
|
|
189
|
+
typeof Reflector === "undefined" ? Object : Reflector,
|
|
190
|
+
typeof StaticEntitlementService === "undefined" ? Object : StaticEntitlementService,
|
|
191
|
+
Object
|
|
192
|
+
])
|
|
193
|
+
], StaticFeatureGuard);
|
|
194
|
+
|
|
195
|
+
// src/platform/enforce-quota.interceptor.ts
|
|
196
|
+
import { Inject as Inject3, Injectable as Injectable3, Optional as Optional2 } from "@nestjs/common";
|
|
197
|
+
import { Reflector as Reflector2 } from "@nestjs/core";
|
|
198
|
+
import { from } from "rxjs";
|
|
199
|
+
import { switchMap } from "rxjs/operators";
|
|
200
|
+
function _ts_decorate3(decorators, target, key, desc) {
|
|
201
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
202
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
203
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
204
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
205
|
+
}
|
|
206
|
+
__name(_ts_decorate3, "_ts_decorate");
|
|
207
|
+
function _ts_metadata3(k, v) {
|
|
208
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
209
|
+
}
|
|
210
|
+
__name(_ts_metadata3, "_ts_metadata");
|
|
211
|
+
function _ts_param3(paramIndex, decorator) {
|
|
212
|
+
return function(target, key) {
|
|
213
|
+
decorator(target, key, paramIndex);
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
__name(_ts_param3, "_ts_param");
|
|
217
|
+
var QUOTA_PROVIDERS_TOKEN = /* @__PURE__ */ Symbol.for("saas-platform-nest/QuotaProviders");
|
|
218
|
+
var EnforceQuotaInterceptor = class {
|
|
219
|
+
static {
|
|
220
|
+
__name(this, "EnforceQuotaInterceptor");
|
|
221
|
+
}
|
|
222
|
+
reflector;
|
|
223
|
+
entitlements;
|
|
224
|
+
providers;
|
|
225
|
+
constructor(reflector, entitlements, providers = null) {
|
|
226
|
+
this.reflector = reflector;
|
|
227
|
+
this.entitlements = entitlements;
|
|
228
|
+
this.providers = providers;
|
|
229
|
+
}
|
|
230
|
+
intercept(context, next) {
|
|
231
|
+
const meta = this.reflector.getAllAndOverride(ENFORCE_QUOTA_KEY, [
|
|
232
|
+
context.getHandler(),
|
|
233
|
+
context.getClass()
|
|
234
|
+
]);
|
|
235
|
+
if (!meta?.quotaKey) return next.handle();
|
|
236
|
+
return from(this.check(context, meta)).pipe(switchMap(() => next.handle()));
|
|
237
|
+
}
|
|
238
|
+
async check(context, meta) {
|
|
239
|
+
const request = context.switchToHttp().getRequest();
|
|
240
|
+
const user = request.user;
|
|
241
|
+
if (!user) return;
|
|
242
|
+
const role = user.role ?? user.platformRole;
|
|
243
|
+
if (role === "SUPER_ADMIN") return;
|
|
244
|
+
const tenantId = request.tenantId ?? user.tenantId;
|
|
245
|
+
if (!tenantId) return;
|
|
246
|
+
const provider = (this.providers ?? []).find((p) => p.key === meta.quotaKey);
|
|
247
|
+
if (!provider) {
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
const limit = await this.entitlements.quotaLimit(tenantId, meta.quotaKey);
|
|
251
|
+
if (limit === null || limit === -1) return;
|
|
252
|
+
const current = await provider.count(tenantId);
|
|
253
|
+
const delta = meta.incrementBy ?? 1;
|
|
254
|
+
if (current + delta > limit) {
|
|
255
|
+
throw new LimitExceededError(meta.quotaKey, limit, current);
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
};
|
|
259
|
+
EnforceQuotaInterceptor = _ts_decorate3([
|
|
260
|
+
Injectable3(),
|
|
261
|
+
_ts_param3(0, Inject3(Reflector2)),
|
|
262
|
+
_ts_param3(1, Inject3(StaticEntitlementService)),
|
|
263
|
+
_ts_param3(2, Optional2()),
|
|
264
|
+
_ts_param3(2, Inject3(QUOTA_PROVIDERS_TOKEN)),
|
|
265
|
+
_ts_metadata3("design:type", Function),
|
|
266
|
+
_ts_metadata3("design:paramtypes", [
|
|
267
|
+
typeof Reflector2 === "undefined" ? Object : Reflector2,
|
|
268
|
+
typeof StaticEntitlementService === "undefined" ? Object : StaticEntitlementService,
|
|
269
|
+
Object
|
|
270
|
+
])
|
|
271
|
+
], EnforceQuotaInterceptor);
|
|
272
|
+
|
|
273
|
+
// src/platform/tenant-manifest.service.ts
|
|
274
|
+
import { Injectable as Injectable4 } from "@nestjs/common";
|
|
275
|
+
function _ts_decorate4(decorators, target, key, desc) {
|
|
276
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
277
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
278
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
279
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
280
|
+
}
|
|
281
|
+
__name(_ts_decorate4, "_ts_decorate");
|
|
282
|
+
function _ts_metadata4(k, v) {
|
|
283
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
284
|
+
}
|
|
285
|
+
__name(_ts_metadata4, "_ts_metadata");
|
|
286
|
+
var TenantManifestService = class {
|
|
287
|
+
static {
|
|
288
|
+
__name(this, "TenantManifestService");
|
|
289
|
+
}
|
|
290
|
+
entitlements;
|
|
291
|
+
navItems = [];
|
|
292
|
+
constructor(entitlements) {
|
|
293
|
+
this.entitlements = entitlements;
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* Call in the app's `OnModuleInit`: registers app navigation for the
|
|
297
|
+
* Tenant UI. Idempotent: the same `id` overwrites.
|
|
298
|
+
*/
|
|
299
|
+
registerNavItem(item) {
|
|
300
|
+
const existing = this.navItems.findIndex((i) => i.id === item.id);
|
|
301
|
+
if (existing >= 0) this.navItems[existing] = item;
|
|
302
|
+
else this.navItems.push(item);
|
|
303
|
+
}
|
|
304
|
+
/** Bulk variant. */
|
|
305
|
+
registerNavItems(items) {
|
|
306
|
+
for (const item of items) this.registerNavItem(item);
|
|
307
|
+
}
|
|
308
|
+
/**
|
|
309
|
+
* Returns the filtered manifest for a Tenant. NavItems with
|
|
310
|
+
* `requiresFeature` are filtered out server-side as soon as none of the
|
|
311
|
+
* required features are present in the entitlement snapshot.
|
|
312
|
+
*/
|
|
313
|
+
async getManifest(tenantId) {
|
|
314
|
+
const snap = await this.entitlements.snapshot(tenantId);
|
|
315
|
+
const featureSet = new Set(snap.features);
|
|
316
|
+
const visible = this.navItems.filter((item) => isVisible(item, featureSet)).map((item) => ({
|
|
317
|
+
...item
|
|
318
|
+
})).sort((a, b) => (a.order ?? 100) - (b.order ?? 100));
|
|
319
|
+
return {
|
|
320
|
+
schemaVersion: 1,
|
|
321
|
+
tenant: {
|
|
322
|
+
id: tenantId
|
|
323
|
+
},
|
|
324
|
+
planId: snap.planId,
|
|
325
|
+
features: snap.features,
|
|
326
|
+
quotas: snap.quotas,
|
|
327
|
+
navigation: visible
|
|
328
|
+
};
|
|
329
|
+
}
|
|
330
|
+
};
|
|
331
|
+
TenantManifestService = _ts_decorate4([
|
|
332
|
+
Injectable4(),
|
|
333
|
+
_ts_metadata4("design:type", Function),
|
|
334
|
+
_ts_metadata4("design:paramtypes", [
|
|
335
|
+
typeof StaticEntitlementService === "undefined" ? Object : StaticEntitlementService
|
|
336
|
+
])
|
|
337
|
+
], TenantManifestService);
|
|
338
|
+
function isVisible(item, features) {
|
|
339
|
+
if (!item.requiresFeature) return true;
|
|
340
|
+
const required = Array.isArray(item.requiresFeature) ? item.requiresFeature : [
|
|
341
|
+
item.requiresFeature
|
|
342
|
+
];
|
|
343
|
+
return required.some((f) => features.has(f));
|
|
344
|
+
}
|
|
345
|
+
__name(isVisible, "isVisible");
|
|
346
|
+
|
|
347
|
+
// src/platform/tenant-manifest.controller.ts
|
|
348
|
+
import { Controller, Get, Inject as Inject4, Req, UseGuards } from "@nestjs/common";
|
|
349
|
+
function _ts_decorate5(decorators, target, key, desc) {
|
|
350
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
351
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
352
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
353
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
354
|
+
}
|
|
355
|
+
__name(_ts_decorate5, "_ts_decorate");
|
|
356
|
+
function _ts_metadata5(k, v) {
|
|
357
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
358
|
+
}
|
|
359
|
+
__name(_ts_metadata5, "_ts_metadata");
|
|
360
|
+
function _ts_param4(paramIndex, decorator) {
|
|
361
|
+
return function(target, key) {
|
|
362
|
+
decorator(target, key, paramIndex);
|
|
363
|
+
};
|
|
364
|
+
}
|
|
365
|
+
__name(_ts_param4, "_ts_param");
|
|
366
|
+
function buildTenantManifestController(options) {
|
|
367
|
+
const path = options.path ?? "tenant/manifest";
|
|
368
|
+
let GeneratedTenantManifestController = class GeneratedTenantManifestController {
|
|
369
|
+
static {
|
|
370
|
+
__name(this, "GeneratedTenantManifestController");
|
|
371
|
+
}
|
|
372
|
+
svc;
|
|
373
|
+
constructor(svc) {
|
|
374
|
+
this.svc = svc;
|
|
375
|
+
}
|
|
376
|
+
async get(req) {
|
|
377
|
+
const tenantId = req.user?.tenantId ?? req.tenantId;
|
|
378
|
+
if (!tenantId) {
|
|
379
|
+
throw new Error("Kein Mandant im Request \u2014 TenantManifest braucht user.tenantId.");
|
|
380
|
+
}
|
|
381
|
+
return this.svc.getManifest(tenantId);
|
|
382
|
+
}
|
|
383
|
+
};
|
|
384
|
+
_ts_decorate5([
|
|
385
|
+
Get(),
|
|
386
|
+
_ts_param4(0, Req()),
|
|
387
|
+
_ts_metadata5("design:type", Function),
|
|
388
|
+
_ts_metadata5("design:paramtypes", [
|
|
389
|
+
typeof RequestWithUser === "undefined" ? Object : RequestWithUser
|
|
390
|
+
]),
|
|
391
|
+
_ts_metadata5("design:returntype", Promise)
|
|
392
|
+
], GeneratedTenantManifestController.prototype, "get", null);
|
|
393
|
+
GeneratedTenantManifestController = _ts_decorate5([
|
|
394
|
+
Controller(path),
|
|
395
|
+
UseGuards(...options.guards),
|
|
396
|
+
_ts_param4(0, Inject4(TenantManifestService)),
|
|
397
|
+
_ts_metadata5("design:type", Function),
|
|
398
|
+
_ts_metadata5("design:paramtypes", [
|
|
399
|
+
typeof TenantManifestService === "undefined" ? Object : TenantManifestService
|
|
400
|
+
])
|
|
401
|
+
], GeneratedTenantManifestController);
|
|
402
|
+
return GeneratedTenantManifestController;
|
|
403
|
+
}
|
|
404
|
+
__name(buildTenantManifestController, "buildTenantManifestController");
|
|
405
|
+
|
|
406
|
+
// src/platform/saas-platform.module.ts
|
|
407
|
+
import { Module } from "@nestjs/common";
|
|
408
|
+
import { APP_GUARD, APP_INTERCEPTOR } from "@nestjs/core";
|
|
409
|
+
function _ts_decorate6(decorators, target, key, desc) {
|
|
410
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
411
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
412
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
413
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
414
|
+
}
|
|
415
|
+
__name(_ts_decorate6, "_ts_decorate");
|
|
416
|
+
function buildMinimalManifestConfig() {
|
|
417
|
+
return {
|
|
418
|
+
useFactory: /* @__PURE__ */ __name((catalog) => ({
|
|
419
|
+
project: {
|
|
420
|
+
key: catalog.projectKey,
|
|
421
|
+
displayName: catalog.app?.name ?? catalog.projectKey,
|
|
422
|
+
label: catalog.app?.label,
|
|
423
|
+
icon: catalog.app?.icon,
|
|
424
|
+
logoUrl: catalog.app?.logoUrl,
|
|
425
|
+
environment: process.env.NODE_ENV === "production" ? "production" : "development",
|
|
426
|
+
availableLocales: catalog.marketing?.availableLocales,
|
|
427
|
+
defaultLocale: catalog.marketing?.availableLocales?.[0]
|
|
428
|
+
},
|
|
429
|
+
build: {
|
|
430
|
+
platformPackageVersion: "0.0.0",
|
|
431
|
+
appVersion: "0.0.0"
|
|
432
|
+
},
|
|
433
|
+
planCatalogSnapshot: {
|
|
434
|
+
source: "saas-platform-module",
|
|
435
|
+
hash: "sha256-quickstart",
|
|
436
|
+
currency: catalog.currency,
|
|
437
|
+
vatRate: catalog.vatRate,
|
|
438
|
+
plans: catalog.plans ?? [],
|
|
439
|
+
features: catalog.features ?? []
|
|
440
|
+
}
|
|
441
|
+
}), "useFactory"),
|
|
442
|
+
inject: [
|
|
443
|
+
PLAN_CATALOG_TOKEN
|
|
444
|
+
]
|
|
445
|
+
};
|
|
446
|
+
}
|
|
447
|
+
__name(buildMinimalManifestConfig, "buildMinimalManifestConfig");
|
|
448
|
+
var SaasPlatformModule = class _SaasPlatformModule {
|
|
449
|
+
static {
|
|
450
|
+
__name(this, "SaasPlatformModule");
|
|
451
|
+
}
|
|
452
|
+
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.");
|
|
455
|
+
}
|
|
456
|
+
if (options.entitlement) {
|
|
457
|
+
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");
|
|
461
|
+
if (missing.length) {
|
|
462
|
+
throw new Error(`SaasPlatformModule.forRoot: entitlement aktiv, aber Adapter fehlen: ${missing.join(", ")}`);
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
const planCatalogModule = options.planCatalog ? PlanCatalogModule.forRootWithCatalog(options.planCatalog, {
|
|
466
|
+
global: true
|
|
467
|
+
}) : PlanCatalogModule.forRoot({
|
|
468
|
+
projectKey: "",
|
|
469
|
+
currency: "",
|
|
470
|
+
vatRate: 0,
|
|
471
|
+
sink: options.adapters.planCatalogReadSink,
|
|
472
|
+
imports: options.imports
|
|
473
|
+
});
|
|
474
|
+
const appInfo = options.app ?? {
|
|
475
|
+
key: options.planCatalog?.projectKey ?? "app",
|
|
476
|
+
version: options.planCatalog?.app?.version ?? "0.0.0"
|
|
477
|
+
};
|
|
478
|
+
const imports = [
|
|
479
|
+
planCatalogModule,
|
|
480
|
+
DiscoveryModule.forRoot({
|
|
481
|
+
app: appInfo,
|
|
482
|
+
controller: {
|
|
483
|
+
guards: options.controller.guards
|
|
484
|
+
},
|
|
485
|
+
imports: options.imports,
|
|
486
|
+
snapshotPath: options.discoverySnapshotPath === void 0 ? "var/discovery-snapshot.json" : options.discoverySnapshotPath
|
|
487
|
+
}),
|
|
488
|
+
AdminModule.forRoot({
|
|
489
|
+
mfaPort: options.adapters.mfa,
|
|
490
|
+
auditPort: options.adapters.audit,
|
|
491
|
+
rlsBypassPort: options.adapters.rlsBypass,
|
|
492
|
+
global: true
|
|
493
|
+
}),
|
|
494
|
+
AdminManifestModule.forRoot({
|
|
495
|
+
config: options.adminManifestConfig ?? buildMinimalManifestConfig(),
|
|
496
|
+
guards: options.controller.guards,
|
|
497
|
+
reloadGuards: options.reloadGuards
|
|
498
|
+
})
|
|
499
|
+
];
|
|
500
|
+
if (options.entitlement) {
|
|
501
|
+
imports.push(EntitlementModule.forRoot({
|
|
502
|
+
subscriptionRepository: options.adapters.subscriptionRepository,
|
|
503
|
+
planVersionRepository: options.adapters.planVersionRepository,
|
|
504
|
+
transactionRunner: options.adapters.transactionRunner,
|
|
505
|
+
resolutionConfig: options.entitlement.resolutionConfig
|
|
506
|
+
}));
|
|
507
|
+
}
|
|
508
|
+
const lightweightProviders = [];
|
|
509
|
+
const lightweightExports = [];
|
|
510
|
+
const hasResolver = !!options.adapters.planResolver;
|
|
511
|
+
const hasFallback = !!options.defaultPlanId;
|
|
512
|
+
if (hasResolver || hasFallback) {
|
|
513
|
+
lightweightProviders.push(hasResolver ? asProvider(PLAN_RESOLVER_PORT_TOKEN, options.adapters.planResolver) : {
|
|
514
|
+
provide: PLAN_RESOLVER_PORT_TOKEN,
|
|
515
|
+
useValue: new StaticPlanResolver(options.defaultPlanId)
|
|
516
|
+
}, StaticEntitlementService, StaticFeatureGuard, EnforceQuotaInterceptor, ...options.quotaProviders ?? [], {
|
|
517
|
+
provide: QUOTA_PROVIDERS_TOKEN,
|
|
518
|
+
useFactory: /* @__PURE__ */ __name((...providers) => providers, "useFactory"),
|
|
519
|
+
inject: options.quotaProviders ?? []
|
|
520
|
+
}, {
|
|
521
|
+
provide: APP_GUARD,
|
|
522
|
+
useExisting: StaticFeatureGuard
|
|
523
|
+
}, {
|
|
524
|
+
provide: APP_INTERCEPTOR,
|
|
525
|
+
useExisting: EnforceQuotaInterceptor
|
|
526
|
+
});
|
|
527
|
+
lightweightExports.push(PLAN_RESOLVER_PORT_TOKEN, StaticEntitlementService, StaticFeatureGuard, EnforceQuotaInterceptor, QUOTA_PROVIDERS_TOKEN);
|
|
528
|
+
}
|
|
529
|
+
const tenantControllers = [];
|
|
530
|
+
if (options.tenantManifest) {
|
|
531
|
+
if (!hasResolver && !hasFallback) {
|
|
532
|
+
throw new Error("SaasPlatformModule.forRoot: tenantManifest erfordert defaultPlanId oder adapters.planResolver, sonst kann das Manifest keine Features aufl\xF6sen.");
|
|
533
|
+
}
|
|
534
|
+
lightweightProviders.push(TenantManifestService);
|
|
535
|
+
lightweightExports.push(TenantManifestService);
|
|
536
|
+
tenantControllers.push(buildTenantManifestController(options.tenantManifest));
|
|
537
|
+
}
|
|
538
|
+
return {
|
|
539
|
+
module: _SaasPlatformModule,
|
|
540
|
+
imports,
|
|
541
|
+
providers: lightweightProviders,
|
|
542
|
+
controllers: tenantControllers,
|
|
543
|
+
exports: [
|
|
544
|
+
PlanCatalogModule,
|
|
545
|
+
DiscoveryModule,
|
|
546
|
+
AdminModule,
|
|
547
|
+
AdminManifestModule,
|
|
548
|
+
...options.entitlement ? [
|
|
549
|
+
EntitlementModule
|
|
550
|
+
] : [],
|
|
551
|
+
ADMIN_MANIFEST_CONFIG,
|
|
552
|
+
...lightweightExports
|
|
553
|
+
],
|
|
554
|
+
global: true
|
|
555
|
+
};
|
|
556
|
+
}
|
|
557
|
+
};
|
|
558
|
+
SaasPlatformModule = _ts_decorate6([
|
|
559
|
+
Module({})
|
|
560
|
+
], SaasPlatformModule);
|
|
561
|
+
|
|
562
|
+
export {
|
|
563
|
+
PLAN_RESOLVER_PORT_TOKEN,
|
|
564
|
+
StaticPlanResolver,
|
|
565
|
+
StaticEntitlementService,
|
|
566
|
+
STATIC_FEATURE_GUARD_CONFIG_TOKEN,
|
|
567
|
+
StaticFeatureGuard,
|
|
568
|
+
QUOTA_PROVIDERS_TOKEN,
|
|
569
|
+
EnforceQuotaInterceptor,
|
|
570
|
+
TenantManifestService,
|
|
571
|
+
buildTenantManifestController,
|
|
572
|
+
SaasPlatformModule
|
|
573
|
+
};
|