@telorun/runner-core 0.5.2

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 (109) hide show
  1. package/LICENSE +17 -0
  2. package/README.md +38 -0
  3. package/dist/backend.d.ts +71 -0
  4. package/dist/backend.d.ts.map +1 -0
  5. package/dist/backend.js +2 -0
  6. package/dist/backend.js.map +1 -0
  7. package/dist/base-image-catalog.d.ts +110 -0
  8. package/dist/base-image-catalog.d.ts.map +1 -0
  9. package/dist/base-image-catalog.js +245 -0
  10. package/dist/base-image-catalog.js.map +1 -0
  11. package/dist/capabilities-schema.d.ts +33 -0
  12. package/dist/capabilities-schema.d.ts.map +1 -0
  13. package/dist/capabilities-schema.js +44 -0
  14. package/dist/capabilities-schema.js.map +1 -0
  15. package/dist/config.d.ts +37 -0
  16. package/dist/config.d.ts.map +1 -0
  17. package/dist/config.js +93 -0
  18. package/dist/config.js.map +1 -0
  19. package/dist/contract.d.ts +170 -0
  20. package/dist/contract.d.ts.map +1 -0
  21. package/dist/contract.js +24 -0
  22. package/dist/contract.js.map +1 -0
  23. package/dist/debug/relay.d.ts +25 -0
  24. package/dist/debug/relay.d.ts.map +1 -0
  25. package/dist/debug/relay.js +89 -0
  26. package/dist/debug/relay.js.map +1 -0
  27. package/dist/dependency-key.d.ts +38 -0
  28. package/dist/dependency-key.d.ts.map +1 -0
  29. package/dist/dependency-key.js +68 -0
  30. package/dist/dependency-key.js.map +1 -0
  31. package/dist/index.d.ts +20 -0
  32. package/dist/index.d.ts.map +1 -0
  33. package/dist/index.js +19 -0
  34. package/dist/index.js.map +1 -0
  35. package/dist/routes/capabilities.d.ts +12 -0
  36. package/dist/routes/capabilities.d.ts.map +1 -0
  37. package/dist/routes/capabilities.js +15 -0
  38. package/dist/routes/capabilities.js.map +1 -0
  39. package/dist/routes/health.d.ts +5 -0
  40. package/dist/routes/health.d.ts.map +1 -0
  41. package/dist/routes/health.js +8 -0
  42. package/dist/routes/health.js.map +1 -0
  43. package/dist/routes/io.d.ts +8 -0
  44. package/dist/routes/io.d.ts.map +1 -0
  45. package/dist/routes/io.js +239 -0
  46. package/dist/routes/io.js.map +1 -0
  47. package/dist/routes/probe.d.ts +7 -0
  48. package/dist/routes/probe.d.ts.map +1 -0
  49. package/dist/routes/probe.js +22 -0
  50. package/dist/routes/probe.js.map +1 -0
  51. package/dist/routes/sessions.d.ts +22 -0
  52. package/dist/routes/sessions.d.ts.map +1 -0
  53. package/dist/routes/sessions.js +223 -0
  54. package/dist/routes/sessions.js.map +1 -0
  55. package/dist/server.d.ts +34 -0
  56. package/dist/server.d.ts.map +1 -0
  57. package/dist/server.js +67 -0
  58. package/dist/server.js.map +1 -0
  59. package/dist/session/bundle-path.d.ts +12 -0
  60. package/dist/session/bundle-path.d.ts.map +1 -0
  61. package/dist/session/bundle-path.js +27 -0
  62. package/dist/session/bundle-path.js.map +1 -0
  63. package/dist/session/byte-ring-buffer.d.ts +29 -0
  64. package/dist/session/byte-ring-buffer.d.ts.map +1 -0
  65. package/dist/session/byte-ring-buffer.js +54 -0
  66. package/dist/session/byte-ring-buffer.js.map +1 -0
  67. package/dist/session/registry.d.ts +62 -0
  68. package/dist/session/registry.d.ts.map +1 -0
  69. package/dist/session/registry.js +156 -0
  70. package/dist/session/registry.js.map +1 -0
  71. package/dist/session/ring-buffer.d.ts +37 -0
  72. package/dist/session/ring-buffer.d.ts.map +1 -0
  73. package/dist/session/ring-buffer.js +64 -0
  74. package/dist/session/ring-buffer.js.map +1 -0
  75. package/dist/session/session-id.d.ts +3 -0
  76. package/dist/session/session-id.d.ts.map +1 -0
  77. package/dist/session/session-id.js +19 -0
  78. package/dist/session/session-id.js.map +1 -0
  79. package/dist/sse/channel.d.ts +11 -0
  80. package/dist/sse/channel.d.ts.map +1 -0
  81. package/dist/sse/channel.js +129 -0
  82. package/dist/sse/channel.js.map +1 -0
  83. package/package.json +48 -0
  84. package/src/backend.ts +88 -0
  85. package/src/base-image-catalog.test.ts +209 -0
  86. package/src/base-image-catalog.ts +320 -0
  87. package/src/capabilities-schema.test.ts +54 -0
  88. package/src/capabilities-schema.ts +71 -0
  89. package/src/config.ts +122 -0
  90. package/src/contract.ts +170 -0
  91. package/src/debug/relay.ts +104 -0
  92. package/src/dependency-key.test.ts +64 -0
  93. package/src/dependency-key.ts +105 -0
  94. package/src/index.ts +33 -0
  95. package/src/routes/capabilities.ts +20 -0
  96. package/src/routes/health.ts +9 -0
  97. package/src/routes/io.ts +265 -0
  98. package/src/routes/probe.ts +35 -0
  99. package/src/routes/sessions.ts +270 -0
  100. package/src/server.ts +108 -0
  101. package/src/session/bundle-path.ts +27 -0
  102. package/src/session/byte-ring-buffer.ts +62 -0
  103. package/src/session/registry.test.ts +34 -0
  104. package/src/session/registry.ts +185 -0
  105. package/src/session/ring-buffer.test.ts +54 -0
  106. package/src/session/ring-buffer.ts +75 -0
  107. package/src/session/session-id.test.ts +17 -0
  108. package/src/session/session-id.ts +20 -0
  109. package/src/sse/channel.ts +154 -0
package/dist/config.js ADDED
@@ -0,0 +1,93 @@
1
+ import { createHash } from "node:crypto";
2
+ import { readFileSync } from "node:fs";
3
+ export class RunnerConfigError extends Error {
4
+ }
5
+ export function parsePositiveInt(raw, fallback, field) {
6
+ if (raw === undefined || raw.trim() === "")
7
+ return fallback;
8
+ const n = Number(raw);
9
+ if (!Number.isInteger(n) || n <= 0) {
10
+ throw new RunnerConfigError(`${field} must be a positive integer, got '${raw}'.`);
11
+ }
12
+ return n;
13
+ }
14
+ export function parseBool(raw, fallback, field) {
15
+ const v = raw?.trim().toLowerCase();
16
+ if (v === undefined || v === "")
17
+ return fallback;
18
+ if (v === "true" || v === "1" || v === "yes")
19
+ return true;
20
+ if (v === "false" || v === "0" || v === "no")
21
+ return false;
22
+ throw new RunnerConfigError(`${field} must be a boolean (true/false), got '${raw}'.`);
23
+ }
24
+ export function parsePort(raw, fallback) {
25
+ const portStr = raw ?? String(fallback);
26
+ const port = Number(portStr);
27
+ if (!Number.isInteger(port) || port <= 0 || port > 65535) {
28
+ throw new RunnerConfigError(`PORT must be an integer in 1..65535, got '${portStr}'.`);
29
+ }
30
+ return port;
31
+ }
32
+ /**
33
+ * Build the runner's usage terms from the environment. Terms are opt-in: returns
34
+ * `undefined` (no gate) unless a non-empty body is provided.
35
+ *
36
+ * The body comes from `RUNNER_TERMS_FILE` (a path read at startup — the natural
37
+ * fit for a k8s ConfigMap mount or a bind-mounted file) or, for short notes,
38
+ * inline `RUNNER_TERMS_BODY`. `RUNNER_TERMS_VERSION` is optional and defaults to
39
+ * a short hash of the body, so editing the agreement automatically re-prompts
40
+ * every client; set it explicitly only to control "material change vs. typo".
41
+ * A configured-but-unreadable `RUNNER_TERMS_FILE` is a hard error rather than a
42
+ * silent "no terms", so a misconfiguration can't quietly drop the gate.
43
+ */
44
+ export function loadTermsFromEnv(env) {
45
+ const body = resolveTermsBody(env);
46
+ if (!body || body.trim() === "")
47
+ return undefined;
48
+ return {
49
+ version: env.RUNNER_TERMS_VERSION?.trim() || hashTermsVersion(body),
50
+ title: env.RUNNER_TERMS_TITLE?.trim() || "Usage agreement",
51
+ body,
52
+ };
53
+ }
54
+ function resolveTermsBody(env) {
55
+ const file = env.RUNNER_TERMS_FILE?.trim();
56
+ if (file) {
57
+ try {
58
+ return readFileSync(file, "utf8");
59
+ }
60
+ catch (err) {
61
+ throw new RunnerConfigError(`RUNNER_TERMS_FILE could not be read at '${file}': ${err.message}`);
62
+ }
63
+ }
64
+ return env.RUNNER_TERMS_BODY;
65
+ }
66
+ /** Short content fingerprint used as the terms version when none is set. Any
67
+ * edit to the body changes it, which re-prompts every client. */
68
+ function hashTermsVersion(body) {
69
+ return createHash("sha256").update(body).digest("hex").slice(0, 12);
70
+ }
71
+ export function parseCorsOrigins(raw) {
72
+ if (raw === undefined || raw.trim() === "" || raw.trim() === "*")
73
+ return "*";
74
+ return raw
75
+ .split(",")
76
+ .map((s) => s.trim())
77
+ .filter((s) => s.length > 0);
78
+ }
79
+ export function loadCoreConfig(env, defaults = {}) {
80
+ return {
81
+ port: parsePort(env.PORT, defaults.port ?? 8061),
82
+ logLevel: env.LOG_LEVEL?.trim() || "info",
83
+ maxSessions: parsePositiveInt(env.RUNNER_MAX_SESSIONS, 32, "RUNNER_MAX_SESSIONS"),
84
+ // Exited sessions linger so the editor can re-attach and replay their console
85
+ // + inspection history after a page reload. The registry evicts the oldest
86
+ // *terminal* session early when at capacity, so a long TTL never blocks a new
87
+ // run while live sessions are protected.
88
+ exitTtlMs: parsePositiveInt(env.RUNNER_EXIT_TTL_MS, 4 * 60 * 60 * 1000, "RUNNER_EXIT_TTL_MS"),
89
+ replayBufferBytes: parsePositiveInt(env.RUNNER_REPLAY_BUFFER_BYTES, 5_000_000, "RUNNER_REPLAY_BUFFER_BYTES"),
90
+ corsOrigins: parseCorsOrigins(env.RUNNER_CORS_ORIGINS),
91
+ };
92
+ }
93
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,170 @@
1
+ /**
2
+ * The backend-neutral `/v1` session contract. Every field here is shared by
3
+ * the docker and kubernetes backends and travels over the HTTP+SSE wire to the
4
+ * editor adapter. Backend-specific concerns (how a container/pod is spawned,
5
+ * how the bundle is delivered) live behind the `RunnerBackend` interface.
6
+ */
7
+ import type { DebugFrame } from "@telorun/debug-wire";
8
+ export type PullPolicy = "missing" | "always" | "never";
9
+ /**
10
+ * What a runner advertises about itself on `GET /v1/capabilities`. The editor
11
+ * fetches this to render a generic runner config form — instead of hardcoding
12
+ * per-backend fields — so the runner is the authority on its own config surface.
13
+ * `config.schema` is a JSON Schema describing the editable `SessionConfig` fields
14
+ * (each property carries its own `default`); server-enforced fields are marked
15
+ * `readOnly` with the enforced value as their `default`. `baseUrl` is never in
16
+ * this schema — the client owns it (you need it to reach the runner).
17
+ */
18
+ export interface RunnerCapabilities {
19
+ displayName: string;
20
+ description: string;
21
+ config: {
22
+ schema: JsonSchema;
23
+ };
24
+ features: RunnerFeatures;
25
+ /** A usage agreement the operator requires before a session may start.
26
+ * Omitted (or undefined) when this runner has no terms — e.g. a local
27
+ * development runner. The runner ENFORCES it: `POST /v1/sessions` is rejected
28
+ * with `428 terms_required` unless the client sends `x-telo-accepted-terms`
29
+ * matching `terms.version`. The editor surfaces it and records acceptance. */
30
+ terms?: RunnerTerms;
31
+ }
32
+ /** An operator-defined agreement. `version` is opaque and operator-controlled;
33
+ * bumping it re-prompts every client. `body` is plain text / markdown. */
34
+ export interface RunnerTerms {
35
+ version: string;
36
+ title: string;
37
+ body: string;
38
+ }
39
+ /** HTTP header carrying the accepted terms version on `POST /v1/sessions`. */
40
+ export declare const ACCEPTED_TERMS_HEADER = "x-telo-accepted-terms";
41
+ export interface RunnerFeatures {
42
+ /** Runner exposes a live PTY byte channel (`/v1/sessions/:id/io`). */
43
+ io: boolean;
44
+ /** Runner can publish workload ports back to the client. */
45
+ ports: boolean;
46
+ }
47
+ /** A JSON Schema document, kept structurally open so runner-core need not depend
48
+ * on a JSON-Schema type package. The editor treats it as `JSONSchema7`. */
49
+ export type JsonSchema = Record<string, unknown>;
50
+ export interface ProbeConfig {
51
+ image: string;
52
+ pullPolicy: PullPolicy;
53
+ }
54
+ export interface SessionConfig {
55
+ image: string;
56
+ pullPolicy: PullPolicy;
57
+ registryUrl?: string;
58
+ }
59
+ export interface ConfigIssue {
60
+ path: string;
61
+ message: string;
62
+ }
63
+ export type AvailabilityReport = {
64
+ status: "ready";
65
+ } | {
66
+ status: "needs-setup";
67
+ issues: ConfigIssue[];
68
+ } | {
69
+ status: "unavailable";
70
+ message: string;
71
+ remediation?: string;
72
+ };
73
+ export interface RunBundle {
74
+ entryRelativePath: string;
75
+ files: Array<{
76
+ relativePath: string;
77
+ contents: string;
78
+ }>;
79
+ }
80
+ export type PortProtocol = "tcp" | "udp";
81
+ export interface PortMapping {
82
+ port: number;
83
+ protocol: PortProtocol;
84
+ }
85
+ /**
86
+ * Announced on `RunStatus.running`. `host`/`port` describe a directly-dialable
87
+ * endpoint (docker host-port publish); `url` carries a fully-qualified address
88
+ * for backends that front the workload with a proxy/ingress (k8s per-session
89
+ * ingress), where a bare host:port is not reachable. The client adapter fills an
90
+ * empty `host` from its own baseUrl — the runner does not know the hostname the
91
+ * client used to reach it.
92
+ */
93
+ export interface RunnerEndpoint {
94
+ host: string;
95
+ port: number;
96
+ protocol: PortProtocol;
97
+ /** Fully-qualified URL when the endpoint is fronted by a proxy/ingress. */
98
+ url?: string;
99
+ }
100
+ export interface StartSessionRequest {
101
+ bundle: RunBundle;
102
+ env: Record<string, string>;
103
+ ports?: PortMapping[];
104
+ config: SessionConfig;
105
+ /** Request the kernel debug stream. When true the runner launches the
106
+ * workload with `--inspect`, subscribes to the in-workload inspect endpoint
107
+ * (reachable only by the runner — never published outward), and relays each
108
+ * frame to the client as a `debug` {@link RunEvent}. */
109
+ inspect?: boolean;
110
+ }
111
+ export type RunStatus = {
112
+ kind: "starting";
113
+ }
114
+ /** `inspectUrl` is the kernel debug/inspection UI fronted by a proxy (set only
115
+ * when the session ran with `inspect` and the runner has a public base URL);
116
+ * absent when the inspect endpoint isn't externally reachable. */
117
+ | {
118
+ kind: "running";
119
+ endpoints?: RunnerEndpoint[];
120
+ inspectUrl?: string;
121
+ } | {
122
+ kind: "exited";
123
+ code: number;
124
+ } | {
125
+ kind: "failed";
126
+ message: string;
127
+ } | {
128
+ kind: "stopped";
129
+ };
130
+ /**
131
+ * Coarse phase a session passes through while coming up, carried on `progress`
132
+ * events. Additive to the status enum: `RunStatus` stays `starting` until the
133
+ * workload is actually up; these messages drive the editor's spinner + step feed.
134
+ */
135
+ export type RunPhase = "build" | "provision" | "boot";
136
+ export type RunEvent = {
137
+ type: "stdout";
138
+ chunk: string;
139
+ } | {
140
+ type: "stderr";
141
+ chunk: string;
142
+ } | {
143
+ type: "status";
144
+ status: RunStatus;
145
+ } | {
146
+ type: "progress";
147
+ phase: RunPhase;
148
+ message: string;
149
+ done?: boolean;
150
+ }
151
+ /** A frame relayed from the workload's kernel debug stream (kernel event or
152
+ * log line). Only emitted when the session was started with `inspect`. */
153
+ | {
154
+ type: "debug";
155
+ frame: DebugFrame;
156
+ };
157
+ export declare function isTerminal(status: RunStatus): boolean;
158
+ /**
159
+ * Stages a session start can fail at. The docker/k8s backends share the
160
+ * vocabulary; not every stage applies to every backend (`pull`/`inspect` are
161
+ * image-availability stages, `create`/`attach`/`start` are workload stages).
162
+ */
163
+ export type StartFailureStage = "pull" | "inspect" | "daemon" | "create" | "attach" | "start";
164
+ export declare class SessionStartError extends Error {
165
+ readonly kind: "pull_failed" | "start_failed";
166
+ readonly stage: StartFailureStage;
167
+ readonly daemonMessage?: string | undefined;
168
+ constructor(kind: "pull_failed" | "start_failed", stage: StartFailureStage, message: string, daemonMessage?: string | undefined);
169
+ }
170
+ //# sourceMappingURL=contract.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../src/contract.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * The backend-neutral `/v1` session contract. Every field here is shared by
3
+ * the docker and kubernetes backends and travels over the HTTP+SSE wire to the
4
+ * editor adapter. Backend-specific concerns (how a container/pod is spawned,
5
+ * how the bundle is delivered) live behind the `RunnerBackend` interface.
6
+ */
7
+ /** HTTP header carrying the accepted terms version on `POST /v1/sessions`. */
8
+ export const ACCEPTED_TERMS_HEADER = "x-telo-accepted-terms";
9
+ export function isTerminal(status) {
10
+ return status.kind === "exited" || status.kind === "failed" || status.kind === "stopped";
11
+ }
12
+ export class SessionStartError extends Error {
13
+ kind;
14
+ stage;
15
+ daemonMessage;
16
+ constructor(kind, stage, message, daemonMessage) {
17
+ super(message);
18
+ this.kind = kind;
19
+ this.stage = stage;
20
+ this.daemonMessage = daemonMessage;
21
+ this.name = "SessionStartError";
22
+ }
23
+ }
24
+ //# sourceMappingURL=contract.js.map
@@ -0,0 +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"}
@@ -0,0 +1,25 @@
1
+ import type { DebugFrame } from "@telorun/debug-wire";
2
+ export interface DebugRelayOptions {
3
+ /** The workload's inspect SSE endpoint, e.g. `http://telo-run-<id>:9230/events`.
4
+ * Reachable only by the runner over the backend's private network. */
5
+ url: string;
6
+ /** Delivered each parsed frame off the stream. */
7
+ onFrame: (frame: DebugFrame) => void;
8
+ /** Aborts the relay (session ended). */
9
+ signal: AbortSignal;
10
+ /** Optional connect-retry budget. The workload's inspect server isn't up the
11
+ * instant the container starts; we retry until it answers or `signal` aborts.
12
+ * Default: retry indefinitely (until abort). */
13
+ onError?: (err: Error) => void;
14
+ }
15
+ /**
16
+ * Subscribe to a workload's inspect SSE endpoint and deliver each frame to
17
+ * `onFrame`. Retries the connection until the endpoint answers or `signal`
18
+ * aborts, and reconnects if the stream drops while the session is still live.
19
+ * The runner relays these frames onward; the workload's inspect port is never
20
+ * exposed outside the runner.
21
+ *
22
+ * Backend-neutral (uses global `fetch`); the docker and k8s backends share it.
23
+ */
24
+ export declare function relayDebugStream(opts: DebugRelayOptions): Promise<void>;
25
+ //# sourceMappingURL=relay.d.ts.map
@@ -0,0 +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"}
@@ -0,0 +1,89 @@
1
+ const RECONNECT_DELAY_MS = 500;
2
+ /**
3
+ * Subscribe to a workload's inspect SSE endpoint and deliver each frame to
4
+ * `onFrame`. Retries the connection until the endpoint answers or `signal`
5
+ * aborts, and reconnects if the stream drops while the session is still live.
6
+ * The runner relays these frames onward; the workload's inspect port is never
7
+ * exposed outside the runner.
8
+ *
9
+ * Backend-neutral (uses global `fetch`); the docker and k8s backends share it.
10
+ */
11
+ export async function relayDebugStream(opts) {
12
+ const { url, onFrame, signal } = opts;
13
+ while (!signal.aborted) {
14
+ try {
15
+ const res = await fetch(url, {
16
+ signal,
17
+ headers: { accept: "text/event-stream" },
18
+ });
19
+ if (!res.ok || !res.body) {
20
+ await delay(RECONNECT_DELAY_MS, signal);
21
+ continue;
22
+ }
23
+ await pump(res.body, onFrame, signal);
24
+ }
25
+ catch (err) {
26
+ if (signal.aborted)
27
+ return;
28
+ opts.onError?.(err instanceof Error ? err : new Error(String(err)));
29
+ }
30
+ await delay(RECONNECT_DELAY_MS, signal);
31
+ }
32
+ }
33
+ async function pump(body, onFrame, signal) {
34
+ const reader = body.getReader();
35
+ const decoder = new TextDecoder();
36
+ let buf = "";
37
+ try {
38
+ while (!signal.aborted) {
39
+ const { value, done } = await reader.read();
40
+ if (done)
41
+ return;
42
+ buf += decoder.decode(value, { stream: true });
43
+ let sep;
44
+ // SSE frames are separated by a blank line.
45
+ while ((sep = buf.indexOf("\n\n")) >= 0) {
46
+ const frame = parseSseData(buf.slice(0, sep));
47
+ buf = buf.slice(sep + 2);
48
+ if (frame)
49
+ onFrame(frame);
50
+ }
51
+ }
52
+ }
53
+ finally {
54
+ reader.cancel().catch(() => undefined);
55
+ }
56
+ }
57
+ /** Extract and parse the `data:` payload of one SSE frame. Ignores comment
58
+ * lines (`: heartbeat`) and unparseable frames. */
59
+ function parseSseData(block) {
60
+ const data = block
61
+ .split("\n")
62
+ .filter((line) => line.startsWith("data:"))
63
+ .map((line) => line.slice(5).trimStart())
64
+ .join("\n");
65
+ if (!data)
66
+ return null;
67
+ try {
68
+ return JSON.parse(data);
69
+ }
70
+ catch {
71
+ return null;
72
+ }
73
+ }
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
+ //# sourceMappingURL=relay.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"relay.js","sourceRoot":"","sources":["../../src/debug/relay.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,38 @@
1
+ import type { RunBundle } from "./contract.js";
2
+ /**
3
+ * The inputs that determine a session's baked dependency layer — everything
4
+ * `telo install` would resolve into `.telo/{manifests,npm}`, and nothing about
5
+ * resource bodies or CEL. A backend that prebuilds a per-app image keys the
6
+ * image tag on this so a body-only edit reuses the image while an import or
7
+ * controller change rebuilds it.
8
+ *
9
+ * Derived by a SHALLOW static parse of the in-memory bundle — no graph load, no
10
+ * network, no archive. Exact import versions pin the transitive closure, so the
11
+ * authored `imports:` + body-declared controllers are sufficient.
12
+ *
13
+ * Assumes every file in the bundle is reachable from the entry (true for
14
+ * editor / control-plane-produced bundles, which carry exactly the app's
15
+ * files). It scans ALL `Telo.Definition` docs rather than following the entry's
16
+ * include/import graph — cheaper, and erring toward over-inclusion only ever
17
+ * busts the cache more eagerly. The one unsound case is a bundle carrying an
18
+ * orphan controller-bearing Definition that `telo install` would NOT bake (not
19
+ * reachable from this entry) yet another entry with the same closure WOULD: they
20
+ * could share a tag whose image lacks that controller. Not reachable via the
21
+ * editor; revisit (anchor to the include graph) if bundles ever carry unreachable
22
+ * Definition files.
23
+ */
24
+ export interface DependencyKey {
25
+ /** Sorted `imports:` source strings from every module doc. */
26
+ importSources: string[];
27
+ /** Sorted controller PURLs declared by inline `Telo.Definition` docs. */
28
+ controllerLocators: string[];
29
+ /**
30
+ * True when a `Telo.Definition` resolves its controller from bundle-local
31
+ * source (`local_path`), or a file failed to parse. In either case the dep
32
+ * key alone can't capture a controller change, so the caller MUST also fold
33
+ * the full bundle contents into the tag (safe fallback to content-keying).
34
+ */
35
+ fullContentFallback: boolean;
36
+ }
37
+ export declare function extractDependencyKey(bundle: RunBundle): DependencyKey;
38
+ //# sourceMappingURL=dependency-key.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dependency-key.d.ts","sourceRoot":"","sources":["../src/dependency-key.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAE/C;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,WAAW,aAAa;IAC5B,8DAA8D;IAC9D,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,yEAAyE;IACzE,kBAAkB,EAAE,MAAM,EAAE,CAAC;IAC7B;;;;;OAKG;IACH,mBAAmB,EAAE,OAAO,CAAC;CAC9B;AAgBD,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,SAAS,GAAG,aAAa,CAkDrE"}
@@ -0,0 +1,68 @@
1
+ import { parseAllDocuments } from "yaml";
2
+ function asModuleKind(kind) {
3
+ return kind === "Telo.Application" || kind === "Telo.Library";
4
+ }
5
+ /** Pull `{ source }` out of an `imports:` map value (bare string or object). */
6
+ function importSourceOf(value) {
7
+ if (typeof value === "string")
8
+ return value;
9
+ if (value && typeof value === "object") {
10
+ const source = value.source;
11
+ if (typeof source === "string")
12
+ return source;
13
+ }
14
+ return undefined;
15
+ }
16
+ export function extractDependencyKey(bundle) {
17
+ const importSources = new Set();
18
+ const controllerLocators = new Set();
19
+ let fullContentFallback = false;
20
+ for (const file of bundle.files) {
21
+ let docs;
22
+ try {
23
+ docs = parseAllDocuments(file.contents);
24
+ }
25
+ catch {
26
+ // Unparseable file — we can't know what it declares, so fall back to
27
+ // hashing the whole bundle rather than risk an under-specified key.
28
+ fullContentFallback = true;
29
+ continue;
30
+ }
31
+ for (const doc of docs) {
32
+ if (doc.errors.length > 0) {
33
+ fullContentFallback = true;
34
+ continue;
35
+ }
36
+ const value = doc.toJS();
37
+ if (!value || typeof value !== "object")
38
+ continue;
39
+ const kind = value.kind;
40
+ if (asModuleKind(kind) && value.imports && typeof value.imports === "object") {
41
+ for (const entry of Object.values(value.imports)) {
42
+ const source = importSourceOf(entry);
43
+ if (source)
44
+ importSources.add(source);
45
+ }
46
+ }
47
+ if (kind === "Telo.Definition") {
48
+ const controllers = value.controllers;
49
+ if (Array.isArray(controllers)) {
50
+ for (const c of controllers) {
51
+ if (typeof c === "string")
52
+ controllerLocators.add(c);
53
+ }
54
+ }
55
+ // A bundle-local controller's source lives in the body; the PURL/path
56
+ // can't capture an edit to it, so force full-content keying.
57
+ if (typeof value.local_path === "string")
58
+ fullContentFallback = true;
59
+ }
60
+ }
61
+ }
62
+ return {
63
+ importSources: [...importSources].sort(),
64
+ controllerLocators: [...controllerLocators].sort(),
65
+ fullContentFallback,
66
+ };
67
+ }
68
+ //# sourceMappingURL=dependency-key.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dependency-key.js","sourceRoot":"","sources":["../src/dependency-key.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAC;AAwCzC,SAAS,YAAY,CAAC,IAAa;IACjC,OAAO,IAAI,KAAK,kBAAkB,IAAI,IAAI,KAAK,cAAc,CAAC;AAChE,CAAC;AAED,gFAAgF;AAChF,SAAS,cAAc,CAAC,KAAc;IACpC,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAC5C,IAAI,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QACvC,MAAM,MAAM,GAAI,KAA8B,CAAC,MAAM,CAAC;QACtD,IAAI,OAAO,MAAM,KAAK,QAAQ;YAAE,OAAO,MAAM,CAAC;IAChD,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,MAAiB;IACpD,MAAM,aAAa,GAAG,IAAI,GAAG,EAAU,CAAC;IACxC,MAAM,kBAAkB,GAAG,IAAI,GAAG,EAAU,CAAC;IAC7C,IAAI,mBAAmB,GAAG,KAAK,CAAC;IAEhC,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;QAChC,IAAI,IAAI,CAAC;QACT,IAAI,CAAC;YACH,IAAI,GAAG,iBAAiB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC1C,CAAC;QAAC,MAAM,CAAC;YACP,qEAAqE;YACrE,oEAAoE;YACpE,mBAAmB,GAAG,IAAI,CAAC;YAC3B,SAAS;QACX,CAAC;QACD,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACvB,IAAI,GAAG,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC1B,mBAAmB,GAAG,IAAI,CAAC;gBAC3B,SAAS;YACX,CAAC;YACD,MAAM,KAAK,GAAG,GAAG,CAAC,IAAI,EAAoC,CAAC;YAC3D,IAAI,CAAC,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ;gBAAE,SAAS;YAClD,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC;YAExB,IAAI,YAAY,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,OAAO,IAAI,OAAO,KAAK,CAAC,OAAO,KAAK,QAAQ,EAAE,CAAC;gBAC7E,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,OAAkC,CAAC,EAAE,CAAC;oBAC5E,MAAM,MAAM,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC;oBACrC,IAAI,MAAM;wBAAE,aAAa,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;gBACxC,CAAC;YACH,CAAC;YAED,IAAI,IAAI,KAAK,iBAAiB,EAAE,CAAC;gBAC/B,MAAM,WAAW,GAAG,KAAK,CAAC,WAAW,CAAC;gBACtC,IAAI,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC;oBAC/B,KAAK,MAAM,CAAC,IAAI,WAAW,EAAE,CAAC;wBAC5B,IAAI,OAAO,CAAC,KAAK,QAAQ;4BAAE,kBAAkB,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;oBACvD,CAAC;gBACH,CAAC;gBACD,sEAAsE;gBACtE,6DAA6D;gBAC7D,IAAI,OAAO,KAAK,CAAC,UAAU,KAAK,QAAQ;oBAAE,mBAAmB,GAAG,IAAI,CAAC;YACvE,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO;QACL,aAAa,EAAE,CAAC,GAAG,aAAa,CAAC,CAAC,IAAI,EAAE;QACxC,kBAAkB,EAAE,CAAC,GAAG,kBAAkB,CAAC,CAAC,IAAI,EAAE;QAClD,mBAAmB;KACpB,CAAC;AACJ,CAAC"}
@@ -0,0 +1,20 @@
1
+ export * from "./contract.js";
2
+ export * from "./backend.js";
3
+ export * from "./config.js";
4
+ export * from "./server.js";
5
+ export { sessionConfigSchema, type SessionConfigSchemaOptions } from "./capabilities-schema.js";
6
+ export { BaseImageCatalog, filterTags, parseDockerHubRef, resolveTagDigest, type TagFilter, type BaseImageCatalogOptions, } from "./base-image-catalog.js";
7
+ export { extractDependencyKey, type DependencyKey } from "./dependency-key.js";
8
+ export { SessionRegistry, SessionLimitError, SessionEvictedError, type SessionEntry, type RegistryDeps, } from "./session/registry.js";
9
+ export { EventRingBuffer, type BufferedEvent } from "./session/ring-buffer.js";
10
+ export { ByteRingBuffer, type BufferedBytes } from "./session/byte-ring-buffer.js";
11
+ export { normalizeBundlePath, validateSessionId, BundlePathError } from "./session/bundle-path.js";
12
+ export { streamSessionEvents, type SseStreamArgs } from "./sse/channel.js";
13
+ export { healthRoute } from "./routes/health.js";
14
+ export { capabilitiesRoute } from "./routes/capabilities.js";
15
+ export { probeRoute, type ProbeRouteDeps } from "./routes/probe.js";
16
+ export { sessionsRoute, type SessionsRouteDeps } from "./routes/sessions.js";
17
+ export { ioRoute, type IoRouteDeps } from "./routes/io.js";
18
+ export { relayDebugStream, type DebugRelayOptions } from "./debug/relay.js";
19
+ export type { DebugFrame, DebugEvent, DebugLog } from "@telorun/debug-wire";
20
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +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"}
package/dist/index.js ADDED
@@ -0,0 +1,19 @@
1
+ export * from "./contract.js";
2
+ export * from "./backend.js";
3
+ export * from "./config.js";
4
+ export * from "./server.js";
5
+ export { sessionConfigSchema } from "./capabilities-schema.js";
6
+ export { BaseImageCatalog, filterTags, parseDockerHubRef, resolveTagDigest, } from "./base-image-catalog.js";
7
+ export { extractDependencyKey } from "./dependency-key.js";
8
+ export { SessionRegistry, SessionLimitError, SessionEvictedError, } from "./session/registry.js";
9
+ export { EventRingBuffer } from "./session/ring-buffer.js";
10
+ export { ByteRingBuffer } from "./session/byte-ring-buffer.js";
11
+ export { normalizeBundlePath, validateSessionId, BundlePathError } from "./session/bundle-path.js";
12
+ export { streamSessionEvents } from "./sse/channel.js";
13
+ export { healthRoute } from "./routes/health.js";
14
+ export { capabilitiesRoute } from "./routes/capabilities.js";
15
+ export { probeRoute } from "./routes/probe.js";
16
+ export { sessionsRoute } from "./routes/sessions.js";
17
+ export { ioRoute } from "./routes/io.js";
18
+ export { relayDebugStream } from "./debug/relay.js";
19
+ //# sourceMappingURL=index.js.map
@@ -0,0 +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"}
@@ -0,0 +1,12 @@
1
+ import type { FastifyPluginAsync } from "fastify";
2
+ import type { RunnerCapabilities } from "../contract.js";
3
+ /** Advertises the runner's self-description + editable config schema, so the
4
+ * editor can render a generic runner config form without hardcoding per-backend
5
+ * fields. The document is backend-authored — each concrete runner supplies its
6
+ * own `RunnerCapabilities`; core only serves it.
7
+ *
8
+ * Accepts a getter as well as a static document so a runner whose config
9
+ * surface changes at runtime (e.g. a base-image catalog refreshed from a
10
+ * registry) is re-resolved on each request rather than frozen at boot. */
11
+ export declare function capabilitiesRoute(capabilities: RunnerCapabilities | (() => RunnerCapabilities)): FastifyPluginAsync;
12
+ //# sourceMappingURL=capabilities.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capabilities.d.ts","sourceRoot":"","sources":["../../src/routes/capabilities.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAmB,kBAAkB,EAAE,MAAM,SAAS,CAAC;AAEnE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAEzD;;;;;;;2EAO2E;AAC3E,wBAAgB,iBAAiB,CAC/B,YAAY,EAAE,kBAAkB,GAAG,CAAC,MAAM,kBAAkB,CAAC,GAC5D,kBAAkB,CAKpB"}
@@ -0,0 +1,15 @@
1
+ /** Advertises the runner's self-description + editable config schema, so the
2
+ * editor can render a generic runner config form without hardcoding per-backend
3
+ * fields. The document is backend-authored — each concrete runner supplies its
4
+ * own `RunnerCapabilities`; core only serves it.
5
+ *
6
+ * Accepts a getter as well as a static document so a runner whose config
7
+ * surface changes at runtime (e.g. a base-image catalog refreshed from a
8
+ * registry) is re-resolved on each request rather than frozen at boot. */
9
+ export function capabilitiesRoute(capabilities) {
10
+ const resolve = typeof capabilities === "function" ? capabilities : () => capabilities;
11
+ return async (app) => {
12
+ app.get("/v1/capabilities", async () => resolve());
13
+ };
14
+ }
15
+ //# sourceMappingURL=capabilities.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capabilities.js","sourceRoot":"","sources":["../../src/routes/capabilities.ts"],"names":[],"mappings":"AAIA;;;;;;;2EAO2E;AAC3E,MAAM,UAAU,iBAAiB,CAC/B,YAA6D;IAE7D,MAAM,OAAO,GAAG,OAAO,YAAY,KAAK,UAAU,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,YAAY,CAAC;IACvF,OAAO,KAAK,EAAE,GAAoB,EAAE,EAAE;QACpC,GAAG,CAAC,GAAG,CAAC,kBAAkB,EAAE,KAAK,IAAI,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC;IACrD,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,5 @@
1
+ import type { FastifyPluginAsync } from "fastify";
2
+ /** Liveness. Returns the runner's own version, supplied by the concrete runner
3
+ * (each runner package has its own version). */
4
+ export declare function healthRoute(version: string): FastifyPluginAsync;
5
+ //# sourceMappingURL=health.d.ts.map