@cosmicdrift/kumiko-dev-server 0.328.1 → 0.330.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/README.md +17 -0
- package/bin/kumiko-build.ts +3 -2
- package/bin/kumiko-dev.ts +1 -1
- package/bin/kumiko-init-deploy.ts +1 -1
- package/bin/kumiko-schema-check.ts +4 -1
- package/dist/build-server-bundle.d.ts +31 -0
- package/dist/build-server-bundle.js +282 -0
- package/dist/build.d.ts +2 -0
- package/dist/build.js +5 -0
- package/dist/cli.d.ts +5 -0
- package/dist/cli.js +9 -0
- package/dist/codegen/index.d.ts +4 -0
- package/dist/codegen/index.js +4 -0
- package/dist/codegen/render.d.ts +55 -0
- package/dist/codegen/render.js +273 -0
- package/dist/codegen/run-codegen.d.ts +20 -0
- package/dist/codegen/run-codegen.js +219 -0
- package/dist/codegen/scan-events.d.ts +76 -0
- package/dist/codegen/scan-events.js +447 -0
- package/dist/codegen/watch.d.ts +33 -0
- package/dist/codegen/watch.js +112 -0
- package/dist/compose-stacks.d.ts +60 -0
- package/dist/compose-stacks.js +127 -0
- package/dist/crash-tracker.d.ts +17 -0
- package/dist/crash-tracker.js +37 -0
- package/dist/create-kumiko-server.d.ts +195 -0
- package/dist/create-kumiko-server.js +1040 -0
- package/dist/env-schema.d.ts +15 -0
- package/dist/env-schema.js +60 -0
- package/dist/few-shot-corpus.d.ts +72 -0
- package/dist/few-shot-corpus.js +262 -0
- package/dist/framework-version.d.ts +1 -0
- package/dist/framework-version.js +31 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.js +33 -0
- package/dist/init-deploy-cli.d.ts +10 -0
- package/dist/init-deploy-cli.js +111 -0
- package/dist/kebab.d.ts +1 -0
- package/{src/kebab.ts → dist/kebab.js} +2 -3
- package/dist/run-dev-app.d.ts +174 -0
- package/dist/run-dev-app.js +403 -0
- package/dist/scaffold-app-feature.d.ts +16 -0
- package/dist/scaffold-app-feature.js +240 -0
- package/dist/scaffold-app.d.ts +45 -0
- package/dist/scaffold-app.js +852 -0
- package/dist/scaffold-demo-tasks.d.ts +8 -0
- package/{src/scaffold-demo-tasks.ts → dist/scaffold-demo-tasks.js} +69 -98
- package/dist/scaffold-deploy.d.ts +92 -0
- package/dist/scaffold-deploy.js +254 -0
- package/dist/scaffold-feature.d.ts +26 -0
- package/dist/scaffold-feature.js +163 -0
- package/dist/schema-apply.d.ts +11 -0
- package/dist/schema-apply.js +95 -0
- package/dist/schema-check-core.d.ts +2 -0
- package/{src/schema-check-core.ts → dist/schema-check-core.js} +8 -10
- package/dist/schema-tables-auth-mode.d.ts +2 -0
- package/{src/schema-tables-auth-mode.ts → dist/schema-tables-auth-mode.js} +2 -10
- package/dist/schema-tables-minimal.d.ts +2 -0
- package/{src/schema-tables-minimal.ts → dist/schema-tables-minimal.js} +2 -11
- package/dist/setup-test-stack-from-features.d.ts +11 -0
- package/dist/setup-test-stack-from-features.js +42 -0
- package/dist/welcome-banner.d.ts +15 -0
- package/dist/welcome-banner.js +27 -0
- package/package.json +71 -24
- package/src/changes.json +6 -0
- package/src/__tests__/build-prod-bundle.integration.test.ts +0 -282
- package/src/__tests__/build-server-bundle.test.ts +0 -228
- package/src/__tests__/classify-change.test.ts +0 -87
- package/src/__tests__/compose-stacks.test.ts +0 -273
- package/src/__tests__/config-resolver-default.integration.test.ts +0 -165
- package/src/__tests__/crash-tracker.test.ts +0 -89
- package/src/__tests__/create-kumiko-server-errors.test.ts +0 -54
- package/src/__tests__/create-kumiko-server-options.test.ts +0 -33
- package/src/__tests__/create-kumiko-server.integration.test.ts +0 -1007
- package/src/__tests__/discover-format.test.ts +0 -32
- package/src/__tests__/env-schema.integration.test.ts +0 -248
- package/src/__tests__/env-schema.test.ts +0 -132
- package/src/__tests__/few-shot-corpus.test.ts +0 -316
- package/src/__tests__/framework-version.test.ts +0 -45
- package/src/__tests__/init-deploy-cli.test.ts +0 -113
- package/src/__tests__/kumiko-schema-check.test.ts +0 -56
- package/src/__tests__/merge-extra-context.test.ts +0 -67
- package/src/__tests__/resolve-stylesheet.test.ts +0 -132
- package/src/__tests__/run-dev-app-boot-validation.test.ts +0 -38
- package/src/__tests__/run-dev-app.integration.test.ts +0 -290
- package/src/__tests__/runtime-classification.test.ts +0 -26
- package/src/__tests__/saas-identity-wire.integration.test.ts +0 -427
- package/src/__tests__/scaffold-app-feature.test.ts +0 -216
- package/src/__tests__/scaffold-app.test.ts +0 -630
- package/src/__tests__/scaffold-demo-tasks.test.ts +0 -47
- package/src/__tests__/scaffold-deploy.test.ts +0 -464
- package/src/__tests__/scaffold-dev-cycle.integration.test.ts +0 -109
- package/src/__tests__/scaffold-feature.test.ts +0 -143
- package/src/__tests__/schema-apply.integration.test.ts +0 -191
- package/src/__tests__/setup-test-stack-from-features.integration.test.ts +0 -30
- package/src/__tests__/setup-test-stack-job-run-logger.integration.test.ts +0 -72
- package/src/__tests__/walkthrough.integration.test.ts +0 -140
- package/src/__tests__/welcome-banner.test.ts +0 -42
- package/src/build-server-bundle.ts +0 -346
- package/src/build.ts +0 -28
- package/src/codegen/__tests__/render-codegen.test.ts +0 -100
- package/src/codegen/__tests__/run-codegen.test.ts +0 -665
- package/src/codegen/__tests__/strict-mode-diagnostics.test.ts +0 -347
- package/src/codegen/__tests__/watch.test.ts +0 -222
- package/src/codegen/index.ts +0 -19
- package/src/codegen/render.ts +0 -305
- package/src/codegen/run-codegen.ts +0 -278
- package/src/codegen/scan-events.ts +0 -565
- package/src/codegen/watch.ts +0 -140
- package/src/compose-stacks.ts +0 -193
- package/src/crash-tracker.ts +0 -56
- package/src/create-kumiko-server.ts +0 -1397
- package/src/env-schema.ts +0 -72
- package/src/few-shot-corpus.ts +0 -370
- package/src/framework-version.ts +0 -39
- package/src/index.ts +0 -105
- package/src/init-deploy-cli.ts +0 -148
- package/src/run-dev-app.ts +0 -694
- package/src/scaffold-app-feature.ts +0 -283
- package/src/scaffold-app.ts +0 -1033
- package/src/scaffold-deploy.ts +0 -393
- package/src/scaffold-feature.ts +0 -226
- package/src/schema-apply.ts +0 -123
- package/src/setup-test-stack-from-features.ts +0 -80
- package/src/welcome-banner.ts +0 -43
package/src/codegen/watch.ts
DELETED
|
@@ -1,140 +0,0 @@
|
|
|
1
|
-
// watchAndRegenerate — file-watcher der bei jeder TS-Änderung unter
|
|
2
|
-
// `<appRoot>/src/**` `runCodegen` neu fährt. Lebendige IDE-DX: User
|
|
3
|
-
// editiert ein r.defineEvent, drückt save, das `.kumiko/types.generated.d.ts`
|
|
4
|
-
// ist innerhalb von ~50ms aktualisiert, der TS-Sprachserver merkt es,
|
|
5
|
-
// neue Auto-Complete-Vorschläge erscheinen ohne Server-Restart.
|
|
6
|
-
//
|
|
7
|
-
// Implementation: node:fs.watch (recursive) auf `<appRoot>/src/`.
|
|
8
|
-
// Debounced damit ein batch-edit (z.B. find+replace via sed) nicht
|
|
9
|
-
// 50× hintereinander feuert. Idempotent — runCodegen schreibt nur bei
|
|
10
|
-
// echter Änderung, der Watcher kann ohne Schaden über-ruft werden.
|
|
11
|
-
//
|
|
12
|
-
// Nicht-Ziele: kein Watcher auf `node_modules`, `.kumiko`, `dist*`,
|
|
13
|
-
// `__tests__` (gleicher SKIP-Set wie scan-events). fs.watch's
|
|
14
|
-
// recursive-Mode liefert events für jede Subdir; wir filtern im
|
|
15
|
-
// Callback.
|
|
16
|
-
|
|
17
|
-
import { type FSWatcher, watch } from "node:fs";
|
|
18
|
-
import { join } from "node:path";
|
|
19
|
-
import { runCodegen } from "./run-codegen";
|
|
20
|
-
import { formatScanWarning } from "./scan-events";
|
|
21
|
-
|
|
22
|
-
export type WatchOptions = {
|
|
23
|
-
/** App-Wurzel — gleiche Bedeutung wie für `runCodegen`. */
|
|
24
|
-
readonly appRoot: string;
|
|
25
|
-
/** Optional: alle registrierten Write-Handler-QNs. Durchgereicht an
|
|
26
|
-
* `runCodegen` für die Generierung der `WriteHandlerQn`-Union.
|
|
27
|
-
* Der Dev-Server extrahiert sie beim Boot aus den Features und
|
|
28
|
-
* reicht sie hier rein — der Watcher reicht sie bei jedem Re-Run
|
|
29
|
-
* an `runCodegen` weiter, damit der generated-Type nicht verschwindet. */
|
|
30
|
-
readonly handlerQns?: readonly string[];
|
|
31
|
-
/** Wartet diese Millisekunden zusätzliche Events ab, bevor codegen
|
|
32
|
-
* einmal fährt. 50ms catched typische save-bursts (Editor-Saves
|
|
33
|
-
* feuern oft 2-3 Events: temp-file → rename → cleanup), bleibt aber
|
|
34
|
-
* unmerklich für den User. */
|
|
35
|
-
readonly debounceMs?: number;
|
|
36
|
-
/** Callback nach jedem erfolgreichen Codegen-Pass. Default: stderr-
|
|
37
|
-
* Log mit event-count + warnings. Wer den Output strukturiert
|
|
38
|
-
* konsumieren will (Dev-Server-UI, IDE-Plugin), gibt einen eigenen
|
|
39
|
-
* Handler. */
|
|
40
|
-
readonly onResult?: (result: ReturnType<typeof runCodegen>) => void;
|
|
41
|
-
/** Callback bei runCodegen-Fehlern. Default: stderr-Warning. */
|
|
42
|
-
readonly onError?: (err: unknown) => void;
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
export type WatchHandle = {
|
|
46
|
-
/** Beendet den Watcher. Idempotent — mehrfacher Aufruf ist no-op. */
|
|
47
|
-
readonly close: () => void;
|
|
48
|
-
};
|
|
49
|
-
|
|
50
|
-
const SKIP_SUBSTRINGS = ["/node_modules/", "/.kumiko/", "/dist/", "/dist-server/", "/__tests__/"];
|
|
51
|
-
|
|
52
|
-
const DEFAULT_DEBOUNCE_MS = 50;
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Startet den Watcher. Beim Boot fährt einmalig `runCodegen` (sodass
|
|
56
|
-
* die generated Files sofort frisch sind), dann hängt sich an `fs.watch`
|
|
57
|
-
* und re-runs bei file-changes mit Debounce.
|
|
58
|
-
*/
|
|
59
|
-
export function watchAndRegenerate(opts: WatchOptions): WatchHandle {
|
|
60
|
-
const debounceMs = opts.debounceMs ?? DEFAULT_DEBOUNCE_MS;
|
|
61
|
-
const srcDir = join(opts.appRoot, "src");
|
|
62
|
-
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
63
|
-
let watcher: FSWatcher | undefined;
|
|
64
|
-
let closed = false;
|
|
65
|
-
|
|
66
|
-
const fire = () => {
|
|
67
|
-
try {
|
|
68
|
-
const result = runCodegen({
|
|
69
|
-
appRoot: opts.appRoot,
|
|
70
|
-
...(opts.handlerQns !== undefined && { handlerQns: opts.handlerQns }),
|
|
71
|
-
});
|
|
72
|
-
if (opts.onResult) {
|
|
73
|
-
opts.onResult(result);
|
|
74
|
-
} else {
|
|
75
|
-
if (result.warnings.length > 0) {
|
|
76
|
-
for (const w of result.warnings) {
|
|
77
|
-
// biome-ignore lint/suspicious/noConsole: codegen-watcher logs to terminal
|
|
78
|
-
console.warn(`[codegen] ${formatScanWarning(w)}`);
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
} catch (err) {
|
|
83
|
-
if (opts.onError) opts.onError(err);
|
|
84
|
-
else {
|
|
85
|
-
// biome-ignore lint/suspicious/noConsole: codegen-watcher logs to terminal
|
|
86
|
-
console.warn(
|
|
87
|
-
`[codegen] regenerate failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
88
|
-
);
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
};
|
|
92
|
-
|
|
93
|
-
// Initial run — gleiches Verhalten wie wenn ein file-change kam, aber
|
|
94
|
-
// ohne Debounce (User wartet auf den ersten codegen).
|
|
95
|
-
fire();
|
|
96
|
-
|
|
97
|
-
try {
|
|
98
|
-
watcher = watch(srcDir, { recursive: true }, (_eventType, filename) => {
|
|
99
|
-
// skip: watcher closed or no filename reported, nothing to act on
|
|
100
|
-
if (closed || !filename) return;
|
|
101
|
-
// node liefert filename relativ zu srcDir, kann aber posix oder
|
|
102
|
-
// windows-style separators haben. Wir prüfen substring-tolerant.
|
|
103
|
-
const normalised = `/${filename.toString().replace(/\\/g, "/")}`;
|
|
104
|
-
// skip: path matches an excluded segment (node_modules/dist/etc.)
|
|
105
|
-
if (SKIP_SUBSTRINGS.some((seg) => normalised.includes(seg))) return;
|
|
106
|
-
// skip: Nur .ts/.tsx interessieren — alles andere (CSS, MD, JSON) hat
|
|
107
|
-
// keinen Einfluss auf r.defineEvent-Calls.
|
|
108
|
-
if (!normalised.endsWith(".ts") && !normalised.endsWith(".tsx")) return;
|
|
109
|
-
// skip: .d.ts ausgenommen — die kommen meistens vom codegen selbst.
|
|
110
|
-
if (normalised.endsWith(".d.ts")) return;
|
|
111
|
-
// skip: .test.ts/.test.tsx ausgenommen — Tests definieren keine
|
|
112
|
-
// Production-Features.
|
|
113
|
-
if (normalised.endsWith(".test.ts") || normalised.endsWith(".test.tsx")) return;
|
|
114
|
-
|
|
115
|
-
if (timer) clearTimeout(timer);
|
|
116
|
-
timer = setTimeout(fire, debounceMs);
|
|
117
|
-
});
|
|
118
|
-
} catch (err) {
|
|
119
|
-
// Watch failed (z.B. fs nicht recursive-fähig auf Linux ohne
|
|
120
|
-
// patches) — degraded mode: codegen läuft nur beim initial-call.
|
|
121
|
-
// User kriegt keine live-updates, aber das ist nicht fatal.
|
|
122
|
-
if (opts.onError) opts.onError(err);
|
|
123
|
-
else {
|
|
124
|
-
// biome-ignore lint/suspicious/noConsole: codegen-watcher logs to terminal
|
|
125
|
-
console.warn(
|
|
126
|
-
`[codegen] watcher failed to start (live-updates disabled): ${err instanceof Error ? err.message : String(err)}`,
|
|
127
|
-
);
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
return {
|
|
132
|
-
close: () => {
|
|
133
|
-
// skip: already closed, avoid double-close
|
|
134
|
-
if (closed) return;
|
|
135
|
-
closed = true;
|
|
136
|
-
if (timer) clearTimeout(timer);
|
|
137
|
-
watcher?.close();
|
|
138
|
-
},
|
|
139
|
-
};
|
|
140
|
-
}
|
package/src/compose-stacks.ts
DELETED
|
@@ -1,193 +0,0 @@
|
|
|
1
|
-
// @runtime runtime
|
|
2
|
-
// Despite living in this "dev"-marked package, every preset here composes
|
|
3
|
-
// @cosmicdrift/kumiko-bundled-features factories, and run-config.ts in every
|
|
4
|
-
// app repo feeds it into the runProdApp boot path, not just runDevApp
|
|
5
|
-
// (kumiko-framework#2337).
|
|
6
|
-
//
|
|
7
|
-
// Composable SaaS stack presets — explicit opt-in blocks for run-config.ts.
|
|
8
|
-
// Presets export feature instances only; no implicit PAT scopes, anonymousAccess,
|
|
9
|
-
// or tier maps (those stay in bin/server.ts / app run-config).
|
|
10
|
-
|
|
11
|
-
import { createAuditFeature } from "@cosmicdrift/kumiko-bundled-features/audit";
|
|
12
|
-
import { authFoundationFeature } from "@cosmicdrift/kumiko-bundled-features/auth-foundation";
|
|
13
|
-
import {
|
|
14
|
-
type AuthMfaFeatureOptions,
|
|
15
|
-
createAuthMfaFeature,
|
|
16
|
-
} from "@cosmicdrift/kumiko-bundled-features/auth-mfa";
|
|
17
|
-
import { createComplianceProfilesFeature } from "@cosmicdrift/kumiko-bundled-features/compliance-profiles";
|
|
18
|
-
import { createDataRetentionFeature } from "@cosmicdrift/kumiko-bundled-features/data-retention";
|
|
19
|
-
import { createDeliveryFeature } from "@cosmicdrift/kumiko-bundled-features/delivery";
|
|
20
|
-
import { fileFoundationFeature } from "@cosmicdrift/kumiko-bundled-features/file-foundation";
|
|
21
|
-
import { fileProviderInMemoryFeature } from "@cosmicdrift/kumiko-bundled-features/file-provider-inmemory";
|
|
22
|
-
import { fileProviderS3Feature } from "@cosmicdrift/kumiko-bundled-features/file-provider-s3";
|
|
23
|
-
import { fileProviderS3EnvFeature } from "@cosmicdrift/kumiko-bundled-features/file-provider-s3-env";
|
|
24
|
-
import { createFilesFeature } from "@cosmicdrift/kumiko-bundled-features/files";
|
|
25
|
-
import { createJobsFeature } from "@cosmicdrift/kumiko-bundled-features/jobs";
|
|
26
|
-
import {
|
|
27
|
-
createLegalPagesFeature,
|
|
28
|
-
type LegalPagesOptions,
|
|
29
|
-
} from "@cosmicdrift/kumiko-bundled-features/legal-pages";
|
|
30
|
-
import { mailFoundationFeature } from "@cosmicdrift/kumiko-bundled-features/mail-foundation";
|
|
31
|
-
import { mailTransportInMemoryFeature } from "@cosmicdrift/kumiko-bundled-features/mail-transport-inmemory";
|
|
32
|
-
import { mailTransportSmtpFeature } from "@cosmicdrift/kumiko-bundled-features/mail-transport-smtp";
|
|
33
|
-
import { createRateLimitingFeature } from "@cosmicdrift/kumiko-bundled-features/rate-limiting";
|
|
34
|
-
import { createRendererFoundationFeature } from "@cosmicdrift/kumiko-bundled-features/renderer-foundation";
|
|
35
|
-
import { createRendererSimpleFeature } from "@cosmicdrift/kumiko-bundled-features/renderer-simple";
|
|
36
|
-
import { createSessionsFeature } from "@cosmicdrift/kumiko-bundled-features/sessions";
|
|
37
|
-
import { createTemplateResolverFeature } from "@cosmicdrift/kumiko-bundled-features/template-resolver";
|
|
38
|
-
import { createTenantLifecycleFeature } from "@cosmicdrift/kumiko-bundled-features/tenant-lifecycle";
|
|
39
|
-
|
|
40
|
-
import {
|
|
41
|
-
createUserDataRightsFeature,
|
|
42
|
-
type UserDataRightsOptions,
|
|
43
|
-
} from "@cosmicdrift/kumiko-bundled-features/user-data-rights";
|
|
44
|
-
import { createUserDataRightsDefaultsFeature } from "@cosmicdrift/kumiko-bundled-features/user-data-rights-defaults";
|
|
45
|
-
import type { FeatureDefinition } from "@cosmicdrift/kumiko-framework/engine";
|
|
46
|
-
|
|
47
|
-
export type FileProviderKind = "inmemory" | "s3" | "s3-env";
|
|
48
|
-
export type MailTransportKind = "inmemory" | "smtp";
|
|
49
|
-
export type GdprStackOrder = "retention-first" | "compliance-first";
|
|
50
|
-
|
|
51
|
-
export type FileStackOptions = {
|
|
52
|
-
readonly providers: readonly FileProviderKind[];
|
|
53
|
-
readonly includeFilesFeature?: boolean;
|
|
54
|
-
};
|
|
55
|
-
|
|
56
|
-
export type MailStackOptions = {
|
|
57
|
-
readonly transports: readonly MailTransportKind[];
|
|
58
|
-
};
|
|
59
|
-
|
|
60
|
-
export type PagesStackOptions = {
|
|
61
|
-
readonly wrapLayout?: LegalPagesOptions["wrapLayout"];
|
|
62
|
-
};
|
|
63
|
-
|
|
64
|
-
export type GdprStackOptions = {
|
|
65
|
-
readonly order?: GdprStackOrder;
|
|
66
|
-
readonly sessions?: boolean;
|
|
67
|
-
readonly tenantLifecycle?: boolean;
|
|
68
|
-
/** Optional tokenVerifier provider(s) (e.g. PAT) when `sessions` is on.
|
|
69
|
-
* Session-only stacks need none — sessions registers sessionStore, which
|
|
70
|
-
* satisfies auth-foundation's boot check (#1570). Pass providers when the
|
|
71
|
-
* app also wants Bearer/PAT auth. */
|
|
72
|
-
readonly providers?: readonly FeatureDefinition[];
|
|
73
|
-
};
|
|
74
|
-
|
|
75
|
-
export type UserDataRightsStackOptions = {
|
|
76
|
-
readonly userDataRights?: UserDataRightsOptions;
|
|
77
|
-
readonly includeDefaults?: boolean;
|
|
78
|
-
};
|
|
79
|
-
|
|
80
|
-
// `sessions` may live on composeIdentityStack OR composeGdprStack; both with default
|
|
81
|
-
// options is deduped at boot, differing options throw "Duplicate feature".
|
|
82
|
-
export type OpsStackOptions = {
|
|
83
|
-
readonly delivery?: boolean;
|
|
84
|
-
readonly audit?: boolean;
|
|
85
|
-
readonly jobs?: boolean;
|
|
86
|
-
readonly rateLimiting?: boolean;
|
|
87
|
-
};
|
|
88
|
-
|
|
89
|
-
/** sessions (+ optional auth-mfa). config/user/tenant/auth-email-password stay
|
|
90
|
-
* on composeFeatures(includeBundled). Pass `mfa` options to mount TOTP.
|
|
91
|
-
* When `sessions` is on (the default), auth-foundation is mounted alongside it —
|
|
92
|
-
* the framework's registry now hard-requires it (sessions.requires("auth-foundation")).
|
|
93
|
-
* Session-only is enough for boot (#1570); optional Bearer/PAT still needs a
|
|
94
|
-
* tokenVerifier provider from the caller (e.g. createPersonalAccessTokensFeature
|
|
95
|
-
* ({ scopes })) — PAT scopes are app-specific, so they stay caller-owned. */
|
|
96
|
-
export type IdentityStackOptions = {
|
|
97
|
-
readonly sessions?: boolean;
|
|
98
|
-
readonly mfa?: AuthMfaFeatureOptions;
|
|
99
|
-
};
|
|
100
|
-
|
|
101
|
-
export function stackFeatureNames(features: readonly FeatureDefinition[]): string[] {
|
|
102
|
-
return features.map((f) => f.name);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
export function composePagesStack(options: PagesStackOptions = {}): FeatureDefinition[] {
|
|
106
|
-
// Pages content lives in template-resolver (kind text-block), which the
|
|
107
|
-
// renderer stack already mounts — an app composing pages WITHOUT the renderer
|
|
108
|
-
// stack has to add createTemplateResolverFeature() itself, or legal-pages'
|
|
109
|
-
// r.requires fails the boot. Mounting it here instead would collide with
|
|
110
|
-
// composeRendererStack (createRegistry rejects duplicate features).
|
|
111
|
-
return [
|
|
112
|
-
createLegalPagesFeature(
|
|
113
|
-
options.wrapLayout !== undefined ? { wrapLayout: options.wrapLayout } : {},
|
|
114
|
-
),
|
|
115
|
-
];
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
export function composeRendererStack(): FeatureDefinition[] {
|
|
119
|
-
return [
|
|
120
|
-
createTemplateResolverFeature(),
|
|
121
|
-
createRendererFoundationFeature(),
|
|
122
|
-
createRendererSimpleFeature(),
|
|
123
|
-
];
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
export function composeMailStack(options: MailStackOptions): FeatureDefinition[] {
|
|
127
|
-
const out: FeatureDefinition[] = [mailFoundationFeature];
|
|
128
|
-
for (const transport of options.transports) {
|
|
129
|
-
if (transport === "inmemory") out.push(mailTransportInMemoryFeature);
|
|
130
|
-
if (transport === "smtp") out.push(mailTransportSmtpFeature);
|
|
131
|
-
}
|
|
132
|
-
return out;
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
export function composeFileStack(options: FileStackOptions): FeatureDefinition[] {
|
|
136
|
-
const out: FeatureDefinition[] = [fileFoundationFeature];
|
|
137
|
-
for (const provider of options.providers) {
|
|
138
|
-
if (provider === "inmemory") out.push(fileProviderInMemoryFeature);
|
|
139
|
-
if (provider === "s3") out.push(fileProviderS3Feature);
|
|
140
|
-
if (provider === "s3-env") out.push(fileProviderS3EnvFeature);
|
|
141
|
-
}
|
|
142
|
-
if (options.includeFilesFeature ?? true) out.push(createFilesFeature());
|
|
143
|
-
return out;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
/** Retention + compliance (+ optional lifecycle/sessions). UDR/files mount separately — order varies per app. */
|
|
147
|
-
export function composeGdprStack(options: GdprStackOptions = {}): FeatureDefinition[] {
|
|
148
|
-
const order = options.order ?? "retention-first";
|
|
149
|
-
const retention = createDataRetentionFeature();
|
|
150
|
-
const compliance = createComplianceProfilesFeature();
|
|
151
|
-
const out: FeatureDefinition[] =
|
|
152
|
-
order === "compliance-first" ? [compliance, retention] : [retention, compliance];
|
|
153
|
-
if (options.tenantLifecycle) out.push(createTenantLifecycleFeature());
|
|
154
|
-
if (options.sessions) {
|
|
155
|
-
out.push(authFoundationFeature, createSessionsFeature());
|
|
156
|
-
if (options.providers) out.push(...options.providers);
|
|
157
|
-
}
|
|
158
|
-
return out;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
export function composeUserDataRightsStack(
|
|
162
|
-
options: UserDataRightsStackOptions = {},
|
|
163
|
-
): FeatureDefinition[] {
|
|
164
|
-
const includeDefaults = options.includeDefaults ?? true;
|
|
165
|
-
const out: FeatureDefinition[] = [createUserDataRightsFeature(options.userDataRights ?? {})];
|
|
166
|
-
if (includeDefaults) out.push(createUserDataRightsDefaultsFeature());
|
|
167
|
-
return out;
|
|
168
|
-
}
|
|
169
|
-
|
|
170
|
-
export function composeOpsStack(options: OpsStackOptions = {}): FeatureDefinition[] {
|
|
171
|
-
const delivery = options.delivery ?? true;
|
|
172
|
-
const audit = options.audit ?? true;
|
|
173
|
-
const jobs = options.jobs ?? true;
|
|
174
|
-
const rateLimiting = options.rateLimiting ?? false;
|
|
175
|
-
const out: FeatureDefinition[] = [];
|
|
176
|
-
if (delivery) out.push(createDeliveryFeature());
|
|
177
|
-
if (audit) out.push(createAuditFeature());
|
|
178
|
-
if (jobs) out.push(createJobsFeature());
|
|
179
|
-
if (rateLimiting) out.push(createRateLimitingFeature());
|
|
180
|
-
return out;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
/** Identity opt-ins: sessions by default; auth-mfa when `mfa` options given.
|
|
184
|
-
* Do not also pass `sessions: true` to composeGdprStack — duplicate feature. */
|
|
185
|
-
export function composeIdentityStack(options: IdentityStackOptions = {}): FeatureDefinition[] {
|
|
186
|
-
const sessions = options.sessions ?? true;
|
|
187
|
-
const out: FeatureDefinition[] = [];
|
|
188
|
-
if (sessions) {
|
|
189
|
-
out.push(authFoundationFeature, createSessionsFeature());
|
|
190
|
-
}
|
|
191
|
-
if (options.mfa !== undefined) out.push(createAuthMfaFeature(options.mfa));
|
|
192
|
-
return out;
|
|
193
|
-
}
|
package/src/crash-tracker.ts
DELETED
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
// Tracks server-Crashes in einem rollenden Zeitfenster und entscheidet,
|
|
2
|
-
// ob der dev-wrapper noch respawnen darf oder den Crash-Loop aufgeben
|
|
3
|
-
// muss. Liegt als eigener File, damit `kumiko-dev.ts` (bin-Script ohne
|
|
4
|
-
// Test-Setup) eine pure, injizierbare API bekommt — die Logik ist
|
|
5
|
-
// testbar via createCrashTracker, ohne den Wrapper-Prozess fahren zu
|
|
6
|
-
// müssen.
|
|
7
|
-
//
|
|
8
|
-
// Semantik: ein Crash "zählt im Fenster", wenn er innerhalb der letzten
|
|
9
|
-
// `windowMs` ms vor `now` registriert wurde. Wenn nach Aufnahme des
|
|
10
|
-
// neuen Crashes mehr als `maxCrashes` im Fenster liegen, gibt der
|
|
11
|
-
// Tracker `false` zurück → Wrapper soll aufgeben.
|
|
12
|
-
|
|
13
|
-
export type CrashTrackerOptions = {
|
|
14
|
-
readonly maxCrashes: number;
|
|
15
|
-
readonly windowMs: number;
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
export type CrashTracker = {
|
|
19
|
-
/** Crash bei `now` registrieren. Returns `true` wenn der Wrapper
|
|
20
|
-
* noch respawnen darf, `false` wenn das Limit überschritten ist.
|
|
21
|
-
*
|
|
22
|
-
* Der Crash wird IMMER aufgenommen, auch wenn `false` zurückkommt —
|
|
23
|
-
* der Caller terminiert in dem Fall normalerweise eh. Reuse mit
|
|
24
|
-
* "rejected → state unchanged"-Semantik wird nicht unterstützt. */
|
|
25
|
-
readonly noteCrash: (now: number) => boolean;
|
|
26
|
-
/** Anzahl Crashes im Fenster relativ zu `now` — prunt lazy, damit
|
|
27
|
-
* der Aufruf auch ohne vorheriges noteCrash konsistent ist. */
|
|
28
|
-
readonly crashCountInWindow: (now: number) => number;
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
export function createCrashTracker(options: CrashTrackerOptions): CrashTracker {
|
|
32
|
-
const timestamps: number[] = [];
|
|
33
|
-
|
|
34
|
-
const pruneBefore = (cutoff: number): void => {
|
|
35
|
-
// Crashes älter als `cutoff` raus. Gleicher Timestamp wie cutoff
|
|
36
|
-
// bleibt drin (`<` statt `<=`) — symmetrisch zur Fenster-Definition
|
|
37
|
-
// "innerhalb der letzten windowMs", also Endpoint inklusive.
|
|
38
|
-
while (timestamps.length > 0) {
|
|
39
|
-
const head = timestamps[0];
|
|
40
|
-
if (head !== undefined && head < cutoff) timestamps.shift();
|
|
41
|
-
else break;
|
|
42
|
-
}
|
|
43
|
-
};
|
|
44
|
-
|
|
45
|
-
return {
|
|
46
|
-
noteCrash: (now) => {
|
|
47
|
-
pruneBefore(now - options.windowMs);
|
|
48
|
-
timestamps.push(now);
|
|
49
|
-
return timestamps.length <= options.maxCrashes;
|
|
50
|
-
},
|
|
51
|
-
crashCountInWindow: (now) => {
|
|
52
|
-
pruneBefore(now - options.windowMs);
|
|
53
|
-
return timestamps.length;
|
|
54
|
-
},
|
|
55
|
-
};
|
|
56
|
-
}
|