// Client-safe Schema-Types. Wohnen in framework/ui-types statt renderer // damit der Server (createKumikoServer / buildAppSchema) sie produzieren // kann ohne renderer als Dependency zu ziehen. Renderer + Renderer-Web // re-exporten dieselben Symbole — Konsumenten merken den Umzug nicht. // // Pattern: Types fließen "downstream" (framework → renderer → renderer- // web), Runtime-Helpers (toAppSchema, isAppSchema) bleiben renderer-side // weil das die Layer ist die mit den AppSchemas zur Laufzeit arbeitet. import type { TranslationKeys } from "../engine/types/config"; import type { EntityDefinition } from "../engine/types/fields"; import type { ContentCollectionDefinition, NavDefinition } from "../engine/types/nav"; import type { ScreenDefinition } from "../engine/types/screen"; import type { WorkspaceDefinition } from "../engine/types/workspace"; export type FeatureSchema = { readonly featureName: string; readonly entities: Readonly>; readonly screens: readonly ScreenDefinition[]; // Flat list; resolveNavigation builds the tree at render-time from // the registry's indexes. Omitted when the app has no top-level nav. readonly navs?: readonly NavDefinition[]; // Content collections declared via r.contentCollection(), each with its nav // QN already qualified. The matching nav entries are in `navs` like any // other; this list only carries what a NavDefinition can't express — which // template-resource `kind` the node lists — so the client can build one // tree provider per collection. Omitted when a feature declares none. readonly contentCollections?: readonly QualifiedContentCollection[]; // Server-authored `r.translations({ keys })`, projected verbatim — byte- // identical keys, NOT re-prefixed with featureName (unlike the registry's // internal mergedTranslations, which double-prefixes features that // already qualify their own keys — see registry-ingest.ts populate // Translations). Nav/screen labels resolve these keys directly via // `t(label)`, so shipping anything other than the raw authored string // would break the lookup. Omitted when a feature declares none. #1059: // without this, nav labels only resolved when an app ALSO duplicated the // key in `web/i18n.ts` — most bundled features never did, so labels // rendered as raw i18n keys in the shell. readonly translations?: TranslationKeys; // Workspaces — Legacy-Slot für single-feature-Apps. Bevorzugt liegt // workspaces auf der AppSchema-Ebene weil ihre navMembers regelmäßig // Cross-Feature-Navs referenzieren (siehe AppSchema-Doc). Hier als // Fallback erhalten damit alte clientSchema-Files (vor AppSchema) // ohne Migration weiter laufen — toAppSchema() hebt die Liste hoch. readonly workspaces?: readonly WorkspaceSchema[]; // True only when the server confirmed at boot that no SearchAdapter is // wired on context.searchAdapter — mirrors the global (not per-entity) // check behind api/server.ts's boot warning (#2051). Duplicated // identically across every feature purely so it threads through the // existing per-feature prop chain into screen renderers (kumiko-screen.tsx) // without a separate app-level plumbing path. Omitted for schemas that // don't flow through buildAppSchema() (hand-authored fixtures, legacy // toAppSchema()) — treated as "not missing" so search bars keep rendering // exactly as before this flag existed (#2062). readonly searchAdapterMissing?: boolean; }; // A content collection as it reaches the client: the declaration plus the // already-qualified nav QN, so consumers don't rebuild ":nav:". export type QualifiedContentCollection = ContentCollectionDefinition & { readonly navQn: string; }; // Per-workspace projection of the engine's WorkspaceDefinition + the // pre-resolved member nav QNs. The shell renders the switcher from // `definition` and filters the nav tree using `navMembers`. export type WorkspaceSchema = { readonly definition: WorkspaceDefinition; // Nav QNs that belong to this workspace, in the order the engine // resolved them (explicit r.workspace.nav first, then nav-self-assigned // entries — deduped). Empty when no nav has been assigned. readonly navMembers: readonly string[]; }; // App-level schema. Bündelt ein oder mehrere FeatureSchemas + die App- // weiten Workspaces. Sinn der Trennung: Workspaces aggregieren über // Feature-Grenzen (admin-Workspace zeigt navs aus mehreren Features), und // die navMembers-Liste enthält voll qualifizierte QNs die der Browser // gegen die jeweilige feature-spezifische `navs`-Liste auflöst. // // Backwards-Compat: createKumikoApp + die Layouts (DefaultAppShell, // WorkspaceShell) akzeptieren beides — `FeatureSchema` (single-feature, // historisch) und `AppSchema` (multi-feature). Ein `toAppSchema(input)`- // Adapter normalisiert intern, sodass die ganze inneren Renderer-Pipeline // nur noch AppSchema kennt. export type AppSchema = { readonly features: readonly FeatureSchema[]; // Optional — Apps ohne Workspaces nutzen DefaultAppShell und sehen // schlicht die NavTree aller Features. readonly workspaces?: readonly WorkspaceSchema[]; };