1import * as NodeServices from "@effect/platform-node/NodeServices";
2import { assert, it } from "@effect/vitest";
3import * as Effect from "effect/Effect";
4import * as FileSystem from "effect/FileSystem";
5import * as Path from "effect/Path";
6import * as PlatformError from "effect/PlatformError";
7
8import { resolveUserDataPath } from "./DesktopUserData.ts";
9
10it.effect("identifies a failed source read and preserves its cause", () => {
11 const sourceState = "/profiles/t3code/Local State";
12 const cause = PlatformError.systemError({
13 _tag: "PermissionDenied",
14 module: "FileSystem",
15 method: "readFileString",
16 pathOrDescriptor: sourceState,
17 });
18 return Effect.gen(function* () {
19 const error = yield* resolveUserDataPath({
20 appDataDirectory: "/profiles",
21 isDevelopment: false,
22 platform: "win32",
23 }).pipe(Effect.flip);
24 assert.equal(error.operation, "read");
25 assert.equal(error.resourcePath, sourceState);
26 assert.equal(error.category, "PermissionDenied");
27 assert.strictEqual(error.cause, cause);
28 }).pipe(
29 Effect.provideService(
30 FileSystem.FileSystem,
31 FileSystem.makeNoop({
32 exists: (path) => Effect.succeed(path === sourceState),
33 readFileString: () => Effect.fail(cause),
34 }),
35 ),
36 Effect.provide(NodeServices.layer),
37 );
38});
39
40it.effect.each(["t3code", "T3 Code (Alpha)"])(
41 "preserves Windows credential keys from %s without copying browser databases",
42 (sourceName) =>
43 Effect.gen(function* () {
44 const fs = yield* FileSystem.FileSystem;
45 const path = yield* Path.Path;
46 const directory = yield* fs.makeTempDirectoryScoped({ prefix: "t3-v2-profile-" });
47 const source = path.join(directory, sourceName);
48 const destination = path.join(directory, "t3code-v2");
49 const state = '{"os_crypt":{"encrypted_key":"test-encrypted-key"}}';
50 yield* fs.makeDirectory(path.join(directory, "T3 Code (Alpha)"), { recursive: true });
51 yield* fs.makeDirectory(path.join(source, "IndexedDB"), { recursive: true });
52 yield* fs.writeFileString(path.join(source, "Local State"), state);
53 yield* fs.writeFileString(path.join(source, "IndexedDB", "LOCK"), "V1 owns this database");
54 yield* resolveUserDataPath({
55 appDataDirectory: directory,
56 isDevelopment: false,
57 platform: "win32",
58 });
59 assert.equal(yield* fs.readFileString(path.join(destination, "Local State")), state);
60 assert.equal(yield* fs.readFileString(path.join(source, "Local State")), state);
61 assert.isFalse(yield* fs.exists(path.join(destination, "IndexedDB")));
62 yield* fs.writeFileString(path.join(destination, "Local State"), "existing V2 state");
63 yield* resolveUserDataPath({
64 appDataDirectory: directory,
65 isDevelopment: false,
66 platform: "win32",
67 });
68 assert.equal(
69 yield* fs.readFileString(path.join(destination, "Local State")),
70 "existing V2 state",
71 );
72 }).pipe(Effect.scoped, Effect.provide(NodeServices.layer)),
73);