@dfosco/storyboard 0.5.0-alpha.21 → 0.5.0-alpha.22

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.
@@ -0,0 +1,305 @@
1
+ import { z } from 'zod';
2
+
3
+ /**
4
+ * `POST /devserver/acquire` — request a devserver for a `(devDomain, worktree)` slot.
5
+ *
6
+ * If a devserver already exists for the slot, the runtime returns its existing
7
+ * lease (renewed). Otherwise it either rents a hot-pool member or spawns a new
8
+ * Vite process. The slot is locked for the duration of the call.
9
+ */
10
+ declare const AcquireRequest: z.ZodObject<{
11
+ slot: z.ZodObject<{
12
+ devDomain: z.ZodBranded<z.ZodString, "DevDomain">;
13
+ worktree: z.ZodBranded<z.ZodString, "WorktreeName">;
14
+ }, "strip", z.ZodTypeAny, {
15
+ devDomain?: string & z.BRAND<"DevDomain">;
16
+ worktree?: string & z.BRAND<"WorktreeName">;
17
+ }, {
18
+ devDomain?: string;
19
+ worktree?: string;
20
+ }>;
21
+ /** Absolute path of the worktree directory; the runtime spawns Vite with `cwd: targetCwd`. */
22
+ targetCwd: z.ZodString;
23
+ /** Lease TTL in seconds. Defaults to 5 min; CLI clients renew on each command. */
24
+ ttlSeconds: z.ZodDefault<z.ZodNumber>;
25
+ /**
26
+ * Escape hatch for the deprecated default devDomain `"storyboard"`. CI and
27
+ * one-off scripts may pass true; the CLI never does.
28
+ */
29
+ allowDefaultDomain: z.ZodDefault<z.ZodBoolean>;
30
+ }, "strip", z.ZodTypeAny, {
31
+ slot?: {
32
+ devDomain?: string & z.BRAND<"DevDomain">;
33
+ worktree?: string & z.BRAND<"WorktreeName">;
34
+ };
35
+ targetCwd?: string;
36
+ ttlSeconds?: number;
37
+ allowDefaultDomain?: boolean;
38
+ }, {
39
+ slot?: {
40
+ devDomain?: string;
41
+ worktree?: string;
42
+ };
43
+ targetCwd?: string;
44
+ ttlSeconds?: number;
45
+ allowDefaultDomain?: boolean;
46
+ }>;
47
+ type AcquireRequest = z.infer<typeof AcquireRequest>;
48
+ declare const AcquireResponse: z.ZodObject<{
49
+ lease: z.ZodObject<{
50
+ id: z.ZodString;
51
+ devServerId: z.ZodString;
52
+ slot: z.ZodObject<{
53
+ devDomain: z.ZodBranded<z.ZodString, "DevDomain">;
54
+ worktree: z.ZodBranded<z.ZodString, "WorktreeName">;
55
+ }, "strip", z.ZodTypeAny, {
56
+ devDomain?: string & z.BRAND<"DevDomain">;
57
+ worktree?: string & z.BRAND<"WorktreeName">;
58
+ }, {
59
+ devDomain?: string;
60
+ worktree?: string;
61
+ }>;
62
+ url: z.ZodString;
63
+ expiresAt: z.ZodString;
64
+ }, "strip", z.ZodTypeAny, {
65
+ id?: string;
66
+ slot?: {
67
+ devDomain?: string & z.BRAND<"DevDomain">;
68
+ worktree?: string & z.BRAND<"WorktreeName">;
69
+ };
70
+ devServerId?: string;
71
+ url?: string;
72
+ expiresAt?: string;
73
+ }, {
74
+ id?: string;
75
+ slot?: {
76
+ devDomain?: string;
77
+ worktree?: string;
78
+ };
79
+ devServerId?: string;
80
+ url?: string;
81
+ expiresAt?: string;
82
+ }>;
83
+ devServer: z.ZodObject<{
84
+ id: z.ZodString;
85
+ pid: z.ZodNumber;
86
+ port: z.ZodBranded<z.ZodNumber, "Port">;
87
+ status: z.ZodEnum<["idle", "spawning", "ready", "draining", "stopped"]>;
88
+ slot: z.ZodNullable<z.ZodObject<{
89
+ devDomain: z.ZodBranded<z.ZodString, "DevDomain">;
90
+ worktree: z.ZodBranded<z.ZodString, "WorktreeName">;
91
+ }, "strip", z.ZodTypeAny, {
92
+ devDomain?: string & z.BRAND<"DevDomain">;
93
+ worktree?: string & z.BRAND<"WorktreeName">;
94
+ }, {
95
+ devDomain?: string;
96
+ worktree?: string;
97
+ }>>;
98
+ cwd: z.ZodNullable<z.ZodString>;
99
+ spawnedAt: z.ZodString;
100
+ updatedAt: z.ZodString;
101
+ }, "strip", z.ZodTypeAny, {
102
+ status?: "idle" | "spawning" | "ready" | "draining" | "stopped";
103
+ id?: string;
104
+ pid?: number;
105
+ port?: number & z.BRAND<"Port">;
106
+ slot?: {
107
+ devDomain?: string & z.BRAND<"DevDomain">;
108
+ worktree?: string & z.BRAND<"WorktreeName">;
109
+ };
110
+ cwd?: string;
111
+ spawnedAt?: string;
112
+ updatedAt?: string;
113
+ }, {
114
+ status?: "idle" | "spawning" | "ready" | "draining" | "stopped";
115
+ id?: string;
116
+ pid?: number;
117
+ port?: number;
118
+ slot?: {
119
+ devDomain?: string;
120
+ worktree?: string;
121
+ };
122
+ cwd?: string;
123
+ spawnedAt?: string;
124
+ updatedAt?: string;
125
+ }>;
126
+ }, "strip", z.ZodTypeAny, {
127
+ lease?: {
128
+ id?: string;
129
+ slot?: {
130
+ devDomain?: string & z.BRAND<"DevDomain">;
131
+ worktree?: string & z.BRAND<"WorktreeName">;
132
+ };
133
+ devServerId?: string;
134
+ url?: string;
135
+ expiresAt?: string;
136
+ };
137
+ devServer?: {
138
+ status?: "idle" | "spawning" | "ready" | "draining" | "stopped";
139
+ id?: string;
140
+ pid?: number;
141
+ port?: number & z.BRAND<"Port">;
142
+ slot?: {
143
+ devDomain?: string & z.BRAND<"DevDomain">;
144
+ worktree?: string & z.BRAND<"WorktreeName">;
145
+ };
146
+ cwd?: string;
147
+ spawnedAt?: string;
148
+ updatedAt?: string;
149
+ };
150
+ }, {
151
+ lease?: {
152
+ id?: string;
153
+ slot?: {
154
+ devDomain?: string;
155
+ worktree?: string;
156
+ };
157
+ devServerId?: string;
158
+ url?: string;
159
+ expiresAt?: string;
160
+ };
161
+ devServer?: {
162
+ status?: "idle" | "spawning" | "ready" | "draining" | "stopped";
163
+ id?: string;
164
+ pid?: number;
165
+ port?: number;
166
+ slot?: {
167
+ devDomain?: string;
168
+ worktree?: string;
169
+ };
170
+ cwd?: string;
171
+ spawnedAt?: string;
172
+ updatedAt?: string;
173
+ };
174
+ }>;
175
+ type AcquireResponse = z.infer<typeof AcquireResponse>;
176
+ /** `POST /devserver/release` — relinquish the lease and trigger draining. */
177
+ declare const ReleaseRequest: z.ZodObject<{
178
+ leaseId: z.ZodString;
179
+ }, "strip", z.ZodTypeAny, {
180
+ leaseId?: string;
181
+ }, {
182
+ leaseId?: string;
183
+ }>;
184
+ type ReleaseRequest = z.infer<typeof ReleaseRequest>;
185
+ /** `POST /devserver/renew` — extend the lease without changing devserver state. */
186
+ declare const RenewRequest: z.ZodObject<{
187
+ leaseId: z.ZodString;
188
+ ttlSeconds: z.ZodDefault<z.ZodNumber>;
189
+ }, "strip", z.ZodTypeAny, {
190
+ ttlSeconds?: number;
191
+ leaseId?: string;
192
+ }, {
193
+ ttlSeconds?: number;
194
+ leaseId?: string;
195
+ }>;
196
+ type RenewRequest = z.infer<typeof RenewRequest>;
197
+ /** `GET /proxy/state` — current routing table the runtime believes Caddy holds. */
198
+ declare const ProxyState: z.ZodObject<{
199
+ routes: z.ZodArray<z.ZodObject<{
200
+ devDomain: z.ZodBranded<z.ZodString, "DevDomain">;
201
+ host: z.ZodString;
202
+ upstreams: z.ZodRecord<z.ZodString, z.ZodBranded<z.ZodNumber, "Port">>;
203
+ }, "strip", z.ZodTypeAny, {
204
+ devDomain?: string & z.BRAND<"DevDomain">;
205
+ host?: string;
206
+ upstreams?: Record<string, number & z.BRAND<"Port">>;
207
+ }, {
208
+ devDomain?: string;
209
+ host?: string;
210
+ upstreams?: Record<string, number>;
211
+ }>, "many">;
212
+ caddyReachable: z.ZodBoolean;
213
+ }, "strip", z.ZodTypeAny, {
214
+ routes?: {
215
+ devDomain?: string & z.BRAND<"DevDomain">;
216
+ host?: string;
217
+ upstreams?: Record<string, number & z.BRAND<"Port">>;
218
+ }[];
219
+ caddyReachable?: boolean;
220
+ }, {
221
+ routes?: {
222
+ devDomain?: string;
223
+ host?: string;
224
+ upstreams?: Record<string, number>;
225
+ }[];
226
+ caddyReachable?: boolean;
227
+ }>;
228
+ type ProxyState = z.infer<typeof ProxyState>;
229
+ /** `GET /pool/status` — hot-pool inventory. */
230
+ declare const PoolStatus: z.ZodObject<{
231
+ warm: z.ZodNumber;
232
+ bound: z.ZodNumber;
233
+ capacity: z.ZodNumber;
234
+ }, "strip", z.ZodTypeAny, {
235
+ warm?: number;
236
+ bound?: number;
237
+ capacity?: number;
238
+ }, {
239
+ warm?: number;
240
+ bound?: number;
241
+ capacity?: number;
242
+ }>;
243
+ type PoolStatus = z.infer<typeof PoolStatus>;
244
+ /** `POST /proxy/upsert` — bind (devDomain, worktree) → port in the proxy. */
245
+ declare const ProxyUpsertRequest: z.ZodObject<{
246
+ devDomain: z.ZodString;
247
+ worktree: z.ZodString;
248
+ port: z.ZodNumber;
249
+ }, "strip", z.ZodTypeAny, {
250
+ devDomain?: string;
251
+ worktree?: string;
252
+ port?: number;
253
+ }, {
254
+ devDomain?: string;
255
+ worktree?: string;
256
+ port?: number;
257
+ }>;
258
+ type ProxyUpsertRequest = z.infer<typeof ProxyUpsertRequest>;
259
+ /** `POST /proxy/remove` — drop a worktree's route from the proxy. */
260
+ declare const ProxyRemoveRequest: z.ZodObject<{
261
+ devDomain: z.ZodString;
262
+ worktree: z.ZodString;
263
+ }, "strip", z.ZodTypeAny, {
264
+ devDomain?: string;
265
+ worktree?: string;
266
+ }, {
267
+ devDomain?: string;
268
+ worktree?: string;
269
+ }>;
270
+ type ProxyRemoveRequest = z.infer<typeof ProxyRemoveRequest>;
271
+ /** `GET /health` — daemon liveness probe. */
272
+ declare const Health: z.ZodObject<{
273
+ ok: z.ZodLiteral<true>;
274
+ version: z.ZodString;
275
+ uptimeSeconds: z.ZodNumber;
276
+ port: z.ZodBranded<z.ZodNumber, "Port">;
277
+ }, "strip", z.ZodTypeAny, {
278
+ port?: number & z.BRAND<"Port">;
279
+ ok?: true;
280
+ version?: string;
281
+ uptimeSeconds?: number;
282
+ }, {
283
+ port?: number;
284
+ ok?: true;
285
+ version?: string;
286
+ uptimeSeconds?: number;
287
+ }>;
288
+ type Health = z.infer<typeof Health>;
289
+ /** Runtime error envelope. All non-2xx responses share this shape. */
290
+ declare const RuntimeError: z.ZodObject<{
291
+ error: z.ZodString;
292
+ code: z.ZodEnum<["NOT_IMPLEMENTED", "BAD_REQUEST", "CONFLICT", "NOT_FOUND", "FORBIDDEN_DEFAULT_DOMAIN", "INTERNAL", "CADDY_UNREACHABLE", "PORT_EXHAUSTED", "TIMEOUT"]>;
293
+ details: z.ZodOptional<z.ZodUnknown>;
294
+ }, "strip", z.ZodTypeAny, {
295
+ code?: "NOT_IMPLEMENTED" | "BAD_REQUEST" | "CONFLICT" | "NOT_FOUND" | "FORBIDDEN_DEFAULT_DOMAIN" | "INTERNAL" | "CADDY_UNREACHABLE" | "PORT_EXHAUSTED" | "TIMEOUT";
296
+ error?: string;
297
+ details?: unknown;
298
+ }, {
299
+ code?: "NOT_IMPLEMENTED" | "BAD_REQUEST" | "CONFLICT" | "NOT_FOUND" | "FORBIDDEN_DEFAULT_DOMAIN" | "INTERNAL" | "CADDY_UNREACHABLE" | "PORT_EXHAUSTED" | "TIMEOUT";
300
+ error?: string;
301
+ details?: unknown;
302
+ }>;
303
+ type RuntimeError = z.infer<typeof RuntimeError>;
304
+
305
+ export { AcquireRequest as A, Health as H, ProxyState as P, ReleaseRequest as R, AcquireResponse as a, RenewRequest as b, PoolStatus as c, ProxyUpsertRequest as d, ProxyRemoveRequest as e, RuntimeError as f };
@@ -0,0 +1,32 @@
1
+ import { z } from 'zod';
2
+ import { H as Health, A as AcquireRequest, a as AcquireResponse, R as ReleaseRequest, b as RenewRequest, P as ProxyState, d as ProxyUpsertRequest, e as ProxyRemoveRequest, c as PoolStatus, f as RuntimeError } from '../api-Bbh7Mcv9.js';
3
+
4
+ interface RuntimeClientOptions {
5
+ /** Override base URL (mostly for tests). */
6
+ baseUrl?: string;
7
+ /** Auto-start the daemon if it isn't running. Default: true. */
8
+ autoStart?: boolean;
9
+ }
10
+ declare class RuntimeRequestError extends Error {
11
+ readonly status: number;
12
+ readonly code: z.infer<typeof RuntimeError>['code'];
13
+ readonly details?: unknown;
14
+ constructor(message: string, status: number, code: z.infer<typeof RuntimeError>['code'], details?: unknown);
15
+ }
16
+ declare class RuntimeClient {
17
+ readonly baseUrl: string;
18
+ readonly autoStart: boolean;
19
+ constructor(opts?: RuntimeClientOptions);
20
+ health(): Promise<Health>;
21
+ acquire(input: z.input<typeof AcquireRequest>): Promise<AcquireResponse>;
22
+ release(input: z.input<typeof ReleaseRequest>): Promise<void>;
23
+ renew(input: z.input<typeof RenewRequest>): Promise<void>;
24
+ proxyState(): Promise<ProxyState>;
25
+ proxyUpsert(input: z.input<typeof ProxyUpsertRequest>): Promise<ProxyState>;
26
+ proxyRemove(input: z.input<typeof ProxyRemoveRequest>): Promise<ProxyState>;
27
+ poolStatus(): Promise<PoolStatus>;
28
+ }
29
+ /** Default singleton client for casual callers. */
30
+ declare const runtime: RuntimeClient;
31
+
32
+ export { RuntimeClient, type RuntimeClientOptions, RuntimeRequestError, runtime };
@@ -0,0 +1,239 @@
1
+ // src/runtime/client/index.ts
2
+ import { spawn } from "child_process";
3
+ import { fileURLToPath } from "url";
4
+ import { dirname, resolve } from "path";
5
+
6
+ // src/runtime/schema/identity.ts
7
+ import { z } from "zod";
8
+ var DevDomain = z.string().min(1).max(32).regex(/^[a-z][a-z0-9-]*$/, "devDomain must match /^[a-z][a-z0-9-]*$/").brand();
9
+ var WorktreeName = z.string().min(1).max(64).regex(/^[a-z0-9][a-z0-9._-]*$/i, "worktree name must be URL-safe").brand();
10
+ var Port = z.number().int().min(1024).max(65535).brand();
11
+ var DevServerSlot = z.object({
12
+ devDomain: DevDomain,
13
+ worktree: WorktreeName
14
+ });
15
+
16
+ // src/runtime/schema/devserver.ts
17
+ import { z as z2 } from "zod";
18
+ var DevServerStatus = z2.enum([
19
+ "idle",
20
+ // pre-warmed in the hot pool, no project bound yet
21
+ "spawning",
22
+ // process started, waiting for `ready in …` from Vite stdout
23
+ "ready",
24
+ // bound to a slot, accepting traffic via Caddy
25
+ "draining",
26
+ // releasing — finishing in-flight requests before kill
27
+ "stopped"
28
+ // process exited, slot freed, port returned to the pool
29
+ ]);
30
+ var DevServer = z2.object({
31
+ id: z2.string().uuid(),
32
+ pid: z2.number().int().positive(),
33
+ port: Port,
34
+ status: DevServerStatus,
35
+ slot: DevServerSlot.nullable(),
36
+ /** Absolute path of the worktree directory once bound; null while in the pool. */
37
+ cwd: z2.string().nullable(),
38
+ /** ISO timestamp; immutable after spawn. */
39
+ spawnedAt: z2.string().datetime(),
40
+ /** ISO timestamp of last status change. */
41
+ updatedAt: z2.string().datetime()
42
+ });
43
+ var Lease = z2.object({
44
+ id: z2.string().uuid(),
45
+ devServerId: z2.string().uuid(),
46
+ slot: DevServerSlot,
47
+ /** Public proxy URL the client should print to the user. Authoritative. */
48
+ url: z2.string().url(),
49
+ /** Renew before this timestamp or the lease expires and the devserver drains. */
50
+ expiresAt: z2.string().datetime()
51
+ });
52
+ var ProxyRoute = z2.object({
53
+ devDomain: DevDomain,
54
+ host: z2.string(),
55
+ /** worktree name → upstream port. `main` is the host's catch-all. */
56
+ upstreams: z2.record(z2.string(), Port)
57
+ });
58
+
59
+ // src/runtime/schema/api.ts
60
+ import { z as z3 } from "zod";
61
+ var AcquireRequest = z3.object({
62
+ slot: DevServerSlot,
63
+ /** Absolute path of the worktree directory; the runtime spawns Vite with `cwd: targetCwd`. */
64
+ targetCwd: z3.string().min(1),
65
+ /** Lease TTL in seconds. Defaults to 5 min; CLI clients renew on each command. */
66
+ ttlSeconds: z3.number().int().min(30).max(60 * 60).default(300),
67
+ /**
68
+ * Escape hatch for the deprecated default devDomain `"storyboard"`. CI and
69
+ * one-off scripts may pass true; the CLI never does.
70
+ */
71
+ allowDefaultDomain: z3.boolean().default(false)
72
+ });
73
+ var AcquireResponse = z3.object({
74
+ lease: Lease,
75
+ devServer: DevServer
76
+ });
77
+ var ReleaseRequest = z3.object({
78
+ leaseId: z3.string().uuid()
79
+ });
80
+ var RenewRequest = z3.object({
81
+ leaseId: z3.string().uuid(),
82
+ ttlSeconds: z3.number().int().min(30).max(60 * 60).default(300)
83
+ });
84
+ var ProxyState = z3.object({
85
+ routes: z3.array(ProxyRoute),
86
+ caddyReachable: z3.boolean()
87
+ });
88
+ var PoolStatus = z3.object({
89
+ warm: z3.number().int().nonnegative(),
90
+ bound: z3.number().int().nonnegative(),
91
+ capacity: z3.number().int().nonnegative()
92
+ });
93
+ var ProxyUpsertRequest = z3.object({
94
+ devDomain: z3.string(),
95
+ worktree: z3.string(),
96
+ port: z3.number()
97
+ });
98
+ var ProxyRemoveRequest = z3.object({
99
+ devDomain: z3.string(),
100
+ worktree: z3.string()
101
+ });
102
+ var Health = z3.object({
103
+ ok: z3.literal(true),
104
+ version: z3.string(),
105
+ uptimeSeconds: z3.number().nonnegative(),
106
+ port: Port
107
+ });
108
+ var RuntimeError = z3.object({
109
+ error: z3.string(),
110
+ code: z3.enum([
111
+ "NOT_IMPLEMENTED",
112
+ "BAD_REQUEST",
113
+ "CONFLICT",
114
+ "NOT_FOUND",
115
+ "FORBIDDEN_DEFAULT_DOMAIN",
116
+ "INTERNAL",
117
+ "CADDY_UNREACHABLE",
118
+ "PORT_EXHAUSTED",
119
+ "TIMEOUT"
120
+ ]),
121
+ details: z3.unknown().optional()
122
+ });
123
+
124
+ // src/runtime/client/index.ts
125
+ var RUNTIME_BASE = "http://127.0.0.1:4321";
126
+ var RuntimeRequestError = class extends Error {
127
+ constructor(message, status, code, details) {
128
+ super(message);
129
+ this.status = status;
130
+ this.code = code;
131
+ this.details = details;
132
+ this.name = "RuntimeRequestError";
133
+ }
134
+ };
135
+ async function request(baseUrl, method, path, body, responseSchema) {
136
+ const init = {
137
+ method,
138
+ headers: body !== void 0 ? { "Content-Type": "application/json" } : void 0,
139
+ body: body !== void 0 ? JSON.stringify(body) : void 0
140
+ };
141
+ let res;
142
+ try {
143
+ res = await fetch(`${baseUrl}${path}`, init);
144
+ } catch (err) {
145
+ throw new RuntimeRequestError(
146
+ `Cannot reach Storyboard Runtime at ${baseUrl} \u2014 is the daemon running? (${err.message})`,
147
+ 0,
148
+ "INTERNAL"
149
+ );
150
+ }
151
+ const text = await res.text();
152
+ let parsed;
153
+ try {
154
+ parsed = text ? JSON.parse(text) : {};
155
+ } catch {
156
+ parsed = { error: text, code: "INTERNAL" };
157
+ }
158
+ if (!res.ok) {
159
+ const err = RuntimeError.safeParse(parsed);
160
+ if (err.success) {
161
+ throw new RuntimeRequestError(err.data.error, res.status, err.data.code, err.data.details);
162
+ }
163
+ throw new RuntimeRequestError(`HTTP ${res.status}`, res.status, "INTERNAL", parsed);
164
+ }
165
+ if (responseSchema === null) return void 0;
166
+ return responseSchema.parse(parsed);
167
+ }
168
+ async function spawnDaemon(baseUrl) {
169
+ const here = dirname(fileURLToPath(import.meta.url));
170
+ const binPath = resolve(here, "..", "..", "bin", "runtime.js");
171
+ const child = spawn(process.execPath, [binPath], {
172
+ detached: true,
173
+ stdio: "ignore",
174
+ env: process.env
175
+ });
176
+ child.unref();
177
+ const deadline = Date.now() + 5e3;
178
+ while (Date.now() < deadline) {
179
+ try {
180
+ const r = await fetch(`${baseUrl}/health`);
181
+ if (r.ok) return;
182
+ } catch {
183
+ }
184
+ await new Promise((r) => setTimeout(r, 100));
185
+ }
186
+ throw new Error("Storyboard Runtime did not become ready within 5s");
187
+ }
188
+ var RuntimeClient = class {
189
+ baseUrl;
190
+ autoStart;
191
+ constructor(opts = {}) {
192
+ this.baseUrl = opts.baseUrl ?? RUNTIME_BASE;
193
+ this.autoStart = opts.autoStart !== false;
194
+ }
195
+ async health() {
196
+ try {
197
+ return await request(this.baseUrl, "GET", "/health", void 0, Health);
198
+ } catch (err) {
199
+ if (this.autoStart && err instanceof RuntimeRequestError && err.status === 0) {
200
+ await spawnDaemon(this.baseUrl);
201
+ return request(this.baseUrl, "GET", "/health", void 0, Health);
202
+ }
203
+ throw err;
204
+ }
205
+ }
206
+ async acquire(input) {
207
+ const body = AcquireRequest.parse(input);
208
+ return request(this.baseUrl, "POST", "/devserver/acquire", body, AcquireResponse);
209
+ }
210
+ async release(input) {
211
+ const body = ReleaseRequest.parse(input);
212
+ await request(this.baseUrl, "POST", "/devserver/release", body, null);
213
+ }
214
+ async renew(input) {
215
+ const body = RenewRequest.parse(input);
216
+ await request(this.baseUrl, "POST", "/devserver/renew", body, null);
217
+ }
218
+ async proxyState() {
219
+ return request(this.baseUrl, "GET", "/proxy/state", void 0, ProxyState);
220
+ }
221
+ async proxyUpsert(input) {
222
+ const body = ProxyUpsertRequest.parse(input);
223
+ return request(this.baseUrl, "POST", "/proxy/upsert", body, ProxyState);
224
+ }
225
+ async proxyRemove(input) {
226
+ const body = ProxyRemoveRequest.parse(input);
227
+ return request(this.baseUrl, "POST", "/proxy/remove", body, ProxyState);
228
+ }
229
+ async poolStatus() {
230
+ return request(this.baseUrl, "GET", "/pool/status", void 0, PoolStatus);
231
+ }
232
+ };
233
+ var runtime = new RuntimeClient();
234
+ export {
235
+ RuntimeClient,
236
+ RuntimeRequestError,
237
+ runtime
238
+ };
239
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/runtime/client/index.ts","../../../src/runtime/schema/identity.ts","../../../src/runtime/schema/devserver.ts","../../../src/runtime/schema/api.ts"],"sourcesContent":["import { spawn } from 'node:child_process'\nimport { fileURLToPath } from 'node:url'\nimport { dirname, resolve } from 'node:path'\nimport {\n AcquireRequest,\n AcquireResponse,\n Health,\n PoolStatus,\n ProxyRemoveRequest,\n ProxyState,\n ProxyUpsertRequest,\n ReleaseRequest,\n RenewRequest,\n RuntimeError,\n} from '../schema/index.js'\nimport type { z } from 'zod'\n\n/**\n * Typed JS/TS client for the Storyboard Runtime daemon.\n *\n * Consumers should always go through this client rather than hand-rolling\n * `fetch` calls — the client is the only place where the daemon's URL is\n * known, and it's the only place where on-demand daemon spawning happens.\n */\n\nconst RUNTIME_BASE = 'http://127.0.0.1:4321'\n\nexport interface RuntimeClientOptions {\n /** Override base URL (mostly for tests). */\n baseUrl?: string\n /** Auto-start the daemon if it isn't running. Default: true. */\n autoStart?: boolean\n}\n\nexport class RuntimeRequestError extends Error {\n constructor(\n message: string,\n public readonly status: number,\n public readonly code: z.infer<typeof RuntimeError>['code'],\n public readonly details?: unknown,\n ) {\n super(message)\n this.name = 'RuntimeRequestError'\n }\n}\n\nasync function request<S extends z.ZodTypeAny>(\n baseUrl: string,\n method: 'GET' | 'POST',\n path: string,\n body: unknown,\n responseSchema: S | null,\n): Promise<S extends z.ZodTypeAny ? z.output<S> : void> {\n const init: RequestInit = {\n method,\n headers: body !== undefined ? { 'Content-Type': 'application/json' } : undefined,\n body: body !== undefined ? JSON.stringify(body) : undefined,\n }\n let res: Response\n try {\n res = await fetch(`${baseUrl}${path}`, init)\n } catch (err) {\n throw new RuntimeRequestError(\n `Cannot reach Storyboard Runtime at ${baseUrl} — is the daemon running? (${(err as Error).message})`,\n 0,\n 'INTERNAL',\n )\n }\n const text = await res.text()\n let parsed: unknown\n try { parsed = text ? JSON.parse(text) : {} }\n catch { parsed = { error: text, code: 'INTERNAL' } }\n\n if (!res.ok) {\n const err = RuntimeError.safeParse(parsed)\n if (err.success) {\n throw new RuntimeRequestError(err.data.error, res.status, err.data.code, err.data.details)\n }\n throw new RuntimeRequestError(`HTTP ${res.status}`, res.status, 'INTERNAL', parsed)\n }\n if (responseSchema === null) return undefined as never\n return responseSchema.parse(parsed) as never\n}\n\n/**\n * Spawn the daemon as a detached child. Resolves once the health endpoint\n * answers (or rejects after a short timeout).\n */\nasync function spawnDaemon(baseUrl: string): Promise<void> {\n const here = dirname(fileURLToPath(import.meta.url))\n // bin/runtime.js lives next to dist/, two levels up from dist/client/index.js\n const binPath = resolve(here, '..', '..', 'bin', 'runtime.js')\n const child = spawn(process.execPath, [binPath], {\n detached: true,\n stdio: 'ignore',\n env: process.env,\n })\n child.unref()\n\n // Poll /health until the daemon is up.\n const deadline = Date.now() + 5000\n while (Date.now() < deadline) {\n try {\n const r = await fetch(`${baseUrl}/health`)\n if (r.ok) return\n } catch { /* not up yet */ }\n await new Promise(r => setTimeout(r, 100))\n }\n throw new Error('Storyboard Runtime did not become ready within 5s')\n}\n\nexport class RuntimeClient {\n readonly baseUrl: string\n readonly autoStart: boolean\n\n constructor(opts: RuntimeClientOptions = {}) {\n this.baseUrl = opts.baseUrl ?? RUNTIME_BASE\n this.autoStart = opts.autoStart !== false\n }\n\n async health(): Promise<Health> {\n try {\n return await request(this.baseUrl, 'GET', '/health', undefined, Health)\n } catch (err) {\n if (this.autoStart && err instanceof RuntimeRequestError && err.status === 0) {\n await spawnDaemon(this.baseUrl)\n return request(this.baseUrl, 'GET', '/health', undefined, Health)\n }\n throw err\n }\n }\n\n async acquire(input: z.input<typeof AcquireRequest>): Promise<AcquireResponse> {\n const body = AcquireRequest.parse(input)\n return request(this.baseUrl, 'POST', '/devserver/acquire', body, AcquireResponse)\n }\n\n async release(input: z.input<typeof ReleaseRequest>): Promise<void> {\n const body = ReleaseRequest.parse(input)\n await request(this.baseUrl, 'POST', '/devserver/release', body, null)\n }\n\n async renew(input: z.input<typeof RenewRequest>): Promise<void> {\n const body = RenewRequest.parse(input)\n await request(this.baseUrl, 'POST', '/devserver/renew', body, null)\n }\n\n async proxyState(): Promise<ProxyState> {\n return request(this.baseUrl, 'GET', '/proxy/state', undefined, ProxyState)\n }\n\n async proxyUpsert(input: z.input<typeof ProxyUpsertRequest>): Promise<ProxyState> {\n const body = ProxyUpsertRequest.parse(input)\n return request(this.baseUrl, 'POST', '/proxy/upsert', body, ProxyState)\n }\n\n async proxyRemove(input: z.input<typeof ProxyRemoveRequest>): Promise<ProxyState> {\n const body = ProxyRemoveRequest.parse(input)\n return request(this.baseUrl, 'POST', '/proxy/remove', body, ProxyState)\n }\n\n async poolStatus(): Promise<PoolStatus> {\n return request(this.baseUrl, 'GET', '/pool/status', undefined, PoolStatus)\n }\n}\n\n/** Default singleton client for casual callers. */\nexport const runtime = new RuntimeClient()\n","import { z } from 'zod'\n\n/**\n * The legacy/default devDomain. Acquire requests using this value are rejected\n * unless `allowDefaultDomain` is set — see DevServerOrchestrator for details.\n */\nexport const DEFAULT_DEV_DOMAIN = 'storyboard'\n\n/**\n * A devDomain identifies a Storyboard repo on this machine.\n *\n * The literal default value `\"storyboard\"` is intentionally *not* allowed by\n * `acquire` (see schema/acquire.ts) — every checkout MUST set its own\n * `devDomain` in `storyboard.config.json`. This is the structural fix for H3\n * in the server-state RCA: two repos can never share a host space.\n *\n * Allowed: lowercase letters, digits, hyphens. Must start with a letter.\n * 1–32 chars. The runtime constructs the public host as `${devDomain}.localhost`.\n */\nexport const DevDomain = z\n .string()\n .min(1)\n .max(32)\n .regex(/^[a-z][a-z0-9-]*$/, 'devDomain must match /^[a-z][a-z0-9-]*$/')\n .brand<'DevDomain'>()\nexport type DevDomain = z.infer<typeof DevDomain>\n\n/**\n * A worktree name. `\"main\"` is reserved for the repo root.\n *\n * Names are URL-safe by construction so we never have to escape them when\n * building branch URLs (`/branch--<name>/...`).\n */\nexport const WorktreeName = z\n .string()\n .min(1)\n .max(64)\n .regex(/^[a-z0-9][a-z0-9._-]*$/i, 'worktree name must be URL-safe')\n .brand<'WorktreeName'>()\nexport type WorktreeName = z.infer<typeof WorktreeName>\n\n/**\n * A TCP port the runtime has leased to a devserver. The runtime is the sole\n * authority for port allocation; clients never pick their own port.\n */\nexport const Port = z.number().int().min(1024).max(65535).brand<'Port'>()\nexport type Port = z.infer<typeof Port>\n\n/**\n * The composite key `(devDomain, worktree)` uniquely identifies a devserver.\n *\n * The runtime guarantees at most one devserver per slot — illegal collisions\n * (e.g. two repos trying to claim `(storyboard, main)`) are rejected with\n * `409 CONFLICT` rather than silently overwriting routes.\n */\nexport const DevServerSlot = z.object({\n devDomain: DevDomain,\n worktree: WorktreeName,\n})\nexport type DevServerSlot = z.infer<typeof DevServerSlot>\n\n/**\n * Convert a slot to its canonical string key, used for map lookups and\n * logging. Format: `${devDomain}::${worktree}`.\n */\nexport function slotKey(slot: DevServerSlot): string {\n return `${slot.devDomain}::${slot.worktree}`\n}\n","import { z } from 'zod'\nimport { DevDomain, DevServerSlot, Port, WorktreeName } from './identity.js'\n\n/**\n * DevServer lifecycle FSM.\n *\n * Transitions are enforced in code; illegal transitions throw. This is the\n * structural fix for the per-repo server's \"best-effort\" state — a devserver\n * that thinks it's `ready` but whose port is dead cannot exist here.\n *\n * ```\n * idle → spawning → ready → draining → stopped\n * │ │ │\n * └───────────┴────────┴──────→ stopped (on crash)\n * ```\n */\nexport const DevServerStatus = z.enum([\n 'idle', // pre-warmed in the hot pool, no project bound yet\n 'spawning', // process started, waiting for `ready in …` from Vite stdout\n 'ready', // bound to a slot, accepting traffic via Caddy\n 'draining', // releasing — finishing in-flight requests before kill\n 'stopped', // process exited, slot freed, port returned to the pool\n])\nexport type DevServerStatus = z.infer<typeof DevServerStatus>\n\n/** Allowed FSM transitions. Centralised so misuse is a one-line review catch. */\nexport const ALLOWED_TRANSITIONS: Record<DevServerStatus, readonly DevServerStatus[]> = {\n idle: ['spawning', 'stopped'],\n spawning: ['ready', 'stopped'],\n ready: ['draining', 'stopped'],\n draining: ['stopped'],\n stopped: [],\n} as const\n\nexport class IllegalTransitionError extends Error {\n constructor(from: DevServerStatus, to: DevServerStatus) {\n super(`Illegal devserver transition: ${from} → ${to}`)\n this.name = 'IllegalTransitionError'\n }\n}\n\nexport function assertTransition(from: DevServerStatus, to: DevServerStatus): void {\n if (!ALLOWED_TRANSITIONS[from].includes(to)) {\n throw new IllegalTransitionError(from, to)\n }\n}\n\n/**\n * A devserver record as exposed by the runtime API.\n *\n * `slot` is `null` for hot-pool members that haven't been acquired yet.\n * Once bound, `slot.devDomain + slot.worktree` is unique across the whole\n * runtime; the orchestrator rejects duplicate binds.\n */\nexport const DevServer = z.object({\n id: z.string().uuid(),\n pid: z.number().int().positive(),\n port: Port,\n status: DevServerStatus,\n slot: DevServerSlot.nullable(),\n /** Absolute path of the worktree directory once bound; null while in the pool. */\n cwd: z.string().nullable(),\n /** ISO timestamp; immutable after spawn. */\n spawnedAt: z.string().datetime(),\n /** ISO timestamp of last status change. */\n updatedAt: z.string().datetime(),\n})\nexport type DevServer = z.infer<typeof DevServer>\n\n/**\n * A short-lived lease handed to a CLI client when it acquires a devserver.\n *\n * Leases are the *only* way a client controls a devserver — the runtime\n * refuses commands without a valid leaseId. This means a stale `sb dev`\n * process can't kill a devserver belonging to a newer session.\n */\nexport const Lease = z.object({\n id: z.string().uuid(),\n devServerId: z.string().uuid(),\n slot: DevServerSlot,\n /** Public proxy URL the client should print to the user. Authoritative. */\n url: z.string().url(),\n /** Renew before this timestamp or the lease expires and the devserver drains. */\n expiresAt: z.string().datetime(),\n})\nexport type Lease = z.infer<typeof Lease>\n\n/**\n * A Caddy proxy route owned by the runtime. The `@id` is always the devDomain;\n * this lets the runtime PATCH a single route in place without touching others.\n *\n * `upstreams` is keyed by plain string (validated elsewhere as WorktreeName)\n * to avoid `Partial<Record<branded, …>>` shenanigans at the value-spread sites.\n */\nexport const ProxyRoute = z.object({\n devDomain: DevDomain,\n host: z.string(),\n /** worktree name → upstream port. `main` is the host's catch-all. */\n upstreams: z.record(z.string(), Port),\n})\nexport type ProxyRoute = z.infer<typeof ProxyRoute>\n","import { z } from 'zod'\nimport { DevServerSlot, Port } from './identity.js'\nimport { DevServer, Lease, ProxyRoute } from './devserver.js'\n\n/**\n * `POST /devserver/acquire` — request a devserver for a `(devDomain, worktree)` slot.\n *\n * If a devserver already exists for the slot, the runtime returns its existing\n * lease (renewed). Otherwise it either rents a hot-pool member or spawns a new\n * Vite process. The slot is locked for the duration of the call.\n */\nexport const AcquireRequest = z.object({\n slot: DevServerSlot,\n /** Absolute path of the worktree directory; the runtime spawns Vite with `cwd: targetCwd`. */\n targetCwd: z.string().min(1),\n /** Lease TTL in seconds. Defaults to 5 min; CLI clients renew on each command. */\n ttlSeconds: z.number().int().min(30).max(60 * 60).default(300),\n /**\n * Escape hatch for the deprecated default devDomain `\"storyboard\"`. CI and\n * one-off scripts may pass true; the CLI never does.\n */\n allowDefaultDomain: z.boolean().default(false),\n})\nexport type AcquireRequest = z.infer<typeof AcquireRequest>\n\nexport const AcquireResponse = z.object({\n lease: Lease,\n devServer: DevServer,\n})\nexport type AcquireResponse = z.infer<typeof AcquireResponse>\n\n/** `POST /devserver/release` — relinquish the lease and trigger draining. */\nexport const ReleaseRequest = z.object({\n leaseId: z.string().uuid(),\n})\nexport type ReleaseRequest = z.infer<typeof ReleaseRequest>\n\n/** `POST /devserver/renew` — extend the lease without changing devserver state. */\nexport const RenewRequest = z.object({\n leaseId: z.string().uuid(),\n ttlSeconds: z.number().int().min(30).max(60 * 60).default(300),\n})\nexport type RenewRequest = z.infer<typeof RenewRequest>\n\n/** `GET /proxy/state` — current routing table the runtime believes Caddy holds. */\nexport const ProxyState = z.object({\n routes: z.array(ProxyRoute),\n caddyReachable: z.boolean(),\n})\nexport type ProxyState = z.infer<typeof ProxyState>\n\n/** `GET /pool/status` — hot-pool inventory. */\nexport const PoolStatus = z.object({\n warm: z.number().int().nonnegative(),\n bound: z.number().int().nonnegative(),\n capacity: z.number().int().nonnegative(),\n})\nexport type PoolStatus = z.infer<typeof PoolStatus>\n\n/** `POST /proxy/upsert` — bind (devDomain, worktree) → port in the proxy. */\nexport const ProxyUpsertRequest = z.object({\n devDomain: z.string(),\n worktree: z.string(),\n port: z.number(),\n})\nexport type ProxyUpsertRequest = z.infer<typeof ProxyUpsertRequest>\n\n/** `POST /proxy/remove` — drop a worktree's route from the proxy. */\nexport const ProxyRemoveRequest = z.object({\n devDomain: z.string(),\n worktree: z.string(),\n})\nexport type ProxyRemoveRequest = z.infer<typeof ProxyRemoveRequest>\n\n/** `GET /health` — daemon liveness probe. */\nexport const Health = z.object({\n ok: z.literal(true),\n version: z.string(),\n uptimeSeconds: z.number().nonnegative(),\n port: Port,\n})\nexport type Health = z.infer<typeof Health>\n\n/** Runtime error envelope. All non-2xx responses share this shape. */\nexport const RuntimeError = z.object({\n error: z.string(),\n code: z.enum([\n 'NOT_IMPLEMENTED',\n 'BAD_REQUEST',\n 'CONFLICT',\n 'NOT_FOUND',\n 'FORBIDDEN_DEFAULT_DOMAIN',\n 'INTERNAL',\n 'CADDY_UNREACHABLE',\n 'PORT_EXHAUSTED',\n 'TIMEOUT',\n ]),\n details: z.unknown().optional(),\n})\nexport type RuntimeError = z.infer<typeof RuntimeError>\n"],"mappings":"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","names":["z","z","z","z","z"]}
@@ -0,0 +1,18 @@
1
+ export { ALLOWED_TRANSITIONS, DEFAULT_DEV_DOMAIN, DevDomain, DevServer, DevServerSlot, DevServerStatus, IllegalTransitionError, Lease, Port, ProxyRoute, WorktreeName, assertTransition, slotKey } from './schema/index.js';
2
+ export { A as AcquireRequest, a as AcquireResponse, H as Health, c as PoolStatus, e as ProxyRemoveRequest, P as ProxyState, d as ProxyUpsertRequest, R as ReleaseRequest, b as RenewRequest, f as RuntimeError } from './api-Bbh7Mcv9.js';
3
+ export { RuntimeClient, RuntimeRequestError, runtime } from './client/index.js';
4
+ export { startDaemon } from './server/main.js';
5
+ import 'zod';
6
+
7
+ /**
8
+ * Runtime constants — single source of truth for ports, paths, and version.
9
+ *
10
+ * The runtime port (`4321`) is intentionally fixed: a single global daemon
11
+ * needs a well-known address so the CLI client can find it without
12
+ * configuration. Port 4321 is RFC-allowed and avoids collisions with
13
+ * Vite (1234), Caddy admin (2019), and the per-repo legacy server (4100-4199).
14
+ */
15
+ declare const RUNTIME_PORT: 4321;
16
+ declare const RUNTIME_HOST: "127.0.0.1";
17
+
18
+ export { RUNTIME_HOST, RUNTIME_PORT };