@noego/wood 0.4.5 → 0.4.7
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 +9 -1
- package/dist/client/app_env.cjs +39 -0
- package/dist/client/app_env.cjs.map +1 -0
- package/dist/client/app_env.d.cts +7 -0
- package/dist/client/app_env.d.ts +7 -0
- package/dist/client/app_env.js +14 -0
- package/dist/client/app_env.js.map +1 -0
- package/dist/client/index.cjs +33 -9
- package/dist/client/index.cjs.map +1 -1
- package/dist/client/index.d.cts +5 -1
- package/dist/client/index.d.ts +5 -1
- package/dist/client/index.js +32 -9
- package/dist/client/index.js.map +1 -1
- package/dist/codegen/channel_map_generator.cjs +102 -0
- package/dist/codegen/channel_map_generator.cjs.map +1 -0
- package/dist/codegen/channel_map_generator.d.cts +6 -0
- package/dist/codegen/channel_map_generator.d.ts +6 -0
- package/dist/codegen/channel_map_generator.js +78 -0
- package/dist/codegen/channel_map_generator.js.map +1 -0
- package/dist/codegen/controller_registration_generator.cjs +6 -1
- package/dist/codegen/controller_registration_generator.cjs.map +1 -1
- package/dist/codegen/controller_registration_generator.js +6 -1
- package/dist/codegen/controller_registration_generator.js.map +1 -1
- package/dist/codegen/generated_file_notice.cjs +40 -0
- package/dist/codegen/generated_file_notice.cjs.map +1 -0
- package/dist/codegen/generated_file_notice.d.cts +3 -0
- package/dist/codegen/generated_file_notice.d.ts +3 -0
- package/dist/codegen/generated_file_notice.js +16 -0
- package/dist/codegen/generated_file_notice.js.map +1 -0
- package/dist/codegen/index.cjs +3 -0
- package/dist/codegen/index.cjs.map +1 -1
- package/dist/codegen/index.d.cts +1 -0
- package/dist/codegen/index.d.ts +1 -0
- package/dist/codegen/index.js +2 -0
- package/dist/codegen/index.js.map +1 -1
- package/dist/codegen/preload_generator.cjs +97 -1
- package/dist/codegen/preload_generator.cjs.map +1 -1
- package/dist/codegen/preload_generator.js +97 -1
- package/dist/codegen/preload_generator.js.map +1 -1
- package/dist/codegen/renderer_app_generator.cjs +6 -1
- package/dist/codegen/renderer_app_generator.cjs.map +1 -1
- package/dist/codegen/renderer_app_generator.js +6 -1
- package/dist/codegen/renderer_app_generator.js.map +1 -1
- package/dist/codegen/renderer_controller_registration_generator.cjs +6 -1
- package/dist/codegen/renderer_controller_registration_generator.cjs.map +1 -1
- package/dist/codegen/renderer_controller_registration_generator.js +6 -1
- package/dist/codegen/renderer_controller_registration_generator.js.map +1 -1
- package/dist/codegen/renderer_view_manifest_generator.cjs +6 -1
- package/dist/codegen/renderer_view_manifest_generator.cjs.map +1 -1
- package/dist/codegen/renderer_view_manifest_generator.js +6 -1
- package/dist/codegen/renderer_view_manifest_generator.js.map +1 -1
- package/dist/codegen/runtime_generator.cjs +6 -1
- package/dist/codegen/runtime_generator.cjs.map +1 -1
- package/dist/codegen/runtime_generator.js +6 -1
- package/dist/codegen/runtime_generator.js.map +1 -1
- package/dist/codegen/test_mock_generator.cjs +5 -1
- package/dist/codegen/test_mock_generator.cjs.map +1 -1
- package/dist/codegen/test_mock_generator.js +5 -1
- package/dist/codegen/test_mock_generator.js.map +1 -1
- package/dist/codegen/type_generator.cjs +7 -1
- package/dist/codegen/type_generator.cjs.map +1 -1
- package/dist/codegen/type_generator.js +7 -1
- package/dist/codegen/type_generator.js.map +1 -1
- package/dist/index.cjs +19 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -1
- package/dist/index.d.ts +7 -1
- package/dist/index.js +13 -1
- package/dist/index.js.map +1 -1
- package/dist/main/index.cjs +287 -62
- package/dist/main/index.cjs.map +1 -1
- package/dist/main/index.d.cts +57 -3
- package/dist/main/index.d.ts +57 -3
- package/dist/main/index.js +289 -62
- package/dist/main/index.js.map +1 -1
- package/dist/main/renderer_trace_drain_coordinator.cjs +127 -0
- package/dist/main/renderer_trace_drain_coordinator.cjs.map +1 -0
- package/dist/main/renderer_trace_drain_coordinator.d.cts +46 -0
- package/dist/main/renderer_trace_drain_coordinator.d.ts +46 -0
- package/dist/main/renderer_trace_drain_coordinator.js +101 -0
- package/dist/main/renderer_trace_drain_coordinator.js.map +1 -0
- package/dist/router/wood_router.cjs +9 -1
- package/dist/router/wood_router.cjs.map +1 -1
- package/dist/router/wood_router.d.cts +1 -1
- package/dist/router/wood_router.d.ts +1 -1
- package/dist/router/wood_router.js +9 -1
- package/dist/router/wood_router.js.map +1 -1
- package/dist/runtime/app_env.cjs +52 -0
- package/dist/runtime/app_env.cjs.map +1 -0
- package/dist/runtime/app_env.d.cts +10 -0
- package/dist/runtime/app_env.d.ts +10 -0
- package/dist/runtime/app_env.js +18 -0
- package/dist/runtime/app_env.js.map +1 -0
- package/dist/runtime/index.cjs +9 -2
- package/dist/runtime/index.cjs.map +1 -1
- package/dist/runtime/index.d.cts +5 -1
- package/dist/runtime/index.d.ts +5 -1
- package/dist/runtime/index.js +9 -1
- package/dist/runtime/index.js.map +1 -1
- package/dist/runtime/renderer_log_dispatcher.cjs.map +1 -1
- package/dist/runtime/renderer_log_dispatcher.d.cts +1 -1
- package/dist/runtime/renderer_log_dispatcher.d.ts +1 -1
- package/dist/runtime/renderer_log_dispatcher.js.map +1 -1
- package/dist/runtime/renderer_trace_batch_receiver_registry.cjs +50 -0
- package/dist/runtime/renderer_trace_batch_receiver_registry.cjs.map +1 -0
- package/dist/runtime/renderer_trace_batch_receiver_registry.d.cts +10 -0
- package/dist/runtime/renderer_trace_batch_receiver_registry.d.ts +10 -0
- package/dist/runtime/renderer_trace_batch_receiver_registry.js +24 -0
- package/dist/runtime/renderer_trace_batch_receiver_registry.js.map +1 -0
- package/dist/runtime/runtime.cjs +75 -57
- package/dist/runtime/runtime.cjs.map +1 -1
- package/dist/runtime/runtime.d.cts +8 -1
- package/dist/runtime/runtime.d.ts +8 -1
- package/dist/runtime/runtime.js +80 -58
- package/dist/runtime/runtime.js.map +1 -1
- package/dist/testing/browser.cjs +540 -11
- package/dist/testing/browser.cjs.map +1 -1
- package/dist/testing/browser.d.cts +219 -3
- package/dist/testing/browser.d.ts +219 -3
- package/dist/testing/browser.js +540 -11
- package/dist/testing/browser.js.map +1 -1
- package/dist/testing/create_controller_harness.d.cts +1 -1
- package/dist/testing/create_controller_harness.d.ts +1 -1
- package/dist/testing/index.cjs +13 -0
- package/dist/testing/index.cjs.map +1 -1
- package/dist/testing/index.d.cts +7 -2
- package/dist/testing/index.d.ts +7 -2
- package/dist/testing/index.js +14 -0
- package/dist/testing/index.js.map +1 -1
- package/dist/trace-testing/index.d.cts +1 -1
- package/dist/trace-testing/index.d.ts +1 -1
- package/dist/trace-testing/trace_recorder.d.cts +1 -1
- package/dist/trace-testing/trace_recorder.d.ts +1 -1
- package/dist/trace-transport/index.cjs +32 -0
- package/dist/trace-transport/index.cjs.map +1 -0
- package/dist/trace-transport/index.d.cts +6 -0
- package/dist/trace-transport/index.d.ts +6 -0
- package/dist/trace-transport/index.js +7 -0
- package/dist/trace-transport/index.js.map +1 -0
- package/dist/trace_hub-Cob54qRx.d.cts +56 -0
- package/dist/trace_hub-Cob54qRx.d.ts +56 -0
- package/dist/tracing/index.cjs +14 -0
- package/dist/tracing/index.cjs.map +1 -1
- package/dist/tracing/index.d.cts +7 -1
- package/dist/tracing/index.d.ts +7 -1
- package/dist/tracing/index.js +12 -0
- package/dist/tracing/index.js.map +1 -1
- package/dist/tracing/renderer_trace_batch_host.cjs +80 -0
- package/dist/tracing/renderer_trace_batch_host.cjs.map +1 -0
- package/dist/tracing/renderer_trace_batch_host.d.cts +16 -0
- package/dist/tracing/renderer_trace_batch_host.d.ts +16 -0
- package/dist/tracing/renderer_trace_batch_host.js +56 -0
- package/dist/tracing/renderer_trace_batch_host.js.map +1 -0
- package/dist/tracing/renderer_trace_batch_transport.cjs +313 -0
- package/dist/tracing/renderer_trace_batch_transport.cjs.map +1 -0
- package/dist/tracing/renderer_trace_batch_transport.d.cts +53 -0
- package/dist/tracing/renderer_trace_batch_transport.d.ts +53 -0
- package/dist/tracing/renderer_trace_batch_transport.js +292 -0
- package/dist/tracing/renderer_trace_batch_transport.js.map +1 -0
- package/dist/tracing/trace_commit_writer.cjs +159 -0
- package/dist/tracing/trace_commit_writer.cjs.map +1 -0
- package/dist/tracing/trace_commit_writer.d.cts +97 -0
- package/dist/tracing/trace_commit_writer.d.ts +97 -0
- package/dist/tracing/trace_commit_writer.js +135 -0
- package/dist/tracing/trace_commit_writer.js.map +1 -0
- package/dist/tracing/trace_hub.cjs +58 -3
- package/dist/tracing/trace_hub.cjs.map +1 -1
- package/dist/tracing/trace_hub.d.cts +2 -46
- package/dist/tracing/trace_hub.d.ts +2 -46
- package/dist/tracing/trace_hub.js +56 -3
- package/dist/tracing/trace_hub.js.map +1 -1
- package/dist/tracing/trace_provider.cjs +42 -12
- package/dist/tracing/trace_provider.cjs.map +1 -1
- package/dist/tracing/trace_provider.d.cts +15 -1
- package/dist/tracing/trace_provider.d.ts +15 -1
- package/dist/tracing/trace_provider.js +43 -12
- package/dist/tracing/trace_provider.js.map +1 -1
- package/dist/tracing/types/wood_trace_batch.types.cjs +17 -0
- package/dist/tracing/types/wood_trace_batch.types.cjs.map +1 -0
- package/dist/tracing/types/wood_trace_batch.types.d.cts +124 -0
- package/dist/tracing/types/wood_trace_batch.types.d.ts +124 -0
- package/dist/tracing/types/wood_trace_batch.types.js +1 -0
- package/dist/tracing/types/wood_trace_batch.types.js.map +1 -0
- package/dist/tracing/types/wood_trace_sink.types.cjs +17 -0
- package/dist/tracing/types/wood_trace_sink.types.cjs.map +1 -0
- package/dist/tracing/types/wood_trace_sink.types.d.cts +2 -0
- package/dist/tracing/types/wood_trace_sink.types.d.ts +2 -0
- package/dist/tracing/types/wood_trace_sink.types.js +1 -0
- package/dist/tracing/types/wood_trace_sink.types.js.map +1 -0
- package/dist/tracing/wood_trace_batch_contract.cjs +229 -0
- package/dist/tracing/wood_trace_batch_contract.cjs.map +1 -0
- package/dist/tracing/wood_trace_batch_contract.d.cts +23 -0
- package/dist/tracing/wood_trace_batch_contract.d.ts +23 -0
- package/dist/tracing/wood_trace_batch_contract.js +205 -0
- package/dist/tracing/wood_trace_batch_contract.js.map +1 -0
- package/dist/transport/build_transport_bridge.cjs +62 -0
- package/dist/transport/build_transport_bridge.cjs.map +1 -0
- package/dist/transport/build_transport_bridge.d.cts +29 -0
- package/dist/transport/build_transport_bridge.d.ts +29 -0
- package/dist/transport/build_transport_bridge.js +38 -0
- package/dist/transport/build_transport_bridge.js.map +1 -0
- package/dist/transport/in_process_router_transport.cjs +41 -0
- package/dist/transport/in_process_router_transport.cjs.map +1 -0
- package/dist/transport/in_process_router_transport.d.cts +31 -0
- package/dist/transport/in_process_router_transport.d.ts +31 -0
- package/dist/transport/in_process_router_transport.js +17 -0
- package/dist/transport/in_process_router_transport.js.map +1 -0
- package/dist/transport/index.cjs +42 -0
- package/dist/transport/index.cjs.map +1 -0
- package/dist/transport/index.d.cts +8 -0
- package/dist/transport/index.d.ts +8 -0
- package/dist/transport/index.js +19 -0
- package/dist/transport/index.js.map +1 -0
- package/dist/transport/loopback_remote_transport.cjs +270 -0
- package/dist/transport/loopback_remote_transport.cjs.map +1 -0
- package/dist/transport/loopback_remote_transport.d.cts +49 -0
- package/dist/transport/loopback_remote_transport.d.ts +49 -0
- package/dist/transport/loopback_remote_transport.js +237 -0
- package/dist/transport/loopback_remote_transport.js.map +1 -0
- package/dist/transport/loopback_serialization.cjs +116 -0
- package/dist/transport/loopback_serialization.cjs.map +1 -0
- package/dist/transport/loopback_serialization.d.cts +28 -0
- package/dist/transport/loopback_serialization.d.ts +28 -0
- package/dist/transport/loopback_serialization.js +91 -0
- package/dist/transport/loopback_serialization.js.map +1 -0
- package/dist/transport/transport_contract_suite.cjs +110 -0
- package/dist/transport/transport_contract_suite.cjs.map +1 -0
- package/dist/transport/transport_contract_suite.d.cts +23 -0
- package/dist/transport/transport_contract_suite.d.ts +23 -0
- package/dist/transport/transport_contract_suite.js +85 -0
- package/dist/transport/transport_contract_suite.js.map +1 -0
- package/dist/transport/wood_rpc_transport.cjs +17 -0
- package/dist/transport/wood_rpc_transport.cjs.map +1 -0
- package/dist/transport/wood_rpc_transport.d.cts +44 -0
- package/dist/transport/wood_rpc_transport.d.ts +44 -0
- package/dist/transport/wood_rpc_transport.js +1 -0
- package/dist/transport/wood_rpc_transport.js.map +1 -0
- 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/docs/browser-testing.md +139 -1
- package/package.json +22 -3
- package/src/components/NavigationShell.browser.test.ts +236 -0
- package/src/components/NavigationShell.svelte +162 -49
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,
|
|
@@ -20,6 +21,40 @@ import {
|
|
|
20
21
|
} from "../runtime/renderer_log_dispatcher.js";
|
|
21
22
|
import { Ipc, getIpc } from "../ipc/index.js";
|
|
22
23
|
import { setIpcPushSender, clearIpcPushSender } from "../ipc/shared.js";
|
|
24
|
+
import {
|
|
25
|
+
drainRendererTracesBeforeQuit,
|
|
26
|
+
RendererTraceDrainCoordinator
|
|
27
|
+
} from "./renderer_trace_drain_coordinator.js";
|
|
28
|
+
class BootstrapActivationGate {
|
|
29
|
+
constructor(hasWindow, createMainWindow) {
|
|
30
|
+
this.hasWindow = hasWindow;
|
|
31
|
+
this.createMainWindow = createMainWindow;
|
|
32
|
+
this.currentState = "pending";
|
|
33
|
+
}
|
|
34
|
+
get state() {
|
|
35
|
+
return this.currentState;
|
|
36
|
+
}
|
|
37
|
+
activate() {
|
|
38
|
+
if (this.currentState === "ready" && !this.hasWindow()) {
|
|
39
|
+
this.createMainWindow();
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
ready() {
|
|
43
|
+
if (this.currentState !== "pending") {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
this.createMainWindow();
|
|
47
|
+
this.currentState = "ready";
|
|
48
|
+
}
|
|
49
|
+
failed() {
|
|
50
|
+
if (this.currentState === "pending") {
|
|
51
|
+
this.currentState = "failed";
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
function shouldDeferLastWindowCloseForCleanup(trackedWindowCount, cleanupComplete) {
|
|
56
|
+
return trackedWindowCount === 1 && !cleanupComplete;
|
|
57
|
+
}
|
|
23
58
|
const DEFAULT_WOOD_REMOTE_DEBUGGING_PORT = 9333;
|
|
24
59
|
function resolveWoodDebugMetadataConfiguration(env = process.env) {
|
|
25
60
|
const isDevelopment = env.WOOD_MODE === "development";
|
|
@@ -60,11 +95,15 @@ function startWoodMain(options) {
|
|
|
60
95
|
const debugConfig = resolveWoodDebugMetadataConfiguration();
|
|
61
96
|
const windowState = new WindowStateStore();
|
|
62
97
|
const windows = /* @__PURE__ */ new Map();
|
|
98
|
+
const rendererHealth = /* @__PURE__ */ new Map();
|
|
63
99
|
let mainWindow = null;
|
|
64
100
|
let beforeQuitCleanupComplete = false;
|
|
65
101
|
let beforeQuitCleanupPromise = null;
|
|
66
102
|
let runtimeContext = null;
|
|
67
103
|
let mainBootCleanup;
|
|
104
|
+
let nativeQuitFallbackInstalled = false;
|
|
105
|
+
const rendererTraceDrain = new RendererTraceDrainCoordinator(ipcMain);
|
|
106
|
+
rendererTraceDrain.start();
|
|
68
107
|
for (const stream of [process.stdout, process.stderr]) {
|
|
69
108
|
stream.on("error", (error) => {
|
|
70
109
|
if (error.code === "EPIPE") {
|
|
@@ -89,11 +128,12 @@ function startWoodMain(options) {
|
|
|
89
128
|
protocol,
|
|
90
129
|
net,
|
|
91
130
|
shell,
|
|
92
|
-
screen
|
|
131
|
+
screen,
|
|
132
|
+
Menu
|
|
93
133
|
},
|
|
94
134
|
logger
|
|
95
135
|
};
|
|
96
|
-
|
|
136
|
+
const initializeRuntime = async () => {
|
|
97
137
|
const appBootResult = options.appBoot ? await options.appBoot(bootContext) : void 0;
|
|
98
138
|
const bootOverrides = appBootResult ?? {};
|
|
99
139
|
const scope = bootOverrides.scope ?? options.scope ?? process.cwd();
|
|
@@ -140,6 +180,129 @@ function startWoodMain(options) {
|
|
|
140
180
|
}
|
|
141
181
|
return null;
|
|
142
182
|
};
|
|
183
|
+
const getRendererHealthState = (windowId) => {
|
|
184
|
+
return rendererHealth.get(windowId) ?? null;
|
|
185
|
+
};
|
|
186
|
+
const notifyRendererHealthChanged = (event) => {
|
|
187
|
+
if (!options.onRendererHealthChanged) {
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
if (!runtimeContext) {
|
|
191
|
+
runtimeLogger.warn("renderer health hook skipped before runtime context", {
|
|
192
|
+
windowId: event.windowId,
|
|
193
|
+
state: event.state
|
|
194
|
+
});
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
Promise.resolve(options.onRendererHealthChanged(event, runtimeContext)).catch((error) => {
|
|
198
|
+
runtimeLogger.warn("renderer health hook failed", {
|
|
199
|
+
windowId: event.windowId,
|
|
200
|
+
state: event.state,
|
|
201
|
+
error: toErrorMessage(error)
|
|
202
|
+
});
|
|
203
|
+
});
|
|
204
|
+
};
|
|
205
|
+
const setRendererHealth = (windowId, state, details = {}) => {
|
|
206
|
+
const previousState = rendererHealth.get(windowId) ?? null;
|
|
207
|
+
rendererHealth.set(windowId, state);
|
|
208
|
+
notifyRendererHealthChanged({
|
|
209
|
+
windowId,
|
|
210
|
+
state,
|
|
211
|
+
previousState,
|
|
212
|
+
...details
|
|
213
|
+
});
|
|
214
|
+
};
|
|
215
|
+
const attachRendererHealth = (windowId, win) => {
|
|
216
|
+
const healthLogger = getLogger("wood:main").named(`renderer-health:${windowId}`);
|
|
217
|
+
const webContentsId = win.webContents.id;
|
|
218
|
+
setRendererHealth(windowId, "loading", { webContentsId });
|
|
219
|
+
win.webContents.on("did-start-loading", () => {
|
|
220
|
+
setRendererHealth(windowId, "loading", { webContentsId });
|
|
221
|
+
healthLogger.info("renderer loading", { windowId, webContentsId });
|
|
222
|
+
});
|
|
223
|
+
win.webContents.on("did-finish-load", () => {
|
|
224
|
+
setRendererHealth(windowId, "ready", { webContentsId });
|
|
225
|
+
healthLogger.info("renderer ready", { windowId, webContentsId });
|
|
226
|
+
});
|
|
227
|
+
win.webContents.on("unresponsive", () => {
|
|
228
|
+
setRendererHealth(windowId, "unresponsive", { webContentsId });
|
|
229
|
+
healthLogger.error("renderer unresponsive", { windowId, webContentsId });
|
|
230
|
+
});
|
|
231
|
+
win.webContents.on("responsive", () => {
|
|
232
|
+
setRendererHealth(windowId, "ready", { webContentsId });
|
|
233
|
+
healthLogger.info("renderer responsive", { windowId, webContentsId });
|
|
234
|
+
});
|
|
235
|
+
win.webContents.on("render-process-gone", (_event, details) => {
|
|
236
|
+
setRendererHealth(windowId, "gone", {
|
|
237
|
+
webContentsId,
|
|
238
|
+
reason: details.reason,
|
|
239
|
+
exitCode: details.exitCode
|
|
240
|
+
});
|
|
241
|
+
healthLogger.error("renderer process gone", {
|
|
242
|
+
windowId,
|
|
243
|
+
webContentsId,
|
|
244
|
+
reason: details.reason,
|
|
245
|
+
exitCode: details.exitCode
|
|
246
|
+
});
|
|
247
|
+
});
|
|
248
|
+
win.webContents.on("destroyed", () => {
|
|
249
|
+
setRendererHealth(windowId, "destroyed");
|
|
250
|
+
healthLogger.warn("renderer destroyed", { windowId, webContentsId });
|
|
251
|
+
});
|
|
252
|
+
win.on("closed", () => {
|
|
253
|
+
setRendererHealth(windowId, "destroyed");
|
|
254
|
+
rendererHealth.delete(windowId);
|
|
255
|
+
});
|
|
256
|
+
};
|
|
257
|
+
const canSendToWindow = (win) => {
|
|
258
|
+
if (win.isDestroyed()) {
|
|
259
|
+
return false;
|
|
260
|
+
}
|
|
261
|
+
if (win.webContents.isDestroyed()) {
|
|
262
|
+
return false;
|
|
263
|
+
}
|
|
264
|
+
if (typeof win.webContents.isCrashed === "function" && win.webContents.isCrashed()) {
|
|
265
|
+
return false;
|
|
266
|
+
}
|
|
267
|
+
return true;
|
|
268
|
+
};
|
|
269
|
+
const safeSend = (windowId, win, channel, data) => {
|
|
270
|
+
if (!canSendToWindow(win)) {
|
|
271
|
+
runtimeLogger.warn("skipping send to unhealthy renderer", {
|
|
272
|
+
windowId,
|
|
273
|
+
channel,
|
|
274
|
+
rendererHealth: getRendererHealthState(windowId)
|
|
275
|
+
});
|
|
276
|
+
return false;
|
|
277
|
+
}
|
|
278
|
+
try {
|
|
279
|
+
win.webContents.send(channel, data);
|
|
280
|
+
return true;
|
|
281
|
+
} catch (error) {
|
|
282
|
+
runtimeLogger.warn("send to renderer failed", {
|
|
283
|
+
windowId,
|
|
284
|
+
channel,
|
|
285
|
+
rendererHealth: getRendererHealthState(windowId),
|
|
286
|
+
error: toErrorMessage(error)
|
|
287
|
+
});
|
|
288
|
+
return false;
|
|
289
|
+
}
|
|
290
|
+
};
|
|
291
|
+
const installNativeQuitFallback = () => {
|
|
292
|
+
if (nativeQuitFallbackInstalled) {
|
|
293
|
+
return;
|
|
294
|
+
}
|
|
295
|
+
Menu.setApplicationMenu(Menu.buildFromTemplate([
|
|
296
|
+
{
|
|
297
|
+
label: electronApp.name,
|
|
298
|
+
submenu: [
|
|
299
|
+
{ role: "quit" }
|
|
300
|
+
]
|
|
301
|
+
}
|
|
302
|
+
]));
|
|
303
|
+
nativeQuitFallbackInstalled = true;
|
|
304
|
+
logger.info("native quit fallback installed");
|
|
305
|
+
};
|
|
143
306
|
const waitForWindowReady = async (win) => {
|
|
144
307
|
const webContents = win.webContents;
|
|
145
308
|
const isLoading = typeof webContents.isLoadingMainFrame === "function" ? webContents.isLoadingMainFrame() : webContents.isLoading();
|
|
@@ -162,7 +325,8 @@ function startWoodMain(options) {
|
|
|
162
325
|
title: win.getTitle(),
|
|
163
326
|
webContentsId: win.webContents.id,
|
|
164
327
|
url: win.webContents.getURL(),
|
|
165
|
-
focused: win.isFocused()
|
|
328
|
+
focused: win.isFocused(),
|
|
329
|
+
rendererHealth: getRendererHealthState(windowId) ?? void 0
|
|
166
330
|
});
|
|
167
331
|
}
|
|
168
332
|
return {
|
|
@@ -183,6 +347,9 @@ function startWoodMain(options) {
|
|
|
183
347
|
const windowDef = resolveWindowDef(options.windowDefs, windowId);
|
|
184
348
|
const defaultShow = windowDef.show ?? true;
|
|
185
349
|
const parentWindow = windowDef.parent ? getWindow(windowDef.parent) : null;
|
|
350
|
+
if (windowDef.nativeQuitFallback === true) {
|
|
351
|
+
installNativeQuitFallback();
|
|
352
|
+
}
|
|
186
353
|
windowState.setScreen(screen);
|
|
187
354
|
const savedBounds = windowDef.rememberBounds ? windowState.getBounds(windowId) : null;
|
|
188
355
|
const windowOptions = {
|
|
@@ -209,6 +376,12 @@ function startWoodMain(options) {
|
|
|
209
376
|
backgroundMaterial: windowDef.backgroundMaterial
|
|
210
377
|
} : {},
|
|
211
378
|
...typeof windowDef.acceptFirstMouse === "boolean" ? { acceptFirstMouse: windowDef.acceptFirstMouse } : {},
|
|
379
|
+
// Hidden title bar with native window controls: macOS draws the
|
|
380
|
+
// traffic lights (positionable), Windows draws min/max/close via the
|
|
381
|
+
// Window Controls Overlay (always top-right; styled via titleBarOverlay).
|
|
382
|
+
...typeof windowDef.titleBarStyle === "string" ? { titleBarStyle: windowDef.titleBarStyle } : {},
|
|
383
|
+
...process.platform === "darwin" && windowDef.trafficLightPosition ? { trafficLightPosition: windowDef.trafficLightPosition } : {},
|
|
384
|
+
...process.platform === "win32" && windowDef.titleBarOverlay != null ? { titleBarOverlay: windowDef.titleBarOverlay } : {},
|
|
212
385
|
show: savedBounds ? false : defaultShow,
|
|
213
386
|
webPreferences: {
|
|
214
387
|
preload: preloadPath,
|
|
@@ -218,6 +391,7 @@ function startWoodMain(options) {
|
|
|
218
391
|
};
|
|
219
392
|
const win = new BrowserWindow(windowOptions);
|
|
220
393
|
windows.set(windowId, win);
|
|
394
|
+
attachRendererHealth(windowId, win);
|
|
221
395
|
if (windowId === "main") {
|
|
222
396
|
mainWindow = win;
|
|
223
397
|
}
|
|
@@ -305,6 +479,7 @@ function startWoodMain(options) {
|
|
|
305
479
|
}
|
|
306
480
|
win.on("closed", () => {
|
|
307
481
|
windows.delete(windowId);
|
|
482
|
+
rendererHealth.delete(windowId);
|
|
308
483
|
if (windowId === "main") {
|
|
309
484
|
mainWindow = null;
|
|
310
485
|
}
|
|
@@ -312,13 +487,27 @@ function startWoodMain(options) {
|
|
|
312
487
|
electronApp.quit();
|
|
313
488
|
}
|
|
314
489
|
});
|
|
490
|
+
if (options.onWindowCreated) {
|
|
491
|
+
Promise.resolve(options.onWindowCreated(windowId, win, runtimeContext)).catch((error) => {
|
|
492
|
+
runtimeLogger.warn("window created hook failed", {
|
|
493
|
+
windowId,
|
|
494
|
+
error: toErrorMessage(error)
|
|
495
|
+
});
|
|
496
|
+
});
|
|
497
|
+
}
|
|
315
498
|
logger.info("window created", { windowId });
|
|
316
499
|
return win;
|
|
317
500
|
};
|
|
501
|
+
const bootstrapActivationGate = new BootstrapActivationGate(
|
|
502
|
+
() => BrowserWindow.getAllWindows().length > 0,
|
|
503
|
+
() => {
|
|
504
|
+
createWindow("main");
|
|
505
|
+
}
|
|
506
|
+
);
|
|
318
507
|
const navigateWindow = async (windowId, route) => {
|
|
319
508
|
const win = createWindow(windowId);
|
|
320
509
|
await waitForWindowReady(win);
|
|
321
|
-
win
|
|
510
|
+
safeSend(windowId, win, "__event:__navigate", { route });
|
|
322
511
|
win.show();
|
|
323
512
|
win.focus();
|
|
324
513
|
};
|
|
@@ -326,8 +515,8 @@ function startWoodMain(options) {
|
|
|
326
515
|
const eventChannel = channel.startsWith("__event:") ? channel : `__event:${channel}`;
|
|
327
516
|
if (options2?.windowId) {
|
|
328
517
|
const target = getWindow(options2.windowId);
|
|
329
|
-
if (target
|
|
330
|
-
target
|
|
518
|
+
if (target) {
|
|
519
|
+
safeSend(options2.windowId, target, eventChannel, data);
|
|
331
520
|
}
|
|
332
521
|
return;
|
|
333
522
|
}
|
|
@@ -336,7 +525,7 @@ function startWoodMain(options) {
|
|
|
336
525
|
windows.delete(windowId);
|
|
337
526
|
continue;
|
|
338
527
|
}
|
|
339
|
-
win
|
|
528
|
+
safeSend(windowId, win, eventChannel, data);
|
|
340
529
|
}
|
|
341
530
|
};
|
|
342
531
|
setIpcPushSender(dispatchPushEvent);
|
|
@@ -346,7 +535,7 @@ function startWoodMain(options) {
|
|
|
346
535
|
windows.delete(windowId);
|
|
347
536
|
continue;
|
|
348
537
|
}
|
|
349
|
-
win
|
|
538
|
+
safeSend(windowId, win, channel, data);
|
|
350
539
|
}
|
|
351
540
|
};
|
|
352
541
|
runtimeContext = {
|
|
@@ -357,11 +546,16 @@ function startWoodMain(options) {
|
|
|
357
546
|
createWindow,
|
|
358
547
|
navigateWindow,
|
|
359
548
|
broadcast,
|
|
549
|
+
getRendererHealthState,
|
|
360
550
|
setRendererLogCallback: (callback) => {
|
|
361
551
|
getRendererLogDispatcher().setCallback(callback);
|
|
362
552
|
},
|
|
363
553
|
getRendererLogCallback: () => getRendererLogDispatcher().getCallback(),
|
|
364
|
-
getDebugMetadata
|
|
554
|
+
getDebugMetadata,
|
|
555
|
+
// Late-bound after bootRuntime constructs the router (see bootstrap).
|
|
556
|
+
dispatch: async () => {
|
|
557
|
+
throw new Error("WoodMainRuntimeContext.dispatch called before the runtime router was constructed.");
|
|
558
|
+
}
|
|
365
559
|
};
|
|
366
560
|
const bootstrap = async () => {
|
|
367
561
|
logger.info("bootstrap starting");
|
|
@@ -374,7 +568,7 @@ function startWoodMain(options) {
|
|
|
374
568
|
mainBootCleanup = bootResult;
|
|
375
569
|
}
|
|
376
570
|
}
|
|
377
|
-
await bootRuntime({
|
|
571
|
+
const { router: runtimeRouter } = await bootRuntime({
|
|
378
572
|
container,
|
|
379
573
|
ipcMain,
|
|
380
574
|
registerRuntime: options.registerRuntime,
|
|
@@ -470,67 +664,98 @@ function startWoodMain(options) {
|
|
|
470
664
|
};
|
|
471
665
|
}
|
|
472
666
|
});
|
|
473
|
-
|
|
667
|
+
runtimeContext.dispatch = (channel, payload) => runtimeRouter.dispatch(channel, payload ?? {});
|
|
668
|
+
bootstrapActivationGate.ready();
|
|
474
669
|
logger.info("bootstrap complete");
|
|
475
670
|
};
|
|
476
|
-
|
|
671
|
+
const handleBootstrapFailure = (error) => {
|
|
672
|
+
bootstrapActivationGate.failed();
|
|
477
673
|
logger.error("bootstrap failed", {
|
|
478
674
|
message: toErrorMessage(error),
|
|
479
675
|
stack: error instanceof Error ? error.stack : void 0
|
|
480
676
|
});
|
|
481
|
-
});
|
|
482
|
-
const destroyWindowsForQuit = () => {
|
|
483
|
-
for (const [id, win] of windows) {
|
|
484
|
-
if (!win.isDestroyed()) {
|
|
485
|
-
win.destroy();
|
|
486
|
-
logger.debug("destroyed window on quit", { windowId: id });
|
|
487
|
-
}
|
|
488
|
-
}
|
|
489
|
-
windows.clear();
|
|
490
677
|
};
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
return;
|
|
511
|
-
}
|
|
512
|
-
beforeQuitCleanupPromise = (async () => {
|
|
513
|
-
try {
|
|
514
|
-
await runBeforeQuitCleanup();
|
|
515
|
-
} catch (error) {
|
|
516
|
-
logger.warn("before-quit handler failed", { error: toErrorMessage(error) });
|
|
517
|
-
} finally {
|
|
518
|
-
beforeQuitCleanupComplete = true;
|
|
519
|
-
beforeQuitCleanupPromise = null;
|
|
678
|
+
void electronApp.whenReady().then(bootstrap).catch(handleBootstrapFailure);
|
|
679
|
+
const registerApplicationLifecycle = () => {
|
|
680
|
+
electronApp.on(
|
|
681
|
+
"browser-window-created",
|
|
682
|
+
(_event, window) => {
|
|
683
|
+
window.on("close", (event) => {
|
|
684
|
+
const isTrackedWindow = [...windows.values()].includes(window);
|
|
685
|
+
if (!isTrackedWindow || !shouldDeferLastWindowCloseForCleanup(
|
|
686
|
+
windows.size,
|
|
687
|
+
beforeQuitCleanupComplete
|
|
688
|
+
)) {
|
|
689
|
+
return;
|
|
690
|
+
}
|
|
691
|
+
event.preventDefault();
|
|
692
|
+
if (!beforeQuitCleanupPromise) {
|
|
693
|
+
logger.debug("deferring last window close for renderer trace drain");
|
|
694
|
+
electronApp.quit();
|
|
695
|
+
}
|
|
696
|
+
});
|
|
520
697
|
}
|
|
521
|
-
|
|
698
|
+
);
|
|
699
|
+
const destroyWindowsForQuit = () => {
|
|
700
|
+
for (const [id, win] of windows) {
|
|
701
|
+
if (!win.isDestroyed()) {
|
|
702
|
+
win.destroy();
|
|
703
|
+
logger.debug("destroyed window on quit", { windowId: id });
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
windows.clear();
|
|
707
|
+
};
|
|
708
|
+
const runBeforeQuitCleanup = async () => {
|
|
709
|
+
await drainRendererTracesBeforeQuit(
|
|
710
|
+
rendererTraceDrain,
|
|
711
|
+
windows.values(),
|
|
712
|
+
logger,
|
|
713
|
+
Date.now() + 1e3
|
|
714
|
+
);
|
|
715
|
+
clearIpcPushSender();
|
|
716
|
+
if (mainBootCleanup) {
|
|
717
|
+
await mainBootCleanup();
|
|
718
|
+
}
|
|
719
|
+
if (options.onBeforeQuit) {
|
|
720
|
+
await options.onBeforeQuit(runtimeContext);
|
|
721
|
+
}
|
|
722
|
+
};
|
|
723
|
+
electronApp.on("before-quit", (event) => {
|
|
724
|
+
if (!runtimeContext) {
|
|
725
|
+
return;
|
|
726
|
+
}
|
|
727
|
+
if (beforeQuitCleanupComplete) {
|
|
728
|
+
destroyWindowsForQuit();
|
|
729
|
+
return;
|
|
730
|
+
}
|
|
731
|
+
event.preventDefault();
|
|
732
|
+
if (beforeQuitCleanupPromise) {
|
|
733
|
+
return;
|
|
734
|
+
}
|
|
735
|
+
beforeQuitCleanupPromise = (async () => {
|
|
736
|
+
try {
|
|
737
|
+
await runBeforeQuitCleanup();
|
|
738
|
+
} catch (error) {
|
|
739
|
+
logger.warn("before-quit handler failed", { error: toErrorMessage(error) });
|
|
740
|
+
} finally {
|
|
741
|
+
beforeQuitCleanupComplete = true;
|
|
742
|
+
beforeQuitCleanupPromise = null;
|
|
743
|
+
}
|
|
744
|
+
destroyWindowsForQuit();
|
|
745
|
+
electronApp.quit();
|
|
746
|
+
})();
|
|
747
|
+
});
|
|
748
|
+
electronApp.on("window-all-closed", () => {
|
|
522
749
|
electronApp.quit();
|
|
523
|
-
})
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
}
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
});
|
|
533
|
-
})().catch((error) => {
|
|
750
|
+
});
|
|
751
|
+
electronApp.on("activate", () => {
|
|
752
|
+
bootstrapActivationGate.activate();
|
|
753
|
+
});
|
|
754
|
+
};
|
|
755
|
+
registerApplicationLifecycle();
|
|
756
|
+
};
|
|
757
|
+
void initializeRuntime().catch((error) => {
|
|
758
|
+
rendererTraceDrain.stop();
|
|
534
759
|
logger.error("startup failed before ready", {
|
|
535
760
|
message: toErrorMessage(error),
|
|
536
761
|
stack: error instanceof Error ? error.stack : void 0
|
|
@@ -538,7 +763,9 @@ function startWoodMain(options) {
|
|
|
538
763
|
});
|
|
539
764
|
}
|
|
540
765
|
export {
|
|
766
|
+
BootstrapActivationGate,
|
|
541
767
|
resolveWoodDebugMetadataConfiguration,
|
|
768
|
+
shouldDeferLastWindowCloseForCleanup,
|
|
542
769
|
startWoodMain
|
|
543
770
|
};
|
|
544
771
|
//# sourceMappingURL=index.js.map
|