@saasicat/cli 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/dist/index.cjs ADDED
@@ -0,0 +1,2284 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
9
+ var __export = (target, all) => {
10
+ for (var name in all)
11
+ __defProp(target, name, { get: all[name], enumerable: true });
12
+ };
13
+ var __copyProps = (to, from, except, desc) => {
14
+ if (from && typeof from === "object" || typeof from === "function") {
15
+ for (let key of __getOwnPropNames(from))
16
+ if (!__hasOwnProp.call(to, key) && key !== except)
17
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
18
+ }
19
+ return to;
20
+ };
21
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
22
+ // If the importer is in node compatibility mode or this is not an ESM
23
+ // file that has been converted to a CommonJS file using a Babel-
24
+ // compatible transform (i.e. "__esModule" has not been set), then set
25
+ // "default" to the CommonJS "module.exports" for node compatibility.
26
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
27
+ mod
28
+ ));
29
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
30
+
31
+ // src/index.ts
32
+ var index_exports = {};
33
+ __export(index_exports, {
34
+ AUDIT_QUERY_PORT_TOKEN: () => AUDIT_QUERY_PORT_TOKEN,
35
+ AdminCommands: () => AdminCommands,
36
+ AdminManifestDoctorCheck: () => AdminManifestDoctorCheck,
37
+ AdminMfaSetupCommand: () => AdminMfaSetupCommand,
38
+ AdminWhoamiCommand: () => AdminWhoamiCommand,
39
+ AuditCommands: () => AuditCommands,
40
+ AuditTailCommand: () => AuditTailCommand,
41
+ AuditTailFlow: () => AuditTailFlow,
42
+ CLI_CONTEXT_CONFIG_TOKEN: () => CLI_CONTEXT_CONFIG_TOKEN,
43
+ CliContextModule: () => CliContextModule,
44
+ CliContextService: () => CliContextService,
45
+ CliError: () => CliError,
46
+ DEFAULT_MANIFEST_CHECKS: () => DEFAULT_MANIFEST_CHECKS,
47
+ DOCTOR_CHECKS_TOKEN: () => DOCTOR_CHECKS_TOKEN,
48
+ DiscoveryCommands: () => DiscoveryCommands,
49
+ DiscoveryScanCommand: () => DiscoveryScanCommand,
50
+ DiscoverySnapshotDoctorCheck: () => DiscoverySnapshotDoctorCheck,
51
+ DoctorCommands: () => DoctorCommands,
52
+ DoctorFlow: () => DoctorFlow,
53
+ MANIFEST_ACCESS_PORT_TOKEN: () => MANIFEST_ACCESS_PORT_TOKEN,
54
+ MANIFEST_CHECKS_TOKEN: () => MANIFEST_CHECKS_TOKEN,
55
+ ManifestCheckCommand: () => ManifestCheckCommand,
56
+ ManifestCliFlow: () => ManifestCliFlow,
57
+ ManifestCommands: () => ManifestCommands,
58
+ ManifestDumpCommand: () => ManifestDumpCommand,
59
+ ManifestHashCommand: () => ManifestHashCommand,
60
+ ManifestValidateCommand: () => ManifestValidateCommand,
61
+ MfaSetupFlow: () => MfaSetupFlow,
62
+ PLATFORM_DOCTOR_CHECK_PROVIDERS: () => PLATFORM_DOCTOR_CHECK_PROVIDERS,
63
+ PlanCatalogDoctorCheck: () => PlanCatalogDoctorCheck,
64
+ USER_MANAGEMENT_PORT_TOKEN: () => USER_MANAGEMENT_PORT_TOKEN,
65
+ USER_PORT_TOKEN: () => USER_PORT_TOKEN,
66
+ UserCommands: () => UserCommands,
67
+ UserPortDoctorCheck: () => UserPortDoctorCheck,
68
+ WhoAmIFlow: () => WhoAmIFlow,
69
+ applyFragmentBlocks: () => applyFragmentBlocks,
70
+ extractModelBlocks: () => extractModelBlocks,
71
+ extractModelNames: () => extractModelNames
72
+ });
73
+ module.exports = __toCommonJS(index_exports);
74
+
75
+ // src/tokens.ts
76
+ var CLI_CONTEXT_CONFIG_TOKEN = /* @__PURE__ */ Symbol.for("saas-platform-cli/Config");
77
+ var USER_PORT_TOKEN = /* @__PURE__ */ Symbol.for("saas-platform-cli/UserPort");
78
+ var USER_MANAGEMENT_PORT_TOKEN = /* @__PURE__ */ Symbol.for("saas-platform-cli/UserManagementPort");
79
+ var AUDIT_QUERY_PORT_TOKEN = /* @__PURE__ */ Symbol.for("saas-platform-cli/AuditQueryPort");
80
+ var DOCTOR_CHECKS_TOKEN = /* @__PURE__ */ Symbol.for("saas-platform-cli/DoctorChecks");
81
+ var MANIFEST_ACCESS_PORT_TOKEN = /* @__PURE__ */ Symbol.for("saas-platform-cli/ManifestAccessPort");
82
+ var MANIFEST_CHECKS_TOKEN = /* @__PURE__ */ Symbol.for("saas-platform-cli/ManifestChecks");
83
+
84
+ // src/cli-context.service.ts
85
+ var os = __toESM(require("os"), 1);
86
+ var readline = __toESM(require("readline"), 1);
87
+ var import_common = require("@nestjs/common");
88
+ var import_nest = require("@saasicat/nest");
89
+ function _ts_decorate(decorators, target, key, desc) {
90
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
91
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
92
+ 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;
93
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
94
+ }
95
+ __name(_ts_decorate, "_ts_decorate");
96
+ function _ts_metadata(k, v) {
97
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
98
+ }
99
+ __name(_ts_metadata, "_ts_metadata");
100
+ function _ts_param(paramIndex, decorator) {
101
+ return function(target, key) {
102
+ decorator(target, key, paramIndex);
103
+ };
104
+ }
105
+ __name(_ts_param, "_ts_param");
106
+ var CliContextService = class {
107
+ static {
108
+ __name(this, "CliContextService");
109
+ }
110
+ config;
111
+ users;
112
+ mfa;
113
+ audit;
114
+ constructor(config, users, mfa, audit) {
115
+ this.config = config;
116
+ this.users = users;
117
+ this.mfa = mfa;
118
+ this.audit = audit;
119
+ }
120
+ // ---------------------------------------------------------------------
121
+ // §1 Identity
122
+ // ---------------------------------------------------------------------
123
+ resolveIdentity(asFlag) {
124
+ const fromEnv = process.env[this.config.adminEmailEnvVar] ?? "";
125
+ const email = (asFlag ?? fromEnv).trim().toLowerCase();
126
+ if (!email) {
127
+ throw new CliError("NO_IDENTITY", `Keine Admin-Identit\xE4t gesetzt. Bitte $${this.config.adminEmailEnvVar} setzen oder --as <email> \xFCbergeben.`, 2);
128
+ }
129
+ const host = os.hostname();
130
+ return {
131
+ email,
132
+ host,
133
+ actor: `cli:${email}:${host}`
134
+ };
135
+ }
136
+ /**
137
+ * Loads + validates the user for a CLI identity:
138
+ * - user exists + active
139
+ * - user has platform role SUPER_ADMIN
140
+ *
141
+ * Throws `CliError(NOT_SUPER_ADMIN, exit=2)` otherwise.
142
+ */
143
+ async ensureSuperAdmin(identity) {
144
+ const user = await this.users.findByEmail(identity.email);
145
+ if (!user || user.deletedAt || !user.isActive) {
146
+ throw new CliError("USER_NOT_FOUND", `SUPER_ADMIN-User ${identity.email} nicht gefunden oder inaktiv.`, 2);
147
+ }
148
+ if (user.platformRole !== "SUPER_ADMIN") {
149
+ throw new CliError("NOT_SUPER_ADMIN", `User ${identity.email} hat Rolle ${user.platformRole} \u2014 nur SUPER_ADMIN darf das CLI nutzen.`, 2);
150
+ }
151
+ return user;
152
+ }
153
+ // ---------------------------------------------------------------------
154
+ // §2 MFA — mandatory TOTP
155
+ // ---------------------------------------------------------------------
156
+ /**
157
+ * Prompts the user for a TOTP code and verifies it against the stored
158
+ * secret (via the platform `MfaService` → `MfaPort`).
159
+ *
160
+ * Bypass: `process.env[mfaSkipEnvVar] === '1'` AND `!isProductionEnvironment()`.
161
+ */
162
+ async requireMfa(userId) {
163
+ if (process.env[this.config.mfaSkipEnvVar] === "1" && !this.config.isProductionEnvironment()) {
164
+ return;
165
+ }
166
+ const enabled = await this.mfa.isEnabled(userId);
167
+ if (!enabled) {
168
+ throw new CliError("MFA_NOT_SET_UP", "MFA ist nicht konfiguriert. Bitte zuerst 'admin mfa-setup' ausf\xFChren.", 3);
169
+ }
170
+ const code = await this.prompt("TOTP-Code: ");
171
+ const ok2 = await this.mfa.verify({
172
+ userId,
173
+ code
174
+ });
175
+ if (!ok2) {
176
+ throw new CliError("MFA_FAILED", "TOTP-Code ung\xFCltig.", 3);
177
+ }
178
+ }
179
+ // ---------------------------------------------------------------------
180
+ // §3 Production confirmation
181
+ // ---------------------------------------------------------------------
182
+ async ensureProductionConfirmation(opts = {}) {
183
+ if (!this.config.isProductionEnvironment()) return;
184
+ if (opts.yes) return;
185
+ const answer = await this.prompt("Tippe production zur Best\xE4tigung: ");
186
+ if (answer.trim().toLowerCase() !== "production") {
187
+ throw new CliError("PRODUCTION_CONFIRM_ABORTED", "Production-Confirmation abgebrochen.", 1);
188
+ }
189
+ }
190
+ // ---------------------------------------------------------------------
191
+ // §5 Audit
192
+ // ---------------------------------------------------------------------
193
+ /**
194
+ * Writes an audit-log entry with the CLI actor tag. Wrapper over
195
+ * `AdminAuditService.log` with automatic `fromCli` construction.
196
+ */
197
+ async log(input) {
198
+ const actor = this.audit.fromCli({
199
+ id: input.userId,
200
+ email: input.identity.email
201
+ });
202
+ await this.audit.log({
203
+ actor,
204
+ entity: input.entity,
205
+ entityId: input.entityId,
206
+ action: input.action,
207
+ changes: input.changes
208
+ });
209
+ }
210
+ // ---------------------------------------------------------------------
211
+ // Output helpers (§4)
212
+ // ---------------------------------------------------------------------
213
+ table(rows) {
214
+ if (rows.length === 0) {
215
+ console.log("\u2014 keine Eintr\xE4ge \u2014");
216
+ return;
217
+ }
218
+ console.table(rows);
219
+ }
220
+ /**
221
+ * Reads a line from stdin. Override hook for tests: set
222
+ * `process.env.SAAS_PLATFORM_CLI_PROMPT_REPLY` to a reply, then
223
+ * the method succeeds without interaction.
224
+ */
225
+ async prompt(question) {
226
+ const testReply = process.env.SAAS_PLATFORM_CLI_PROMPT_REPLY;
227
+ if (testReply !== void 0) return testReply;
228
+ const rl = readline.createInterface({
229
+ input: process.stdin,
230
+ output: process.stdout
231
+ });
232
+ return new Promise((resolve) => {
233
+ rl.question(question, (answer) => {
234
+ rl.close();
235
+ resolve(answer);
236
+ });
237
+ });
238
+ }
239
+ };
240
+ CliContextService = _ts_decorate([
241
+ (0, import_common.Injectable)(),
242
+ _ts_param(0, (0, import_common.Inject)(CLI_CONTEXT_CONFIG_TOKEN)),
243
+ _ts_param(1, (0, import_common.Inject)(USER_PORT_TOKEN)),
244
+ _ts_metadata("design:type", Function),
245
+ _ts_metadata("design:paramtypes", [
246
+ typeof CliContextConfig === "undefined" ? Object : CliContextConfig,
247
+ typeof UserPort === "undefined" ? Object : UserPort,
248
+ typeof import_nest.MfaService === "undefined" ? Object : import_nest.MfaService,
249
+ typeof import_nest.AdminAuditService === "undefined" ? Object : import_nest.AdminAuditService
250
+ ])
251
+ ], CliContextService);
252
+ var CliError = class extends Error {
253
+ static {
254
+ __name(this, "CliError");
255
+ }
256
+ code;
257
+ exitCode;
258
+ constructor(code, message, exitCode) {
259
+ super(message), this.code = code, this.exitCode = exitCode;
260
+ this.name = "CliError";
261
+ }
262
+ };
263
+
264
+ // src/mfa-setup-flow.ts
265
+ var import_common2 = require("@nestjs/common");
266
+ var import_nest2 = require("@saasicat/nest");
267
+ function _ts_decorate2(decorators, target, key, desc) {
268
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
269
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
270
+ 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;
271
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
272
+ }
273
+ __name(_ts_decorate2, "_ts_decorate");
274
+ function _ts_metadata2(k, v) {
275
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
276
+ }
277
+ __name(_ts_metadata2, "_ts_metadata");
278
+ var MfaSetupFlow = class {
279
+ static {
280
+ __name(this, "MfaSetupFlow");
281
+ }
282
+ ctx;
283
+ mfa;
284
+ constructor(ctx, mfa) {
285
+ this.ctx = ctx;
286
+ this.mfa = mfa;
287
+ }
288
+ /**
289
+ * Runs the full setup flow. Throws `CliError` subclasses on
290
+ * auth/identity/confirmation errors.
291
+ */
292
+ async run(options) {
293
+ const identity = this.ctx.resolveIdentity(options.asFlag);
294
+ const user = await this.ctx.ensureSuperAdmin(identity);
295
+ const alreadyEnabled = await this.mfa.isEnabled(user.id);
296
+ if (alreadyEnabled && !options.force) {
297
+ const answer = await this.ctx.prompt("MFA ist bereits konfiguriert. Tippe `yes`, um das Secret zu \xFCberschreiben: ");
298
+ if (answer.trim().toLowerCase() !== "yes") {
299
+ throw new CliError("MFA_SETUP_ABORTED", "Re-Setup nicht best\xE4tigt \u2014 bestehendes Secret bleibt aktiv.", 1);
300
+ }
301
+ }
302
+ const setup = await this.mfa.setup(user.id, user.email, options.issuer);
303
+ await this.ctx.log({
304
+ identity,
305
+ userId: user.id,
306
+ entity: "User",
307
+ entityId: user.id,
308
+ action: alreadyEnabled ? "MFA_SETUP_RESET" : "MFA_SETUP_COMPLETED",
309
+ changes: {
310
+ issuer: options.issuer
311
+ }
312
+ });
313
+ return {
314
+ secret: setup.secret,
315
+ otpauthUri: setup.otpauthUri,
316
+ userId: user.id,
317
+ userEmail: user.email
318
+ };
319
+ }
320
+ /**
321
+ * Helper: returns a human-readable output block with secret + otpauthUri
322
+ * for `console.log` in the consumer command. Consumers may prepend their
323
+ * own QR-code renderer (e.g. `qrcode-terminal`).
324
+ */
325
+ formatSetupResult(result) {
326
+ return [
327
+ `MFA-Setup f\xFCr ${result.userEmail} abgeschlossen.`,
328
+ "",
329
+ `Secret (Base32): ${result.secret}`,
330
+ `otpauth-URI: ${result.otpauthUri}`,
331
+ "",
332
+ "Bitte den otpauth-URI in den Authenticator (Google Authenticator,",
333
+ "1Password, \u2026) importieren oder als QR-Code in einem QR-Generator",
334
+ "rendern. Danach mit dem ersten TOTP-Code testen, dass der Login",
335
+ "funktioniert \u2014 sonst kommst du nicht mehr ans CLI."
336
+ ].join("\n");
337
+ }
338
+ };
339
+ MfaSetupFlow = _ts_decorate2([
340
+ (0, import_common2.Injectable)(),
341
+ _ts_metadata2("design:type", Function),
342
+ _ts_metadata2("design:paramtypes", [
343
+ typeof CliContextService === "undefined" ? Object : CliContextService,
344
+ typeof import_nest2.MfaService === "undefined" ? Object : import_nest2.MfaService
345
+ ])
346
+ ], MfaSetupFlow);
347
+
348
+ // src/whoami-flow.ts
349
+ var import_common3 = require("@nestjs/common");
350
+ var import_nest3 = require("@saasicat/nest");
351
+ function _ts_decorate3(decorators, target, key, desc) {
352
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
353
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
354
+ 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;
355
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
356
+ }
357
+ __name(_ts_decorate3, "_ts_decorate");
358
+ function _ts_metadata3(k, v) {
359
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
360
+ }
361
+ __name(_ts_metadata3, "_ts_metadata");
362
+ function _ts_param2(paramIndex, decorator) {
363
+ return function(target, key) {
364
+ decorator(target, key, paramIndex);
365
+ };
366
+ }
367
+ __name(_ts_param2, "_ts_param");
368
+ var WhoAmIFlow = class {
369
+ static {
370
+ __name(this, "WhoAmIFlow");
371
+ }
372
+ config;
373
+ ctx;
374
+ mfa;
375
+ constructor(config, ctx, mfa) {
376
+ this.config = config;
377
+ this.ctx = ctx;
378
+ this.mfa = mfa;
379
+ }
380
+ async run(asFlag) {
381
+ const identity = this.ctx.resolveIdentity(asFlag);
382
+ const isProduction = this.config.isProductionEnvironment();
383
+ const mfaSkipActive = !isProduction && process.env[this.config.mfaSkipEnvVar] === "1";
384
+ let userId = null;
385
+ let isSuperAdmin = false;
386
+ let mfaEnabled = false;
387
+ try {
388
+ const user = await this.ctx.ensureSuperAdmin(identity);
389
+ userId = user.id;
390
+ isSuperAdmin = true;
391
+ mfaEnabled = await this.mfa.isEnabled(user.id);
392
+ } catch {
393
+ }
394
+ return {
395
+ email: identity.email,
396
+ host: identity.host,
397
+ actor: identity.actor,
398
+ userId,
399
+ isSuperAdmin,
400
+ mfaEnabled,
401
+ isProduction,
402
+ mfaSkipActive
403
+ };
404
+ }
405
+ formatResult(r) {
406
+ const lines = [
407
+ `Identit\xE4t: ${r.email}`,
408
+ `Host: ${r.host}`,
409
+ `Actor-Tag: ${r.actor}`,
410
+ `User-ID: ${r.userId ?? "\u2014 (User nicht gefunden)"}`,
411
+ `Plattform-Rolle: ${r.isSuperAdmin ? "SUPER_ADMIN \u2713" : "\u2014 (kein SUPER_ADMIN!)"}`,
412
+ `MFA konfiguriert: ${r.mfaEnabled ? "\u2713" : "\u2717 \u2014 bitte `admin mfa-setup` ausf\xFChren"}`,
413
+ `Environment: ${r.isProduction ? "PRODUCTION" : "non-production"}`
414
+ ];
415
+ if (r.mfaSkipActive) {
416
+ lines.push("\u26A0 MFA-Bypass aktiv (SKIP-Env-Var gesetzt, non-prod)");
417
+ }
418
+ return lines.join("\n");
419
+ }
420
+ };
421
+ WhoAmIFlow = _ts_decorate3([
422
+ (0, import_common3.Injectable)(),
423
+ _ts_param2(0, (0, import_common3.Inject)(CLI_CONTEXT_CONFIG_TOKEN)),
424
+ _ts_metadata3("design:type", Function),
425
+ _ts_metadata3("design:paramtypes", [
426
+ typeof CliContextConfig === "undefined" ? Object : CliContextConfig,
427
+ typeof CliContextService === "undefined" ? Object : CliContextService,
428
+ typeof import_nest3.MfaService === "undefined" ? Object : import_nest3.MfaService
429
+ ])
430
+ ], WhoAmIFlow);
431
+
432
+ // src/audit-tail-flow.ts
433
+ var import_common4 = require("@nestjs/common");
434
+ function _ts_decorate4(decorators, target, key, desc) {
435
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
436
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
437
+ 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;
438
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
439
+ }
440
+ __name(_ts_decorate4, "_ts_decorate");
441
+ function _ts_metadata4(k, v) {
442
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
443
+ }
444
+ __name(_ts_metadata4, "_ts_metadata");
445
+ function _ts_param3(paramIndex, decorator) {
446
+ return function(target, key) {
447
+ decorator(target, key, paramIndex);
448
+ };
449
+ }
450
+ __name(_ts_param3, "_ts_param");
451
+ var AuditTailFlow = class {
452
+ static {
453
+ __name(this, "AuditTailFlow");
454
+ }
455
+ auditQuery;
456
+ constructor(auditQuery) {
457
+ this.auditQuery = auditQuery;
458
+ }
459
+ async run(options = {}) {
460
+ const filter = {};
461
+ if (options.actor) filter.actorTag = options.actor;
462
+ if (options.action) filter.action = options.action;
463
+ if (options.entity) filter.entity = options.entity;
464
+ if (options.since) filter.from = options.since;
465
+ if (options.limit) filter.pageSize = options.limit;
466
+ return this.auditQuery.list(filter);
467
+ }
468
+ /** Format the result as an ASCII table for `console.table`. */
469
+ formatRows(entries) {
470
+ return entries.map((e) => ({
471
+ createdAt: e.createdAt,
472
+ actor: e.actorTag ?? "\u2014",
473
+ entity: e.entity,
474
+ entityId: this.truncate(e.entityId, 12),
475
+ action: e.action
476
+ }));
477
+ }
478
+ truncate(s, maxLen) {
479
+ return s.length > maxLen ? s.slice(0, maxLen - 1) + "\u2026" : s;
480
+ }
481
+ };
482
+ AuditTailFlow = _ts_decorate4([
483
+ (0, import_common4.Injectable)(),
484
+ _ts_param3(0, (0, import_common4.Inject)(AUDIT_QUERY_PORT_TOKEN)),
485
+ _ts_metadata4("design:type", Function),
486
+ _ts_metadata4("design:paramtypes", [
487
+ typeof AuditQueryPort === "undefined" ? Object : AuditQueryPort
488
+ ])
489
+ ], AuditTailFlow);
490
+
491
+ // src/doctor-flow.ts
492
+ var import_common5 = require("@nestjs/common");
493
+ function _ts_decorate5(decorators, target, key, desc) {
494
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
495
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
496
+ 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;
497
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
498
+ }
499
+ __name(_ts_decorate5, "_ts_decorate");
500
+ function _ts_metadata5(k, v) {
501
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
502
+ }
503
+ __name(_ts_metadata5, "_ts_metadata");
504
+ function _ts_param4(paramIndex, decorator) {
505
+ return function(target, key) {
506
+ decorator(target, key, paramIndex);
507
+ };
508
+ }
509
+ __name(_ts_param4, "_ts_param");
510
+ var DoctorFlow = class {
511
+ static {
512
+ __name(this, "DoctorFlow");
513
+ }
514
+ checks;
515
+ constructor(checks) {
516
+ this.checks = checks;
517
+ }
518
+ async run() {
519
+ const results = [];
520
+ let overall = "ok";
521
+ for (const check of this.checks) {
522
+ try {
523
+ const r = await check.run();
524
+ results.push({
525
+ id: check.id,
526
+ label: check.label,
527
+ ...r
528
+ });
529
+ overall = aggregateSeverity(overall, r.severity);
530
+ } catch (err2) {
531
+ const message = err2 instanceof Error ? err2.message : String(err2);
532
+ results.push({
533
+ id: check.id,
534
+ label: check.label,
535
+ severity: "error",
536
+ message: `Check threw an exception: ${message}`
537
+ });
538
+ overall = "error";
539
+ }
540
+ }
541
+ return {
542
+ overall,
543
+ checks: results
544
+ };
545
+ }
546
+ /** Returns the appropriate CLI exit code: 0 for `ok`/`warning`, 4 for `error`. */
547
+ exitCodeFor(report) {
548
+ return report.overall === "error" ? 4 : 0;
549
+ }
550
+ formatReport(report) {
551
+ const lines = [
552
+ `Doctor-Check (Gesamtstatus: ${report.overall.toUpperCase()})`,
553
+ ""
554
+ ];
555
+ for (const c of report.checks) {
556
+ const icon = c.severity === "ok" ? "\u2713" : c.severity === "warning" ? "\u26A0" : "\u2717";
557
+ lines.push(` ${icon} ${c.label}: ${c.message}`);
558
+ }
559
+ return lines.join("\n");
560
+ }
561
+ };
562
+ DoctorFlow = _ts_decorate5([
563
+ (0, import_common5.Injectable)(),
564
+ _ts_param4(0, (0, import_common5.Inject)(DOCTOR_CHECKS_TOKEN)),
565
+ _ts_metadata5("design:type", Function),
566
+ _ts_metadata5("design:paramtypes", [
567
+ Array
568
+ ])
569
+ ], DoctorFlow);
570
+ function aggregateSeverity(a, b) {
571
+ if (a === "error" || b === "error") return "error";
572
+ if (a === "warning" || b === "warning") return "warning";
573
+ return "ok";
574
+ }
575
+ __name(aggregateSeverity, "aggregateSeverity");
576
+
577
+ // src/manifest-checks.ts
578
+ var COMPONENT_KEY_PATTERN = /^[a-z][a-z0-9]*([.-][a-z0-9]+)+$/;
579
+ var ACTION_KEY_PATTERN = /^[A-Z][A-Z0-9_]+$/;
580
+ var TENANT_ACTION_KEY_PATTERN = /^[a-z][a-zA-Z0-9_]*(\.[a-z][a-zA-Z0-9_]*)+$/;
581
+ var CAPABILITY_PATTERN = /^[a-z][a-zA-Z0-9_]*(\.[a-z][a-zA-Z0-9_]*)+$/;
582
+ var ROUTE_PREFIX = "/admin";
583
+ function ok(message) {
584
+ return {
585
+ severity: "ok",
586
+ message
587
+ };
588
+ }
589
+ __name(ok, "ok");
590
+ function err(message, paths) {
591
+ return {
592
+ severity: "error",
593
+ message,
594
+ paths
595
+ };
596
+ }
597
+ __name(err, "err");
598
+ function allProjectPages(m) {
599
+ return m.navigation?.projectPages ?? [];
600
+ }
601
+ __name(allProjectPages, "allProjectPages");
602
+ function allKpiCards(m) {
603
+ return m.dashboard?.kpiCards ?? [];
604
+ }
605
+ __name(allKpiCards, "allKpiCards");
606
+ function allTenantActions(m) {
607
+ return m.tenants?.actions ?? [];
608
+ }
609
+ __name(allTenantActions, "allTenantActions");
610
+ function allTenantColumns(m) {
611
+ return m.tenants?.columns ?? [];
612
+ }
613
+ __name(allTenantColumns, "allTenantColumns");
614
+ function allAuditActions(m) {
615
+ return m.audit?.actions ?? [];
616
+ }
617
+ __name(allAuditActions, "allAuditActions");
618
+ function allCapabilities(m) {
619
+ return Object.keys(m.capabilities ?? {});
620
+ }
621
+ __name(allCapabilities, "allCapabilities");
622
+ var DEFAULT_MANIFEST_CHECKS = [
623
+ {
624
+ id: "manifest.schema-version",
625
+ label: "schemaVersion ist 1",
626
+ run: /* @__PURE__ */ __name((m) => m.schemaVersion === 1 ? ok("schemaVersion=1") : err(`Unerwartete schemaVersion ${m.schemaVersion}`), "run")
627
+ },
628
+ {
629
+ id: "manifest.hash-format",
630
+ label: "manifestHash folgt sha256-<base64url>-Pattern",
631
+ run: /* @__PURE__ */ __name((m) => {
632
+ const hash = m.build?.manifestHash;
633
+ if (!hash) return err("manifestHash fehlt");
634
+ return /^sha256-[A-Za-z0-9_-]+$/.test(hash) ? ok(hash) : err(`manifestHash hat falsches Format: ${hash}`);
635
+ }, "run")
636
+ },
637
+ {
638
+ id: "manifest.project-page-component-keys",
639
+ label: "ProjectPage.componentKey-Format (lowercase-hyphenated ODER namespace.dot)",
640
+ run: /* @__PURE__ */ __name((m) => {
641
+ const bad = [];
642
+ for (const p of allProjectPages(m)) {
643
+ if (!COMPONENT_KEY_PATTERN.test(p.componentKey)) bad.push(p.componentKey);
644
+ }
645
+ return bad.length === 0 ? ok(`${allProjectPages(m).length} ProjectPage(s) ok`) : err(`${bad.length} componentKey(s) verletzen das Pattern`, bad);
646
+ }, "run")
647
+ },
648
+ {
649
+ id: "manifest.tenant-action-keys",
650
+ label: "TenantAction.actionKey-Format (domain.action \u2014 SPEC \xA74.2.1)",
651
+ run: /* @__PURE__ */ __name((m) => {
652
+ const bad = [];
653
+ for (const a of allTenantActions(m)) {
654
+ if (!TENANT_ACTION_KEY_PATTERN.test(a.actionKey)) bad.push(a.actionKey);
655
+ }
656
+ return bad.length === 0 ? ok("alle actionKeys folgen domain.action") : err(`${bad.length} actionKey(s) verletzen das Pattern`, bad);
657
+ }, "run")
658
+ },
659
+ {
660
+ id: "manifest.audit-action-keys",
661
+ label: "AuditAction.key-Format (SCREAMING_SNAKE_CASE)",
662
+ run: /* @__PURE__ */ __name((m) => {
663
+ const bad = [];
664
+ for (const a of allAuditActions(m)) {
665
+ if (!ACTION_KEY_PATTERN.test(a.key)) bad.push(a.key);
666
+ }
667
+ return bad.length === 0 ? ok("alle AuditAction.keys SCREAMING_SNAKE_CASE") : err(`${bad.length} AuditAction.key(s) verletzen das Pattern`, bad);
668
+ }, "run")
669
+ },
670
+ {
671
+ id: "manifest.capabilities-pattern",
672
+ label: "Capability-Pattern <domain>.<action> (SPEC \xA74.2.1)",
673
+ run: /* @__PURE__ */ __name((m) => {
674
+ const bad = allCapabilities(m).filter((c) => !CAPABILITY_PATTERN.test(c));
675
+ return bad.length === 0 ? ok(`${allCapabilities(m).length} Capabilities ok`) : err(`${bad.length} Capability/-ies verletzen das Pattern`, bad);
676
+ }, "run")
677
+ },
678
+ {
679
+ id: "manifest.required-capabilities-known",
680
+ label: "requiredCapability-Referenzen existieren in capabilities-Map",
681
+ run: /* @__PURE__ */ __name((m) => {
682
+ const known = new Set(allCapabilities(m));
683
+ const bad = [];
684
+ const visit = /* @__PURE__ */ __name((cap, ctx) => {
685
+ if (cap && !known.has(cap)) bad.push(`${ctx ?? "?"}: ${cap}`);
686
+ }, "visit");
687
+ for (const p of allProjectPages(m)) visit(p.requiredCapability, p.id);
688
+ for (const k of allKpiCards(m)) visit(k.requiredCapability, k.id);
689
+ for (const a of allTenantActions(m)) visit(a.requiredCapability, a.id);
690
+ for (const c of allTenantColumns(m)) visit(c.requiredCapability, c.key);
691
+ return bad.length === 0 ? ok("alle requiredCapability-Refs aufgel\xF6st") : err(`${bad.length} unbekannte Capability-Ref(s)`, bad);
692
+ }, "run")
693
+ },
694
+ {
695
+ id: "manifest.route-prefix",
696
+ label: "ProjectPage.route beginnt mit /admin",
697
+ run: /* @__PURE__ */ __name((m) => {
698
+ const bad = [];
699
+ for (const p of allProjectPages(m)) {
700
+ if (!p.route.startsWith(ROUTE_PREFIX)) bad.push(p.route);
701
+ }
702
+ return bad.length === 0 ? ok("alle ProjectPage-Routes unter /admin") : err(`${bad.length} Route(s) ohne /admin-Prefix`, bad);
703
+ }, "run")
704
+ },
705
+ {
706
+ id: "manifest.kpi-slot-priority",
707
+ label: "KpiCard.slotPriority (falls gesetzt) ist endliche Zahl",
708
+ run: /* @__PURE__ */ __name((m) => {
709
+ const bad = [];
710
+ for (const k of allKpiCards(m)) {
711
+ if (k.slotPriority !== void 0 && !Number.isFinite(k.slotPriority)) {
712
+ bad.push(k.id);
713
+ }
714
+ }
715
+ return bad.length === 0 ? ok("alle slotPriority-Werte endlich") : err(`${bad.length} KpiCard(s) mit ung\xFCltiger slotPriority`, bad);
716
+ }, "run")
717
+ },
718
+ {
719
+ id: "manifest.unique-project-page-ids",
720
+ label: "ProjectPage.id ist unique",
721
+ run: /* @__PURE__ */ __name((m) => {
722
+ const seen = /* @__PURE__ */ new Map();
723
+ for (const p of allProjectPages(m)) {
724
+ seen.set(p.id, (seen.get(p.id) ?? 0) + 1);
725
+ }
726
+ const dups = [
727
+ ...seen.entries()
728
+ ].filter(([, n]) => n > 1).map(([k]) => k);
729
+ return dups.length === 0 ? ok("alle ProjectPage.id eindeutig") : err(`${dups.length} doppelte ProjectPage.id`, dups);
730
+ }, "run")
731
+ },
732
+ {
733
+ id: "manifest.unique-action-keys",
734
+ label: "actionKeys sind je Namespace (TenantAction / AuditAction) eindeutig",
735
+ run: /* @__PURE__ */ __name((m) => {
736
+ const dups = [];
737
+ const tenantSeen = /* @__PURE__ */ new Map();
738
+ for (const a of allTenantActions(m)) {
739
+ tenantSeen.set(a.actionKey, (tenantSeen.get(a.actionKey) ?? 0) + 1);
740
+ }
741
+ for (const [k, n] of tenantSeen) {
742
+ if (n > 1) dups.push(`TenantAction:${k}`);
743
+ }
744
+ const auditSeen = /* @__PURE__ */ new Map();
745
+ for (const a of allAuditActions(m)) {
746
+ auditSeen.set(a.key, (auditSeen.get(a.key) ?? 0) + 1);
747
+ }
748
+ for (const [k, n] of auditSeen) {
749
+ if (n > 1) dups.push(`AuditAction:${k}`);
750
+ }
751
+ return dups.length === 0 ? ok("alle actionKeys je Namespace eindeutig") : err(`${dups.length} doppelte actionKey(s)`, dups);
752
+ }, "run")
753
+ },
754
+ {
755
+ id: "manifest.tenant-columns-batchable",
756
+ label: "TenantColumns haben endpoint-Pfad f\xFCr Batch-Fetch",
757
+ run: /* @__PURE__ */ __name((m) => {
758
+ const bad = [];
759
+ for (const c of allTenantColumns(m)) {
760
+ if (!c.endpoint || c.endpoint.trim().length === 0) bad.push(c.key);
761
+ else if (c.endpoint.includes("{slug}") || c.endpoint.includes("{tenantId}")) {
762
+ bad.push(`${c.key} (per-Tenant statt batch)`);
763
+ }
764
+ }
765
+ return bad.length === 0 ? ok("alle TenantColumns batch-f\xE4hig") : err(`${bad.length} TenantColumn(s) verletzen Batch-Pflicht`, bad);
766
+ }, "run")
767
+ }
768
+ ];
769
+
770
+ // src/manifest-cli-flow.ts
771
+ var import_common6 = require("@nestjs/common");
772
+ function _ts_decorate6(decorators, target, key, desc) {
773
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
774
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
775
+ 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;
776
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
777
+ }
778
+ __name(_ts_decorate6, "_ts_decorate");
779
+ function _ts_metadata6(k, v) {
780
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
781
+ }
782
+ __name(_ts_metadata6, "_ts_metadata");
783
+ function _ts_param5(paramIndex, decorator) {
784
+ return function(target, key) {
785
+ decorator(target, key, paramIndex);
786
+ };
787
+ }
788
+ __name(_ts_param5, "_ts_param");
789
+ var ManifestCliFlow = class {
790
+ static {
791
+ __name(this, "ManifestCliFlow");
792
+ }
793
+ access;
794
+ checks;
795
+ constructor(access, checks) {
796
+ this.access = access;
797
+ this.checks = checks;
798
+ }
799
+ /** `<app> manifest dump` — JSON output of the current manifest. */
800
+ dump() {
801
+ return this.access.getManifest();
802
+ }
803
+ /**
804
+ * `<app> manifest hash` — canonical manifestHash value. Returns
805
+ * the value from `build.manifestHash`. Consumers can pin this in CI
806
+ * (`expected-hash.txt`) and check for drift.
807
+ */
808
+ hash() {
809
+ const m = this.access.getManifest();
810
+ const h = m.build?.manifestHash;
811
+ if (!h) throw new Error("manifestHash fehlt im Manifest \u2014 Boot-Zeit-Bug?");
812
+ return h;
813
+ }
814
+ /**
815
+ * `<app> manifest validate` — returns `true` when all structures
816
+ * are present. Deeper schema validation runs separately via Ajv with
817
+ * `@saasicat/spec/schemas/admin-manifest.schema.json`;
818
+ * this helper provides the quick diagnostic without the Ajv cost.
819
+ */
820
+ validate() {
821
+ const m = this.access.getManifest();
822
+ if (m.schemaVersion !== 1) {
823
+ return {
824
+ ok: false,
825
+ reason: `Unerwartete schemaVersion ${m.schemaVersion}`
826
+ };
827
+ }
828
+ if (!m.project?.key) {
829
+ return {
830
+ ok: false,
831
+ reason: "Kein `project.key` im Manifest"
832
+ };
833
+ }
834
+ if (!m.build?.manifestHash) {
835
+ return {
836
+ ok: false,
837
+ reason: "manifestHash fehlt"
838
+ };
839
+ }
840
+ return {
841
+ ok: true
842
+ };
843
+ }
844
+ /**
845
+ * `<app> manifest diff <expected.json>` — flat diff over the two
846
+ * manifest hashes plus list differences for top-level fields. Returns
847
+ * `null` when the manifests are identical.
848
+ */
849
+ diff(expected) {
850
+ const current = this.access.getManifest();
851
+ if (current.build?.manifestHash === expected.build?.manifestHash) return null;
852
+ const currentKeys = collectComponentKeys(current);
853
+ const expectedKeys = collectComponentKeys(expected);
854
+ return {
855
+ currentHash: current.build?.manifestHash ?? null,
856
+ expectedHash: expected.build?.manifestHash ?? null,
857
+ componentKeysAdded: [
858
+ ...currentKeys
859
+ ].filter((k) => !expectedKeys.has(k)).sort(),
860
+ componentKeysRemoved: [
861
+ ...expectedKeys
862
+ ].filter((k) => !currentKeys.has(k)).sort()
863
+ };
864
+ }
865
+ /**
866
+ * `<app> manifest check` — runs all registered manifest checks.
867
+ * Aggregates severity (ok/warning/error) into `overall`. The consumer
868
+ * maps `error` to exit code 7 (drift) per `cli-conventions.md` §6.
869
+ */
870
+ async runChecks() {
871
+ const manifest = this.access.getManifest();
872
+ const checks = [];
873
+ let overall = "ok";
874
+ for (const check of this.checks) {
875
+ try {
876
+ const r = check.run(manifest);
877
+ checks.push({
878
+ id: check.id,
879
+ label: check.label,
880
+ ...r
881
+ });
882
+ overall = aggregate(overall, r.severity);
883
+ } catch (err2) {
884
+ const message = err2 instanceof Error ? err2.message : String(err2);
885
+ checks.push({
886
+ id: check.id,
887
+ label: check.label,
888
+ severity: "error",
889
+ message: `Check warf eine Exception: ${message}`
890
+ });
891
+ overall = "error";
892
+ }
893
+ }
894
+ return {
895
+ overall,
896
+ checks
897
+ };
898
+ }
899
+ /** Returns the appropriate CLI exit code: 0 for `ok`/`warning`, 7 for `error` (drift). */
900
+ exitCodeFor(report) {
901
+ return report.overall === "error" ? 7 : 0;
902
+ }
903
+ formatReport(report) {
904
+ const lines = [
905
+ `Manifest-Check (Gesamtstatus: ${report.overall.toUpperCase()})`,
906
+ ""
907
+ ];
908
+ for (const c of report.checks) {
909
+ const icon = c.severity === "ok" ? "\u2713" : c.severity === "warning" ? "\u26A0" : "\u2717";
910
+ lines.push(` ${icon} ${c.label}: ${c.message}`);
911
+ if (c.paths && c.paths.length > 0) {
912
+ for (const p of c.paths) lines.push(` \xB7 ${p}`);
913
+ }
914
+ }
915
+ return lines.join("\n");
916
+ }
917
+ };
918
+ ManifestCliFlow = _ts_decorate6([
919
+ (0, import_common6.Injectable)(),
920
+ _ts_param5(0, (0, import_common6.Inject)(MANIFEST_ACCESS_PORT_TOKEN)),
921
+ _ts_param5(1, (0, import_common6.Inject)(MANIFEST_CHECKS_TOKEN)),
922
+ _ts_metadata6("design:type", Function),
923
+ _ts_metadata6("design:paramtypes", [
924
+ typeof ManifestAccessPort === "undefined" ? Object : ManifestAccessPort,
925
+ Array
926
+ ])
927
+ ], ManifestCliFlow);
928
+ function aggregate(a, b) {
929
+ if (a === "error" || b === "error") return "error";
930
+ if (a === "warning" || b === "warning") return "warning";
931
+ return "ok";
932
+ }
933
+ __name(aggregate, "aggregate");
934
+ function collectComponentKeys(m) {
935
+ const keys = /* @__PURE__ */ new Set();
936
+ for (const p of m.navigation?.projectPages ?? []) keys.add(p.componentKey);
937
+ return keys;
938
+ }
939
+ __name(collectComponentKeys, "collectComponentKeys");
940
+
941
+ // src/default-doctor-checks.ts
942
+ var import_common7 = require("@nestjs/common");
943
+ var import_nest4 = require("@saasicat/nest");
944
+ function _ts_decorate7(decorators, target, key, desc) {
945
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
946
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
947
+ 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;
948
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
949
+ }
950
+ __name(_ts_decorate7, "_ts_decorate");
951
+ function _ts_metadata7(k, v) {
952
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
953
+ }
954
+ __name(_ts_metadata7, "_ts_metadata");
955
+ function _ts_param6(paramIndex, decorator) {
956
+ return function(target, key) {
957
+ decorator(target, key, paramIndex);
958
+ };
959
+ }
960
+ __name(_ts_param6, "_ts_param");
961
+ var PlanCatalogDoctorCheck = class {
962
+ static {
963
+ __name(this, "PlanCatalogDoctorCheck");
964
+ }
965
+ catalog;
966
+ id = "platform.plan-catalog";
967
+ label = "Plan-Catalog im DI";
968
+ constructor(catalog) {
969
+ this.catalog = catalog;
970
+ }
971
+ async run() {
972
+ const plans = this.catalog?.plans ?? [];
973
+ if (plans.length === 0) {
974
+ return {
975
+ severity: "error",
976
+ message: "PlanCatalog enth\xE4lt keine Pl\xE4ne \u2014 Onboarding-Pricing-Page wird leer."
977
+ };
978
+ }
979
+ return {
980
+ severity: "ok",
981
+ message: `${plans.length} Plan(s), ${this.catalog.features?.length ?? 0} Feature(s) geladen.`,
982
+ details: {
983
+ projectKey: this.catalog.projectKey,
984
+ planIds: plans.map((p) => p.id)
985
+ }
986
+ };
987
+ }
988
+ };
989
+ PlanCatalogDoctorCheck = _ts_decorate7([
990
+ (0, import_common7.Injectable)(),
991
+ _ts_param6(0, (0, import_common7.Inject)(import_nest4.PLAN_CATALOG_TOKEN)),
992
+ _ts_metadata7("design:type", Function),
993
+ _ts_metadata7("design:paramtypes", [
994
+ typeof PlanCatalog === "undefined" ? Object : PlanCatalog
995
+ ])
996
+ ], PlanCatalogDoctorCheck);
997
+ var DiscoverySnapshotDoctorCheck = class {
998
+ static {
999
+ __name(this, "DiscoverySnapshotDoctorCheck");
1000
+ }
1001
+ snapshot;
1002
+ id = "platform.discovery-snapshot";
1003
+ label = "Discovery-Snapshot beim Boot";
1004
+ constructor(snapshot) {
1005
+ this.snapshot = snapshot;
1006
+ }
1007
+ async run() {
1008
+ const caps = this.snapshot?.capabilities ?? [];
1009
+ if (caps.length === 0) {
1010
+ return {
1011
+ severity: "warning",
1012
+ message: "Keine Capabilities entdeckt \u2014 Decorator-tragende Module evtl. nicht in AppModule.imports[]."
1013
+ };
1014
+ }
1015
+ return {
1016
+ severity: "ok",
1017
+ message: `${caps.length} Capabilities, ${this.snapshot.features?.length ?? 0} Features, ${this.snapshot.quotas?.length ?? 0} Quotas.`
1018
+ };
1019
+ }
1020
+ };
1021
+ DiscoverySnapshotDoctorCheck = _ts_decorate7([
1022
+ (0, import_common7.Injectable)(),
1023
+ _ts_param6(0, (0, import_common7.Inject)(import_nest4.DISCOVERY_SNAPSHOT_TOKEN)),
1024
+ _ts_metadata7("design:type", Function),
1025
+ _ts_metadata7("design:paramtypes", [
1026
+ typeof DiscoverySnapshot === "undefined" ? Object : DiscoverySnapshot
1027
+ ])
1028
+ ], DiscoverySnapshotDoctorCheck);
1029
+ var UserPortDoctorCheck = class {
1030
+ static {
1031
+ __name(this, "UserPortDoctorCheck");
1032
+ }
1033
+ users;
1034
+ id = "platform.user-port";
1035
+ label = "UserPort.findByEmail erreichbar";
1036
+ constructor(users) {
1037
+ this.users = users;
1038
+ }
1039
+ async run() {
1040
+ try {
1041
+ await this.users.findByEmail("__doctor-check__@invalid.local");
1042
+ return {
1043
+ severity: "ok",
1044
+ message: "UserPort antwortet."
1045
+ };
1046
+ } catch (err2) {
1047
+ return {
1048
+ severity: "error",
1049
+ message: `UserPort wirft: ${err2 instanceof Error ? err2.message : String(err2)}`
1050
+ };
1051
+ }
1052
+ }
1053
+ };
1054
+ UserPortDoctorCheck = _ts_decorate7([
1055
+ (0, import_common7.Injectable)(),
1056
+ _ts_param6(0, (0, import_common7.Inject)(USER_PORT_TOKEN)),
1057
+ _ts_metadata7("design:type", Function),
1058
+ _ts_metadata7("design:paramtypes", [
1059
+ typeof UserPort === "undefined" ? Object : UserPort
1060
+ ])
1061
+ ], UserPortDoctorCheck);
1062
+ var AdminManifestDoctorCheck = class {
1063
+ static {
1064
+ __name(this, "AdminManifestDoctorCheck");
1065
+ }
1066
+ manifest;
1067
+ id = "platform.admin-manifest";
1068
+ label = "AdminManifestService liefert Manifest";
1069
+ constructor(manifest) {
1070
+ this.manifest = manifest;
1071
+ }
1072
+ async run() {
1073
+ try {
1074
+ const m = this.manifest.getManifest();
1075
+ const pageCount = Object.keys(m.navigation?.standardPages ?? {}).length;
1076
+ return {
1077
+ severity: "ok",
1078
+ message: `Manifest mit ${pageCount} Standard-Pages, Hash ${m.build?.manifestHash?.slice(0, 12) ?? "???"}\u2026`
1079
+ };
1080
+ } catch (err2) {
1081
+ return {
1082
+ severity: "error",
1083
+ message: `Manifest-Build wirft: ${err2 instanceof Error ? err2.message : String(err2)}`
1084
+ };
1085
+ }
1086
+ }
1087
+ };
1088
+ AdminManifestDoctorCheck = _ts_decorate7([
1089
+ (0, import_common7.Injectable)(),
1090
+ _ts_metadata7("design:type", Function),
1091
+ _ts_metadata7("design:paramtypes", [
1092
+ typeof import_nest4.AdminManifestService === "undefined" ? Object : import_nest4.AdminManifestService
1093
+ ])
1094
+ ], AdminManifestDoctorCheck);
1095
+ var PLATFORM_DOCTOR_CHECK_PROVIDERS = [
1096
+ PlanCatalogDoctorCheck,
1097
+ DiscoverySnapshotDoctorCheck,
1098
+ UserPortDoctorCheck,
1099
+ AdminManifestDoctorCheck
1100
+ ];
1101
+
1102
+ // src/schema-apply.ts
1103
+ function stripLineComment(line) {
1104
+ const commentStart = line.indexOf("//");
1105
+ return commentStart === -1 ? line : line.slice(0, commentStart);
1106
+ }
1107
+ __name(stripLineComment, "stripLineComment");
1108
+ function extractModelNames(schema) {
1109
+ const names = [];
1110
+ const lines = schema.split("\n");
1111
+ for (const line of lines) {
1112
+ const stripped = stripLineComment(line).trim();
1113
+ const match = stripped.match(/^model\s+([A-Za-z_][A-Za-z0-9_]*)\s*\{/);
1114
+ if (match) names.push(match[1]);
1115
+ }
1116
+ return names;
1117
+ }
1118
+ __name(extractModelNames, "extractModelNames");
1119
+ function extractModelBlocks(fragment) {
1120
+ const blocks = /* @__PURE__ */ new Map();
1121
+ const lines = fragment.split("\n");
1122
+ let current = null;
1123
+ for (const rawLine of lines) {
1124
+ const stripped = stripLineComment(rawLine);
1125
+ if (!current) {
1126
+ const match = rawLine.match(/^\s*model\s+([A-Za-z_][A-Za-z0-9_]*)\s*\{/);
1127
+ if (match) {
1128
+ const openCount = (stripped.match(/\{/g) ?? []).length;
1129
+ const closeCount = (stripped.match(/\}/g) ?? []).length;
1130
+ current = {
1131
+ name: match[1],
1132
+ lines: [
1133
+ rawLine
1134
+ ],
1135
+ depth: openCount - closeCount
1136
+ };
1137
+ if (current.depth === 0) {
1138
+ blocks.set(current.name, current.lines.join("\n"));
1139
+ current = null;
1140
+ }
1141
+ }
1142
+ continue;
1143
+ }
1144
+ current.lines.push(rawLine);
1145
+ current.depth += (stripped.match(/\{/g) ?? []).length;
1146
+ current.depth -= (stripped.match(/\}/g) ?? []).length;
1147
+ if (current.depth <= 0) {
1148
+ blocks.set(current.name, current.lines.join("\n"));
1149
+ current = null;
1150
+ }
1151
+ }
1152
+ return blocks;
1153
+ }
1154
+ __name(extractModelBlocks, "extractModelBlocks");
1155
+ function applyFragmentBlocks(schema, fragmentBlocks, options = {}) {
1156
+ const existing = new Set(extractModelNames(schema));
1157
+ const added = [];
1158
+ const skipped = [];
1159
+ const additions = [];
1160
+ for (const [name, block] of fragmentBlocks) {
1161
+ if (existing.has(name)) {
1162
+ skipped.push(name);
1163
+ } else {
1164
+ added.push(name);
1165
+ additions.push(block);
1166
+ }
1167
+ }
1168
+ if (additions.length === 0) {
1169
+ return {
1170
+ added,
1171
+ skipped,
1172
+ schema
1173
+ };
1174
+ }
1175
+ const header = options.fragmentLabel ? `
1176
+
1177
+ // ============================================================
1178
+ // Eingef\xFCgt durch \`saas-platform schema apply\` aus ${options.fragmentLabel}
1179
+ // ============================================================
1180
+ ` : `
1181
+
1182
+ // Eingef\xFCgt durch \`saas-platform schema apply\`
1183
+ `;
1184
+ const trimmedSchema = schema.endsWith("\n") ? schema : schema + "\n";
1185
+ return {
1186
+ added,
1187
+ skipped,
1188
+ schema: trimmedSchema + header + additions.join("\n\n") + "\n"
1189
+ };
1190
+ }
1191
+ __name(applyFragmentBlocks, "applyFragmentBlocks");
1192
+
1193
+ // src/module.ts
1194
+ var import_common8 = require("@nestjs/common");
1195
+ var import_nest5 = require("@saasicat/nest");
1196
+ function _ts_decorate8(decorators, target, key, desc) {
1197
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1198
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
1199
+ 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;
1200
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
1201
+ }
1202
+ __name(_ts_decorate8, "_ts_decorate");
1203
+ var CliContextModule = class _CliContextModule {
1204
+ static {
1205
+ __name(this, "CliContextModule");
1206
+ }
1207
+ static forRoot(options) {
1208
+ const providers = [
1209
+ {
1210
+ provide: CLI_CONTEXT_CONFIG_TOKEN,
1211
+ useValue: options.config
1212
+ },
1213
+ (0, import_nest5.asProvider)(USER_PORT_TOKEN, options.userPort),
1214
+ CliContextService,
1215
+ MfaSetupFlow,
1216
+ WhoAmIFlow
1217
+ ];
1218
+ const exports_ = [
1219
+ CLI_CONTEXT_CONFIG_TOKEN,
1220
+ CliContextService,
1221
+ MfaSetupFlow,
1222
+ WhoAmIFlow
1223
+ ];
1224
+ if (options.auditQueryPort) {
1225
+ providers.push((0, import_nest5.asProvider)(AUDIT_QUERY_PORT_TOKEN, options.auditQueryPort));
1226
+ providers.push(AuditTailFlow);
1227
+ exports_.push(AuditTailFlow);
1228
+ }
1229
+ if (options.defaultDoctorChecks) {
1230
+ providers.push(...PLATFORM_DOCTOR_CHECK_PROVIDERS);
1231
+ providers.push({
1232
+ provide: DOCTOR_CHECKS_TOKEN,
1233
+ useFactory: /* @__PURE__ */ __name((...platformChecks) => {
1234
+ const extra = Array.isArray(options.doctorChecks) ? options.doctorChecks : [];
1235
+ return [
1236
+ ...platformChecks,
1237
+ ...extra
1238
+ ];
1239
+ }, "useFactory"),
1240
+ inject: PLATFORM_DOCTOR_CHECK_PROVIDERS
1241
+ });
1242
+ } else {
1243
+ providers.push((0, import_nest5.asProvider)(DOCTOR_CHECKS_TOKEN, options.doctorChecks ?? []));
1244
+ }
1245
+ providers.push(DoctorFlow);
1246
+ exports_.push(DoctorFlow);
1247
+ if (options.manifestAccessPort) {
1248
+ providers.push((0, import_nest5.asProvider)(MANIFEST_ACCESS_PORT_TOKEN, options.manifestAccessPort), (0, import_nest5.asProvider)(MANIFEST_CHECKS_TOKEN, options.manifestChecks ?? DEFAULT_MANIFEST_CHECKS), ManifestCliFlow);
1249
+ exports_.push(ManifestCliFlow);
1250
+ }
1251
+ if (options.userManagementPort) {
1252
+ providers.push((0, import_nest5.asProvider)(USER_MANAGEMENT_PORT_TOKEN, options.userManagementPort));
1253
+ exports_.push(USER_MANAGEMENT_PORT_TOKEN);
1254
+ }
1255
+ return {
1256
+ module: _CliContextModule,
1257
+ global: options.global ?? false,
1258
+ providers,
1259
+ exports: exports_
1260
+ };
1261
+ }
1262
+ };
1263
+ CliContextModule = _ts_decorate8([
1264
+ (0, import_common8.Module)({})
1265
+ ], CliContextModule);
1266
+
1267
+ // src/manifest.command.ts
1268
+ var import_common9 = require("@nestjs/common");
1269
+ var import_nest_commander = require("nest-commander");
1270
+ function _ts_decorate9(decorators, target, key, desc) {
1271
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1272
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
1273
+ 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;
1274
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
1275
+ }
1276
+ __name(_ts_decorate9, "_ts_decorate");
1277
+ function _ts_metadata8(k, v) {
1278
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
1279
+ }
1280
+ __name(_ts_metadata8, "_ts_metadata");
1281
+ var ManifestDumpCommand = class extends import_nest_commander.CommandRunner {
1282
+ static {
1283
+ __name(this, "ManifestDumpCommand");
1284
+ }
1285
+ ctx;
1286
+ flow;
1287
+ constructor(ctx, flow) {
1288
+ super(), this.ctx = ctx, this.flow = flow;
1289
+ }
1290
+ async run(_args, flags) {
1291
+ const identity = this.ctx.resolveIdentity(flags.as);
1292
+ await this.ctx.ensureSuperAdmin(identity);
1293
+ process.stdout.write(JSON.stringify(this.flow.dump(), null, 2) + "\n");
1294
+ }
1295
+ parseAs(v) {
1296
+ return v;
1297
+ }
1298
+ };
1299
+ _ts_decorate9([
1300
+ (0, import_nest_commander.Option)({
1301
+ flags: "--as <email>"
1302
+ }),
1303
+ _ts_metadata8("design:type", Function),
1304
+ _ts_metadata8("design:paramtypes", [
1305
+ String
1306
+ ]),
1307
+ _ts_metadata8("design:returntype", String)
1308
+ ], ManifestDumpCommand.prototype, "parseAs", null);
1309
+ ManifestDumpCommand = _ts_decorate9([
1310
+ (0, import_common9.Injectable)(),
1311
+ (0, import_nest_commander.SubCommand)({
1312
+ name: "dump",
1313
+ description: "Manifest als JSON ausgeben"
1314
+ }),
1315
+ _ts_metadata8("design:type", Function),
1316
+ _ts_metadata8("design:paramtypes", [
1317
+ typeof CliContextService === "undefined" ? Object : CliContextService,
1318
+ typeof ManifestCliFlow === "undefined" ? Object : ManifestCliFlow
1319
+ ])
1320
+ ], ManifestDumpCommand);
1321
+ var ManifestHashCommand = class extends import_nest_commander.CommandRunner {
1322
+ static {
1323
+ __name(this, "ManifestHashCommand");
1324
+ }
1325
+ ctx;
1326
+ flow;
1327
+ constructor(ctx, flow) {
1328
+ super(), this.ctx = ctx, this.flow = flow;
1329
+ }
1330
+ async run(_args, flags) {
1331
+ const identity = this.ctx.resolveIdentity(flags.as);
1332
+ await this.ctx.ensureSuperAdmin(identity);
1333
+ process.stdout.write(this.flow.hash() + "\n");
1334
+ }
1335
+ parseAs(v) {
1336
+ return v;
1337
+ }
1338
+ };
1339
+ _ts_decorate9([
1340
+ (0, import_nest_commander.Option)({
1341
+ flags: "--as <email>"
1342
+ }),
1343
+ _ts_metadata8("design:type", Function),
1344
+ _ts_metadata8("design:paramtypes", [
1345
+ String
1346
+ ]),
1347
+ _ts_metadata8("design:returntype", String)
1348
+ ], ManifestHashCommand.prototype, "parseAs", null);
1349
+ ManifestHashCommand = _ts_decorate9([
1350
+ (0, import_common9.Injectable)(),
1351
+ (0, import_nest_commander.SubCommand)({
1352
+ name: "hash",
1353
+ description: "manifestHash ausgeben (CI-Pinning)"
1354
+ }),
1355
+ _ts_metadata8("design:type", Function),
1356
+ _ts_metadata8("design:paramtypes", [
1357
+ typeof CliContextService === "undefined" ? Object : CliContextService,
1358
+ typeof ManifestCliFlow === "undefined" ? Object : ManifestCliFlow
1359
+ ])
1360
+ ], ManifestHashCommand);
1361
+ var ManifestValidateCommand = class extends import_nest_commander.CommandRunner {
1362
+ static {
1363
+ __name(this, "ManifestValidateCommand");
1364
+ }
1365
+ ctx;
1366
+ flow;
1367
+ constructor(ctx, flow) {
1368
+ super(), this.ctx = ctx, this.flow = flow;
1369
+ }
1370
+ async run(_args, flags) {
1371
+ const identity = this.ctx.resolveIdentity(flags.as);
1372
+ await this.ctx.ensureSuperAdmin(identity);
1373
+ const result = this.flow.validate();
1374
+ if (result.ok) {
1375
+ process.stdout.write("Manifest validiert \u2713\n");
1376
+ return;
1377
+ }
1378
+ process.stderr.write(`Manifest invalid: ${result.reason}
1379
+ `);
1380
+ process.exit(1);
1381
+ }
1382
+ parseAs(v) {
1383
+ return v;
1384
+ }
1385
+ };
1386
+ _ts_decorate9([
1387
+ (0, import_nest_commander.Option)({
1388
+ flags: "--as <email>"
1389
+ }),
1390
+ _ts_metadata8("design:type", Function),
1391
+ _ts_metadata8("design:paramtypes", [
1392
+ String
1393
+ ]),
1394
+ _ts_metadata8("design:returntype", String)
1395
+ ], ManifestValidateCommand.prototype, "parseAs", null);
1396
+ ManifestValidateCommand = _ts_decorate9([
1397
+ (0, import_common9.Injectable)(),
1398
+ (0, import_nest_commander.SubCommand)({
1399
+ name: "validate",
1400
+ description: "Schnell-Sanity (schemaVersion + project.key + manifestHash)"
1401
+ }),
1402
+ _ts_metadata8("design:type", Function),
1403
+ _ts_metadata8("design:paramtypes", [
1404
+ typeof CliContextService === "undefined" ? Object : CliContextService,
1405
+ typeof ManifestCliFlow === "undefined" ? Object : ManifestCliFlow
1406
+ ])
1407
+ ], ManifestValidateCommand);
1408
+ var ManifestCheckCommand = class extends import_nest_commander.CommandRunner {
1409
+ static {
1410
+ __name(this, "ManifestCheckCommand");
1411
+ }
1412
+ ctx;
1413
+ flow;
1414
+ constructor(ctx, flow) {
1415
+ super(), this.ctx = ctx, this.flow = flow;
1416
+ }
1417
+ async run(_args, flags) {
1418
+ const identity = this.ctx.resolveIdentity(flags.as);
1419
+ await this.ctx.ensureSuperAdmin(identity);
1420
+ const report = await this.flow.runChecks();
1421
+ process.stdout.write(this.flow.formatReport(report) + "\n");
1422
+ const code = this.flow.exitCodeFor(report);
1423
+ if (code !== 0) process.exit(code);
1424
+ }
1425
+ parseAs(v) {
1426
+ return v;
1427
+ }
1428
+ };
1429
+ _ts_decorate9([
1430
+ (0, import_nest_commander.Option)({
1431
+ flags: "--as <email>"
1432
+ }),
1433
+ _ts_metadata8("design:type", Function),
1434
+ _ts_metadata8("design:paramtypes", [
1435
+ String
1436
+ ]),
1437
+ _ts_metadata8("design:returntype", String)
1438
+ ], ManifestCheckCommand.prototype, "parseAs", null);
1439
+ ManifestCheckCommand = _ts_decorate9([
1440
+ (0, import_common9.Injectable)(),
1441
+ (0, import_nest_commander.SubCommand)({
1442
+ name: "check",
1443
+ description: "Alle Manifest-Checks (Exit-Code 7 bei error/Drift)"
1444
+ }),
1445
+ _ts_metadata8("design:type", Function),
1446
+ _ts_metadata8("design:paramtypes", [
1447
+ typeof CliContextService === "undefined" ? Object : CliContextService,
1448
+ typeof ManifestCliFlow === "undefined" ? Object : ManifestCliFlow
1449
+ ])
1450
+ ], ManifestCheckCommand);
1451
+ var ManifestCommands = class extends import_nest_commander.CommandRunner {
1452
+ static {
1453
+ __name(this, "ManifestCommands");
1454
+ }
1455
+ async run() {
1456
+ process.stderr.write("Bitte Sub-Command angeben: dump, hash, validate, check.\n");
1457
+ process.exit(2);
1458
+ }
1459
+ };
1460
+ ManifestCommands = _ts_decorate9([
1461
+ (0, import_common9.Injectable)(),
1462
+ (0, import_nest_commander.Command)({
1463
+ name: "manifest",
1464
+ description: "Manifest-Operations (dump, hash, validate, check)",
1465
+ subCommands: [
1466
+ ManifestDumpCommand,
1467
+ ManifestHashCommand,
1468
+ ManifestValidateCommand,
1469
+ ManifestCheckCommand
1470
+ ]
1471
+ })
1472
+ ], ManifestCommands);
1473
+
1474
+ // src/admin.command.ts
1475
+ var import_common10 = require("@nestjs/common");
1476
+ var import_nest_commander2 = require("nest-commander");
1477
+ var import_qrcode_terminal = __toESM(require("qrcode-terminal"), 1);
1478
+ function _ts_decorate10(decorators, target, key, desc) {
1479
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1480
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
1481
+ 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;
1482
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
1483
+ }
1484
+ __name(_ts_decorate10, "_ts_decorate");
1485
+ function _ts_metadata9(k, v) {
1486
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
1487
+ }
1488
+ __name(_ts_metadata9, "_ts_metadata");
1489
+ function _ts_param7(paramIndex, decorator) {
1490
+ return function(target, key) {
1491
+ decorator(target, key, paramIndex);
1492
+ };
1493
+ }
1494
+ __name(_ts_param7, "_ts_param");
1495
+ var AdminWhoamiCommand = class extends import_nest_commander2.CommandRunner {
1496
+ static {
1497
+ __name(this, "AdminWhoamiCommand");
1498
+ }
1499
+ flow;
1500
+ constructor(flow) {
1501
+ super(), this.flow = flow;
1502
+ }
1503
+ async run(_args, flags) {
1504
+ const result = await this.flow.run(flags.as);
1505
+ process.stdout.write(this.flow.formatResult(result) + "\n");
1506
+ }
1507
+ parseAs(v) {
1508
+ return v;
1509
+ }
1510
+ };
1511
+ _ts_decorate10([
1512
+ (0, import_nest_commander2.Option)({
1513
+ flags: "--as <email>"
1514
+ }),
1515
+ _ts_metadata9("design:type", Function),
1516
+ _ts_metadata9("design:paramtypes", [
1517
+ String
1518
+ ]),
1519
+ _ts_metadata9("design:returntype", String)
1520
+ ], AdminWhoamiCommand.prototype, "parseAs", null);
1521
+ AdminWhoamiCommand = _ts_decorate10([
1522
+ (0, import_common10.Injectable)(),
1523
+ (0, import_nest_commander2.SubCommand)({
1524
+ name: "whoami",
1525
+ description: "Aktive CLI-Identit\xE4t + MFA-/Production-Status"
1526
+ }),
1527
+ _ts_metadata9("design:type", Function),
1528
+ _ts_metadata9("design:paramtypes", [
1529
+ typeof WhoAmIFlow === "undefined" ? Object : WhoAmIFlow
1530
+ ])
1531
+ ], AdminWhoamiCommand);
1532
+ var AdminMfaSetupCommand = class extends import_nest_commander2.CommandRunner {
1533
+ static {
1534
+ __name(this, "AdminMfaSetupCommand");
1535
+ }
1536
+ config;
1537
+ flow;
1538
+ constructor(config, flow) {
1539
+ super(), this.config = config, this.flow = flow;
1540
+ }
1541
+ async run(_args, flags) {
1542
+ const result = await this.flow.run({
1543
+ asFlag: flags.as,
1544
+ issuer: this.config.mfaIssuer ?? "SuperAdmin",
1545
+ force: flags.force
1546
+ });
1547
+ await new Promise((resolve) => {
1548
+ import_qrcode_terminal.default.generate(result.otpauthUri, {
1549
+ small: true
1550
+ }, (qr) => {
1551
+ process.stdout.write("\n" + qr + "\n");
1552
+ resolve();
1553
+ });
1554
+ });
1555
+ process.stdout.write(this.flow.formatSetupResult(result) + "\n");
1556
+ }
1557
+ parseAs(v) {
1558
+ return v;
1559
+ }
1560
+ parseForce() {
1561
+ return true;
1562
+ }
1563
+ };
1564
+ _ts_decorate10([
1565
+ (0, import_nest_commander2.Option)({
1566
+ flags: "--as <email>"
1567
+ }),
1568
+ _ts_metadata9("design:type", Function),
1569
+ _ts_metadata9("design:paramtypes", [
1570
+ String
1571
+ ]),
1572
+ _ts_metadata9("design:returntype", String)
1573
+ ], AdminMfaSetupCommand.prototype, "parseAs", null);
1574
+ _ts_decorate10([
1575
+ (0, import_nest_commander2.Option)({
1576
+ flags: "--force",
1577
+ description: "bestehendes Secret ohne R\xFCckfrage \xFCberschreiben"
1578
+ }),
1579
+ _ts_metadata9("design:type", Function),
1580
+ _ts_metadata9("design:paramtypes", []),
1581
+ _ts_metadata9("design:returntype", Boolean)
1582
+ ], AdminMfaSetupCommand.prototype, "parseForce", null);
1583
+ AdminMfaSetupCommand = _ts_decorate10([
1584
+ (0, import_common10.Injectable)(),
1585
+ (0, import_nest_commander2.SubCommand)({
1586
+ name: "mfa-setup",
1587
+ description: "TOTP-MFA f\xFCr den eigenen SuperAdmin einrichten"
1588
+ }),
1589
+ _ts_param7(0, (0, import_common10.Inject)(CLI_CONTEXT_CONFIG_TOKEN)),
1590
+ _ts_metadata9("design:type", Function),
1591
+ _ts_metadata9("design:paramtypes", [
1592
+ typeof CliContextConfig === "undefined" ? Object : CliContextConfig,
1593
+ typeof MfaSetupFlow === "undefined" ? Object : MfaSetupFlow
1594
+ ])
1595
+ ], AdminMfaSetupCommand);
1596
+ var AdminCommands = class extends import_nest_commander2.CommandRunner {
1597
+ static {
1598
+ __name(this, "AdminCommands");
1599
+ }
1600
+ async run() {
1601
+ process.stderr.write("Bitte Sub-Command angeben: whoami, mfa-setup.\n");
1602
+ process.exit(2);
1603
+ }
1604
+ };
1605
+ AdminCommands = _ts_decorate10([
1606
+ (0, import_common10.Injectable)(),
1607
+ (0, import_nest_commander2.Command)({
1608
+ name: "admin",
1609
+ description: "SuperAdmin-Operations (whoami, mfa-setup)",
1610
+ subCommands: [
1611
+ AdminWhoamiCommand,
1612
+ AdminMfaSetupCommand
1613
+ ]
1614
+ })
1615
+ ], AdminCommands);
1616
+
1617
+ // src/audit.command.ts
1618
+ var import_common11 = require("@nestjs/common");
1619
+ var import_nest_commander3 = require("nest-commander");
1620
+ function _ts_decorate11(decorators, target, key, desc) {
1621
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1622
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
1623
+ 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;
1624
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
1625
+ }
1626
+ __name(_ts_decorate11, "_ts_decorate");
1627
+ function _ts_metadata10(k, v) {
1628
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
1629
+ }
1630
+ __name(_ts_metadata10, "_ts_metadata");
1631
+ var AuditTailCommand = class extends import_nest_commander3.CommandRunner {
1632
+ static {
1633
+ __name(this, "AuditTailCommand");
1634
+ }
1635
+ ctx;
1636
+ flow;
1637
+ constructor(ctx, flow) {
1638
+ super(), this.ctx = ctx, this.flow = flow;
1639
+ }
1640
+ async run(_args, flags) {
1641
+ const identity = this.ctx.resolveIdentity(flags.as);
1642
+ await this.ctx.ensureSuperAdmin(identity);
1643
+ const entries = await this.flow.run({
1644
+ actor: flags.actor,
1645
+ action: flags.action,
1646
+ entity: flags.entity,
1647
+ since: flags.since,
1648
+ limit: flags.limit
1649
+ });
1650
+ this.ctx.table(this.flow.formatRows(entries));
1651
+ }
1652
+ parseAs(v) {
1653
+ return v;
1654
+ }
1655
+ parseActor(v) {
1656
+ return v;
1657
+ }
1658
+ parseAction(v) {
1659
+ return v;
1660
+ }
1661
+ parseEntity(v) {
1662
+ return v;
1663
+ }
1664
+ parseSince(v) {
1665
+ return v;
1666
+ }
1667
+ parseLimit(v) {
1668
+ return Number.parseInt(v, 10);
1669
+ }
1670
+ };
1671
+ _ts_decorate11([
1672
+ (0, import_nest_commander3.Option)({
1673
+ flags: "--as <email>"
1674
+ }),
1675
+ _ts_metadata10("design:type", Function),
1676
+ _ts_metadata10("design:paramtypes", [
1677
+ String
1678
+ ]),
1679
+ _ts_metadata10("design:returntype", String)
1680
+ ], AuditTailCommand.prototype, "parseAs", null);
1681
+ _ts_decorate11([
1682
+ (0, import_nest_commander3.Option)({
1683
+ flags: "--actor <email>"
1684
+ }),
1685
+ _ts_metadata10("design:type", Function),
1686
+ _ts_metadata10("design:paramtypes", [
1687
+ String
1688
+ ]),
1689
+ _ts_metadata10("design:returntype", String)
1690
+ ], AuditTailCommand.prototype, "parseActor", null);
1691
+ _ts_decorate11([
1692
+ (0, import_nest_commander3.Option)({
1693
+ flags: "--action <name>"
1694
+ }),
1695
+ _ts_metadata10("design:type", Function),
1696
+ _ts_metadata10("design:paramtypes", [
1697
+ String
1698
+ ]),
1699
+ _ts_metadata10("design:returntype", String)
1700
+ ], AuditTailCommand.prototype, "parseAction", null);
1701
+ _ts_decorate11([
1702
+ (0, import_nest_commander3.Option)({
1703
+ flags: "--entity <name>"
1704
+ }),
1705
+ _ts_metadata10("design:type", Function),
1706
+ _ts_metadata10("design:paramtypes", [
1707
+ String
1708
+ ]),
1709
+ _ts_metadata10("design:returntype", String)
1710
+ ], AuditTailCommand.prototype, "parseEntity", null);
1711
+ _ts_decorate11([
1712
+ (0, import_nest_commander3.Option)({
1713
+ flags: "--since <iso-date>"
1714
+ }),
1715
+ _ts_metadata10("design:type", Function),
1716
+ _ts_metadata10("design:paramtypes", [
1717
+ String
1718
+ ]),
1719
+ _ts_metadata10("design:returntype", String)
1720
+ ], AuditTailCommand.prototype, "parseSince", null);
1721
+ _ts_decorate11([
1722
+ (0, import_nest_commander3.Option)({
1723
+ flags: "--limit <n>"
1724
+ }),
1725
+ _ts_metadata10("design:type", Function),
1726
+ _ts_metadata10("design:paramtypes", [
1727
+ String
1728
+ ]),
1729
+ _ts_metadata10("design:returntype", Number)
1730
+ ], AuditTailCommand.prototype, "parseLimit", null);
1731
+ AuditTailCommand = _ts_decorate11([
1732
+ (0, import_common11.Injectable)(),
1733
+ (0, import_nest_commander3.SubCommand)({
1734
+ name: "tail",
1735
+ description: "Letzte Audit-Log-Eintr\xE4ge (--actor/--action/--entity/--since/--limit)"
1736
+ }),
1737
+ _ts_metadata10("design:type", Function),
1738
+ _ts_metadata10("design:paramtypes", [
1739
+ typeof CliContextService === "undefined" ? Object : CliContextService,
1740
+ typeof AuditTailFlow === "undefined" ? Object : AuditTailFlow
1741
+ ])
1742
+ ], AuditTailCommand);
1743
+ var AuditCommands = class extends import_nest_commander3.CommandRunner {
1744
+ static {
1745
+ __name(this, "AuditCommands");
1746
+ }
1747
+ async run() {
1748
+ process.stderr.write("Bitte Sub-Command angeben: tail.\n");
1749
+ process.exit(2);
1750
+ }
1751
+ };
1752
+ AuditCommands = _ts_decorate11([
1753
+ (0, import_common11.Injectable)(),
1754
+ (0, import_nest_commander3.Command)({
1755
+ name: "audit",
1756
+ description: "Audit-Log-Operations (tail)",
1757
+ subCommands: [
1758
+ AuditTailCommand
1759
+ ]
1760
+ })
1761
+ ], AuditCommands);
1762
+
1763
+ // src/doctor.command.ts
1764
+ var import_common12 = require("@nestjs/common");
1765
+ var import_nest_commander4 = require("nest-commander");
1766
+ function _ts_decorate12(decorators, target, key, desc) {
1767
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1768
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
1769
+ 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;
1770
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
1771
+ }
1772
+ __name(_ts_decorate12, "_ts_decorate");
1773
+ function _ts_metadata11(k, v) {
1774
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
1775
+ }
1776
+ __name(_ts_metadata11, "_ts_metadata");
1777
+ var DoctorCommands = class extends import_nest_commander4.CommandRunner {
1778
+ static {
1779
+ __name(this, "DoctorCommands");
1780
+ }
1781
+ ctx;
1782
+ flow;
1783
+ constructor(ctx, flow) {
1784
+ super(), this.ctx = ctx, this.flow = flow;
1785
+ }
1786
+ async run(_args, flags) {
1787
+ const identity = this.ctx.resolveIdentity(flags.as);
1788
+ await this.ctx.ensureSuperAdmin(identity);
1789
+ const report = await this.flow.run();
1790
+ process.stdout.write(this.flow.formatReport(report) + "\n");
1791
+ const code = this.flow.exitCodeFor(report);
1792
+ if (code !== 0) process.exit(code);
1793
+ }
1794
+ parseAs(v) {
1795
+ return v;
1796
+ }
1797
+ };
1798
+ _ts_decorate12([
1799
+ (0, import_nest_commander4.Option)({
1800
+ flags: "--as <email>"
1801
+ }),
1802
+ _ts_metadata11("design:type", Function),
1803
+ _ts_metadata11("design:paramtypes", [
1804
+ String
1805
+ ]),
1806
+ _ts_metadata11("design:returntype", String)
1807
+ ], DoctorCommands.prototype, "parseAs", null);
1808
+ DoctorCommands = _ts_decorate12([
1809
+ (0, import_common12.Injectable)(),
1810
+ (0, import_nest_commander4.Command)({
1811
+ name: "doctor",
1812
+ description: "Health-/Drift-Checks (Exit-Code 4 bei error)"
1813
+ }),
1814
+ _ts_metadata11("design:type", Function),
1815
+ _ts_metadata11("design:paramtypes", [
1816
+ typeof CliContextService === "undefined" ? Object : CliContextService,
1817
+ typeof DoctorFlow === "undefined" ? Object : DoctorFlow
1818
+ ])
1819
+ ], DoctorCommands);
1820
+
1821
+ // src/discovery.command.ts
1822
+ var import_node_fs = require("fs");
1823
+ var import_node_path = require("path");
1824
+ var import_common13 = require("@nestjs/common");
1825
+ var import_nest_commander5 = require("nest-commander");
1826
+ var import_nest6 = require("@saasicat/nest");
1827
+ function _ts_decorate13(decorators, target, key, desc) {
1828
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1829
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
1830
+ 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;
1831
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
1832
+ }
1833
+ __name(_ts_decorate13, "_ts_decorate");
1834
+ function _ts_metadata12(k, v) {
1835
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
1836
+ }
1837
+ __name(_ts_metadata12, "_ts_metadata");
1838
+ function _ts_param8(paramIndex, decorator) {
1839
+ return function(target, key) {
1840
+ decorator(target, key, paramIndex);
1841
+ };
1842
+ }
1843
+ __name(_ts_param8, "_ts_param");
1844
+ var DiscoveryScanCommand = class extends import_nest_commander5.CommandRunner {
1845
+ static {
1846
+ __name(this, "DiscoveryScanCommand");
1847
+ }
1848
+ scanner;
1849
+ configuredPath;
1850
+ constructor(scanner = null, configuredPath = null) {
1851
+ super(), this.scanner = scanner, this.configuredPath = configuredPath;
1852
+ }
1853
+ async run(_args, flags) {
1854
+ if (!this.scanner) {
1855
+ this.fail("DiscoveryScanner nicht registriert \u2014 DiscoveryModule.forRoot() im CLI-Modul importieren.", flags);
1856
+ return;
1857
+ }
1858
+ try {
1859
+ const snapshot = this.scanner.rebuildSnapshot();
1860
+ if (flags.out) {
1861
+ const outPath = (0, import_node_path.resolve)(flags.out);
1862
+ (0, import_node_fs.mkdirSync)((0, import_node_path.dirname)(outPath), {
1863
+ recursive: true
1864
+ });
1865
+ (0, import_node_fs.writeFileSync)(outPath, JSON.stringify(snapshot, null, 2) + "\n", "utf-8");
1866
+ }
1867
+ const target = flags.out ?? this.configuredPath;
1868
+ process.stdout.write(`Discovery-Scan (${snapshot.app.key} v${snapshot.app.version}): ${snapshot.capabilities.length} Capabilities \xB7 ${snapshot.features.length} Features \xB7 ${snapshot.quotas.length} Quotas \xB7 hash ${snapshot.hash.slice(0, 19)}\u2026
1869
+ `);
1870
+ if (target) {
1871
+ process.stdout.write(`Snapshot persistiert: ${(0, import_node_path.resolve)(target)}
1872
+ `);
1873
+ } else {
1874
+ process.stderr.write("WARNUNG: Snapshot wurde nicht persistiert \u2014 weder snapshotPath (DiscoveryModule.forRoot) konfiguriert noch --out angegeben. Das Seed-Gate findet so keinen Snapshot.\n");
1875
+ }
1876
+ } catch (err2) {
1877
+ this.fail(err2 instanceof Error ? err2.message : String(err2), flags);
1878
+ }
1879
+ }
1880
+ /** Exit 4 (analogous to Seed-Gate/Preflight) — only a warning with `--non-fatal`. */
1881
+ fail(message, flags) {
1882
+ if (flags.nonFatal) {
1883
+ process.stderr.write(`[discovery scan] WARN (non-fatal): ${message}
1884
+ `);
1885
+ return;
1886
+ }
1887
+ process.stderr.write(`[discovery scan] FEHLER: ${message}
1888
+ `);
1889
+ process.exit(4);
1890
+ }
1891
+ parseOut(v) {
1892
+ return v;
1893
+ }
1894
+ parseNonFatal() {
1895
+ return true;
1896
+ }
1897
+ };
1898
+ _ts_decorate13([
1899
+ (0, import_nest_commander5.Option)({
1900
+ flags: "--out <path>",
1901
+ description: "Snapshot zus\xE4tzlich an diesen Pfad schreiben"
1902
+ }),
1903
+ _ts_metadata12("design:type", Function),
1904
+ _ts_metadata12("design:paramtypes", [
1905
+ String
1906
+ ]),
1907
+ _ts_metadata12("design:returntype", String)
1908
+ ], DiscoveryScanCommand.prototype, "parseOut", null);
1909
+ _ts_decorate13([
1910
+ (0, import_nest_commander5.Option)({
1911
+ flags: "--non-fatal",
1912
+ description: "Scan-Fehler nur als Warnung melden (Exit 0) \u2014 gestufter Rollout"
1913
+ }),
1914
+ _ts_metadata12("design:type", Function),
1915
+ _ts_metadata12("design:paramtypes", []),
1916
+ _ts_metadata12("design:returntype", Boolean)
1917
+ ], DiscoveryScanCommand.prototype, "parseNonFatal", null);
1918
+ DiscoveryScanCommand = _ts_decorate13([
1919
+ (0, import_common13.Injectable)(),
1920
+ (0, import_nest_commander5.SubCommand)({
1921
+ name: "scan",
1922
+ description: "Discovery-Snapshot headless erzeugen + persistieren (Seed-Gate, #23)"
1923
+ }),
1924
+ _ts_param8(0, (0, import_common13.Optional)()),
1925
+ _ts_param8(0, (0, import_common13.Inject)(import_nest6.DiscoveryScanner)),
1926
+ _ts_param8(1, (0, import_common13.Optional)()),
1927
+ _ts_param8(1, (0, import_common13.Inject)(import_nest6.DISCOVERY_SNAPSHOT_PATH_TOKEN)),
1928
+ _ts_metadata12("design:type", Function),
1929
+ _ts_metadata12("design:paramtypes", [
1930
+ Object,
1931
+ Object
1932
+ ])
1933
+ ], DiscoveryScanCommand);
1934
+ var DiscoveryCommands = class extends import_nest_commander5.CommandRunner {
1935
+ static {
1936
+ __name(this, "DiscoveryCommands");
1937
+ }
1938
+ async run() {
1939
+ process.stderr.write("Bitte Sub-Command angeben: scan.\n");
1940
+ process.exit(2);
1941
+ }
1942
+ };
1943
+ DiscoveryCommands = _ts_decorate13([
1944
+ (0, import_common13.Injectable)(),
1945
+ (0, import_nest_commander5.Command)({
1946
+ name: "discovery",
1947
+ description: "Discovery-Operations (scan)",
1948
+ subCommands: [
1949
+ DiscoveryScanCommand
1950
+ ]
1951
+ })
1952
+ ], DiscoveryCommands);
1953
+
1954
+ // src/user.command.ts
1955
+ var import_common14 = require("@nestjs/common");
1956
+ var import_node_crypto = require("crypto");
1957
+ var import_nest_commander6 = require("nest-commander");
1958
+ function _ts_decorate14(decorators, target, key, desc) {
1959
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
1960
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
1961
+ 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;
1962
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
1963
+ }
1964
+ __name(_ts_decorate14, "_ts_decorate");
1965
+ function _ts_metadata13(k, v) {
1966
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
1967
+ }
1968
+ __name(_ts_metadata13, "_ts_metadata");
1969
+ function _ts_param9(paramIndex, decorator) {
1970
+ return function(target, key) {
1971
+ decorator(target, key, paramIndex);
1972
+ };
1973
+ }
1974
+ __name(_ts_param9, "_ts_param");
1975
+ var AUDIT_ENTITY = "User";
1976
+ function generatePassword() {
1977
+ return (0, import_node_crypto.randomBytes)(12).toString("base64url");
1978
+ }
1979
+ __name(generatePassword, "generatePassword");
1980
+ var UserCommands = class extends import_nest_commander6.CommandRunner {
1981
+ static {
1982
+ __name(this, "UserCommands");
1983
+ }
1984
+ ctx;
1985
+ users;
1986
+ constructor(ctx, users) {
1987
+ super(), this.ctx = ctx, this.users = users;
1988
+ }
1989
+ async run(args, flags) {
1990
+ const sub = args[0];
1991
+ const identity = this.ctx.resolveIdentity(flags.as);
1992
+ const me = await this.ctx.ensureSuperAdmin(identity);
1993
+ switch (sub) {
1994
+ case "create-super-admin":
1995
+ return this.createSuperAdmin(args[1], flags, identity, me.id, me.email);
1996
+ case "reassign-admin":
1997
+ return this.reassignAdmin(args[1], flags, identity, me.id);
1998
+ case "list":
1999
+ return this.list(args[1]);
2000
+ case "reset-password":
2001
+ return this.resetPassword(args[1], flags, identity, me.id);
2002
+ case "deactivate":
2003
+ return this.deactivate(args[1], flags, identity, me.id);
2004
+ default:
2005
+ throw new CliError("UNKNOWN_SUBCOMMAND", `Unbekannter Subbefehl: user ${sub ?? "(leer)"}. Verf\xFCgbar: create-super-admin <email>, reassign-admin <slug>, list <slug>, reset-password <email>, deactivate <email>.`, 1);
2006
+ }
2007
+ }
2008
+ async createSuperAdmin(email, flags, identity, meId, meEmail) {
2009
+ if (!email) {
2010
+ throw new CliError("MISSING_ARG", "user create-super-admin <email> erwartet eine E-Mail.", 1);
2011
+ }
2012
+ await this.ctx.requireMfa(meId);
2013
+ await this.ctx.ensureProductionConfirmation({
2014
+ yes: flags.yes
2015
+ });
2016
+ const generated = !flags.password;
2017
+ const password = flags.password ?? generatePassword();
2018
+ const created = await this.users.createSuperAdmin({
2019
+ email: email.toLowerCase(),
2020
+ password,
2021
+ firstName: flags.first,
2022
+ lastName: flags.last
2023
+ });
2024
+ await this.ctx.log({
2025
+ identity,
2026
+ userId: meId,
2027
+ entity: AUDIT_ENTITY,
2028
+ entityId: created.id,
2029
+ action: "SUPER_ADMIN_CREATE",
2030
+ changes: {
2031
+ email: created.email,
2032
+ createdBy: meEmail
2033
+ }
2034
+ });
2035
+ console.log(`\u2714 SUPER_ADMIN ${created.email} angelegt (durch ${meEmail}).`);
2036
+ console.log(` User-ID: ${created.id}`);
2037
+ if (generated) {
2038
+ console.log(` Passwort: ${password}`);
2039
+ console.log(" \u2192 Sicher \xFCbermitteln. Beim ersten Login \xE4ndern.");
2040
+ }
2041
+ console.log(` N\xE4chster Schritt: admin mfa-setup f\xFCr ${created.email}.`);
2042
+ }
2043
+ async reassignAdmin(slug, flags, identity, meId) {
2044
+ if (!slug) {
2045
+ throw new CliError("MISSING_ARG", "user reassign-admin <tenant-slug> erwartet einen Slug.", 1);
2046
+ }
2047
+ if (!flags.to) throw new CliError("MISSING_FLAG", "--to=<email> ist Pflicht.", 1);
2048
+ if (!flags.reason) throw new CliError("MISSING_FLAG", '--reason="\u2026" ist Pflicht.', 1);
2049
+ await this.ctx.requireMfa(meId);
2050
+ const result = await this.users.reassignTenantAdmin(slug, flags.to.toLowerCase());
2051
+ await this.ctx.log({
2052
+ identity,
2053
+ userId: meId,
2054
+ entity: AUDIT_ENTITY,
2055
+ entityId: result.user.id,
2056
+ action: result.created ? "USER_REASSIGN_ADMIN" : "USER_ROLE_CHANGE",
2057
+ changes: {
2058
+ tenant: slug,
2059
+ to: "TENANT_ADMIN",
2060
+ from: result.previousRole,
2061
+ reason: flags.reason,
2062
+ emergency: true
2063
+ }
2064
+ });
2065
+ if (result.created) {
2066
+ console.log(`\u2714 Notfall-Admin ${result.user.email} f\xFCr ${slug} angelegt.`);
2067
+ if (result.oneTimePassword) {
2068
+ console.log(` Initial-Passwort: ${result.oneTimePassword}`);
2069
+ console.log(" \u2192 Sicher \xFCbermitteln. Beim ersten Login \xE4ndern.");
2070
+ }
2071
+ } else {
2072
+ console.log(`\u2714 ${result.user.email} ist jetzt TENANT_ADMIN von ${slug}.`);
2073
+ }
2074
+ }
2075
+ async list(slug) {
2076
+ if (!slug) {
2077
+ throw new CliError("MISSING_ARG", "user list <tenant-slug> erwartet einen Slug.", 1);
2078
+ }
2079
+ const rows = await this.users.listTenantUsers(slug);
2080
+ this.ctx.table(rows.map((u) => ({
2081
+ email: u.email,
2082
+ role: u.role,
2083
+ status: u.status,
2084
+ lastLogin: u.lastLoginAt?.slice(0, 10) ?? "\u2014"
2085
+ })));
2086
+ }
2087
+ async resetPassword(email, flags, identity, meId) {
2088
+ if (!email) {
2089
+ throw new CliError("MISSING_ARG", "user reset-password <email> erwartet eine E-Mail.", 1);
2090
+ }
2091
+ if (!flags.reason) throw new CliError("MISSING_FLAG", '--reason="\u2026" ist Pflicht.', 1);
2092
+ const result = await this.users.triggerPasswordReset(email.toLowerCase());
2093
+ await this.ctx.log({
2094
+ identity,
2095
+ userId: meId,
2096
+ entity: AUDIT_ENTITY,
2097
+ entityId: result.user.id,
2098
+ action: "USER_PASSWORD_RESET_TRIGGERED",
2099
+ changes: {
2100
+ reason: flags.reason
2101
+ }
2102
+ });
2103
+ if (result.oneTimePassword) {
2104
+ console.log(`\u2714 Einmal-Passwort f\xFCr ${result.user.email} gesetzt.`);
2105
+ console.log(` Passwort: ${result.oneTimePassword}`);
2106
+ console.log(" \u2192 Sicher \xFCbermitteln. Beim ersten Login \xE4ndern.");
2107
+ } else {
2108
+ console.log(`\u2714 Passwort-Reset f\xFCr ${result.user.email} ausgel\xF6st.`);
2109
+ }
2110
+ }
2111
+ async deactivate(email, flags, identity, meId) {
2112
+ if (!email) {
2113
+ throw new CliError("MISSING_ARG", "user deactivate <email> erwartet eine E-Mail.", 1);
2114
+ }
2115
+ if (!flags.reason) throw new CliError("MISSING_FLAG", '--reason="\u2026" ist Pflicht.', 1);
2116
+ await this.ctx.requireMfa(meId);
2117
+ await this.ctx.ensureProductionConfirmation({
2118
+ yes: flags.yes
2119
+ });
2120
+ const user = await this.users.deactivate(email.toLowerCase(), flags.reason);
2121
+ await this.ctx.log({
2122
+ identity,
2123
+ userId: meId,
2124
+ entity: AUDIT_ENTITY,
2125
+ entityId: user.id,
2126
+ action: "USER_DEACTIVATED",
2127
+ changes: {
2128
+ reason: flags.reason,
2129
+ emergency: true
2130
+ }
2131
+ });
2132
+ console.log(`\u2714 ${user.email} deaktiviert.`);
2133
+ }
2134
+ parseAs(val) {
2135
+ return val;
2136
+ }
2137
+ parseTo(val) {
2138
+ return val;
2139
+ }
2140
+ parseReason(val) {
2141
+ return val;
2142
+ }
2143
+ parseYes() {
2144
+ return true;
2145
+ }
2146
+ parseFirst(val) {
2147
+ return val;
2148
+ }
2149
+ parseLast(val) {
2150
+ return val;
2151
+ }
2152
+ parsePassword(val) {
2153
+ return val;
2154
+ }
2155
+ };
2156
+ _ts_decorate14([
2157
+ (0, import_nest_commander6.Option)({
2158
+ flags: "--as <email>",
2159
+ description: "CLI-Identit\xE4t (sonst <APP>_ADMIN_EMAIL)"
2160
+ }),
2161
+ _ts_metadata13("design:type", Function),
2162
+ _ts_metadata13("design:paramtypes", [
2163
+ String
2164
+ ]),
2165
+ _ts_metadata13("design:returntype", String)
2166
+ ], UserCommands.prototype, "parseAs", null);
2167
+ _ts_decorate14([
2168
+ (0, import_nest_commander6.Option)({
2169
+ flags: "--to <email>",
2170
+ description: "Ziel-User (reassign-admin)"
2171
+ }),
2172
+ _ts_metadata13("design:type", Function),
2173
+ _ts_metadata13("design:paramtypes", [
2174
+ String
2175
+ ]),
2176
+ _ts_metadata13("design:returntype", String)
2177
+ ], UserCommands.prototype, "parseTo", null);
2178
+ _ts_decorate14([
2179
+ (0, import_nest_commander6.Option)({
2180
+ flags: "--reason <text>",
2181
+ description: "Begr\xFCndung (Audit)"
2182
+ }),
2183
+ _ts_metadata13("design:type", Function),
2184
+ _ts_metadata13("design:paramtypes", [
2185
+ String
2186
+ ]),
2187
+ _ts_metadata13("design:returntype", String)
2188
+ ], UserCommands.prototype, "parseReason", null);
2189
+ _ts_decorate14([
2190
+ (0, import_nest_commander6.Option)({
2191
+ flags: "-y, --yes",
2192
+ description: "Production-Confirmation \xFCberspringen"
2193
+ }),
2194
+ _ts_metadata13("design:type", Function),
2195
+ _ts_metadata13("design:paramtypes", []),
2196
+ _ts_metadata13("design:returntype", Boolean)
2197
+ ], UserCommands.prototype, "parseYes", null);
2198
+ _ts_decorate14([
2199
+ (0, import_nest_commander6.Option)({
2200
+ flags: "--first <name>",
2201
+ description: "Vorname (create-super-admin)"
2202
+ }),
2203
+ _ts_metadata13("design:type", Function),
2204
+ _ts_metadata13("design:paramtypes", [
2205
+ String
2206
+ ]),
2207
+ _ts_metadata13("design:returntype", String)
2208
+ ], UserCommands.prototype, "parseFirst", null);
2209
+ _ts_decorate14([
2210
+ (0, import_nest_commander6.Option)({
2211
+ flags: "--last <name>",
2212
+ description: "Nachname (create-super-admin)"
2213
+ }),
2214
+ _ts_metadata13("design:type", Function),
2215
+ _ts_metadata13("design:paramtypes", [
2216
+ String
2217
+ ]),
2218
+ _ts_metadata13("design:returntype", String)
2219
+ ], UserCommands.prototype, "parseLast", null);
2220
+ _ts_decorate14([
2221
+ (0, import_nest_commander6.Option)({
2222
+ flags: "--password <pwd>",
2223
+ description: "Passwort (create-super-admin; ohne Angabe generiert)"
2224
+ }),
2225
+ _ts_metadata13("design:type", Function),
2226
+ _ts_metadata13("design:paramtypes", [
2227
+ String
2228
+ ]),
2229
+ _ts_metadata13("design:returntype", String)
2230
+ ], UserCommands.prototype, "parsePassword", null);
2231
+ UserCommands = _ts_decorate14([
2232
+ (0, import_common14.Injectable)(),
2233
+ (0, import_nest_commander6.Command)({
2234
+ name: "user",
2235
+ description: "User-Operationen (create-super-admin, reassign-admin, list, reset-password, deactivate)"
2236
+ }),
2237
+ _ts_param9(1, (0, import_common14.Inject)(USER_MANAGEMENT_PORT_TOKEN)),
2238
+ _ts_metadata13("design:type", Function),
2239
+ _ts_metadata13("design:paramtypes", [
2240
+ typeof CliContextService === "undefined" ? Object : CliContextService,
2241
+ typeof UserManagementPort === "undefined" ? Object : UserManagementPort
2242
+ ])
2243
+ ], UserCommands);
2244
+ // Annotate the CommonJS export names for ESM import in node:
2245
+ 0 && (module.exports = {
2246
+ AUDIT_QUERY_PORT_TOKEN,
2247
+ AdminCommands,
2248
+ AdminManifestDoctorCheck,
2249
+ AdminMfaSetupCommand,
2250
+ AdminWhoamiCommand,
2251
+ AuditCommands,
2252
+ AuditTailCommand,
2253
+ AuditTailFlow,
2254
+ CLI_CONTEXT_CONFIG_TOKEN,
2255
+ CliContextModule,
2256
+ CliContextService,
2257
+ CliError,
2258
+ DEFAULT_MANIFEST_CHECKS,
2259
+ DOCTOR_CHECKS_TOKEN,
2260
+ DiscoveryCommands,
2261
+ DiscoveryScanCommand,
2262
+ DiscoverySnapshotDoctorCheck,
2263
+ DoctorCommands,
2264
+ DoctorFlow,
2265
+ MANIFEST_ACCESS_PORT_TOKEN,
2266
+ MANIFEST_CHECKS_TOKEN,
2267
+ ManifestCheckCommand,
2268
+ ManifestCliFlow,
2269
+ ManifestCommands,
2270
+ ManifestDumpCommand,
2271
+ ManifestHashCommand,
2272
+ ManifestValidateCommand,
2273
+ MfaSetupFlow,
2274
+ PLATFORM_DOCTOR_CHECK_PROVIDERS,
2275
+ PlanCatalogDoctorCheck,
2276
+ USER_MANAGEMENT_PORT_TOKEN,
2277
+ USER_PORT_TOKEN,
2278
+ UserCommands,
2279
+ UserPortDoctorCheck,
2280
+ WhoAmIFlow,
2281
+ applyFragmentBlocks,
2282
+ extractModelBlocks,
2283
+ extractModelNames
2284
+ });