feat: add display kiosk host
This commit is contained in:
@@ -70,7 +70,8 @@ Every module-facing contract in this platform is written so that **full Ekklesia
|
||||
thing that can satisfy it**. The intended second implementation is a reusable single-module
|
||||
standalone host — conceptually `@ekklesia/standalone-host` — which loads exactly one module and
|
||||
supplies the same host contracts Ekklesia does: configuration, secrets, object storage, HTTP, module
|
||||
lifecycle, and realtime, with display/kiosk hosting still later.
|
||||
lifecycle, and realtime. Ekklesia now also has a dedicated display surface, but the reusable
|
||||
single-module standalone host remains later.
|
||||
|
||||
**No such package exists yet, and this pass does not create one.** It is recorded here because it is
|
||||
what several contract decisions are *for*, and because a change that quietly makes it unimplementable
|
||||
@@ -370,9 +371,10 @@ and nothing more; there is no runtime health-probe contract. Modules remain trus
|
||||
disabling one is an operational control, never a sandbox. No installer exists.
|
||||
|
||||
Phase 7A pass 2 adds the module configuration and secrets contract
|
||||
([ADR 0029](decisions/0029-module-configuration-and-secrets.md)). A module declares what it needs
|
||||
configured in its manifest — `manifestVersion: 5`, a hard cutover — using six types (`string`,
|
||||
`integer`, `boolean`, `enum`, `url`, `secret`) with bounded constraints and no nesting. Static
|
||||
([ADR 0029](decisions/0029-module-configuration-and-secrets.md)). That pass introduced static
|
||||
configuration with the `manifestVersion: 5` hard cutover; the current strict manifest is version 6
|
||||
after ADR 0033. A module uses six declaration types (`string`, `integer`, `boolean`, `enum`, `url`,
|
||||
`secret`) with bounded constraints and no nesting. Static
|
||||
declaration is what lets the platform validate configuration **before** deciding whether a module may
|
||||
start, so an unconfigured module is reported `blocked · configuration_missing` rather than taking
|
||||
startup down from inside its own `start` hook; discovery, `pnpm modules:validate`, and Doctor all read
|
||||
@@ -469,5 +471,36 @@ for requests already in flight. Reverse-order stop then deactivates each module'
|
||||
immediately before that module's own stop hook, so dependencies remain operational while dependents
|
||||
clean up and captured publishers cannot outlive their module. Direct object-delivery URLs remain
|
||||
opaque payload strings and are never re-signed per publication or subscriber. MQTT remains an
|
||||
external-control concern for a future Companion boundary, not an internal module bus. Display/kiosk
|
||||
hosting and its public/device principal are explicitly not part of this pass.
|
||||
external-control concern for a future Companion boundary, not an internal module bus.
|
||||
|
||||
Phase 7A pass 6 adds a dedicated display role and Ekklesia host
|
||||
([ADR 0033](decisions/0033-display-kiosk-host-contract.md)). Manifest version 6 gives a module one
|
||||
optional `entrypoints.display` object containing a compiled artifact and one module-owned permission.
|
||||
The permission must have an `authenticated` or `restricted` baseline: public/device display identity
|
||||
is still intentionally unsolved. The display artifact must be distinct from every other configured
|
||||
entrypoint. Primary UI, display UI, both, and neither are all valid module shapes.
|
||||
|
||||
The two browser roles share the existing `defineModuleUi({ id, version, mount })` export and exactly
|
||||
the same `ModuleUiHostContext`; role selection comes from separate artifacts, never a `mode`,
|
||||
`presentation.kind`, or host-identity branch. The canonical builder reads only
|
||||
`src/ui/index.tsx` and `src/display/index.tsx`, bundles React into each declared role, rejects CSS
|
||||
sidecars, and publishes no output until every requested bundle has compiled. Core validates both
|
||||
paths inertly and builds both publication records only from the dependency-resolved eligible/running
|
||||
set; it never imports browser code.
|
||||
|
||||
Ekklesia keeps its primary Dashboard host unchanged and adds a separate full-viewport application.
|
||||
For each running display-capable module, the API registers the stable page `/display/<module-id>`, a
|
||||
protected descriptor at `/api/v1/module-displays/<module-id>`, and the exact display artifact at
|
||||
`/api/v1/module-ui/<module-id>/<version>/display`. The page and descriptor use normal cookie identity
|
||||
and the manifest's display permission; the artifact remains anonymous trusted code because bytes
|
||||
confer no authority. There is no display inventory in this pass. The descriptor supplies the same
|
||||
module API root, realtime root, principal-derived permission hints, and exact artifact identity the
|
||||
generic loader already consumes. The surface adds no Dashboard chrome and does not request the
|
||||
browser Fullscreen API; failures remain bounded behind a fixed state and manual retry.
|
||||
|
||||
Production reads the fixed display HTML and script once before binding the listener and serves that
|
||||
frozen snapshot, never a directory. Enablement, dependency blocking, and runtime startup determine
|
||||
whether routes exist, and installed-manifest changes remain restart-based. Realtime and direct signed
|
||||
object URLs are unchanged and flow through the same portable contracts. Named display variants,
|
||||
targeting, display inventory/management, device/public identity, a standalone host, shared CSS,
|
||||
Announcements migration, and Companion integration remain later work.
|
||||
|
||||
Reference in New Issue
Block a user