@telorun/runner-core 0.5.2 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/dist/abortable-delay.d.ts +10 -0
  2. package/dist/abortable-delay.d.ts.map +1 -0
  3. package/dist/abortable-delay.js +26 -0
  4. package/dist/abortable-delay.js.map +1 -0
  5. package/dist/backend.d.ts +10 -1
  6. package/dist/backend.d.ts.map +1 -1
  7. package/dist/config.d.ts +43 -1
  8. package/dist/config.d.ts.map +1 -1
  9. package/dist/config.js +77 -0
  10. package/dist/config.js.map +1 -1
  11. package/dist/contract.d.ts +34 -2
  12. package/dist/contract.d.ts.map +1 -1
  13. package/dist/contract.js.map +1 -1
  14. package/dist/debug/relay.d.ts.map +1 -1
  15. package/dist/debug/relay.js +3 -17
  16. package/dist/debug/relay.js.map +1 -1
  17. package/dist/index.d.ts +1 -0
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js +1 -0
  20. package/dist/index.js.map +1 -1
  21. package/dist/reachability.d.ts +37 -0
  22. package/dist/reachability.d.ts.map +1 -0
  23. package/dist/reachability.js +71 -0
  24. package/dist/reachability.js.map +1 -0
  25. package/dist/routes/sessions.d.ts +5 -0
  26. package/dist/routes/sessions.d.ts.map +1 -1
  27. package/dist/routes/sessions.js +83 -31
  28. package/dist/routes/sessions.js.map +1 -1
  29. package/dist/server.d.ts +7 -2
  30. package/dist/server.d.ts.map +1 -1
  31. package/dist/server.js +11 -2
  32. package/dist/server.js.map +1 -1
  33. package/package.json +1 -1
  34. package/src/abortable-delay.ts +24 -0
  35. package/src/app-catalog.test.ts +54 -0
  36. package/src/backend.ts +10 -0
  37. package/src/config.ts +116 -1
  38. package/src/contract.ts +33 -3
  39. package/src/debug/relay.ts +4 -17
  40. package/src/index.ts +4 -0
  41. package/src/reachability.test.ts +83 -0
  42. package/src/reachability.ts +106 -0
  43. package/src/routes/sessions.ts +93 -30
  44. package/src/server.ts +24 -5
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Resolve after `ms`, or immediately when `signal` aborts. Safe to call in a
3
+ * poll loop on a shared signal: it removes its abort listener on the timer path
4
+ * (so repeated calls can't accumulate listeners) and fast-paths an
5
+ * already-aborted signal (so a loop tears down promptly instead of waiting out
6
+ * one more interval). The timer is `unref`'d so a pending delay can't keep the
7
+ * process alive on its own.
8
+ */
9
+ export declare function abortableDelay(ms: number, signal: AbortSignal): Promise<void>;
10
+ //# sourceMappingURL=abortable-delay.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"abortable-delay.d.ts","sourceRoot":"","sources":["../src/abortable-delay.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAe7E"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Resolve after `ms`, or immediately when `signal` aborts. Safe to call in a
3
+ * poll loop on a shared signal: it removes its abort listener on the timer path
4
+ * (so repeated calls can't accumulate listeners) and fast-paths an
5
+ * already-aborted signal (so a loop tears down promptly instead of waiting out
6
+ * one more interval). The timer is `unref`'d so a pending delay can't keep the
7
+ * process alive on its own.
8
+ */
9
+ export function abortableDelay(ms, signal) {
10
+ return new Promise((resolve) => {
11
+ if (signal.aborted)
12
+ return resolve();
13
+ let timer;
14
+ const onAbort = () => {
15
+ clearTimeout(timer);
16
+ resolve();
17
+ };
18
+ timer = setTimeout(() => {
19
+ signal.removeEventListener("abort", onAbort);
20
+ resolve();
21
+ }, ms);
22
+ timer.unref?.();
23
+ signal.addEventListener("abort", onAbort, { once: true });
24
+ });
25
+ }
26
+ //# sourceMappingURL=abortable-delay.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"abortable-delay.js","sourceRoot":"","sources":["../src/abortable-delay.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,MAAM,UAAU,cAAc,CAAC,EAAU,EAAE,MAAmB;IAC5D,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,IAAI,MAAM,CAAC,OAAO;YAAE,OAAO,OAAO,EAAE,CAAC;QACrC,IAAI,KAAoC,CAAC;QACzC,MAAM,OAAO,GAAG,GAAS,EAAE;YACzB,YAAY,CAAC,KAAK,CAAC,CAAC;YACpB,OAAO,EAAE,CAAC;QACZ,CAAC,CAAC;QACF,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;YACtB,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;YAC7C,OAAO,EAAE,CAAC;QACZ,CAAC,EAAE,EAAE,CAAC,CAAC;QACP,KAAK,CAAC,KAAK,EAAE,EAAE,CAAC;QAChB,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;IAC5D,CAAC,CAAC,CAAC;AACL,CAAC"}
package/dist/backend.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { DebugFrame } from "@telorun/debug-wire";
2
- import type { AvailabilityReport, PortMapping, ProbeConfig, RunBundle, RunPhase, RunStatus, SessionConfig } from "./contract.js";
2
+ import type { AvailabilityReport, PortMapping, ProbeConfig, ReachabilityState, RunBundle, RunPhase, RunStatus, SessionConfig } from "./contract.js";
3
3
  /**
4
4
  * The seam between backend-neutral session machinery (routes, registry, SSE)
5
5
  * and a concrete workload runtime (docker container, kubernetes pod).
@@ -34,6 +34,11 @@ export interface BackendStartSpec {
34
34
  env: Record<string, string>;
35
35
  ports: PortMapping[];
36
36
  config: SessionConfig;
37
+ /** True for an operator-predefined app session (`StartSessionRequest.app`):
38
+ * `config.image` is self-contained (app + controllers baked in), so the
39
+ * backend runs the image's own entrypoint and stages no bundle — `bundle`
40
+ * is an empty placeholder. */
41
+ selfContained: boolean;
37
42
  /** When true, launch the workload with `--inspect` and relay its kernel debug
38
43
  * stream via `onDebug`. The inspect endpoint stays reachable only by the
39
44
  * runner — never published outward. */
@@ -50,6 +55,10 @@ export interface BackendStartSpec {
50
55
  /** A frame relayed from the workload's kernel debug stream. Only called when
51
56
  * `inspect` is true and the backend has connected to the inspect endpoint. */
52
57
  onDebug(frame: DebugFrame): void;
58
+ /** Report a declared port's reachability from the runner network — `checking`
59
+ * while the workload comes up, then `reachable`, or `unreachable` after a
60
+ * timeout. Surfaced on the editor's endpoint badge, not the log stream. */
61
+ onReachability(port: number, state: ReachabilityState): void;
53
62
  /** True once a user stop / shutdown has been requested — lets the backend
54
63
  * classify a kill as `stopped` rather than `failed`. */
55
64
  isUserStopped(): boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"backend.d.ts","sourceRoot":"","sources":["../src/backend.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEtD,OAAO,KAAK,EACV,kBAAkB,EAClB,WAAW,EACX,WAAW,EACX,SAAS,EACT,QAAQ,EACR,SAAS,EACT,aAAa,EACd,MAAM,eAAe,CAAC;AAEvB;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,aAAa;IAC5B;wEACoE;IACpE,KAAK,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC;IAExD;;8DAE0D;IAC1D,KAAK,CAAC,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;IAEvD;;qEAEiE;IACjE,WAAW,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC/B;AAED,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,SAAS,CAAC;IAClB,wEAAwE;IACxE,iBAAiB,EAAE,MAAM,CAAC;IAC1B,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5B,KAAK,EAAE,WAAW,EAAE,CAAC;IACrB,MAAM,EAAE,aAAa,CAAC;IACtB;;4CAEwC;IACxC,OAAO,EAAE,OAAO,CAAC;IAEjB;kDAC8C;IAC9C,QAAQ,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAAC;IAClC;;gEAE4D;IAC5D,UAAU,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IACnE,8DAA8D;IAC9D,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B;mFAC+E;IAC/E,OAAO,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,CAAC;IACjC;6DACyD;IACzD,aAAa,IAAI,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,cAAc;IAC7B;0DACsD;IACtD,UAAU,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,CAAC;IAEpC,iCAAiC;IACjC,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAEzC;;2BAEuB;IACvB,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IAE7B;wEACoE;IACpE,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACvB"}
1
+ {"version":3,"file":"backend.d.ts","sourceRoot":"","sources":["../src/backend.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEtD,OAAO,KAAK,EACV,kBAAkB,EAClB,WAAW,EACX,WAAW,EACX,iBAAiB,EACjB,SAAS,EACT,QAAQ,EACR,SAAS,EACT,aAAa,EACd,MAAM,eAAe,CAAC;AAEvB;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,aAAa;IAC5B;wEACoE;IACpE,KAAK,CAAC,MAAM,EAAE,WAAW,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC;IAExD;;8DAE0D;IAC1D,KAAK,CAAC,IAAI,EAAE,gBAAgB,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;IAEvD;;qEAEiE;IACjE,WAAW,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CAC/B;AAED,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,SAAS,CAAC;IAClB,wEAAwE;IACxE,iBAAiB,EAAE,MAAM,CAAC;IAC1B,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5B,KAAK,EAAE,WAAW,EAAE,CAAC;IACrB,MAAM,EAAE,aAAa,CAAC;IACtB;;;mCAG+B;IAC/B,aAAa,EAAE,OAAO,CAAC;IACvB;;4CAEwC;IACxC,OAAO,EAAE,OAAO,CAAC;IAEjB;kDAC8C;IAC9C,QAAQ,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAAC;IAClC;;gEAE4D;IAC5D,UAAU,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IACnE,8DAA8D;IAC9D,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B;mFAC+E;IAC/E,OAAO,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,CAAC;IACjC;;gFAE4E;IAC5E,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,iBAAiB,GAAG,IAAI,CAAC;IAC7D;6DACyD;IACzD,aAAa,IAAI,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,cAAc;IAC7B;0DACsD;IACtD,UAAU,CAAC,KAAK,EAAE,UAAU,GAAG,IAAI,CAAC;IAEpC,iCAAiC;IACjC,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAEzC;;2BAEuB;IACvB,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IAE7B;wEACoE;IACpE,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACvB"}
package/dist/config.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { RunnerTerms } from "./contract.js";
1
+ import type { PullPolicy, RunnerTerms } from "./contract.js";
2
2
  /**
3
3
  * Backend-neutral runner configuration. Concrete runners (docker, k8s) extend
4
4
  * `RunnerCoreConfig` with their own fields and reuse these parse helpers so
@@ -30,6 +30,48 @@ export declare function parsePort(raw: string | undefined, fallback: number): nu
30
30
  * silent "no terms", so a misconfiguration can't quietly drop the gate.
31
31
  */
32
32
  export declare function loadTermsFromEnv(env: NodeJS.ProcessEnv): RunnerTerms | undefined;
33
+ /**
34
+ * An operator-predefined application entry in `RUNNER_APPS`. The catalog is the
35
+ * whole gate: a client launches an app by name and can neither pick the image
36
+ * nor read the injected env, so no allowlist beyond the catalog is needed.
37
+ *
38
+ * The catalog may embed secrets (`env` values), so treat the whole `RUNNER_APPS`
39
+ * value as secret material (docker: a `.env.local` file; k8s: source it from a
40
+ * Secret). Only `name`/`title`/`description` are ever advertised outward —
41
+ * `image` and `env` never leave the runner.
42
+ */
43
+ export interface RunnerAppConfig {
44
+ image: string;
45
+ /** Env injected verbatim into the app's workload (operator secrets included).
46
+ * A client-supplied value for any key defined here is dropped — operator
47
+ * values always win. */
48
+ env?: Record<string, string>;
49
+ /** Workload image pull policy (default `missing`); `always` keeps a moving
50
+ * tag like `latest-slim` fresh. */
51
+ pullPolicy?: PullPolicy;
52
+ title?: string;
53
+ description?: string;
54
+ }
55
+ /** A validated catalog entry with defaults applied, keyed back by its name. */
56
+ export interface ResolvedRunnerApp {
57
+ name: string;
58
+ image: string;
59
+ env: Record<string, string>;
60
+ pullPolicy: PullPolicy;
61
+ title?: string;
62
+ description?: string;
63
+ }
64
+ /**
65
+ * Parse the `RUNNER_APPS` JSON catalog ({ "<name>": RunnerAppConfig }).
66
+ * Returns `undefined` when unset (no apps offered). Malformed JSON or entries
67
+ * are a hard `RunnerConfigError` — a broken catalog must not silently drop
68
+ * the apps.
69
+ */
70
+ export declare function loadAppsFromEnv(env: NodeJS.ProcessEnv): Record<string, RunnerAppConfig> | undefined;
71
+ /** The catalog runners pass to `buildServer`: `RUNNER_APPS` validated with
72
+ * defaults applied; empty when unset. The catalog is pure operator
73
+ * configuration — runner-core knows nothing about any specific app. */
74
+ export declare function loadResolvedApps(env: NodeJS.ProcessEnv): Record<string, ResolvedRunnerApp>;
33
75
  export declare function parseCorsOrigins(raw: string | undefined): string[] | "*";
34
76
  export declare function loadCoreConfig(env: NodeJS.ProcessEnv, defaults?: {
35
77
  port?: number;
@@ -1 +1 @@
1
- {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAEjD;;;;GAIG;AACH,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,WAAW,EAAE,MAAM,EAAE,GAAG,GAAG,CAAC;CAC7B;AAED,qBAAa,iBAAkB,SAAQ,KAAK;CAAG;AAE/C,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,MAAM,GAAG,SAAS,EACvB,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,GACZ,MAAM,CAOR;AAED,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAM5F;AAED,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAO3E;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,CAAC,UAAU,GAAG,WAAW,GAAG,SAAS,CAQhF;AAsBD,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,EAAE,GAAG,GAAG,CAMxE;AAED,wBAAgB,cAAc,CAC5B,GAAG,EAAE,MAAM,CAAC,UAAU,EACtB,QAAQ,GAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAA;CAAO,GAC/B,gBAAgB,CAiBlB"}
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAE7D;;;;GAIG;AACH,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,WAAW,EAAE,MAAM,EAAE,GAAG,GAAG,CAAC;CAC7B;AAED,qBAAa,iBAAkB,SAAQ,KAAK;CAAG;AAE/C,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,MAAM,GAAG,SAAS,EACvB,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,GACZ,MAAM,CAOR;AAED,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,EAAE,QAAQ,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAM5F;AAED,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAO3E;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,CAAC,UAAU,GAAG,WAAW,GAAG,SAAS,CAQhF;AAsBD;;;;;;;;;GASG;AACH,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd;;6BAEyB;IACzB,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7B;wCACoC;IACpC,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,+EAA+E;AAC/E,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5B,UAAU,EAAE,UAAU,CAAC;IACvB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAID;;;;;GAKG;AACH,wBAAgB,eAAe,CAC7B,GAAG,EAAE,MAAM,CAAC,UAAU,GACrB,MAAM,CAAC,MAAM,EAAE,eAAe,CAAC,GAAG,SAAS,CAmB7C;AAkCD;;wEAEwE;AACxE,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,CAAC,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAc1F;AAED,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,EAAE,GAAG,GAAG,CAMxE;AAED,wBAAgB,cAAc,CAC5B,GAAG,EAAE,MAAM,CAAC,UAAU,EACtB,QAAQ,GAAE;IAAE,IAAI,CAAC,EAAE,MAAM,CAAA;CAAO,GAC/B,gBAAgB,CAiBlB"}
package/dist/config.js CHANGED
@@ -68,6 +68,83 @@ function resolveTermsBody(env) {
68
68
  function hashTermsVersion(body) {
69
69
  return createHash("sha256").update(body).digest("hex").slice(0, 12);
70
70
  }
71
+ const PULL_POLICIES = ["missing", "always", "never"];
72
+ /**
73
+ * Parse the `RUNNER_APPS` JSON catalog ({ "<name>": RunnerAppConfig }).
74
+ * Returns `undefined` when unset (no apps offered). Malformed JSON or entries
75
+ * are a hard `RunnerConfigError` — a broken catalog must not silently drop
76
+ * the apps.
77
+ */
78
+ export function loadAppsFromEnv(env) {
79
+ const raw = env.RUNNER_APPS?.trim();
80
+ if (!raw)
81
+ return undefined;
82
+ let parsed;
83
+ try {
84
+ parsed = JSON.parse(raw);
85
+ }
86
+ catch (err) {
87
+ throw new RunnerConfigError(`RUNNER_APPS is not valid JSON: ${err.message}`);
88
+ }
89
+ if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
90
+ throw new RunnerConfigError("RUNNER_APPS must be a JSON object mapping app name → app config.");
91
+ }
92
+ // Null-prototype map so an app literally named `__proto__` is stored as a
93
+ // plain key rather than mutating the object's prototype.
94
+ const catalog = Object.create(null);
95
+ for (const [name, value] of Object.entries(parsed)) {
96
+ catalog[name] = validateAppEntry(name, value);
97
+ }
98
+ return catalog;
99
+ }
100
+ function validateAppEntry(name, value) {
101
+ const fail = (detail) => {
102
+ throw new RunnerConfigError(`RUNNER_APPS entry '${name}' ${detail}`);
103
+ };
104
+ if (name.trim() === "")
105
+ fail("has an empty name.");
106
+ if (value === null || typeof value !== "object" || Array.isArray(value)) {
107
+ fail("must be an object.");
108
+ }
109
+ const entry = value;
110
+ if (typeof entry.image !== "string" || entry.image.trim() === "") {
111
+ fail("needs a non-empty string 'image'.");
112
+ }
113
+ if (entry.env !== undefined &&
114
+ (entry.env === null ||
115
+ typeof entry.env !== "object" ||
116
+ Array.isArray(entry.env) ||
117
+ Object.values(entry.env).some((v) => typeof v !== "string"))) {
118
+ fail("has an invalid 'env' — expected an object of string values.");
119
+ }
120
+ if (entry.pullPolicy !== undefined && !PULL_POLICIES.includes(entry.pullPolicy)) {
121
+ fail(`has an invalid 'pullPolicy' — expected one of ${PULL_POLICIES.join(", ")}.`);
122
+ }
123
+ for (const key of ["title", "description"]) {
124
+ if (entry[key] !== undefined && typeof entry[key] !== "string") {
125
+ fail(`has an invalid '${key}' — expected a string.`);
126
+ }
127
+ }
128
+ return entry;
129
+ }
130
+ /** The catalog runners pass to `buildServer`: `RUNNER_APPS` validated with
131
+ * defaults applied; empty when unset. The catalog is pure operator
132
+ * configuration — runner-core knows nothing about any specific app. */
133
+ export function loadResolvedApps(env) {
134
+ const catalog = loadAppsFromEnv(env) ?? {};
135
+ const resolved = Object.create(null);
136
+ for (const [name, entry] of Object.entries(catalog)) {
137
+ resolved[name] = {
138
+ name,
139
+ image: entry.image,
140
+ env: entry.env ?? {},
141
+ pullPolicy: entry.pullPolicy ?? "missing",
142
+ title: entry.title,
143
+ description: entry.description,
144
+ };
145
+ }
146
+ return resolved;
147
+ }
71
148
  export function parseCorsOrigins(raw) {
72
149
  if (raw === undefined || raw.trim() === "" || raw.trim() === "*")
73
150
  return "*";
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAkBvC,MAAM,OAAO,iBAAkB,SAAQ,KAAK;CAAG;AAE/C,MAAM,UAAU,gBAAgB,CAC9B,GAAuB,EACvB,QAAgB,EAChB,KAAa;IAEb,IAAI,GAAG,KAAK,SAAS,IAAI,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE;QAAE,OAAO,QAAQ,CAAC;IAC5D,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;IACtB,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QACnC,MAAM,IAAI,iBAAiB,CAAC,GAAG,KAAK,qCAAqC,GAAG,IAAI,CAAC,CAAC;IACpF,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,GAAuB,EAAE,QAAiB,EAAE,KAAa;IACjF,MAAM,CAAC,GAAG,GAAG,EAAE,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACpC,IAAI,CAAC,KAAK,SAAS,IAAI,CAAC,KAAK,EAAE;QAAE,OAAO,QAAQ,CAAC;IACjD,IAAI,CAAC,KAAK,MAAM,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,KAAK;QAAE,OAAO,IAAI,CAAC;IAC1D,IAAI,CAAC,KAAK,OAAO,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,IAAI;QAAE,OAAO,KAAK,CAAC;IAC3D,MAAM,IAAI,iBAAiB,CAAC,GAAG,KAAK,yCAAyC,GAAG,IAAI,CAAC,CAAC;AACxF,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,GAAuB,EAAE,QAAgB;IACjE,MAAM,OAAO,GAAG,GAAG,IAAI,MAAM,CAAC,QAAQ,CAAC,CAAC;IACxC,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC;IAC7B,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,IAAI,GAAG,KAAK,EAAE,CAAC;QACzD,MAAM,IAAI,iBAAiB,CAAC,6CAA6C,OAAO,IAAI,CAAC,CAAC;IACxF,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,gBAAgB,CAAC,GAAsB;IACrD,MAAM,IAAI,GAAG,gBAAgB,CAAC,GAAG,CAAC,CAAC;IACnC,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE;QAAE,OAAO,SAAS,CAAC;IAClD,OAAO;QACL,OAAO,EAAE,GAAG,CAAC,oBAAoB,EAAE,IAAI,EAAE,IAAI,gBAAgB,CAAC,IAAI,CAAC;QACnE,KAAK,EAAE,GAAG,CAAC,kBAAkB,EAAE,IAAI,EAAE,IAAI,iBAAiB;QAC1D,IAAI;KACL,CAAC;AACJ,CAAC;AAED,SAAS,gBAAgB,CAAC,GAAsB;IAC9C,MAAM,IAAI,GAAG,GAAG,CAAC,iBAAiB,EAAE,IAAI,EAAE,CAAC;IAC3C,IAAI,IAAI,EAAE,CAAC;QACT,IAAI,CAAC;YACH,OAAO,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;QACpC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,IAAI,iBAAiB,CACzB,2CAA2C,IAAI,MAAO,GAAa,CAAC,OAAO,EAAE,CAC9E,CAAC;QACJ,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC,iBAAiB,CAAC;AAC/B,CAAC;AAED;kEACkE;AAClE,SAAS,gBAAgB,CAAC,IAAY;IACpC,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AACtE,CAAC;AAmCD,MAAM,aAAa,GAAsB,CAAC,SAAS,EAAE,QAAQ,EAAE,OAAO,CAAC,CAAC;AAExE;;;;;GAKG;AACH,MAAM,UAAU,eAAe,CAC7B,GAAsB;IAEtB,MAAM,GAAG,GAAG,GAAG,CAAC,WAAW,EAAE,IAAI,EAAE,CAAC;IACpC,IAAI,CAAC,GAAG;QAAE,OAAO,SAAS,CAAC;IAC3B,IAAI,MAAe,CAAC;IACpB,IAAI,CAAC;QACH,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC3B,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,IAAI,iBAAiB,CAAC,kCAAmC,GAAa,CAAC,OAAO,EAAE,CAAC,CAAC;IAC1F,CAAC;IACD,IAAI,MAAM,KAAK,IAAI,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAC3E,MAAM,IAAI,iBAAiB,CAAC,kEAAkE,CAAC,CAAC;IAClG,CAAC;IACD,0EAA0E;IAC1E,yDAAyD;IACzD,MAAM,OAAO,GAAoC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACrE,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QACnD,OAAO,CAAC,IAAI,CAAC,GAAG,gBAAgB,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;IAChD,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,SAAS,gBAAgB,CAAC,IAAY,EAAE,KAAc;IACpD,MAAM,IAAI,GAAG,CAAC,MAAc,EAAS,EAAE;QACrC,MAAM,IAAI,iBAAiB,CAAC,sBAAsB,IAAI,KAAK,MAAM,EAAE,CAAC,CAAC;IACvE,CAAC,CAAC;IACF,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE;QAAE,IAAI,CAAC,oBAAoB,CAAC,CAAC;IACnD,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QACxE,IAAI,CAAC,oBAAoB,CAAC,CAAC;IAC7B,CAAC;IACD,MAAM,KAAK,GAAG,KAAgC,CAAC;IAC/C,IAAI,OAAO,KAAK,CAAC,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;QACjE,IAAI,CAAC,mCAAmC,CAAC,CAAC;IAC5C,CAAC;IACD,IACE,KAAK,CAAC,GAAG,KAAK,SAAS;QACvB,CAAC,KAAK,CAAC,GAAG,KAAK,IAAI;YACjB,OAAO,KAAK,CAAC,GAAG,KAAK,QAAQ;YAC7B,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC;YACxB,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,EAC9D,CAAC;QACD,IAAI,CAAC,6DAA6D,CAAC,CAAC;IACtE,CAAC;IACD,IAAI,KAAK,CAAC,UAAU,KAAK,SAAS,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,KAAK,CAAC,UAAoB,CAAC,EAAE,CAAC;QAC1F,IAAI,CAAC,iDAAiD,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACrF,CAAC;IACD,KAAK,MAAM,GAAG,IAAI,CAAC,OAAO,EAAE,aAAa,CAAU,EAAE,CAAC;QACpD,IAAI,KAAK,CAAC,GAAG,CAAC,KAAK,SAAS,IAAI,OAAO,KAAK,CAAC,GAAG,CAAC,KAAK,QAAQ,EAAE,CAAC;YAC/D,IAAI,CAAC,mBAAmB,GAAG,wBAAwB,CAAC,CAAC;QACvD,CAAC;IACH,CAAC;IACD,OAAO,KAAmC,CAAC;AAC7C,CAAC;AAED;;wEAEwE;AACxE,MAAM,UAAU,gBAAgB,CAAC,GAAsB;IACrD,MAAM,OAAO,GAAG,eAAe,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;IAC3C,MAAM,QAAQ,GAAsC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACxE,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QACpD,QAAQ,CAAC,IAAI,CAAC,GAAG;YACf,IAAI;YACJ,KAAK,EAAE,KAAK,CAAC,KAAK;YAClB,GAAG,EAAE,KAAK,CAAC,GAAG,IAAI,EAAE;YACpB,UAAU,EAAE,KAAK,CAAC,UAAU,IAAI,SAAS;YACzC,KAAK,EAAE,KAAK,CAAC,KAAK;YAClB,WAAW,EAAE,KAAK,CAAC,WAAW;SAC/B,CAAC;IACJ,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,GAAuB;IACtD,IAAI,GAAG,KAAK,SAAS,IAAI,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,GAAG,CAAC,IAAI,EAAE,KAAK,GAAG;QAAE,OAAO,GAAG,CAAC;IAC7E,OAAO,GAAG;SACP,KAAK,CAAC,GAAG,CAAC;SACV,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;SACpB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;AACjC,CAAC;AAED,MAAM,UAAU,cAAc,CAC5B,GAAsB,EACtB,WAA8B,EAAE;IAEhC,OAAO;QACL,IAAI,EAAE,SAAS,CAAC,GAAG,CAAC,IAAI,EAAE,QAAQ,CAAC,IAAI,IAAI,IAAI,CAAC;QAChD,QAAQ,EAAE,GAAG,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,MAAM;QACzC,WAAW,EAAE,gBAAgB,CAAC,GAAG,CAAC,mBAAmB,EAAE,EAAE,EAAE,qBAAqB,CAAC;QACjF,8EAA8E;QAC9E,2EAA2E;QAC3E,8EAA8E;QAC9E,yCAAyC;QACzC,SAAS,EAAE,gBAAgB,CAAC,GAAG,CAAC,kBAAkB,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,EAAE,oBAAoB,CAAC;QAC7F,iBAAiB,EAAE,gBAAgB,CACjC,GAAG,CAAC,0BAA0B,EAC9B,SAAS,EACT,4BAA4B,CAC7B;QACD,WAAW,EAAE,gBAAgB,CAAC,GAAG,CAAC,mBAAmB,CAAC;KACvD,CAAC;AACJ,CAAC"}
@@ -28,6 +28,10 @@ export interface RunnerCapabilities {
28
28
  * with `428 terms_required` unless the client sends `x-telo-accepted-terms`
29
29
  * matching `terms.version`. The editor surfaces it and records acceptance. */
30
30
  terms?: RunnerTerms;
31
+ /** Operator-predefined applications this runner can launch by name
32
+ * (`StartSessionRequest.app`). Absent/empty when none are offered — clients
33
+ * hide the corresponding entry points. */
34
+ apps?: RunnerAppDescriptor[];
31
35
  }
32
36
  /** An operator-defined agreement. `version` is opaque and operator-controlled;
33
37
  * bumping it re-prompts every client. `body` is plain text / markdown. */
@@ -44,6 +48,17 @@ export interface RunnerFeatures {
44
48
  /** Runner can publish workload ports back to the client. */
45
49
  ports: boolean;
46
50
  }
51
+ /** An operator-predefined application the runner can launch by name. Only the
52
+ * identity is advertised — the image and the operator env injected into it
53
+ * stay server-side, so a client can never pick the image or reach the
54
+ * secrets. Which apps exist is pure operator configuration (`RUNNER_APPS`);
55
+ * the runner has no built-in knowledge of any specific app. */
56
+ export interface RunnerAppDescriptor {
57
+ /** Wire id requested via `StartSessionRequest.app`. */
58
+ name: string;
59
+ title?: string;
60
+ description?: string;
61
+ }
47
62
  /** A JSON Schema document, kept structurally open so runner-core need not depend
48
63
  * on a JSON-Schema type package. The editor treats it as `JSONSchema7`. */
49
64
  export type JsonSchema = Record<string, unknown>;
@@ -98,10 +113,17 @@ export interface RunnerEndpoint {
98
113
  url?: string;
99
114
  }
100
115
  export interface StartSessionRequest {
101
- bundle: RunBundle;
116
+ /** Launch an operator-predefined application by name (see
117
+ * {@link RunnerAppDescriptor}) instead of a client bundle. The runner
118
+ * resolves the image and injects the app's operator env server-side;
119
+ * `bundle` and `config.image` are ignored. */
120
+ app?: string;
121
+ /** Required unless `app` is set. */
122
+ bundle?: RunBundle;
102
123
  env: Record<string, string>;
103
124
  ports?: PortMapping[];
104
- config: SessionConfig;
125
+ /** Required unless `app` is set. */
126
+ config?: SessionConfig;
105
127
  /** Request the kernel debug stream. When true the runner launches the
106
128
  * workload with `--inspect`, subscribes to the in-workload inspect endpoint
107
129
  * (reachable only by the runner — never published outward), and relays each
@@ -133,6 +155,10 @@ export type RunStatus = {
133
155
  * workload is actually up; these messages drive the editor's spinner + step feed.
134
156
  */
135
157
  export type RunPhase = "build" | "provision" | "boot";
158
+ /** Per-port reachability of a running session's declared ports, watched by the
159
+ * runner from its own network. Drives the editor's endpoint badge
160
+ * (spinner → ok / error) instead of an app-log line. */
161
+ export type ReachabilityState = "checking" | "reachable" | "unreachable";
136
162
  export type RunEvent = {
137
163
  type: "stdout";
138
164
  chunk: string;
@@ -153,6 +179,12 @@ export type RunEvent = {
153
179
  | {
154
180
  type: "debug";
155
181
  frame: DebugFrame;
182
+ }
183
+ /** A reachability transition for one declared port, keyed by port. */
184
+ | {
185
+ type: "reachability";
186
+ port: number;
187
+ state: ReachabilityState;
156
188
  };
157
189
  export declare function isTerminal(status: RunStatus): boolean;
158
190
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"contract.js","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAoCH,8EAA8E;AAC9E,MAAM,CAAC,MAAM,qBAAqB,GAAG,uBAAuB,CAAC;AAoG7D,MAAM,UAAU,UAAU,CAAC,MAAiB;IAC1C,OAAO,MAAM,CAAC,IAAI,KAAK,QAAQ,IAAI,MAAM,CAAC,IAAI,KAAK,QAAQ,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS,CAAC;AAC3F,CAAC;AAeD,MAAM,OAAO,iBAAkB,SAAQ,KAAK;IAExB;IACA;IAEA;IAJlB,YACkB,IAAoC,EACpC,KAAwB,EACxC,OAAe,EACC,aAAsB;QAEtC,KAAK,CAAC,OAAO,CAAC,CAAC;QALC,SAAI,GAAJ,IAAI,CAAgC;QACpC,UAAK,GAAL,KAAK,CAAmB;QAExB,kBAAa,GAAb,aAAa,CAAS;QAGtC,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAC;IAClC,CAAC;CACF"}
1
+ {"version":3,"file":"contract.js","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAwCH,8EAA8E;AAC9E,MAAM,CAAC,MAAM,qBAAqB,GAAG,uBAAuB,CAAC;AA8H7D,MAAM,UAAU,UAAU,CAAC,MAAiB;IAC1C,OAAO,MAAM,CAAC,IAAI,KAAK,QAAQ,IAAI,MAAM,CAAC,IAAI,KAAK,QAAQ,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS,CAAC;AAC3F,CAAC;AAeD,MAAM,OAAO,iBAAkB,SAAQ,KAAK;IAExB;IACA;IAEA;IAJlB,YACkB,IAAoC,EACpC,KAAwB,EACxC,OAAe,EACC,aAAsB;QAEtC,KAAK,CAAC,OAAO,CAAC,CAAC;QALC,SAAI,GAAJ,IAAI,CAAgC;QACpC,UAAK,GAAL,KAAK,CAAmB;QAExB,kBAAa,GAAb,aAAa,CAAS;QAGtC,IAAI,CAAC,IAAI,GAAG,mBAAmB,CAAC;IAClC,CAAC;CACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"relay.d.ts","sourceRoot":"","sources":["../../src/debug/relay.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEtD,MAAM,WAAW,iBAAiB;IAChC;2EACuE;IACvE,GAAG,EAAE,MAAM,CAAC;IACZ,kDAAkD;IAClD,OAAO,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;IACrC,wCAAwC;IACxC,MAAM,EAAE,WAAW,CAAC;IACpB;;qDAEiD;IACjD,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,KAAK,KAAK,IAAI,CAAC;CAChC;AAID;;;;;;;;GAQG;AACH,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAmB7E"}
1
+ {"version":3,"file":"relay.d.ts","sourceRoot":"","sources":["../../src/debug/relay.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAItD,MAAM,WAAW,iBAAiB;IAChC;2EACuE;IACvE,GAAG,EAAE,MAAM,CAAC;IACZ,kDAAkD;IAClD,OAAO,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;IACrC,wCAAwC;IACxC,MAAM,EAAE,WAAW,CAAC;IACpB;;qDAEiD;IACjD,OAAO,CAAC,EAAE,CAAC,GAAG,EAAE,KAAK,KAAK,IAAI,CAAC;CAChC;AAID;;;;;;;;GAQG;AACH,wBAAsB,gBAAgB,CAAC,IAAI,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAmB7E"}
@@ -1,3 +1,4 @@
1
+ import { abortableDelay } from "../abortable-delay.js";
1
2
  const RECONNECT_DELAY_MS = 500;
2
3
  /**
3
4
  * Subscribe to a workload's inspect SSE endpoint and deliver each frame to
@@ -17,7 +18,7 @@ export async function relayDebugStream(opts) {
17
18
  headers: { accept: "text/event-stream" },
18
19
  });
19
20
  if (!res.ok || !res.body) {
20
- await delay(RECONNECT_DELAY_MS, signal);
21
+ await abortableDelay(RECONNECT_DELAY_MS, signal);
21
22
  continue;
22
23
  }
23
24
  await pump(res.body, onFrame, signal);
@@ -27,7 +28,7 @@ export async function relayDebugStream(opts) {
27
28
  return;
28
29
  opts.onError?.(err instanceof Error ? err : new Error(String(err)));
29
30
  }
30
- await delay(RECONNECT_DELAY_MS, signal);
31
+ await abortableDelay(RECONNECT_DELAY_MS, signal);
31
32
  }
32
33
  }
33
34
  async function pump(body, onFrame, signal) {
@@ -71,19 +72,4 @@ function parseSseData(block) {
71
72
  return null;
72
73
  }
73
74
  }
74
- function delay(ms, signal) {
75
- return new Promise((resolve) => {
76
- if (signal.aborted)
77
- return resolve();
78
- const timer = setTimeout(() => {
79
- signal.removeEventListener("abort", onAbort);
80
- resolve();
81
- }, ms);
82
- const onAbort = () => {
83
- clearTimeout(timer);
84
- resolve();
85
- };
86
- signal.addEventListener("abort", onAbort, { once: true });
87
- });
88
- }
89
75
  //# sourceMappingURL=relay.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"relay.js","sourceRoot":"","sources":["../../src/debug/relay.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"relay.js","sourceRoot":"","sources":["../../src/debug/relay.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -16,5 +16,6 @@ export { probeRoute, type ProbeRouteDeps } from "./routes/probe.js";
16
16
  export { sessionsRoute, type SessionsRouteDeps } from "./routes/sessions.js";
17
17
  export { ioRoute, type IoRouteDeps } from "./routes/io.js";
18
18
  export { relayDebugStream, type DebugRelayOptions } from "./debug/relay.js";
19
+ export { watchReachability, type WatchReachabilityOptions, } from "./reachability.js";
19
20
  export type { DebugFrame, DebugEvent, DebugLog } from "@telorun/debug-wire";
20
21
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,OAAO,EAAE,mBAAmB,EAAE,KAAK,0BAA0B,EAAE,MAAM,0BAA0B,CAAC;AAChG,OAAO,EACL,gBAAgB,EAChB,UAAU,EACV,iBAAiB,EACjB,gBAAgB,EAChB,KAAK,SAAS,EACd,KAAK,uBAAuB,GAC7B,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,oBAAoB,EAAE,KAAK,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAE/E,OAAO,EACL,eAAe,EACf,iBAAiB,EACjB,mBAAmB,EACnB,KAAK,YAAY,EACjB,KAAK,YAAY,GAClB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,eAAe,EAAE,KAAK,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAC/E,OAAO,EAAE,cAAc,EAAE,KAAK,aAAa,EAAE,MAAM,+BAA+B,CAAC;AACnF,OAAO,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AACnG,OAAO,EAAE,mBAAmB,EAAE,KAAK,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAC3E,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,UAAU,EAAE,KAAK,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACpE,OAAO,EAAE,aAAa,EAAE,KAAK,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAC7E,OAAO,EAAE,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC3D,OAAO,EAAE,gBAAgB,EAAE,KAAK,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAC5E,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,OAAO,EAAE,mBAAmB,EAAE,KAAK,0BAA0B,EAAE,MAAM,0BAA0B,CAAC;AAChG,OAAO,EACL,gBAAgB,EAChB,UAAU,EACV,iBAAiB,EACjB,gBAAgB,EAChB,KAAK,SAAS,EACd,KAAK,uBAAuB,GAC7B,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,oBAAoB,EAAE,KAAK,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAE/E,OAAO,EACL,eAAe,EACf,iBAAiB,EACjB,mBAAmB,EACnB,KAAK,YAAY,EACjB,KAAK,YAAY,GAClB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,eAAe,EAAE,KAAK,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAC/E,OAAO,EAAE,cAAc,EAAE,KAAK,aAAa,EAAE,MAAM,+BAA+B,CAAC;AACnF,OAAO,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AACnG,OAAO,EAAE,mBAAmB,EAAE,KAAK,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAC3E,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,UAAU,EAAE,KAAK,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACpE,OAAO,EAAE,aAAa,EAAE,KAAK,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AAC7E,OAAO,EAAE,OAAO,EAAE,KAAK,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC3D,OAAO,EAAE,gBAAgB,EAAE,KAAK,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAC5E,OAAO,EACL,iBAAiB,EACjB,KAAK,wBAAwB,GAC9B,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC"}
package/dist/index.js CHANGED
@@ -16,4 +16,5 @@ export { probeRoute } from "./routes/probe.js";
16
16
  export { sessionsRoute } from "./routes/sessions.js";
17
17
  export { ioRoute } from "./routes/io.js";
18
18
  export { relayDebugStream } from "./debug/relay.js";
19
+ export { watchReachability, } from "./reachability.js";
19
20
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,OAAO,EAAE,mBAAmB,EAAmC,MAAM,0BAA0B,CAAC;AAChG,OAAO,EACL,gBAAgB,EAChB,UAAU,EACV,iBAAiB,EACjB,gBAAgB,GAGjB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,oBAAoB,EAAsB,MAAM,qBAAqB,CAAC;AAE/E,OAAO,EACL,eAAe,EACf,iBAAiB,EACjB,mBAAmB,GAGpB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,eAAe,EAAsB,MAAM,0BAA0B,CAAC;AAC/E,OAAO,EAAE,cAAc,EAAsB,MAAM,+BAA+B,CAAC;AACnF,OAAO,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AACnG,OAAO,EAAE,mBAAmB,EAAsB,MAAM,kBAAkB,CAAC;AAC3E,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,UAAU,EAAuB,MAAM,mBAAmB,CAAC;AACpE,OAAO,EAAE,aAAa,EAA0B,MAAM,sBAAsB,CAAC;AAC7E,OAAO,EAAE,OAAO,EAAoB,MAAM,gBAAgB,CAAC;AAC3D,OAAO,EAAE,gBAAgB,EAA0B,MAAM,kBAAkB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,OAAO,EAAE,mBAAmB,EAAmC,MAAM,0BAA0B,CAAC;AAChG,OAAO,EACL,gBAAgB,EAChB,UAAU,EACV,iBAAiB,EACjB,gBAAgB,GAGjB,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,oBAAoB,EAAsB,MAAM,qBAAqB,CAAC;AAE/E,OAAO,EACL,eAAe,EACf,iBAAiB,EACjB,mBAAmB,GAGpB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAAE,eAAe,EAAsB,MAAM,0BAA0B,CAAC;AAC/E,OAAO,EAAE,cAAc,EAAsB,MAAM,+BAA+B,CAAC;AACnF,OAAO,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AACnG,OAAO,EAAE,mBAAmB,EAAsB,MAAM,kBAAkB,CAAC;AAC3E,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,EAAE,UAAU,EAAuB,MAAM,mBAAmB,CAAC;AACpE,OAAO,EAAE,aAAa,EAA0B,MAAM,sBAAsB,CAAC;AAC7E,OAAO,EAAE,OAAO,EAAoB,MAAM,gBAAgB,CAAC;AAC3D,OAAO,EAAE,gBAAgB,EAA0B,MAAM,kBAAkB,CAAC;AAC5E,OAAO,EACL,iBAAiB,GAElB,MAAM,mBAAmB,CAAC"}
@@ -0,0 +1,37 @@
1
+ import type { ReachabilityState } from "./contract.js";
2
+ export interface WatchReachabilityOptions {
3
+ /** Address the runner dials — pod IP (k8s) or published host / container name (docker). */
4
+ host: string;
5
+ /** TCP ports the workload declared; each is watched and reported by port. */
6
+ ports: number[];
7
+ /** Receives every state transition for a port: `checking` on start, then
8
+ * `reachable` once it accepts a connection, or `unreachable` after the timeout. */
9
+ onState: (port: number, state: ReachabilityState) => void;
10
+ /** Aborts the watch — wire to the session's teardown. */
11
+ signal: AbortSignal;
12
+ /** How long a port may stay unreachable before it's reported `unreachable`.
13
+ * Default 30s. */
14
+ timeoutMs?: number;
15
+ /** Poll interval while waiting for a port to come up. Default 1s. */
16
+ intervalMs?: number;
17
+ /** Poll interval after a port was reported `unreachable`, to flip it back to
18
+ * `reachable` if it recovers. Default 5s. */
19
+ recheckIntervalMs?: number;
20
+ /** Per-attempt TCP connect timeout. Default 1s. */
21
+ connectTimeoutMs?: number;
22
+ }
23
+ /**
24
+ * Watches each declared TCP port for reachability from the runner network and
25
+ * reports per-port transitions via `onState`: `checking` immediately, then
26
+ * `reachable` the moment a connection succeeds, or `unreachable` after
27
+ * `timeoutMs` of refusal. After `unreachable` it keeps probing (slower) and
28
+ * flips back to `reachable` on recovery — so a slow-but-correct start
29
+ * self-corrects.
30
+ *
31
+ * This catches the loopback-bind / wrong-port / crash-loop failure that
32
+ * otherwise surfaces only as an opaque downstream 502; emitting state (not a log
33
+ * line) lets the editor render it on the endpoint badge. Backend-neutral: the
34
+ * runner supplies how its workload is dialed and where state goes.
35
+ */
36
+ export declare function watchReachability(options: WatchReachabilityOptions): Promise<void>;
37
+ //# sourceMappingURL=reachability.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reachability.d.ts","sourceRoot":"","sources":["../src/reachability.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAEvD,MAAM,WAAW,wBAAwB;IACvC,2FAA2F;IAC3F,IAAI,EAAE,MAAM,CAAC;IACb,6EAA6E;IAC7E,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB;wFACoF;IACpF,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,iBAAiB,KAAK,IAAI,CAAC;IAC1D,yDAAyD;IACzD,MAAM,EAAE,WAAW,CAAC;IACpB;uBACmB;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,qEAAqE;IACrE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;kDAC8C;IAC9C,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,mDAAmD;IACnD,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAuDD;;;;;;;;;;;;GAYG;AACH,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,wBAAwB,GAAG,OAAO,CAAC,IAAI,CAAC,CAYxF"}
@@ -0,0 +1,71 @@
1
+ import net from "node:net";
2
+ import { abortableDelay } from "./abortable-delay.js";
3
+ const DEFAULT_TIMEOUT_MS = 30_000;
4
+ const DEFAULT_INTERVAL_MS = 1_000;
5
+ const DEFAULT_RECHECK_INTERVAL_MS = 5_000;
6
+ const DEFAULT_CONNECT_TIMEOUT_MS = 1_000;
7
+ /** One TCP connect attempt. Resolves true on a completed connection, false on
8
+ * refusal / timeout / error. Never throws; `unref`'d so a pending attempt can't
9
+ * keep the event loop alive, and always torn down. */
10
+ function tryConnect(host, port, timeoutMs) {
11
+ return new Promise((resolve) => {
12
+ const socket = net.connect({ host, port });
13
+ socket.unref();
14
+ let settled = false;
15
+ const done = (ok) => {
16
+ if (settled)
17
+ return;
18
+ settled = true;
19
+ socket.destroy();
20
+ resolve(ok);
21
+ };
22
+ socket.setTimeout(timeoutMs);
23
+ socket.once("connect", () => done(true));
24
+ socket.once("timeout", () => done(false));
25
+ socket.once("error", () => done(false));
26
+ });
27
+ }
28
+ async function watchPort(port, cfg) {
29
+ cfg.onState(port, "checking");
30
+ const start = Date.now();
31
+ let reportedUnreachable = false;
32
+ while (!cfg.signal.aborted) {
33
+ if (await tryConnect(cfg.host, port, cfg.connectTimeoutMs)) {
34
+ cfg.onState(port, "reachable");
35
+ return;
36
+ }
37
+ if (!reportedUnreachable && Date.now() - start >= cfg.timeoutMs) {
38
+ reportedUnreachable = true;
39
+ cfg.onState(port, "unreachable");
40
+ }
41
+ await abortableDelay(reportedUnreachable ? cfg.recheckIntervalMs : cfg.intervalMs, cfg.signal);
42
+ }
43
+ }
44
+ /**
45
+ * Watches each declared TCP port for reachability from the runner network and
46
+ * reports per-port transitions via `onState`: `checking` immediately, then
47
+ * `reachable` the moment a connection succeeds, or `unreachable` after
48
+ * `timeoutMs` of refusal. After `unreachable` it keeps probing (slower) and
49
+ * flips back to `reachable` on recovery — so a slow-but-correct start
50
+ * self-corrects.
51
+ *
52
+ * This catches the loopback-bind / wrong-port / crash-loop failure that
53
+ * otherwise surfaces only as an opaque downstream 502; emitting state (not a log
54
+ * line) lets the editor render it on the endpoint badge. Backend-neutral: the
55
+ * runner supplies how its workload is dialed and where state goes.
56
+ */
57
+ export async function watchReachability(options) {
58
+ if (options.ports.length === 0)
59
+ return;
60
+ const cfg = {
61
+ host: options.host,
62
+ onState: options.onState,
63
+ signal: options.signal,
64
+ timeoutMs: options.timeoutMs ?? DEFAULT_TIMEOUT_MS,
65
+ intervalMs: options.intervalMs ?? DEFAULT_INTERVAL_MS,
66
+ recheckIntervalMs: options.recheckIntervalMs ?? DEFAULT_RECHECK_INTERVAL_MS,
67
+ connectTimeoutMs: options.connectTimeoutMs ?? DEFAULT_CONNECT_TIMEOUT_MS,
68
+ };
69
+ await Promise.all(options.ports.map((port) => watchPort(port, cfg)));
70
+ }
71
+ //# sourceMappingURL=reachability.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reachability.js","sourceRoot":"","sources":["../src/reachability.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,7 @@
1
1
  import type { FastifyPluginAsync } from "fastify";
2
2
  import type { RunnerBackend } from "../backend.js";
3
3
  import { type RunnerTerms, type SessionConfig } from "../contract.js";
4
+ import type { ResolvedRunnerApp } from "../config.js";
4
5
  import { type SessionRegistry } from "../session/registry.js";
5
6
  export interface SessionsRouteDeps {
6
7
  backend: RunnerBackend;
@@ -12,6 +13,10 @@ export interface SessionsRouteDeps {
12
13
  /** When set, a session may only start if the client acknowledges this exact
13
14
  * terms version via the `x-telo-accepted-terms` header. */
14
15
  terms?: RunnerTerms;
16
+ /** Operator-predefined applications launchable by name
17
+ * (`StartSessionRequest.app`), with their operator env already resolved.
18
+ * The catalog is the whole gate — an unknown name is rejected. */
19
+ apps?: Record<string, ResolvedRunnerApp>;
15
20
  /** Backend-supplied config gate. Returns an error message to reject the
16
21
  * request with `400 invalid_config`, or `undefined` to accept. The runner is
17
22
  * the source of truth, so this re-checks what `/v1/capabilities` advertises
@@ -1 +1 @@
1
- {"version":3,"file":"sessions.d.ts","sourceRoot":"","sources":["../../src/routes/sessions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAmB,kBAAkB,EAAgB,MAAM,SAAS,CAAC;AAGjF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,EAGL,KAAK,WAAW,EAChB,KAAK,aAAa,EAEnB,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EAAqB,KAAK,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAGjF,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,aAAa,CAAC;IACvB,QAAQ,EAAE,eAAe,CAAC;IAC1B,WAAW,EAAE,MAAM,EAAE,GAAG,GAAG,CAAC;IAC5B;kEAC8D;IAC9D,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B;gEAC4D;IAC5D,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB;;;gFAG4E;IAC5E,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,aAAa,KAAK,MAAM,GAAG,SAAS,CAAC;CAChE;AAoDD,wBAAgB,aAAa,CAAC,IAAI,EAAE,iBAAiB,GAAG,kBAAkB,CAkEzE"}
1
+ {"version":3,"file":"sessions.d.ts","sourceRoot":"","sources":["../../src/routes/sessions.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAmB,kBAAkB,EAAgB,MAAM,SAAS,CAAC;AAGjF,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AACnD,OAAO,EAIL,KAAK,WAAW,EAChB,KAAK,aAAa,EAEnB,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAGtD,OAAO,EAAqB,KAAK,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAGjF,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,aAAa,CAAC;IACvB,QAAQ,EAAE,eAAe,CAAC;IAC1B,WAAW,EAAE,MAAM,EAAE,GAAG,GAAG,CAAC;IAC5B;kEAC8D;IAC9D,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B;gEAC4D;IAC5D,KAAK,CAAC,EAAE,WAAW,CAAC;IACpB;;uEAEmE;IACnE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC;IACzC;;;gFAG4E;IAC5E,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,aAAa,KAAK,MAAM,GAAG,SAAS,CAAC;CAChE;AAuDD,wBAAgB,aAAa,CAAC,IAAI,EAAE,iBAAiB,GAAG,kBAAkB,CAkEzE"}