t3-code-android-nightly/scripts/build-desktop-artifact.test.ts
2026-10-06 12:41:30 -07:00

2413 lines
90 KiB
TypeScript

// @effect-diagnostics nodeBuiltinImport:off - Tests use Node's glob matcher to verify electron-builder exclusions.
import * as NodeCrypto from "node:crypto";
import * as NodePath from "node:path";
import * as NodeServices from "@effect/platform-node/NodeServices";
import { assert, it } from "@effect/vitest";
import * as ConfigProvider from "effect/ConfigProvider";
import * as FileSystem from "effect/FileSystem";
import * as Effect from "effect/Effect";
import * as Layer from "effect/Layer";
import * as Option from "effect/Option";
import * as Path from "effect/Path";
import * as Sink from "effect/Sink";
import * as Stream from "effect/Stream";
import { ChildProcess, ChildProcessSpawner } from "effect/process";
import {
BundleNotSelfContainedError,
BuildCommandFailedError,
parseWslRuntimeArchiveMembers,
DesktopDmgBackgroundSourceMissingError,
createStageWorkspaceConfig,
createStagePatchedDependencies,
createBuildConfig,
DESKTOP_ELECTRON_LANGUAGES,
DESKTOP_FILE_EXCLUSIONS,
DESKTOP_EXTRA_RESOURCES,
LINUX_CAPTURE_EXTRA_RESOURCES,
LINUX_BROWSER_SECRET_EXTRA_RESOURCES,
LINUX_FILE_EXCLUSIONS,
MAC_FILE_EXCLUSIONS,
InvalidMacPasskeyRpDomainError,
InvalidMacPasskeyPublishableKeyError,
InvalidMockUpdateServerPortError,
UnsupportedDesktopBuildArchitectureError,
isMacPasskeySigningConfigurationError,
LinuxIconResizeError,
LinuxDesktopBuildPrerequisitesMissingError,
MacDesktopBuildPrerequisitesMissingError,
MacPasskeySigningConfigurationResolutionError,
MissingMacPasskeyProvisioningProfileError,
packWindowsServerAsar,
preflightLinuxDesktopBuild,
preflightMacDesktopBuild,
preflightWindowsDesktopBuild,
renderMacPasskeyEntitlements,
resolveClerkPasskeyNativeArtifacts,
resolveMacPasskeySigningConfiguration,
resolveDesktopRuntimeDependencies,
resolveMergedStageDependencies,
resolveFffNativeDependencies,
resolveBuildOptions,
resolveDesktopBuildIconAssets,
resolveDesktopProductName,
resolveDesktopUpdateChannel,
resolveDesktopWebAssetBrand,
resolveResourceMonitorRustTargets,
resolveWindowsServerAsarIgnoreGlobs,
resourceMonitorExecutableName,
resolveGitHubPublishConfig,
resolveMockUpdateServerPort,
resolveMockUpdateServerUrl,
resolvePackageManagerUserAgent,
stageLinuxIconSize,
stageDesktopDmgBackground,
stageResourceMonitor,
stageLinuxCaptureHelper,
stageWslRuntimeArchive,
bundlesWslRuntime,
STAGE_INSTALL_ARGS,
ancestorNodeModulesPaths,
copyDirectoryPreservingSymlinks,
LinuxBrowserSecretHostError,
stageBrowserSecret,
validateWindowsPackagedPayload,
WindowsPrimaryNativeProbeError,
WindowsDesktopBuildPrerequisitesMissingError,
WindowsPackagedPayloadValidationError,
WINDOWS_NATIVE_ASAR_UNPACK_GLOB,
stageCursorSdkPlatformPackages,
WINDOWS_PACKAGED_PAYLOAD_FILE_LIMIT,
WINDOWS_SERVER_ASAR_IGNORE_GLOBS,
WINDOWS_SERVER_EXTRA_RESOURCES,
WINDOWS_SERVER_ASAR_RESOURCE,
WINDOWS_SERVER_RESOURCE_SOURCE_DIR,
WSL_RUNTIME_ARCHIVE_EXTRA_RESOURCE,
WSL_RUNTIME_ARCHIVE_HASH_EXTRA_RESOURCE,
WSL_RUNTIME_ARCHIVE_HASH_NAME,
WSL_RUNTIME_ARCHIVE_NAME,
WSL_RUNTIME_EXTRA_RESOURCES,
WslRuntimeArchiveMissingError,
wslRuntimeArchiveStem,
} from "./build-desktop-artifact.ts";
import { BRAND_ASSET_PATHS } from "./lib/brand-assets.ts";
import { HostProcessArchitecture, HostProcessPlatform } from "@t3tools/shared/hostProcess";
import { symlinksSupported } from "@t3tools/shared/testing/symlinks";
// A minimal stand-in for the Linux CLI release archive: one top-level
// directory named after the archive stem holding the executable, the web
// client, and the runtime externals with node-pty built from source.
const makeLinuxCliArchiveFixture = Effect.fn("test.makeLinuxCliArchiveFixture")(function* (input: {
readonly root: string;
readonly stem: string;
readonly extraMembers?: ReadonlyArray<string>;
readonly omitMembers?: ReadonlyArray<string>;
}) {
const fs = yield* FileSystem.FileSystem;
const path = yield* Path.Path;
const spawner = yield* ChildProcessSpawner.ChildProcessSpawner;
const contentRoot = path.join(input.root, "content");
const members = [
`${input.stem}/t3`,
`${input.stem}/client/index.html`,
`${input.stem}/node_modules/node-pty/package.json`,
`${input.stem}/node_modules/node-pty/build/Release/pty.node`,
...(input.extraMembers ?? []),
].filter((member) => !(input.omitMembers ?? []).includes(member));
for (const member of members) {
const memberPath = path.join(contentRoot, member);
yield* fs.makeDirectory(path.dirname(memberPath), { recursive: true });
yield* fs.writeFileString(memberPath, member);
}
const archivePath = path.join(input.root, `${input.stem}.tar.gz`);
const tar = yield* spawner.spawn(
ChildProcess.make("tar", ["-czf", archivePath, "-C", contentRoot, "."], {
stdin: "ignore",
stdout: "ignore",
stderr: "pipe",
}),
);
assert.equal(Number(yield* tar.exitCode), 0);
return archivePath;
});
function mockProcess(exitCode: number, stdout = "") {
const encodedStdout = new TextEncoder().encode(stdout);
return ChildProcessSpawner.makeHandle({
pid: ChildProcessSpawner.ProcessId(1),
exitCode: Effect.succeed(ChildProcessSpawner.ExitCode(exitCode)),
isRunning: Effect.succeed(false),
kill: () => Effect.void,
unref: Effect.succeed(Effect.void),
stdin: Sink.drain,
stdout: stdout ? Stream.make(encodedStdout) : Stream.empty,
stderr: Stream.empty,
all: Stream.empty,
getInputFd: () => Sink.drain,
getOutputFd: () => Stream.empty,
});
}
function iconResizeSpawnerLayer(
commands: Array<{ readonly command: string; readonly args: ReadonlyArray<string> }>,
exitCodes: ReadonlyArray<number>,
) {
let commandIndex = 0;
return Layer.succeed(
ChildProcessSpawner.ChildProcessSpawner,
ChildProcessSpawner.make((command) => {
const childProcess = command as unknown as {
readonly command: string;
readonly args: ReadonlyArray<string>;
};
commands.push({
command: childProcess.command,
args: childProcess.args,
});
return Effect.succeed(mockProcess(exitCodes[commandIndex++] ?? 0));
}),
);
}
const WINDOWS_PAYLOAD_FIXTURE_VERSION = "1.2.3";
const makeWindowsPayloadFixture = Effect.fn("test.makeWindowsPayloadFixture")(function* (input: {
readonly copyUnpackedNatives: boolean;
readonly serverEntrySource?: string;
readonly wslRuntime?: "valid" | "loose-server-tree" | "missing-pty" | "bad-digest";
readonly targetArch?: "x64" | "arm64";
readonly ptyPrebuildArch?: "x64" | "arm64";
}) {
const fs = yield* FileSystem.FileSystem;
const path = yield* Path.Path;
const tempDir = yield* fs.makeTempDirectoryScoped({
prefix: "t3-windows-payload-test-",
});
const sourceDir = path.join(tempDir, "server-source");
const serverEntryPath = path.join(sourceDir, "apps/server/dist/bin.mjs");
const nativePath = path.join(sourceDir, "node_modules/native/addon.node");
yield* fs.makeDirectory(path.dirname(serverEntryPath), { recursive: true });
yield* fs.makeDirectory(path.dirname(nativePath), { recursive: true });
yield* fs.writeFileString(serverEntryPath, input.serverEntrySource ?? "console.log('server');\n");
yield* fs.writeFileString(nativePath, "native-binary");
const generatedAsarPath = path.join(tempDir, WINDOWS_SERVER_ASAR_RESOURCE);
yield* packWindowsServerAsar({ sourceDir, asarPath: generatedAsarPath, arch: "x64" });
const stageDistDir = path.join(tempDir, "dist");
const packagedAppDir = path.join(stageDistDir, "win-unpacked");
const resourcesDir = path.join(packagedAppDir, "resources");
yield* fs.makeDirectory(path.join(resourcesDir, "resource-monitor"), { recursive: true });
yield* fs.copyFile(generatedAsarPath, path.join(resourcesDir, WINDOWS_SERVER_ASAR_RESOURCE));
if (input.copyUnpackedNatives) {
yield* fs.copy(
`${generatedAsarPath}.unpacked`,
path.join(resourcesDir, `${WINDOWS_SERVER_ASAR_RESOURCE}.unpacked`),
);
}
yield* fs.writeFileString(
path.join(resourcesDir, "resource-monitor/t3-resource-monitor.exe"),
"monitor",
);
const appExecutableName = "t3code.exe";
yield* fs.writeFileString(path.join(packagedAppDir, appExecutableName), "electron");
yield* fs.writeFileString(path.join(packagedAppDir, "chrome_crashpad_handler.exe"), "crashpad");
if (input.wslRuntime !== undefined) {
const stem = wslRuntimeArchiveStem(WINDOWS_PAYLOAD_FIXTURE_VERSION, input.targetArch ?? "x64");
const sourceArchivePath =
input.wslRuntime === "loose-server-tree"
? // The old hand-rolled runtime: apps/server/dist + node_modules at the
// archive root, no single stem directory, no `t3` executable.
yield* makeLinuxCliArchiveFixture({
root: path.join(tempDir, "wsl-runtime"),
stem: "apps",
omitMembers: ["apps/t3", "apps/client/index.html"],
extraMembers: ["apps/server/dist/bin.mjs", "node_modules/node-pty/package.json"],
})
: yield* makeLinuxCliArchiveFixture({
root: path.join(tempDir, "wsl-runtime"),
stem,
...(input.wslRuntime === "missing-pty" || input.ptyPrebuildArch !== undefined
? { omitMembers: [`${stem}/node_modules/node-pty/build/Release/pty.node`] }
: {}),
...(input.ptyPrebuildArch !== undefined
? {
extraMembers: [
`${stem}/node_modules/node-pty/prebuilds/linux-${input.ptyPrebuildArch}/pty.node`,
],
}
: {}),
});
const archivePath = path.join(resourcesDir, WSL_RUNTIME_ARCHIVE_NAME);
const hashPath = path.join(resourcesDir, WSL_RUNTIME_ARCHIVE_HASH_NAME);
yield* stageWslRuntimeArchive({ sourceArchivePath, archivePath, hashPath });
if (input.wslRuntime === "bad-digest") {
yield* fs.writeFileString(hashPath, `${"0".repeat(64)}\n`);
}
}
return {
stageDistDir,
packagedAppDir,
sourceDir,
generatedAsarPath,
appExecutableName,
} as const;
});
it.layer(NodeServices.layer)("build-desktop-artifact", (it) => {
it("resolves the dedicated nightly updater channel from nightly versions", () => {
assert.equal(resolveDesktopUpdateChannel("0.0.17-nightly.20260413.42"), "nightly");
assert.equal(resolveDesktopUpdateChannel("0.0.17"), "latest");
});
it("switches desktop packaging product names to nightly for nightly builds", () => {
assert.equal(resolveDesktopProductName("0.0.17"), "T3 Code (Alpha)");
assert.equal(resolveDesktopProductName("0.0.17-nightly.20260413.42"), "T3 Code (Nightly)");
});
it("switches desktop packaging icons to the nightly artwork for nightly versions", () => {
assert.deepStrictEqual(resolveDesktopBuildIconAssets("0.0.17"), {
macIconPng: BRAND_ASSET_PATHS.productionMacIconPng,
linuxIconPng: BRAND_ASSET_PATHS.productionLinuxIconPng,
windowsIconIco: BRAND_ASSET_PATHS.productionWindowsIconIco,
});
assert.deepStrictEqual(resolveDesktopBuildIconAssets("0.0.17-nightly.20260413.42"), {
macIconPng: BRAND_ASSET_PATHS.nightlyMacIconPng,
linuxIconPng: BRAND_ASSET_PATHS.nightlyLinuxIconPng,
windowsIconIco: BRAND_ASSET_PATHS.nightlyWindowsIconIco,
});
});
it("switches the bundled splash and favicon branding for nightly versions", () => {
assert.equal(resolveDesktopWebAssetBrand("0.0.17"), "production");
assert.equal(resolveDesktopWebAssetBrand("0.0.17-nightly.20260413.42"), "nightly");
});
it.effect("resolves GitHub desktop publish config from Effect config", () =>
Effect.gen(function* () {
const latestConfig = yield* resolveGitHubPublishConfig("latest").pipe(
Effect.provide(
ConfigProvider.layer(
ConfigProvider.fromEnv({
env: {
T3CODE_DESKTOP_UPDATE_REPOSITORY: "pingdotgg/t3code",
},
}),
),
),
);
const nightlyConfig = yield* resolveGitHubPublishConfig("nightly").pipe(
Effect.provide(
ConfigProvider.layer(
ConfigProvider.fromEnv({
env: {
GITHUB_REPOSITORY: "pingdotgg/t3code",
},
}),
),
),
);
assert.deepStrictEqual(latestConfig, {
provider: "github",
owner: "pingdotgg",
repo: "t3code",
releaseType: "release",
});
assert.deepStrictEqual(nightlyConfig, {
provider: "github",
owner: "pingdotgg",
repo: "t3code",
releaseType: "prerelease",
channel: "nightly",
});
}),
);
it.effect("omits update feeds for pull request preview builds", () =>
Effect.gen(function* () {
const preview = yield* createBuildConfig(
"mac",
"dmg",
"0.0.33-pr.8182.1",
false,
false,
undefined,
undefined,
);
const release = yield* createBuildConfig(
"mac",
"dmg",
"0.0.33",
false,
false,
undefined,
undefined,
);
const previewChannel = yield* createBuildConfig(
"mac",
"dmg",
"0.0.41-preview.20260912.1589",
false,
false,
undefined,
undefined,
);
assert.notProperty(preview, "publish");
assert.notProperty(previewChannel, "publish");
assert.deepStrictEqual(release.publish, [
{
provider: "github",
owner: "pingdotgg",
repo: "t3code",
releaseType: "release",
},
]);
}).pipe(
Effect.provide(
ConfigProvider.layer(
ConfigProvider.fromEnv({ env: { GITHUB_REPOSITORY: "pingdotgg/t3code" } }),
),
),
),
);
it("stages only the desktop main-process externals", () => {
assert.deepStrictEqual(
resolveDesktopRuntimeDependencies(
{
"@clerk/electron": "catalog:",
"@clerk/electron-passkeys": "catalog:",
"@crowecawcaw/xa11y": "0.13.0",
"@effect/platform-node": "catalog:",
"@napi-rs/keyring": "^1.3.0",
"@t3tools/contracts": "workspace:*",
"@t3tools/shared": "workspace:*",
"dbus-next": "0.10.2",
effect: "catalog:",
electron: "41.5.0",
"electron-updater": "^6.6.2",
"ffi-rs": "1.3.2",
"playwright-core": "1.60.0",
},
{
"@clerk/electron": "0.0.37",
"@clerk/electron-passkeys": "0.0.3",
"@effect/platform-node": "4.0.0-beta.59",
effect: "4.0.0-beta.59",
},
),
{
"@clerk/electron-passkeys": "0.0.3",
"@crowecawcaw/xa11y": "0.13.0",
"@napi-rs/keyring": "^1.3.0",
"ffi-rs": "1.3.2",
"playwright-core": "1.60.0",
},
);
});
it("carries only staged dependency patch metadata into staged desktop installs", () => {
assert.deepStrictEqual(
createStagePatchedDependencies(
{
"@expo/metro-config@56.0.13": "patches/@expo%2Fmetro-config@56.0.13.patch",
"@ff-labs/fff-node@0.9.4": "patches/@ff-labs__fff-node@0.9.4.patch",
"@pierre/diffs@1.1.20": "patches/@pierre%2Fdiffs@1.1.20.patch",
"alchemy@2.0.0-beta.49": "patches/alchemy@2.0.0-beta.49.patch",
"effect@4.0.0-beta.73": "patches/effect@4.0.0-beta.73.patch",
},
{
"@ff-labs/fff-node": "0.9.4",
"@pierre/diffs": "1.1.20",
effect: "4.0.0-beta.73",
},
),
{
"@ff-labs/fff-node@0.9.4": "patches/@ff-labs__fff-node@0.9.4.patch",
"@pierre/diffs@1.1.20": "patches/@pierre%2Fdiffs@1.1.20.patch",
"effect@4.0.0-beta.73": "patches/effect@4.0.0-beta.73.patch",
},
);
assert.deepStrictEqual(
createStagePatchedDependencies(
{
"@expo/metro-config@56.0.13": "patches/@expo%2Fmetro-config@56.0.13.patch",
},
{ effect: "4.0.0-beta.73" },
),
{},
);
});
it("installs optional native dependencies for the target desktop architecture", () => {
assert.deepStrictEqual(STAGE_INSTALL_ARGS, ["install", "--prod"]);
assert.deepStrictEqual(createStageWorkspaceConfig({ platform: "mac", arch: "x64" }), {
supportedArchitectures: {
os: ["darwin"],
cpu: ["x64"],
},
});
assert.deepStrictEqual(createStageWorkspaceConfig({ platform: "linux", arch: "x64" }), {
supportedArchitectures: {
os: ["linux"],
cpu: ["x64"],
libc: ["glibc"],
},
});
// Windows stages only win32 natives; WSL runs the separately built Linux
// CLI archive rather than anything installed here.
assert.deepStrictEqual(createStageWorkspaceConfig({ platform: "win", arch: "x64" }), {
supportedArchitectures: {
os: ["win32"],
cpu: ["x64"],
},
});
assert.deepStrictEqual(createStageWorkspaceConfig({ platform: "win", arch: "arm64" }), {
supportedArchitectures: {
os: ["win32"],
cpu: ["arm64"],
},
});
assert.deepStrictEqual(createStageWorkspaceConfig({ platform: "mac", arch: "universal" }), {
supportedArchitectures: {
os: ["darwin"],
cpu: ["arm64", "x64"],
},
});
});
it("stages pnpm 11 allowBuilds and patchedDependencies in the workspace yaml", () => {
assert.deepStrictEqual(
createStageWorkspaceConfig({
platform: "linux",
arch: "x64",
allowBuilds: {
electron: true,
"node-pty": true,
"browser-tabs-lock": false,
},
patchedDependencies: {
"effect@4.0.0-beta.73": "patches/effect@4.0.0-beta.73.patch",
},
overrides: {
effect: "4.0.0-beta.73",
},
}),
{
supportedArchitectures: {
os: ["linux"],
cpu: ["x64"],
libc: ["glibc"],
},
allowBuilds: {
electron: true,
"node-pty": true,
"browser-tabs-lock": false,
},
patchedDependencies: {
"effect@4.0.0-beta.73": "patches/effect@4.0.0-beta.73.patch",
},
overrides: {
effect: "4.0.0-beta.73",
},
},
);
// Empty maps must not be written — pnpm would still require reviewed
// packages if allowBuilds is present but incomplete, and omitting empty
// patchedDependencies keeps the stage yaml minimal.
assert.deepStrictEqual(
createStageWorkspaceConfig({
platform: "mac",
arch: "arm64",
allowBuilds: {},
patchedDependencies: {},
overrides: {},
}),
{
supportedArchitectures: {
os: ["darwin"],
cpu: ["arm64"],
},
},
);
});
it("limits Electron locales and excludes separately packaged resources", () => {
assert.deepStrictEqual(DESKTOP_ELECTRON_LANGUAGES, ["en-US"]);
// Every platform staging input is emitted once at resources/, so adding one
// without its exclusion silently packs a second copy into app.asar. The
// snapshot below cannot catch that on its own: adding a resource and
// forgetting the exclusion leaves the exclusion list untouched, so it still
// matches. Assert the invariant first, where the failure names the culprit.
for (const resource of [
...WSL_RUNTIME_EXTRA_RESOURCES,
...LINUX_BROWSER_SECRET_EXTRA_RESOURCES,
]) {
assert.include(
DESKTOP_FILE_EXCLUSIONS,
`!${resource.from}`,
`${resource.from} ships via extraResources and must be excluded from app.asar`,
);
}
assert.deepStrictEqual(DESKTOP_FILE_EXCLUSIONS, [
"!**/node_modules/@cursor/sdk-*/**/*",
"!apps/desktop/prod-resources/cursor-sdk",
"!apps/desktop/prod-resources/cursor-sdk/**/*",
"!**/node_modules/@anthropic-ai/claude-agent-sdk-*/**/*",
"!**/*.map",
"!**/*.d.cts",
"!apps/desktop/resources/browser-secret",
"!apps/desktop/resources/browser-secret/**/*",
"!apps/desktop/prod-resources/browser-secret",
"!apps/desktop/prod-resources/browser-secret/**/*",
"!apps/desktop/prod-resources/windows-server",
"!apps/desktop/prod-resources/windows-server/**/*",
"!apps/desktop/prod-resources/wsl-runtime.tar.gz",
"!apps/desktop/prod-resources/wsl-runtime.tar.gz.sha256",
"!apps/desktop/gnome-extension",
"!apps/desktop/gnome-extension/**/*",
]);
assert.equal(WINDOWS_SERVER_RESOURCE_SOURCE_DIR, "apps/desktop/prod-resources/windows-server");
assert.deepStrictEqual(WINDOWS_SERVER_EXTRA_RESOURCES, [
{
from: "apps/desktop/prod-resources/windows-server",
to: ".",
filter: ["server.asar", "server.asar.unpacked/**/*"],
},
]);
});
it.effect("applies platform-specific packaging to the build config", () =>
Effect.gen(function* () {
const mac = yield* createBuildConfig(
"mac",
"dmg",
"1.2.3",
false,
false,
undefined,
undefined,
);
const linux = yield* createBuildConfig(
"linux",
"AppImage",
"1.2.3",
false,
false,
undefined,
undefined,
);
const win = yield* createBuildConfig(
"win",
"nsis",
"1.2.3",
false,
false,
undefined,
undefined,
true,
);
const winWithoutWslRuntime = yield* createBuildConfig(
"win",
"nsis",
"1.2.3",
false,
false,
undefined,
undefined,
false,
);
// Windows unpacks native files explicitly so their JavaScript and metadata
// stay archived. Other platforms retain electron-builder's defaults.
assert.notProperty(mac, "asar");
assert.notProperty(linux, "asar");
assert.notProperty(mac, "asarUnpack");
assert.notProperty(linux, "asarUnpack");
assert.deepStrictEqual(win.asar, { smartUnpack: false });
assert.deepStrictEqual(win.asarUnpack, [WINDOWS_NATIVE_ASAR_UNPACK_GLOB]);
assert.deepStrictEqual(winWithoutWslRuntime.asar, win.asar);
assert.deepStrictEqual(winWithoutWslRuntime.asarUnpack, win.asarUnpack);
assert.deepStrictEqual(mac.extraResources, DESKTOP_EXTRA_RESOURCES);
assert.deepStrictEqual(linux.extraResources, [
...DESKTOP_EXTRA_RESOURCES,
...LINUX_CAPTURE_EXTRA_RESOURCES,
{ from: "apps/desktop/prod-resources/browser-secret", to: "browser-secret" },
]);
assert.deepStrictEqual(win.extraResources, [
...DESKTOP_EXTRA_RESOURCES,
...WINDOWS_SERVER_EXTRA_RESOURCES,
...WSL_RUNTIME_EXTRA_RESOURCES,
]);
// No Linux CLI archive means staging never writes the runtime, so
// listing it here would fail the build on a missing source file.
assert.deepStrictEqual(winWithoutWslRuntime.extraResources, [
...DESKTOP_EXTRA_RESOURCES,
...WINDOWS_SERVER_EXTRA_RESOURCES,
]);
assert.deepStrictEqual(win.nsis, { differentialPackage: true });
// The Claude SDK platform packages and .bin shims never ship.
assert.deepStrictEqual(WINDOWS_SERVER_ASAR_IGNORE_GLOBS, [
"**/node_modules/@cursor/sdk-*",
"**/node_modules/@cursor/sdk-*/**",
"**/node_modules/@anthropic-ai/claude-agent-sdk-*",
"**/node_modules/@anthropic-ai/claude-agent-sdk-*/**",
"**/node_modules/.bin",
"**/node_modules/.bin/**",
"**/*.map",
]);
assert.deepStrictEqual(mac.dmg, {
title: "T3 Code (Alpha) 1.2.3 Installer",
background: "dmg/dmg-background-latest.png",
window: { width: 640, height: 432 },
contents: [
{ x: 166, y: 214, type: "file" },
{ x: 474, y: 214, type: "link", path: "/Applications" },
],
iconSize: 120,
iconTextSize: 12,
});
// A Linux AppImage build also emits the .deb from the same run.
assert.deepStrictEqual((linux.linux as Record<string, unknown>).target, ["AppImage", "deb"]);
// Linux must register the renderer schemes so the generated .desktop
// entry advertises MimeType=x-scheme-handler/t3code; for OAuth deep links.
assert.deepStrictEqual((linux.linux as Record<string, unknown>).protocols, [
{ name: "T3 Code", schemes: ["t3code", "t3code-dev"] },
]);
assert.deepStrictEqual(linux.toolsets, { appimage: "1.0.3" });
assert.notProperty(mac, "toolsets");
assert.notProperty(win, "toolsets");
assert.deepStrictEqual(mac.files, [...DESKTOP_FILE_EXCLUSIONS, ...MAC_FILE_EXCLUSIONS]);
assert.deepStrictEqual(linux.files, [...DESKTOP_FILE_EXCLUSIONS, ...LINUX_FILE_EXCLUSIONS]);
assert.deepStrictEqual(win.files, DESKTOP_FILE_EXCLUSIONS);
assert.deepStrictEqual(winWithoutWslRuntime.files, win.files);
assert.notProperty(mac.mac as Record<string, unknown>, "sign");
for (const config of [linux, win]) {
assert.deepStrictEqual(config.electronLanguages, DESKTOP_ELECTRON_LANGUAGES);
}
assert.deepStrictEqual(mac.electronLanguages, DESKTOP_ELECTRON_LANGUAGES);
}).pipe(Effect.provide(ConfigProvider.layer(ConfigProvider.fromEnv({ env: {} })))),
);
it("excludes foreign node-pty prebuilds from macOS and Linux packages", () => {
assert.deepStrictEqual(MAC_FILE_EXCLUSIONS, [
"!**/node_modules/node-pty/prebuilds/win32-*/**/*",
"!**/node_modules/node-pty/third_party/conpty/**/*",
]);
assert.deepStrictEqual(LINUX_FILE_EXCLUSIONS, [
...MAC_FILE_EXCLUSIONS,
"!**/node_modules/node-pty/prebuilds/darwin-*/**/*",
]);
});
it("unpacks native binaries while keeping their JavaScript and metadata archived", () => {
for (const file of [
"node_modules/@napi-rs/keyring/keyring.win32-x64-msvc.node",
"node_modules/@clerk/electron-passkeys/electron-passkeys.win32-x64-msvc.node",
"node_modules/@ff-labs/fff-bin-win32-x64/fff_c.dll",
"node_modules/node-pty/prebuilds/win32-x64/conpty/OpenConsole.exe",
"node_modules/native/addon.so",
"node_modules/native/addon.so.1",
"node_modules/native/addon.dylib",
]) {
assert.isTrue(
NodePath.matchesGlob(file, WINDOWS_NATIVE_ASAR_UNPACK_GLOB),
`${file} must be available as a real file`,
);
}
for (const file of [
"node_modules/@napi-rs/keyring/index.js",
"node_modules/@napi-rs/keyring/keytar.js",
"node_modules/@clerk/electron-passkeys/index.js",
]) {
assert.isFalse(
NodePath.matchesGlob(file, WINDOWS_NATIVE_ASAR_UNPACK_GLOB),
`${file} should remain inside the archive`,
);
}
});
it("stages only the externals of both bundles in merged packages", () => {
assert.deepStrictEqual(
resolveMergedStageDependencies({
platform: "mac",
serverDependencies: {
"@cursor/sdk": "1.0.22",
"@anthropic-ai/claude-agent-sdk": "^0.3.170",
"@ff-labs/fff-node": "0.9.4",
"@opencode-ai/sdk": "^1.3.15",
"@pierre/diffs": "1.3.0",
"node-pty": "1.1.0",
},
desktopDependencies: {
"@napi-rs/keyring": "1.3.0",
"playwright-core": "1.60.0",
},
arch: "arm64",
fffNodeVersion: "0.9.4",
}),
{
"@cursor/sdk": "1.0.22",
"@ff-labs/fff-node": "0.9.4",
"node-pty": "1.1.0",
"@napi-rs/keyring": "1.3.0",
"playwright-core": "1.60.0",
"@ff-labs/fff-bin-darwin-arm64": "0.9.4",
},
);
assert.deepStrictEqual(
resolveMergedStageDependencies({
platform: "linux",
serverDependencies: { "@ff-labs/fff-node": "0.9.4", "node-pty": "1.1.0", effect: "4.0.0" },
desktopDependencies: { "@crowecawcaw/xa11y": "0.13.0" },
arch: "x64",
fffNodeVersion: "0.9.4",
}),
{
"@ff-labs/fff-node": "0.9.4",
"node-pty": "1.1.0",
"@crowecawcaw/xa11y": "0.13.0",
"@ff-labs/fff-bin-linux-x64-gnu": "0.9.4",
"@ff-labs/fff-bin-linux-x64-musl": "0.9.4",
},
);
});
it.effect("ships Cursor platform assets outside asar for spawning and native loading", () =>
Effect.scoped(
Effect.gen(function* () {
const fs = yield* FileSystem.FileSystem;
const path = yield* Path.Path;
const root = yield* fs.makeTempDirectoryScoped({ prefix: "t3-cursor-helpers-" });
const nodeModules = path.join(root, "node_modules");
const destination = path.join(root, "resources/node_modules/@cursor");
const cursorDirectory = symlinksSupported
? path.join(root, "store/@cursor")
: path.join(nodeModules, "@cursor");
yield* fs.makeDirectory(path.join(cursorDirectory, "sdk"), { recursive: true });
if (symlinksSupported) {
yield* fs.makeDirectory(path.join(nodeModules, "@cursor"), { recursive: true });
yield* fs.symlink(
path.join(cursorDirectory, "sdk"),
path.join(nodeModules, "@cursor/sdk"),
);
}
const helpers = [
"sdk-darwin-arm64/bin/rg",
"sdk-darwin-arm64/bin/cursorsandbox",
"sdk-darwin-arm64/vendor/tree-sitter/index.js",
"sdk-darwin-arm64/vendor/tree-sitter/binding.node",
"sdk-darwin-arm64/vendor/tree-sitter-bash/binding.node",
"sdk-darwin-arm64/package.json",
"sdk-win32-x64/bin/rg.exe",
];
for (const helper of helpers) {
const source = path.join(cursorDirectory, helper);
yield* fs.makeDirectory(path.dirname(source), { recursive: true });
yield* fs.writeFileString(source, "fixture helper", { mode: 0o755 });
}
yield* stageCursorSdkPlatformPackages(nodeModules, destination);
for (const helper of helpers) {
assert.equal(yield* fs.readFileString(path.join(destination, helper)), "fixture helper");
const packagedPath = `node_modules/@cursor/${helper}`;
assert.isTrue(
DESKTOP_FILE_EXCLUSIONS.some((glob) =>
NodePath.matchesGlob(packagedPath, glob.slice(1)),
),
);
assert.isTrue(
WINDOWS_SERVER_ASAR_IGNORE_GLOBS.some((glob) =>
NodePath.matchesGlob(packagedPath, glob),
),
);
}
}),
),
);
it("excludes node-pty binaries for the other Windows architecture", () => {
assert.deepStrictEqual(resolveWindowsServerAsarIgnoreGlobs("x64"), [
...WINDOWS_SERVER_ASAR_IGNORE_GLOBS,
"**/node_modules/node-pty/prebuilds/win32-arm64",
"**/node_modules/node-pty/prebuilds/win32-arm64/**",
"**/node_modules/node-pty/third_party/conpty/*/win10-arm64",
"**/node_modules/node-pty/third_party/conpty/*/win10-arm64/**",
]);
assert.deepStrictEqual(resolveWindowsServerAsarIgnoreGlobs("arm64"), [
...WINDOWS_SERVER_ASAR_IGNORE_GLOBS,
"**/node_modules/node-pty/prebuilds/win32-x64",
"**/node_modules/node-pty/prebuilds/win32-x64/**",
"**/node_modules/node-pty/third_party/conpty/*/win10-x64",
"**/node_modules/node-pty/third_party/conpty/*/win10-x64/**",
]);
});
it.effect("keeps target native files while excluding the other Windows architecture", () =>
Effect.scoped(
Effect.gen(function* () {
const fs = yield* FileSystem.FileSystem;
const path = yield* Path.Path;
const tempDir = yield* fs.makeTempDirectoryScoped({
prefix: "t3-windows-architecture-test-",
});
const sourceDir = path.join(tempDir, "server");
const nativeFiles = [
"node_modules/node-pty/prebuilds/win32-x64/conpty/OpenConsole.exe",
"node_modules/node-pty/prebuilds/win32-arm64/conpty/OpenConsole.exe",
"node_modules/node-pty/third_party/conpty/1.0.0/win10-x64/OpenConsole.exe",
"node_modules/node-pty/third_party/conpty/1.0.0/win10-arm64/OpenConsole.exe",
];
for (const nativeFile of nativeFiles) {
const nativePath = path.join(sourceDir, nativeFile);
yield* fs.makeDirectory(path.dirname(nativePath), { recursive: true });
yield* fs.writeFileString(nativePath, "native");
}
const asarPath = path.join(tempDir, "server.asar");
yield* packWindowsServerAsar({ sourceDir, asarPath, arch: "x64" });
const unpackedRoot = `${asarPath}.unpacked`;
assert.isTrue(
yield* fs.exists(
path.join(
unpackedRoot,
"node_modules/node-pty/prebuilds/win32-x64/conpty/OpenConsole.exe",
),
),
);
assert.isFalse(
yield* fs.exists(path.join(unpackedRoot, "node_modules/node-pty/prebuilds/win32-arm64")),
);
assert.isFalse(
yield* fs.exists(
path.join(unpackedRoot, "node_modules/node-pty/third_party/conpty/1.0.0/win10-arm64"),
),
);
}),
),
);
it.effect("stages a cached resource monitor without invoking Cargo", () =>
Effect.scoped(
Effect.gen(function* () {
const fs = yield* FileSystem.FileSystem;
const path = yield* Path.Path;
const repoRoot = yield* fs.makeTempDirectoryScoped({
prefix: "t3-resource-monitor-cache-test-",
});
const binaryPath = path.join(
repoRoot,
"native/resource-monitor/target/x86_64-unknown-linux-gnu/release/t3-resource-monitor",
);
const stageResourcesDir = path.join(repoRoot, "stage");
yield* fs.makeDirectory(path.dirname(binaryPath), { recursive: true });
yield* fs.writeFileString(binaryPath, "cached monitor");
yield* stageResourceMonitor({
repoRoot,
stageResourcesDir,
platform: "linux",
arch: "x64",
verbose: false,
}).pipe(
Effect.provide(
ConfigProvider.layer(
ConfigProvider.fromEnv({
env: { T3CODE_DESKTOP_REUSE_RESOURCE_MONITOR: "true" },
}),
),
),
);
assert.equal(
yield* fs.readFileString(
path.join(stageResourcesDir, "resource-monitor/t3-resource-monitor"),
),
"cached monitor",
);
}),
),
);
it.effect("reports every missing Linux desktop build prerequisite with an install command", () =>
Effect.scoped(
Effect.gen(function* () {
const commands: Array<{ readonly command: string; readonly args: ReadonlyArray<string> }> =
[];
const spawner = Layer.succeed(
ChildProcessSpawner.ChildProcessSpawner,
ChildProcessSpawner.make((command) => {
const childProcess = command as unknown as {
readonly command: string;
readonly args: ReadonlyArray<string>;
};
commands.push(childProcess);
const fails =
childProcess.command === "cargo" ||
childProcess.command === "rustc" ||
childProcess.command === "pkg-config";
return Effect.succeed(mockProcess(fails ? 1 : 0));
}),
);
const error = yield* preflightLinuxDesktopBuild("arm64").pipe(
Effect.provide(spawner),
Effect.flip,
);
assert.instanceOf(error, LinuxDesktopBuildPrerequisitesMissingError);
assert.deepStrictEqual(error.missing, ["cargo", "rust-target", "libsecret"]);
assert.include(error.message, "Rust compiler and Cargo (cargo, rustc)");
assert.include(error.message, "Requested Rust standard library");
assert.include(
error.message,
"sudo apt-get install cargo rustc libsecret-1-dev pkg-config",
);
assert.include(error.message, "rustup target add aarch64-unknown-linux-gnu");
assert.isTrue(
commands.some(
(command) =>
command.command === "rustc" && command.args.includes("aarch64-unknown-linux-gnu"),
),
);
}),
),
);
it.effect("reports missing macOS tools and Rust targets before building", () =>
Effect.scoped(
Effect.gen(function* () {
const spawner = Layer.succeed(
ChildProcessSpawner.ChildProcessSpawner,
ChildProcessSpawner.make((command) => {
const childProcess = command as unknown as {
readonly command: string;
readonly args: ReadonlyArray<string>;
};
const fails =
childProcess.command === "rustc" ||
(childProcess.command === "xcrun" && childProcess.args.includes("iconutil"));
return Effect.succeed(mockProcess(fails ? 1 : 0));
}),
);
const error = yield* preflightMacDesktopBuild("universal").pipe(
Effect.provide(spawner),
Effect.flip,
);
assert.instanceOf(error, MacDesktopBuildPrerequisitesMissingError);
assert.deepStrictEqual(error.missing, ["rust", "iconutil"]);
assert.deepStrictEqual(error.rustTargets, ["aarch64-apple-darwin", "x86_64-apple-darwin"]);
assert.include(error.message, "xcode-select --install");
assert.include(error.message, "rustup target add aarch64-apple-darwin x86_64-apple-darwin");
}),
),
);
it.effect("reports missing Windows toolchain capabilities before building", () =>
Effect.scoped(
Effect.gen(function* () {
const fs = yield* FileSystem.FileSystem;
const path = yield* Path.Path;
const tempDir = yield* fs.makeTempDirectoryScoped({ prefix: "t3-windows-preflight-" });
const pythonPath = path.join(tempDir, "python.exe");
yield* fs.writeFileString(pythonPath, "python");
const spawner = Layer.succeed(
ChildProcessSpawner.ChildProcessSpawner,
ChildProcessSpawner.make((command) => {
const childProcess = command as unknown as { readonly command: string };
const fails =
childProcess.command === "rustc" ||
childProcess.command === "powershell.exe" ||
childProcess.command === pythonPath;
return Effect.succeed(mockProcess(fails ? 1 : 0));
}),
);
const error = yield* preflightWindowsDesktopBuild({
arch: "x64",
bundlesWslRuntime: true,
}).pipe(
Effect.provide(
Layer.merge(
spawner,
ConfigProvider.layer(
ConfigProvider.fromEnv({ env: { npm_config_python: pythonPath } }),
),
),
),
Effect.flip,
);
assert.instanceOf(error, WindowsDesktopBuildPrerequisitesMissingError);
assert.deepStrictEqual(error.missing, ["rust", "python", "msvc"]);
assert.equal(error.rustTarget, "x86_64-pc-windows-msvc");
assert.include(error.message, "Visual Studio Build Tools components");
}),
),
);
it.effect("does not require MSVC when reusing a prebuilt Windows resource monitor", () =>
Effect.scoped(
Effect.gen(function* () {
const fs = yield* FileSystem.FileSystem;
const path = yield* Path.Path;
const tempDir = yield* fs.makeTempDirectoryScoped({ prefix: "t3-windows-preflight-" });
const pythonPath = path.join(tempDir, "python.exe");
yield* fs.writeFileString(pythonPath, "python");
const commands: string[] = [];
const spawner = Layer.succeed(
ChildProcessSpawner.ChildProcessSpawner,
ChildProcessSpawner.make((command) => {
const childProcess = command as unknown as { readonly command: string };
commands.push(childProcess.command);
return Effect.succeed(mockProcess(childProcess.command === "powershell.exe" ? 1 : 0));
}),
);
yield* preflightWindowsDesktopBuild({
arch: "x64",
bundlesWslRuntime: true,
}).pipe(
Effect.provide(
Layer.merge(
spawner,
ConfigProvider.layer(
ConfigProvider.fromEnv({
env: {
npm_config_python: pythonPath,
T3CODE_DESKTOP_REUSE_RESOURCE_MONITOR: "true",
},
}),
),
),
),
);
assert.notInclude(commands, "powershell.exe");
}),
),
);
it.effect("rejects a PATH-discovered Python executable that is not Python 3", () =>
Effect.scoped(
Effect.gen(function* () {
const fs = yield* FileSystem.FileSystem;
const path = yield* Path.Path;
const tempDir = yield* fs.makeTempDirectoryScoped({ prefix: "t3-python2-preflight-" });
const pythonPath = path.join(tempDir, "python");
yield* fs.writeFileString(pythonPath, "python2");
const spawner = Layer.succeed(
ChildProcessSpawner.ChildProcessSpawner,
ChildProcessSpawner.make((command) => {
const childProcess = command as unknown as {
readonly command: string;
readonly args: ReadonlyArray<string>;
};
if (childProcess.command === "python") {
return Effect.succeed(mockProcess(0, `${pythonPath}\n`));
}
if (childProcess.command === pythonPath) {
return Effect.succeed(mockProcess(1));
}
return Effect.succeed(mockProcess(0));
}),
);
const error = yield* preflightWindowsDesktopBuild({
arch: "x64",
bundlesWslRuntime: false,
}).pipe(
Effect.provide(
Layer.merge(
spawner,
ConfigProvider.layer(
ConfigProvider.fromEnv({
env: { T3CODE_DESKTOP_REUSE_RESOURCE_MONITOR: "true" },
}),
),
),
),
Effect.flip,
);
assert.instanceOf(error, WindowsDesktopBuildPrerequisitesMissingError);
assert.deepStrictEqual(error.missing, ["python"]);
}),
),
);
it.effect("builds and stages native capture helpers for each Linux architecture", () =>
Effect.scoped(
Effect.gen(function* () {
const fs = yield* FileSystem.FileSystem;
const path = yield* Path.Path;
const repoRoot = yield* fs.makeTempDirectoryScoped({ prefix: "t3-kde-stage-test-" });
const protocols = path.join(repoRoot, "native/hyprland-snap-shot/protocols");
yield* fs.makeDirectory(protocols, { recursive: true });
yield* fs.writeFileString(path.join(protocols, "capture.xml"), "BSD protocol notice");
for (const backend of ["kde", "hyprland"] as const) {
for (const [arch, target] of [
["x64", "x86_64-unknown-linux-gnu"],
["arm64", "aarch64-unknown-linux-gnu"],
] as const) {
const binary = path.join(
repoRoot,
`native/${backend}-snap-shot/target`,
target,
`release/t3-${backend}-snap-shot`,
);
const stageResourcesDir = path.join(repoRoot, "stage", backend, arch);
const spawner = Layer.succeed(
ChildProcessSpawner.ChildProcessSpawner,
ChildProcessSpawner.make((command) =>
Effect.gen(function* () {
assert.equal(command._tag, "StandardCommand");
if (command._tag !== "StandardCommand") return mockProcess(1);
assert.equal(command.command, "cargo");
assert.deepEqual(command.args, [
"build",
"--locked",
"--release",
"--manifest-path",
path.join(repoRoot, `native/${backend}-snap-shot/Cargo.toml`),
"--target",
target,
]);
yield* fs.makeDirectory(path.dirname(binary), { recursive: true });
yield* fs.writeFileString(binary, `helper-${arch}`);
return mockProcess(0);
}),
),
);
yield* stageLinuxCaptureHelper({
backend,
repoRoot,
stageResourcesDir,
arch,
verbose: false,
}).pipe(Effect.provide(spawner));
const installed = path.join(
stageResourcesDir,
`${backend}-capture/t3-${backend}-snap-shot`,
);
assert.equal(yield* fs.readFileString(installed), `helper-${arch}`);
assert.equal((yield* fs.stat(installed)).mode & 0o777, 0o755);
if (backend === "hyprland")
assert.equal(
yield* fs.readFileString(
path.join(stageResourcesDir, "hyprland-capture/protocols/capture.xml"),
),
"BSD protocol notice",
);
}
}
}),
),
);
// The fixture's t3code.exe is a text placeholder, not an executable. These
// cases reach the native-load probe, so pin only that host-platform check to
// Linux. Host-native paths and the real Windows tar/archive checks still run.
it.effect("validates every ASAR-unpacked native in the packaged Windows payload", () =>
Effect.scoped(
Effect.gen(function* () {
const fs = yield* FileSystem.FileSystem;
const path = yield* Path.Path;
const fixture = yield* makeWindowsPayloadFixture({ copyUnpackedNatives: true });
const result = yield* validateWindowsPackagedPayload({
stageDistDir: fixture.stageDistDir,
appExecutableName: fixture.appExecutableName,
targetArch: "x64",
appVersion: WINDOWS_PAYLOAD_FIXTURE_VERSION,
});
const secondAsarPath = path.join(path.dirname(fixture.generatedAsarPath), "second.asar");
yield* packWindowsServerAsar({
sourceDir: fixture.sourceDir,
asarPath: secondAsarPath,
arch: "x64",
});
const [firstAsar, secondAsar] = yield* Effect.all([
fs.readFile(fixture.generatedAsarPath),
fs.readFile(secondAsarPath),
]);
assert.equal(result.packagedAppDir, fixture.packagedAppDir);
assert.deepStrictEqual(result.unpackedFiles, ["node_modules/native/addon.node"]);
assert.isBelow(result.fileCount, WINDOWS_PACKAGED_PAYLOAD_FILE_LIMIT);
assert.deepStrictEqual(secondAsar, firstAsar);
}),
).pipe(Effect.provideService(HostProcessPlatform, "linux")),
);
it.effect("accepts an embedded Linux CLI release archive with a matching digest", () =>
Effect.scoped(
Effect.gen(function* () {
const fixture = yield* makeWindowsPayloadFixture({
copyUnpackedNatives: true,
wslRuntime: "valid",
});
const result = yield* validateWindowsPackagedPayload({
stageDistDir: fixture.stageDistDir,
appExecutableName: fixture.appExecutableName,
targetArch: "x64",
appVersion: WINDOWS_PAYLOAD_FIXTURE_VERSION,
expectWslRuntime: true,
});
assert.equal(result.packagedAppDir, fixture.packagedAppDir);
}),
).pipe(Effect.provideService(HostProcessPlatform, "linux")),
);
it.effect.each(["x64", "arm64"] as const)(
"accepts an embedded archive with the Linux %s node-pty prebuild",
(targetArch) =>
Effect.scoped(
Effect.gen(function* () {
const fixture = yield* makeWindowsPayloadFixture({
copyUnpackedNatives: true,
wslRuntime: "valid",
targetArch,
ptyPrebuildArch: targetArch,
});
const result = yield* validateWindowsPackagedPayload({
stageDistDir: fixture.stageDistDir,
appExecutableName: fixture.appExecutableName,
targetArch,
appVersion: WINDOWS_PAYLOAD_FIXTURE_VERSION,
expectWslRuntime: true,
});
assert.equal(result.packagedAppDir, fixture.packagedAppDir);
}),
).pipe(Effect.provideService(HostProcessPlatform, "linux")),
);
it.effect.each(["x64", "arm64"] as const)(
"rejects a node-pty prebuild for the wrong architecture in a Linux %s archive",
(targetArch) =>
Effect.scoped(
Effect.gen(function* () {
const fixture = yield* makeWindowsPayloadFixture({
copyUnpackedNatives: true,
wslRuntime: "valid",
targetArch,
ptyPrebuildArch: targetArch === "x64" ? "arm64" : "x64",
});
const error = yield* validateWindowsPackagedPayload({
stageDistDir: fixture.stageDistDir,
appExecutableName: fixture.appExecutableName,
targetArch,
appVersion: WINDOWS_PAYLOAD_FIXTURE_VERSION,
expectWslRuntime: true,
}).pipe(Effect.flip);
assert.instanceOf(error, WindowsPackagedPayloadValidationError);
assert.equal(error.reason, "wsl-runtime-invalid");
}),
),
);
it.effect("rejects an embedded archive built for a different release version", () =>
Effect.scoped(
Effect.gen(function* () {
const fixture = yield* makeWindowsPayloadFixture({
copyUnpackedNatives: true,
wslRuntime: "valid",
});
const error = yield* validateWindowsPackagedPayload({
stageDistDir: fixture.stageDistDir,
appExecutableName: fixture.appExecutableName,
targetArch: "x64",
appVersion: "9.9.9",
expectWslRuntime: true,
}).pipe(Effect.flip);
assert.instanceOf(error, WindowsPackagedPayloadValidationError);
assert.equal(error.reason, "wsl-runtime-invalid");
}),
),
);
it.effect("rejects a Windows package missing its expected WSL runtime", () =>
Effect.scoped(
Effect.gen(function* () {
const fixture = yield* makeWindowsPayloadFixture({ copyUnpackedNatives: true });
const error = yield* validateWindowsPackagedPayload({
stageDistDir: fixture.stageDistDir,
appExecutableName: fixture.appExecutableName,
targetArch: "x64",
appVersion: WINDOWS_PAYLOAD_FIXTURE_VERSION,
expectWslRuntime: true,
}).pipe(Effect.flip);
assert.instanceOf(error, WindowsPackagedPayloadValidationError);
assert.equal(error.reason, "wsl-runtime-missing");
}),
),
);
it.effect("rejects a loose server tree that is not a Linux CLI release archive", () =>
Effect.scoped(
Effect.gen(function* () {
const fixture = yield* makeWindowsPayloadFixture({
copyUnpackedNatives: true,
wslRuntime: "loose-server-tree",
});
const error = yield* validateWindowsPackagedPayload({
stageDistDir: fixture.stageDistDir,
appExecutableName: fixture.appExecutableName,
targetArch: "x64",
appVersion: WINDOWS_PAYLOAD_FIXTURE_VERSION,
expectWslRuntime: true,
}).pipe(Effect.flip);
assert.instanceOf(error, WindowsPackagedPayloadValidationError);
assert.equal(error.reason, "wsl-runtime-invalid");
}),
),
);
it.effect("rejects an embedded archive without the Linux node-pty binary", () =>
Effect.scoped(
Effect.gen(function* () {
const fixture = yield* makeWindowsPayloadFixture({
copyUnpackedNatives: true,
wslRuntime: "missing-pty",
});
const error = yield* validateWindowsPackagedPayload({
stageDistDir: fixture.stageDistDir,
appExecutableName: fixture.appExecutableName,
targetArch: "x64",
appVersion: WINDOWS_PAYLOAD_FIXTURE_VERSION,
expectWslRuntime: true,
}).pipe(Effect.flip);
assert.instanceOf(error, WindowsPackagedPayloadValidationError);
assert.equal(error.reason, "wsl-runtime-invalid");
assert.deepStrictEqual(error.missingFiles, [
`${wslRuntimeArchiveStem(WINDOWS_PAYLOAD_FIXTURE_VERSION, "x64")}/node_modules/node-pty/build/Release/pty.node`,
`${wslRuntimeArchiveStem(WINDOWS_PAYLOAD_FIXTURE_VERSION, "x64")}/node_modules/node-pty/prebuilds/linux-x64/pty.node`,
]);
}),
),
);
it.effect("rejects an emitted WSL archive whose sidecar digest does not match", () =>
Effect.scoped(
Effect.gen(function* () {
const fixture = yield* makeWindowsPayloadFixture({
copyUnpackedNatives: true,
wslRuntime: "bad-digest",
});
const error = yield* validateWindowsPackagedPayload({
stageDistDir: fixture.stageDistDir,
appExecutableName: fixture.appExecutableName,
targetArch: "x64",
appVersion: WINDOWS_PAYLOAD_FIXTURE_VERSION,
expectWslRuntime: true,
}).pipe(Effect.flip);
assert.instanceOf(error, WindowsPackagedPayloadValidationError);
assert.equal(error.reason, "wsl-runtime-invalid");
}),
),
);
it.effect("probes fff through the packaged Windows primary instead of helper executables", () => {
const commands: Array<{
readonly command: string;
readonly args: ReadonlyArray<string>;
readonly options: {
readonly cwd?: string;
readonly env?: Readonly<Record<string, string | undefined>>;
};
}> = [];
const spawnerLayer = Layer.succeed(
ChildProcessSpawner.ChildProcessSpawner,
ChildProcessSpawner.make((command) => {
commands.push(command as unknown as (typeof commands)[number]);
return Effect.succeed(mockProcess(0));
}),
);
return Effect.scoped(
Effect.gen(function* () {
const path = yield* Path.Path;
const fixture = yield* makeWindowsPayloadFixture({ copyUnpackedNatives: true });
yield* validateWindowsPackagedPayload({
stageDistDir: fixture.stageDistDir,
appExecutableName: fixture.appExecutableName,
targetArch: "x64",
appVersion: WINDOWS_PAYLOAD_FIXTURE_VERSION,
});
const primaryProbe = commands.find(
(command) => command.options.env?.ELECTRON_RUN_AS_NODE === "1",
);
if (primaryProbe === undefined) return assert.fail("Windows primary probe was not spawned");
assert.equal(
primaryProbe.command,
path.join(fixture.packagedAppDir, fixture.appExecutableName),
);
assert.deepStrictEqual(primaryProbe.args.slice(0, 3), [
"--no-global-search-paths",
"--input-type=module",
"--eval",
]);
assert.include(primaryProbe.args[3], "FileFinder.create");
assert.equal(
primaryProbe.args[4],
path.join(
fixture.packagedAppDir,
"resources/server.asar/node_modules/@ff-labs/fff-node/dist/src/index.js",
),
);
assert.equal(primaryProbe.options.cwd, fixture.packagedAppDir);
assert.equal(primaryProbe.options.env?.NODE_PATH, "");
}),
).pipe(
Effect.provide(
Layer.mergeAll(
spawnerLayer,
Layer.succeed(HostProcessPlatform, "win32"),
Layer.succeed(HostProcessArchitecture, "x64"),
),
),
);
});
it.effect("builds the Linux browser secret helper for a concrete architecture", () => {
const commands: Array<{ readonly command: string; readonly args: ReadonlyArray<string> }> = [];
const spawnerLayer = Layer.succeed(
ChildProcessSpawner.ChildProcessSpawner,
ChildProcessSpawner.make((command) => {
commands.push(command as unknown as (typeof commands)[number]);
return Effect.succeed(mockProcess(0));
}),
);
return Effect.gen(function* () {
// `universal` is a mac-only arch the option type still admits. The helper
// script only knows x64 and arm64, so the request maps to x64, the same
// concrete target the Linux resource monitor resolves it to.
yield* stageBrowserSecret({
repoRoot: "/repo",
stageResourcesDir: "/stage/resources",
platform: "linux",
arch: "universal",
verbose: false,
});
const helper = commands.find((command) =>
command.args.some((arg) => arg.endsWith("build-browser-secret.mjs")),
);
assert.isDefined(helper);
const path = yield* Path.Path;
assert.deepStrictEqual(helper.args.slice(-4), [
"--arch",
"x64",
"--output",
path.join("/stage/resources", "browser-secret", "t3-browser-secret"),
]);
}).pipe(
Effect.provide(
Layer.mergeAll(
spawnerLayer,
Layer.succeed(HostProcessPlatform, "linux"),
Layer.succeed(HostProcessArchitecture, "x64"),
),
),
);
});
it.effect("refuses a Linux build on a host that cannot build the browser secret helper", () => {
const commands: Array<{ readonly command: string }> = [];
const spawnerLayer = Layer.succeed(
ChildProcessSpawner.ChildProcessSpawner,
ChildProcessSpawner.make((command) => {
commands.push(command as unknown as (typeof commands)[number]);
return Effect.succeed(mockProcess(0));
}),
);
return Effect.gen(function* () {
// The helper links against the host's libsecret and its build script is
// a no-op elsewhere, so a Linux artifact built on macOS would ship
// without it and report the keyring as unavailable on every import.
const error = yield* stageBrowserSecret({
repoRoot: "/repo",
stageResourcesDir: "/stage/resources",
platform: "linux",
arch: "x64",
verbose: false,
}).pipe(Effect.flip);
assert.instanceOf(error, LinuxBrowserSecretHostError);
assert.equal(error.hostPlatform, "darwin");
assert.include(error.message, "Linux host");
assert.lengthOf(commands, 0);
}).pipe(
Effect.provide(
Layer.mergeAll(
spawnerLayer,
Layer.succeed(HostProcessPlatform, "darwin"),
Layer.succeed(HostProcessArchitecture, "arm64"),
),
),
);
});
it.effect("skips the primary native probe for cross-architecture Windows payloads", () => {
const commands: Array<{
readonly command: string;
readonly options: {
readonly env?: Readonly<Record<string, string | undefined>>;
};
}> = [];
const spawnerLayer = Layer.succeed(
ChildProcessSpawner.ChildProcessSpawner,
ChildProcessSpawner.make((command) => {
commands.push(command as unknown as (typeof commands)[number]);
return Effect.succeed(mockProcess(0));
}),
);
return Effect.scoped(
Effect.gen(function* () {
const fixture = yield* makeWindowsPayloadFixture({ copyUnpackedNatives: true });
yield* validateWindowsPackagedPayload({
stageDistDir: fixture.stageDistDir,
appExecutableName: fixture.appExecutableName,
targetArch: "arm64",
appVersion: WINDOWS_PAYLOAD_FIXTURE_VERSION,
});
assert.isFalse(
commands.some((command) => command.options.env?.ELECTRON_RUN_AS_NODE === "1"),
);
assert.isTrue(
commands.some(
(command) =>
command.command === process.execPath && command.options.env?.NODE_PATH === "",
),
);
}),
).pipe(
Effect.provide(
Layer.mergeAll(
spawnerLayer,
Layer.succeed(HostProcessPlatform, "win32"),
Layer.succeed(HostProcessArchitecture, "x64"),
),
),
);
});
it.effect("rejects a cross-architecture Windows payload without its primary executable", () =>
Effect.scoped(
Effect.gen(function* () {
const fs = yield* FileSystem.FileSystem;
const path = yield* Path.Path;
const fixture = yield* makeWindowsPayloadFixture({ copyUnpackedNatives: true });
const executablePath = path.join(fixture.packagedAppDir, fixture.appExecutableName);
yield* fs.remove(executablePath);
const error = yield* validateWindowsPackagedPayload({
stageDistDir: fixture.stageDistDir,
appExecutableName: fixture.appExecutableName,
targetArch: "arm64",
appVersion: WINDOWS_PAYLOAD_FIXTURE_VERSION,
}).pipe(Effect.flip);
assert.instanceOf(error, WindowsPrimaryNativeProbeError);
assert.equal(error.executablePath, executablePath);
}),
).pipe(
Effect.provide(
Layer.mergeAll(
Layer.succeed(HostProcessPlatform, "win32"),
Layer.succeed(HostProcessArchitecture, "x64"),
),
),
),
);
it.effect("rejects a packaged sidecar whose ASAR-unpacked native is missing", () =>
Effect.scoped(
Effect.gen(function* () {
const fixture = yield* makeWindowsPayloadFixture({ copyUnpackedNatives: false });
const error = yield* validateWindowsPackagedPayload({
stageDistDir: fixture.stageDistDir,
appExecutableName: fixture.appExecutableName,
targetArch: "x64",
appVersion: WINDOWS_PAYLOAD_FIXTURE_VERSION,
}).pipe(Effect.flip);
assert.instanceOf(error, WindowsPackagedPayloadValidationError);
assert.equal(error.reason, "unpacked-native-missing");
assert.deepStrictEqual(error.missingFiles, [
"server.asar.unpacked/node_modules/native/addon.node",
]);
}),
),
);
it.effect("rejects directories in place of packaged executable files", () =>
Effect.scoped(
Effect.gen(function* () {
const fs = yield* FileSystem.FileSystem;
const path = yield* Path.Path;
const fixture = yield* makeWindowsPayloadFixture({ copyUnpackedNatives: true });
const nativePath = path.join(
fixture.packagedAppDir,
"resources/server.asar.unpacked/node_modules/native/addon.node",
);
yield* fs.remove(nativePath);
yield* fs.makeDirectory(nativePath);
const nativeError = yield* validateWindowsPackagedPayload({
stageDistDir: fixture.stageDistDir,
appExecutableName: fixture.appExecutableName,
targetArch: "x64",
appVersion: WINDOWS_PAYLOAD_FIXTURE_VERSION,
}).pipe(Effect.flip);
assert.instanceOf(nativeError, WindowsPackagedPayloadValidationError);
assert.equal(nativeError.reason, "unpacked-native-missing");
assert.deepStrictEqual(nativeError.missingFiles, [
"server.asar.unpacked/node_modules/native/addon.node",
]);
yield* fs.remove(nativePath, { recursive: true });
yield* fs.writeFileString(nativePath, "native-binary");
const resourceMonitorPath = path.join(
fixture.packagedAppDir,
"resources/resource-monitor/t3-resource-monitor.exe",
);
yield* fs.remove(resourceMonitorPath);
yield* fs.makeDirectory(resourceMonitorPath);
const resourceMonitorError = yield* validateWindowsPackagedPayload({
stageDistDir: fixture.stageDistDir,
appExecutableName: fixture.appExecutableName,
targetArch: "x64",
appVersion: WINDOWS_PAYLOAD_FIXTURE_VERSION,
}).pipe(Effect.flip);
assert.instanceOf(resourceMonitorError, WindowsPackagedPayloadValidationError);
assert.equal(resourceMonitorError.reason, "resource-monitor-missing");
assert.deepStrictEqual(resourceMonitorError.missingFiles, [
"resource-monitor/t3-resource-monitor.exe",
]);
}),
),
);
it.effect("rejects a Windows payload that regresses above the file-count budget", () =>
Effect.scoped(
Effect.gen(function* () {
const fixture = yield* makeWindowsPayloadFixture({ copyUnpackedNatives: true });
const error = yield* validateWindowsPackagedPayload({
stageDistDir: fixture.stageDistDir,
appExecutableName: fixture.appExecutableName,
targetArch: "x64",
appVersion: WINDOWS_PAYLOAD_FIXTURE_VERSION,
fileLimit: 2,
}).pipe(Effect.flip);
assert.instanceOf(error, WindowsPackagedPayloadValidationError);
assert.equal(error.reason, "file-limit-exceeded");
assert.isAbove(error.fileCount ?? 0, 2);
}),
),
);
it.effect("rejects a sidecar whose extracted server bundle cannot resolve", () =>
Effect.scoped(
Effect.gen(function* () {
const fixture = yield* makeWindowsPayloadFixture({
copyUnpackedNatives: true,
serverEntrySource: 'import "t3code-deliberately-missing-package";\n',
});
const error = yield* validateWindowsPackagedPayload({
stageDistDir: fixture.stageDistDir,
appExecutableName: fixture.appExecutableName,
targetArch: "x64",
appVersion: WINDOWS_PAYLOAD_FIXTURE_VERSION,
}).pipe(Effect.flip);
assert.instanceOf(error, BundleNotSelfContainedError);
assert.include(error.output, "t3code-deliberately-missing-package");
}),
).pipe(Effect.provideService(HostProcessPlatform, "linux")),
);
it.effect("preserves both Linux icon resize failures with structural context", () => {
const commands: Array<{ readonly command: string; readonly args: ReadonlyArray<string> }> = [];
return Effect.gen(function* () {
const error = yield* stageLinuxIconSize("source.png", "target.png", 512, false).pipe(
Effect.provide(iconResizeSpawnerLayer(commands, [1, 2])),
Effect.flip,
);
assert.instanceOf(error, LinuxIconResizeError);
assert.equal(error.operation, "resize");
assert.equal(error.iconSize, 512);
assert.equal(error.primaryTool, "magick");
assert.equal(error.fallbackTool, "convert");
assert.include(error.message, "512x512");
assert.include(error.message, "`magick`");
assert.include(error.message, "`convert`");
assert.notInclude(error.message, "non-zero exit code");
assert.instanceOf(error.cause, AggregateError);
const aggregateCause = error.cause as AggregateError;
assert.lengthOf(aggregateCause.errors, 2);
assert.strictEqual(aggregateCause.cause, aggregateCause.errors[0]);
assert.instanceOf(aggregateCause.errors[0], BuildCommandFailedError);
assert.instanceOf(aggregateCause.errors[1], BuildCommandFailedError);
const primaryError = aggregateCause.errors[0] as BuildCommandFailedError;
const fallbackError = aggregateCause.errors[1] as BuildCommandFailedError;
assert.equal(primaryError.command, "magick linux icon 512x512");
assert.equal(primaryError.exitCode, 1);
assert.include(primaryError.message, "magick linux icon");
assert.equal(fallbackError.command, "convert linux icon 512x512");
assert.equal(fallbackError.exitCode, 2);
assert.include(fallbackError.message, "convert linux icon");
assert.deepStrictEqual(
commands.map(({ command }) => command),
["magick", "convert"],
);
});
});
it.effect("rasterizes staged DMG backgrounds at standard and Retina sizes", () =>
Effect.scoped(
Effect.gen(function* () {
const fs = yield* FileSystem.FileSystem;
const path = yield* Path.Path;
const stageResourcesDir = yield* fs.makeTempDirectoryScoped({
prefix: "t3code-dmg-background-",
});
const dmgDir = path.join(stageResourcesDir, "dmg");
yield* fs.makeDirectory(dmgDir, { recursive: true });
const sourcePath = path.join(dmgDir, "dmg-background-nightly.svg");
yield* fs.writeFileString(sourcePath, '<svg xmlns="http://www.w3.org/2000/svg"/>');
const commands: Array<{ readonly command: string; readonly args: ReadonlyArray<string> }> =
[];
yield* stageDesktopDmgBackground(stageResourcesDir, "nightly", false).pipe(
Effect.provide(iconResizeSpawnerLayer(commands, [0, 0])),
);
assert.deepStrictEqual(
commands.map((command) => [command.command, ...command.args]),
[
[
"sips",
"-s",
"format",
"png",
"-z",
"432",
"640",
sourcePath,
"--out",
path.join(dmgDir, "dmg-background-nightly.png"),
],
[
"sips",
"-s",
"format",
"png",
"-z",
"864",
"1280",
sourcePath,
"--out",
path.join(dmgDir, "dmg-background-nightly@2x.png"),
],
],
);
}),
),
);
it.effect("fails clearly when the selected DMG background source is missing", () =>
Effect.scoped(
Effect.gen(function* () {
const fs = yield* FileSystem.FileSystem;
const stageResourcesDir = yield* fs.makeTempDirectoryScoped({
prefix: "t3code-dmg-background-missing-",
});
const error = yield* stageDesktopDmgBackground(stageResourcesDir, "latest", false).pipe(
Effect.flip,
);
assert.instanceOf(error, DesktopDmgBackgroundSourceMissingError);
assert.equal(error.channel, "latest");
assert.include(error.sourcePath, "dmg-background-latest.svg");
}),
),
);
it("derives macOS passkey signing configuration from the Clerk publishable key", () => {
const configuration = resolveMacPasskeySigningConfiguration({
T3CODE_APPLE_TEAM_ID: "abc1234567",
T3CODE_MACOS_PROVISIONING_PROFILE: "/tmp/t3code.provisionprofile",
T3CODE_CLERK_PUBLISHABLE_KEY: `pk_test_${btoa("example.clerk.accounts.dev$")}`,
});
assert.deepStrictEqual(configuration, {
appId: "com.t3tools.t3code",
teamId: "ABC1234567",
rpDomains: ["example.clerk.accounts.dev"],
provisioningProfilePath: "/tmp/t3code.provisionprofile",
});
});
it("normalizes explicit macOS passkey RP domains and renders required entitlements", () => {
const configuration = resolveMacPasskeySigningConfiguration({
T3CODE_APPLE_TEAM_ID: "ABC1234567",
T3CODE_MACOS_PROVISIONING_PROFILE: "/tmp/t3code.provisionprofile",
T3CODE_CLERK_PASSKEY_RP_DOMAINS:
" Clerk.Example.com,example.clerk.accounts.dev,clerk.example.com ",
});
const entitlements = renderMacPasskeyEntitlements(configuration);
assert.deepStrictEqual(configuration.rpDomains, [
"clerk.example.com",
"example.clerk.accounts.dev",
]);
assert.include(entitlements, "<string>ABC1234567.com.t3tools.t3code</string>");
assert.include(entitlements, "<string>webcredentials:clerk.example.com</string>");
assert.include(entitlements, "<string>webcredentials:example.clerk.accounts.dev</string>");
assert.include(entitlements, "<key>com.apple.security.cs.allow-jit</key>");
});
it("rejects incomplete macOS passkey signing configuration", () => {
const captureError = (env: Readonly<Record<string, string | undefined>>) => {
try {
resolveMacPasskeySigningConfiguration(env);
} catch (error) {
return error;
}
return assert.fail("Expected passkey signing configuration to fail.");
};
const missingProfileError = captureError({
T3CODE_APPLE_TEAM_ID: "ABC1234567",
T3CODE_CLERK_PASSKEY_RP_DOMAINS: "example.clerk.accounts.dev",
});
assert.instanceOf(missingProfileError, MissingMacPasskeyProvisioningProfileError);
assert.equal(
missingProfileError.message,
"T3CODE_MACOS_PROVISIONING_PROFILE must point to an Associated Domains provisioning profile.",
);
const unsafeDomain =
"https://domain-user:domain-secret@example.clerk.accounts.dev/path?token=query-secret";
const invalidDomainError = captureError({
T3CODE_APPLE_TEAM_ID: "ABC1234567",
T3CODE_MACOS_PROVISIONING_PROFILE: "/tmp/t3code.provisionprofile",
T3CODE_CLERK_PASSKEY_RP_DOMAINS: unsafeDomain,
});
assert.instanceOf(invalidDomainError, InvalidMacPasskeyRpDomainError);
assert.equal(invalidDomainError.reason, "scheme-not-allowed");
assert.equal(invalidDomainError.inputLength, unsafeDomain.length);
assert.equal(invalidDomainError.message, "Invalid passkey RP domain (scheme-not-allowed).");
assert.notProperty(invalidDomainError, "domain");
assert.notProperty(invalidDomainError, "cause");
const serializedInvalidDomainError = JSON.stringify(invalidDomainError);
assert.notInclude(serializedInvalidDomainError, unsafeDomain);
assert.notInclude(serializedInvalidDomainError, "domain-user");
assert.notInclude(serializedInvalidDomainError, "domain-secret");
assert.notInclude(serializedInvalidDomainError, "query-secret");
assert.throws(
() =>
resolveMacPasskeySigningConfiguration({
T3CODE_APPLE_TEAM_ID: "ABC1234567",
T3CODE_MACOS_PROVISIONING_PROFILE: "/tmp/t3code.provisionprofile",
T3CODE_CLERK_PASSKEY_RP_DOMAINS: "example.clerk.accounts.dev:8443",
}),
/Invalid passkey RP domain/u,
);
const invalidPublishableKeyError = captureError({
T3CODE_APPLE_TEAM_ID: "ABC1234567",
T3CODE_MACOS_PROVISIONING_PROFILE: "/tmp/t3code.provisionprofile",
T3CODE_CLERK_PUBLISHABLE_KEY: "pk_test_%",
});
assert.instanceOf(invalidPublishableKeyError, InvalidMacPasskeyPublishableKeyError);
assert.ok(invalidPublishableKeyError.cause);
assert.equal(invalidPublishableKeyError.message, "T3CODE_CLERK_PUBLISHABLE_KEY is invalid.");
assert.notProperty(invalidPublishableKeyError, "publishableKey");
assert.notInclude(invalidPublishableKeyError.message, "pk_test_%");
});
it("preserves known passkey signing configuration errors at the build boundary", () => {
const decodingCause = new Error("publishable-key-decode-failed");
const knownError = new InvalidMacPasskeyPublishableKeyError({ cause: decodingCause });
const error = MacPasskeySigningConfigurationResolutionError.fromCause(knownError);
assert.strictEqual(error, knownError);
assert.instanceOf(error, InvalidMacPasskeyPublishableKeyError);
assert.strictEqual(error.cause, decodingCause);
assert.isTrue(isMacPasskeySigningConfigurationError(error));
});
it("wraps unknown passkey signing configuration defects without copying cause text", () => {
const secret = "pk_test_do-not-retain";
const cause = new Error(secret);
const error = MacPasskeySigningConfigurationResolutionError.fromCause(cause);
assert.instanceOf(error, MacPasskeySigningConfigurationResolutionError);
assert.strictEqual(error.cause, cause);
assert.equal(error.message, "Failed to resolve macOS passkey signing configuration.");
assert.notInclude(error.message, secret);
});
it.effect("adds passkey entitlements and both renderer protocols to signed macOS builds", () =>
Effect.gen(function* () {
const config = yield* createBuildConfig("mac", "dmg", "1.2.3", true, false, undefined, {
entitlementsPath: "/tmp/entitlements.mac.plist",
provisioningProfilePath: "/tmp/t3code.provisionprofile",
});
const mac = config.mac as Record<string, unknown>;
assert.equal(config.appId, "com.t3tools.t3code");
assert.equal(mac.entitlements, "/tmp/entitlements.mac.plist");
assert.equal(mac.provisioningProfile, "/tmp/t3code.provisionprofile");
assert.match(String(mac.sign), /[\\/]scripts[\\/]sign-macos\.ts$/);
assert.deepStrictEqual(mac.protocols, [
{ name: "T3 Code", schemes: ["t3code", "t3code-dev"] },
]);
}).pipe(Effect.provide(ConfigProvider.layer(ConfigProvider.fromEnv({ env: {} })))),
);
it.effect("uses the nightly DMG background for nightly macOS builds", () =>
Effect.gen(function* () {
const config = yield* createBuildConfig(
"mac",
"dmg",
"1.2.3-nightly.20260815.1",
false,
false,
undefined,
undefined,
);
assert.equal(
(config.dmg as Record<string, unknown>).background,
"dmg/dmg-background-nightly.png",
);
}).pipe(Effect.provide(ConfigProvider.layer(ConfigProvider.fromEnv({ env: {} })))),
);
it.effect("keeps executable resource editing enabled for unsigned Windows builds", () =>
Effect.gen(function* () {
const config = yield* createBuildConfig(
"win",
"nsis",
"1.2.3",
false,
false,
undefined,
undefined,
);
const win = config.win as Record<string, unknown>;
assert.equal(win.icon, "icon.ico");
assert.equal(win.signAndEditExecutable, true);
assert.notProperty(win, "azureSignOptions");
}).pipe(Effect.provide(ConfigProvider.layer(ConfigProvider.fromEnv({ env: {} })))),
);
it("stages the resource monitor as an external executable resource", () => {
assert.deepStrictEqual(DESKTOP_EXTRA_RESOURCES, [
{
from: "apps/desktop/prod-resources/cursor-sdk",
to: "node_modules/@cursor",
},
{
from: "apps/desktop/prod-resources/resource-monitor",
to: "resource-monitor",
},
]);
assert.deepStrictEqual(resolveResourceMonitorRustTargets("mac", "universal"), [
"aarch64-apple-darwin",
"x86_64-apple-darwin",
]);
assert.deepStrictEqual(resolveResourceMonitorRustTargets("linux", "x64"), [
"x86_64-unknown-linux-gnu",
]);
assert.deepStrictEqual(resolveResourceMonitorRustTargets("win", "arm64"), [
"aarch64-pc-windows-msvc",
]);
assert.equal(resourceMonitorExecutableName("mac"), "t3-resource-monitor");
assert.equal(resourceMonitorExecutableName("win"), "t3-resource-monitor.exe");
});
it("ships the Linux CLI release archive as the WSL runtime", () => {
assert.equal(WSL_RUNTIME_ARCHIVE_NAME, "wsl-runtime.tar.gz");
assert.equal(WSL_RUNTIME_ARCHIVE_HASH_NAME, "wsl-runtime.tar.gz.sha256");
assert.deepStrictEqual(WSL_RUNTIME_ARCHIVE_EXTRA_RESOURCE, {
from: "apps/desktop/prod-resources/wsl-runtime.tar.gz",
to: "wsl-runtime.tar.gz",
});
assert.deepStrictEqual(WSL_RUNTIME_ARCHIVE_HASH_EXTRA_RESOURCE, {
from: "apps/desktop/prod-resources/wsl-runtime.tar.gz.sha256",
to: "wsl-runtime.tar.gz.sha256",
});
// Both the staging and the packaging config hang off this one decision:
// Windows only, and only when CI handed the build a Linux CLI archive.
const runtimeArchivePath = "/tmp/t3-1.2.3-linux-x64.tar.gz";
assert.isTrue(bundlesWslRuntime({ platform: "win", runtimeArchivePath }));
assert.isFalse(bundlesWslRuntime({ platform: "win", runtimeArchivePath: undefined }));
assert.isFalse(bundlesWslRuntime({ platform: "linux", runtimeArchivePath }));
assert.isFalse(bundlesWslRuntime({ platform: "mac", runtimeArchivePath }));
assert.equal(wslRuntimeArchiveStem("1.2.3", "x64"), "t3-1.2.3-linux-x64");
});
it("parses Windows bsdtar member listings with CRLF line endings", () => {
assert.deepStrictEqual(
parseWslRuntimeArchiveMembers("./t3-1.2.3-linux-x64/t3\r\nt3-1.2.3-linux-x64/client/\r\n"),
["t3-1.2.3-linux-x64/t3", "t3-1.2.3-linux-x64/client"],
);
});
it.effect("stages the Linux CLI archive verbatim with its SHA-256 sidecar", () =>
Effect.scoped(
Effect.gen(function* () {
const fs = yield* FileSystem.FileSystem;
const path = yield* Path.Path;
const root = yield* fs.makeTempDirectoryScoped({ prefix: "t3-wsl-runtime-stage-" });
const sourceArchivePath = yield* makeLinuxCliArchiveFixture({
root,
stem: "t3-1.2.3-linux-x64",
});
const stageAppDir = path.join(root, "app");
const archivePath = path.join(stageAppDir, WSL_RUNTIME_ARCHIVE_EXTRA_RESOURCE.from);
const hashPath = path.join(stageAppDir, WSL_RUNTIME_ARCHIVE_HASH_EXTRA_RESOURCE.from);
yield* stageWslRuntimeArchive({ sourceArchivePath, archivePath, hashPath });
const [source, staged] = yield* Effect.all([
fs.readFile(sourceArchivePath),
fs.readFile(archivePath),
]);
assert.deepStrictEqual(staged, source);
// The digest both gates installation inside the distro and names the
// extracted runtime's cache directory.
const hash = yield* fs.readFileString(hashPath);
assert.equal(hash, `${NodeCrypto.createHash("sha256").update(source).digest("hex")}\n`);
}),
),
);
it.effect("fails when the Linux CLI archive handed to the build does not exist", () =>
Effect.scoped(
Effect.gen(function* () {
const fs = yield* FileSystem.FileSystem;
const path = yield* Path.Path;
const root = yield* fs.makeTempDirectoryScoped({ prefix: "t3-wsl-runtime-missing-" });
const error = yield* stageWslRuntimeArchive({
sourceArchivePath: path.join(root, "t3-1.2.3-linux-x64.tar.gz"),
archivePath: path.join(root, WSL_RUNTIME_ARCHIVE_NAME),
hashPath: path.join(root, WSL_RUNTIME_ARCHIVE_HASH_NAME),
}).pipe(Effect.flip);
assert.instanceOf(error, WslRuntimeArchiveMissingError);
}),
),
);
it("promotes target fff binaries to direct staged dependencies", () => {
assert.deepStrictEqual(resolveFffNativeDependencies("mac", "arm64", "0.9.4"), {
"@ff-labs/fff-bin-darwin-arm64": "0.9.4",
});
assert.deepStrictEqual(resolveFffNativeDependencies("mac", "universal", "0.9.4"), {
"@ff-labs/fff-bin-darwin-arm64": "0.9.4",
"@ff-labs/fff-bin-darwin-x64": "0.9.4",
});
assert.deepStrictEqual(resolveFffNativeDependencies("win", "x64", "0.9.4"), {
"@ff-labs/fff-bin-win32-x64": "0.9.4",
});
assert.deepStrictEqual(resolveFffNativeDependencies("linux", "x64", "0.9.4"), {
"@ff-labs/fff-bin-linux-x64-gnu": "0.9.4",
"@ff-labs/fff-bin-linux-x64-musl": "0.9.4",
});
assert.deepStrictEqual(resolveFffNativeDependencies("linux", "arm64", "0.9.4"), {
"@ff-labs/fff-bin-linux-arm64-gnu": "0.9.4",
"@ff-labs/fff-bin-linux-arm64-musl": "0.9.4",
});
});
it("resolves target Clerk passkey native artifacts", () => {
assert.deepStrictEqual(resolveClerkPasskeyNativeArtifacts("mac", "universal"), [
{
packageName: "@clerk/electron-passkeys-darwin-arm64",
binaryFileName: "electron-passkeys.darwin-arm64.node",
},
{
packageName: "@clerk/electron-passkeys-darwin-x64",
binaryFileName: "electron-passkeys.darwin-x64.node",
},
]);
assert.deepStrictEqual(resolveClerkPasskeyNativeArtifacts("win", "x64"), [
{
packageName: "@clerk/electron-passkeys-win32-x64-msvc",
binaryFileName: "electron-passkeys.win32-x64-msvc.node",
},
]);
assert.deepStrictEqual(resolveClerkPasskeyNativeArtifacts("linux", "x64"), []);
});
it("falls back to the default mock update port when the configured port is blank", () => {
assert.equal(resolveMockUpdateServerUrl(undefined), "http://localhost:3000");
assert.equal(resolveMockUpdateServerUrl(4123), "http://localhost:4123");
});
it("derives the electron-builder package manager user agent from packageManager", () => {
assert.equal(resolvePackageManagerUserAgent("pnpm@11.10.0"), "pnpm/11.10.0");
assert.equal(resolvePackageManagerUserAgent(" yarn@4.9.2 "), "yarn/4.9.2");
assert.equal(resolvePackageManagerUserAgent("pnpm"), "pnpm");
});
it.effect("normalizes mock update server ports from env-style strings", () =>
Effect.gen(function* () {
assert.equal(yield* resolveMockUpdateServerPort(undefined), undefined);
assert.equal(yield* resolveMockUpdateServerPort(""), undefined);
assert.equal(yield* resolveMockUpdateServerPort(" "), undefined);
assert.equal(yield* resolveMockUpdateServerPort("4123"), 4123);
}),
);
it.effect("rejects non-numeric or out-of-range mock update ports", () =>
Effect.gen(function* () {
const invalidPorts = ["abc", "12.5", "0", "65536"];
for (const port of invalidPorts) {
const exit = yield* Effect.exit(resolveMockUpdateServerPort(port));
assert.equal(exit._tag, "Failure");
}
}),
);
it("classifies invalid configured ports with the decoder's number grammar", () => {
const cause = new Error("invalid configured port");
assert.equal(
InvalidMockUpdateServerPortError.fromConfigValue("0x10", cause).reason,
"not-numeric",
);
assert.equal(
InvalidMockUpdateServerPortError.fromConfigValue("12.5", cause).reason,
"not-integer",
);
assert.equal(
InvalidMockUpdateServerPortError.fromConfigValue("65536", cause).reason,
"out-of-range",
);
assert.strictEqual(
InvalidMockUpdateServerPortError.fromConfigValue("0x10", cause).cause,
cause,
);
});
it.effect("resolves default platform and architecture from host references", () =>
Effect.gen(function* () {
const resolved = yield* resolveBuildOptions({
platform: Option.none(),
target: Option.none(),
arch: Option.none(),
buildVersion: Option.none(),
outputDir: Option.none(),
skipBuild: Option.none(),
keepStage: Option.none(),
signed: Option.none(),
verbose: Option.none(),
mockUpdates: Option.none(),
mockUpdateServerPort: Option.none(),
wslRuntime: Option.none(),
}).pipe(
Effect.provide(
Layer.mergeAll(
Layer.succeed(HostProcessPlatform, "win32"),
Layer.succeed(HostProcessArchitecture, "x64"),
ConfigProvider.layer(
ConfigProvider.fromEnv({
env: {
PROCESSOR_ARCHITECTURE: "AMD64",
PROCESSOR_ARCHITEW6432: "ARM64",
},
}),
),
),
),
);
assert.equal(resolved.platform, "win");
assert.equal(resolved.target, "nsis");
assert.equal(resolved.arch, "arm64");
}),
);
it.effect("rejects universal builds on Linux and Windows before staging binaries", () =>
Effect.gen(function* () {
for (const platform of ["linux", "win"] as const) {
const error = yield* Effect.flip(
resolveBuildOptions({
platform: Option.some(platform),
target: Option.none(),
arch: Option.some("universal"),
buildVersion: Option.none(),
outputDir: Option.none(),
skipBuild: Option.none(),
keepStage: Option.none(),
signed: Option.none(),
verbose: Option.none(),
mockUpdates: Option.none(),
mockUpdateServerPort: Option.none(),
wslRuntime: Option.none(),
}),
);
assert.instanceOf(error, UnsupportedDesktopBuildArchitectureError);
assert.deepStrictEqual(error.supportedArchitectures, ["x64", "arm64"]);
}
}),
);
it.effect("preserves explicit false boolean flags over true env defaults", () =>
Effect.gen(function* () {
const resolved = yield* resolveBuildOptions({
platform: Option.some("mac"),
target: Option.none(),
arch: Option.some("arm64"),
buildVersion: Option.none(),
outputDir: Option.some("release-test"),
skipBuild: Option.some(false),
keepStage: Option.some(false),
signed: Option.some(false),
verbose: Option.some(false),
mockUpdates: Option.some(false),
mockUpdateServerPort: Option.none(),
wslRuntime: Option.none(),
}).pipe(
Effect.provide(
ConfigProvider.layer(
ConfigProvider.fromEnv({
env: {
T3CODE_DESKTOP_SKIP_BUILD: "true",
T3CODE_DESKTOP_KEEP_STAGE: "true",
T3CODE_DESKTOP_SIGNED: "true",
T3CODE_DESKTOP_VERBOSE: "true",
T3CODE_DESKTOP_MOCK_UPDATES: "true",
},
}),
),
),
);
assert.equal(resolved.skipBuild, false);
assert.equal(resolved.keepStage, false);
assert.equal(resolved.signed, false);
assert.equal(resolved.verbose, false);
assert.equal(resolved.mockUpdates, false);
}),
);
});
// The self-containment check runs the packaged tree in a scratch directory. Its
// own node_modules holds the sidecar externals and must be ignored, but any
// node_modules *above* it would let Node's parent walk satisfy an import that is
// missing from the package, so the probe refuses to run in that case.
it("lists ancestor node_modules, nearest first, excluding the start directory", () => {
assert.deepStrictEqual(ancestorNodeModulesPaths("C:\\tmp\\probe\\app", "\\"), [
"C:\\tmp\\probe\\node_modules",
"C:\\tmp\\node_modules",
"C:\\node_modules",
]);
});
it("includes the filesystem root for posix paths", () => {
assert.deepStrictEqual(ancestorNodeModulesPaths("/tmp/probe", "/"), [
"/tmp/node_modules",
"/node_modules",
]);
});
// A UNC root must keep its \\server\share prefix. Rebuilding it from segments
// produced relative paths, which fs.exists resolves against the build cwd, so
// the guard checked directories that do not exist and silently passed.
it("keeps the prefix of a UNC path instead of going relative", () => {
const paths = ancestorNodeModulesPaths("\\\\server\\share\\tmp\\app", "\\");
for (const candidate of paths) {
assert.ok(candidate.startsWith("\\\\server\\share"), candidate);
}
assert.deepStrictEqual(paths[0], "\\\\server\\share\\tmp\\node_modules");
});
it.effect.skipIf(!symlinksSupported)("rebases packaged links into the isolated tree", () =>
Effect.gen(function* () {
const fs = yield* FileSystem.FileSystem;
const path = yield* Path.Path;
const root = yield* fs.makeTempDirectoryScoped({ prefix: "t3code-copy-symlinks-" });
const source = path.join(root, "source");
const destination = path.join(root, "destination");
const packageDir = path.join(source, "node_modules/.pnpm/example@1/node_modules/example");
const relativePackageLink = path.join(source, "node_modules/example-relative");
const absolutePackageLink = path.join(source, "node_modules/example-absolute");
yield* fs.makeDirectory(packageDir, { recursive: true });
yield* fs.writeFileString(path.join(packageDir, "index.js"), "module.exports = true;\n");
yield* fs.symlink(
path.join(".pnpm", "example@1", "node_modules", "example"),
relativePackageLink,
);
yield* fs.symlink(packageDir, absolutePackageLink);
yield* copyDirectoryPreservingSymlinks(source, destination);
const copiedPackage = path.join(
destination,
"node_modules/.pnpm/example@1/node_modules/example",
);
const resolvedCopiedPackage = yield* fs.realPath(copiedPackage);
assert.equal(
yield* fs.readLink(path.join(destination, "node_modules/example-relative")),
copiedPackage,
);
assert.equal(
yield* fs.readLink(path.join(destination, "node_modules/example-absolute")),
copiedPackage,
);
assert.equal(
yield* fs.realPath(path.join(destination, "node_modules/example-relative")),
resolvedCopiedPackage,
);
assert.equal(
yield* fs.realPath(path.join(destination, "node_modules/example-absolute")),
resolvedCopiedPackage,
);
}).pipe(Effect.provide(NodeServices.layer)),
);
it("ignores trailing separators", () => {
assert.deepStrictEqual(
ancestorNodeModulesPaths("C:\\tmp\\probe\\app\\", "\\"),
ancestorNodeModulesPaths("C:\\tmp\\probe\\app", "\\"),
);
});