import * as Http from "node:http";import * as NodeServices from "@effect/platform-node/NodeServices";import { assert, it, vi } from "@effect/vitest";import * as ConfigProvider from "effect/ConfigProvider";import * as Effect from "effect/Effect";import * as Layer from "effect/Layer";import * as Command from "effect/unstable/cli/Command";import { beforeEach } from "vitest"; import { CliConfig, t3Cli, type CliConfigShape } from "./main";import { NetService, ServerConfig, type ServerConfigShape } from "./config";import { Open, type OpenShape } from "./open";import { Server, type ServerShape } from "./wsServer"; const start = vi.fn(() => undefined);const stop = vi.fn(() => undefined);let resolvedConfig: ServerConfigShape | null = null;const serverStart = Effect.acquireRelease( Effect.gen(function* () { resolvedConfig = yield* ServerConfig; start(); return {} as unknown as Http.Server; }), () => Effect.sync(() => stop()),);const findAvailablePort = vi.fn((preferred: number) => Effect.succeed(preferred)); // Shared service layer used by this CLI test suite.const testLayer = Layer.mergeAll( Layer.succeed(CliConfig, { cwd: "/tmp/t3-test-workspace", fixPath: Effect.void, resolveStaticDir: Effect.undefined, } satisfies CliConfigShape), Layer.succeed(NetService, { findAvailablePort, }), Layer.succeed(Server, { start: serverStart, stopSignal: Effect.void, } satisfies ServerShape), Layer.succeed(Open, { openBrowser: (_target: string) => Effect.void, openInEditor: () => Effect.void, } satisfies OpenShape), NodeServices.layer,); const runCli = ( args: ReadonlyArray<string>, env: Record<string, string> = { T3CODE_NO_BROWSER: "true" },) => Command.runWith(t3Cli, { version: "0.0.0-test" })(args).pipe( Effect.provide(ConfigProvider.layer(ConfigProvider.fromEnv({ env }))), ); beforeEach(() => { vi.clearAllMocks(); resolvedConfig = null; start.mockImplementation(() => undefined); stop.mockImplementation(() => undefined); findAvailablePort.mockImplementation((preferred: number) => Effect.succeed(preferred));}); it.layer(testLayer)("server CLI command", (it) => { it.effect("parses all CLI flags and wires scoped start/stop", () => Effect.gen(function* () { yield* runCli([ "--mode", "desktop", "--port", "4010", "--host", "0.0.0.0", "--state-dir", "/tmp/t3-cli-state", "--dev-url", "http://127.0.0.1:5173", "--no-browser", "--auth-token", "auth-secret", ]); assert.equal(start.mock.calls.length, 1); assert.equal(resolvedConfig?.mode, "desktop"); assert.equal(resolvedConfig?.port, 4010); assert.equal(resolvedConfig?.host, "0.0.0.0"); assert.equal(resolvedConfig?.stateDir, "/tmp/t3-cli-state"); assert.equal(resolvedConfig?.devUrl?.toString(), "http://127.0.0.1:5173/"); assert.equal(resolvedConfig?.noBrowser, true); assert.equal(resolvedConfig?.authToken, "auth-secret"); assert.equal(resolvedConfig?.autoBootstrapProjectFromCwd, false); assert.equal(resolvedConfig?.logWebSocketEvents, true); assert.equal(stop.mock.calls.length, 1); }), ); it.effect("supports --token as an alias for --auth-token", () => Effect.gen(function* () { yield* runCli(["--token", "token-secret"]); assert.equal(start.mock.calls.length, 1); assert.equal(resolvedConfig?.authToken, "token-secret"); }), ); it.effect("uses env fallbacks when flags are not provided", () => Effect.gen(function* () { yield* runCli([], { T3CODE_MODE: "desktop", T3CODE_PORT: "4999", T3CODE_HOST: "100.88.10.4", T3CODE_STATE_DIR: "/tmp/t3-env-state", VITE_DEV_SERVER_URL: "http://localhost:5173", T3CODE_NO_BROWSER: "true", T3CODE_AUTH_TOKEN: "env-token", }); assert.equal(start.mock.calls.length, 1); assert.equal(resolvedConfig?.mode, "desktop"); assert.equal(resolvedConfig?.port, 4999); assert.equal(resolvedConfig?.host, "100.88.10.4"); assert.equal(resolvedConfig?.stateDir, "/tmp/t3-env-state"); assert.equal(resolvedConfig?.devUrl?.toString(), "http://localhost:5173/"); assert.equal(resolvedConfig?.noBrowser, true); assert.equal(resolvedConfig?.authToken, "env-token"); assert.equal(resolvedConfig?.autoBootstrapProjectFromCwd, false); assert.equal(resolvedConfig?.logWebSocketEvents, true); assert.equal(findAvailablePort.mock.calls.length, 0); }), ); it.effect("prefers --mode over T3CODE_MODE", () => Effect.gen(function* () { findAvailablePort.mockImplementation((_preferred: number) => Effect.succeed(4666)); yield* runCli(["--mode", "web"], { T3CODE_MODE: "desktop", T3CODE_NO_BROWSER: "true", }); assert.deepStrictEqual(findAvailablePort.mock.calls, [[3773]]); assert.equal(start.mock.calls.length, 1); assert.equal(resolvedConfig?.mode, "web"); assert.equal(resolvedConfig?.port, 4666); assert.equal(resolvedConfig?.host, undefined); }), ); it.effect("prefers --no-browser over T3CODE_NO_BROWSER", () => Effect.gen(function* () { yield* runCli(["--no-browser"], { T3CODE_NO_BROWSER: "false", }); assert.equal(start.mock.calls.length, 1); assert.equal(resolvedConfig?.noBrowser, true); }), ); it.effect("uses dynamic port discovery in web mode when port is omitted", () => Effect.gen(function* () { findAvailablePort.mockImplementation((_preferred: number) => Effect.succeed(5444)); yield* runCli([]); assert.deepStrictEqual(findAvailablePort.mock.calls, [[3773]]); assert.equal(start.mock.calls.length, 1); assert.equal(resolvedConfig?.port, 5444); assert.equal(resolvedConfig?.mode, "web"); }), ); it.effect("uses fixed localhost defaults in desktop mode", () => Effect.gen(function* () { yield* runCli([], { T3CODE_MODE: "desktop", T3CODE_NO_BROWSER: "true", }); assert.equal(findAvailablePort.mock.calls.length, 0); assert.equal(start.mock.calls.length, 1); assert.equal(resolvedConfig?.port, 3773); assert.equal(resolvedConfig?.host, "127.0.0.1"); assert.equal(resolvedConfig?.mode, "desktop"); }), ); it.effect("allows overriding desktop host with --host", () => Effect.gen(function* () { yield* runCli(["--host", "0.0.0.0"], { T3CODE_MODE: "desktop", T3CODE_NO_BROWSER: "true", }); assert.equal(start.mock.calls.length, 1); assert.equal(resolvedConfig?.mode, "desktop"); assert.equal(resolvedConfig?.host, "0.0.0.0"); }), ); it.effect("supports CLI and env for bootstrap/log websocket toggles", () => Effect.gen(function* () { yield* runCli(["--auto-bootstrap-project-from-cwd"], { T3CODE_MODE: "desktop", T3CODE_LOG_WS_EVENTS: "false", T3CODE_AUTO_BOOTSTRAP_PROJECT_FROM_CWD: "false", T3CODE_NO_BROWSER: "true", }); assert.equal(start.mock.calls.length, 1); assert.equal(resolvedConfig?.autoBootstrapProjectFromCwd, true); assert.equal(resolvedConfig?.logWebSocketEvents, false); }), ); it.effect("does not start server for invalid --mode values", () => Effect.gen(function* () { yield* runCli(["--mode", "invalid"]); assert.equal(start.mock.calls.length, 0); assert.equal(stop.mock.calls.length, 0); }), ); it.effect("does not start server for invalid --dev-url values", () => Effect.gen(function* () { yield* runCli(["--dev-url", "not-a-url"]).pipe(Effect.catch(() => Effect.void)); assert.equal(start.mock.calls.length, 0); assert.equal(stop.mock.calls.length, 0); }), ); it.effect("does not start server for out-of-range --port values", () => Effect.gen(function* () { yield* runCli(["--port", "70000"]); // effect/unstable/cli renders help/errors for parse failures and returns success. assert.equal(start.mock.calls.length, 0); assert.equal(stop.mock.calls.length, 0); }), );});
import * as Http from "node:http";
import * as NodeServices from "@effect/platform-node/NodeServices";
import { assert, it, vi } from "@effect/vitest";
import * as ConfigProvider from "effect/ConfigProvider";
import * as Effect from "effect/Effect";
import * as Layer from "effect/Layer";
import * as Command from "effect/unstable/cli/Command";
import { beforeEach } from "vitest";
import { CliConfig, t3Cli, type CliConfigShape } from "./main";
import { NetService, ServerConfig, type ServerConfigShape } from "./config";
import { Open, type OpenShape } from "./open";
import { Server, type ServerShape } from "./wsServer";
const start = vi.fn(() => undefined);
const stop = vi.fn(() => undefined);
let resolvedConfig: ServerConfigShape | null = null;
const serverStart = Effect.acquireRelease(
Effect.gen(function* () {
resolvedConfig = yield* ServerConfig;
start();
return {} as unknown as Http.Server;
}),
() => Effect.sync(() => stop()),
);
const findAvailablePort = vi.fn((preferred: number) => Effect.succeed(preferred));
// Shared service layer used by this CLI test suite.
const testLayer = Layer.mergeAll(
Layer.succeed(CliConfig, {
cwd: "/tmp/t3-test-workspace",
fixPath: Effect.void,
resolveStaticDir: Effect.undefined,
} satisfies CliConfigShape),
Layer.succeed(NetService, {
findAvailablePort,
}),
Layer.succeed(Server, {
start: serverStart,
stopSignal: Effect.void,
} satisfies ServerShape),
Layer.succeed(Open, {
openBrowser: (_target: string) => Effect.void,
openInEditor: () => Effect.void,
} satisfies OpenShape),
NodeServices.layer,
);
const runCli = (
args: ReadonlyArray<string>,
env: Record<string, string> = { T3CODE_NO_BROWSER: "true" },
) =>
Command.runWith(t3Cli, { version: "0.0.0-test" })(args).pipe(
Effect.provide(ConfigProvider.layer(ConfigProvider.fromEnv({ env }))),
);
beforeEach(() => {
vi.clearAllMocks();
resolvedConfig = null;
start.mockImplementation(() => undefined);
stop.mockImplementation(() => undefined);
findAvailablePort.mockImplementation((preferred: number) => Effect.succeed(preferred));
});
it.layer(testLayer)("server CLI command", (it) => {
it.effect("parses all CLI flags and wires scoped start/stop", () =>
Effect.gen(function* () {
yield* runCli([
"--mode",
"desktop",
"--port",
"4010",
"--host",
"0.0.0.0",
"--state-dir",
"/tmp/t3-cli-state",
"--dev-url",
"http://127.0.0.1:5173",
"--no-browser",
"--auth-token",
"auth-secret",
]);
assert.equal(start.mock.calls.length, 1);
assert.equal(resolvedConfig?.mode, "desktop");
assert.equal(resolvedConfig?.port, 4010);
assert.equal(resolvedConfig?.host, "0.0.0.0");
assert.equal(resolvedConfig?.stateDir, "/tmp/t3-cli-state");
assert.equal(resolvedConfig?.devUrl?.toString(), "http://127.0.0.1:5173/");
assert.equal(resolvedConfig?.noBrowser, true);
assert.equal(resolvedConfig?.authToken, "auth-secret");
assert.equal(resolvedConfig?.autoBootstrapProjectFromCwd, false);
assert.equal(resolvedConfig?.logWebSocketEvents, true);
assert.equal(stop.mock.calls.length, 1);
}),
);
it.effect("supports --token as an alias for --auth-token", () =>
Effect.gen(function* () {
yield* runCli(["--token", "token-secret"]);
assert.equal(start.mock.calls.length, 1);
assert.equal(resolvedConfig?.authToken, "token-secret");
}),
);
it.effect("uses env fallbacks when flags are not provided", () =>
Effect.gen(function* () {
yield* runCli([], {
T3CODE_MODE: "desktop",
T3CODE_PORT: "4999",
T3CODE_HOST: "100.88.10.4",
T3CODE_STATE_DIR: "/tmp/t3-env-state",
VITE_DEV_SERVER_URL: "http://localhost:5173",
T3CODE_NO_BROWSER: "true",
T3CODE_AUTH_TOKEN: "env-token",
});
assert.equal(start.mock.calls.length, 1);
assert.equal(resolvedConfig?.mode, "desktop");
assert.equal(resolvedConfig?.port, 4999);
assert.equal(resolvedConfig?.host, "100.88.10.4");
assert.equal(resolvedConfig?.stateDir, "/tmp/t3-env-state");
assert.equal(resolvedConfig?.devUrl?.toString(), "http://localhost:5173/");
assert.equal(resolvedConfig?.noBrowser, true);
assert.equal(resolvedConfig?.authToken, "env-token");
assert.equal(resolvedConfig?.autoBootstrapProjectFromCwd, false);
assert.equal(resolvedConfig?.logWebSocketEvents, true);
assert.equal(findAvailablePort.mock.calls.length, 0);
}),
);
it.effect("prefers --mode over T3CODE_MODE", () =>
Effect.gen(function* () {
findAvailablePort.mockImplementation((_preferred: number) => Effect.succeed(4666));
yield* runCli(["--mode", "web"], {
T3CODE_MODE: "desktop",
T3CODE_NO_BROWSER: "true",
});
assert.deepStrictEqual(findAvailablePort.mock.calls, [[3773]]);
assert.equal(start.mock.calls.length, 1);
assert.equal(resolvedConfig?.mode, "web");
assert.equal(resolvedConfig?.port, 4666);
assert.equal(resolvedConfig?.host, undefined);
}),
);
it.effect("prefers --no-browser over T3CODE_NO_BROWSER", () =>
Effect.gen(function* () {
yield* runCli(["--no-browser"], {
T3CODE_NO_BROWSER: "false",
});
assert.equal(start.mock.calls.length, 1);
assert.equal(resolvedConfig?.noBrowser, true);
}),
);
it.effect("uses dynamic port discovery in web mode when port is omitted", () =>
Effect.gen(function* () {
findAvailablePort.mockImplementation((_preferred: number) => Effect.succeed(5444));
yield* runCli([]);
assert.deepStrictEqual(findAvailablePort.mock.calls, [[3773]]);
assert.equal(start.mock.calls.length, 1);
assert.equal(resolvedConfig?.port, 5444);
assert.equal(resolvedConfig?.mode, "web");
}),
);
it.effect("uses fixed localhost defaults in desktop mode", () =>
Effect.gen(function* () {
yield* runCli([], {
T3CODE_MODE: "desktop",
T3CODE_NO_BROWSER: "true",
});
assert.equal(findAvailablePort.mock.calls.length, 0);
assert.equal(start.mock.calls.length, 1);
assert.equal(resolvedConfig?.port, 3773);
assert.equal(resolvedConfig?.host, "127.0.0.1");
assert.equal(resolvedConfig?.mode, "desktop");
}),
);
it.effect("allows overriding desktop host with --host", () =>
Effect.gen(function* () {
yield* runCli(["--host", "0.0.0.0"], {
T3CODE_MODE: "desktop",
T3CODE_NO_BROWSER: "true",
});
assert.equal(start.mock.calls.length, 1);
assert.equal(resolvedConfig?.mode, "desktop");
assert.equal(resolvedConfig?.host, "0.0.0.0");
}),
);
it.effect("supports CLI and env for bootstrap/log websocket toggles", () =>
Effect.gen(function* () {
yield* runCli(["--auto-bootstrap-project-from-cwd"], {
T3CODE_MODE: "desktop",
T3CODE_LOG_WS_EVENTS: "false",
T3CODE_AUTO_BOOTSTRAP_PROJECT_FROM_CWD: "false",
T3CODE_NO_BROWSER: "true",
});
assert.equal(start.mock.calls.length, 1);
assert.equal(resolvedConfig?.autoBootstrapProjectFromCwd, true);
assert.equal(resolvedConfig?.logWebSocketEvents, false);
}),
);
it.effect("does not start server for invalid --mode values", () =>
Effect.gen(function* () {
yield* runCli(["--mode", "invalid"]);
assert.equal(start.mock.calls.length, 0);
assert.equal(stop.mock.calls.length, 0);
}),
);
it.effect("does not start server for invalid --dev-url values", () =>
Effect.gen(function* () {
yield* runCli(["--dev-url", "not-a-url"]).pipe(Effect.catch(() => Effect.void));
assert.equal(start.mock.calls.length, 0);
assert.equal(stop.mock.calls.length, 0);
}),
);
it.effect("does not start server for out-of-range --port values", () =>
Effect.gen(function* () {
yield* runCli(["--port", "70000"]);
// effect/unstable/cli renders help/errors for parse failures and returns success.
assert.equal(start.mock.calls.length, 0);
assert.equal(stop.mock.calls.length, 0);
}),
);
});