@noego/wood 0.4.5 → 0.4.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/wood.js +3 -0
- package/dist/codegen/type_generator.cjs +1 -0
- package/dist/codegen/type_generator.cjs.map +1 -1
- package/dist/codegen/type_generator.js +1 -0
- package/dist/codegen/type_generator.js.map +1 -1
- package/dist/main/index.cjs +154 -7
- package/dist/main/index.cjs.map +1 -1
- package/dist/main/index.d.cts +28 -2
- package/dist/main/index.d.ts +28 -2
- package/dist/main/index.js +155 -7
- package/dist/main/index.js.map +1 -1
- package/dist/types/config.cjs.map +1 -1
- package/dist/types/config.d.cts +12 -0
- package/dist/types/config.d.ts +12 -0
- package/dist/window/window_manager.cjs +3 -0
- package/dist/window/window_manager.cjs.map +1 -1
- package/dist/window/window_manager.js +3 -0
- package/dist/window/window_manager.js.map +1 -1
- package/package.json +1 -1
package/dist/main/index.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Privileges, app, BrowserWindow, ipcMain, protocol, net, shell, screen } from 'electron';
|
|
1
|
+
import { Privileges, app, BrowserWindow, ipcMain, protocol, net, shell, screen, Menu } from 'electron';
|
|
2
2
|
import { getLogger } from '@noego/logger';
|
|
3
3
|
import { TraceLevel } from '../tracing/trace_hub.cjs';
|
|
4
4
|
import { RegisterRuntimeRouter } from '../runtime/runtime.cjs';
|
|
@@ -8,6 +8,7 @@ import '../router/wood_router.cjs';
|
|
|
8
8
|
import '../types/operations.cjs';
|
|
9
9
|
|
|
10
10
|
type CleanupHandler = () => void | Promise<void>;
|
|
11
|
+
type RendererHealthState = 'ready' | 'loading' | 'unresponsive' | 'gone' | 'destroyed';
|
|
11
12
|
type WoodWindowConfig = {
|
|
12
13
|
title: string;
|
|
13
14
|
width: number;
|
|
@@ -30,6 +31,17 @@ type WoodWindowConfig = {
|
|
|
30
31
|
rememberBounds?: boolean;
|
|
31
32
|
contextMenu?: 'native' | 'custom';
|
|
32
33
|
acceptFirstMouse?: boolean;
|
|
34
|
+
nativeQuitFallback?: boolean;
|
|
35
|
+
titleBarStyle?: 'default' | 'hidden' | 'hiddenInset' | 'customButtonsOnHover';
|
|
36
|
+
trafficLightPosition?: {
|
|
37
|
+
x: number;
|
|
38
|
+
y: number;
|
|
39
|
+
};
|
|
40
|
+
titleBarOverlay?: boolean | {
|
|
41
|
+
color?: string;
|
|
42
|
+
symbolColor?: string;
|
|
43
|
+
height?: number;
|
|
44
|
+
};
|
|
33
45
|
};
|
|
34
46
|
type PrivilegedSchemeRegistration = {
|
|
35
47
|
scheme: string;
|
|
@@ -49,6 +61,7 @@ interface WoodMainBootContext {
|
|
|
49
61
|
net: typeof net;
|
|
50
62
|
shell: typeof shell;
|
|
51
63
|
screen: typeof screen;
|
|
64
|
+
Menu: typeof Menu;
|
|
52
65
|
};
|
|
53
66
|
logger: ReturnType<typeof getLogger>;
|
|
54
67
|
}
|
|
@@ -59,10 +72,20 @@ interface WoodMainRuntimeContext extends WoodMainBootContext {
|
|
|
59
72
|
createWindow: (windowId?: string) => BrowserWindow;
|
|
60
73
|
navigateWindow: (windowId: string, route: string) => Promise<void>;
|
|
61
74
|
broadcast: (channel: string, data: unknown) => void;
|
|
75
|
+
getRendererHealthState: (windowId: string) => RendererHealthState | null;
|
|
62
76
|
setRendererLogCallback: (callback: RendererLogCallback | null) => void;
|
|
63
77
|
getRendererLogCallback: () => RendererLogCallback | null;
|
|
64
78
|
getDebugMetadata: () => WoodDebugMetadata;
|
|
65
79
|
}
|
|
80
|
+
interface WoodRendererHealthEvent {
|
|
81
|
+
windowId: string;
|
|
82
|
+
state: RendererHealthState;
|
|
83
|
+
previousState: RendererHealthState | null;
|
|
84
|
+
webContentsId?: number;
|
|
85
|
+
reason?: string;
|
|
86
|
+
exitCode?: number;
|
|
87
|
+
}
|
|
88
|
+
type WoodWindowLifecycleContext = WoodMainRuntimeContext;
|
|
66
89
|
interface StartWoodMainOptions {
|
|
67
90
|
registerRuntime: (router: RegisterRuntimeRouter) => void;
|
|
68
91
|
windowDefs: Record<string, WoodWindowConfig>;
|
|
@@ -74,6 +97,8 @@ interface StartWoodMainOptions {
|
|
|
74
97
|
appBoot?: (context: WoodMainBootContext) => void | WoodMainAppBootResult | Promise<void | WoodMainAppBootResult>;
|
|
75
98
|
mainBoot?: (appBootResult: unknown, context: WoodMainRuntimeContext) => void | CleanupHandler | Promise<void | CleanupHandler>;
|
|
76
99
|
onBeforeQuit?: (context: WoodMainRuntimeContext) => void | Promise<void>;
|
|
100
|
+
onWindowCreated?: (windowId: string, win: BrowserWindow, context: WoodMainRuntimeContext) => void | Promise<void>;
|
|
101
|
+
onRendererHealthChanged?: (event: WoodRendererHealthEvent, context: WoodMainRuntimeContext) => void | Promise<void>;
|
|
77
102
|
onLoad?: (data: unknown, event?: unknown) => Promise<unknown>;
|
|
78
103
|
onContextMenu?: (data: unknown, event?: unknown) => Promise<unknown>;
|
|
79
104
|
traceMinLevel?: TraceLevel;
|
|
@@ -87,6 +112,7 @@ interface WoodDebugWindowMetadata {
|
|
|
87
112
|
webContentsId: number;
|
|
88
113
|
url: string;
|
|
89
114
|
focused: boolean;
|
|
115
|
+
rendererHealth?: RendererHealthState;
|
|
90
116
|
}
|
|
91
117
|
interface WoodDebugMetadata {
|
|
92
118
|
ok: boolean;
|
|
@@ -102,4 +128,4 @@ declare function resolveWoodDebugMetadataConfiguration(env?: NodeJS.ProcessEnv):
|
|
|
102
128
|
};
|
|
103
129
|
declare function startWoodMain(options: StartWoodMainOptions): void;
|
|
104
130
|
|
|
105
|
-
export { type PrivilegedSchemeRegistration, type StartWoodMainOptions, type WoodDebugMetadata, type WoodDebugWindowMetadata, type WoodMainAppBootResult, type WoodMainBootContext, type WoodMainRuntimeContext, type WoodWindowConfig, resolveWoodDebugMetadataConfiguration, startWoodMain };
|
|
131
|
+
export { type PrivilegedSchemeRegistration, type RendererHealthState, type StartWoodMainOptions, type WoodDebugMetadata, type WoodDebugWindowMetadata, type WoodMainAppBootResult, type WoodMainBootContext, type WoodMainRuntimeContext, type WoodRendererHealthEvent, type WoodWindowConfig, type WoodWindowLifecycleContext, resolveWoodDebugMetadataConfiguration, startWoodMain };
|
package/dist/main/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Privileges, app, BrowserWindow, ipcMain, protocol, net, shell, screen } from 'electron';
|
|
1
|
+
import { Privileges, app, BrowserWindow, ipcMain, protocol, net, shell, screen, Menu } from 'electron';
|
|
2
2
|
import { getLogger } from '@noego/logger';
|
|
3
3
|
import { TraceLevel } from '../tracing/trace_hub.js';
|
|
4
4
|
import { RegisterRuntimeRouter } from '../runtime/runtime.js';
|
|
@@ -8,6 +8,7 @@ import '../router/wood_router.js';
|
|
|
8
8
|
import '../types/operations.js';
|
|
9
9
|
|
|
10
10
|
type CleanupHandler = () => void | Promise<void>;
|
|
11
|
+
type RendererHealthState = 'ready' | 'loading' | 'unresponsive' | 'gone' | 'destroyed';
|
|
11
12
|
type WoodWindowConfig = {
|
|
12
13
|
title: string;
|
|
13
14
|
width: number;
|
|
@@ -30,6 +31,17 @@ type WoodWindowConfig = {
|
|
|
30
31
|
rememberBounds?: boolean;
|
|
31
32
|
contextMenu?: 'native' | 'custom';
|
|
32
33
|
acceptFirstMouse?: boolean;
|
|
34
|
+
nativeQuitFallback?: boolean;
|
|
35
|
+
titleBarStyle?: 'default' | 'hidden' | 'hiddenInset' | 'customButtonsOnHover';
|
|
36
|
+
trafficLightPosition?: {
|
|
37
|
+
x: number;
|
|
38
|
+
y: number;
|
|
39
|
+
};
|
|
40
|
+
titleBarOverlay?: boolean | {
|
|
41
|
+
color?: string;
|
|
42
|
+
symbolColor?: string;
|
|
43
|
+
height?: number;
|
|
44
|
+
};
|
|
33
45
|
};
|
|
34
46
|
type PrivilegedSchemeRegistration = {
|
|
35
47
|
scheme: string;
|
|
@@ -49,6 +61,7 @@ interface WoodMainBootContext {
|
|
|
49
61
|
net: typeof net;
|
|
50
62
|
shell: typeof shell;
|
|
51
63
|
screen: typeof screen;
|
|
64
|
+
Menu: typeof Menu;
|
|
52
65
|
};
|
|
53
66
|
logger: ReturnType<typeof getLogger>;
|
|
54
67
|
}
|
|
@@ -59,10 +72,20 @@ interface WoodMainRuntimeContext extends WoodMainBootContext {
|
|
|
59
72
|
createWindow: (windowId?: string) => BrowserWindow;
|
|
60
73
|
navigateWindow: (windowId: string, route: string) => Promise<void>;
|
|
61
74
|
broadcast: (channel: string, data: unknown) => void;
|
|
75
|
+
getRendererHealthState: (windowId: string) => RendererHealthState | null;
|
|
62
76
|
setRendererLogCallback: (callback: RendererLogCallback | null) => void;
|
|
63
77
|
getRendererLogCallback: () => RendererLogCallback | null;
|
|
64
78
|
getDebugMetadata: () => WoodDebugMetadata;
|
|
65
79
|
}
|
|
80
|
+
interface WoodRendererHealthEvent {
|
|
81
|
+
windowId: string;
|
|
82
|
+
state: RendererHealthState;
|
|
83
|
+
previousState: RendererHealthState | null;
|
|
84
|
+
webContentsId?: number;
|
|
85
|
+
reason?: string;
|
|
86
|
+
exitCode?: number;
|
|
87
|
+
}
|
|
88
|
+
type WoodWindowLifecycleContext = WoodMainRuntimeContext;
|
|
66
89
|
interface StartWoodMainOptions {
|
|
67
90
|
registerRuntime: (router: RegisterRuntimeRouter) => void;
|
|
68
91
|
windowDefs: Record<string, WoodWindowConfig>;
|
|
@@ -74,6 +97,8 @@ interface StartWoodMainOptions {
|
|
|
74
97
|
appBoot?: (context: WoodMainBootContext) => void | WoodMainAppBootResult | Promise<void | WoodMainAppBootResult>;
|
|
75
98
|
mainBoot?: (appBootResult: unknown, context: WoodMainRuntimeContext) => void | CleanupHandler | Promise<void | CleanupHandler>;
|
|
76
99
|
onBeforeQuit?: (context: WoodMainRuntimeContext) => void | Promise<void>;
|
|
100
|
+
onWindowCreated?: (windowId: string, win: BrowserWindow, context: WoodMainRuntimeContext) => void | Promise<void>;
|
|
101
|
+
onRendererHealthChanged?: (event: WoodRendererHealthEvent, context: WoodMainRuntimeContext) => void | Promise<void>;
|
|
77
102
|
onLoad?: (data: unknown, event?: unknown) => Promise<unknown>;
|
|
78
103
|
onContextMenu?: (data: unknown, event?: unknown) => Promise<unknown>;
|
|
79
104
|
traceMinLevel?: TraceLevel;
|
|
@@ -87,6 +112,7 @@ interface WoodDebugWindowMetadata {
|
|
|
87
112
|
webContentsId: number;
|
|
88
113
|
url: string;
|
|
89
114
|
focused: boolean;
|
|
115
|
+
rendererHealth?: RendererHealthState;
|
|
90
116
|
}
|
|
91
117
|
interface WoodDebugMetadata {
|
|
92
118
|
ok: boolean;
|
|
@@ -102,4 +128,4 @@ declare function resolveWoodDebugMetadataConfiguration(env?: NodeJS.ProcessEnv):
|
|
|
102
128
|
};
|
|
103
129
|
declare function startWoodMain(options: StartWoodMainOptions): void;
|
|
104
130
|
|
|
105
|
-
export { type PrivilegedSchemeRegistration, type StartWoodMainOptions, type WoodDebugMetadata, type WoodDebugWindowMetadata, type WoodMainAppBootResult, type WoodMainBootContext, type WoodMainRuntimeContext, type WoodWindowConfig, resolveWoodDebugMetadataConfiguration, startWoodMain };
|
|
131
|
+
export { type PrivilegedSchemeRegistration, type RendererHealthState, type StartWoodMainOptions, type WoodDebugMetadata, type WoodDebugWindowMetadata, type WoodMainAppBootResult, type WoodMainBootContext, type WoodMainRuntimeContext, type WoodRendererHealthEvent, type WoodWindowConfig, type WoodWindowLifecycleContext, resolveWoodDebugMetadataConfiguration, startWoodMain };
|
package/dist/main/index.js
CHANGED
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
BrowserWindow,
|
|
5
5
|
ipcMain,
|
|
6
6
|
MessageChannelMain,
|
|
7
|
+
Menu,
|
|
7
8
|
protocol,
|
|
8
9
|
net,
|
|
9
10
|
shell,
|
|
@@ -60,11 +61,13 @@ function startWoodMain(options) {
|
|
|
60
61
|
const debugConfig = resolveWoodDebugMetadataConfiguration();
|
|
61
62
|
const windowState = new WindowStateStore();
|
|
62
63
|
const windows = /* @__PURE__ */ new Map();
|
|
64
|
+
const rendererHealth = /* @__PURE__ */ new Map();
|
|
63
65
|
let mainWindow = null;
|
|
64
66
|
let beforeQuitCleanupComplete = false;
|
|
65
67
|
let beforeQuitCleanupPromise = null;
|
|
66
68
|
let runtimeContext = null;
|
|
67
69
|
let mainBootCleanup;
|
|
70
|
+
let nativeQuitFallbackInstalled = false;
|
|
68
71
|
for (const stream of [process.stdout, process.stderr]) {
|
|
69
72
|
stream.on("error", (error) => {
|
|
70
73
|
if (error.code === "EPIPE") {
|
|
@@ -89,7 +92,8 @@ function startWoodMain(options) {
|
|
|
89
92
|
protocol,
|
|
90
93
|
net,
|
|
91
94
|
shell,
|
|
92
|
-
screen
|
|
95
|
+
screen,
|
|
96
|
+
Menu
|
|
93
97
|
},
|
|
94
98
|
logger
|
|
95
99
|
};
|
|
@@ -140,6 +144,129 @@ function startWoodMain(options) {
|
|
|
140
144
|
}
|
|
141
145
|
return null;
|
|
142
146
|
};
|
|
147
|
+
const getRendererHealthState = (windowId) => {
|
|
148
|
+
return rendererHealth.get(windowId) ?? null;
|
|
149
|
+
};
|
|
150
|
+
const notifyRendererHealthChanged = (event) => {
|
|
151
|
+
if (!options.onRendererHealthChanged) {
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
if (!runtimeContext) {
|
|
155
|
+
runtimeLogger.warn("renderer health hook skipped before runtime context", {
|
|
156
|
+
windowId: event.windowId,
|
|
157
|
+
state: event.state
|
|
158
|
+
});
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
Promise.resolve(options.onRendererHealthChanged(event, runtimeContext)).catch((error) => {
|
|
162
|
+
runtimeLogger.warn("renderer health hook failed", {
|
|
163
|
+
windowId: event.windowId,
|
|
164
|
+
state: event.state,
|
|
165
|
+
error: toErrorMessage(error)
|
|
166
|
+
});
|
|
167
|
+
});
|
|
168
|
+
};
|
|
169
|
+
const setRendererHealth = (windowId, state, details = {}) => {
|
|
170
|
+
const previousState = rendererHealth.get(windowId) ?? null;
|
|
171
|
+
rendererHealth.set(windowId, state);
|
|
172
|
+
notifyRendererHealthChanged({
|
|
173
|
+
windowId,
|
|
174
|
+
state,
|
|
175
|
+
previousState,
|
|
176
|
+
...details
|
|
177
|
+
});
|
|
178
|
+
};
|
|
179
|
+
const attachRendererHealth = (windowId, win) => {
|
|
180
|
+
const healthLogger = getLogger("wood:main").named(`renderer-health:${windowId}`);
|
|
181
|
+
const webContentsId = win.webContents.id;
|
|
182
|
+
setRendererHealth(windowId, "loading", { webContentsId });
|
|
183
|
+
win.webContents.on("did-start-loading", () => {
|
|
184
|
+
setRendererHealth(windowId, "loading", { webContentsId });
|
|
185
|
+
healthLogger.info("renderer loading", { windowId, webContentsId });
|
|
186
|
+
});
|
|
187
|
+
win.webContents.on("did-finish-load", () => {
|
|
188
|
+
setRendererHealth(windowId, "ready", { webContentsId });
|
|
189
|
+
healthLogger.info("renderer ready", { windowId, webContentsId });
|
|
190
|
+
});
|
|
191
|
+
win.webContents.on("unresponsive", () => {
|
|
192
|
+
setRendererHealth(windowId, "unresponsive", { webContentsId });
|
|
193
|
+
healthLogger.error("renderer unresponsive", { windowId, webContentsId });
|
|
194
|
+
});
|
|
195
|
+
win.webContents.on("responsive", () => {
|
|
196
|
+
setRendererHealth(windowId, "ready", { webContentsId });
|
|
197
|
+
healthLogger.info("renderer responsive", { windowId, webContentsId });
|
|
198
|
+
});
|
|
199
|
+
win.webContents.on("render-process-gone", (_event, details) => {
|
|
200
|
+
setRendererHealth(windowId, "gone", {
|
|
201
|
+
webContentsId,
|
|
202
|
+
reason: details.reason,
|
|
203
|
+
exitCode: details.exitCode
|
|
204
|
+
});
|
|
205
|
+
healthLogger.error("renderer process gone", {
|
|
206
|
+
windowId,
|
|
207
|
+
webContentsId,
|
|
208
|
+
reason: details.reason,
|
|
209
|
+
exitCode: details.exitCode
|
|
210
|
+
});
|
|
211
|
+
});
|
|
212
|
+
win.webContents.on("destroyed", () => {
|
|
213
|
+
setRendererHealth(windowId, "destroyed");
|
|
214
|
+
healthLogger.warn("renderer destroyed", { windowId, webContentsId });
|
|
215
|
+
});
|
|
216
|
+
win.on("closed", () => {
|
|
217
|
+
setRendererHealth(windowId, "destroyed");
|
|
218
|
+
rendererHealth.delete(windowId);
|
|
219
|
+
});
|
|
220
|
+
};
|
|
221
|
+
const canSendToWindow = (win) => {
|
|
222
|
+
if (win.isDestroyed()) {
|
|
223
|
+
return false;
|
|
224
|
+
}
|
|
225
|
+
if (win.webContents.isDestroyed()) {
|
|
226
|
+
return false;
|
|
227
|
+
}
|
|
228
|
+
if (typeof win.webContents.isCrashed === "function" && win.webContents.isCrashed()) {
|
|
229
|
+
return false;
|
|
230
|
+
}
|
|
231
|
+
return true;
|
|
232
|
+
};
|
|
233
|
+
const safeSend = (windowId, win, channel, data) => {
|
|
234
|
+
if (!canSendToWindow(win)) {
|
|
235
|
+
runtimeLogger.warn("skipping send to unhealthy renderer", {
|
|
236
|
+
windowId,
|
|
237
|
+
channel,
|
|
238
|
+
rendererHealth: getRendererHealthState(windowId)
|
|
239
|
+
});
|
|
240
|
+
return false;
|
|
241
|
+
}
|
|
242
|
+
try {
|
|
243
|
+
win.webContents.send(channel, data);
|
|
244
|
+
return true;
|
|
245
|
+
} catch (error) {
|
|
246
|
+
runtimeLogger.warn("send to renderer failed", {
|
|
247
|
+
windowId,
|
|
248
|
+
channel,
|
|
249
|
+
rendererHealth: getRendererHealthState(windowId),
|
|
250
|
+
error: toErrorMessage(error)
|
|
251
|
+
});
|
|
252
|
+
return false;
|
|
253
|
+
}
|
|
254
|
+
};
|
|
255
|
+
const installNativeQuitFallback = () => {
|
|
256
|
+
if (nativeQuitFallbackInstalled) {
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
Menu.setApplicationMenu(Menu.buildFromTemplate([
|
|
260
|
+
{
|
|
261
|
+
label: electronApp.name,
|
|
262
|
+
submenu: [
|
|
263
|
+
{ role: "quit" }
|
|
264
|
+
]
|
|
265
|
+
}
|
|
266
|
+
]));
|
|
267
|
+
nativeQuitFallbackInstalled = true;
|
|
268
|
+
logger.info("native quit fallback installed");
|
|
269
|
+
};
|
|
143
270
|
const waitForWindowReady = async (win) => {
|
|
144
271
|
const webContents = win.webContents;
|
|
145
272
|
const isLoading = typeof webContents.isLoadingMainFrame === "function" ? webContents.isLoadingMainFrame() : webContents.isLoading();
|
|
@@ -162,7 +289,8 @@ function startWoodMain(options) {
|
|
|
162
289
|
title: win.getTitle(),
|
|
163
290
|
webContentsId: win.webContents.id,
|
|
164
291
|
url: win.webContents.getURL(),
|
|
165
|
-
focused: win.isFocused()
|
|
292
|
+
focused: win.isFocused(),
|
|
293
|
+
rendererHealth: getRendererHealthState(windowId) ?? void 0
|
|
166
294
|
});
|
|
167
295
|
}
|
|
168
296
|
return {
|
|
@@ -183,6 +311,9 @@ function startWoodMain(options) {
|
|
|
183
311
|
const windowDef = resolveWindowDef(options.windowDefs, windowId);
|
|
184
312
|
const defaultShow = windowDef.show ?? true;
|
|
185
313
|
const parentWindow = windowDef.parent ? getWindow(windowDef.parent) : null;
|
|
314
|
+
if (windowDef.nativeQuitFallback === true) {
|
|
315
|
+
installNativeQuitFallback();
|
|
316
|
+
}
|
|
186
317
|
windowState.setScreen(screen);
|
|
187
318
|
const savedBounds = windowDef.rememberBounds ? windowState.getBounds(windowId) : null;
|
|
188
319
|
const windowOptions = {
|
|
@@ -209,6 +340,12 @@ function startWoodMain(options) {
|
|
|
209
340
|
backgroundMaterial: windowDef.backgroundMaterial
|
|
210
341
|
} : {},
|
|
211
342
|
...typeof windowDef.acceptFirstMouse === "boolean" ? { acceptFirstMouse: windowDef.acceptFirstMouse } : {},
|
|
343
|
+
// Hidden title bar with native window controls: macOS draws the
|
|
344
|
+
// traffic lights (positionable), Windows draws min/max/close via the
|
|
345
|
+
// Window Controls Overlay (always top-right; styled via titleBarOverlay).
|
|
346
|
+
...typeof windowDef.titleBarStyle === "string" ? { titleBarStyle: windowDef.titleBarStyle } : {},
|
|
347
|
+
...process.platform === "darwin" && windowDef.trafficLightPosition ? { trafficLightPosition: windowDef.trafficLightPosition } : {},
|
|
348
|
+
...process.platform === "win32" && windowDef.titleBarOverlay != null ? { titleBarOverlay: windowDef.titleBarOverlay } : {},
|
|
212
349
|
show: savedBounds ? false : defaultShow,
|
|
213
350
|
webPreferences: {
|
|
214
351
|
preload: preloadPath,
|
|
@@ -218,6 +355,7 @@ function startWoodMain(options) {
|
|
|
218
355
|
};
|
|
219
356
|
const win = new BrowserWindow(windowOptions);
|
|
220
357
|
windows.set(windowId, win);
|
|
358
|
+
attachRendererHealth(windowId, win);
|
|
221
359
|
if (windowId === "main") {
|
|
222
360
|
mainWindow = win;
|
|
223
361
|
}
|
|
@@ -305,6 +443,7 @@ function startWoodMain(options) {
|
|
|
305
443
|
}
|
|
306
444
|
win.on("closed", () => {
|
|
307
445
|
windows.delete(windowId);
|
|
446
|
+
rendererHealth.delete(windowId);
|
|
308
447
|
if (windowId === "main") {
|
|
309
448
|
mainWindow = null;
|
|
310
449
|
}
|
|
@@ -312,13 +451,21 @@ function startWoodMain(options) {
|
|
|
312
451
|
electronApp.quit();
|
|
313
452
|
}
|
|
314
453
|
});
|
|
454
|
+
if (options.onWindowCreated) {
|
|
455
|
+
Promise.resolve(options.onWindowCreated(windowId, win, runtimeContext)).catch((error) => {
|
|
456
|
+
runtimeLogger.warn("window created hook failed", {
|
|
457
|
+
windowId,
|
|
458
|
+
error: toErrorMessage(error)
|
|
459
|
+
});
|
|
460
|
+
});
|
|
461
|
+
}
|
|
315
462
|
logger.info("window created", { windowId });
|
|
316
463
|
return win;
|
|
317
464
|
};
|
|
318
465
|
const navigateWindow = async (windowId, route) => {
|
|
319
466
|
const win = createWindow(windowId);
|
|
320
467
|
await waitForWindowReady(win);
|
|
321
|
-
win
|
|
468
|
+
safeSend(windowId, win, "__event:__navigate", { route });
|
|
322
469
|
win.show();
|
|
323
470
|
win.focus();
|
|
324
471
|
};
|
|
@@ -326,8 +473,8 @@ function startWoodMain(options) {
|
|
|
326
473
|
const eventChannel = channel.startsWith("__event:") ? channel : `__event:${channel}`;
|
|
327
474
|
if (options2?.windowId) {
|
|
328
475
|
const target = getWindow(options2.windowId);
|
|
329
|
-
if (target
|
|
330
|
-
target
|
|
476
|
+
if (target) {
|
|
477
|
+
safeSend(options2.windowId, target, eventChannel, data);
|
|
331
478
|
}
|
|
332
479
|
return;
|
|
333
480
|
}
|
|
@@ -336,7 +483,7 @@ function startWoodMain(options) {
|
|
|
336
483
|
windows.delete(windowId);
|
|
337
484
|
continue;
|
|
338
485
|
}
|
|
339
|
-
win
|
|
486
|
+
safeSend(windowId, win, eventChannel, data);
|
|
340
487
|
}
|
|
341
488
|
};
|
|
342
489
|
setIpcPushSender(dispatchPushEvent);
|
|
@@ -346,7 +493,7 @@ function startWoodMain(options) {
|
|
|
346
493
|
windows.delete(windowId);
|
|
347
494
|
continue;
|
|
348
495
|
}
|
|
349
|
-
win
|
|
496
|
+
safeSend(windowId, win, channel, data);
|
|
350
497
|
}
|
|
351
498
|
};
|
|
352
499
|
runtimeContext = {
|
|
@@ -357,6 +504,7 @@ function startWoodMain(options) {
|
|
|
357
504
|
createWindow,
|
|
358
505
|
navigateWindow,
|
|
359
506
|
broadcast,
|
|
507
|
+
getRendererHealthState,
|
|
360
508
|
setRendererLogCallback: (callback) => {
|
|
361
509
|
getRendererLogDispatcher().setCallback(callback);
|
|
362
510
|
},
|
package/dist/main/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/main/index.ts"],"sourcesContent":["import path from 'path';\nimport {\n app as electronApp,\n BrowserWindow,\n ipcMain,\n MessageChannelMain,\n protocol,\n net,\n shell,\n screen,\n} from 'electron';\nimport type {\n BrowserWindowConstructorOptions,\n BrowserWindow as ElectronBrowserWindow,\n Event as ElectronEvent,\n IpcMainInvokeEvent,\n Privileges,\n} from 'electron';\nimport { getLogger } from '@noego/logger';\nimport { WindowStateStore } from '../window/window_state_store.js';\nimport { getContainer } from '../runtime/get_container.js';\nimport { runtime as bootRuntime } from '../runtime/runtime.js';\nimport { dispatchRendererTracePayload, type TraceLevel } from '../tracing/index.js';\nimport { setApplicationRoot } from '../runtime/application_root.js';\nimport type { RegisterRuntimeRouter } from '../runtime/runtime.js';\nimport {\n getRendererLogDispatcher,\n type RendererLogCallback,\n} from '../runtime/renderer_log_dispatcher.js';\nimport { Ipc, getIpc } from '../ipc/index.js';\nimport { setIpcPushSender, clearIpcPushSender, type IpcPushOptions } from '../ipc/shared.js';\n\ntype CleanupHandler = () => void | Promise<void>;\n\nexport type WoodWindowConfig = {\n title: string;\n width: number;\n height: number;\n defaultRoute?: string;\n frame?: boolean;\n transparent?: boolean;\n resizable?: boolean;\n alwaysOnTop?: boolean;\n minWidth?: number;\n minHeight?: number;\n maxWidth?: number;\n maxHeight?: number;\n show?: boolean;\n parent?: string;\n modal?: boolean;\n vibrancy?: string;\n backgroundMaterial?: string;\n backgroundColor?: string;\n rememberBounds?: boolean;\n contextMenu?: 'native' | 'custom';\n acceptFirstMouse?: boolean;\n};\n\nexport type PrivilegedSchemeRegistration = {\n scheme: string;\n privileges: Privileges;\n};\n\nexport interface WoodMainAppBootResult {\n scope?: string;\n configureContainer?: (container: any) => void;\n registerSchemesAsPrivileged?: PrivilegedSchemeRegistration[];\n}\n\nexport interface WoodMainBootContext {\n electron: {\n app: typeof electronApp;\n BrowserWindow: typeof BrowserWindow;\n ipcMain: typeof ipcMain;\n protocol: typeof protocol;\n net: typeof net;\n shell: typeof shell;\n screen: typeof screen;\n };\n logger: ReturnType<typeof getLogger>;\n}\n\nexport interface WoodMainRuntimeContext extends WoodMainBootContext {\n container: any;\n applicationRoot: string;\n getWindow: (windowId: string) => ElectronBrowserWindow | null;\n createWindow: (windowId?: string) => ElectronBrowserWindow;\n navigateWindow: (windowId: string, route: string) => Promise<void>;\n broadcast: (channel: string, data: unknown) => void;\n setRendererLogCallback: (callback: RendererLogCallback | null) => void;\n getRendererLogCallback: () => RendererLogCallback | null;\n getDebugMetadata: () => WoodDebugMetadata;\n}\n\nexport interface StartWoodMainOptions {\n registerRuntime: (router: RegisterRuntimeRouter) => void;\n windowDefs: Record<string, WoodWindowConfig>;\n controllersDir: string;\n middlewareDir: string;\n outDir?: string;\n scope?: string;\n configureContainer?: (container: any) => void;\n appBoot?: (\n context: WoodMainBootContext,\n ) => void | WoodMainAppBootResult | Promise<void | WoodMainAppBootResult>;\n mainBoot?: (\n appBootResult: unknown,\n context: WoodMainRuntimeContext,\n ) => void | CleanupHandler | Promise<void | CleanupHandler>;\n onBeforeQuit?: (context: WoodMainRuntimeContext) => void | Promise<void>;\n onLoad?: (data: unknown, event?: unknown) => Promise<unknown>;\n onContextMenu?: (data: unknown, event?: unknown) => Promise<unknown>;\n traceMinLevel?: TraceLevel;\n rendererTraceEnabled?: boolean;\n rendererTraceMinLevel?: TraceLevel;\n traceTransport?: 'ipc' | 'messageport';\n}\n\nexport interface WoodDebugWindowMetadata {\n windowId: string;\n title: string;\n webContentsId: number;\n url: string;\n focused: boolean;\n}\n\nexport interface WoodDebugMetadata {\n ok: boolean;\n enabled: boolean;\n mode: 'development' | 'production';\n port?: number;\n windows: WoodDebugWindowMetadata[];\n}\n\nconst DEFAULT_WOOD_REMOTE_DEBUGGING_PORT = 9333;\n\nexport function resolveWoodDebugMetadataConfiguration(env: NodeJS.ProcessEnv = process.env): {\n enabled: boolean;\n mode: 'development' | 'production';\n port?: number;\n} {\n const isDevelopment = env.WOOD_MODE === 'development';\n if (!isDevelopment) {\n return {\n enabled: false,\n mode: 'production',\n };\n }\n\n const rawPort = env.WOOD_REMOTE_DEBUGGING_PORT;\n const parsedPort = rawPort ? Number.parseInt(rawPort, 10) : DEFAULT_WOOD_REMOTE_DEBUGGING_PORT;\n const port = Number.isFinite(parsedPort) && parsedPort > 0\n ? parsedPort\n : DEFAULT_WOOD_REMOTE_DEBUGGING_PORT;\n\n return {\n enabled: true,\n mode: 'development',\n port,\n };\n}\n\nfunction resolveWindowDef(\n windowDefs: Record<string, WoodWindowConfig>,\n windowId = 'main',\n): WoodWindowConfig {\n const def = windowDefs[windowId];\n if (!def) {\n throw new Error(`Window \"${windowId}\" not defined in generated window defs.`);\n }\n return def;\n}\n\nfunction resolveRuntimePath(relativeOrAbsolutePath: string): string {\n if (path.isAbsolute(relativeOrAbsolutePath)) {\n return relativeOrAbsolutePath;\n }\n return path.join(electronApp.getAppPath(), relativeOrAbsolutePath);\n}\n\nfunction toErrorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\nexport function startWoodMain(options: StartWoodMainOptions): void {\n const logger = getLogger('wood:main').named('bootstrap');\n const runtimeLogger = getLogger('wood:main').named('runtime');\n const debugConfig = resolveWoodDebugMetadataConfiguration();\n const windowState = new WindowStateStore();\n const windows = new Map<string, ElectronBrowserWindow>();\n let mainWindow: ElectronBrowserWindow | null = null;\n let beforeQuitCleanupComplete = false;\n let beforeQuitCleanupPromise: Promise<void> | null = null;\n let runtimeContext: WoodMainRuntimeContext | null = null;\n let mainBootCleanup: CleanupHandler | undefined;\n\n for (const stream of [process.stdout, process.stderr]) {\n stream.on('error', (error: NodeJS.ErrnoException) => {\n if (error.code === 'EPIPE') {\n return;\n }\n throw error;\n });\n }\n\n if (debugConfig.enabled && debugConfig.port) {\n electronApp.commandLine.appendSwitch('remote-debugging-port', String(debugConfig.port));\n electronApp.commandLine.appendSwitch('remote-debugging-address', '127.0.0.1');\n logger.info('devtools remote debugging enabled', {\n port: debugConfig.port,\n mode: debugConfig.mode,\n });\n }\n\n const bootContext: WoodMainBootContext = {\n electron: {\n app: electronApp,\n BrowserWindow,\n ipcMain,\n protocol,\n net,\n shell,\n screen,\n },\n logger,\n };\n\n void (async () => {\n const appBootResult = options.appBoot\n ? await options.appBoot(bootContext)\n : undefined;\n\n const bootOverrides = (appBootResult ?? {}) as WoodMainAppBootResult;\n const scope = bootOverrides.scope ?? options.scope ?? process.cwd();\n const configureContainer = bootOverrides.configureContainer ?? options.configureContainer;\n const privilegedSchemes = Array.isArray(bootOverrides.registerSchemesAsPrivileged)\n ? bootOverrides.registerSchemesAsPrivileged\n : [];\n\n if (privilegedSchemes.length > 0) {\n protocol.registerSchemesAsPrivileged(privilegedSchemes);\n logger.info('registered privileged schemes', {\n count: privilegedSchemes.length,\n schemes: privilegedSchemes.map((entry) => entry.scheme),\n });\n }\n\n const outDir = options.outDir ?? 'out';\n const preloadPath = path.join(electronApp.getAppPath(), outDir, 'preload', 'index.js');\n const rendererFile = path.join(electronApp.getAppPath(), outDir, 'renderer', 'index.html');\n\n const container = getContainer({\n scope,\n ...(configureContainer ? { configure: configureContainer } : {}),\n });\n\n const registrationContainer = container as {\n registerFunction?: (\n token: any,\n resolver: (...args: any[]) => unknown,\n options?: Record<string, unknown>,\n ) => void;\n };\n\n if (typeof registrationContainer.registerFunction === 'function') {\n registrationContainer.registerFunction(Ipc, () => getIpc());\n }\n\n const getWindow = (windowId: string): ElectronBrowserWindow | null => {\n const existing = windows.get(windowId);\n if (!existing) {\n return null;\n }\n if (existing.isDestroyed()) {\n windows.delete(windowId);\n return null;\n }\n return existing;\n };\n\n const findWindowIdByWebContents = (webContentsId: number): string | null => {\n for (const [windowId, win] of windows.entries()) {\n if (win.isDestroyed()) {\n windows.delete(windowId);\n continue;\n }\n if (win.webContents.id === webContentsId) {\n return windowId;\n }\n }\n return null;\n };\n\n const waitForWindowReady = async (win: ElectronBrowserWindow): Promise<void> => {\n const webContents = win.webContents as ElectronBrowserWindow['webContents'] & {\n isLoadingMainFrame?: () => boolean;\n };\n const isLoading = typeof webContents.isLoadingMainFrame === 'function'\n ? webContents.isLoadingMainFrame()\n : webContents.isLoading();\n if (!isLoading) {\n return;\n }\n\n await new Promise<void>((resolve) => {\n webContents.once('did-finish-load', () => resolve());\n });\n };\n\n const getDebugMetadata = (): WoodDebugMetadata => {\n const debugWindows: WoodDebugWindowMetadata[] = [];\n\n for (const [windowId, win] of windows.entries()) {\n if (win.isDestroyed()) {\n windows.delete(windowId);\n continue;\n }\n\n debugWindows.push({\n windowId,\n title: win.getTitle(),\n webContentsId: win.webContents.id,\n url: win.webContents.getURL(),\n focused: win.isFocused(),\n });\n }\n\n return {\n ok: true,\n enabled: debugConfig.enabled,\n mode: debugConfig.mode,\n ...(debugConfig.port ? { port: debugConfig.port } : {}),\n windows: debugWindows,\n };\n };\n\n const createWindow = (windowId = 'main'): ElectronBrowserWindow => {\n const existing = getWindow(windowId);\n if (existing) {\n existing.show();\n existing.focus();\n return existing;\n }\n\n const windowDef = resolveWindowDef(options.windowDefs, windowId);\n const defaultShow = windowDef.show ?? true;\n const parentWindow = windowDef.parent ? getWindow(windowDef.parent) : null;\n\n windowState.setScreen(screen);\n const savedBounds = windowDef.rememberBounds ? windowState.getBounds(windowId) : null;\n\n const windowOptions: BrowserWindowConstructorOptions = {\n width: savedBounds?.width ?? windowDef.width,\n height: savedBounds?.height ?? windowDef.height,\n ...(savedBounds ? { x: savedBounds.x, y: savedBounds.y } : {}),\n ...(windowDef.minWidth != null ? { minWidth: windowDef.minWidth } : {}),\n ...(windowDef.minHeight != null ? { minHeight: windowDef.minHeight } : {}),\n ...(windowDef.maxWidth != null ? { maxWidth: windowDef.maxWidth } : {}),\n ...(windowDef.maxHeight != null ? { maxHeight: windowDef.maxHeight } : {}),\n ...(typeof windowDef.modal === 'boolean' ? { modal: windowDef.modal } : {}),\n ...(parentWindow ? { parent: parentWindow } : {}),\n title: windowDef.title,\n frame: windowDef.frame ?? true,\n transparent: windowDef.transparent ?? false,\n resizable: windowDef.resizable ?? true,\n alwaysOnTop: windowDef.alwaysOnTop ?? false,\n ...(typeof windowDef.backgroundColor === 'string' ? { backgroundColor: windowDef.backgroundColor } : {}),\n ...(process.platform === 'darwin' && typeof windowDef.vibrancy === 'string'\n ? {\n vibrancy: windowDef.vibrancy as BrowserWindowConstructorOptions['vibrancy'],\n visualEffectState: 'active' as const,\n }\n : {}),\n ...(process.platform === 'win32' && typeof windowDef.backgroundMaterial === 'string'\n ? {\n backgroundMaterial: windowDef.backgroundMaterial as BrowserWindowConstructorOptions['backgroundMaterial'],\n }\n : {}),\n ...(typeof windowDef.acceptFirstMouse === 'boolean' ? { acceptFirstMouse: windowDef.acceptFirstMouse } : {}),\n show: savedBounds ? false : defaultShow,\n webPreferences: {\n preload: preloadPath,\n contextIsolation: true,\n nodeIntegration: false,\n },\n };\n\n const win = new BrowserWindow(windowOptions);\n windows.set(windowId, win);\n if (windowId === 'main') {\n mainWindow = win;\n }\n\n if (savedBounds?.isMaximized) {\n win.maximize();\n } else if (savedBounds?.isFullScreen) {\n win.setFullScreen(true);\n }\n\n if (savedBounds && defaultShow) {\n win.show();\n }\n\n if (windowDef.rememberBounds) {\n const captureNormalBounds = () => {\n if (!win.isMaximized() && !win.isFullScreen()) {\n const rect = win.getBounds();\n windowState.updateBoundsDebounced(windowId, {\n ...rect,\n isMaximized: false,\n isFullScreen: false,\n });\n }\n };\n win.on('move', captureNormalBounds);\n win.on('resize', captureNormalBounds);\n win.on('close', () => {\n const rect = win.getBounds();\n windowState.saveBoundsSync(windowId, {\n ...rect,\n isMaximized: win.isMaximized(),\n isFullScreen: win.isFullScreen(),\n });\n });\n }\n\n win.webContents.setWindowOpenHandler(({ url }) => {\n if (url.startsWith('http://') || url.startsWith('https://')) {\n void shell.openExternal(url);\n }\n return { action: 'deny' };\n });\n\n win.webContents.on('will-navigate', (event, url) => {\n if (process.env.ELECTRON_RENDERER_URL && url.startsWith(process.env.ELECTRON_RENDERER_URL)) {\n return;\n }\n if (url.startsWith('http://') || url.startsWith('https://')) {\n event.preventDefault();\n void shell.openExternal(url);\n }\n });\n\n const rendererLogger = getLogger('wood:main').named(`renderer:${windowId}`);\n const levelMap: Record<number, 'debug' | 'info' | 'warn' | 'error'> = {\n 0: 'debug',\n 1: 'info',\n 2: 'warn',\n 3: 'error',\n };\n\n win.webContents.on('console-message', (_event, level, message, line, sourceId) => {\n const method = levelMap[level] ?? 'info';\n rendererLogger[method](message, { source: sourceId, line, windowId });\n });\n\n if (process.env.ELECTRON_RENDERER_URL) {\n void win.loadURL(process.env.ELECTRON_RENDERER_URL);\n } else {\n void win.loadFile(rendererFile);\n }\n\n if (options.traceTransport === 'messageport' && options.rendererTraceEnabled === true) {\n const { port1, port2 } = new MessageChannelMain();\n\n const portHandler = (event: Electron.MessageEvent) => {\n dispatchRendererTracePayload(event.data, {\n windowId,\n webContentsId: win.webContents.id,\n });\n };\n port1.on('message', portHandler);\n port1.start();\n\n win.webContents.once('did-finish-load', () => {\n if (!win.isDestroyed()) {\n win.webContents.postMessage('__trace-port', null, [port2]);\n logger.info('trace messageport sent to renderer', { windowId });\n }\n });\n\n win.on('closed', () => {\n port1.off('message', portHandler);\n port1.close();\n });\n }\n\n win.on('closed', () => {\n windows.delete(windowId);\n if (windowId === 'main') {\n mainWindow = null;\n }\n if (windows.size === 0) {\n electronApp.quit();\n }\n });\n\n logger.info('window created', { windowId });\n return win;\n };\n\n const navigateWindow = async (windowId: string, route: string): Promise<void> => {\n const win = createWindow(windowId);\n await waitForWindowReady(win);\n win.webContents.send('__event:__navigate', { route });\n win.show();\n win.focus();\n };\n\n const dispatchPushEvent = (\n channel: string,\n data: unknown,\n options?: IpcPushOptions,\n ): void => {\n const eventChannel = channel.startsWith('__event:')\n ? channel\n : `__event:${channel}`;\n\n if (options?.windowId) {\n const target = getWindow(options.windowId);\n if (target && !target.isDestroyed()) {\n target.webContents.send(eventChannel, data);\n }\n return;\n }\n\n for (const [windowId, win] of windows.entries()) {\n if (win.isDestroyed()) {\n windows.delete(windowId);\n continue;\n }\n win.webContents.send(eventChannel, data);\n }\n };\n\n setIpcPushSender(dispatchPushEvent);\n\n const broadcast = (channel: string, data: unknown): void => {\n for (const [windowId, win] of windows.entries()) {\n if (win.isDestroyed()) {\n windows.delete(windowId);\n continue;\n }\n win.webContents.send(channel, data);\n }\n };\n\n runtimeContext = {\n ...bootContext,\n container,\n applicationRoot: '',\n getWindow,\n createWindow,\n navigateWindow,\n broadcast,\n setRendererLogCallback: (callback) => {\n getRendererLogDispatcher().setCallback(callback);\n },\n getRendererLogCallback: () => getRendererLogDispatcher().getCallback(),\n getDebugMetadata,\n };\n\n const bootstrap = async () => {\n logger.info('bootstrap starting');\n const applicationRoot = setApplicationRoot(path.join(electronApp.getPath('userData'), 'wood'));\n runtimeContext!.applicationRoot = applicationRoot;\n logger.info('application root configured', { applicationRoot });\n\n if (options.mainBoot) {\n const bootResult = await options.mainBoot(appBootResult, runtimeContext!);\n if (typeof bootResult === 'function') {\n mainBootCleanup = bootResult;\n }\n }\n\n await bootRuntime({\n container,\n ipcMain,\n registerRuntime: options.registerRuntime,\n controllersDir: resolveRuntimePath(options.controllersDir),\n middlewareDir: resolveRuntimePath(options.middlewareDir),\n ...(options.traceMinLevel ? { traceMinLevel: options.traceMinLevel } : {}),\n ...(typeof options.rendererTraceEnabled === 'boolean'\n ? { rendererTraceEnabled: options.rendererTraceEnabled }\n : {}),\n ...(options.rendererTraceMinLevel\n ? { rendererTraceMinLevel: options.rendererTraceMinLevel }\n : {}),\n ...(options.traceTransport === 'messageport' ? { enableRendererTraceBridge: false } : {}),\n onLoad: options.onLoad ?? (async () => {\n throw new Error('Reserved channel \"__load\" is not configured for this app.');\n }),\n onNavigate: async (rawData) => {\n const data = rawData as { windowId?: string; route?: string };\n if (!data.windowId) {\n throw new Error('__navigate requires windowId');\n }\n if (!data.route) {\n throw new Error('__navigate requires route');\n }\n await navigateWindow(data.windowId, data.route);\n return { ok: true };\n },\n onWindow: async (rawData, event) => {\n const data = rawData as { action?: string; windowId?: string };\n const action = data.action ?? '';\n const windowId = data.windowId;\n\n if (action === 'current') {\n const ipcEvent = event as IpcMainInvokeEvent | undefined;\n const senderWindowId = ipcEvent?.sender ? findWindowIdByWebContents(ipcEvent.sender.id) : null;\n if (!senderWindowId) {\n return { ok: false };\n }\n const senderWindowDef = resolveWindowDef(options.windowDefs, senderWindowId);\n return {\n ok: true,\n windowId: senderWindowId,\n defaultRoute: senderWindowDef.defaultRoute,\n };\n }\n\n if (action === 'open') {\n if (!windowId) {\n throw new Error('__window.open requires windowId');\n }\n createWindow(windowId);\n return { ok: true };\n }\n\n const win = windowId ? getWindow(windowId) : mainWindow;\n if (!win) {\n return { ok: false };\n }\n\n switch (action) {\n case 'close':\n win.close();\n return { ok: true };\n case 'focus':\n win.show();\n win.focus();\n return { ok: true };\n case 'minimize':\n win.minimize();\n return { ok: true };\n case 'maximize':\n win.isMaximized() ? win.unmaximize() : win.maximize();\n return { ok: true };\n default:\n return { ok: false };\n }\n },\n onDebug: async (rawData) => {\n const data = rawData as { action?: string } | undefined;\n const action = data?.action ?? '';\n\n if (action === 'current') {\n return getDebugMetadata();\n }\n\n return { ok: false };\n },\n onContextMenu: options.onContextMenu ?? (async (_rawData: unknown, event?: unknown) => {\n const ipcEvent = event as IpcMainInvokeEvent | undefined;\n const senderId = ipcEvent?.sender?.id;\n runtimeLogger.debug('context menu requested', { senderId });\n return { ok: true };\n }),\n resolveRendererTraceContext: (event) => {\n const ipcEvent = event as IpcMainInvokeEvent | undefined;\n const webContentsId = ipcEvent?.sender?.id;\n if (typeof webContentsId !== 'number') {\n return undefined;\n }\n return {\n webContentsId,\n windowId: findWindowIdByWebContents(webContentsId) ?? undefined,\n };\n },\n });\n\n createWindow('main');\n logger.info('bootstrap complete');\n };\n\n void electronApp.whenReady().then(bootstrap).catch((error) => {\n logger.error('bootstrap failed', {\n message: toErrorMessage(error),\n stack: error instanceof Error ? error.stack : undefined,\n });\n });\n\n const destroyWindowsForQuit = (): void => {\n for (const [id, win] of windows) {\n if (!win.isDestroyed()) {\n win.destroy();\n logger.debug('destroyed window on quit', { windowId: id });\n }\n }\n windows.clear();\n };\n\n const runBeforeQuitCleanup = async (): Promise<void> => {\n clearIpcPushSender();\n if (mainBootCleanup) {\n await mainBootCleanup();\n }\n if (options.onBeforeQuit) {\n await options.onBeforeQuit(runtimeContext!);\n }\n };\n\n electronApp.on('before-quit', (event: ElectronEvent) => {\n if (!runtimeContext) {\n return;\n }\n\n if (beforeQuitCleanupComplete) {\n destroyWindowsForQuit();\n return;\n }\n\n event.preventDefault();\n if (beforeQuitCleanupPromise) {\n return;\n }\n\n beforeQuitCleanupPromise = (async () => {\n try {\n await runBeforeQuitCleanup();\n } catch (error) {\n logger.warn('before-quit handler failed', { error: toErrorMessage(error) });\n } finally {\n beforeQuitCleanupComplete = true;\n beforeQuitCleanupPromise = null;\n }\n\n destroyWindowsForQuit();\n electronApp.quit();\n })();\n });\n\n electronApp.on('window-all-closed', () => {\n electronApp.quit();\n });\n\n electronApp.on('activate', () => {\n if (BrowserWindow.getAllWindows().length === 0) {\n createWindow('main');\n }\n });\n })().catch((error) => {\n logger.error('startup failed before ready', {\n message: toErrorMessage(error),\n stack: error instanceof Error ? error.stack : undefined,\n });\n });\n}\n"],"mappings":"AAAA,OAAO,UAAU;AACjB;AAAA,EACE,OAAO;AAAA,EACP;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;AAQP,SAAS,iBAAiB;AAC1B,SAAS,wBAAwB;AACjC,SAAS,oBAAoB;AAC7B,SAAS,WAAW,mBAAmB;AACvC,SAAS,oCAAqD;AAC9D,SAAS,0BAA0B;AAEnC;AAAA,EACE;AAAA,OAEK;AACP,SAAS,KAAK,cAAc;AAC5B,SAAS,kBAAkB,0BAA+C;AAwG1E,MAAM,qCAAqC;AAEpC,SAAS,sCAAsC,MAAyB,QAAQ,KAIrF;AACA,QAAM,gBAAgB,IAAI,cAAc;AACxC,MAAI,CAAC,eAAe;AAClB,WAAO;AAAA,MACL,SAAS;AAAA,MACT,MAAM;AAAA,IACR;AAAA,EACF;AAEA,QAAM,UAAU,IAAI;AACpB,QAAM,aAAa,UAAU,OAAO,SAAS,SAAS,EAAE,IAAI;AAC5D,QAAM,OAAO,OAAO,SAAS,UAAU,KAAK,aAAa,IACrD,aACA;AAEJ,SAAO;AAAA,IACL,SAAS;AAAA,IACT,MAAM;AAAA,IACN;AAAA,EACF;AACF;AAEA,SAAS,iBACP,YACA,WAAW,QACO;AAClB,QAAM,MAAM,WAAW,QAAQ;AAC/B,MAAI,CAAC,KAAK;AACR,UAAM,IAAI,MAAM,WAAW,QAAQ,yCAAyC;AAAA,EAC9E;AACA,SAAO;AACT;AAEA,SAAS,mBAAmB,wBAAwC;AAClE,MAAI,KAAK,WAAW,sBAAsB,GAAG;AAC3C,WAAO;AAAA,EACT;AACA,SAAO,KAAK,KAAK,YAAY,WAAW,GAAG,sBAAsB;AACnE;AAEA,SAAS,eAAe,OAAwB;AAC9C,SAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAC9D;AAEO,SAAS,cAAc,SAAqC;AACjE,QAAM,SAAS,UAAU,WAAW,EAAE,MAAM,WAAW;AACvD,QAAM,gBAAgB,UAAU,WAAW,EAAE,MAAM,SAAS;AAC5D,QAAM,cAAc,sCAAsC;AAC1D,QAAM,cAAc,IAAI,iBAAiB;AACzC,QAAM,UAAU,oBAAI,IAAmC;AACvD,MAAI,aAA2C;AAC/C,MAAI,4BAA4B;AAChC,MAAI,2BAAiD;AACrD,MAAI,iBAAgD;AACpD,MAAI;AAEJ,aAAW,UAAU,CAAC,QAAQ,QAAQ,QAAQ,MAAM,GAAG;AACrD,WAAO,GAAG,SAAS,CAAC,UAAiC;AACnD,UAAI,MAAM,SAAS,SAAS;AAC1B;AAAA,MACF;AACA,YAAM;AAAA,IACR,CAAC;AAAA,EACH;AAEA,MAAI,YAAY,WAAW,YAAY,MAAM;AAC3C,gBAAY,YAAY,aAAa,yBAAyB,OAAO,YAAY,IAAI,CAAC;AACtF,gBAAY,YAAY,aAAa,4BAA4B,WAAW;AAC5E,WAAO,KAAK,qCAAqC;AAAA,MAC/C,MAAM,YAAY;AAAA,MAClB,MAAM,YAAY;AAAA,IACpB,CAAC;AAAA,EACH;AAEA,QAAM,cAAmC;AAAA,IACvC,UAAU;AAAA,MACR,KAAK;AAAA,MACL;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,IACA;AAAA,EACF;AAEA,QAAM,YAAY;AAChB,UAAM,gBAAgB,QAAQ,UAC1B,MAAM,QAAQ,QAAQ,WAAW,IACjC;AAEJ,UAAM,gBAAiB,iBAAiB,CAAC;AACzC,UAAM,QAAQ,cAAc,SAAS,QAAQ,SAAS,QAAQ,IAAI;AAClE,UAAM,qBAAqB,cAAc,sBAAsB,QAAQ;AACvE,UAAM,oBAAoB,MAAM,QAAQ,cAAc,2BAA2B,IAC7E,cAAc,8BACd,CAAC;AAEL,QAAI,kBAAkB,SAAS,GAAG;AAChC,eAAS,4BAA4B,iBAAiB;AACtD,aAAO,KAAK,iCAAiC;AAAA,QAC3C,OAAO,kBAAkB;AAAA,QACzB,SAAS,kBAAkB,IAAI,CAAC,UAAU,MAAM,MAAM;AAAA,MACxD,CAAC;AAAA,IACH;AAEA,UAAM,SAAS,QAAQ,UAAU;AACjC,UAAM,cAAc,KAAK,KAAK,YAAY,WAAW,GAAG,QAAQ,WAAW,UAAU;AACrF,UAAM,eAAe,KAAK,KAAK,YAAY,WAAW,GAAG,QAAQ,YAAY,YAAY;AAEzF,UAAM,YAAY,aAAa;AAAA,MAC7B;AAAA,MACA,GAAI,qBAAqB,EAAE,WAAW,mBAAmB,IAAI,CAAC;AAAA,IAChE,CAAC;AAED,UAAM,wBAAwB;AAQ9B,QAAI,OAAO,sBAAsB,qBAAqB,YAAY;AAChE,4BAAsB,iBAAiB,KAAK,MAAM,OAAO,CAAC;AAAA,IAC5D;AAEA,UAAM,YAAY,CAAC,aAAmD;AACpE,YAAM,WAAW,QAAQ,IAAI,QAAQ;AACrC,UAAI,CAAC,UAAU;AACb,eAAO;AAAA,MACT;AACA,UAAI,SAAS,YAAY,GAAG;AAC1B,gBAAQ,OAAO,QAAQ;AACvB,eAAO;AAAA,MACT;AACA,aAAO;AAAA,IACT;AAEA,UAAM,4BAA4B,CAAC,kBAAyC;AAC1E,iBAAW,CAAC,UAAU,GAAG,KAAK,QAAQ,QAAQ,GAAG;AAC/C,YAAI,IAAI,YAAY,GAAG;AACrB,kBAAQ,OAAO,QAAQ;AACvB;AAAA,QACF;AACA,YAAI,IAAI,YAAY,OAAO,eAAe;AACxC,iBAAO;AAAA,QACT;AAAA,MACF;AACA,aAAO;AAAA,IACT;AAEA,UAAM,qBAAqB,OAAO,QAA8C;AAC9E,YAAM,cAAc,IAAI;AAGxB,YAAM,YAAY,OAAO,YAAY,uBAAuB,aACxD,YAAY,mBAAmB,IAC/B,YAAY,UAAU;AAC1B,UAAI,CAAC,WAAW;AACd;AAAA,MACF;AAEA,YAAM,IAAI,QAAc,CAAC,YAAY;AACnC,oBAAY,KAAK,mBAAmB,MAAM,QAAQ,CAAC;AAAA,MACrD,CAAC;AAAA,IACH;AAEA,UAAM,mBAAmB,MAAyB;AAChD,YAAM,eAA0C,CAAC;AAEjD,iBAAW,CAAC,UAAU,GAAG,KAAK,QAAQ,QAAQ,GAAG;AAC/C,YAAI,IAAI,YAAY,GAAG;AACrB,kBAAQ,OAAO,QAAQ;AACvB;AAAA,QACF;AAEA,qBAAa,KAAK;AAAA,UAChB;AAAA,UACA,OAAO,IAAI,SAAS;AAAA,UACpB,eAAe,IAAI,YAAY;AAAA,UAC/B,KAAK,IAAI,YAAY,OAAO;AAAA,UAC5B,SAAS,IAAI,UAAU;AAAA,QACzB,CAAC;AAAA,MACH;AAEA,aAAO;AAAA,QACL,IAAI;AAAA,QACJ,SAAS,YAAY;AAAA,QACrB,MAAM,YAAY;AAAA,QAClB,GAAI,YAAY,OAAO,EAAE,MAAM,YAAY,KAAK,IAAI,CAAC;AAAA,QACrD,SAAS;AAAA,MACX;AAAA,IACF;AAEA,UAAM,eAAe,CAAC,WAAW,WAAkC;AACjE,YAAM,WAAW,UAAU,QAAQ;AACnC,UAAI,UAAU;AACZ,iBAAS,KAAK;AACd,iBAAS,MAAM;AACf,eAAO;AAAA,MACT;AAEA,YAAM,YAAY,iBAAiB,QAAQ,YAAY,QAAQ;AAC/D,YAAM,cAAc,UAAU,QAAQ;AACtC,YAAM,eAAe,UAAU,SAAS,UAAU,UAAU,MAAM,IAAI;AAEtE,kBAAY,UAAU,MAAM;AAC5B,YAAM,cAAc,UAAU,iBAAiB,YAAY,UAAU,QAAQ,IAAI;AAEjF,YAAM,gBAAiD;AAAA,QACrD,OAAO,aAAa,SAAS,UAAU;AAAA,QACvC,QAAQ,aAAa,UAAU,UAAU;AAAA,QACzC,GAAI,cAAc,EAAE,GAAG,YAAY,GAAG,GAAG,YAAY,EAAE,IAAI,CAAC;AAAA,QAC5D,GAAI,UAAU,YAAY,OAAO,EAAE,UAAU,UAAU,SAAS,IAAI,CAAC;AAAA,QACrE,GAAI,UAAU,aAAa,OAAO,EAAE,WAAW,UAAU,UAAU,IAAI,CAAC;AAAA,QACxE,GAAI,UAAU,YAAY,OAAO,EAAE,UAAU,UAAU,SAAS,IAAI,CAAC;AAAA,QACrE,GAAI,UAAU,aAAa,OAAO,EAAE,WAAW,UAAU,UAAU,IAAI,CAAC;AAAA,QACxE,GAAI,OAAO,UAAU,UAAU,YAAY,EAAE,OAAO,UAAU,MAAM,IAAI,CAAC;AAAA,QACzE,GAAI,eAAe,EAAE,QAAQ,aAAa,IAAI,CAAC;AAAA,QAC/C,OAAO,UAAU;AAAA,QACjB,OAAO,UAAU,SAAS;AAAA,QAC1B,aAAa,UAAU,eAAe;AAAA,QACtC,WAAW,UAAU,aAAa;AAAA,QAClC,aAAa,UAAU,eAAe;AAAA,QACtC,GAAI,OAAO,UAAU,oBAAoB,WAAW,EAAE,iBAAiB,UAAU,gBAAgB,IAAI,CAAC;AAAA,QACtG,GAAI,QAAQ,aAAa,YAAY,OAAO,UAAU,aAAa,WAC/D;AAAA,UACE,UAAU,UAAU;AAAA,UACpB,mBAAmB;AAAA,QACrB,IACA,CAAC;AAAA,QACL,GAAI,QAAQ,aAAa,WAAW,OAAO,UAAU,uBAAuB,WACxE;AAAA,UACE,oBAAoB,UAAU;AAAA,QAChC,IACA,CAAC;AAAA,QACL,GAAI,OAAO,UAAU,qBAAqB,YAAY,EAAE,kBAAkB,UAAU,iBAAiB,IAAI,CAAC;AAAA,QAC1G,MAAM,cAAc,QAAQ;AAAA,QAC5B,gBAAgB;AAAA,UACd,SAAS;AAAA,UACT,kBAAkB;AAAA,UAClB,iBAAiB;AAAA,QACnB;AAAA,MACF;AAEA,YAAM,MAAM,IAAI,cAAc,aAAa;AAC3C,cAAQ,IAAI,UAAU,GAAG;AACzB,UAAI,aAAa,QAAQ;AACvB,qBAAa;AAAA,MACf;AAEA,UAAI,aAAa,aAAa;AAC5B,YAAI,SAAS;AAAA,MACf,WAAW,aAAa,cAAc;AACpC,YAAI,cAAc,IAAI;AAAA,MACxB;AAEA,UAAI,eAAe,aAAa;AAC9B,YAAI,KAAK;AAAA,MACX;AAEA,UAAI,UAAU,gBAAgB;AAC5B,cAAM,sBAAsB,MAAM;AAChC,cAAI,CAAC,IAAI,YAAY,KAAK,CAAC,IAAI,aAAa,GAAG;AAC7C,kBAAM,OAAO,IAAI,UAAU;AAC3B,wBAAY,sBAAsB,UAAU;AAAA,cAC1C,GAAG;AAAA,cACH,aAAa;AAAA,cACb,cAAc;AAAA,YAChB,CAAC;AAAA,UACH;AAAA,QACF;AACA,YAAI,GAAG,QAAQ,mBAAmB;AAClC,YAAI,GAAG,UAAU,mBAAmB;AACpC,YAAI,GAAG,SAAS,MAAM;AACpB,gBAAM,OAAO,IAAI,UAAU;AAC3B,sBAAY,eAAe,UAAU;AAAA,YACnC,GAAG;AAAA,YACH,aAAa,IAAI,YAAY;AAAA,YAC7B,cAAc,IAAI,aAAa;AAAA,UACjC,CAAC;AAAA,QACH,CAAC;AAAA,MACH;AAEA,UAAI,YAAY,qBAAqB,CAAC,EAAE,IAAI,MAAM;AAChD,YAAI,IAAI,WAAW,SAAS,KAAK,IAAI,WAAW,UAAU,GAAG;AAC3D,eAAK,MAAM,aAAa,GAAG;AAAA,QAC7B;AACA,eAAO,EAAE,QAAQ,OAAO;AAAA,MAC1B,CAAC;AAED,UAAI,YAAY,GAAG,iBAAiB,CAAC,OAAO,QAAQ;AAClD,YAAI,QAAQ,IAAI,yBAAyB,IAAI,WAAW,QAAQ,IAAI,qBAAqB,GAAG;AAC1F;AAAA,QACF;AACA,YAAI,IAAI,WAAW,SAAS,KAAK,IAAI,WAAW,UAAU,GAAG;AAC3D,gBAAM,eAAe;AACrB,eAAK,MAAM,aAAa,GAAG;AAAA,QAC7B;AAAA,MACF,CAAC;AAED,YAAM,iBAAiB,UAAU,WAAW,EAAE,MAAM,YAAY,QAAQ,EAAE;AAC1E,YAAM,WAAgE;AAAA,QACpE,GAAG;AAAA,QACH,GAAG;AAAA,QACH,GAAG;AAAA,QACH,GAAG;AAAA,MACL;AAEA,UAAI,YAAY,GAAG,mBAAmB,CAAC,QAAQ,OAAO,SAAS,MAAM,aAAa;AAChF,cAAM,SAAS,SAAS,KAAK,KAAK;AAClC,uBAAe,MAAM,EAAE,SAAS,EAAE,QAAQ,UAAU,MAAM,SAAS,CAAC;AAAA,MACtE,CAAC;AAED,UAAI,QAAQ,IAAI,uBAAuB;AACrC,aAAK,IAAI,QAAQ,QAAQ,IAAI,qBAAqB;AAAA,MACpD,OAAO;AACL,aAAK,IAAI,SAAS,YAAY;AAAA,MAChC;AAEA,UAAI,QAAQ,mBAAmB,iBAAiB,QAAQ,yBAAyB,MAAM;AACrF,cAAM,EAAE,OAAO,MAAM,IAAI,IAAI,mBAAmB;AAEhD,cAAM,cAAc,CAAC,UAAiC;AACpD,uCAA6B,MAAM,MAAM;AAAA,YACvC;AAAA,YACA,eAAe,IAAI,YAAY;AAAA,UACjC,CAAC;AAAA,QACH;AACA,cAAM,GAAG,WAAW,WAAW;AAC/B,cAAM,MAAM;AAEZ,YAAI,YAAY,KAAK,mBAAmB,MAAM;AAC5C,cAAI,CAAC,IAAI,YAAY,GAAG;AACtB,gBAAI,YAAY,YAAY,gBAAgB,MAAM,CAAC,KAAK,CAAC;AACzD,mBAAO,KAAK,sCAAsC,EAAE,SAAS,CAAC;AAAA,UAChE;AAAA,QACF,CAAC;AAED,YAAI,GAAG,UAAU,MAAM;AACrB,gBAAM,IAAI,WAAW,WAAW;AAChC,gBAAM,MAAM;AAAA,QACd,CAAC;AAAA,MACH;AAEA,UAAI,GAAG,UAAU,MAAM;AACrB,gBAAQ,OAAO,QAAQ;AACvB,YAAI,aAAa,QAAQ;AACvB,uBAAa;AAAA,QACf;AACA,YAAI,QAAQ,SAAS,GAAG;AACtB,sBAAY,KAAK;AAAA,QACnB;AAAA,MACF,CAAC;AAED,aAAO,KAAK,kBAAkB,EAAE,SAAS,CAAC;AAC1C,aAAO;AAAA,IACT;AAEA,UAAM,iBAAiB,OAAO,UAAkB,UAAiC;AAC/E,YAAM,MAAM,aAAa,QAAQ;AACjC,YAAM,mBAAmB,GAAG;AAC5B,UAAI,YAAY,KAAK,sBAAsB,EAAE,MAAM,CAAC;AACpD,UAAI,KAAK;AACT,UAAI,MAAM;AAAA,IACZ;AAEA,UAAM,oBAAoB,CACxB,SACA,MACAA,aACS;AACT,YAAM,eAAe,QAAQ,WAAW,UAAU,IAC9C,UACA,WAAW,OAAO;AAEtB,UAAIA,UAAS,UAAU;AACrB,cAAM,SAAS,UAAUA,SAAQ,QAAQ;AACzC,YAAI,UAAU,CAAC,OAAO,YAAY,GAAG;AACnC,iBAAO,YAAY,KAAK,cAAc,IAAI;AAAA,QAC5C;AACA;AAAA,MACF;AAEA,iBAAW,CAAC,UAAU,GAAG,KAAK,QAAQ,QAAQ,GAAG;AAC/C,YAAI,IAAI,YAAY,GAAG;AACrB,kBAAQ,OAAO,QAAQ;AACvB;AAAA,QACF;AACA,YAAI,YAAY,KAAK,cAAc,IAAI;AAAA,MACzC;AAAA,IACF;AAEA,qBAAiB,iBAAiB;AAElC,UAAM,YAAY,CAAC,SAAiB,SAAwB;AAC1D,iBAAW,CAAC,UAAU,GAAG,KAAK,QAAQ,QAAQ,GAAG;AAC/C,YAAI,IAAI,YAAY,GAAG;AACrB,kBAAQ,OAAO,QAAQ;AACvB;AAAA,QACF;AACA,YAAI,YAAY,KAAK,SAAS,IAAI;AAAA,MACpC;AAAA,IACF;AAEA,qBAAiB;AAAA,MACf,GAAG;AAAA,MACH;AAAA,MACA,iBAAiB;AAAA,MACjB;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,wBAAwB,CAAC,aAAa;AACpC,iCAAyB,EAAE,YAAY,QAAQ;AAAA,MACjD;AAAA,MACA,wBAAwB,MAAM,yBAAyB,EAAE,YAAY;AAAA,MACrE;AAAA,IACF;AAEA,UAAM,YAAY,YAAY;AAC5B,aAAO,KAAK,oBAAoB;AAChC,YAAM,kBAAkB,mBAAmB,KAAK,KAAK,YAAY,QAAQ,UAAU,GAAG,MAAM,CAAC;AAC7F,qBAAgB,kBAAkB;AAClC,aAAO,KAAK,+BAA+B,EAAE,gBAAgB,CAAC;AAE9D,UAAI,QAAQ,UAAU;AACpB,cAAM,aAAa,MAAM,QAAQ,SAAS,eAAe,cAAe;AACxE,YAAI,OAAO,eAAe,YAAY;AACpC,4BAAkB;AAAA,QACpB;AAAA,MACF;AAEA,YAAM,YAAY;AAAA,QAChB;AAAA,QACA;AAAA,QACA,iBAAiB,QAAQ;AAAA,QACzB,gBAAgB,mBAAmB,QAAQ,cAAc;AAAA,QACzD,eAAe,mBAAmB,QAAQ,aAAa;AAAA,QACvD,GAAI,QAAQ,gBAAgB,EAAE,eAAe,QAAQ,cAAc,IAAI,CAAC;AAAA,QACxE,GAAI,OAAO,QAAQ,yBAAyB,YACxC,EAAE,sBAAsB,QAAQ,qBAAqB,IACrD,CAAC;AAAA,QACL,GAAI,QAAQ,wBACR,EAAE,uBAAuB,QAAQ,sBAAsB,IACvD,CAAC;AAAA,QACL,GAAI,QAAQ,mBAAmB,gBAAgB,EAAE,2BAA2B,MAAM,IAAI,CAAC;AAAA,QACvF,QAAQ,QAAQ,WAAW,YAAY;AACrC,gBAAM,IAAI,MAAM,2DAA2D;AAAA,QAC7E;AAAA,QACA,YAAY,OAAO,YAAY;AAC7B,gBAAM,OAAO;AACb,cAAI,CAAC,KAAK,UAAU;AAClB,kBAAM,IAAI,MAAM,8BAA8B;AAAA,UAChD;AACA,cAAI,CAAC,KAAK,OAAO;AACf,kBAAM,IAAI,MAAM,2BAA2B;AAAA,UAC7C;AACA,gBAAM,eAAe,KAAK,UAAU,KAAK,KAAK;AAC9C,iBAAO,EAAE,IAAI,KAAK;AAAA,QACpB;AAAA,QACA,UAAU,OAAO,SAAS,UAAU;AAClC,gBAAM,OAAO;AACb,gBAAM,SAAS,KAAK,UAAU;AAC9B,gBAAM,WAAW,KAAK;AAEtB,cAAI,WAAW,WAAW;AACxB,kBAAM,WAAW;AACjB,kBAAM,iBAAiB,UAAU,SAAS,0BAA0B,SAAS,OAAO,EAAE,IAAI;AAC1F,gBAAI,CAAC,gBAAgB;AACnB,qBAAO,EAAE,IAAI,MAAM;AAAA,YACrB;AACA,kBAAM,kBAAkB,iBAAiB,QAAQ,YAAY,cAAc;AAC3E,mBAAO;AAAA,cACL,IAAI;AAAA,cACJ,UAAU;AAAA,cACV,cAAc,gBAAgB;AAAA,YAChC;AAAA,UACF;AAEA,cAAI,WAAW,QAAQ;AACrB,gBAAI,CAAC,UAAU;AACb,oBAAM,IAAI,MAAM,iCAAiC;AAAA,YACnD;AACA,yBAAa,QAAQ;AACrB,mBAAO,EAAE,IAAI,KAAK;AAAA,UACpB;AAEA,gBAAM,MAAM,WAAW,UAAU,QAAQ,IAAI;AAC7C,cAAI,CAAC,KAAK;AACR,mBAAO,EAAE,IAAI,MAAM;AAAA,UACrB;AAEA,kBAAQ,QAAQ;AAAA,YACd,KAAK;AACH,kBAAI,MAAM;AACV,qBAAO,EAAE,IAAI,KAAK;AAAA,YACpB,KAAK;AACH,kBAAI,KAAK;AACT,kBAAI,MAAM;AACV,qBAAO,EAAE,IAAI,KAAK;AAAA,YACpB,KAAK;AACH,kBAAI,SAAS;AACb,qBAAO,EAAE,IAAI,KAAK;AAAA,YACpB,KAAK;AACH,kBAAI,YAAY,IAAI,IAAI,WAAW,IAAI,IAAI,SAAS;AACpD,qBAAO,EAAE,IAAI,KAAK;AAAA,YACpB;AACE,qBAAO,EAAE,IAAI,MAAM;AAAA,UACvB;AAAA,QACF;AAAA,QACA,SAAS,OAAO,YAAY;AAC1B,gBAAM,OAAO;AACb,gBAAM,SAAS,MAAM,UAAU;AAE/B,cAAI,WAAW,WAAW;AACxB,mBAAO,iBAAiB;AAAA,UAC1B;AAEA,iBAAO,EAAE,IAAI,MAAM;AAAA,QACrB;AAAA,QACA,eAAe,QAAQ,kBAAkB,OAAO,UAAmB,UAAoB;AACrF,gBAAM,WAAW;AACjB,gBAAM,WAAW,UAAU,QAAQ;AACnC,wBAAc,MAAM,0BAA0B,EAAE,SAAS,CAAC;AAC1D,iBAAO,EAAE,IAAI,KAAK;AAAA,QACpB;AAAA,QACA,6BAA6B,CAAC,UAAU;AACtC,gBAAM,WAAW;AACjB,gBAAM,gBAAgB,UAAU,QAAQ;AACxC,cAAI,OAAO,kBAAkB,UAAU;AACrC,mBAAO;AAAA,UACT;AACA,iBAAO;AAAA,YACL;AAAA,YACA,UAAU,0BAA0B,aAAa,KAAK;AAAA,UACxD;AAAA,QACF;AAAA,MACF,CAAC;AAED,mBAAa,MAAM;AACnB,aAAO,KAAK,oBAAoB;AAAA,IAClC;AAEA,SAAK,YAAY,UAAU,EAAE,KAAK,SAAS,EAAE,MAAM,CAAC,UAAU;AAC5D,aAAO,MAAM,oBAAoB;AAAA,QAC/B,SAAS,eAAe,KAAK;AAAA,QAC7B,OAAO,iBAAiB,QAAQ,MAAM,QAAQ;AAAA,MAChD,CAAC;AAAA,IACH,CAAC;AAED,UAAM,wBAAwB,MAAY;AACxC,iBAAW,CAAC,IAAI,GAAG,KAAK,SAAS;AAC/B,YAAI,CAAC,IAAI,YAAY,GAAG;AACtB,cAAI,QAAQ;AACZ,iBAAO,MAAM,4BAA4B,EAAE,UAAU,GAAG,CAAC;AAAA,QAC3D;AAAA,MACF;AACA,cAAQ,MAAM;AAAA,IAChB;AAEA,UAAM,uBAAuB,YAA2B;AACtD,yBAAmB;AACnB,UAAI,iBAAiB;AACnB,cAAM,gBAAgB;AAAA,MACxB;AACA,UAAI,QAAQ,cAAc;AACxB,cAAM,QAAQ,aAAa,cAAe;AAAA,MAC5C;AAAA,IACF;AAEA,gBAAY,GAAG,eAAe,CAAC,UAAyB;AACtD,UAAI,CAAC,gBAAgB;AACnB;AAAA,MACF;AAEA,UAAI,2BAA2B;AAC7B,8BAAsB;AACtB;AAAA,MACF;AAEA,YAAM,eAAe;AACrB,UAAI,0BAA0B;AAC5B;AAAA,MACF;AAEA,kCAA4B,YAAY;AACtC,YAAI;AACF,gBAAM,qBAAqB;AAAA,QAC7B,SAAS,OAAO;AACd,iBAAO,KAAK,8BAA8B,EAAE,OAAO,eAAe,KAAK,EAAE,CAAC;AAAA,QAC5E,UAAE;AACA,sCAA4B;AAC5B,qCAA2B;AAAA,QAC7B;AAEA,8BAAsB;AACtB,oBAAY,KAAK;AAAA,MACnB,GAAG;AAAA,IACL,CAAC;AAED,gBAAY,GAAG,qBAAqB,MAAM;AACxC,kBAAY,KAAK;AAAA,IACnB,CAAC;AAED,gBAAY,GAAG,YAAY,MAAM;AAC/B,UAAI,cAAc,cAAc,EAAE,WAAW,GAAG;AAC9C,qBAAa,MAAM;AAAA,MACrB;AAAA,IACF,CAAC;AAAA,EACH,GAAG,EAAE,MAAM,CAAC,UAAU;AACpB,WAAO,MAAM,+BAA+B;AAAA,MAC1C,SAAS,eAAe,KAAK;AAAA,MAC7B,OAAO,iBAAiB,QAAQ,MAAM,QAAQ;AAAA,IAChD,CAAC;AAAA,EACH,CAAC;AACH;","names":["options"]}
|
|
1
|
+
{"version":3,"sources":["../../src/main/index.ts"],"sourcesContent":["import path from 'path';\nimport {\n app as electronApp,\n BrowserWindow,\n ipcMain,\n MessageChannelMain,\n Menu,\n protocol,\n net,\n shell,\n screen,\n} from 'electron';\nimport type {\n BrowserWindowConstructorOptions,\n BrowserWindow as ElectronBrowserWindow,\n Event as ElectronEvent,\n IpcMainInvokeEvent,\n Privileges,\n RenderProcessGoneDetails,\n} from 'electron';\nimport { getLogger } from '@noego/logger';\nimport { WindowStateStore } from '../window/window_state_store.js';\nimport { getContainer } from '../runtime/get_container.js';\nimport { runtime as bootRuntime } from '../runtime/runtime.js';\nimport { dispatchRendererTracePayload, type TraceLevel } from '../tracing/index.js';\nimport { setApplicationRoot } from '../runtime/application_root.js';\nimport type { RegisterRuntimeRouter } from '../runtime/runtime.js';\nimport {\n getRendererLogDispatcher,\n type RendererLogCallback,\n} from '../runtime/renderer_log_dispatcher.js';\nimport { Ipc, getIpc } from '../ipc/index.js';\nimport { setIpcPushSender, clearIpcPushSender, type IpcPushOptions } from '../ipc/shared.js';\n\ntype CleanupHandler = () => void | Promise<void>;\n\nexport type RendererHealthState =\n | 'ready'\n | 'loading'\n | 'unresponsive'\n | 'gone'\n | 'destroyed';\n\nexport type WoodWindowConfig = {\n title: string;\n width: number;\n height: number;\n defaultRoute?: string;\n frame?: boolean;\n transparent?: boolean;\n resizable?: boolean;\n alwaysOnTop?: boolean;\n minWidth?: number;\n minHeight?: number;\n maxWidth?: number;\n maxHeight?: number;\n show?: boolean;\n parent?: string;\n modal?: boolean;\n vibrancy?: string;\n backgroundMaterial?: string;\n backgroundColor?: string;\n rememberBounds?: boolean;\n contextMenu?: 'native' | 'custom';\n acceptFirstMouse?: boolean;\n nativeQuitFallback?: boolean;\n titleBarStyle?: 'default' | 'hidden' | 'hiddenInset' | 'customButtonsOnHover';\n trafficLightPosition?: { x: number; y: number };\n titleBarOverlay?: boolean | { color?: string; symbolColor?: string; height?: number };\n};\n\nexport type PrivilegedSchemeRegistration = {\n scheme: string;\n privileges: Privileges;\n};\n\nexport interface WoodMainAppBootResult {\n scope?: string;\n configureContainer?: (container: any) => void;\n registerSchemesAsPrivileged?: PrivilegedSchemeRegistration[];\n}\n\nexport interface WoodMainBootContext {\n electron: {\n app: typeof electronApp;\n BrowserWindow: typeof BrowserWindow;\n ipcMain: typeof ipcMain;\n protocol: typeof protocol;\n net: typeof net;\n shell: typeof shell;\n screen: typeof screen;\n Menu: typeof Menu;\n };\n logger: ReturnType<typeof getLogger>;\n}\n\nexport interface WoodMainRuntimeContext extends WoodMainBootContext {\n container: any;\n applicationRoot: string;\n getWindow: (windowId: string) => ElectronBrowserWindow | null;\n createWindow: (windowId?: string) => ElectronBrowserWindow;\n navigateWindow: (windowId: string, route: string) => Promise<void>;\n broadcast: (channel: string, data: unknown) => void;\n getRendererHealthState: (windowId: string) => RendererHealthState | null;\n setRendererLogCallback: (callback: RendererLogCallback | null) => void;\n getRendererLogCallback: () => RendererLogCallback | null;\n getDebugMetadata: () => WoodDebugMetadata;\n}\n\nexport interface WoodRendererHealthEvent {\n windowId: string;\n state: RendererHealthState;\n previousState: RendererHealthState | null;\n webContentsId?: number;\n reason?: string;\n exitCode?: number;\n}\n\nexport type WoodWindowLifecycleContext = WoodMainRuntimeContext;\n\nexport interface StartWoodMainOptions {\n registerRuntime: (router: RegisterRuntimeRouter) => void;\n windowDefs: Record<string, WoodWindowConfig>;\n controllersDir: string;\n middlewareDir: string;\n outDir?: string;\n scope?: string;\n configureContainer?: (container: any) => void;\n appBoot?: (\n context: WoodMainBootContext,\n ) => void | WoodMainAppBootResult | Promise<void | WoodMainAppBootResult>;\n mainBoot?: (\n appBootResult: unknown,\n context: WoodMainRuntimeContext,\n ) => void | CleanupHandler | Promise<void | CleanupHandler>;\n onBeforeQuit?: (context: WoodMainRuntimeContext) => void | Promise<void>;\n onWindowCreated?: (\n windowId: string,\n win: ElectronBrowserWindow,\n context: WoodMainRuntimeContext,\n ) => void | Promise<void>;\n onRendererHealthChanged?: (\n event: WoodRendererHealthEvent,\n context: WoodMainRuntimeContext,\n ) => void | Promise<void>;\n onLoad?: (data: unknown, event?: unknown) => Promise<unknown>;\n onContextMenu?: (data: unknown, event?: unknown) => Promise<unknown>;\n traceMinLevel?: TraceLevel;\n rendererTraceEnabled?: boolean;\n rendererTraceMinLevel?: TraceLevel;\n traceTransport?: 'ipc' | 'messageport';\n}\n\nexport interface WoodDebugWindowMetadata {\n windowId: string;\n title: string;\n webContentsId: number;\n url: string;\n focused: boolean;\n rendererHealth?: RendererHealthState;\n}\n\nexport interface WoodDebugMetadata {\n ok: boolean;\n enabled: boolean;\n mode: 'development' | 'production';\n port?: number;\n windows: WoodDebugWindowMetadata[];\n}\n\nconst DEFAULT_WOOD_REMOTE_DEBUGGING_PORT = 9333;\n\nexport function resolveWoodDebugMetadataConfiguration(env: NodeJS.ProcessEnv = process.env): {\n enabled: boolean;\n mode: 'development' | 'production';\n port?: number;\n} {\n const isDevelopment = env.WOOD_MODE === 'development';\n if (!isDevelopment) {\n return {\n enabled: false,\n mode: 'production',\n };\n }\n\n const rawPort = env.WOOD_REMOTE_DEBUGGING_PORT;\n const parsedPort = rawPort ? Number.parseInt(rawPort, 10) : DEFAULT_WOOD_REMOTE_DEBUGGING_PORT;\n const port = Number.isFinite(parsedPort) && parsedPort > 0\n ? parsedPort\n : DEFAULT_WOOD_REMOTE_DEBUGGING_PORT;\n\n return {\n enabled: true,\n mode: 'development',\n port,\n };\n}\n\nfunction resolveWindowDef(\n windowDefs: Record<string, WoodWindowConfig>,\n windowId = 'main',\n): WoodWindowConfig {\n const def = windowDefs[windowId];\n if (!def) {\n throw new Error(`Window \"${windowId}\" not defined in generated window defs.`);\n }\n return def;\n}\n\nfunction resolveRuntimePath(relativeOrAbsolutePath: string): string {\n if (path.isAbsolute(relativeOrAbsolutePath)) {\n return relativeOrAbsolutePath;\n }\n return path.join(electronApp.getAppPath(), relativeOrAbsolutePath);\n}\n\nfunction toErrorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\nexport function startWoodMain(options: StartWoodMainOptions): void {\n const logger = getLogger('wood:main').named('bootstrap');\n const runtimeLogger = getLogger('wood:main').named('runtime');\n const debugConfig = resolveWoodDebugMetadataConfiguration();\n const windowState = new WindowStateStore();\n const windows = new Map<string, ElectronBrowserWindow>();\n const rendererHealth = new Map<string, RendererHealthState>();\n let mainWindow: ElectronBrowserWindow | null = null;\n let beforeQuitCleanupComplete = false;\n let beforeQuitCleanupPromise: Promise<void> | null = null;\n let runtimeContext: WoodMainRuntimeContext | null = null;\n let mainBootCleanup: CleanupHandler | undefined;\n let nativeQuitFallbackInstalled = false;\n\n for (const stream of [process.stdout, process.stderr]) {\n stream.on('error', (error: NodeJS.ErrnoException) => {\n if (error.code === 'EPIPE') {\n return;\n }\n throw error;\n });\n }\n\n if (debugConfig.enabled && debugConfig.port) {\n electronApp.commandLine.appendSwitch('remote-debugging-port', String(debugConfig.port));\n electronApp.commandLine.appendSwitch('remote-debugging-address', '127.0.0.1');\n logger.info('devtools remote debugging enabled', {\n port: debugConfig.port,\n mode: debugConfig.mode,\n });\n }\n\n const bootContext: WoodMainBootContext = {\n electron: {\n app: electronApp,\n BrowserWindow,\n ipcMain,\n protocol,\n net,\n shell,\n screen,\n Menu,\n },\n logger,\n };\n\n void (async () => {\n const appBootResult = options.appBoot\n ? await options.appBoot(bootContext)\n : undefined;\n\n const bootOverrides = (appBootResult ?? {}) as WoodMainAppBootResult;\n const scope = bootOverrides.scope ?? options.scope ?? process.cwd();\n const configureContainer = bootOverrides.configureContainer ?? options.configureContainer;\n const privilegedSchemes = Array.isArray(bootOverrides.registerSchemesAsPrivileged)\n ? bootOverrides.registerSchemesAsPrivileged\n : [];\n\n if (privilegedSchemes.length > 0) {\n protocol.registerSchemesAsPrivileged(privilegedSchemes);\n logger.info('registered privileged schemes', {\n count: privilegedSchemes.length,\n schemes: privilegedSchemes.map((entry) => entry.scheme),\n });\n }\n\n const outDir = options.outDir ?? 'out';\n const preloadPath = path.join(electronApp.getAppPath(), outDir, 'preload', 'index.js');\n const rendererFile = path.join(electronApp.getAppPath(), outDir, 'renderer', 'index.html');\n\n const container = getContainer({\n scope,\n ...(configureContainer ? { configure: configureContainer } : {}),\n });\n\n const registrationContainer = container as {\n registerFunction?: (\n token: any,\n resolver: (...args: any[]) => unknown,\n options?: Record<string, unknown>,\n ) => void;\n };\n\n if (typeof registrationContainer.registerFunction === 'function') {\n registrationContainer.registerFunction(Ipc, () => getIpc());\n }\n\n const getWindow = (windowId: string): ElectronBrowserWindow | null => {\n const existing = windows.get(windowId);\n if (!existing) {\n return null;\n }\n if (existing.isDestroyed()) {\n windows.delete(windowId);\n return null;\n }\n return existing;\n };\n\n const findWindowIdByWebContents = (webContentsId: number): string | null => {\n for (const [windowId, win] of windows.entries()) {\n if (win.isDestroyed()) {\n windows.delete(windowId);\n continue;\n }\n if (win.webContents.id === webContentsId) {\n return windowId;\n }\n }\n return null;\n };\n\n const getRendererHealthState = (windowId: string): RendererHealthState | null => {\n return rendererHealth.get(windowId) ?? null;\n };\n\n const notifyRendererHealthChanged = (event: WoodRendererHealthEvent): void => {\n if (!options.onRendererHealthChanged) {\n return;\n }\n if (!runtimeContext) {\n runtimeLogger.warn('renderer health hook skipped before runtime context', {\n windowId: event.windowId,\n state: event.state,\n });\n return;\n }\n\n Promise.resolve(options.onRendererHealthChanged(event, runtimeContext)).catch((error) => {\n runtimeLogger.warn('renderer health hook failed', {\n windowId: event.windowId,\n state: event.state,\n error: toErrorMessage(error),\n });\n });\n };\n\n const setRendererHealth = (\n windowId: string,\n state: RendererHealthState,\n details: {\n webContentsId?: number;\n reason?: string;\n exitCode?: number;\n } = {},\n ): void => {\n const previousState = rendererHealth.get(windowId) ?? null;\n rendererHealth.set(windowId, state);\n notifyRendererHealthChanged({\n windowId,\n state,\n previousState,\n ...details,\n });\n };\n\n const attachRendererHealth = (windowId: string, win: ElectronBrowserWindow): void => {\n const healthLogger = getLogger('wood:main').named(`renderer-health:${windowId}`);\n const webContentsId = win.webContents.id;\n\n setRendererHealth(windowId, 'loading', { webContentsId });\n\n win.webContents.on('did-start-loading', () => {\n setRendererHealth(windowId, 'loading', { webContentsId });\n healthLogger.info('renderer loading', { windowId, webContentsId });\n });\n\n win.webContents.on('did-finish-load', () => {\n setRendererHealth(windowId, 'ready', { webContentsId });\n healthLogger.info('renderer ready', { windowId, webContentsId });\n });\n\n win.webContents.on('unresponsive', () => {\n setRendererHealth(windowId, 'unresponsive', { webContentsId });\n healthLogger.error('renderer unresponsive', { windowId, webContentsId });\n });\n\n win.webContents.on('responsive', () => {\n setRendererHealth(windowId, 'ready', { webContentsId });\n healthLogger.info('renderer responsive', { windowId, webContentsId });\n });\n\n win.webContents.on('render-process-gone', (_event, details: RenderProcessGoneDetails) => {\n setRendererHealth(windowId, 'gone', {\n webContentsId,\n reason: details.reason,\n exitCode: details.exitCode,\n });\n healthLogger.error('renderer process gone', {\n windowId,\n webContentsId,\n reason: details.reason,\n exitCode: details.exitCode,\n });\n });\n\n win.webContents.on('destroyed', () => {\n setRendererHealth(windowId, 'destroyed');\n healthLogger.warn('renderer destroyed', { windowId, webContentsId });\n });\n\n win.on('closed', () => {\n setRendererHealth(windowId, 'destroyed');\n rendererHealth.delete(windowId);\n });\n };\n\n const canSendToWindow = (win: ElectronBrowserWindow): boolean => {\n if (win.isDestroyed()) {\n return false;\n }\n if (win.webContents.isDestroyed()) {\n return false;\n }\n if (typeof win.webContents.isCrashed === 'function' && win.webContents.isCrashed()) {\n return false;\n }\n return true;\n };\n\n const safeSend = (\n windowId: string,\n win: ElectronBrowserWindow,\n channel: string,\n data: unknown,\n ): boolean => {\n if (!canSendToWindow(win)) {\n runtimeLogger.warn('skipping send to unhealthy renderer', {\n windowId,\n channel,\n rendererHealth: getRendererHealthState(windowId),\n });\n return false;\n }\n\n try {\n win.webContents.send(channel, data);\n return true;\n } catch (error) {\n runtimeLogger.warn('send to renderer failed', {\n windowId,\n channel,\n rendererHealth: getRendererHealthState(windowId),\n error: toErrorMessage(error),\n });\n return false;\n }\n };\n\n const installNativeQuitFallback = (): void => {\n if (nativeQuitFallbackInstalled) {\n return;\n }\n Menu.setApplicationMenu(Menu.buildFromTemplate([\n {\n label: electronApp.name,\n submenu: [\n { role: 'quit' },\n ],\n },\n ]));\n nativeQuitFallbackInstalled = true;\n logger.info('native quit fallback installed');\n };\n\n const waitForWindowReady = async (win: ElectronBrowserWindow): Promise<void> => {\n const webContents = win.webContents as ElectronBrowserWindow['webContents'] & {\n isLoadingMainFrame?: () => boolean;\n };\n const isLoading = typeof webContents.isLoadingMainFrame === 'function'\n ? webContents.isLoadingMainFrame()\n : webContents.isLoading();\n if (!isLoading) {\n return;\n }\n\n await new Promise<void>((resolve) => {\n webContents.once('did-finish-load', () => resolve());\n });\n };\n\n const getDebugMetadata = (): WoodDebugMetadata => {\n const debugWindows: WoodDebugWindowMetadata[] = [];\n\n for (const [windowId, win] of windows.entries()) {\n if (win.isDestroyed()) {\n windows.delete(windowId);\n continue;\n }\n\n debugWindows.push({\n windowId,\n title: win.getTitle(),\n webContentsId: win.webContents.id,\n url: win.webContents.getURL(),\n focused: win.isFocused(),\n rendererHealth: getRendererHealthState(windowId) ?? undefined,\n });\n }\n\n return {\n ok: true,\n enabled: debugConfig.enabled,\n mode: debugConfig.mode,\n ...(debugConfig.port ? { port: debugConfig.port } : {}),\n windows: debugWindows,\n };\n };\n\n const createWindow = (windowId = 'main'): ElectronBrowserWindow => {\n const existing = getWindow(windowId);\n if (existing) {\n existing.show();\n existing.focus();\n return existing;\n }\n\n const windowDef = resolveWindowDef(options.windowDefs, windowId);\n const defaultShow = windowDef.show ?? true;\n const parentWindow = windowDef.parent ? getWindow(windowDef.parent) : null;\n\n if (windowDef.nativeQuitFallback === true) {\n installNativeQuitFallback();\n }\n\n windowState.setScreen(screen);\n const savedBounds = windowDef.rememberBounds ? windowState.getBounds(windowId) : null;\n\n const windowOptions: BrowserWindowConstructorOptions = {\n width: savedBounds?.width ?? windowDef.width,\n height: savedBounds?.height ?? windowDef.height,\n ...(savedBounds ? { x: savedBounds.x, y: savedBounds.y } : {}),\n ...(windowDef.minWidth != null ? { minWidth: windowDef.minWidth } : {}),\n ...(windowDef.minHeight != null ? { minHeight: windowDef.minHeight } : {}),\n ...(windowDef.maxWidth != null ? { maxWidth: windowDef.maxWidth } : {}),\n ...(windowDef.maxHeight != null ? { maxHeight: windowDef.maxHeight } : {}),\n ...(typeof windowDef.modal === 'boolean' ? { modal: windowDef.modal } : {}),\n ...(parentWindow ? { parent: parentWindow } : {}),\n title: windowDef.title,\n frame: windowDef.frame ?? true,\n transparent: windowDef.transparent ?? false,\n resizable: windowDef.resizable ?? true,\n alwaysOnTop: windowDef.alwaysOnTop ?? false,\n ...(typeof windowDef.backgroundColor === 'string' ? { backgroundColor: windowDef.backgroundColor } : {}),\n ...(process.platform === 'darwin' && typeof windowDef.vibrancy === 'string'\n ? {\n vibrancy: windowDef.vibrancy as BrowserWindowConstructorOptions['vibrancy'],\n visualEffectState: 'active' as const,\n }\n : {}),\n ...(process.platform === 'win32' && typeof windowDef.backgroundMaterial === 'string'\n ? {\n backgroundMaterial: windowDef.backgroundMaterial as BrowserWindowConstructorOptions['backgroundMaterial'],\n }\n : {}),\n ...(typeof windowDef.acceptFirstMouse === 'boolean' ? { acceptFirstMouse: windowDef.acceptFirstMouse } : {}),\n // Hidden title bar with native window controls: macOS draws the\n // traffic lights (positionable), Windows draws min/max/close via the\n // Window Controls Overlay (always top-right; styled via titleBarOverlay).\n ...(typeof windowDef.titleBarStyle === 'string'\n ? { titleBarStyle: windowDef.titleBarStyle as BrowserWindowConstructorOptions['titleBarStyle'] }\n : {}),\n ...(process.platform === 'darwin' && windowDef.trafficLightPosition\n ? { trafficLightPosition: windowDef.trafficLightPosition }\n : {}),\n ...(process.platform === 'win32' && windowDef.titleBarOverlay != null\n ? { titleBarOverlay: windowDef.titleBarOverlay }\n : {}),\n show: savedBounds ? false : defaultShow,\n webPreferences: {\n preload: preloadPath,\n contextIsolation: true,\n nodeIntegration: false,\n },\n };\n\n const win = new BrowserWindow(windowOptions);\n windows.set(windowId, win);\n attachRendererHealth(windowId, win);\n if (windowId === 'main') {\n mainWindow = win;\n }\n\n if (savedBounds?.isMaximized) {\n win.maximize();\n } else if (savedBounds?.isFullScreen) {\n win.setFullScreen(true);\n }\n\n if (savedBounds && defaultShow) {\n win.show();\n }\n\n if (windowDef.rememberBounds) {\n const captureNormalBounds = () => {\n if (!win.isMaximized() && !win.isFullScreen()) {\n const rect = win.getBounds();\n windowState.updateBoundsDebounced(windowId, {\n ...rect,\n isMaximized: false,\n isFullScreen: false,\n });\n }\n };\n win.on('move', captureNormalBounds);\n win.on('resize', captureNormalBounds);\n win.on('close', () => {\n const rect = win.getBounds();\n windowState.saveBoundsSync(windowId, {\n ...rect,\n isMaximized: win.isMaximized(),\n isFullScreen: win.isFullScreen(),\n });\n });\n }\n\n win.webContents.setWindowOpenHandler(({ url }) => {\n if (url.startsWith('http://') || url.startsWith('https://')) {\n void shell.openExternal(url);\n }\n return { action: 'deny' };\n });\n\n win.webContents.on('will-navigate', (event, url) => {\n if (process.env.ELECTRON_RENDERER_URL && url.startsWith(process.env.ELECTRON_RENDERER_URL)) {\n return;\n }\n if (url.startsWith('http://') || url.startsWith('https://')) {\n event.preventDefault();\n void shell.openExternal(url);\n }\n });\n\n const rendererLogger = getLogger('wood:main').named(`renderer:${windowId}`);\n const levelMap: Record<number, 'debug' | 'info' | 'warn' | 'error'> = {\n 0: 'debug',\n 1: 'info',\n 2: 'warn',\n 3: 'error',\n };\n\n win.webContents.on('console-message', (_event, level, message, line, sourceId) => {\n const method = levelMap[level] ?? 'info';\n rendererLogger[method](message, { source: sourceId, line, windowId });\n });\n\n if (process.env.ELECTRON_RENDERER_URL) {\n void win.loadURL(process.env.ELECTRON_RENDERER_URL);\n } else {\n void win.loadFile(rendererFile);\n }\n\n if (options.traceTransport === 'messageport' && options.rendererTraceEnabled === true) {\n const { port1, port2 } = new MessageChannelMain();\n\n const portHandler = (event: Electron.MessageEvent) => {\n dispatchRendererTracePayload(event.data, {\n windowId,\n webContentsId: win.webContents.id,\n });\n };\n port1.on('message', portHandler);\n port1.start();\n\n win.webContents.once('did-finish-load', () => {\n if (!win.isDestroyed()) {\n win.webContents.postMessage('__trace-port', null, [port2]);\n logger.info('trace messageport sent to renderer', { windowId });\n }\n });\n\n win.on('closed', () => {\n port1.off('message', portHandler);\n port1.close();\n });\n }\n\n win.on('closed', () => {\n windows.delete(windowId);\n rendererHealth.delete(windowId);\n if (windowId === 'main') {\n mainWindow = null;\n }\n if (windows.size === 0) {\n electronApp.quit();\n }\n });\n\n if (options.onWindowCreated) {\n Promise.resolve(options.onWindowCreated(windowId, win, runtimeContext!)).catch((error) => {\n runtimeLogger.warn('window created hook failed', {\n windowId,\n error: toErrorMessage(error),\n });\n });\n }\n\n logger.info('window created', { windowId });\n return win;\n };\n\n const navigateWindow = async (windowId: string, route: string): Promise<void> => {\n const win = createWindow(windowId);\n await waitForWindowReady(win);\n safeSend(windowId, win, '__event:__navigate', { route });\n win.show();\n win.focus();\n };\n\n const dispatchPushEvent = (\n channel: string,\n data: unknown,\n options?: IpcPushOptions,\n ): void => {\n const eventChannel = channel.startsWith('__event:')\n ? channel\n : `__event:${channel}`;\n\n if (options?.windowId) {\n const target = getWindow(options.windowId);\n if (target) {\n safeSend(options.windowId, target, eventChannel, data);\n }\n return;\n }\n\n for (const [windowId, win] of windows.entries()) {\n if (win.isDestroyed()) {\n windows.delete(windowId);\n continue;\n }\n safeSend(windowId, win, eventChannel, data);\n }\n };\n\n setIpcPushSender(dispatchPushEvent);\n\n const broadcast = (channel: string, data: unknown): void => {\n for (const [windowId, win] of windows.entries()) {\n if (win.isDestroyed()) {\n windows.delete(windowId);\n continue;\n }\n safeSend(windowId, win, channel, data);\n }\n };\n\n runtimeContext = {\n ...bootContext,\n container,\n applicationRoot: '',\n getWindow,\n createWindow,\n navigateWindow,\n broadcast,\n getRendererHealthState,\n setRendererLogCallback: (callback) => {\n getRendererLogDispatcher().setCallback(callback);\n },\n getRendererLogCallback: () => getRendererLogDispatcher().getCallback(),\n getDebugMetadata,\n };\n\n const bootstrap = async () => {\n logger.info('bootstrap starting');\n const applicationRoot = setApplicationRoot(path.join(electronApp.getPath('userData'), 'wood'));\n runtimeContext!.applicationRoot = applicationRoot;\n logger.info('application root configured', { applicationRoot });\n\n if (options.mainBoot) {\n const bootResult = await options.mainBoot(appBootResult, runtimeContext!);\n if (typeof bootResult === 'function') {\n mainBootCleanup = bootResult;\n }\n }\n\n await bootRuntime({\n container,\n ipcMain,\n registerRuntime: options.registerRuntime,\n controllersDir: resolveRuntimePath(options.controllersDir),\n middlewareDir: resolveRuntimePath(options.middlewareDir),\n ...(options.traceMinLevel ? { traceMinLevel: options.traceMinLevel } : {}),\n ...(typeof options.rendererTraceEnabled === 'boolean'\n ? { rendererTraceEnabled: options.rendererTraceEnabled }\n : {}),\n ...(options.rendererTraceMinLevel\n ? { rendererTraceMinLevel: options.rendererTraceMinLevel }\n : {}),\n ...(options.traceTransport === 'messageport' ? { enableRendererTraceBridge: false } : {}),\n onLoad: options.onLoad ?? (async () => {\n throw new Error('Reserved channel \"__load\" is not configured for this app.');\n }),\n onNavigate: async (rawData) => {\n const data = rawData as { windowId?: string; route?: string };\n if (!data.windowId) {\n throw new Error('__navigate requires windowId');\n }\n if (!data.route) {\n throw new Error('__navigate requires route');\n }\n await navigateWindow(data.windowId, data.route);\n return { ok: true };\n },\n onWindow: async (rawData, event) => {\n const data = rawData as { action?: string; windowId?: string };\n const action = data.action ?? '';\n const windowId = data.windowId;\n\n if (action === 'current') {\n const ipcEvent = event as IpcMainInvokeEvent | undefined;\n const senderWindowId = ipcEvent?.sender ? findWindowIdByWebContents(ipcEvent.sender.id) : null;\n if (!senderWindowId) {\n return { ok: false };\n }\n const senderWindowDef = resolveWindowDef(options.windowDefs, senderWindowId);\n return {\n ok: true,\n windowId: senderWindowId,\n defaultRoute: senderWindowDef.defaultRoute,\n };\n }\n\n if (action === 'open') {\n if (!windowId) {\n throw new Error('__window.open requires windowId');\n }\n createWindow(windowId);\n return { ok: true };\n }\n\n const win = windowId ? getWindow(windowId) : mainWindow;\n if (!win) {\n return { ok: false };\n }\n\n switch (action) {\n case 'close':\n win.close();\n return { ok: true };\n case 'focus':\n win.show();\n win.focus();\n return { ok: true };\n case 'minimize':\n win.minimize();\n return { ok: true };\n case 'maximize':\n win.isMaximized() ? win.unmaximize() : win.maximize();\n return { ok: true };\n default:\n return { ok: false };\n }\n },\n onDebug: async (rawData) => {\n const data = rawData as { action?: string } | undefined;\n const action = data?.action ?? '';\n\n if (action === 'current') {\n return getDebugMetadata();\n }\n\n return { ok: false };\n },\n onContextMenu: options.onContextMenu ?? (async (_rawData: unknown, event?: unknown) => {\n const ipcEvent = event as IpcMainInvokeEvent | undefined;\n const senderId = ipcEvent?.sender?.id;\n runtimeLogger.debug('context menu requested', { senderId });\n return { ok: true };\n }),\n resolveRendererTraceContext: (event) => {\n const ipcEvent = event as IpcMainInvokeEvent | undefined;\n const webContentsId = ipcEvent?.sender?.id;\n if (typeof webContentsId !== 'number') {\n return undefined;\n }\n return {\n webContentsId,\n windowId: findWindowIdByWebContents(webContentsId) ?? undefined,\n };\n },\n });\n\n createWindow('main');\n logger.info('bootstrap complete');\n };\n\n void electronApp.whenReady().then(bootstrap).catch((error) => {\n logger.error('bootstrap failed', {\n message: toErrorMessage(error),\n stack: error instanceof Error ? error.stack : undefined,\n });\n });\n\n const destroyWindowsForQuit = (): void => {\n for (const [id, win] of windows) {\n if (!win.isDestroyed()) {\n win.destroy();\n logger.debug('destroyed window on quit', { windowId: id });\n }\n }\n windows.clear();\n };\n\n const runBeforeQuitCleanup = async (): Promise<void> => {\n clearIpcPushSender();\n if (mainBootCleanup) {\n await mainBootCleanup();\n }\n if (options.onBeforeQuit) {\n await options.onBeforeQuit(runtimeContext!);\n }\n };\n\n electronApp.on('before-quit', (event: ElectronEvent) => {\n if (!runtimeContext) {\n return;\n }\n\n if (beforeQuitCleanupComplete) {\n destroyWindowsForQuit();\n return;\n }\n\n event.preventDefault();\n if (beforeQuitCleanupPromise) {\n return;\n }\n\n beforeQuitCleanupPromise = (async () => {\n try {\n await runBeforeQuitCleanup();\n } catch (error) {\n logger.warn('before-quit handler failed', { error: toErrorMessage(error) });\n } finally {\n beforeQuitCleanupComplete = true;\n beforeQuitCleanupPromise = null;\n }\n\n destroyWindowsForQuit();\n electronApp.quit();\n })();\n });\n\n electronApp.on('window-all-closed', () => {\n electronApp.quit();\n });\n\n electronApp.on('activate', () => {\n if (BrowserWindow.getAllWindows().length === 0) {\n createWindow('main');\n }\n });\n })().catch((error) => {\n logger.error('startup failed before ready', {\n message: toErrorMessage(error),\n stack: error instanceof Error ? error.stack : undefined,\n });\n });\n}\n"],"mappings":"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","names":["options"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/types/config.ts"],"sourcesContent":["/** Configuration types for wood.config.yml */\n\n/** Top-level Wood configuration parsed from wood.config.yml */\nexport interface WoodConfig {\n root: string;\n outDir: string;\n app: {\n boot: string;\n watch: string[];\n };\n main: {\n entry: string;\n controllers: string;\n middleware: string;\n openapi: string;\n watch: string[];\n };\n renderer: {\n openapi: string;\n componentDir: string;\n controllers: string;\n entry?: string;\n watch?: string[];\n };\n windows: Record<string, WindowDef>;\n database?: {\n path: string;\n migrations?: string;\n };\n assets?: string[];\n dev?: DevConfig;\n build?: ElectronBuilderConfig;\n}\n\n/** BrowserWindow definition from the `windows` section of wood.config.yml */\nexport interface WindowDef {\n title: string;\n width: number;\n height: number;\n defaultRoute: string;\n frame?: boolean;\n transparent?: boolean;\n resizable?: boolean;\n alwaysOnTop?: boolean;\n minWidth?: number;\n minHeight?: number;\n maxWidth?: number;\n maxHeight?: number;\n show?: boolean;\n parent?: string;\n modal?: boolean;\n vibrancy?: string;\n backgroundMaterial?: string;\n rememberBounds?: boolean;\n contextMenu?: 'native' | 'custom';\n}\n\n/** Dev-mode settings from the `dev` section of wood.config.yml */\nexport interface DevConfig {\n port?: number;\n watch?: boolean;\n splitServe?: boolean;\n electronArgs?: string[];\n inspectPort?: number;\n backendInspectPort?: number;\n}\n\n/** Electron-builder packaging configuration from the `build` section */\nexport interface ElectronBuilderConfig {\n appId: string;\n productName: string;\n mac?: Record<string, unknown>;\n win?: Record<string, unknown>;\n linux?: Record<string, unknown>;\n [key: string]: unknown;\n}\n"],"mappings":";;;;;;;;;;;;;;AAAA;AAAA;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/types/config.ts"],"sourcesContent":["/** Configuration types for wood.config.yml */\n\n/** Top-level Wood configuration parsed from wood.config.yml */\nexport interface WoodConfig {\n root: string;\n outDir: string;\n app: {\n boot: string;\n watch: string[];\n };\n main: {\n entry: string;\n controllers: string;\n middleware: string;\n openapi: string;\n watch: string[];\n };\n renderer: {\n openapi: string;\n componentDir: string;\n controllers: string;\n entry?: string;\n watch?: string[];\n };\n windows: Record<string, WindowDef>;\n database?: {\n path: string;\n migrations?: string;\n };\n assets?: string[];\n dev?: DevConfig;\n build?: ElectronBuilderConfig;\n}\n\n/** BrowserWindow definition from the `windows` section of wood.config.yml */\nexport interface WindowDef {\n title: string;\n width: number;\n height: number;\n defaultRoute: string;\n frame?: boolean;\n transparent?: boolean;\n resizable?: boolean;\n alwaysOnTop?: boolean;\n minWidth?: number;\n minHeight?: number;\n maxWidth?: number;\n maxHeight?: number;\n show?: boolean;\n parent?: string;\n modal?: boolean;\n vibrancy?: string;\n backgroundMaterial?: string;\n rememberBounds?: boolean;\n contextMenu?: 'native' | 'custom';\n acceptFirstMouse?: boolean;\n nativeQuitFallback?: boolean;\n titleBarStyle?: 'default' | 'hidden' | 'hiddenInset' | 'customButtonsOnHover';\n trafficLightPosition?: { x: number; y: number };\n titleBarOverlay?: boolean | { color?: string; symbolColor?: string; height?: number };\n}\n\n/** Dev-mode settings from the `dev` section of wood.config.yml */\nexport interface DevConfig {\n port?: number;\n watch?: boolean;\n splitServe?: boolean;\n electronArgs?: string[];\n inspectPort?: number;\n backendInspectPort?: number;\n}\n\n/** Electron-builder packaging configuration from the `build` section */\nexport interface ElectronBuilderConfig {\n appId: string;\n productName: string;\n mac?: Record<string, unknown>;\n win?: Record<string, unknown>;\n linux?: Record<string, unknown>;\n [key: string]: unknown;\n}\n"],"mappings":";;;;;;;;;;;;;;AAAA;AAAA;","names":[]}
|