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 Option from "effect/Option";import * as Schema from "effect/Schema"; import * as DesktopConfig from "../app/DesktopConfig.ts";import * as DesktopEnvironment from "../app/DesktopEnvironment.ts";import * as DesktopAppSettings from "./DesktopAppSettings.ts"; const DesktopSettingsPatch = Schema.Struct({ serverExposureMode: Schema.optionalKey(Schema.Literals(["local-only", "network-accessible"])), tailscaleServeEnabled: Schema.optionalKey(Schema.Boolean), tailscaleServePort: Schema.optionalKey(Schema.Number), updateChannel: Schema.optionalKey(Schema.Literals(["latest", "nightly"])), updateChannelConfiguredByUser: Schema.optionalKey(Schema.Boolean), wslBackendEnabled: Schema.optionalKey(Schema.Boolean), wslMode: Schema.optionalKey(Schema.Literals(["local", "wsl"])), wslDistro: Schema.optionalKey(Schema.NullOr(Schema.String)), wslOnly: Schema.optionalKey(Schema.Boolean),}); const decodeDesktopSettingsPatch = Schema.decodeEffect(Schema.fromJsonString(DesktopSettingsPatch));const encodeDesktopSettingsPatch = Schema.encodeEffect(Schema.fromJsonString(DesktopSettingsPatch)); function makeEnvironmentLayer(baseDir: string, appVersion = "0.0.17") { return DesktopEnvironment.layer({ dirname: "/repo/apps/desktop/src", homeDirectory: baseDir, platform: "darwin", processArch: "x64", appVersion, appPath: "/repo", isPackaged: true, resourcesPath: "/missing/resources", runningUnderArm64Translation: false, }).pipe( Layer.provide( Layer.mergeAll(NodeServices.layer, DesktopConfig.layerTest({ T3CODE_HOME: baseDir })), ), );} const withSettings = <A, E, R>( effect: Effect.Effect< A, E, R | DesktopAppSettings.DesktopAppSettings | DesktopEnvironment.DesktopEnvironment >, options?: { readonly appVersion?: string },) => Effect.gen(function* () { const fileSystem = yield* FileSystem.FileSystem; const baseDir = yield* fileSystem.makeTempDirectoryScoped({ prefix: "t3-desktop-settings-test-", }); return yield* effect.pipe( Effect.provide( DesktopAppSettings.layer.pipe( Layer.provideMerge(makeEnvironmentLayer(baseDir, options?.appVersion)), Layer.provideMerge(NodeServices.layer), ), ), ); }).pipe(Effect.provide(NodeServices.layer), Effect.scoped); function writeSettingsPatch(patch: typeof DesktopSettingsPatch.Type) { return Effect.gen(function* () { const environment = yield* DesktopEnvironment.DesktopEnvironment; const fileSystem = yield* FileSystem.FileSystem; const encoded = yield* encodeDesktopSettingsPatch(patch); yield* fileSystem.makeDirectory(environment.stateDir, { recursive: true }); yield* fileSystem.writeFileString(environment.desktopSettingsPath, `${encoded}\n`); });} describe("DesktopSettings", () => { it.effect("loads defaults when no settings file exists", () => withSettings( Effect.gen(function* () { const settings = yield* DesktopAppSettings.DesktopAppSettings; assert.deepEqual(yield* settings.load, DesktopAppSettings.DEFAULT_DESKTOP_SETTINGS); assert.deepEqual(yield* settings.get, DesktopAppSettings.DEFAULT_DESKTOP_SETTINGS); }), ), ); it("defaults packaged nightly builds to the nightly update channel", () => { assert.deepEqual( DesktopAppSettings.resolveDefaultDesktopSettings("0.0.17-nightly.20260415.1"), { serverExposureMode: "local-only", tailscaleServeEnabled: false, tailscaleServePort: 443, updateChannel: "nightly", updateChannelConfiguredByUser: false, wslBackendEnabled: false, wslOnly: false, wslDistro: null, } satisfies DesktopAppSettings.DesktopSettings, ); }); it.effect("loads persisted settings and applies semantic updates", () => withSettings( Effect.gen(function* () { const settings = yield* DesktopAppSettings.DesktopAppSettings; yield* writeSettingsPatch({ serverExposureMode: "network-accessible", tailscaleServeEnabled: true, tailscaleServePort: 8443, updateChannel: "latest", updateChannelConfiguredByUser: true, }); assert.deepEqual(yield* settings.load, { serverExposureMode: "network-accessible", tailscaleServeEnabled: true, tailscaleServePort: 8443, updateChannel: "latest", updateChannelConfiguredByUser: true, wslBackendEnabled: false, wslOnly: false, wslDistro: null, } satisfies DesktopAppSettings.DesktopSettings); const exposure = yield* settings.setServerExposureMode("local-only"); assert.isTrue(exposure.changed); assert.equal(exposure.settings.serverExposureMode, "local-only"); const tailscale = yield* settings.setTailscaleServe({ enabled: true, port: Option.some(9443), }); assert.isTrue(tailscale.changed); assert.equal(tailscale.settings.tailscaleServePort, 9443); const updateChannel = yield* settings.setUpdateChannel("nightly"); assert.isTrue(updateChannel.changed); assert.equal(updateChannel.settings.updateChannel, "nightly"); assert.equal(updateChannel.settings.updateChannelConfiguredByUser, true); }), ), ); it.effect("reports the failed desktop settings write operation and path", () => withSettings( Effect.gen(function* () { const environment = yield* DesktopEnvironment.DesktopEnvironment; const fileSystem = yield* FileSystem.FileSystem; const settings = yield* DesktopAppSettings.DesktopAppSettings; yield* fileSystem.makeDirectory(environment.desktopSettingsPath, { recursive: true }); const error = yield* settings.setServerExposureMode("network-accessible").pipe(Effect.flip); assert.instanceOf(error, DesktopAppSettings.DesktopSettingsWriteError); assert.equal(error.operation, "replace-settings-file"); assert.equal(error.path, environment.desktopSettingsPath); assert.exists(error.cause); assert.equal( error.message, `Desktop settings write failed during replace-settings-file at ${environment.desktopSettingsPath}.`, ); }), ), ); it.effect("does not persist no-op semantic updates", () => withSettings( Effect.gen(function* () { const settings = yield* DesktopAppSettings.DesktopAppSettings; const exposure = yield* settings.setServerExposureMode("local-only"); assert.isFalse(exposure.changed); const tailscale = yield* settings.setTailscaleServe({ enabled: false, port: Option.none(), }); assert.isFalse(tailscale.changed); const updateChannel = yield* settings.setUpdateChannel("latest"); assert.isFalse(updateChannel.changed); assert.equal(updateChannel.settings.updateChannelConfiguredByUser, false); }), ), ); it.effect("falls back to defaults when the settings file is malformed", () => withSettings( Effect.gen(function* () { const environment = yield* DesktopEnvironment.DesktopEnvironment; const fileSystem = yield* FileSystem.FileSystem; const settings = yield* DesktopAppSettings.DesktopAppSettings; yield* fileSystem.makeDirectory(environment.stateDir, { recursive: true }); yield* fileSystem.writeFileString(environment.desktopSettingsPath, "{not-json"); assert.deepEqual(yield* settings.load, DesktopAppSettings.DEFAULT_DESKTOP_SETTINGS); }), ), ); it.effect("loads lenient persisted desktop settings JSON", () => withSettings( Effect.gen(function* () { const environment = yield* DesktopEnvironment.DesktopEnvironment; const fileSystem = yield* FileSystem.FileSystem; const settings = yield* DesktopAppSettings.DesktopAppSettings; yield* fileSystem.makeDirectory(environment.stateDir, { recursive: true }); yield* fileSystem.writeFileString( environment.desktopSettingsPath, `{ // JSONC-style comments and trailing commas match server settings parsing. "serverExposureMode": "network-accessible", "tailscaleServeEnabled": true, "tailscaleServePort": 8443, }\n`, ); assert.deepEqual(yield* settings.load, { serverExposureMode: "network-accessible", tailscaleServeEnabled: true, tailscaleServePort: 8443, updateChannel: "latest", updateChannelConfiguredByUser: false, wslBackendEnabled: false, wslOnly: false, wslDistro: null, } satisfies DesktopAppSettings.DesktopSettings); }), ), ); it.effect("persists sparse desktop settings documents", () => withSettings( Effect.gen(function* () { const environment = yield* DesktopEnvironment.DesktopEnvironment; const fileSystem = yield* FileSystem.FileSystem; const settings = yield* DesktopAppSettings.DesktopAppSettings; yield* settings.setServerExposureMode("network-accessible"); const persisted = yield* decodeDesktopSettingsPatch( yield* fileSystem.readFileString(environment.desktopSettingsPath), ); assert.deepEqual(persisted, { serverExposureMode: "network-accessible", } satisfies typeof DesktopSettingsPatch.Type); }), ), ); it.effect("migrates legacy implicit update channels to the runtime default", () => withSettings( Effect.gen(function* () { const settings = yield* DesktopAppSettings.DesktopAppSettings; yield* writeSettingsPatch({ serverExposureMode: "local-only", updateChannel: "latest", }); assert.deepEqual(yield* settings.load, { serverExposureMode: "local-only", tailscaleServeEnabled: false, tailscaleServePort: 443, updateChannel: "nightly", updateChannelConfiguredByUser: false, wslBackendEnabled: false, wslOnly: false, wslDistro: null, } satisfies DesktopAppSettings.DesktopSettings); }), { appVersion: "0.0.17-nightly.20260415.1" }, ), ); it.effect("preserves explicit stable update channel on nightly builds", () => withSettings( Effect.gen(function* () { const settings = yield* DesktopAppSettings.DesktopAppSettings; yield* writeSettingsPatch({ serverExposureMode: "local-only", updateChannel: "latest", updateChannelConfiguredByUser: true, }); assert.deepEqual(yield* settings.load, { serverExposureMode: "local-only", tailscaleServeEnabled: false, tailscaleServePort: 443, updateChannel: "latest", updateChannelConfiguredByUser: true, wslBackendEnabled: false, wslOnly: false, wslDistro: null, } satisfies DesktopAppSettings.DesktopSettings); }), { appVersion: "0.0.17-nightly.20260415.1" }, ), ); it.effect("normalizes invalid persisted Tailscale Serve ports", () => withSettings( Effect.gen(function* () { const settings = yield* DesktopAppSettings.DesktopAppSettings; yield* writeSettingsPatch({ tailscaleServeEnabled: true, tailscaleServePort: 0, }); assert.deepEqual(yield* settings.load, { serverExposureMode: "local-only", tailscaleServeEnabled: true, tailscaleServePort: 443, updateChannel: "latest", updateChannelConfiguredByUser: false, wslBackendEnabled: false, wslOnly: false, wslDistro: null, } satisfies DesktopAppSettings.DesktopSettings); }), ), ); it.effect("persists wsl backend toggle and normalizes invalid distro names", () => withSettings( Effect.gen(function* () { const settings = yield* DesktopAppSettings.DesktopAppSettings; const enable = yield* settings.setWslBackendEnabled(true); assert.isTrue(enable.changed); assert.equal(enable.settings.wslBackendEnabled, true); const distro = yield* settings.setWslDistro("Ubuntu-22.04"); assert.isTrue(distro.changed); assert.equal(distro.settings.wslDistro, "Ubuntu-22.04"); const reloaded = yield* settings.load; assert.equal(reloaded.wslBackendEnabled, true); assert.equal(reloaded.wslDistro, "Ubuntu-22.04"); const reject = yield* settings.setWslDistro("bad name!"); assert.equal(reject.settings.wslDistro, null); const noop = yield* settings.setWslDistro(null); assert.isFalse(noop.changed); }), ), ); it.effect("applies WSL Windows fallback with persisted and volatile updates", () => withSettings( Effect.gen(function* () { const settings = yield* DesktopAppSettings.DesktopAppSettings; yield* settings.setWslBackendEnabled(true); yield* settings.setWslOnly(true); const persistedFallback = yield* settings.applyWslWindowsFallback; assert.isTrue(persistedFallback.changed); assert.equal(persistedFallback.settings.wslBackendEnabled, false); assert.equal(persistedFallback.settings.wslOnly, false); const persistedReload = yield* settings.load; assert.equal(persistedReload.wslBackendEnabled, false); assert.equal(persistedReload.wslOnly, false); yield* settings.setWslBackendEnabled(true); yield* settings.setWslOnly(true); const volatileFallback = yield* settings.applyWslWindowsFallbackInMemory; assert.isTrue(volatileFallback.changed); assert.equal(volatileFallback.settings.wslBackendEnabled, false); assert.equal(volatileFallback.settings.wslOnly, false); const current = yield* settings.get; assert.equal(current.wslBackendEnabled, false); assert.equal(current.wslOnly, false); const diskReload = yield* settings.load; assert.equal(diskReload.wslBackendEnabled, true); assert.equal(diskReload.wslOnly, true); }), ), ); it.effect("migrates legacy wslMode=wsl to wslBackendEnabled on load", () => withSettings( Effect.gen(function* () { const settings = yield* DesktopAppSettings.DesktopAppSettings; yield* writeSettingsPatch({ wslMode: "wsl", wslDistro: "Ubuntu-22.04", }); const loaded = yield* settings.load; assert.equal(loaded.wslBackendEnabled, true); assert.equal(loaded.wslDistro, "Ubuntu-22.04"); }), ), ); it.effect("drops invalid persisted wsl distro values on load", () => withSettings( Effect.gen(function* () { const settings = yield* DesktopAppSettings.DesktopAppSettings; yield* writeSettingsPatch({ wslBackendEnabled: true, wslDistro: "bad/name", }); const loaded = yield* settings.load; assert.equal(loaded.wslBackendEnabled, true); assert.equal(loaded.wslDistro, null); }), ), );});
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 Option from "effect/Option";
import * as Schema from "effect/Schema";
import * as DesktopConfig from "../app/DesktopConfig.ts";
import * as DesktopEnvironment from "../app/DesktopEnvironment.ts";
import * as DesktopAppSettings from "./DesktopAppSettings.ts";
const DesktopSettingsPatch = Schema.Struct({
serverExposureMode: Schema.optionalKey(Schema.Literals(["local-only", "network-accessible"])),
tailscaleServeEnabled: Schema.optionalKey(Schema.Boolean),
tailscaleServePort: Schema.optionalKey(Schema.Number),
updateChannel: Schema.optionalKey(Schema.Literals(["latest", "nightly"])),
updateChannelConfiguredByUser: Schema.optionalKey(Schema.Boolean),
wslBackendEnabled: Schema.optionalKey(Schema.Boolean),
wslMode: Schema.optionalKey(Schema.Literals(["local", "wsl"])),
wslDistro: Schema.optionalKey(Schema.NullOr(Schema.String)),
wslOnly: Schema.optionalKey(Schema.Boolean),
});
const decodeDesktopSettingsPatch = Schema.decodeEffect(Schema.fromJsonString(DesktopSettingsPatch));
const encodeDesktopSettingsPatch = Schema.encodeEffect(Schema.fromJsonString(DesktopSettingsPatch));
function makeEnvironmentLayer(baseDir: string, appVersion = "0.0.17") {
return DesktopEnvironment.layer({
dirname: "/repo/apps/desktop/src",
homeDirectory: baseDir,
platform: "darwin",
processArch: "x64",
appVersion,
appPath: "/repo",
isPackaged: true,
resourcesPath: "/missing/resources",
runningUnderArm64Translation: false,
}).pipe(
Layer.provide(
Layer.mergeAll(NodeServices.layer, DesktopConfig.layerTest({ T3CODE_HOME: baseDir })),
),
);
}
const withSettings = <A, E, R>(
effect: Effect.Effect<
A,
E,
R | DesktopAppSettings.DesktopAppSettings | DesktopEnvironment.DesktopEnvironment
>,
options?: { readonly appVersion?: string },
) =>
Effect.gen(function* () {
const fileSystem = yield* FileSystem.FileSystem;
const baseDir = yield* fileSystem.makeTempDirectoryScoped({
prefix: "t3-desktop-settings-test-",
});
return yield* effect.pipe(
Effect.provide(
DesktopAppSettings.layer.pipe(
Layer.provideMerge(makeEnvironmentLayer(baseDir, options?.appVersion)),
Layer.provideMerge(NodeServices.layer),
),
),
);
}).pipe(Effect.provide(NodeServices.layer), Effect.scoped);
function writeSettingsPatch(patch: typeof DesktopSettingsPatch.Type) {
return Effect.gen(function* () {
const environment = yield* DesktopEnvironment.DesktopEnvironment;
const fileSystem = yield* FileSystem.FileSystem;
const encoded = yield* encodeDesktopSettingsPatch(patch);
yield* fileSystem.makeDirectory(environment.stateDir, { recursive: true });
yield* fileSystem.writeFileString(environment.desktopSettingsPath, `${encoded}\n`);
});
}
describe("DesktopSettings", () => {
it.effect("loads defaults when no settings file exists", () =>
withSettings(
Effect.gen(function* () {
const settings = yield* DesktopAppSettings.DesktopAppSettings;
assert.deepEqual(yield* settings.load, DesktopAppSettings.DEFAULT_DESKTOP_SETTINGS);
assert.deepEqual(yield* settings.get, DesktopAppSettings.DEFAULT_DESKTOP_SETTINGS);
}),
),
);
it("defaults packaged nightly builds to the nightly update channel", () => {
assert.deepEqual(
DesktopAppSettings.resolveDefaultDesktopSettings("0.0.17-nightly.20260415.1"),
{
serverExposureMode: "local-only",
tailscaleServeEnabled: false,
tailscaleServePort: 443,
updateChannel: "nightly",
updateChannelConfiguredByUser: false,
wslBackendEnabled: false,
wslOnly: false,
wslDistro: null,
} satisfies DesktopAppSettings.DesktopSettings,
);
});
it.effect("loads persisted settings and applies semantic updates", () =>
withSettings(
Effect.gen(function* () {
const settings = yield* DesktopAppSettings.DesktopAppSettings;
yield* writeSettingsPatch({
serverExposureMode: "network-accessible",
tailscaleServeEnabled: true,
tailscaleServePort: 8443,
updateChannel: "latest",
updateChannelConfiguredByUser: true,
});
assert.deepEqual(yield* settings.load, {
serverExposureMode: "network-accessible",
tailscaleServeEnabled: true,
tailscaleServePort: 8443,
updateChannel: "latest",
updateChannelConfiguredByUser: true,
wslBackendEnabled: false,
wslOnly: false,
wslDistro: null,
} satisfies DesktopAppSettings.DesktopSettings);
const exposure = yield* settings.setServerExposureMode("local-only");
assert.isTrue(exposure.changed);
assert.equal(exposure.settings.serverExposureMode, "local-only");
const tailscale = yield* settings.setTailscaleServe({
enabled: true,
port: Option.some(9443),
});
assert.isTrue(tailscale.changed);
assert.equal(tailscale.settings.tailscaleServePort, 9443);
const updateChannel = yield* settings.setUpdateChannel("nightly");
assert.isTrue(updateChannel.changed);
assert.equal(updateChannel.settings.updateChannel, "nightly");
assert.equal(updateChannel.settings.updateChannelConfiguredByUser, true);
}),
),
);
it.effect("reports the failed desktop settings write operation and path", () =>
withSettings(
Effect.gen(function* () {
const environment = yield* DesktopEnvironment.DesktopEnvironment;
const fileSystem = yield* FileSystem.FileSystem;
const settings = yield* DesktopAppSettings.DesktopAppSettings;
yield* fileSystem.makeDirectory(environment.desktopSettingsPath, { recursive: true });
const error = yield* settings.setServerExposureMode("network-accessible").pipe(Effect.flip);
assert.instanceOf(error, DesktopAppSettings.DesktopSettingsWriteError);
assert.equal(error.operation, "replace-settings-file");
assert.equal(error.path, environment.desktopSettingsPath);
assert.exists(error.cause);
assert.equal(
error.message,
`Desktop settings write failed during replace-settings-file at ${environment.desktopSettingsPath}.`,
);
}),
),
);
it.effect("does not persist no-op semantic updates", () =>
withSettings(
Effect.gen(function* () {
const settings = yield* DesktopAppSettings.DesktopAppSettings;
const exposure = yield* settings.setServerExposureMode("local-only");
assert.isFalse(exposure.changed);
const tailscale = yield* settings.setTailscaleServe({
enabled: false,
port: Option.none(),
});
assert.isFalse(tailscale.changed);
const updateChannel = yield* settings.setUpdateChannel("latest");
assert.isFalse(updateChannel.changed);
assert.equal(updateChannel.settings.updateChannelConfiguredByUser, false);
}),
),
);
it.effect("falls back to defaults when the settings file is malformed", () =>
withSettings(
Effect.gen(function* () {
const environment = yield* DesktopEnvironment.DesktopEnvironment;
const fileSystem = yield* FileSystem.FileSystem;
const settings = yield* DesktopAppSettings.DesktopAppSettings;
yield* fileSystem.makeDirectory(environment.stateDir, { recursive: true });
yield* fileSystem.writeFileString(environment.desktopSettingsPath, "{not-json");
assert.deepEqual(yield* settings.load, DesktopAppSettings.DEFAULT_DESKTOP_SETTINGS);
}),
),
);
it.effect("loads lenient persisted desktop settings JSON", () =>
withSettings(
Effect.gen(function* () {
const environment = yield* DesktopEnvironment.DesktopEnvironment;
const fileSystem = yield* FileSystem.FileSystem;
const settings = yield* DesktopAppSettings.DesktopAppSettings;
yield* fileSystem.makeDirectory(environment.stateDir, { recursive: true });
yield* fileSystem.writeFileString(
environment.desktopSettingsPath,
`{
// JSONC-style comments and trailing commas match server settings parsing.
"serverExposureMode": "network-accessible",
"tailscaleServeEnabled": true,
"tailscaleServePort": 8443,
}\n`,
);
assert.deepEqual(yield* settings.load, {
serverExposureMode: "network-accessible",
tailscaleServeEnabled: true,
tailscaleServePort: 8443,
updateChannel: "latest",
updateChannelConfiguredByUser: false,
wslBackendEnabled: false,
wslOnly: false,
wslDistro: null,
} satisfies DesktopAppSettings.DesktopSettings);
}),
),
);
it.effect("persists sparse desktop settings documents", () =>
withSettings(
Effect.gen(function* () {
const environment = yield* DesktopEnvironment.DesktopEnvironment;
const fileSystem = yield* FileSystem.FileSystem;
const settings = yield* DesktopAppSettings.DesktopAppSettings;
yield* settings.setServerExposureMode("network-accessible");
const persisted = yield* decodeDesktopSettingsPatch(
yield* fileSystem.readFileString(environment.desktopSettingsPath),
);
assert.deepEqual(persisted, {
serverExposureMode: "network-accessible",
} satisfies typeof DesktopSettingsPatch.Type);
}),
),
);
it.effect("migrates legacy implicit update channels to the runtime default", () =>
withSettings(
Effect.gen(function* () {
const settings = yield* DesktopAppSettings.DesktopAppSettings;
yield* writeSettingsPatch({
serverExposureMode: "local-only",
updateChannel: "latest",
});
assert.deepEqual(yield* settings.load, {
serverExposureMode: "local-only",
tailscaleServeEnabled: false,
tailscaleServePort: 443,
updateChannel: "nightly",
updateChannelConfiguredByUser: false,
wslBackendEnabled: false,
wslOnly: false,
wslDistro: null,
} satisfies DesktopAppSettings.DesktopSettings);
}),
{ appVersion: "0.0.17-nightly.20260415.1" },
),
);
it.effect("preserves explicit stable update channel on nightly builds", () =>
withSettings(
Effect.gen(function* () {
const settings = yield* DesktopAppSettings.DesktopAppSettings;
yield* writeSettingsPatch({
serverExposureMode: "local-only",
updateChannel: "latest",
updateChannelConfiguredByUser: true,
});
assert.deepEqual(yield* settings.load, {
serverExposureMode: "local-only",
tailscaleServeEnabled: false,
tailscaleServePort: 443,
updateChannel: "latest",
updateChannelConfiguredByUser: true,
wslBackendEnabled: false,
wslOnly: false,
wslDistro: null,
} satisfies DesktopAppSettings.DesktopSettings);
}),
{ appVersion: "0.0.17-nightly.20260415.1" },
),
);
it.effect("normalizes invalid persisted Tailscale Serve ports", () =>
withSettings(
Effect.gen(function* () {
const settings = yield* DesktopAppSettings.DesktopAppSettings;
yield* writeSettingsPatch({
tailscaleServeEnabled: true,
tailscaleServePort: 0,
});
assert.deepEqual(yield* settings.load, {
serverExposureMode: "local-only",
tailscaleServeEnabled: true,
tailscaleServePort: 443,
updateChannel: "latest",
updateChannelConfiguredByUser: false,
wslBackendEnabled: false,
wslOnly: false,
wslDistro: null,
} satisfies DesktopAppSettings.DesktopSettings);
}),
),
);
it.effect("persists wsl backend toggle and normalizes invalid distro names", () =>
withSettings(
Effect.gen(function* () {
const settings = yield* DesktopAppSettings.DesktopAppSettings;
const enable = yield* settings.setWslBackendEnabled(true);
assert.isTrue(enable.changed);
assert.equal(enable.settings.wslBackendEnabled, true);
const distro = yield* settings.setWslDistro("Ubuntu-22.04");
assert.isTrue(distro.changed);
assert.equal(distro.settings.wslDistro, "Ubuntu-22.04");
const reloaded = yield* settings.load;
assert.equal(reloaded.wslBackendEnabled, true);
assert.equal(reloaded.wslDistro, "Ubuntu-22.04");
const reject = yield* settings.setWslDistro("bad name!");
assert.equal(reject.settings.wslDistro, null);
const noop = yield* settings.setWslDistro(null);
assert.isFalse(noop.changed);
}),
),
);
it.effect("applies WSL Windows fallback with persisted and volatile updates", () =>
withSettings(
Effect.gen(function* () {
const settings = yield* DesktopAppSettings.DesktopAppSettings;
yield* settings.setWslBackendEnabled(true);
yield* settings.setWslOnly(true);
const persistedFallback = yield* settings.applyWslWindowsFallback;
assert.isTrue(persistedFallback.changed);
assert.equal(persistedFallback.settings.wslBackendEnabled, false);
assert.equal(persistedFallback.settings.wslOnly, false);
const persistedReload = yield* settings.load;
assert.equal(persistedReload.wslBackendEnabled, false);
assert.equal(persistedReload.wslOnly, false);
yield* settings.setWslBackendEnabled(true);
yield* settings.setWslOnly(true);
const volatileFallback = yield* settings.applyWslWindowsFallbackInMemory;
assert.isTrue(volatileFallback.changed);
assert.equal(volatileFallback.settings.wslBackendEnabled, false);
assert.equal(volatileFallback.settings.wslOnly, false);
const current = yield* settings.get;
assert.equal(current.wslBackendEnabled, false);
assert.equal(current.wslOnly, false);
const diskReload = yield* settings.load;
assert.equal(diskReload.wslBackendEnabled, true);
assert.equal(diskReload.wslOnly, true);
}),
),
);
it.effect("migrates legacy wslMode=wsl to wslBackendEnabled on load", () =>
withSettings(
Effect.gen(function* () {
const settings = yield* DesktopAppSettings.DesktopAppSettings;
yield* writeSettingsPatch({
wslMode: "wsl",
wslDistro: "Ubuntu-22.04",
});
const loaded = yield* settings.load;
assert.equal(loaded.wslBackendEnabled, true);
assert.equal(loaded.wslDistro, "Ubuntu-22.04");
}),
),
);
it.effect("drops invalid persisted wsl distro values on load", () =>
withSettings(
Effect.gen(function* () {
const settings = yield* DesktopAppSettings.DesktopAppSettings;
yield* writeSettingsPatch({
wslBackendEnabled: true,
wslDistro: "bad/name",
});
const loaded = yield* settings.load;
assert.equal(loaded.wslBackendEnabled, true);
assert.equal(loaded.wslDistro, null);
}),
),
);
});