From 855b5f9f542ea1172f4676c2748268b856f2e717 Mon Sep 17 00:00:00 2001 From: ekklesia Date: Mon, 5 Oct 2026 22:08:31 -0500 Subject: [PATCH] chore: release signage 0.1.2 0.1.2 fixes what the first production Signage deployment found: - #4: the display and server share one message schema; every heartbeat from an image slide used to be refused with a 400; - #5: every display request retries with backoff and never gives up, so a display that failed one request no longer stays offline until reloaded; - #6: one object URL per cached slide, released when done; the leak exhausted the browser within minutes; - CI (#7, #8): every change runs inside a pinned Ekklesia, end to end in a real browser, and cleans up even when killed. compatibility.platform stays ^0.1.0: every fix is module-side, and CI tested it against platform v0.1.1 plus test-only scripts. The README no longer says Signage is unreleased or undeployed. Co-Authored-By: Claude Opus 5.5 --- README.md | 11 ++++++----- ekklesia.module.json | 2 +- package.json | 2 +- src/display/index.tsx | 2 +- src/server/runtime.ts | 4 ++-- src/ui/index.tsx | 2 +- tests/browser/support/fake-host.ts | 2 +- tests/manifest.test.ts | 6 +++--- 8 files changed, 16 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 2378ce5..0010899 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,8 @@ Ekklesia and vendors none of its SDKs. ## Status -Version 0.1.1 is feature-complete for its declared scope and unreleased. What exists today: +Version 0.1.2 is feature-complete for its declared scope, and Signage has run in production since +0.1.1. What exists today: - The module package, manifest (v7), four capabilities, six permissions, ten operator settings, and one logical storage bucket. @@ -34,10 +35,10 @@ Version 0.1.1 is feature-complete for its declared scope and unreleased. What ex renderers mounted as browser contributions, the built-in "Content unavailable" slate, deliberate blackout, and offline continuation from this display's own persisted state. -Nothing here is deployed, and no cutover from the legacy Announcements container has happened or is -planned by this repository. Video, audio, MQTT, Home Assistant, Companion, and a notification outbox -are out of scope; so is any content module — Signage ships with no announcements, scripture, or -trivia, and cannot render any until one is installed. +No cutover from the legacy Announcements container has happened or is planned by this repository. +Video, audio, MQTT, Home Assistant, Companion, and a notification outbox are out of scope; so is +any content module — Signage ships with no announcements, scripture, or trivia, and cannot render +any until one is installed. ### Offline cold start is not yet possible diff --git a/ekklesia.module.json b/ekklesia.module.json index d41274e..be6aa8f 100644 --- a/ekklesia.module.json +++ b/ekklesia.module.json @@ -3,7 +3,7 @@ "id": "signage", "name": "Signage", "description": "Visual programming, timelines, synchronized channels, and display delivery for church screens.", - "version": "0.1.1", + "version": "0.1.2", "compatibility": { "platform": "^0.1.0", "moduleSdk": "^0.1.0" diff --git a/package.json b/package.json index 7baf1a1..0f21853 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@ekklesia/signage", - "version": "0.1.1", + "version": "0.1.2", "private": true, "type": "module", "description": "Ekklesia's visual programming, timeline, synchronization, and display-delivery module.", diff --git a/src/display/index.tsx b/src/display/index.tsx index 9ab6b91..5d3323f 100644 --- a/src/display/index.tsx +++ b/src/display/index.tsx @@ -59,7 +59,7 @@ function SignageDisplay({ context }: { readonly context: ModuleUiHostContext }): */ export default defineModuleUi({ id: "signage", - version: "0.1.1", + version: "0.1.2", styles: displayStyles, mount(container, context) { const root = createRoot(container); diff --git a/src/server/runtime.ts b/src/server/runtime.ts index a8c712e..4052853 100644 --- a/src/server/runtime.ts +++ b/src/server/runtime.ts @@ -127,7 +127,7 @@ export function createSignageModuleRuntime( const definition = defineModuleRuntime({ id: "signage", - version: "0.1.1", + version: "0.1.2", register({ capabilities, config, http, realtime }) { const settings = readSignageSettings(config); @@ -189,7 +189,7 @@ export function createSignageModuleRuntime( // server enforces — a UI believing a stale limit would offer an upload the server refuses. return Response.json({ crossfadeMs: current.crossfadeMs, - moduleVersion: "0.1.1", + moduleVersion: "0.1.2", nativeImageDurationMs: current.nativeImageDurationMs, nativePresentation: current.nativePresentation, rendererInputVersion: SIGNAGE_SLIDE_RENDERER_INPUT_VERSION, diff --git a/src/ui/index.tsx b/src/ui/index.tsx index de56c12..d55ec67 100644 --- a/src/ui/index.tsx +++ b/src/ui/index.tsx @@ -15,7 +15,7 @@ import ownStyles from "./styles.css"; */ export default defineModuleUi({ id: "signage", - version: "0.1.1", + version: "0.1.2", styles: `${EKKLESIA_UI_STYLESHEET}\n${ownStyles}`, mount(container, context) { const root = createRoot(container); diff --git a/tests/browser/support/fake-host.ts b/tests/browser/support/fake-host.ts index ea561ab..78e0844 100644 --- a/tests/browser/support/fake-host.ts +++ b/tests/browser/support/fake-host.ts @@ -127,7 +127,7 @@ export function createFakeHost(options: FakeHostOptions): FakeHost { /** The settings payload every screen loads first. */ export const FAKE_SETTINGS = Object.freeze({ crossfadeMs: 1000, - moduleVersion: "0.1.1", + moduleVersion: "0.1.2", nativeImageDurationMs: 7000, nativePresentation: { backgroundColor: "#000000", diff --git a/tests/manifest.test.ts b/tests/manifest.test.ts index 629bae1..301f3f0 100644 --- a/tests/manifest.test.ts +++ b/tests/manifest.test.ts @@ -66,7 +66,7 @@ describe("Signage module manifest", () => { expect(manifest.manifestVersion).toBe(7); expect(manifest.id).toBe("signage"); expect(manifest.name).toBe("Signage"); - expect(manifest.version).toBe("0.1.1"); + expect(manifest.version).toBe("0.1.2"); expect(manifest.compatibility).toEqual({ moduleSdk: "^0.1.0", platform: "^0.1.0" }); }); @@ -142,7 +142,7 @@ describe("Signage module manifest", () => { describe("Signage server runtime", () => { it("exports the typed runtime definition the compiled server entrypoint publishes", async () => { - expect(moduleRuntime).toMatchObject({ id: "signage", version: "0.1.1" }); + expect(moduleRuntime).toMatchObject({ id: "signage", version: "0.1.2" }); }); it("registers its routes declaratively, with no database, storage, or realtime work", async () => { @@ -241,7 +241,7 @@ describe("Signage server runtime", () => { expect(response.status).toBe(200); expect(await response.json()).toEqual({ crossfadeMs: 400, - moduleVersion: "0.1.1", + moduleVersion: "0.1.2", nativeImageDurationMs: 12_000, nativePresentation: SIGNAGE_DEFAULT_SETTINGS.nativePresentation, rendererInputVersion: "1.0.0", -- 2.54.0