799 lines · 32.6 KB · TypeScript
RawDownload
import * as NodeServices from "@effect/platform-node/NodeServices";import { assert, describe, it } from "@effect/vitest";import * as Effect from "effect/Effect";import * as FileSystem from "effect/FileSystem";import * as Layer from "effect/Layer";import * as Logger from "effect/Logger";import * as ManagedRuntime from "effect/ManagedRuntime";import * as Option from "effect/Option";import * as Path from "effect/Path";import * as PlatformError from "effect/PlatformError";import * as Schema from "effect/Schema";import { ChildProcessSpawner } from "effect/unstable/process"; import * as DesktopEnvironment from "../app/DesktopEnvironment.ts";import * as DesktopBackendConfiguration from "./DesktopBackendConfiguration.ts";import * as DesktopConfig from "../app/DesktopConfig.ts";import * as DesktopServerExposure from "./DesktopServerExposure.ts";import * as DesktopAppSettings from "../settings/DesktopAppSettings.ts";import * as DesktopWslEnvironment from "../wsl/DesktopWslEnvironment.ts"; const PersistedServerObservabilitySettingsDocument = Schema.Struct({  observability: Schema.Struct({    otlpTracesUrl: Schema.String,    otlpMetricsUrl: Schema.String,  }),}); const encodePersistedServerObservabilitySettingsDocument = Schema.encodeEffect(  Schema.fromJsonString(PersistedServerObservabilitySettingsDocument),); const isDesktopBackendObservabilitySettingsReadError = Schema.is(  DesktopBackendConfiguration.DesktopBackendObservabilitySettingsReadError,); const serverExposureLayer = Layer.succeed(DesktopServerExposure.DesktopServerExposure, {  getState: Effect.die("unexpected getState"),  backendConfig: Effect.succeed({    port: 4888,    bindHost: "0.0.0.0",    httpBaseUrl: new URL("http://127.0.0.1:4888"),    tailscaleServeEnabled: true,    tailscaleServePort: 8443,  }),  configureFromSettings: () => Effect.die("unexpected configureFromSettings"),  setMode: () => Effect.die("unexpected setMode"),  setTailscaleServeEnabled: () => Effect.die("unexpected setTailscaleServeEnabled"),  getAdvertisedEndpoints: Effect.succeed([]),} satisfies DesktopServerExposure.DesktopServerExposure["Service"]); function makeEnvironmentLayer(  baseDir: string,  options?: {    readonly appPath?: string;    readonly isPackaged?: boolean;    readonly devServerUrl?: string;    readonly platform?: NodeJS.Platform;    readonly resourcesPath?: string;  },) {  return DesktopEnvironment.layer({    dirname: "/repo/apps/desktop/src",    homeDirectory: baseDir,    platform: options?.platform ?? "darwin",    processArch: "x64",    appVersion: "1.2.3",    appPath: options?.appPath ?? "/repo",    isPackaged: options?.isPackaged ?? true,    resourcesPath: options?.resourcesPath ?? "/missing/resources",    runningUnderArm64Translation: false,  }).pipe(    Layer.provide(      Layer.mergeAll(        NodeServices.layer,        DesktopConfig.layerTest({          T3CODE_HOME: baseDir,          T3CODE_PORT: "9999",          T3CODE_MODE: "desktop",          T3CODE_DESKTOP_LAN_HOST: "192.168.1.50",          VITE_DEV_SERVER_URL: options?.devServerUrl,        }),      ),    ),  );} const restoreEnv = (name: string, value: string | undefined) => {  if (value === undefined) {    delete process.env[name];  } else {    process.env[name] = value;  }}; const withHarness = <A, E, R>(  effect: Effect.Effect<    A,    E,    | R    | DesktopEnvironment.DesktopEnvironment    | FileSystem.FileSystem    | DesktopBackendConfiguration.DesktopBackendConfiguration  >,) =>  Effect.gen(function* () {    const fileSystem = yield* FileSystem.FileSystem;    const baseDir = yield* fileSystem.makeTempDirectoryScoped({      prefix: "t3-desktop-backend-config-test-",    });     return yield* effect.pipe(      Effect.provide(        DesktopBackendConfiguration.layer.pipe(          Layer.provideMerge(serverExposureLayer),          Layer.provideMerge(DesktopAppSettings.layerTest()),          Layer.provideMerge(DesktopWslEnvironment.layerTest()),          Layer.provideMerge(makeEnvironmentLayer(baseDir)),        ),      ),    );  }).pipe(Effect.scoped, Effect.provide(NodeServices.layer)); describe("DesktopBackendConfiguration", () => {  it.effect("resolvePrimary produces a stable scoped bootstrap token", () =>    withHarness(      Effect.gen(function* () {        const environment = yield* DesktopEnvironment.DesktopEnvironment;        const configuration = yield* DesktopBackendConfiguration.DesktopBackendConfiguration;         const first = yield* configuration.resolvePrimary;        const second = yield* configuration.resolvePrimary;         assert.equal(first.executablePath, process.execPath);        assert.equal(first.entryPath, environment.backendEntryPath);        assert.equal(first.cwd, environment.backendCwd);        assert.equal(first.captureOutput, true);        assert.equal(first.env.ELECTRON_RUN_AS_NODE, "1");        assert.isUndefined(first.env.T3CODE_PORT);        assert.isUndefined(first.env.T3CODE_MODE);        assert.isUndefined(first.env.T3CODE_DESKTOP_LAN_HOST);         assert.equal(first.bootstrap.mode, "desktop");        assert.equal(first.bootstrap.noBrowser, true);        assert.equal(first.bootstrap.port, 4888);        assert.equal(first.bootstrap.host, "0.0.0.0");        assert.equal(first.bootstrap.t3Home, environment.baseDir);        assert.equal(first.bootstrap.tailscaleServeEnabled, true);        assert.equal(first.bootstrap.tailscaleServePort, 8443);        assert.match(first.bootstrap.desktopBootstrapToken, /^[0-9a-f]{48}$/i);        assert.equal(second.bootstrap.desktopBootstrapToken, first.bootstrap.desktopBootstrapToken);      }),    ),  );   it.effect("resolveWsl reuses the primary's bootstrap token", () =>    withHarness(      Effect.gen(function* () {        const configuration = yield* DesktopBackendConfiguration.DesktopBackendConfiguration;         const primary = yield* configuration.resolvePrimary;        const wsl = yield* configuration.resolveWsl({ port: 5000, distro: null });         assert.equal(wsl.bootstrap.desktopBootstrapToken, primary.bootstrap.desktopBootstrapToken);      }),    ),  );   it.effect("resolveWsl pins a default-tracking run to the concrete default distro", () =>    Effect.gen(function* () {      const fileSystem = yield* FileSystem.FileSystem;      const path = yield* Path.Path;      const baseDir = yield* fileSystem.makeTempDirectoryScoped({        prefix: "t3-desktop-backend-config-test-",      });      const entryPath = path.join(baseDir, "app.asar.unpacked/apps/server/dist/bin.mjs");      yield* fileSystem.makeDirectory(path.dirname(entryPath), { recursive: true });      yield* fileSystem.writeFileString(entryPath, "");       const observedDistros: Array<string | null> = [];      const config = yield* Effect.gen(function* () {        const configuration = yield* DesktopBackendConfiguration.DesktopBackendConfiguration;        return yield* configuration.resolveWsl({ port: 5000, distro: null });      }).pipe(        Effect.provide(          DesktopBackendConfiguration.layer.pipe(            Layer.provideMerge(serverExposureLayer),            Layer.provideMerge(DesktopAppSettings.layerTest()),            Layer.provideMerge(              DesktopWslEnvironment.layerTest({                isAvailable: true,                distros: [                  { name: "Debian", isDefault: false, version: 2 },                  { name: "Ubuntu", isDefault: true, version: 2 },                ],                windowsToWslPath: (distro) => {                  observedDistros.push(distro);                  return Option.some("/repo/apps/server/dist/bin.mjs");                },                ensureNodePty: (distro) => {                  observedDistros.push(distro);                  return { ok: true, nodePath: "/usr/bin/node", resolvedPath: "/usr/bin:/bin" };                },                getDistroIp: (distro) => {                  observedDistros.push(distro);                  return Option.some("172.27.0.99");                },              }),            ),            Layer.provideMerge(              makeEnvironmentLayer(baseDir, {                appPath: baseDir,                platform: "win32",                resourcesPath: baseDir,              }),            ),          ),        ),      );       assert.equal(config.runningDistro, "Ubuntu");      assert.deepEqual(config.args.slice(0, 2), ["-d", "Ubuntu"]);      assert.deepEqual(observedDistros, ["Ubuntu", "Ubuntu", "Ubuntu"]);      assert.isTrue(Option.isNone(config.preflightFailure));    }).pipe(Effect.scoped, Effect.provide(NodeServices.layer)),  );   it.effect(    "resolveWsl preserves inherited PATH with quote-sensitive values as separate args",    () =>      Effect.gen(function* () {        const fileSystem = yield* FileSystem.FileSystem;        const path = yield* Path.Path;        const baseDir = yield* fileSystem.makeTempDirectoryScoped({          prefix: "t3-desktop-backend-config-test-",        });        const entryPath = path.join(baseDir, "app.asar.unpacked/apps/server/dist/bin.mjs");        yield* fileSystem.makeDirectory(path.dirname(entryPath), { recursive: true });        yield* fileSystem.writeFileString(entryPath, "");         const nodePath = "/home/test user's/.nvm/versions/node/v22.0.0/bin/node";        const linuxEntryPath = "/tmp/t3 code's launch/entry file.mjs";        const resolvedPath = "/home/test user/bin:/opt/test's tools/bin:/usr/bin:/bin";        const devServerUrl = "http://127.0.0.1:5733/dev%20assets/?label=hello%20world";        const config = yield* Effect.gen(function* () {          const configuration = yield* DesktopBackendConfiguration.DesktopBackendConfiguration;          return yield* configuration.resolveWsl({ port: 5000, distro: "Ubuntu" });        }).pipe(          Effect.provide(            DesktopBackendConfiguration.layer.pipe(              Layer.provideMerge(serverExposureLayer),              Layer.provideMerge(DesktopAppSettings.layerTest()),              Layer.provideMerge(                DesktopWslEnvironment.layerTest({                  isAvailable: true,                  distros: [{ name: "Ubuntu", isDefault: true, version: 2 }],                  windowsToWslPath: () => Option.some(linuxEntryPath),                  ensureNodePty: () => ({ ok: true, nodePath, resolvedPath }),                  getDistroIp: () => Option.some("172.27.0.99"),                }),              ),              Layer.provideMerge(                makeEnvironmentLayer(baseDir, {                  appPath: baseDir,                  devServerUrl,                  isPackaged: true,                  platform: "win32",                  resourcesPath: baseDir,                }),              ),            ),          ),        );         assert.equal(config.bootstrapDelivery, "stdin");        assert.deepEqual(config.args, [          "-d",          "Ubuntu",          "--exec",          "env",          "PATH=/home/test user's/.nvm/versions/node/v22.0.0/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/home/test user/bin:/opt/test's tools/bin:/usr/bin:/bin",          nodePath,          linuxEntryPath,          "--bootstrap-fd",          "0",          "--dev-url",          devServerUrl,        ]);        assert.notInclude(config.args, "bash");        assert.notInclude(config.args, "/bin/sh");        assert.notInclude(config.args, "-c");        assert.isTrue(Option.isNone(config.preflightFailure));      }).pipe(Effect.scoped, Effect.provide(NodeServices.layer)),  );   it.effect("resolvePrimary and resolveWsl share one token under concurrent resolution", () =>    withHarness(      Effect.gen(function* () {        const configuration = yield* DesktopBackendConfiguration.DesktopBackendConfiguration;         // Resolve both before any token is cached, concurrently, so the        // generate step (a yield point) can interleave. The atomic        // get-or-create must still hand both the same token; a non-atomic        // Ref would let each generate its own and break the shared-token        // invariant.        const [primary, wsl] = yield* Effect.all(          [configuration.resolvePrimary, configuration.resolveWsl({ port: 5000, distro: null })],          { concurrency: "unbounded" },        );         assert.equal(wsl.bootstrap.desktopBootstrapToken, primary.bootstrap.desktopBootstrapToken);      }),    ),  );   it.effect("resolvePrimary surfaces persisted backend observability endpoints", () =>    withHarness(      Effect.gen(function* () {        const fileSystem = yield* FileSystem.FileSystem;        const environment = yield* DesktopEnvironment.DesktopEnvironment;        const configuration = yield* DesktopBackendConfiguration.DesktopBackendConfiguration;         yield* fileSystem.makeDirectory(environment.path.dirname(environment.serverSettingsPath), {          recursive: true,        });        yield* fileSystem.writeFileString(          environment.serverSettingsPath,          yield* encodePersistedServerObservabilitySettingsDocument({            observability: {              otlpTracesUrl: " http://127.0.0.1:4318/v1/traces ",              otlpMetricsUrl: " http://127.0.0.1:4318/v1/metrics ",            },          }),        );         const config = yield* configuration.resolvePrimary;        assert.equal(config.bootstrap.otlpTracesUrl, "http://127.0.0.1:4318/v1/traces");        assert.equal(config.bootstrap.otlpMetricsUrl, "http://127.0.0.1:4318/v1/metrics");      }),    ),  );   it.effect("resolvePrimary omits backend observability endpoints when settings are missing", () =>    withHarness(      Effect.gen(function* () {        const configuration = yield* DesktopBackendConfiguration.DesktopBackendConfiguration;        const config = yield* configuration.resolvePrimary;         assert.isUndefined(config.bootstrap.otlpTracesUrl);        assert.isUndefined(config.bootstrap.otlpMetricsUrl);      }),    ),  );   it.effect("logs structured context when persisted observability settings cannot be read", () =>    Effect.gen(function* () {      const fileSystem = yield* FileSystem.FileSystem;      const path = yield* Path.Path;      const baseDir = yield* fileSystem.makeTempDirectoryScoped({        prefix: "t3-desktop-backend-config-test-",      });      const settingsPath = path.join(baseDir, "userdata", "settings.json");      const cause = PlatformError.systemError({        _tag: "PermissionDenied",        module: "FileSystem",        method: "readFileString",        pathOrDescriptor: settingsPath,      });      const messages: Array<unknown> = [];      const logger = Logger.make(({ message }) => {        messages.push(message);      });      const failingFileSystemLayer = Layer.succeed(        FileSystem.FileSystem,        FileSystem.makeNoop({          readFileString: () => Effect.fail(cause),        }),      );       const config = yield* Effect.gen(function* () {        const configuration = yield* DesktopBackendConfiguration.DesktopBackendConfiguration;        return yield* configuration.resolvePrimary;      }).pipe(        Effect.provide(          Layer.mergeAll(            DesktopBackendConfiguration.layer.pipe(              Layer.provideMerge(serverExposureLayer),              Layer.provideMerge(DesktopAppSettings.layerTest()),              Layer.provideMerge(DesktopWslEnvironment.layerTest()),              Layer.provideMerge(makeEnvironmentLayer(baseDir)),              Layer.provideMerge(failingFileSystemLayer),            ),            Logger.layer([logger], { mergeWithExisting: false }),          ),        ),      );       assert.isUndefined(config.bootstrap.otlpTracesUrl);      assert.isUndefined(config.bootstrap.otlpMetricsUrl);       const error = messages        .flatMap((message) => (Array.isArray(message) ? message : [message]))        .find(isDesktopBackendObservabilitySettingsReadError);      assert.isDefined(error);      assert.equal(error.settingsPath, settingsPath);      assert.equal(error.cause, cause);      assert.equal(        error.message,        `Failed to read persisted backend observability settings at ${settingsPath}.`,      );    }).pipe(Effect.scoped, Effect.provide(NodeServices.layer)),  );   it.effect("resolvePrimary captures backend output in dev so child logs can be persisted", () =>    Effect.gen(function* () {      const fileSystem = yield* FileSystem.FileSystem;      const baseDir = yield* fileSystem.makeTempDirectoryScoped({        prefix: "t3-desktop-backend-config-test-",      });       yield* Effect.gen(function* () {        const configuration = yield* DesktopBackendConfiguration.DesktopBackendConfiguration;        const config = yield* configuration.resolvePrimary;        assert.equal(config.captureOutput, true);      }).pipe(        Effect.provide(          DesktopBackendConfiguration.layer.pipe(            Layer.provideMerge(serverExposureLayer),            Layer.provideMerge(DesktopAppSettings.layerTest()),            Layer.provideMerge(DesktopWslEnvironment.layerTest()),            Layer.provideMerge(              makeEnvironmentLayer(baseDir, {                isPackaged: false,                devServerUrl: "http://127.0.0.1:5733",              }),            ),          ),        ),      );    }).pipe(Effect.scoped, Effect.provide(NodeServices.layer)),  );   it.effect("resolveWsl preserves existing WSLENV entries when forwarding backend secrets", () =>    Effect.gen(function* () {      const fileSystem = yield* FileSystem.FileSystem;      const baseDir = yield* fileSystem.makeTempDirectoryScoped({        prefix: "t3-desktop-backend-config-test-",      });       const previousWslEnv = process.env.WSLENV;      const previousOpenAiKey = process.env.OPENAI_API_KEY;      const previousAnthropicKey = process.env.ANTHROPIC_API_KEY;      try {        process.env.WSLENV = "GOPATH/p:OPENAI_API_KEY/u:EMPTY::AZURE_DEVOPS_EXT_PAT/u";        process.env.OPENAI_API_KEY = "openai-key";        process.env.ANTHROPIC_API_KEY = "anthropic-key";         yield* Effect.gen(function* () {          const configuration = yield* DesktopBackendConfiguration.DesktopBackendConfiguration;          const config = yield* configuration.resolveWsl({ port: 5050, distro: null });           assert.equal(config.executablePath, "wsl.exe");          assert.equal(config.bootstrap.port, 5050);          // Binds to 0.0.0.0 inside WSL so the backend is reachable via          // both wslhost-forwarded localhost and the distro's eth0 IP.          assert.equal(config.bootstrap.host, "0.0.0.0");          assert.equal(config.bootstrap.tailscaleServeEnabled, false);          // httpBaseUrl uses the resolved distro IP from the test stub,          // not localhost — the renderer reaches the backend directly to          // avoid relying on wslhost forwarding.          assert.equal(config.httpBaseUrl.href, "http://172.27.0.99:5050/");          assert.equal(config.env.OPENAI_API_KEY, "openai-key");          assert.equal(config.env.ANTHROPIC_API_KEY, "anthropic-key");          // The existing WSLENV is preserved byte-for-byte (note the empty          // "::" segment survives — WSL ignores it, so we don't normalize          // it away) and ANTHROPIC_API_KEY is appended. OPENAI_API_KEY is          // already declared, so it isn't forwarded twice.          assert.equal(            config.env.WSLENV,            "GOPATH/p:OPENAI_API_KEY/u:EMPTY::AZURE_DEVOPS_EXT_PAT/u:ANTHROPIC_API_KEY",          );        }).pipe(          Effect.provide(            DesktopBackendConfiguration.layer.pipe(              Layer.provideMerge(serverExposureLayer),              Layer.provideMerge(DesktopAppSettings.layerTest()),              Layer.provideMerge(                DesktopWslEnvironment.layerTest({                  isAvailable: true,                  windowsToWslPath: () => Option.some("/mnt/c/repo/apps/server/src/index.ts"),                  getDistroIp: () => Option.some("172.27.0.99"),                }),              ),              Layer.provideMerge(makeEnvironmentLayer(baseDir, { platform: "win32" })),            ),          ),        );      } finally {        restoreEnv("WSLENV", previousWslEnv);        restoreEnv("OPENAI_API_KEY", previousOpenAiKey);        restoreEnv("ANTHROPIC_API_KEY", previousAnthropicKey);

Lines 1–500 of 799.