///
import { type AuthRoutesConfig, type ExtraRouteDefinition } from "@cosmicdrift/kumiko-framework/api";
import { type FeatureDefinition } from "@cosmicdrift/kumiko-framework/engine";
import type { ErrorDocsConfig } from "@cosmicdrift/kumiko-framework/errors";
import { type TestStack, type TestStackOptions } from "@cosmicdrift/kumiko-framework/stack";
import { type PageHeadResolver, type PageHeadSystemQuery } from "@cosmicdrift/kumiko-headless/apex";
import { type SystemWireDeps } from "@cosmicdrift/kumiko-server-runtime/extra-routes-deps";
type BunServer = typeof Bun extends undefined ? unknown : ReturnType;
/** Multi-entry mode for apps that ship several separate bundles (e.g.
* publicstatus: `admin.` loads the admin UI, otherwise the public
* page).
*
* kumiko-build reads the same entry list from package.json
* `kumiko.clientEntries` and serves `/client-.js` per HTTP — the
* dev server and the prod build stay in sync via that shared declaration,
* not a filename convention. Mutually exclusive with `clientEntry`.
* Multi-entry apps MUST also set `hostDispatch` — otherwise the server
* has no way to know which HTML to serve. */
export type DevClientEntry = {
/** Logical name. Should match the corresponding package.json
* `kumiko.clientEntries[].name` so dev and prod produce identical
* asset URLs (`/client-.js`). */
readonly name: string;
/** Absoluter Pfad zur Browser-Entry-Datei. */
readonly sourceFile: string;
/** Optional eigenes HTML-Template für diesen Entry. Wenn nicht gesetzt,
* wird `htmlPath` (das default-Template) für alle Entries genutzt. */
readonly htmlPath?: string;
};
/** Discriminated union, identical in shape to `runProdApp.hostDispatch`, so
* dev/prod routing mirrors 1:1 — an apex 404 in prod is an apex 404 in dev
* (with an `/etc/hosts` entry for the affected domain). HTML never carries
* a schema, in dev or prod — createKumikoApp fetches it itself from the
* authenticated GET /api/schema. */
export type DevHostDispatchResult = {
readonly kind: "html";
readonly entryName: string;
/** @deprecated Ignored — HTML never carries the schema; createKumikoApp
* fetches it from the authenticated GET /api/schema. */
readonly injectSchema?: boolean;
} | {
/** Static HTML: serves a file verbatim, no bundle injection. Mirrors
* prod's `{ kind: "html", file: ... }` for marketing/apex pages that
* don't need React. Path relative to the server CWD. */
readonly kind: "static-html";
readonly file: string;
} | {
readonly kind: "redirect";
readonly to: string;
readonly status?: 301 | 302;
} | {
/** Plain 404 by default. `file` serves a static page with status 404
* (like `static-html`), `entryName` serves that bundle's shell with 404;
* `file` wins when both are set. */
readonly kind: "not-found";
readonly entryName?: string;
readonly file?: string;
};
/** Picks an entry by inspecting the incoming request. Wird von
* Multi-Entry-Apps gesetzt; im Single-Entry-Mode irrelevant. */
export type DevHostDispatch = (req: Request, deps: {
readonly systemQuery: PageHeadSystemQuery;
}) => DevHostDispatchResult | Promise;
export type CreateKumikoServerOptions = {
/** Features whose entities, handlers, and screens get wired into the
* dev stack. Pass every feature the app is supposed to run. */
readonly features: readonly FeatureDefinition[];
/** Absolute path to the browser entry module. The dev-server runs
* `Bun.build` on it and serves the output at `/client.js`. Omit to
* run a headless API-only dev-stack (rare — every sample has one).
* Mutually exclusive mit `clientEntries`. */
readonly clientEntry?: string;
/** Multi-Entry-Mode: mehrere getrennte Bundles, jeweils unter
* `/client-.js`. Mutually exclusive mit `clientEntry`. Setze
* `hostDispatch` mit, sonst bleibt unklar welches Template zurück-
* geht. */
readonly clientEntries?: readonly DevClientEntry[];
/** Multi-Entry-Mode: Routing pro Request. Inspiziert `Host` (oder
* was auch immer) und liefert eine Discriminated-Union zurück
* (html → entry-bundle, redirect → 30x, not-found → 404).
* Symmetric zu `runProdApp.hostDispatch` damit dev/prod-Drift
* beim Routing unmöglich ist. */
readonly hostDispatch?: DevHostDispatch;
/** @internal — ersetzt `Bun.build` für Tests. Default ruft die echte
* Bun-Toolchain. Tests unter Node injizieren einen Stub damit der
* Routing-Pfad treibbar bleibt ohne Bun.build aufzurufen.
* KEIN Public-API-Surface — präfixiert mit `_` damit Konsumenten
* wissen dass das ein Test-Seam ist. */
readonly _buildBundle?: (sourceFile: string) => Promise<{
readonly js: string;
readonly map: string;
}>;
/** @internal — replaces the native directory watcher in tests. */
readonly _watchDirectory?: DirectoryWatchEvents;
/** Absolute path to the CSS entry (typically styles.css with
* @import "tailwindcss"). The dev-server builds it with the Tailwind
* CLI and serves the result at /styles.css; `stylesheetWatch` decides
* whether the CLI keeps running with `--watch` afterwards.
*
* When `undefined` and a client entry is set, the app's own
* src/styles.css wins, otherwise `@cosmicdrift/kumiko-renderer-web/styles.css`
* resolves via package exports, so no sample hardcodes a monorepo-relative path.
*
* `stylesheet: false` disables the CSS pipeline. */
readonly stylesheet?: string | false;
/** `true`: the Tailwind CLI keeps running with `--watch` after the
* initial build. `false`: CSS is built once at boot, no watcher.
* When `undefined`, env `KUMIKO_DEV_STYLESHEET_WATCH=0` means `false`,
* anything else `true`. `defineAppE2eConfig` sets that env: Tailwind v4
* subscribes to the whole app cwd without a gitignore filter, so every
* Playwright artifact write under test-results/ would trigger a rebuild. */
readonly stylesheetWatch?: boolean;
/** Optional HTML template served at `GET /`. The dev-server injects
* a `\n