@cosmicdrift/kumiko-dev-server 0.385.0 → 0.387.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -57
- package/dist/build-server-bundle.d.ts +6 -6
- package/dist/build-server-bundle.js +51 -51
- package/dist/build.js +3 -3
- package/dist/compose-stacks.d.ts +2 -2
- package/dist/compose-stacks.js +1 -2
- package/dist/crash-tracker.d.ts +3 -7
- package/dist/crash-tracker.js +4 -13
- package/dist/create-kumiko-server.d.ts +47 -51
- package/dist/create-kumiko-server.js +122 -152
- package/dist/env-schema.d.ts +1 -1
- package/dist/env-schema.js +4 -4
- package/dist/index.js +14 -14
- package/dist/run-dev-app.d.ts +48 -46
- package/dist/run-dev-app.js +57 -55
- package/dist/scaffold-app-feature.js +5 -4
- package/dist/scaffold-app.js +5 -7
- package/dist/schema-apply.d.ts +2 -2
- package/dist/schema-apply.js +12 -12
- package/dist/schema-tables-auth-mode.js +16 -15
- package/dist/schema-tables-minimal.js +7 -7
- package/dist/setup-test-stack-from-features.js +1 -1
- package/dist/testing.js +4 -1
- package/dist/welcome-banner.js +2 -2
- package/package.json +10 -10
package/LICENSE
CHANGED
|
@@ -1,57 +1,21 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
controlling, or under common control with the Licensor ("Affiliates"), or
|
|
23
|
-
contractors acting on their behalf. The Licensor remains free to use the
|
|
24
|
-
Licensed Work for any purpose, including for the operation of kumiko.rocks.
|
|
25
|
-
|
|
26
|
-
Change Date: 2030-05-05
|
|
27
|
-
Change License: Apache License, Version 2.0
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
Terms
|
|
31
|
-
|
|
32
|
-
The Licensor hereby grants you the right to copy, modify, create derivative works,
|
|
33
|
-
redistribute, and make non-production use of the Licensed Work. The Licensor may
|
|
34
|
-
make an Additional Use Grant, above, permitting limited production use.
|
|
35
|
-
|
|
36
|
-
Effective on the Change Date, or the fourth anniversary of the first publicly
|
|
37
|
-
available distribution of the Licensed Work under this License, whichever comes
|
|
38
|
-
first, this License will convert to the Change License.
|
|
39
|
-
|
|
40
|
-
This Business Source License governs use of the Licensed Work in all cases, except
|
|
41
|
-
as to any use that is explicitly granted in the Additional Use Grant above or
|
|
42
|
-
under the Change License after the Change Date.
|
|
43
|
-
|
|
44
|
-
If your use of the Licensed Work does not comply with the requirements of this
|
|
45
|
-
License, you must cease use of the Licensed Work immediately.
|
|
46
|
-
|
|
47
|
-
All copies of the Licensed Work, and all derivative works thereof, must include
|
|
48
|
-
this License.
|
|
49
|
-
|
|
50
|
-
This License does not grant you any right, title, or interest in any trademark,
|
|
51
|
-
logo, or branding of the Licensor, except as required to comply with this License.
|
|
52
|
-
|
|
53
|
-
TO THE EXTENT PERMITTED BY APPLICABLE LAW, THE LICENSED WORK IS PROVIDED ON AN
|
|
54
|
-
“AS IS” BASIS. LICENSOR DISCLAIMS ALL WARRANTIES, EXPRESS OR IMPLIED, INCLUDING
|
|
55
|
-
WITHOUT LIMITATION WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
|
|
56
|
-
TITLE, AND NON-INFRINGEMENT. IN NO EVENT WILL LICENSOR BE LIABLE FOR ANY DAMAGES
|
|
57
|
-
ARISING OUT OF OR RELATED TO THIS LICENSE OR THE USE OF THE LICENSED WORK.
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Marc Frost
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -3,10 +3,10 @@ export type BuildServerBundleOptions = {
|
|
|
3
3
|
readonly cwd?: string;
|
|
4
4
|
/** Output-Folder relativ zu cwd. Default: "dist-server". */
|
|
5
5
|
readonly outDir?: string;
|
|
6
|
-
/**
|
|
7
|
-
* (beyond RUNTIME_EXTERNALS). App-
|
|
6
|
+
/** Additional packages that must be installed at runtime
|
|
7
|
+
* (beyond RUNTIME_EXTERNALS). App-specific; defaults to empty. */
|
|
8
8
|
readonly extraRuntimeExternals?: readonly string[];
|
|
9
|
-
/**
|
|
9
|
+
/** Additional build-only externals. App-specific; defaults to empty. */
|
|
10
10
|
readonly extraBuildOnlyExternals?: readonly string[];
|
|
11
11
|
/** Additional entry points (paths relative to cwd, e.g. "bin/remote-probe.ts"),
|
|
12
12
|
* each emitted as `<basename>.js` next to server.js and sharing its chunks.
|
|
@@ -22,9 +22,9 @@ export type BuildServerBundleResult = {
|
|
|
22
22
|
readonly outDir: string;
|
|
23
23
|
/** Named entry files (server.js, plus kumiko.js, worker.js, bootstrap.js and extra entries when present). */
|
|
24
24
|
readonly entries: readonly BuildServerBundleEntry[];
|
|
25
|
-
/**
|
|
25
|
+
/** Shared framework chunks (from splitting). */
|
|
26
26
|
readonly chunks: readonly BuildServerBundleEntry[];
|
|
27
|
-
/**
|
|
27
|
+
/** Total size of all outputs (entries + chunks) in bytes. */
|
|
28
28
|
readonly totalBytes: number;
|
|
29
29
|
readonly runtimeDeps: Readonly<Record<string, string>>;
|
|
30
30
|
};
|
|
@@ -37,7 +37,7 @@ export type KumikoBuildArgs = {
|
|
|
37
37
|
/** Parse `kumiko-build [app-dir] [--entry <path>]...` (also `--entry=<path>`).
|
|
38
38
|
* Unknown flags and a missing `--entry` value throw instead of being ignored. */
|
|
39
39
|
export declare function parseKumikoBuildArgs(args: readonly string[]): KumikoBuildArgs;
|
|
40
|
-
/** Read `package.json#kumiko.extraRuntimeExternals` for kumiko-build
|
|
40
|
+
/** Read `package.json#kumiko.extraRuntimeExternals` for kumiko-build.
|
|
41
41
|
* Invalid / missing shapes → empty list (CLI stays convention-driven). */
|
|
42
42
|
export declare function readExtraRuntimeExternals(cwd: string): readonly string[];
|
|
43
43
|
export declare function formatServerBuildResult(result: BuildServerBundleResult, durationMs: number): string;
|
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
// buildServerBundle — Production
|
|
2
|
-
// buildProdBundle (
|
|
3
|
-
// (+ optional <repo>/bin/kumiko.ts)
|
|
4
|
-
// dist-server/
|
|
1
|
+
// buildServerBundle — Production server bundle for Kumiko apps. Counterpart to
|
|
2
|
+
// buildProdBundle (client). Convention-driven discovery reads bin/main.ts
|
|
3
|
+
// (+ optional <repo>/bin/kumiko.ts) and produces a runtime-self-contained
|
|
4
|
+
// dist-server/ from which a Bun-Alpine container can boot without the monorepo.
|
|
5
5
|
//
|
|
6
6
|
// Convention:
|
|
7
7
|
//
|
|
8
|
-
// bin/main.ts → dist-server/server.js (
|
|
9
|
-
// <repo>/bin/kumiko.ts → dist-server/kumiko.js (
|
|
10
|
-
//
|
|
8
|
+
// bin/main.ts → dist-server/server.js (app boot, calls runProdApp)
|
|
9
|
+
// <repo>/bin/kumiko.ts → dist-server/kumiko.js (migration CLI: `schema apply`,
|
|
10
|
+
// found by walking up to bin/kumiko.ts)
|
|
11
11
|
// bin/worker.ts → dist-server/worker.js (optional, next to bin/main.ts:
|
|
12
12
|
// background worker as its own process from the same image)
|
|
13
13
|
// bin/bootstrap.ts → dist-server/bootstrap.js (optional, next to bin/main.ts:
|
|
14
14
|
// one-shot runBootstrap provisioning, run as a k8s Job)
|
|
15
15
|
// extraEntries[i] → dist-server/<basename>.js (opt-in, e.g. a probe script
|
|
16
16
|
// `bin/remote-probe.ts`; CLI: repeatable `--entry <path>`)
|
|
17
|
-
// dist-server/package.json → runtime
|
|
17
|
+
// dist-server/package.json → runtime dependencies with pinned versions
|
|
18
18
|
//
|
|
19
19
|
// All entries are built in ONE Bun.build call with `splitting`: the framework
|
|
20
20
|
// lands once as shared chunk-*.js and server.js, kumiko.js, worker.js,
|
|
@@ -24,41 +24,41 @@
|
|
|
24
24
|
// Output:
|
|
25
25
|
//
|
|
26
26
|
// dist-server/
|
|
27
|
-
// server.js ←
|
|
28
|
-
// kumiko.js ←
|
|
27
|
+
// server.js ← app boot entry
|
|
28
|
+
// kumiko.js ← migration CLI entry (if bin/kumiko.ts is found)
|
|
29
29
|
// worker.js ← worker entry (if bin/worker.ts sits next to main.ts)
|
|
30
30
|
// bootstrap.js ← provisioning entry (if bin/bootstrap.ts sits next to main.ts)
|
|
31
31
|
// <basename>.js ← one per extraEntries path
|
|
32
|
-
// chunk-*.js ←
|
|
33
|
-
// package.json ← runtime
|
|
32
|
+
// chunk-*.js ← shared framework chunks
|
|
33
|
+
// package.json ← runtime dependencies with pinned versions
|
|
34
34
|
// bun.lock ← written by writeServerLockfile (kumiko-build), not by buildServerBundle
|
|
35
35
|
//
|
|
36
|
-
// Externals —
|
|
37
|
-
// `bun install`
|
|
36
|
+
// Externals — packages that are NOT bundled, but installed via
|
|
37
|
+
// `bun install` in the runtime container:
|
|
38
38
|
//
|
|
39
|
-
// RUNTIME_EXTERNALS —
|
|
40
|
-
// worker
|
|
39
|
+
// RUNTIME_EXTERNALS — needed at runtime (native bindings,
|
|
40
|
+
// worker threads, dynamic require). Added to
|
|
41
41
|
// dist-server/package.json#dependencies.
|
|
42
42
|
//
|
|
43
|
-
// BUILD_ONLY_EXTERNALS —
|
|
44
|
-
//
|
|
45
|
-
//
|
|
46
|
-
// resolution
|
|
43
|
+
// BUILD_ONLY_EXTERNALS — referenced only transitively in the framework,
|
|
44
|
+
// never by app code. Tree-shaking removes them from
|
|
45
|
+
// the bundle; the external marker only disables
|
|
46
|
+
// resolution during the build. NOT in runtime dependencies.
|
|
47
47
|
import { existsSync, readFileSync, statSync } from "node:fs";
|
|
48
48
|
import { mkdir, readFile, rename, rm, writeFile } from "node:fs/promises";
|
|
49
49
|
import { basename, dirname, extname, join, resolve } from "node:path";
|
|
50
50
|
import { parseJsonOrThrow, parseJsonSafe } from "@cosmicdrift/kumiko-framework/utils";
|
|
51
51
|
const hasBun = typeof Bun !== "undefined";
|
|
52
|
-
//
|
|
53
|
-
//
|
|
54
|
-
// ioredis), dynamic
|
|
55
|
-
// Bun
|
|
56
|
-
//
|
|
57
|
-
// meilisearch
|
|
52
|
+
// Packages that the bundle still references at runtime (`from "<pkg>"` after
|
|
53
|
+
// tree-shaking). Native bindings (argon2), worker-thread loaders (bullmq,
|
|
54
|
+
// ioredis), and dynamic require (postgres, temporal-polyfill) — anything that
|
|
55
|
+
// breaks under Bun bundling. (drizzle-kit/drizzle-orm are excluded: the
|
|
56
|
+
// migration path now uses the framework's runMigrationsFromDir, not drizzle-kit.)
|
|
57
|
+
// meilisearch is deliberately here, not in BUILD_ONLY_EXTERNALS below — apps
|
|
58
58
|
// that import createMeilisearchAdapter (kumiko-framework/search/meilisearch)
|
|
59
59
|
// reference the package at runtime (no native binding, plain HTTP client,
|
|
60
|
-
// but a real runtime import).
|
|
61
|
-
// "Cannot find package 'meilisearch'" because it used to
|
|
60
|
+
// but a real runtime import). A production crash in money-horse,
|
|
61
|
+
// "Cannot find package 'meilisearch'", occurred because it used to be in
|
|
62
62
|
// BUILD_ONLY_EXTERNALS instead.
|
|
63
63
|
const RUNTIME_EXTERNALS = [
|
|
64
64
|
"@node-rs/argon2",
|
|
@@ -71,11 +71,11 @@ const RUNTIME_EXTERNALS = [
|
|
|
71
71
|
"pino-pretty",
|
|
72
72
|
"meilisearch",
|
|
73
73
|
];
|
|
74
|
-
//
|
|
75
|
-
//
|
|
76
|
-
//
|
|
77
|
-
//
|
|
78
|
-
// runtime
|
|
74
|
+
// Packages that appear only in the build stack (transitive framework imports),
|
|
75
|
+
// but are not referenced by app code. Without the external marker,
|
|
76
|
+
// bun build fails on dynamic imports. Tree-shaking removes them from the
|
|
77
|
+
// bundle; the marker only disables resolution during the build. NOT in
|
|
78
|
+
// runtime dependencies.
|
|
79
79
|
const BUILD_ONLY_EXTERNALS = [
|
|
80
80
|
"@planetscale/database",
|
|
81
81
|
"@libsql/client",
|
|
@@ -86,9 +86,9 @@ const BUILD_ONLY_EXTERNALS = [
|
|
|
86
86
|
// ink (kumiko-tui) hat react-devtools-core als dev-only transitive import.
|
|
87
87
|
"react-devtools-core",
|
|
88
88
|
];
|
|
89
|
-
// Bun
|
|
90
|
-
//
|
|
91
|
-
// chunks
|
|
89
|
+
// Bun names entries after the source basename (bin/main.ts → main.js). server.js
|
|
90
|
+
// is the runtime convention; the entry is not imported by anything (only the
|
|
91
|
+
// chunks are referenced by relative path), so renaming it is safe.
|
|
92
92
|
const ENTRY_RENAMES = { "main.js": "server.js" };
|
|
93
93
|
const OPTIONAL_SIBLING_ENTRY_NAMES = ["worker", "bootstrap"];
|
|
94
94
|
// Output names the built-in entries occupy ("main" is renamed to server.js).
|
|
@@ -141,8 +141,8 @@ export async function buildServerBundle(options = {}) {
|
|
|
141
141
|
];
|
|
142
142
|
await rm(outDir, { recursive: true, force: true });
|
|
143
143
|
await mkdir(outDir, { recursive: true });
|
|
144
|
-
//
|
|
145
|
-
//
|
|
144
|
+
// One Bun.build call with all entries plus splitting stores the framework
|
|
145
|
+
// once as a shared chunk instead of inlining it into every entry.
|
|
146
146
|
const optionalSiblingEntries = OPTIONAL_SIBLING_ENTRY_NAMES.map((baseName) => discoverSiblingEntry(dirname(serverEntry), baseName)).filter((path) => path !== undefined);
|
|
147
147
|
const entrypoints = [
|
|
148
148
|
serverEntry,
|
|
@@ -164,8 +164,8 @@ export async function buildServerBundle(options = {}) {
|
|
|
164
164
|
const logs = result.logs.map(String).join("\n");
|
|
165
165
|
throw new Error(`[buildServerBundle] build FAILED:\n${logs}`);
|
|
166
166
|
}
|
|
167
|
-
//
|
|
168
|
-
//
|
|
167
|
+
// Read the size from disk rather than out.size — the latter is unreliable for
|
|
168
|
+
// split entry points and sometimes reports ~0 for the entry stub.
|
|
169
169
|
const entries = [];
|
|
170
170
|
const chunks = [];
|
|
171
171
|
for (const out of result.outputs) {
|
|
@@ -209,9 +209,9 @@ function discoverSiblingEntry(dir, baseName) {
|
|
|
209
209
|
}
|
|
210
210
|
return undefined;
|
|
211
211
|
}
|
|
212
|
-
//
|
|
213
|
-
// Failsafe:
|
|
214
|
-
//
|
|
212
|
+
// Walk up from the app cwd until a directory containing `bin/kumiko.ts` is found.
|
|
213
|
+
// Failsafe: stop after 8 levels. If nothing is found, there is no repo root,
|
|
214
|
+
// so the function returns undefined and the caller skips the CLI bundle.
|
|
215
215
|
function findRepoRoot(start) {
|
|
216
216
|
let cur = start;
|
|
217
217
|
for (let i = 0; i < 8; i++) {
|
|
@@ -252,7 +252,7 @@ export function parseKumikoBuildArgs(args) {
|
|
|
252
252
|
}
|
|
253
253
|
return { appDir, extraEntries };
|
|
254
254
|
}
|
|
255
|
-
/** Read `package.json#kumiko.extraRuntimeExternals` for kumiko-build
|
|
255
|
+
/** Read `package.json#kumiko.extraRuntimeExternals` for kumiko-build.
|
|
256
256
|
* Invalid / missing shapes → empty list (CLI stays convention-driven). */
|
|
257
257
|
export function readExtraRuntimeExternals(cwd) {
|
|
258
258
|
const pkgJson = join(cwd, "package.json");
|
|
@@ -271,11 +271,11 @@ export function readExtraRuntimeExternals(cwd) {
|
|
|
271
271
|
return [];
|
|
272
272
|
return list.filter((x) => typeof x === "string" && x.trim().length > 0);
|
|
273
273
|
}
|
|
274
|
-
//
|
|
275
|
-
// node_modules/@cosmicdrift/*-
|
|
276
|
-
//
|
|
277
|
-
// features (
|
|
278
|
-
//
|
|
274
|
+
// Resolve versions for RUNTIME_EXTERNALS: first from installed
|
|
275
|
+
// node_modules/@cosmicdrift/*-packages (relative to cwd, which works for
|
|
276
|
+
// any consumer app), then additionally from packages/framework + bundled-
|
|
277
|
+
// features (the framework's own workspace checkout). Fall back to "*"
|
|
278
|
+
// when no source knows the package name.
|
|
279
279
|
async function resolveRuntimeDepsVersions(cwd, repoRoot, packages) {
|
|
280
280
|
const out = {};
|
|
281
281
|
const pinSources = [
|
|
@@ -286,7 +286,7 @@ async function resolveRuntimeDepsVersions(cwd, repoRoot, packages) {
|
|
|
286
286
|
]
|
|
287
287
|
: []),
|
|
288
288
|
// node_modules applied last among framework sources so installed versions
|
|
289
|
-
// win over the repo-root fallback
|
|
289
|
+
// win over the repo-root fallback.
|
|
290
290
|
join(cwd, "node_modules/@cosmicdrift/kumiko-framework/package.json"),
|
|
291
291
|
join(cwd, "node_modules/@cosmicdrift/kumiko-bundled-features/package.json"),
|
|
292
292
|
];
|
|
@@ -299,7 +299,7 @@ async function resolveRuntimeDepsVersions(cwd, repoRoot, packages) {
|
|
|
299
299
|
Object.assign(allDeps, parsed.dependencies ?? {}, parsed.optionalDependencies ?? {});
|
|
300
300
|
}
|
|
301
301
|
// App package.json fills gaps only — pins extraRuntimeExternals without
|
|
302
|
-
// overriding framework-native pins the app may also list
|
|
302
|
+
// overriding framework-native pins the app may also list.
|
|
303
303
|
const appPkg = join(cwd, "package.json");
|
|
304
304
|
if (existsSync(appPkg)) {
|
|
305
305
|
const raw = await readFile(appPkg, "utf-8");
|
package/dist/build.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
// Build-
|
|
2
|
-
//
|
|
3
|
-
// (
|
|
1
|
+
// Build-toolchain public API. The dedicated subpath export `@cosmicdrift/kumiko-dev-server/build`
|
|
2
|
+
// keeps the main barrel from pulling the Bun toolchain bundle into production reads
|
|
3
|
+
// (for example, when drizzle-kit loads the app config under Node).
|
|
4
4
|
export { ASSETS_DIR, buildProdBundle, discoverHtmlTemplate, formatBuildResult, injectAssetTags, readClientEntriesConfig, resolveClientEntries, } from "@cosmicdrift/kumiko-server-runtime/build-prod-bundle";
|
|
5
5
|
export { buildServerBundle, discoverServerEntry, formatServerBuildResult, parseKumikoBuildArgs, readExtraRuntimeExternals, } from "./build-server-bundle.js";
|
|
6
6
|
export { writeServerLockfile, } from "./write-server-lockfile.js";
|
package/dist/compose-stacks.d.ts
CHANGED
|
@@ -37,7 +37,7 @@ export type GdprStackOptions = {
|
|
|
37
37
|
};
|
|
38
38
|
/** Optional tokenVerifier provider(s) (e.g. PAT) when `sessions` is on.
|
|
39
39
|
* Session-only stacks need none — sessions registers sessionStore, which
|
|
40
|
-
* satisfies auth-foundation's boot check
|
|
40
|
+
* satisfies auth-foundation's boot check. Pass providers when the
|
|
41
41
|
* app also wants Bearer/PAT auth. */
|
|
42
42
|
readonly providers?: readonly FeatureDefinition[];
|
|
43
43
|
/** Roles allowed to use the compliance-profiles handlers; default access.admin. */
|
|
@@ -59,7 +59,7 @@ export type OpsStackOptions = {
|
|
|
59
59
|
* on composeFeatures(includeBundled). Pass `mfa` options to mount TOTP.
|
|
60
60
|
* When `sessions` is on (the default), auth-foundation is mounted alongside it —
|
|
61
61
|
* the framework's registry now hard-requires it (sessions.requires("auth-foundation")).
|
|
62
|
-
* Session-only is enough for boot
|
|
62
|
+
* Session-only is enough for boot; optional Bearer/PAT still needs a
|
|
63
63
|
* tokenVerifier provider from the caller (e.g. createPersonalAccessTokensFeature
|
|
64
64
|
* ({ scopes })) — PAT scopes are app-specific, so they stay caller-owned. */
|
|
65
65
|
export type IdentityStackOptions = {
|
package/dist/compose-stacks.js
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
// @runtime runtime
|
|
2
2
|
// Despite living in this "dev"-marked package, every preset here composes
|
|
3
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).
|
|
4
|
+
// app repo feeds it into the runProdApp boot path, not just runDevApp.
|
|
6
5
|
//
|
|
7
6
|
// Composable SaaS stack presets — explicit opt-in blocks for run-config.ts.
|
|
8
7
|
// Presets export feature instances only; no implicit PAT scopes or
|
package/dist/crash-tracker.d.ts
CHANGED
|
@@ -3,15 +3,11 @@ export type CrashTrackerOptions = {
|
|
|
3
3
|
readonly windowMs: number;
|
|
4
4
|
};
|
|
5
5
|
export type CrashTracker = {
|
|
6
|
-
/**
|
|
7
|
-
* noch respawnen darf, `false` wenn das Limit überschritten ist.
|
|
6
|
+
/** Registers a crash at `now`. Returns `true` if the wrapper may still respawn and `false` if the limit has been exceeded.
|
|
8
7
|
*
|
|
9
|
-
*
|
|
10
|
-
* der Caller terminiert in dem Fall normalerweise eh. Reuse mit
|
|
11
|
-
* "rejected → state unchanged"-Semantik wird nicht unterstützt. */
|
|
8
|
+
* The crash is always recorded, even when `false` is returned; the caller normally terminates in that case anyway. Reuse with "rejected → state unchanged" semantics is not supported. */
|
|
12
9
|
readonly noteCrash: (now: number) => boolean;
|
|
13
|
-
/**
|
|
14
|
-
* der Aufruf auch ohne vorheriges noteCrash konsistent ist. */
|
|
10
|
+
/** Counts crashes in the window relative to `now`. Prunes lazily so the call is consistent even without a preceding noteCrash. */
|
|
15
11
|
readonly crashCountInWindow: (now: number) => number;
|
|
16
12
|
};
|
|
17
13
|
export declare function createCrashTracker(options: CrashTrackerOptions): CrashTracker;
|
package/dist/crash-tracker.js
CHANGED
|
@@ -1,20 +1,11 @@
|
|
|
1
|
-
// Tracks server
|
|
2
|
-
//
|
|
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.
|
|
1
|
+
// Tracks server crashes in a rolling time window and decides whether the dev wrapper may respawn or must stop the crash loop.
|
|
2
|
+
// It lives in a separate file so `kumiko-dev.ts` (a bin script without test setup) has a pure, injectable API; the logic can be tested via createCrashTracker without running the wrapper process.
|
|
7
3
|
//
|
|
8
|
-
//
|
|
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.
|
|
4
|
+
// A crash counts as being in the window if it was registered within the last `windowMs` ms before `now`. If, after recording the new crash, more than `maxCrashes` are in the window, the tracker returns `false`, so the wrapper must stop.
|
|
12
5
|
export function createCrashTracker(options) {
|
|
13
6
|
const timestamps = [];
|
|
14
7
|
const pruneBefore = (cutoff) => {
|
|
15
|
-
//
|
|
16
|
-
// bleibt drin (`<` statt `<=`) — symmetrisch zur Fenster-Definition
|
|
17
|
-
// "innerhalb der letzten windowMs", also Endpoint inklusive.
|
|
8
|
+
// Removes crashes older than `cutoff`. A timestamp equal to cutoff remains (`<` rather than `<=`) to match the window definition "within the last windowMs", whose endpoint is inclusive.
|
|
18
9
|
while (timestamps.length > 0) {
|
|
19
10
|
const head = timestamps[0];
|
|
20
11
|
if (head !== undefined && head < cutoff)
|
|
@@ -22,10 +22,9 @@ export type DevClientEntry = {
|
|
|
22
22
|
* `kumiko.clientEntries[].name` so dev and prod produce identical
|
|
23
23
|
* asset URLs (`/client-<name>.js`). */
|
|
24
24
|
readonly name: string;
|
|
25
|
-
/**
|
|
25
|
+
/** Absolute path to the browser entry file. */
|
|
26
26
|
readonly sourceFile: string;
|
|
27
|
-
/** Optional
|
|
28
|
-
* wird `htmlPath` (das default-Template) für alle Entries genutzt. */
|
|
27
|
+
/** Optional HTML template for this entry. If omitted, `htmlPath` (the default template) is used for all entries. */
|
|
29
28
|
readonly htmlPath?: string;
|
|
30
29
|
};
|
|
31
30
|
/** Dev counterpart of `runProdApp.hostDispatch`. Not the same shape: dev names
|
|
@@ -58,8 +57,7 @@ export type DevHostDispatchResult = {
|
|
|
58
57
|
readonly entryName?: string;
|
|
59
58
|
readonly file?: string;
|
|
60
59
|
};
|
|
61
|
-
/** Picks an entry by inspecting the incoming request.
|
|
62
|
-
* Multi-Entry-Apps gesetzt; im Single-Entry-Mode irrelevant. */
|
|
60
|
+
/** Picks an entry by inspecting the incoming request. Set by multi-entry apps; irrelevant in single-entry mode. */
|
|
63
61
|
export type DevHostDispatch = (req: Request, deps: {
|
|
64
62
|
readonly systemQuery: PageHeadSystemQuery;
|
|
65
63
|
/** Always empty: dev serves no per-host CSP. */
|
|
@@ -69,27 +67,26 @@ export type CreateKumikoServerOptions = {
|
|
|
69
67
|
/** Features whose entities, handlers, and screens get wired into the
|
|
70
68
|
* dev stack. Pass every feature the app is supposed to run. */
|
|
71
69
|
readonly features: readonly FeatureDefinition[];
|
|
72
|
-
/** Absolute path to the browser entry module. The dev
|
|
70
|
+
/** Absolute path to the browser entry module. The dev server runs
|
|
73
71
|
* `Bun.build` on it and serves the output at `/client.js`. Omit to
|
|
74
|
-
* run a headless API-only dev
|
|
75
|
-
*
|
|
72
|
+
* run a headless API-only dev stack. Mutually exclusive with
|
|
73
|
+
* `clientEntries`. */
|
|
76
74
|
readonly clientEntry?: string;
|
|
77
|
-
/** Multi-
|
|
78
|
-
* `/client-<name>.js`. Mutually exclusive
|
|
79
|
-
* `hostDispatch`
|
|
80
|
-
*
|
|
75
|
+
/** Multi-entry mode: separate bundles served at
|
|
76
|
+
* `/client-<name>.js`. Mutually exclusive with `clientEntry`. Set
|
|
77
|
+
* `hostDispatch` as well; otherwise the server cannot determine which
|
|
78
|
+
* template to return. */
|
|
81
79
|
readonly clientEntries?: readonly DevClientEntry[];
|
|
82
|
-
/** Multi-
|
|
83
|
-
*
|
|
84
|
-
* (html → entry
|
|
85
|
-
*
|
|
86
|
-
*
|
|
80
|
+
/** Multi-entry request routing. Inspects `Host` (or another request
|
|
81
|
+
* property) and returns a discriminated union
|
|
82
|
+
* (`html` → entry bundle, `redirect` → 30x, `not-found` → 404).
|
|
83
|
+
* Mirrors `runProdApp.hostDispatch` so dev and production routing
|
|
84
|
+
* remain aligned. */
|
|
87
85
|
readonly hostDispatch?: DevHostDispatch;
|
|
88
|
-
/** @internal —
|
|
89
|
-
* Bun-
|
|
90
|
-
*
|
|
91
|
-
*
|
|
92
|
-
* wissen dass das ein Test-Seam ist. */
|
|
86
|
+
/** @internal — replaces `Bun.build` in tests. The default uses the real
|
|
87
|
+
* Bun toolchain; Node-based tests inject a stub so the routing path can
|
|
88
|
+
* run without calling Bun.build.
|
|
89
|
+
* Not part of the public API; the `_` prefix identifies this test seam. */
|
|
93
90
|
readonly _buildBundle?: (sourceFile: string) => Promise<{
|
|
94
91
|
readonly js: string;
|
|
95
92
|
readonly map: string;
|
|
@@ -128,41 +125,40 @@ export type CreateKumikoServerOptions = {
|
|
|
128
125
|
* this so repeated `createKumikoServer` calls don't accumulate
|
|
129
126
|
* listeners on the process. Default true (dev-server behaviour). */
|
|
130
127
|
readonly installSignalHandlers?: boolean;
|
|
131
|
-
/** Auth
|
|
132
|
-
*
|
|
133
|
-
*
|
|
134
|
-
*
|
|
135
|
-
* password) via `features` drin sein. */
|
|
128
|
+
/** Auth route configuration (login, tenants, switch-tenant, logout). When
|
|
129
|
+
* set, disables automatic JWT minting on GET /; the client is responsible
|
|
130
|
+
* for login. The corresponding features (user/tenant/auth-email-password)
|
|
131
|
+
* must also be included through `features` for these routes to work. */
|
|
136
132
|
readonly auth?: AuthRoutesConfig;
|
|
137
|
-
/**
|
|
138
|
-
*
|
|
139
|
-
*
|
|
133
|
+
/** Additional AppContext keys, such as `configResolver` for the config
|
|
134
|
+
* feature. Forwarded to `setupTestStack`; see `TestStackOptions` for
|
|
135
|
+
* the accepted shapes (object or factory function). */
|
|
140
136
|
readonly extraContext?: TestStackOptions["extraContext"];
|
|
141
|
-
/**
|
|
142
|
-
*
|
|
143
|
-
*
|
|
144
|
-
*
|
|
137
|
+
/** Enables anonymous access: requests without a JWT proceed as a
|
|
138
|
+
* pseudo-user with the `anonymous` role when the handler declares
|
|
139
|
+
* `roles: ["anonymous"]`. Tenant resolution uses a header, cookie, or
|
|
140
|
+
* default; see `AnonymousAccessConfig`. */
|
|
145
141
|
readonly anonymousAccess?: TestStackOptions["anonymousAccess"];
|
|
146
|
-
/** File-
|
|
147
|
-
*
|
|
148
|
-
* `ctx.files
|
|
142
|
+
/** File-storage provider forwarded to `setupTestStack`. When set, the
|
|
143
|
+
* stack mounts the upload routes (POST/GET/DELETE /api/files), exposes
|
|
144
|
+
* `ctx.files`, and creates the `file_refs` table. Example:
|
|
149
145
|
* `{ storageProvider: createInMemoryFileProvider() }`. */
|
|
150
146
|
readonly files?: TestStackOptions["files"];
|
|
151
|
-
/** Feature-toggle resolver
|
|
152
|
-
*
|
|
153
|
-
*
|
|
154
|
-
*
|
|
155
|
-
*
|
|
156
|
-
*
|
|
157
|
-
*
|
|
147
|
+
/** Feature-toggle resolver forwarded to `setupTestStack`. When set, the
|
|
148
|
+
* dispatcher feature gate, hook filter, and MSP filter consult it;
|
|
149
|
+
* absent means all features remain enabled. Required for per-tenant
|
|
150
|
+
* feature composition. The typical production implementation is
|
|
151
|
+
* `() => globalFeatureToggleRuntime.effectiveFeatures` after boot,
|
|
152
|
+
* using the createLateBoundHolder pattern because the runtime needs
|
|
153
|
+
* `stack.db`. */
|
|
158
154
|
readonly effectiveFeatures?: TestStackOptions["effectiveFeatures"];
|
|
159
|
-
/**
|
|
160
|
-
*
|
|
161
|
-
*
|
|
162
|
-
*
|
|
155
|
+
/** Called after entity tables are set up. Use this hook for non-entity
|
|
156
|
+
* tables (`unsafePushTables`) and seeding (admin user, initial tenant,
|
|
157
|
+
* and so on). Must be idempotent because persistent-DB mode runs it on
|
|
158
|
+
* every boot. */
|
|
163
159
|
readonly onAfterSetup?: (stack: TestStack) => Promise<void>;
|
|
164
160
|
/** Declarative HTTP-routes outside the /api/write|query|batch pipeline —
|
|
165
|
-
* symmetric to runProdApp.extraRoutes
|
|
161
|
+
* symmetric to runProdApp.extraRoutes. Mounted
|
|
166
162
|
* inside buildServer (setupTestStack), before the Static/HTML-fallback,
|
|
167
163
|
* so an own GET (/feed.xml, /og-image, …) wins over the dev-asset path. */
|
|
168
164
|
readonly extraRoutes?: readonly ExtraRouteDefinition[];
|
|
@@ -179,8 +175,8 @@ export type CreateKumikoServerOptions = {
|
|
|
179
175
|
/** Per-request head-metadata resolver (Open-Graph/title/description) —
|
|
180
176
|
* same option, same `PageHeadResolver` signature, and same shared
|
|
181
177
|
* resolve+inject call (`resolveAndInjectPageHead`) as `runProdApp`'s
|
|
182
|
-
* `resolvePageHead`, so dev and e2e exercise the exact code prod does
|
|
183
|
-
*
|
|
178
|
+
* `resolvePageHead`, so dev and e2e exercise the exact code prod does.
|
|
179
|
+
* Consulted for every templated HTML response
|
|
184
180
|
* (the default single-entry shell and a host-dispatched `"html"` entry),
|
|
185
181
|
* right before it's served. On error, `null`, or a timeout, the shell
|
|
186
182
|
* ships unchanged with status 200 — never a 500. `systemQuery` inside
|