authorgravatar for julius0216@outlook.comJulius Marminge <julius0216@outlook.com> 2026-06-20 11:19:11-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-06-20 11:19:11-07:00
logbfe61741b83dd7f2f66af7e7570ae0f67a16d631
tree0227a45efce004ccc733fced021fd4f8e552de03
parent4d3fcacd840d7b710f8415b4bebf3826df358c91
signature Signed by PGP key B5690EEEBB952194

[codex] Simplify desktop client settings errors (#3265)

Co-authored-by: codex <codex@users.noreply.github.com>

2 files changed, 52 insertions(+), 24 deletions(-)

apps/desktop/src/settings/DesktopClientSettings.test.ts+4-1
......@@ -5,6 +5,7 @@ import * as Effect from "effect/Effect";
55import * as FileSystem from "effect/FileSystem";
66import * as Layer from "effect/Layer";
77import * as Option from "effect/Option";
8import * as PlatformError from "effect/PlatformError";
89import * as Schema from "effect/Schema";
910
1011import * as DesktopConfig from "../app/DesktopConfig.ts";
......@@ -117,11 +118,13 @@ describe("DesktopClientSettings", () => {
117118 assert.instanceOf(error, DesktopClientSettings.DesktopClientSettingsWriteError);
118119 assert.equal(error.operation, "replace-settings-file");
119120 assert.equal(error.path, environment.clientSettingsPath);
120 assert.exists(error.cause);
121 assert.instanceOf(error.cause, PlatformError.PlatformError);
122 assert.isString(error.cause.stack);
121123 assert.equal(
122124 error.message,
123125 `Desktop client settings write failed during replace-settings-file at ${environment.clientSettingsPath}.`,
124126 );
127 assert.notInclude(error.message, error.cause.message);
125128 }),
126129 ),
127130 );
apps/desktop/src/settings/DesktopClientSettings.ts+48-23
......@@ -25,7 +25,9 @@ const decodeClientSettingsJsonValue = Schema.decodeEffect(ClientSettingsJson);
2525const decodeClientSettingsJson = (raw: string): Effect.Effect<ClientSettings, Schema.SchemaError> =>
2626 decodeLegacyClientSettingsDocumentJson(raw).pipe(
2727 Effect.map((document) => document.settings),
28 Effect.catch(() => decodeClientSettingsJsonValue(raw)),
28 Effect.catchTags({
29 SchemaError: () => decodeClientSettingsJsonValue(raw),
30 }),
2931 );
3032const encodeClientSettingsJson = Schema.encodeEffect(ClientSettingsJson);
3133
......@@ -36,7 +38,6 @@ const DesktopClientSettingsWriteOperation = Schema.Literals([
3638 "write-temporary-file",
3739 "replace-settings-file",
3840]);
39type DesktopClientSettingsWriteOperation = typeof DesktopClientSettingsWriteOperation.Type;
4041
4142export class DesktopClientSettingsWriteError extends Schema.TaggedErrorClass<DesktopClientSettingsWriteError>()(
4243 "DesktopClientSettingsWriteError",
......@@ -51,13 +52,6 @@ export class DesktopClientSettingsWriteError extends Schema.TaggedErrorClass<Des
5152 }
5253}
5354
54const writeError = (
55 operation: DesktopClientSettingsWriteOperation,
56 path: string,
57 cause: unknown,
58): DesktopClientSettingsWriteError =>
59 new DesktopClientSettingsWriteError({ operation, path, cause });
60
6155export class DesktopClientSettings extends Context.Service<
6256 DesktopClientSettings,
6357 {
......@@ -96,19 +90,45 @@ const writeClientSettings = Effect.fnUntraced(function* (input: {
9690 const directory = input.path.dirname(input.settingsPath);
9791 const tempPath = `${input.settingsPath}.${process.pid}.${input.suffix}.tmp`;
9892 const encoded = yield* encodeClientSettingsJson(input.settings).pipe(
99 Effect.mapError((cause) => writeError("encode-document", input.settingsPath, cause)),
93 Effect.mapError(
94 (cause) =>
95 new DesktopClientSettingsWriteError({
96 operation: "encode-document",
97 path: input.settingsPath,
98 cause,
99 }),
100 ),
101 );
102 yield* input.fileSystem.makeDirectory(directory, { recursive: true }).pipe(
103 Effect.mapError(
104 (cause) =>
105 new DesktopClientSettingsWriteError({
106 operation: "create-directory",
107 path: directory,
108 cause,
109 }),
110 ),
111 );
112 yield* input.fileSystem.writeFileString(tempPath, `${encoded}\n`).pipe(
113 Effect.mapError(
114 (cause) =>
115 new DesktopClientSettingsWriteError({
116 operation: "write-temporary-file",
117 path: tempPath,
118 cause,
119 }),
120 ),
121 );
122 yield* input.fileSystem.rename(tempPath, input.settingsPath).pipe(
123 Effect.mapError(
124 (cause) =>
125 new DesktopClientSettingsWriteError({
126 operation: "replace-settings-file",
127 path: input.settingsPath,
128 cause,
129 }),
130 ),
100131 );
101 yield* input.fileSystem
102 .makeDirectory(directory, { recursive: true })
103 .pipe(Effect.mapError((cause) => writeError("create-directory", directory, cause)));
104 yield* input.fileSystem
105 .writeFileString(tempPath, `${encoded}\n`)
106 .pipe(Effect.mapError((cause) => writeError("write-temporary-file", tempPath, cause)));
107 yield* input.fileSystem
108 .rename(tempPath, input.settingsPath)
109 .pipe(
110 Effect.mapError((cause) => writeError("replace-settings-file", input.settingsPath, cause)),
111 );
112132});
113133
114134export const make = Effect.gen(function* () {
......@@ -124,8 +144,13 @@ export const make = Effect.gen(function* () {
124144 set: (settings) =>
125145 crypto.randomUUIDv4.pipe(
126146 Effect.map((uuid) => uuid.replace(/-/g, "")),
127 Effect.mapError((cause) =>
128 writeError("create-temporary-file-name", environment.clientSettingsPath, cause),
147 Effect.mapError(
148 (cause) =>
149 new DesktopClientSettingsWriteError({
150 operation: "create-temporary-file-name",
151 path: environment.clientSettingsPath,
152 cause,
153 }),
129154 ),
130155 Effect.flatMap((suffix) =>
131156 writeClientSettings({