diff --git a/apps/hub/src/live-app/host-report.ts b/apps/hub/src/live-app/host-report.ts new file mode 100644 index 00000000..9295c3d5 --- /dev/null +++ b/apps/hub/src/live-app/host-report.ts @@ -0,0 +1,10 @@ +import { type } from "arktype"; + +export const HostReport = type({ + state: "'starting'", + phase: "'installing' | 'starting'", + log: "string[]", +}) + .or({ state: "'running'", url: "string" }) + .or({ state: "'failed'", error: "string", log: "string[]" }); +export type HostReport = typeof HostReport.infer; diff --git a/apps/hub/src/live-app/host.ts b/apps/hub/src/live-app/host.ts index 6eea154a..3626a00f 100644 --- a/apps/hub/src/live-app/host.ts +++ b/apps/hub/src/live-app/host.ts @@ -12,6 +12,7 @@ import { type } from "arktype"; import { hasCode } from "@intx/types"; import { liveAppWording } from "../config/live-app.ts"; import { errorCode } from "../request-error.ts"; +import type { HostReport } from "./host-report.ts"; import { parseJson } from "../lib/json.ts"; import { writeBundle } from "../artifacts/design-tools.ts"; import { bundleFiles, collectApp } from "../builds/app-snapshot.ts"; @@ -21,10 +22,6 @@ import { IGNORED_CHANGES, } from "../builds/posix-sandbox.ts"; -export type HostReport = - | { state: "starting"; phase: "installing" | "starting"; log: string[] } - | { state: "running"; url: string } - | { state: "failed"; error: string; log: string[] }; export const HostSource = type({ dir: "string > 0" }).or({ files: { "[string]": "string" }, "binary?": { "[string]": "string" }, diff --git a/apps/hub/src/live-app/runner.ts b/apps/hub/src/live-app/runner.ts index 78d89f8e..c2727843 100644 --- a/apps/hub/src/live-app/runner.ts +++ b/apps/hub/src/live-app/runner.ts @@ -4,7 +4,8 @@ import { fileURLToPath } from "node:url"; import { getLogger } from "@intx/log"; import { errorCode, requestErrorMetadata } from "../request-error.ts"; import { liveAppWording } from "../config/live-app.ts"; -import type { HostReport, HostSource } from "./host.ts"; +import type { HostSource } from "./host.ts"; +import { HostReport } from "./host-report.ts"; import type { createLiveAppProxy } from "./proxy.ts"; const log = getLogger(["corbits-builder", "hub", "live-app"]); @@ -66,7 +67,7 @@ export function createLiveAppRunner(options: { end !== -1; end = pending.indexOf("\n") ) { - run.state = JSON.parse(pending.slice(0, end)) as HostReport; + run.state = HostReport.assert(JSON.parse(pending.slice(0, end))); pending = pending.slice(end + 1); } } diff --git a/apps/hub/src/sidecar/manifest-store.ts b/apps/hub/src/sidecar/manifest-store.ts index 20b52b6e..1e82de18 100644 --- a/apps/hub/src/sidecar/manifest-store.ts +++ b/apps/hub/src/sidecar/manifest-store.ts @@ -5,13 +5,14 @@ import { type } from "arktype"; import { errorText } from "./error-text.ts"; import { hasCode, type CredentialCipher } from "@intx/types"; +const LocalSidecarManifestSchema = type({ + sidecarId: "string", + hubWebSocketUrl: "string", + dataDir: "string", + token: "string", +}); /** The hub's one local sidecar: the identity it authenticates with and where it keeps its state. */ -export type LocalSidecarManifest = { - readonly sidecarId: string; - readonly hubWebSocketUrl: string; - readonly dataDir: string; - readonly token: string; -}; +export type LocalSidecarManifest = typeof LocalSidecarManifestSchema.infer; /** An allocation the sidecar hosts, at the generation and under the identity the hub offered for it. */ const LocalSidecarHold = type({ @@ -106,7 +107,7 @@ export function createLocalSidecarManifestStore({ const text = await readOptional(manifestFile); if (text === null) return null; try { - const stored = JSON.parse(text) as LocalSidecarManifest; + const stored = LocalSidecarManifestSchema.assert(JSON.parse(text)); return { ...stored, token: await cipher.decrypt(