@workbench-kit/electron-shell 0.0.2-prototype.0.2.32 → 0.0.2-prototype.0.2.33
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/README.md
CHANGED
|
@@ -71,16 +71,22 @@ electronApp.on('before-quit', (event) => {
|
|
|
71
71
|
```
|
|
72
72
|
|
|
73
73
|
Repeated quit events are coalesced into the active request. After save or discard,
|
|
74
|
-
the guard rechecks dirty state and resumes only when clean.
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
74
|
+
the guard rechecks dirty state and resumes only when clean. It invokes `resumeQuit`
|
|
75
|
+
on the next event-loop task so Electron can finish dispatching the original
|
|
76
|
+
`before-quit` event first. Errors, timeout, and a still-dirty recheck fail closed.
|
|
77
|
+
`cancelPending()` aborts an obsolete request and invalidates any late guard
|
|
78
|
+
completion; call it when the owning lifecycle is replaced. A callback that has
|
|
79
|
+
already started must honor its `AbortSignal` to stop its own side effects.
|
|
79
80
|
The injected `resumeQuit` port must re-enter the registered guard synchronously;
|
|
80
81
|
an asynchronous wrapper is treated as a fresh request. OS shutdown paths that do
|
|
81
82
|
not emit `before-quit`, and updater flows that emit it after windows close, remain
|
|
82
83
|
host-owned lifecycle concerns outside this guard.
|
|
83
84
|
|
|
85
|
+
The repository also runs `pnpm test:electron-quit-guard` against Electron 41.5
|
|
86
|
+
with a live `BrowserWindow`. It verifies the deferred save path, a coalesced quit
|
|
87
|
+
attempt before the scheduled resume, and the normal window-close / application-quit
|
|
88
|
+
lifecycle after the permitted re-entry.
|
|
89
|
+
|
|
84
90
|
For external links, keep the product allowlist outside the Kit and pass only an
|
|
85
91
|
opaque link id into the generic helper:
|
|
86
92
|
|
|
@@ -38,6 +38,11 @@ function raceWithAbort(operation, signal, readAbortKind) {
|
|
|
38
38
|
});
|
|
39
39
|
});
|
|
40
40
|
}
|
|
41
|
+
function waitForNextTask() {
|
|
42
|
+
return new Promise((resolve) => {
|
|
43
|
+
setTimeout(resolve, 0);
|
|
44
|
+
});
|
|
45
|
+
}
|
|
41
46
|
/**
|
|
42
47
|
* Coordinate an Electron-style before-quit boundary without importing Electron.
|
|
43
48
|
* The host owns event registration, dirty state, prompts, persistence, and quit invocation.
|
|
@@ -76,7 +81,10 @@ function createApplicationQuitGuard(options) {
|
|
|
76
81
|
}
|
|
77
82
|
return resume(reason);
|
|
78
83
|
};
|
|
79
|
-
const resume = (reason) => {
|
|
84
|
+
const resume = async (reason) => {
|
|
85
|
+
// A Promise continuation can still run before Electron finishes dispatching the original
|
|
86
|
+
// before-quit event. Cross a task boundary before re-entering app.quit().
|
|
87
|
+
await run(waitForNextTask);
|
|
80
88
|
// The decision is now irreversible. `cancelPending` must not report a cancellable request
|
|
81
89
|
// while the host is synchronously re-entering before-quit.
|
|
82
90
|
if (isCurrent()) {
|
|
@@ -99,7 +107,7 @@ function createApplicationQuitGuard(options) {
|
|
|
99
107
|
throw new TypeError('Application quit guard isDirty must return a boolean.');
|
|
100
108
|
}
|
|
101
109
|
if (!dirty) {
|
|
102
|
-
return resume('clean');
|
|
110
|
+
return await resume('clean');
|
|
103
111
|
}
|
|
104
112
|
const decision = await run(() => options.requestDecision(controller.signal));
|
|
105
113
|
if (decision === 'cancel') {
|
package/package.json
CHANGED
|
@@ -109,6 +109,12 @@ function raceWithAbort<Value>(
|
|
|
109
109
|
});
|
|
110
110
|
}
|
|
111
111
|
|
|
112
|
+
function waitForNextTask(): Promise<void> {
|
|
113
|
+
return new Promise((resolve) => {
|
|
114
|
+
setTimeout(resolve, 0);
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
|
|
112
118
|
/**
|
|
113
119
|
* Coordinate an Electron-style before-quit boundary without importing Electron.
|
|
114
120
|
* The host owns event registration, dirty state, prompts, persistence, and quit invocation.
|
|
@@ -158,7 +164,13 @@ export function createApplicationQuitGuard(
|
|
|
158
164
|
return resume(reason);
|
|
159
165
|
};
|
|
160
166
|
|
|
161
|
-
const resume = (
|
|
167
|
+
const resume = async (
|
|
168
|
+
reason: ApplicationQuitProceedReason,
|
|
169
|
+
): Promise<ApplicationQuitGuardResult> => {
|
|
170
|
+
// A Promise continuation can still run before Electron finishes dispatching the original
|
|
171
|
+
// before-quit event. Cross a task boundary before re-entering app.quit().
|
|
172
|
+
await run(waitForNextTask);
|
|
173
|
+
|
|
162
174
|
// The decision is now irreversible. `cancelPending` must not report a cancellable request
|
|
163
175
|
// while the host is synchronously re-entering before-quit.
|
|
164
176
|
if (isCurrent()) {
|
|
@@ -181,7 +193,7 @@ export function createApplicationQuitGuard(
|
|
|
181
193
|
throw new TypeError('Application quit guard isDirty must return a boolean.');
|
|
182
194
|
}
|
|
183
195
|
if (!dirty) {
|
|
184
|
-
return resume('clean');
|
|
196
|
+
return await resume('clean');
|
|
185
197
|
}
|
|
186
198
|
|
|
187
199
|
const decision = await run(() => options.requestDecision(controller.signal));
|