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 Schema from "effect/Schema"; 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"; const PersistedServerObservabilitySettingsDocument = Schema.Struct({ observability: Schema.Struct({ otlpTracesUrl: Schema.String, otlpMetricsUrl: Schema.String, }),}); const encodePersistedServerObservabilitySettingsDocument = Schema.encodeEffect( Schema.fromJsonString(PersistedServerObservabilitySettingsDocument),); 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.DesktopServerExposureShape); function makeEnvironmentLayer( baseDir: string, options?: { readonly isPackaged?: boolean; readonly devServerUrl?: string; },) { return DesktopEnvironment.layer({ dirname: "/repo/apps/desktop/src", homeDirectory: baseDir, platform: "darwin", processArch: "x64", appVersion: "1.2.3", appPath: "/repo", isPackaged: options?.isPackaged ?? true, 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 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(makeEnvironmentLayer(baseDir)), ), ), ); }).pipe(Effect.scoped, Effect.provide(NodeServices.layer)); describe("DesktopBackendConfiguration", () => { it.effect("resolves backend start config with a stable scoped bootstrap token", () => withHarness( Effect.gen(function* () { const environment = yield* DesktopEnvironment.DesktopEnvironment; const configuration = yield* DesktopBackendConfiguration.DesktopBackendConfiguration; const first = yield* configuration.resolve; const second = yield* configuration.resolve; 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("includes persisted backend observability endpoints when present", () => 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.resolve; 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("omits backend observability endpoints when settings are missing", () => withHarness( Effect.gen(function* () { const configuration = yield* DesktopBackendConfiguration.DesktopBackendConfiguration; const config = yield* configuration.resolve; assert.isUndefined(config.bootstrap.otlpTracesUrl); assert.isUndefined(config.bootstrap.otlpMetricsUrl); }), ), ); it.effect("captures backend output in development so child process 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.resolve; assert.equal(config.captureOutput, true); }).pipe( Effect.provide( DesktopBackendConfiguration.layer.pipe( Layer.provideMerge(serverExposureLayer), Layer.provideMerge( makeEnvironmentLayer(baseDir, { isPackaged: false, devServerUrl: "http://127.0.0.1:5733", }), ), ), ), ); }).pipe(Effect.scoped, Effect.provide(NodeServices.layer)), );});
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 Schema from "effect/Schema";
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";
const PersistedServerObservabilitySettingsDocument = Schema.Struct({
observability: Schema.Struct({
otlpTracesUrl: Schema.String,
otlpMetricsUrl: Schema.String,
}),
});
const encodePersistedServerObservabilitySettingsDocument = Schema.encodeEffect(
Schema.fromJsonString(PersistedServerObservabilitySettingsDocument),
);
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.DesktopServerExposureShape);
function makeEnvironmentLayer(
baseDir: string,
options?: {
readonly isPackaged?: boolean;
readonly devServerUrl?: string;
},
) {
return DesktopEnvironment.layer({
dirname: "/repo/apps/desktop/src",
homeDirectory: baseDir,
platform: "darwin",
processArch: "x64",
appVersion: "1.2.3",
appPath: "/repo",
isPackaged: options?.isPackaged ?? true,
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 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(makeEnvironmentLayer(baseDir)),
),
),
);
}).pipe(Effect.scoped, Effect.provide(NodeServices.layer));
describe("DesktopBackendConfiguration", () => {
it.effect("resolves backend start config with a stable scoped bootstrap token", () =>
withHarness(
Effect.gen(function* () {
const environment = yield* DesktopEnvironment.DesktopEnvironment;
const configuration = yield* DesktopBackendConfiguration.DesktopBackendConfiguration;
const first = yield* configuration.resolve;
const second = yield* configuration.resolve;
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("includes persisted backend observability endpoints when present", () =>
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.resolve;
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("omits backend observability endpoints when settings are missing", () =>
withHarness(
Effect.gen(function* () {
const configuration = yield* DesktopBackendConfiguration.DesktopBackendConfiguration;
const config = yield* configuration.resolve;
assert.isUndefined(config.bootstrap.otlpTracesUrl);
assert.isUndefined(config.bootstrap.otlpMetricsUrl);
}),
),
);
it.effect("captures backend output in development so child process 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.resolve;
assert.equal(config.captureOutput, true);
}).pipe(
Effect.provide(
DesktopBackendConfiguration.layer.pipe(
Layer.provideMerge(serverExposureLayer),
Layer.provideMerge(
makeEnvironmentLayer(baseDir, {
isPackaged: false,
devServerUrl: "http://127.0.0.1:5733",
}),
),
),
),
);
}).pipe(Effect.scoped, Effect.provide(NodeServices.layer)),
);
});