Skip to content

Commit 8c9f81c

Browse files
committed
Fix asset probe errors aborting search for alternatives
Restore orElseSucceed for fileSystem.exists calls in resolveResourcePath, resolveIconPath, and resolveUserDataPath so that I/O or permission errors on individual candidates are treated as 'not found' rather than fatal. This ensures the search continues to remaining candidates and prevents probe errors from blocking desktop startup.
1 parent f0d9fb9 commit 8c9f81c

4 files changed

Lines changed: 19 additions & 53 deletions

File tree

apps/desktop/src/app/DesktopAppIdentity.test.ts

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@ describe("DesktopAppIdentity", () => {
153153
),
154154
);
155155

156-
it.effect("preserves failures while inspecting the legacy userData path", () => {
156+
it.effect("falls back to the default userData path when legacy path probe fails", () => {
157157
const legacyPath = "/Users/alice/Library/Application Support/T3 Code (Alpha)";
158158
const cause = PlatformError.systemError({
159159
_tag: "PermissionDenied",
@@ -166,15 +166,9 @@ describe("DesktopAppIdentity", () => {
166166
return withIdentity(
167167
Effect.gen(function* () {
168168
const identity = yield* DesktopAppIdentity.DesktopAppIdentity;
169-
const error = yield* identity.resolveUserDataPath.pipe(Effect.flip);
170-
171-
assert.instanceOf(error, DesktopAppIdentity.DesktopUserDataPathResolutionError);
172-
assert.equal(error.legacyPath, legacyPath);
173-
assert.strictEqual(error.cause, cause);
174-
assert.equal(
175-
error.message,
176-
`Failed to inspect legacy desktop user-data path at "${legacyPath}".`,
177-
);
169+
const userDataPath = yield* identity.resolveUserDataPath;
170+
171+
assert.equal(userDataPath, "/Users/alice/Library/Application Support/t3code");
178172
}),
179173
{ legacyPathProbeError: cause },
180174
);

apps/desktop/src/app/DesktopAppIdentity.ts

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ export class DesktopUserDataPathResolutionError extends Schema.TaggedErrorClass<
3333
export class DesktopAppIdentity extends Context.Service<
3434
DesktopAppIdentity,
3535
{
36-
readonly resolveUserDataPath: Effect.Effect<string, DesktopUserDataPathResolutionError>;
36+
readonly resolveUserDataPath: Effect.Effect<string>;
3737
readonly configure: Effect.Effect<void>;
3838
}
3939
>()("@t3tools/desktop/app/DesktopAppIdentity") {}
@@ -95,15 +95,9 @@ export const make = Effect.gen(function* () {
9595
environment.appDataDirectory,
9696
environment.legacyUserDataDirName,
9797
);
98-
const legacyPathExists = yield* fileSystem.exists(legacyPath).pipe(
99-
Effect.mapError(
100-
(cause) =>
101-
new DesktopUserDataPathResolutionError({
102-
legacyPath,
103-
cause,
104-
}),
105-
),
106-
);
98+
const legacyPathExists = yield* fileSystem
99+
.exists(legacyPath)
100+
.pipe(Effect.orElseSucceed(() => false));
107101
return legacyPathExists
108102
? legacyPath
109103
: environment.path.join(environment.appDataDirectory, environment.userDataDirName);

apps/desktop/src/app/DesktopAssets.test.ts

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { assert, describe, it } from "@effect/vitest";
33
import * as Effect from "effect/Effect";
44
import * as FileSystem from "effect/FileSystem";
55
import * as Layer from "effect/Layer";
6+
import * as Option from "effect/Option";
67
import * as PlatformError from "effect/PlatformError";
78

89
import * as DesktopAssets from "./DesktopAssets.ts";
@@ -22,7 +23,7 @@ const environmentLayer = DesktopEnvironment.layer({
2223
}).pipe(Layer.provide(Layer.mergeAll(NodeServices.layer, DesktopConfig.layerTest({}))));
2324

2425
describe("DesktopAssets", () => {
25-
it.effect("preserves the failed asset candidate and filesystem cause", () =>
26+
it.effect("treats a failed asset probe as not found and continues searching", () =>
2627
Effect.gen(function* () {
2728
const fileName = "custom.bin";
2829
const candidatePath = "/repo/apps/desktop/resources/custom.bin";
@@ -41,17 +42,9 @@ describe("DesktopAssets", () => {
4142
);
4243
const assets = yield* DesktopAssets.DesktopAssets.pipe(Effect.provide(assetsLayer));
4344

44-
const error = yield* assets.resolveResourcePath(fileName).pipe(Effect.flip);
45+
const result = yield* assets.resolveResourcePath(fileName);
4546

46-
assert.instanceOf(error, DesktopAssets.DesktopAssetProbeError);
47-
assert.equal(error.fileName, fileName);
48-
assert.equal(error.candidatePath, candidatePath);
49-
assert.strictEqual(error.cause, cause);
50-
assert.equal(
51-
error.message,
52-
`Failed to probe desktop asset "${fileName}" at ${candidatePath}.`,
53-
);
54-
assert.notInclude(error.message, "private filesystem diagnostic");
47+
assert.isTrue(Option.isNone(result));
5548
}),
5649
);
5750
});

apps/desktop/src/app/DesktopAssets.ts

Lines changed: 7 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -30,30 +30,22 @@ export class DesktopAssets extends Context.Service<
3030
DesktopAssets,
3131
{
3232
readonly iconPaths: Effect.Effect<DesktopIconPaths>;
33-
readonly resolveResourcePath: (
34-
fileName: string,
35-
) => Effect.Effect<Option.Option<string>, DesktopAssetProbeError>;
33+
readonly resolveResourcePath: (fileName: string) => Effect.Effect<Option.Option<string>>;
3634
}
3735
>()("@t3tools/desktop/app/DesktopAssets") {}
3836

3937
const resolveResourcePath = Effect.fn("desktop.assets.resolveResourcePath")(function* (
4038
fileName: string,
4139
): Effect.fn.Return<
4240
Option.Option<string>,
43-
DesktopAssetProbeError,
41+
never,
4442
FileSystem.FileSystem | DesktopEnvironment.DesktopEnvironment
4543
> {
4644
const fileSystem = yield* FileSystem.FileSystem;
4745
const environment = yield* DesktopEnvironment.DesktopEnvironment;
4846
const candidates = environment.resolveResourcePathCandidates(fileName);
4947
for (const candidate of candidates) {
50-
const exists = yield* fileSystem
51-
.exists(candidate)
52-
.pipe(
53-
Effect.mapError(
54-
(cause) => new DesktopAssetProbeError({ fileName, candidatePath: candidate, cause }),
55-
),
56-
);
48+
const exists = yield* fileSystem.exists(candidate).pipe(Effect.orElseSucceed(() => false));
5749
if (exists) {
5850
return Option.some(candidate);
5951
}
@@ -65,23 +57,16 @@ const resolveIconPath = Effect.fn("desktop.assets.resolveIconPath")(function* (
6557
ext: keyof DesktopIconPaths,
6658
): Effect.fn.Return<
6759
Option.Option<string>,
68-
DesktopAssetProbeError,
60+
never,
6961
FileSystem.FileSystem | DesktopEnvironment.DesktopEnvironment
7062
> {
7163
const fileSystem = yield* FileSystem.FileSystem;
7264
const environment = yield* DesktopEnvironment.DesktopEnvironment;
7365
if (environment.isDevelopment && environment.platform === "darwin" && ext === "png") {
7466
const developmentDockIconPath = environment.developmentDockIconPath;
75-
const developmentDockIconExists = yield* fileSystem.exists(developmentDockIconPath).pipe(
76-
Effect.mapError(
77-
(cause) =>
78-
new DesktopAssetProbeError({
79-
fileName: "icon.png",
80-
candidatePath: developmentDockIconPath,
81-
cause,
82-
}),
83-
),
84-
);
67+
const developmentDockIconExists = yield* fileSystem
68+
.exists(developmentDockIconPath)
69+
.pipe(Effect.orElseSucceed(() => false));
8570
if (developmentDockIconExists) {
8671
return Option.some(developmentDockIconPath);
8772
}

0 commit comments

Comments
 (0)