# Files changed · PR \#17568 · pingdotgg/t3code

[View on GitCafe](https://git.cafe/pingdotgg/t3code/pull/17568/diffs)

Repository: [pingdotgg/t3code](https://git.cafe/pingdotgg/t3code)

Visibility: public

[fix\(server\): require the bootstrap envelope before startup](https://git.cafe/pingdotgg/t3code/pull/17568.md)

Version: 8

Head commit: d52b1cc7fb894b189aafcb7bc58f671db1588045

Base commit: 069e63b11758c803a064e5515b4485f43147ac28

Comparison base: 069e63b11758c803a064e5515b4485f43147ac28

Showing up to 20 entries from this revision. If the pull request changes, reopen the first page before continuing.

## apps/server/src/bootstrap.test.ts

Status: modified; +104; −41

```diff
@@ -1,13 +1,12 @@
 // @effect-diagnostics nodeBuiltinImport:off
 import * as NodeFS from "node:fs";
-import * as NodePath from "node:path";
+import * as NodeStream from "node:stream";
-import * as NodeChildProcess from "node:child_process";
 import * as NodeServices from "@effect/platform-node/NodeServices";
 import { assert, it } from "@effect/vitest";
 import * as FileSystem from "effect/FileSystem";
 import * as Schema from "effect/Schema";
-import * as Duration from "effect/Duration";
 import * as Effect from "effect/Effect";
+import * as Deferred from "effect/Deferred";
 import * as Fiber from "effect/Fiber";
 import * as TestClock from "effect/testing/TestClock";
 import { vi } from "vite-plus/test";
@@ -15,22 +14,27 @@
 
 import {
   BootstrapEnvelopeDecodeError,
+  BootstrapEnvelopeMissingError,
+  BootstrapEnvelopeReadError,
+  BootstrapEnvelopeTimeoutError,
   BootstrapFdStatError,
   BootstrapInputStreamOpenError,
   readBootstrapEnvelope,
 } from "./bootstrap.ts";
-import { assertNone, assertSome } from "@effect/vitest/utils";
 
 const openSyncInterceptor = vi.hoisted(() => ({
   failPath: null as string | null,
   errorCode: "ENXIO",
 }));
 const fstatSyncInterceptor = vi.hoisted(() => ({ failFd: null as number | null }));
+const readStreamInterceptor = vi.hoisted(() => ({ stream: null as NodeStream.Readable | null }));
 
 vi.mock("node:fs", async (importOriginal) => {
   const actual = await importOriginal<typeof import("node:fs")>();
   return {
     ...actual,
+    createReadStream: (...args: Parameters<typeof actual.createReadStream>) =>
+      readStreamInterceptor.stream ?? actual.createReadStream(...args),
     openSync: (...args: Parameters<typeof actual.openSync>) => {
       const [filePath, flags] = args;
       if (
@@ -76,6 +80,24 @@
 const TestEnvelopeSchema = Schema.Struct({ mode: Schema.String });
 const encodeTestEnvelopeSchema = Schema.encodeEffect(Schema.fromJsonString(TestEnvelopeSchema));
 
+// Control pipe delivery independently of the virtual timeout, on every host.
+const openControlledBootstrapInput = Effect.acquireRelease(
+  Effect.sync(() => {
+    const fd = NodeFS.openSync(nullDevice, "r");
+    const stream = new NodeStream.PassThrough();
+    const reading = Deferred.makeUnsafe<void>();
+    stream.once("resume", () => Deferred.doneUnsafe(reading, Effect.void));
+    readStreamInterceptor.stream = stream;
+    return { fd, stream, reading };
+  }),
+  ({ fd, stream }) =>
+    Effect.sync(() => {
+      readStreamInterceptor.stream = null;
+      stream.destroy();
+      closeIfOpen(fd);
+    }),
+);
+
 it.layer(NodeServices.layer)("readBootstrapEnvelope", (it) => {
   it.effect("reads a bootstrap envelope from a provided fd", () =>
     Effect.gen(function* () {
@@ -90,7 +112,7 @@
       const fd = yield* openBootstrapInputFd(filePath);
 
       const payload = yield* readBootstrapEnvelope(TestEnvelopeSchema, fd, { timeoutMs: 100 });
+      assert.deepEqual(payload, {
-      assertSome(payload, {
         mode: "desktop",
       });
     }),
@@ -117,7 +139,7 @@
         const payload = yield* readBootstrapEnvelope(TestEnvelopeSchema, fd, {
           timeoutMs: 100,
         }).pipe(Effect.provideService(HostProcess.Platform, "linux"));
+        assert.deepEqual(payload, {
-        assertSome(payload, {
           mode: "desktop",
         });
       } finally {
@@ -159,13 +181,16 @@
     }),
   );
 
-  it.effect("returns none when the fd is unavailable", () =>
+  it.effect("fails when the explicitly provided fd is unavailable", () =>
     Effect.gen(function* () {
       const fd = NodeFS.openSync(nullDevice, "r");
       NodeFS.closeSync(fd);
 
+      const error = yield* readBootstrapEnvelope(TestEnvelopeSchema, fd, {
+        timeoutMs: 100,
+      }).pipe(Effect.flip);
+      assert.instanceOf(error, BootstrapFdStatError);
-      const payload = yield* readBootstrapEnvelope(TestEnvelopeSchema, fd, { timeoutMs: 100 });
+      assert.equal(error.fd, fd);
-      assertNone(payload);
     }),
   );
 
@@ -212,44 +237,82 @@
       );
     }),
   );
+
+  it.effect("accepts an envelope arriving after the former one-second deadline", () =>
+    Effect.gen(function* () {
+      const { fd, stream, reading } = yield* openControlledBootstrapInput;
+      const fiber = yield* readBootstrapEnvelope(TestEnvelopeSchema, fd).pipe(
+        Effect.provideService(HostProcess.Platform, "win32"),
+        Effect.forkScoped,
+      );
+
+      yield* Deferred.await(reading);
+      yield* TestClock.adjust(1_001);
+      stream.end('{"mode":"desktop"}\n');
 
+      const payload = yield* Fiber.join(fiber);
+      assert.deepEqual(payload, { mode: "desktop" });
+      assert.isTrue(stream.destroyed);
+    }).pipe(Effect.provide(TestClock.layer())),
+  );
+
+  it.effect("fails at the default deadline and releases the pending reader", () =>
+    Effect.gen(function* () {
+      const { fd, stream, reading } = yield* openControlledBootstrapInput;
+      const fiber = yield* readBootstrapEnvelope(TestEnvelopeSchema, fd).pipe(
+        Effect.provideService(HostProcess.Platform, "win32"),
+        Effect.flip,
+        Effect.forkScoped,
+      );
+
+      yield* Deferred.await(reading);
+      yield* TestClock.adjust(30_000);
+
-  // Needs a FIFO, which mkfifo creates; Windows has neither.
+      const error = yield* Fiber.join(fiber);
-  it.effect.skipIf(windowsHost)(
-    "returns none when the bootstrap read times out before any value arrives",
-    () =>
-      Effect.gen(function* () {
-        const fs = yield* FileSystem.FileSystem;
-        const tempDir = yield* fs.makeTempDirectoryScoped({ prefix: "t3-bootstrap-" });
-        const fifoPath = NodePath.join(tempDir, "bootstrap.pipe");
+      assert.instanceOf(error, BootstrapEnvelopeTimeoutError);
+      assert.equal(error.fd, fd);
+      assert.equal(error.timeoutMs, 30_000);
+      assert.isTrue(stream.destroyed);
+    }).pipe(Effect.provide(TestClock.layer())),
+  );
 
-        yield* Effect.sync(() => NodeChildProcess.execFileSync("mkfifo", [fifoPath]));
+  it.effect("fails when the pipe closes without an envelope", () =>
+    Effect.gen(function* () {
+      const { fd, stream, reading } = yield* openControlledBootstrapInput;
+      const fiber = yield* readBootstrapEnvelope(TestEnvelopeSchema, fd).pipe(
+        Effect.provideService(HostProcess.Platform, "win32"),
+        Effect.flip,
+        Effect.forkScoped,
+      );
 
-        const _writer = yield* Effect.acquireRelease(
-          Effect.sync(() =>
-            NodeChildProcess.spawn("sh", ["-c", 'exec 3>"$1"; sleep 60', "sh", fifoPath], {
-              stdio: ["ignore", "ignore", "ignore"],
+      yield* Deferred.await(reading);
-            }),
-          ),
-          (writer) =>
-            Effect.sync(() => {
-              writer.kill("SIGKILL");
-            }),
-        );
+      stream.end();
 
+      const error = yield* Fiber.join(fiber);
+      assert.instanceOf(error, BootstrapEnvelopeMissingError);
+      assert.equal(error.fd, fd);
+      assert.isTrue(stream.destroyed);
-        const fd = yield* Effect.acquireRelease(
-          Effect.sync(() => NodeFS.openSync(fifoPath, "r")),
-          (fd) => Effect.sync(() => closeIfOpen(fd)),
-        );
+    }),
+  );
 
+  it.effect("preserves read errors instead of treating an unavailable pipe as optional", () =>
+    Effect.gen(function* () {
+      const { fd, stream, reading } = yield* openControlledBootstrapInput;
-        const fiber = yield* readBootstrapEnvelope(TestEnvelopeSchema, fd, {
-          timeoutMs: 100,
-        }).pipe(Effect.forkScoped);
+      const cause = Object.assign(new Error("closed fd"), { code: "EBADF" });
+      const fiber = yield* readBootstrapEnvelope(TestEnvelopeSchema, fd).pipe(
+        Effect.provideService(HostProcess.Platform, "win32"),
+        Effect.flip,
+        Effect.forkScoped,
+      );
 
-        yield* Effect.yieldNow;
-        yield* TestClock.adjust(Duration.millis(100));
+      yield* Deferred.await(reading);
+      stream.destroy(cause);
 
+      const error = yield* Fiber.join(fiber);
+      assert.instanceOf(error, BootstrapEnvelopeReadError);
+      assert.equal(error.fd, fd);
+      assert.equal(error.cause, cause);
+      assert.isTrue(stream.destroyed);
-        const payload = yield* Fiber.join(fiber);
-        assertNone(payload);
-      }).pipe(Effect.provide(TestClock.layer())),
+    }),
   );
 });
```

## apps/server/src/bootstrap.ts

Status: modified; +45; −37

```diff
@@ -5,7 +5,6 @@
 import type * as NodeStream from "node:stream";
 
 import * as Effect from "effect/Effect";
-import * as Option from "effect/Option";
 import * as Predicate from "effect/Predicate";
 import * as Result from "effect/Result";
 import * as Schema from "effect/Schema";
@@ -63,11 +62,31 @@
   }
 }
 
+export class BootstrapEnvelopeMissingError extends Schema.TaggedError<BootstrapEnvelopeMissingError>()(
+  "BootstrapEnvelopeMissingError",
+  { fd: Schema.Number },
+) {
+  override get message(): string {
+    return `Bootstrap input on file descriptor ${this.fd} closed without an envelope.`;
+  }
+}
+
+export class BootstrapEnvelopeTimeoutError extends Schema.TaggedError<BootstrapEnvelopeTimeoutError>()(
+  "BootstrapEnvelopeTimeoutError",
+  { fd: Schema.Number, timeoutMs: Schema.Number },
+) {
+  override get message(): string {
+    return `Timed out waiting for bootstrap envelope from file descriptor ${this.fd} after ${this.timeoutMs} ms.`;
+  }
+}
+
 export const BootstrapError = Schema.Union([
   BootstrapFdStatError,
   BootstrapInputStreamOpenError,
   BootstrapEnvelopeReadError,
   BootstrapEnvelopeDecodeError,
+  BootstrapEnvelopeMissingError,
+  BootstrapEnvelopeTimeoutError,
 ]);
 export type BootstrapError = typeof BootstrapError.Type;
 
@@ -77,17 +96,21 @@
   options?: {
     timeoutMs?: number;
   },
+): Effect.fn.Return<A, BootstrapError> {
+  yield* Effect.try({
-): Effect.fn.Return<Option.Option<A>, BootstrapError> {
-  const fdReady = yield* isFdReady(fd);
-  if (!fdReady) return Option.none();
+    try: () => NodeFS.fstatSync(fd),
+    catch: (cause) => new BootstrapFdStatError({ fd, cause }),
+  });
 
   const stream = yield* makeBootstrapInputStream(fd);
 
-  const timeoutMs = options?.timeoutMs ?? 1000;
+  // An explicit bootstrap fd is required startup input. Allow cold reads time
+  // to complete, but fail before the desktop's one-minute readiness deadline.
+  const timeoutMs = options?.timeoutMs ?? 30_000;
 
   return yield* Effect.callback<
+    A,
-    Option.Option<A>,
-    BootstrapEnvelopeReadError | BootstrapEnvelopeDecodeError
+    BootstrapEnvelopeReadError | BootstrapEnvelopeDecodeError | BootstrapEnvelopeMissingError
   >((resume) => {
     const input = NodeReadline.createInterface({
       input: stream,
@@ -95,19 +118,20 @@
     });
 
     const cleanup = () => {
+      input.removeListener("error", handleError);
-      stream.removeListener("error", handleError);
       input.removeListener("line", handleLine);
       input.removeListener("close", handleClose);
       input.close();
       stream.destroy();
     };
 
+    const finish = (result: Parameters<typeof resume>[0]) => {
+      cleanup();
+      resume(result);
+    };
+
     const handleError = (error: Error) => {
-      if (isUnavailableBootstrapFdError(error)) {
+      finish(
-        resume(Effect.succeedNone);
-        return;
-      }
-      resume(
         Effect.fail(
           new BootstrapEnvelopeReadError({
             fd,
@@ -120,9 +144,9 @@
     const handleLine = (line: string) => {
       const parsed = decodeJsonResult(schema)(line);
       if (Result.isSuccess(parsed)) {
-        resume(Effect.succeedSome(parsed.success));
+        finish(Effect.succeed(parsed.success));
       } else {
-        resume(
+        finish(
           Effect.fail(
             new BootstrapEnvelopeDecodeError({
               fd,
@@ -134,37 +158,21 @@
     };
 
     const handleClose = () => {
+      finish(Effect.fail(new BootstrapEnvelopeMissingError({ fd })));
-      resume(Effect.succeedNone);
     };
 
-    stream.once("error", handleError);
+    input.once("error", handleError);
     input.once("line", handleLine);
     input.once("close", handleClose);
 
     return Effect.sync(cleanup);
-  }).pipe(Effect.timeoutOption(timeoutMs), Effect.map(Option.flatten));
-});
-
-const isUnavailableBootstrapFdError = Predicate.compose(
-  Predicate.hasProperty("code"),
-  (_) => _.code === "EBADF" || _.code === "ENOENT",
-);
-
-const isFdReady = (fd: number) =>
-  Effect.try({
-    try: () => NodeFS.fstatSync(fd),
-    catch: (error) =>
-      new BootstrapFdStatError({
-        fd,
-        cause: error,
-      }),
   }).pipe(
-    Effect.as(true),
-    Effect.catchTags({
-      BootstrapFdStatError: (error) =>
+    Effect.timeoutOrElse({
+      duration: timeoutMs,
+      orElse: () => Effect.fail(new BootstrapEnvelopeTimeoutError({ fd, timeoutMs })),
-        isUnavailableBootstrapFdError(error.cause) ? Effect.succeed(false) : Effect.fail(error),
     }),
   );
+});
 
 const makeBootstrapInputStream = Effect.fn("bootstrap.makeBootstrapInputStream")(function* (
   fd: number,
```

## apps/server/src/cli/config.test.ts

Status: modified; +45; −2

```diff
@@ -23,6 +23,7 @@
 import { DEFAULT_SIGNAL_EXPORT } from "@t3tools/shared/observability";
 import * as OtelEnvironment from "@t3tools/shared/otelEnvironment";
 import * as NodeServices from "@effect/platform-node/NodeServices";
+import { BootstrapFdStatError } from "../bootstrap.ts";
 import { deriveServerPaths } from "../config.ts";
 import { resolveServerConfig } from "./config.ts";
 
@@ -625,7 +626,7 @@
     }),
   );
 
+  it.effect("creates runtime directories with web defaults without a bootstrap fd", () =>
-  it.effect("creates derived runtime directories during config resolution", () =>
     Effect.gen(function* () {
       const fs = yield* FileSystem.FileSystem;
       const path = yield* Path.Path;
@@ -634,7 +635,7 @@
 
       const resolved = yield* resolveServerConfig(
         {
-          mode: Option.some("desktop"),
+          mode: Option.none(),
           port: Option.some(4888),
           host: Option.none(),
           baseDir: Option.some(baseDir),
@@ -670,6 +671,10 @@
         expect(yield* fs.exists(directory)).toBe(true);
       }
       expect(resolved.cwd).toBe(path.resolve(customCwd));
+      expect(resolved.mode).toBe("web");
+      expect(resolved.noBrowser).toBe(false);
+      expect(resolved.autoBootstrapProjectFromCwd).toBe(true);
+      expect(resolved.desktopBootstrapToken).toBeUndefined();
     }),
   );
 
@@ -1166,6 +1171,44 @@
     tailscaleServePort: Option.none<number>(),
   });
 
+  it.effect.each(["flag", "env"] as const)(
+    "rejects an unavailable bootstrap fd from %s before creating server state",
+    (source) =>
+      Effect.gen(function* () {
+        const fs = yield* FileSystem.FileSystem;
+        const path = yield* Path.Path;
+        const root = yield* fs.makeTempDirectoryScoped({ prefix: "t3-cli-bootstrap-required-" });
+        const baseDir = path.join(root, "server-home");
+        const fd = 2_147_483_647;
+
+        const result = yield* resolveServerConfig(
+          {
+            ...minimalWebFlags(baseDir),
+            mode: Option.none(),
+            bootstrapFd: source === "flag" ? Option.some(fd) : Option.none(),
+          },
+          Option.none(),
+        ).pipe(
+          Effect.provide(
+            Layer.mergeAll(
+              NetService.layer,
+              ConfigProvider.layer(
+                ConfigProvider.fromEnv({
+                  env: source === "env" ? { T3CODE_BOOTSTRAP_FD: String(fd) } : {},
+                }),
+              ),
+            ),
+          ),
+          Effect.result,
+        );
+
+        expect(yield* fs.exists(baseDir)).toBe(false);
+        assert(Result.isFailure(result));
+        assert.instanceOf(result.failure, BootstrapFdStatError);
+        assert.equal(result.failure.fd, fd);
+      }),
+  );
+
   it.effect(
     "resolves each signal's endpoint through T3CODE_OTLP_*_URL, an OTEL endpoint, the bootstrap envelope, and persisted Settings, in that order",
     () =>
```

## apps/server/src/cli/config.ts

Status: modified; +2; −3

```diff
@@ -277,11 +277,10 @@
     tailscaleServePort: flags.tailscaleServePort ?? Option.none(),
   } satisfies CliServerFlags;
   const bootstrapFd = Option.getOrUndefined(normalizedFlags.bootstrapFd) ?? env.bootstrapFd;
-  const bootstrapEnvelope =
+  const bootstrap =
     bootstrapFd !== undefined
       ? yield* readBootstrapEnvelope(DesktopBackendBootstrap, bootstrapFd)
+      : undefined;
-      : Option.none();
-  const bootstrap = Option.getOrUndefined(bootstrapEnvelope);
 
   const mode: ServerConfig.RuntimeMode = Option.getOrElse(
     resolveOptionPrecedence(
```
