dsh-unlag 1.7.6 → 1.7.8
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/client.js +21 -0
- package/index.js +33 -3
- package/package.json +1 -1
package/client.js
CHANGED
|
@@ -115,6 +115,7 @@ window.__ModuleLoader__.load({
|
|
|
115
115
|
for (const id of source.ids) {
|
|
116
116
|
if (!body.includes(id)) return false;
|
|
117
117
|
}
|
|
118
|
+
if (!parsesAsClassicScript(body)) return false;
|
|
118
119
|
} catch {
|
|
119
120
|
return false;
|
|
120
121
|
}
|
|
@@ -125,6 +126,25 @@ window.__ModuleLoader__.load({
|
|
|
125
126
|
// Every row kind a document boot understands; an unknown one ends the document.
|
|
126
127
|
const STARTUP_ROW_KINDS = new Set(['global', 'script', 'script-src', 'script-preload', 'style', 'html']);
|
|
127
128
|
|
|
129
|
+
/**
|
|
130
|
+
* Whether a script body parses the way the document will parse it: as a classic script. A body
|
|
131
|
+
* that needs module syntax never runs, so the document that loads it fails to boot and the
|
|
132
|
+
* desktop shell ends. Compiling runs nothing, so nothing here has a side effect; a page that
|
|
133
|
+
* forbids compiling strings cannot answer, and then the checks already done stand.
|
|
134
|
+
* @param body - the served script.
|
|
135
|
+
* @returns true when the body parses, or when this page cannot compile one at all.
|
|
136
|
+
*/
|
|
137
|
+
function parsesAsClassicScript(body) {
|
|
138
|
+
try {
|
|
139
|
+
new Function(body); // eslint-disable-line no-new-func
|
|
140
|
+
return true;
|
|
141
|
+
} catch (error) {
|
|
142
|
+
const text = String(error?.message ?? error);
|
|
143
|
+
if (/unsafe-eval|Content Security Policy/iu.test(text)) return true;
|
|
144
|
+
return false;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
128
148
|
/**
|
|
129
149
|
* The startup list the desktop shell hands the next document, exactly as it hands it. The
|
|
130
150
|
* shell reads that list once when the app starts and replays the same copy for every document
|
|
@@ -195,6 +215,7 @@ window.__ModuleLoader__.load({
|
|
|
195
215
|
for (const id of bundledIds(target)) {
|
|
196
216
|
if (!body.includes(id)) return false;
|
|
197
217
|
}
|
|
218
|
+
if (!parsesAsClassicScript(body)) return false;
|
|
198
219
|
} catch {
|
|
199
220
|
return false;
|
|
200
221
|
}
|
package/index.js
CHANGED
|
@@ -535,6 +535,36 @@ function releaseBundleShim(shim) {
|
|
|
535
535
|
} catch {}
|
|
536
536
|
}
|
|
537
537
|
|
|
538
|
+
/**
|
|
539
|
+
* Wrap the bundle route unless the wrap already there is the one still on the route. The route can
|
|
540
|
+
* appear after this plugin starts and can be replaced afterwards, so every caller that is about to
|
|
541
|
+
* matter (a reload, a page asking for the graph) asks again instead of trusting an earlier answer.
|
|
542
|
+
*/
|
|
543
|
+
function ensureBundleShim(ctx) {
|
|
544
|
+
const shim = globalThis[SHIM_KEY]
|
|
545
|
+
if (shim !== null && shim !== undefined) {
|
|
546
|
+
const route = ctx.get('webServer')?.prefixes?.get?.(BUNDLE_ROUTE)
|
|
547
|
+
if (route === shim.route && route.handler === shim.wrapped && route[SHIM_MARK] === true) return shim
|
|
548
|
+
releaseBundleShim(shim)
|
|
549
|
+
globalThis[SHIM_KEY] = null
|
|
550
|
+
}
|
|
551
|
+
globalThis[SHIM_KEY] = serveBundlesAtCurrentRevision(ctx)
|
|
552
|
+
return globalThis[SHIM_KEY]
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
/** What the bundle route looks like from here, so a stale answer can be told from a missing wrap. */
|
|
556
|
+
function bundleShimStatus(ctx) {
|
|
557
|
+
const route = ctx.get('webServer')?.prefixes?.get?.(BUNDLE_ROUTE)
|
|
558
|
+
const clientModules = ctx.get('clientModules')
|
|
559
|
+
return {
|
|
560
|
+
route: route !== null && route !== undefined,
|
|
561
|
+
handler: typeof route?.handler === 'function',
|
|
562
|
+
wrapped: route?.[SHIM_MARK] === true,
|
|
563
|
+
fetch: typeof clientModules?.fetchBundle === 'function',
|
|
564
|
+
graph: typeof clientModules?.graph === 'function',
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
|
|
538
568
|
/**
|
|
539
569
|
* The entry points the header button calls. Each answers with the current switches so the page
|
|
540
570
|
* never guesses: with both off it does nothing, and a turn still running is reported rather than
|
|
@@ -552,12 +582,13 @@ function serveButton(ctx, controller, config) {
|
|
|
552
582
|
[
|
|
553
583
|
`${BASE_PATH}/state`,
|
|
554
584
|
(_req, res) => {
|
|
555
|
-
sendJson(res, 200, { plugins: settings.reloadPlugins, page: settings.reloadInterface })
|
|
585
|
+
sendJson(res, 200, { plugins: settings.reloadPlugins, page: settings.reloadInterface, shim: bundleShimStatus(ctx) })
|
|
556
586
|
},
|
|
557
587
|
],
|
|
558
588
|
[
|
|
559
589
|
`${BASE_PATH}/graph`,
|
|
560
590
|
(_req, res) => {
|
|
591
|
+
ensureBundleShim(ctx)
|
|
561
592
|
sendJson(res, 200, { graph: liveBootGraph(server) })
|
|
562
593
|
},
|
|
563
594
|
],
|
|
@@ -622,8 +653,7 @@ export function apply(ctx, config) {
|
|
|
622
653
|
* half starts, and one that appears after it.
|
|
623
654
|
*/
|
|
624
655
|
const syncBundles = () => {
|
|
625
|
-
|
|
626
|
-
globalThis[SHIM_KEY] = serveBundlesAtCurrentRevision(ctx)
|
|
656
|
+
ensureBundleShim(ctx)
|
|
627
657
|
}
|
|
628
658
|
/** Watching needs HMR; start as soon as it exists, drop the watcher when it goes away. */
|
|
629
659
|
const syncWatching = () => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-unlag",
|
|
3
|
-
"version": "1.7.
|
|
3
|
+
"version": "1.7.8",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "One press applies plugin edits right away and brings a laggy interface back; running turns, queued messages and unsent input are untouched, and nothing restarts.",
|
|
6
6
|
"license": "MIT",
|