Skip to content

Commit 6093daa

Browse files
fix(Wind): Use Effect.either for proper fiber-level failure handling in bootstrap
Replace JavaScript try/catch with Effect.either in BootstrapImplementation to properly catch Effect failures from yield*. JavaScript try/catch cannot intercept fiber-level failures from suspended Effects - only Effect.either or Effect.catchAll can handle these. Also simplify logsPath handling in ResolveConfiguration to use Mountain's pre-timestamped directory (e.g., .../logs/20260410T105248/window1/) directly, removing the redundant timestamp nesting that was being added client-side. These changes ensure bootstrap stage failures are correctly captured and reported, and prevent duplicate log directory nesting.
1 parent 1e9a231 commit 6093daa

9 files changed

Lines changed: 106 additions & 127 deletions

File tree

Source/ESBuild.js

Lines changed: 50 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,61 +1,59 @@
11
export const Clean = process.env["Clean"] === "true";
22
export const Meta = process.env["Meta"] === "true";
3-
export const On =
4-
process.env["NODE_ENV"] === "development" ||
5-
process.env["TAURI_ENV_DEBUG"] === "true";
3+
export const On = process.env["NODE_ENV"] === "development" ||
4+
process.env["TAURI_ENV_DEBUG"] === "true";
65
/**
76
* @module ESBuild
87
*
98
*/
109
export default {
11-
color: true,
12-
format: "esm",
13-
logLevel: On ? "debug" : "silent",
14-
metafile: Meta,
15-
minify: !On,
16-
outbase: "Source/Configuration",
17-
outdir: "Configuration",
18-
platform: "node",
19-
target: "esnext",
20-
tsconfig: "tsconfig.json",
21-
write: true,
22-
legalComments: On ? "inline" : "none",
23-
bundle: false,
24-
assetNames: "Asset/[name]-[hash]",
25-
sourcemap: On,
26-
drop: On ? [] : ["debugger"],
27-
ignoreAnnotations: !On,
28-
keepNames: On,
29-
plugins: [
30-
{
31-
name: "Target",
32-
// @ts-ignore
33-
setup({ onStart, initialOptions: { outdir } }) {
34-
switch (true) {
35-
case Clean === true:
36-
onStart(async () => {
37-
try {
38-
outdir
39-
? await (
40-
await import("node:fs/promises")
41-
).rm(outdir, {
42-
recursive: true,
43-
})
44-
: {};
45-
} catch (_Error) {
46-
console.log(_Error);
47-
}
48-
});
49-
break;
50-
default:
51-
break;
52-
}
53-
},
54-
},
55-
],
56-
loader: {
57-
".json": "copy",
58-
".sh": "copy",
59-
},
10+
color: true,
11+
format: "esm",
12+
logLevel: On ? "debug" : "silent",
13+
metafile: Meta,
14+
minify: !On,
15+
outbase: "Source/Configuration",
16+
outdir: "Configuration",
17+
platform: "node",
18+
target: "esnext",
19+
tsconfig: "tsconfig.json",
20+
write: true,
21+
legalComments: On ? "inline" : "none",
22+
bundle: false,
23+
assetNames: "Asset/[name]-[hash]",
24+
sourcemap: On,
25+
drop: On ? [] : ["debugger"],
26+
ignoreAnnotations: !On,
27+
keepNames: On,
28+
plugins: [
29+
{
30+
name: "Target",
31+
// @ts-ignore
32+
setup({ onStart, initialOptions: { outdir } }) {
33+
switch (true) {
34+
case Clean === true:
35+
onStart(async () => {
36+
try {
37+
outdir
38+
? await (await import("node:fs/promises")).rm(outdir, {
39+
recursive: true,
40+
})
41+
: {};
42+
}
43+
catch (_Error) {
44+
console.log(_Error);
45+
}
46+
});
47+
break;
48+
default:
49+
break;
50+
}
51+
},
52+
},
53+
],
54+
loader: {
55+
".json": "copy",
56+
".sh": "copy",
57+
},
6058
};
6159
export const { sep, posix } = await import("node:path");

Source/Effect/Bootstrap/Implementation/BootstrapImplementation.ts

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
* @category Implementation
99
*/
1010

11-
import { Effect, Layer } from "effect";
11+
import { Effect, Either, Layer } from "effect";
1212

1313
import { Telemetry } from "../../Telemetry.js";
1414
import type { BootstrapService } from "../Interface/BootstrapService.js";
@@ -76,22 +76,27 @@ const makeBootstrap = (): BootstrapService => ({
7676
for (const Stage of Stages) {
7777
const StageStartTime = Date.now();
7878
let Result: StageResult;
79-
try {
80-
// @ts-expect-error - Effect stages have different requirements that runtime handles correctly
81-
const StageResult = yield* Effect.suspend(
82-
() => Stage,
83-
) as any;
79+
// Use Effect.either to catch fiber-level failures (missing services, etc.)
80+
// JavaScript try/catch does NOT catch Effect failures from yield*.
81+
const Outcome = yield* Effect.either(
82+
Effect.suspend(() => Stage) as unknown as Effect.Effect<StageResult, unknown>,
83+
);
84+
if (Either.isRight(Outcome)) {
8485
Result = {
85-
...StageResult,
86+
...Outcome.right,
8687
duration: Date.now() - StageStartTime,
8788
};
88-
} catch (E) {
89-
const Error = E instanceof Error ? E : new Error(String(E));
89+
} else {
90+
const FailCause = Outcome.left;
91+
const ErrorObj =
92+
FailCause instanceof Error
93+
? FailCause
94+
: new Error(String(FailCause));
9095
Result = {
9196
stageName: "Unknown",
9297
success: false as boolean,
9398
duration: Date.now() - StageStartTime,
94-
error: Error,
99+
error: ErrorObj,
95100
} satisfies StageResult;
96101
}
97102
Results.push(Result);

Source/Function/Install/Function/ResolveConfiguration.ts

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -81,20 +81,10 @@ export async function ResolveConfiguration(): Promise<ISandboxConfiguration> {
8181
DevLog("config", "folderUri:", JSON.stringify(FolderUri));
8282
DevLog("config", "workspace:", JSON.stringify(Workspace));
8383

84-
// Session timestamp for logs subdirectory
85-
const Now = new Date();
86-
const SessionTimestamp = [
87-
Now.getFullYear(),
88-
String(Now.getMonth() + 1).padStart(2, "0"),
89-
String(Now.getDate()).padStart(2, "0"),
90-
"T",
91-
String(Now.getHours()).padStart(2, "0"),
92-
String(Now.getMinutes()).padStart(2, "0"),
93-
String(Now.getSeconds()).padStart(2, "0"),
94-
].join("");
95-
const LogsLocation = Paths.logsPath
96-
? `${Paths.logsPath}/${SessionTimestamp}`
97-
: undefined;
84+
// Mountain returns logsPath as a session-timestamped directory
85+
// (e.g., .../logs/20260410T105248) with window1/ already created.
86+
// Use it directly — no additional timestamp nesting needed.
87+
const LogsLocation = Paths.logsPath || undefined;
9888

9989
return {
10090
windowId: 1,

Target/Effect/Bootstrap/Implementation/BootstrapImplementation.js

Lines changed: 10 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Target/Effect/Bootstrap/index.js

Lines changed: 1 addition & 3 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Target/Function/Install/Function/ResolveConfiguration.js

Lines changed: 1 addition & 11 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Target/Polyfills/ChildProcessPolyfill.js

Lines changed: 12 additions & 14 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Target/Polyfills/SharedProcessProxy.js

Lines changed: 12 additions & 14 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

tsconfig.tsbuildinfo

Lines changed: 1 addition & 0 deletions
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)