@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,326 @@
|
|
|
1
|
+
import {
|
|
2
|
+
PROMO_CODE_REDEMPTION_REPOSITORY_TOKEN,
|
|
3
|
+
PROMO_CODE_REPOSITORY_TOKEN,
|
|
4
|
+
PROMO_CODE_VALIDATION_LOG_REPOSITORY_TOKEN,
|
|
5
|
+
PROMO_FIRST_TIME_CUSTOMER_CHECK_TOKEN,
|
|
6
|
+
PROMO_REVENUE_DEDUCTION_AGGREGATOR_TOKEN,
|
|
7
|
+
PROMO_SERVICE_CONFIG_TOKEN,
|
|
8
|
+
PROMO_SUBSCRIPTION_LOOKUP_TOKEN,
|
|
9
|
+
PROMO_TRANSACTION_RUNNER_TOKEN,
|
|
10
|
+
PromoCodesService
|
|
11
|
+
} from "./chunk-ZL4LLE2Z.js";
|
|
12
|
+
import {
|
|
13
|
+
asProvider
|
|
14
|
+
} from "./chunk-SABTXESR.js";
|
|
15
|
+
import {
|
|
16
|
+
__name
|
|
17
|
+
} from "./chunk-SHUYVCID.js";
|
|
18
|
+
|
|
19
|
+
// src/promo/expirer.ts
|
|
20
|
+
import { Inject, Injectable, Logger } from "@nestjs/common";
|
|
21
|
+
import { Cron, CronExpression } from "@nestjs/schedule";
|
|
22
|
+
function _ts_decorate(decorators, target, key, desc) {
|
|
23
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
24
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
25
|
+
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;
|
|
26
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
27
|
+
}
|
|
28
|
+
__name(_ts_decorate, "_ts_decorate");
|
|
29
|
+
function _ts_metadata(k, v) {
|
|
30
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
31
|
+
}
|
|
32
|
+
__name(_ts_metadata, "_ts_metadata");
|
|
33
|
+
function _ts_param(paramIndex, decorator) {
|
|
34
|
+
return function(target, key) {
|
|
35
|
+
decorator(target, key, paramIndex);
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
__name(_ts_param, "_ts_param");
|
|
39
|
+
var PromoCodeExpirer = class _PromoCodeExpirer {
|
|
40
|
+
static {
|
|
41
|
+
__name(this, "PromoCodeExpirer");
|
|
42
|
+
}
|
|
43
|
+
promoRepo;
|
|
44
|
+
redemptionRepo;
|
|
45
|
+
logger = new Logger(_PromoCodeExpirer.name);
|
|
46
|
+
constructor(promoRepo, redemptionRepo) {
|
|
47
|
+
this.promoRepo = promoRepo;
|
|
48
|
+
this.redemptionRepo = redemptionRepo;
|
|
49
|
+
}
|
|
50
|
+
async expirePromoCodes() {
|
|
51
|
+
const now = /* @__PURE__ */ new Date();
|
|
52
|
+
const codes = await this.promoRepo.expireDueCodes(now);
|
|
53
|
+
const redemptions = await this.redemptionRepo.expireDueRedemptions(now);
|
|
54
|
+
if (codes > 0 || redemptions > 0) {
|
|
55
|
+
this.logger.log(`PromoCodeExpirer: ${codes} Codes, ${redemptions} Redemptions abgelaufen.`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
_ts_decorate([
|
|
60
|
+
Cron(CronExpression.EVERY_DAY_AT_3AM, {
|
|
61
|
+
name: "promoCodeExpirer",
|
|
62
|
+
timeZone: "Europe/Berlin"
|
|
63
|
+
}),
|
|
64
|
+
_ts_metadata("design:type", Function),
|
|
65
|
+
_ts_metadata("design:paramtypes", []),
|
|
66
|
+
_ts_metadata("design:returntype", Promise)
|
|
67
|
+
], PromoCodeExpirer.prototype, "expirePromoCodes", null);
|
|
68
|
+
PromoCodeExpirer = _ts_decorate([
|
|
69
|
+
Injectable(),
|
|
70
|
+
_ts_param(0, Inject(PROMO_CODE_REPOSITORY_TOKEN)),
|
|
71
|
+
_ts_param(1, Inject(PROMO_CODE_REDEMPTION_REPOSITORY_TOKEN)),
|
|
72
|
+
_ts_metadata("design:type", Function),
|
|
73
|
+
_ts_metadata("design:paramtypes", [
|
|
74
|
+
typeof PromoCodeRepository === "undefined" ? Object : PromoCodeRepository,
|
|
75
|
+
typeof PromoCodeRedemptionRepository === "undefined" ? Object : PromoCodeRedemptionRepository
|
|
76
|
+
])
|
|
77
|
+
], PromoCodeExpirer);
|
|
78
|
+
|
|
79
|
+
// src/promo/rate-limit.guard.ts
|
|
80
|
+
import { HttpException, HttpStatus, Injectable as Injectable2 } from "@nestjs/common";
|
|
81
|
+
function _ts_decorate2(decorators, target, key, desc) {
|
|
82
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
83
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
84
|
+
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;
|
|
85
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
86
|
+
}
|
|
87
|
+
__name(_ts_decorate2, "_ts_decorate");
|
|
88
|
+
var IP_WINDOW_MS = 6e4;
|
|
89
|
+
var IP_LIMIT = 20;
|
|
90
|
+
var SESSION_WINDOW_MS = 60 * 6e4;
|
|
91
|
+
var SESSION_LIMIT = 50;
|
|
92
|
+
var PromoCodeRateLimitGuard = class {
|
|
93
|
+
static {
|
|
94
|
+
__name(this, "PromoCodeRateLimitGuard");
|
|
95
|
+
}
|
|
96
|
+
ipBuckets = /* @__PURE__ */ new Map();
|
|
97
|
+
sessionBuckets = /* @__PURE__ */ new Map();
|
|
98
|
+
canActivate(context) {
|
|
99
|
+
const req = context.switchToHttp().getRequest();
|
|
100
|
+
const ipKey = ipFingerprint(req);
|
|
101
|
+
const sessionKey = req.user?.id ?? null;
|
|
102
|
+
if (this.exceeded(this.ipBuckets, ipKey, IP_WINDOW_MS, IP_LIMIT)) {
|
|
103
|
+
throw new HttpException({
|
|
104
|
+
valid: false,
|
|
105
|
+
reason: "RATE_LIMITED"
|
|
106
|
+
}, HttpStatus.TOO_MANY_REQUESTS);
|
|
107
|
+
}
|
|
108
|
+
if (sessionKey && this.exceeded(this.sessionBuckets, sessionKey, SESSION_WINDOW_MS, SESSION_LIMIT)) {
|
|
109
|
+
throw new HttpException({
|
|
110
|
+
valid: false,
|
|
111
|
+
reason: "RATE_LIMITED"
|
|
112
|
+
}, HttpStatus.TOO_MANY_REQUESTS);
|
|
113
|
+
}
|
|
114
|
+
return true;
|
|
115
|
+
}
|
|
116
|
+
exceeded(map, key, windowMs, limit) {
|
|
117
|
+
const now = Date.now();
|
|
118
|
+
const b = map.get(key);
|
|
119
|
+
if (!b || now - b.windowStart > windowMs) {
|
|
120
|
+
map.set(key, {
|
|
121
|
+
count: 1,
|
|
122
|
+
windowStart: now
|
|
123
|
+
});
|
|
124
|
+
return false;
|
|
125
|
+
}
|
|
126
|
+
b.count += 1;
|
|
127
|
+
return b.count > limit;
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
PromoCodeRateLimitGuard = _ts_decorate2([
|
|
131
|
+
Injectable2()
|
|
132
|
+
], PromoCodeRateLimitGuard);
|
|
133
|
+
function ipFingerprint(req) {
|
|
134
|
+
const fwd = req.headers["x-forwarded-for"];
|
|
135
|
+
const first = Array.isArray(fwd) ? fwd[0] : fwd?.split(",")[0]?.trim();
|
|
136
|
+
return first || req.ip || "unknown";
|
|
137
|
+
}
|
|
138
|
+
__name(ipFingerprint, "ipFingerprint");
|
|
139
|
+
function hashIp(req) {
|
|
140
|
+
const fp = ipFingerprint(req);
|
|
141
|
+
let h = 0;
|
|
142
|
+
for (let i = 0; i < fp.length; i++) {
|
|
143
|
+
h = h * 31 + fp.charCodeAt(i) | 0;
|
|
144
|
+
}
|
|
145
|
+
return `ip${(h >>> 0).toString(16)}`;
|
|
146
|
+
}
|
|
147
|
+
__name(hashIp, "hashIp");
|
|
148
|
+
|
|
149
|
+
// src/promo/controller.ts
|
|
150
|
+
import { Body, Controller, HttpCode, HttpStatus as HttpStatus2, Inject as Inject2, Post, Req, UseGuards } from "@nestjs/common";
|
|
151
|
+
|
|
152
|
+
// src/promo/dto/promo-public.dto.ts
|
|
153
|
+
import { IsEmail, IsOptional, IsString, Matches, MaxLength } from "class-validator";
|
|
154
|
+
function _ts_decorate3(decorators, target, key, desc) {
|
|
155
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
156
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
157
|
+
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;
|
|
158
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
159
|
+
}
|
|
160
|
+
__name(_ts_decorate3, "_ts_decorate");
|
|
161
|
+
function _ts_metadata2(k, v) {
|
|
162
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
163
|
+
}
|
|
164
|
+
__name(_ts_metadata2, "_ts_metadata");
|
|
165
|
+
var PLAN_OR_CYCLE_PATTERN = /^[A-Z][A-Z0-9_]*$/;
|
|
166
|
+
var CODE_PATTERN = /^[A-Z0-9_-]{4,32}$/i;
|
|
167
|
+
var PreviewPromoCodeDto = class {
|
|
168
|
+
static {
|
|
169
|
+
__name(this, "PreviewPromoCodeDto");
|
|
170
|
+
}
|
|
171
|
+
code;
|
|
172
|
+
plan;
|
|
173
|
+
billingCycle;
|
|
174
|
+
email;
|
|
175
|
+
};
|
|
176
|
+
_ts_decorate3([
|
|
177
|
+
IsString(),
|
|
178
|
+
Matches(CODE_PATTERN, {
|
|
179
|
+
message: 'code muss aus A\u2013Z, 0\u20139, "-" und "_" bestehen (4\u201332 Zeichen)'
|
|
180
|
+
}),
|
|
181
|
+
_ts_metadata2("design:type", String)
|
|
182
|
+
], PreviewPromoCodeDto.prototype, "code", void 0);
|
|
183
|
+
_ts_decorate3([
|
|
184
|
+
IsString(),
|
|
185
|
+
Matches(PLAN_OR_CYCLE_PATTERN, {
|
|
186
|
+
message: "plan muss SCREAMING_SNAKE_CASE sein"
|
|
187
|
+
}),
|
|
188
|
+
_ts_metadata2("design:type", String)
|
|
189
|
+
], PreviewPromoCodeDto.prototype, "plan", void 0);
|
|
190
|
+
_ts_decorate3([
|
|
191
|
+
IsString(),
|
|
192
|
+
Matches(PLAN_OR_CYCLE_PATTERN, {
|
|
193
|
+
message: "billingCycle muss SCREAMING_SNAKE_CASE sein (z. B. MONTHLY, YEARLY)"
|
|
194
|
+
}),
|
|
195
|
+
_ts_metadata2("design:type", String)
|
|
196
|
+
], PreviewPromoCodeDto.prototype, "billingCycle", void 0);
|
|
197
|
+
_ts_decorate3([
|
|
198
|
+
IsOptional(),
|
|
199
|
+
IsEmail(),
|
|
200
|
+
MaxLength(254),
|
|
201
|
+
_ts_metadata2("design:type", String)
|
|
202
|
+
], PreviewPromoCodeDto.prototype, "email", void 0);
|
|
203
|
+
|
|
204
|
+
// src/promo/controller.ts
|
|
205
|
+
function _ts_decorate4(decorators, target, key, desc) {
|
|
206
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
207
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
208
|
+
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;
|
|
209
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
210
|
+
}
|
|
211
|
+
__name(_ts_decorate4, "_ts_decorate");
|
|
212
|
+
function _ts_metadata3(k, v) {
|
|
213
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
214
|
+
}
|
|
215
|
+
__name(_ts_metadata3, "_ts_metadata");
|
|
216
|
+
function _ts_param2(paramIndex, decorator) {
|
|
217
|
+
return function(target, key) {
|
|
218
|
+
decorator(target, key, paramIndex);
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
__name(_ts_param2, "_ts_param");
|
|
222
|
+
var PromoCodePublicController = class {
|
|
223
|
+
static {
|
|
224
|
+
__name(this, "PromoCodePublicController");
|
|
225
|
+
}
|
|
226
|
+
promo;
|
|
227
|
+
constructor(promo) {
|
|
228
|
+
this.promo = promo;
|
|
229
|
+
}
|
|
230
|
+
async preview(dto, req) {
|
|
231
|
+
return this.promo.preview({
|
|
232
|
+
code: dto.code,
|
|
233
|
+
planId: dto.plan,
|
|
234
|
+
billingCycle: dto.billingCycle,
|
|
235
|
+
email: dto.email,
|
|
236
|
+
ipHash: hashIp(req),
|
|
237
|
+
sessionId: req.user?.id ?? req.user?.sub
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
};
|
|
241
|
+
_ts_decorate4([
|
|
242
|
+
Post("preview"),
|
|
243
|
+
HttpCode(HttpStatus2.OK),
|
|
244
|
+
UseGuards(PromoCodeRateLimitGuard),
|
|
245
|
+
_ts_param2(0, Body()),
|
|
246
|
+
_ts_param2(1, Req()),
|
|
247
|
+
_ts_metadata3("design:type", Function),
|
|
248
|
+
_ts_metadata3("design:paramtypes", [
|
|
249
|
+
typeof PreviewPromoCodeDto === "undefined" ? Object : PreviewPromoCodeDto,
|
|
250
|
+
typeof RequestLike === "undefined" ? Object : RequestLike
|
|
251
|
+
]),
|
|
252
|
+
_ts_metadata3("design:returntype", Promise)
|
|
253
|
+
], PromoCodePublicController.prototype, "preview", null);
|
|
254
|
+
PromoCodePublicController = _ts_decorate4([
|
|
255
|
+
Controller("billing/promo"),
|
|
256
|
+
_ts_param2(0, Inject2(PromoCodesService)),
|
|
257
|
+
_ts_metadata3("design:type", Function),
|
|
258
|
+
_ts_metadata3("design:paramtypes", [
|
|
259
|
+
typeof PromoCodesService === "undefined" ? Object : PromoCodesService
|
|
260
|
+
])
|
|
261
|
+
], PromoCodePublicController);
|
|
262
|
+
|
|
263
|
+
// src/promo/module.ts
|
|
264
|
+
import { Module } from "@nestjs/common";
|
|
265
|
+
function _ts_decorate5(decorators, target, key, desc) {
|
|
266
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
267
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
268
|
+
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;
|
|
269
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
270
|
+
}
|
|
271
|
+
__name(_ts_decorate5, "_ts_decorate");
|
|
272
|
+
var PromoCodesModule = class _PromoCodesModule {
|
|
273
|
+
static {
|
|
274
|
+
__name(this, "PromoCodesModule");
|
|
275
|
+
}
|
|
276
|
+
static forRoot(options) {
|
|
277
|
+
const includeCron = options.includeExpirerCron ?? true;
|
|
278
|
+
const includePublic = options.includePublicController ?? true;
|
|
279
|
+
const providers = [
|
|
280
|
+
asProvider(PROMO_CODE_REPOSITORY_TOKEN, options.promoCodeRepository),
|
|
281
|
+
asProvider(PROMO_CODE_REDEMPTION_REPOSITORY_TOKEN, options.redemptionRepository),
|
|
282
|
+
asProvider(PROMO_CODE_VALIDATION_LOG_REPOSITORY_TOKEN, options.validationLogRepository),
|
|
283
|
+
asProvider(PROMO_FIRST_TIME_CUSTOMER_CHECK_TOKEN, options.firstTimeCustomerCheck),
|
|
284
|
+
asProvider(PROMO_SUBSCRIPTION_LOOKUP_TOKEN, options.subscriptionLookup),
|
|
285
|
+
asProvider(PROMO_REVENUE_DEDUCTION_AGGREGATOR_TOKEN, options.revenueAggregator),
|
|
286
|
+
asProvider(PROMO_TRANSACTION_RUNNER_TOKEN, options.transactionRunner),
|
|
287
|
+
{
|
|
288
|
+
provide: PROMO_SERVICE_CONFIG_TOKEN,
|
|
289
|
+
useValue: options.config ?? {}
|
|
290
|
+
},
|
|
291
|
+
PromoCodesService,
|
|
292
|
+
PromoCodeRateLimitGuard
|
|
293
|
+
];
|
|
294
|
+
if (includeCron) {
|
|
295
|
+
providers.push(PromoCodeExpirer);
|
|
296
|
+
}
|
|
297
|
+
return {
|
|
298
|
+
module: _PromoCodesModule,
|
|
299
|
+
global: options.global ?? false,
|
|
300
|
+
controllers: includePublic ? [
|
|
301
|
+
PromoCodePublicController
|
|
302
|
+
] : [],
|
|
303
|
+
providers,
|
|
304
|
+
exports: [
|
|
305
|
+
PromoCodesService,
|
|
306
|
+
PromoCodeRateLimitGuard,
|
|
307
|
+
PROMO_CODE_REPOSITORY_TOKEN,
|
|
308
|
+
PROMO_CODE_REDEMPTION_REPOSITORY_TOKEN,
|
|
309
|
+
PROMO_CODE_VALIDATION_LOG_REPOSITORY_TOKEN
|
|
310
|
+
]
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
};
|
|
314
|
+
PromoCodesModule = _ts_decorate5([
|
|
315
|
+
Module({})
|
|
316
|
+
], PromoCodesModule);
|
|
317
|
+
|
|
318
|
+
export {
|
|
319
|
+
PromoCodeExpirer,
|
|
320
|
+
PromoCodeRateLimitGuard,
|
|
321
|
+
ipFingerprint,
|
|
322
|
+
hashIp,
|
|
323
|
+
PreviewPromoCodeDto,
|
|
324
|
+
PromoCodePublicController,
|
|
325
|
+
PromoCodesModule
|
|
326
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
// src/entitlement/tokens.ts
|
|
2
|
+
var SUBSCRIPTION_REPOSITORY_TOKEN = /* @__PURE__ */ Symbol.for("saas-platform/SubscriptionRepository");
|
|
3
|
+
var PLAN_VERSION_REPOSITORY_TOKEN = /* @__PURE__ */ Symbol.for("saas-platform/PlanVersionRepository");
|
|
4
|
+
var TRANSACTION_RUNNER_TOKEN = /* @__PURE__ */ Symbol.for("saas-platform/TransactionRunner");
|
|
5
|
+
var ENTITLEMENT_RESOLUTION_CONFIG_TOKEN = /* @__PURE__ */ Symbol.for("saas-platform/EntitlementResolutionConfig");
|
|
6
|
+
|
|
7
|
+
export {
|
|
8
|
+
SUBSCRIPTION_REPOSITORY_TOKEN,
|
|
9
|
+
PLAN_VERSION_REPOSITORY_TOKEN,
|
|
10
|
+
TRANSACTION_RUNNER_TOKEN,
|
|
11
|
+
ENTITLEMENT_RESOLUTION_CONFIG_TOKEN
|
|
12
|
+
};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import {
|
|
2
|
+
__name
|
|
3
|
+
} from "./chunk-SHUYVCID.js";
|
|
4
|
+
|
|
5
|
+
// src/discovery/snapshot-loader.ts
|
|
6
|
+
import { existsSync, readFileSync } from "fs";
|
|
7
|
+
import { resolve as resolvePath } from "path";
|
|
8
|
+
var DiscoverySnapshotNotFoundError = class extends Error {
|
|
9
|
+
static {
|
|
10
|
+
__name(this, "DiscoverySnapshotNotFoundError");
|
|
11
|
+
}
|
|
12
|
+
path;
|
|
13
|
+
constructor(path) {
|
|
14
|
+
super(`Discovery-Snapshot-Datei nicht gefunden: ${path}. Booten Sie zuerst die App mit DISCOVERY_SNAPSHOT_PATH oder DiscoveryModule.forRoot({ snapshotPath: '\u2026' }), damit der Scanner die Datei beim OnApplicationBootstrap-Hook schreibt.`), this.path = path;
|
|
15
|
+
this.name = "DiscoverySnapshotNotFoundError";
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
function loadDiscoverySnapshotFromFile(path) {
|
|
19
|
+
const absolute = resolvePath(path);
|
|
20
|
+
if (!existsSync(absolute)) {
|
|
21
|
+
throw new DiscoverySnapshotNotFoundError(absolute);
|
|
22
|
+
}
|
|
23
|
+
const raw = readFileSync(absolute, "utf-8");
|
|
24
|
+
return JSON.parse(raw);
|
|
25
|
+
}
|
|
26
|
+
__name(loadDiscoverySnapshotFromFile, "loadDiscoverySnapshotFromFile");
|
|
27
|
+
|
|
28
|
+
export {
|
|
29
|
+
DiscoverySnapshotNotFoundError,
|
|
30
|
+
loadDiscoverySnapshotFromFile
|
|
31
|
+
};
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DISCOVERY_APP_INFO_TOKEN,
|
|
3
|
+
DISCOVERY_SNAPSHOT_PATH_TOKEN,
|
|
4
|
+
DiscoveryScanner
|
|
5
|
+
} from "./chunk-M6CZQYPY.js";
|
|
6
|
+
import {
|
|
7
|
+
DISCOVERY_SNAPSHOT_TOKEN
|
|
8
|
+
} from "./chunk-L4SUWH5B.js";
|
|
9
|
+
import {
|
|
10
|
+
__name
|
|
11
|
+
} from "./chunk-SHUYVCID.js";
|
|
12
|
+
|
|
13
|
+
// src/discovery/discovery.controller.ts
|
|
14
|
+
import { Controller, Get, Header, Headers, HttpStatus, Inject, Post, Res, UseGuards } from "@nestjs/common";
|
|
15
|
+
function _ts_decorate(decorators, target, key, desc) {
|
|
16
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
17
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
18
|
+
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;
|
|
19
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
20
|
+
}
|
|
21
|
+
__name(_ts_decorate, "_ts_decorate");
|
|
22
|
+
function _ts_metadata(k, v) {
|
|
23
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
24
|
+
}
|
|
25
|
+
__name(_ts_metadata, "_ts_metadata");
|
|
26
|
+
function _ts_param(paramIndex, decorator) {
|
|
27
|
+
return function(target, key) {
|
|
28
|
+
decorator(target, key, paramIndex);
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
__name(_ts_param, "_ts_param");
|
|
32
|
+
function buildDiscoveryController(guards) {
|
|
33
|
+
let GeneratedDiscoveryController = class GeneratedDiscoveryController {
|
|
34
|
+
static {
|
|
35
|
+
__name(this, "GeneratedDiscoveryController");
|
|
36
|
+
}
|
|
37
|
+
scanner;
|
|
38
|
+
// Explicit @Inject instead of type reflection: tsup/esbuild do not emit
|
|
39
|
+
// any `design:paramtypes` metadata, so otherwise Nest cannot resolve the
|
|
40
|
+
// service type on the constructor.
|
|
41
|
+
constructor(scanner) {
|
|
42
|
+
this.scanner = scanner;
|
|
43
|
+
}
|
|
44
|
+
getDiscovery(ifNoneMatch, res) {
|
|
45
|
+
const snapshot = this.scanner.getSnapshot();
|
|
46
|
+
const etag = `"${snapshot.hash}-${snapshot.scannedAt}"`;
|
|
47
|
+
res.header("ETag", etag);
|
|
48
|
+
if (ifNoneMatch && ifNoneMatch === etag) {
|
|
49
|
+
res.status(HttpStatus.NOT_MODIFIED);
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
return snapshot;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Forces a fresh code scan and returns the new snapshot.
|
|
56
|
+
* `scannedAt` is updated; the Capability/Feature/Quota data
|
|
57
|
+
* are identical within the running process (code is stable at runtime).
|
|
58
|
+
*/
|
|
59
|
+
rescanDiscovery() {
|
|
60
|
+
return this.scanner.rebuildSnapshot();
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
_ts_decorate([
|
|
64
|
+
Get("discovery"),
|
|
65
|
+
Header("Cache-Control", "private, no-cache"),
|
|
66
|
+
_ts_param(0, Headers("if-none-match")),
|
|
67
|
+
_ts_param(1, Res({
|
|
68
|
+
passthrough: true
|
|
69
|
+
})),
|
|
70
|
+
_ts_metadata("design:type", Function),
|
|
71
|
+
_ts_metadata("design:paramtypes", [
|
|
72
|
+
Object,
|
|
73
|
+
typeof HttpResponseLike === "undefined" ? Object : HttpResponseLike
|
|
74
|
+
]),
|
|
75
|
+
_ts_metadata("design:returntype", Object)
|
|
76
|
+
], GeneratedDiscoveryController.prototype, "getDiscovery", null);
|
|
77
|
+
_ts_decorate([
|
|
78
|
+
Post("discovery/rescan"),
|
|
79
|
+
_ts_metadata("design:type", Function),
|
|
80
|
+
_ts_metadata("design:paramtypes", []),
|
|
81
|
+
_ts_metadata("design:returntype", typeof DiscoverySnapshot === "undefined" ? Object : DiscoverySnapshot)
|
|
82
|
+
], GeneratedDiscoveryController.prototype, "rescanDiscovery", null);
|
|
83
|
+
GeneratedDiscoveryController = _ts_decorate([
|
|
84
|
+
Controller("admin"),
|
|
85
|
+
UseGuards(...guards),
|
|
86
|
+
_ts_param(0, Inject(DiscoveryScanner)),
|
|
87
|
+
_ts_metadata("design:type", Function),
|
|
88
|
+
_ts_metadata("design:paramtypes", [
|
|
89
|
+
typeof DiscoveryScanner === "undefined" ? Object : DiscoveryScanner
|
|
90
|
+
])
|
|
91
|
+
], GeneratedDiscoveryController);
|
|
92
|
+
return GeneratedDiscoveryController;
|
|
93
|
+
}
|
|
94
|
+
__name(buildDiscoveryController, "buildDiscoveryController");
|
|
95
|
+
|
|
96
|
+
// src/discovery/discovery.module.ts
|
|
97
|
+
import { Module } from "@nestjs/common";
|
|
98
|
+
import { DiscoveryModule as NestDiscoveryModule } from "@nestjs/core";
|
|
99
|
+
function _ts_decorate2(decorators, target, key, desc) {
|
|
100
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
101
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
102
|
+
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;
|
|
103
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
104
|
+
}
|
|
105
|
+
__name(_ts_decorate2, "_ts_decorate");
|
|
106
|
+
var DiscoveryModule = class _DiscoveryModule {
|
|
107
|
+
static {
|
|
108
|
+
__name(this, "DiscoveryModule");
|
|
109
|
+
}
|
|
110
|
+
static forRoot(options) {
|
|
111
|
+
const isGlobal = options.isGlobal ?? true;
|
|
112
|
+
const controllers = [];
|
|
113
|
+
if (options.controller) {
|
|
114
|
+
controllers.push(buildDiscoveryController(options.controller.guards));
|
|
115
|
+
}
|
|
116
|
+
const providers = [
|
|
117
|
+
{
|
|
118
|
+
provide: DISCOVERY_APP_INFO_TOKEN,
|
|
119
|
+
useValue: options.app
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
provide: DISCOVERY_SNAPSHOT_PATH_TOKEN,
|
|
123
|
+
useValue: options.snapshotPath ?? null
|
|
124
|
+
},
|
|
125
|
+
DiscoveryScanner,
|
|
126
|
+
{
|
|
127
|
+
provide: DISCOVERY_SNAPSHOT_TOKEN,
|
|
128
|
+
useFactory: /* @__PURE__ */ __name((scanner) => scanner.getSnapshot(), "useFactory"),
|
|
129
|
+
inject: [
|
|
130
|
+
DiscoveryScanner
|
|
131
|
+
]
|
|
132
|
+
}
|
|
133
|
+
];
|
|
134
|
+
return {
|
|
135
|
+
module: _DiscoveryModule,
|
|
136
|
+
imports: [
|
|
137
|
+
NestDiscoveryModule,
|
|
138
|
+
...options.imports ?? []
|
|
139
|
+
],
|
|
140
|
+
controllers,
|
|
141
|
+
providers,
|
|
142
|
+
exports: [
|
|
143
|
+
DiscoveryScanner,
|
|
144
|
+
DISCOVERY_SNAPSHOT_TOKEN
|
|
145
|
+
],
|
|
146
|
+
global: isGlobal
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
DiscoveryModule = _ts_decorate2([
|
|
151
|
+
Module({})
|
|
152
|
+
], DiscoveryModule);
|
|
153
|
+
|
|
154
|
+
export {
|
|
155
|
+
buildDiscoveryController,
|
|
156
|
+
DiscoveryModule
|
|
157
|
+
};
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import {
|
|
2
|
+
__name
|
|
3
|
+
} from "./chunk-SHUYVCID.js";
|
|
4
|
+
|
|
5
|
+
// src/admin/tokens.ts
|
|
6
|
+
var MFA_PORT_TOKEN = /* @__PURE__ */ Symbol.for("saas-platform/MfaPort");
|
|
7
|
+
var AUDIT_PORT_TOKEN = /* @__PURE__ */ Symbol.for("saas-platform/AuditPort");
|
|
8
|
+
var RLS_BYPASS_PORT_TOKEN = /* @__PURE__ */ Symbol.for("saas-platform/RlsBypassPort");
|
|
9
|
+
|
|
10
|
+
// src/admin/admin-audit.service.ts
|
|
11
|
+
import * as os from "os";
|
|
12
|
+
import { Inject, Injectable } from "@nestjs/common";
|
|
13
|
+
function _ts_decorate(decorators, target, key, desc) {
|
|
14
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
15
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
16
|
+
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;
|
|
17
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
18
|
+
}
|
|
19
|
+
__name(_ts_decorate, "_ts_decorate");
|
|
20
|
+
function _ts_metadata(k, v) {
|
|
21
|
+
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
|
22
|
+
}
|
|
23
|
+
__name(_ts_metadata, "_ts_metadata");
|
|
24
|
+
function _ts_param(paramIndex, decorator) {
|
|
25
|
+
return function(target, key) {
|
|
26
|
+
decorator(target, key, paramIndex);
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
__name(_ts_param, "_ts_param");
|
|
30
|
+
var AdminAuditService = class {
|
|
31
|
+
static {
|
|
32
|
+
__name(this, "AdminAuditService");
|
|
33
|
+
}
|
|
34
|
+
audit;
|
|
35
|
+
constructor(audit) {
|
|
36
|
+
this.audit = audit;
|
|
37
|
+
}
|
|
38
|
+
async log(input) {
|
|
39
|
+
await this.audit.write({
|
|
40
|
+
actor: input.actor,
|
|
41
|
+
entity: input.entity,
|
|
42
|
+
entityId: input.entityId,
|
|
43
|
+
action: input.action,
|
|
44
|
+
changes: {
|
|
45
|
+
...input.changes ?? {},
|
|
46
|
+
actor: this.actorTag(input.actor)
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Standardized actor tag for the `changes.actor` column:
|
|
52
|
+
* `<source>:<email>:<context>`.
|
|
53
|
+
*/
|
|
54
|
+
actorTag(actor) {
|
|
55
|
+
return `${actor.source}:${actor.email}:${actor.context}`;
|
|
56
|
+
}
|
|
57
|
+
/** Helper: build an AdminActor from an authenticated web request. */
|
|
58
|
+
fromWebRequest(user, sessionId) {
|
|
59
|
+
return {
|
|
60
|
+
userId: user.id,
|
|
61
|
+
email: user.email,
|
|
62
|
+
source: "web",
|
|
63
|
+
context: sessionId ?? "unknown"
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
/** Helper: build an AdminActor from a CLI identity (hostname as context). */
|
|
67
|
+
fromCli(user) {
|
|
68
|
+
return {
|
|
69
|
+
userId: user.id,
|
|
70
|
+
email: user.email,
|
|
71
|
+
source: "cli",
|
|
72
|
+
context: os.hostname()
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
AdminAuditService = _ts_decorate([
|
|
77
|
+
Injectable(),
|
|
78
|
+
_ts_param(0, Inject(AUDIT_PORT_TOKEN)),
|
|
79
|
+
_ts_metadata("design:type", Function),
|
|
80
|
+
_ts_metadata("design:paramtypes", [
|
|
81
|
+
typeof AuditPort === "undefined" ? Object : AuditPort
|
|
82
|
+
])
|
|
83
|
+
], AdminAuditService);
|
|
84
|
+
|
|
85
|
+
export {
|
|
86
|
+
MFA_PORT_TOKEN,
|
|
87
|
+
AUDIT_PORT_TOKEN,
|
|
88
|
+
RLS_BYPASS_PORT_TOKEN,
|
|
89
|
+
AdminAuditService
|
|
90
|
+
};
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import {
|
|
2
|
+
DiscoveryScanner
|
|
3
|
+
} from "./chunk-M6CZQYPY.js";
|
|
4
|
+
import {
|
|
5
|
+
DEFINES_QUOTA_KEY,
|
|
6
|
+
DISCOVERY_SNAPSHOT_TOKEN,
|
|
7
|
+
ENFORCE_QUOTA_KEY,
|
|
8
|
+
IMPLEMENTS_CAPABILITY_KEY,
|
|
9
|
+
REQUIRES_CAPABILITY_KEY
|
|
10
|
+
} from "./chunk-L4SUWH5B.js";
|
|
11
|
+
import {
|
|
12
|
+
__name
|
|
13
|
+
} from "./chunk-SHUYVCID.js";
|
|
14
|
+
|
|
15
|
+
// src/discovery/decorators.ts
|
|
16
|
+
import { SetMetadata } from "@nestjs/common";
|
|
17
|
+
var ImplementsCapability = /* @__PURE__ */ __name((capabilityKey, options = {}) => SetMetadata(IMPLEMENTS_CAPABILITY_KEY, {
|
|
18
|
+
capabilityKey,
|
|
19
|
+
...options
|
|
20
|
+
}), "ImplementsCapability");
|
|
21
|
+
var RequiresCapability = /* @__PURE__ */ __name((...capabilityKeys) => SetMetadata(REQUIRES_CAPABILITY_KEY, capabilityKeys), "RequiresCapability");
|
|
22
|
+
var DefinesQuota = /* @__PURE__ */ __name((options) => SetMetadata(DEFINES_QUOTA_KEY, options), "DefinesQuota");
|
|
23
|
+
var EnforceQuota = /* @__PURE__ */ __name((quotaKey, options = {}) => SetMetadata(ENFORCE_QUOTA_KEY, {
|
|
24
|
+
quotaKey,
|
|
25
|
+
incrementBy: options.incrementBy ?? 1,
|
|
26
|
+
timing: options.timing ?? "before"
|
|
27
|
+
}), "EnforceQuota");
|
|
28
|
+
|
|
29
|
+
// src/discovery/headless-scan.ts
|
|
30
|
+
import { NestFactory } from "@nestjs/core";
|
|
31
|
+
async function runHeadlessDiscoveryScan(appModule, options = {}) {
|
|
32
|
+
const exit = options.exit ?? ((code) => process.exit(code));
|
|
33
|
+
try {
|
|
34
|
+
const app = await NestFactory.createApplicationContext(appModule, {
|
|
35
|
+
logger: options.logger ?? [
|
|
36
|
+
"error",
|
|
37
|
+
"warn",
|
|
38
|
+
"log"
|
|
39
|
+
]
|
|
40
|
+
});
|
|
41
|
+
try {
|
|
42
|
+
return resolveSnapshotFromContext(app);
|
|
43
|
+
} finally {
|
|
44
|
+
await app.close();
|
|
45
|
+
}
|
|
46
|
+
} catch (err) {
|
|
47
|
+
console.error("[discovery-scan] FEHLER:", err instanceof Error ? err.message : err);
|
|
48
|
+
return exit(4);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
__name(runHeadlessDiscoveryScan, "runHeadlessDiscoveryScan");
|
|
52
|
+
function resolveSnapshotFromContext(app) {
|
|
53
|
+
try {
|
|
54
|
+
return app.get(DISCOVERY_SNAPSHOT_TOKEN, {
|
|
55
|
+
strict: false
|
|
56
|
+
});
|
|
57
|
+
} catch {
|
|
58
|
+
return app.get(DiscoveryScanner, {
|
|
59
|
+
strict: false
|
|
60
|
+
}).getSnapshot();
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
__name(resolveSnapshotFromContext, "resolveSnapshotFromContext");
|
|
64
|
+
|
|
65
|
+
export {
|
|
66
|
+
ImplementsCapability,
|
|
67
|
+
RequiresCapability,
|
|
68
|
+
DefinesQuota,
|
|
69
|
+
EnforceQuota,
|
|
70
|
+
runHeadlessDiscoveryScan
|
|
71
|
+
};
|