dsh-unlag 1.9.24 → 1.9.26
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 +1 -0
- package/index.js +40 -7
- package/package.json +1 -1
package/client.js
CHANGED
|
@@ -245,6 +245,7 @@ window.__ModuleLoader__.load({
|
|
|
245
245
|
network: 'script', // ui-copy-ignore
|
|
246
246
|
parse: 'parse', // ui-copy-ignore
|
|
247
247
|
register: 'plugin', // ui-copy-ignore
|
|
248
|
+
slow: 'script', // ui-copy-ignore
|
|
248
249
|
dependencies: 'covers',
|
|
249
250
|
list: 'list', // ui-copy-ignore
|
|
250
251
|
};
|
package/index.js
CHANGED
|
@@ -92,6 +92,12 @@ const MAX_STARTUP_ROW_CHARS = 4096
|
|
|
92
92
|
* is work the request itself must not be able to grow without bound.
|
|
93
93
|
*/
|
|
94
94
|
const MAX_BUNDLE_IDS = 128
|
|
95
|
+
/**
|
|
96
|
+
* How long one startup check may spend reading the list. Each address is bounded on its own, but a
|
|
97
|
+
* list of them is not: dozens of slow addresses would otherwise hold a press past the moment the
|
|
98
|
+
* page gives up waiting, and the person would see a button that did nothing.
|
|
99
|
+
*/
|
|
100
|
+
const MAX_VERIFY_MS = 9000
|
|
95
101
|
const MIN_INTERVAL_MS = 1500
|
|
96
102
|
/** The route the app publishes client bundles under; the same key the module table registers. */
|
|
97
103
|
const BUNDLE_ROUTE = '/plugins'
|
|
@@ -893,14 +899,34 @@ function currentBundleUrls(graph, request) {
|
|
|
893
899
|
*/
|
|
894
900
|
async function fetchBundleAt(clientModules, url, method) {
|
|
895
901
|
const address = `http://unlag.invalid${url}`
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
902
|
+
/**
|
|
903
|
+
* A table that accepts the question and then never answers would hold the request that asked it:
|
|
904
|
+
* the document waits on this script and the page stops. The wait is bounded, and a table that
|
|
905
|
+
* misses it is answered the same way as one that fails.
|
|
906
|
+
*/
|
|
907
|
+
const limit = Number(process.env.DSH_UNLAG_FETCH_TIMEOUT_MS ?? '') > 0 ? Number(process.env.DSH_UNLAG_FETCH_TIMEOUT_MS) : 8000
|
|
908
|
+
let timer = null
|
|
909
|
+
const late = new Promise((_, reject) => {
|
|
910
|
+
timer = setTimeout(() => reject(new Error('the module table did not answer in time')), limit)
|
|
911
|
+
})
|
|
912
|
+
const asked = (async () => {
|
|
913
|
+
if (typeof Request === 'function') {
|
|
914
|
+
try {
|
|
915
|
+
return await clientModules.fetchBundle(new Request(address, { method, headers: {} }))
|
|
916
|
+
} catch (error) {
|
|
917
|
+
if (error?.name !== 'TypeError') throw error
|
|
918
|
+
}
|
|
901
919
|
}
|
|
920
|
+
return clientModules.fetchBundle({ method, url: address })
|
|
921
|
+
})()
|
|
922
|
+
// Whichever side loses the race must still be observed, or its rejection ends the process.
|
|
923
|
+
asked.catch(() => {})
|
|
924
|
+
late.catch(() => {})
|
|
925
|
+
try {
|
|
926
|
+
return await Promise.race([asked, late])
|
|
927
|
+
} finally {
|
|
928
|
+
if (timer !== null) clearTimeout(timer)
|
|
902
929
|
}
|
|
903
|
-
return clientModules.fetchBundle({ method, url: address })
|
|
904
930
|
}
|
|
905
931
|
|
|
906
932
|
/**
|
|
@@ -1397,7 +1423,7 @@ function parseAsScript(body, name) {
|
|
|
1397
1423
|
* @param fetchBody reads one script address and answers a response-like, or null when it cannot.
|
|
1398
1424
|
* @param rows the startup script addresses, as the next document would request them.
|
|
1399
1425
|
*/
|
|
1400
|
-
export async function verifyStartupRows(graph, fetchBody, rows) {
|
|
1426
|
+
export async function verifyStartupRows(graph, fetchBody, rows, budgetMs = MAX_VERIFY_MS) {
|
|
1401
1427
|
const entries = new Map(
|
|
1402
1428
|
(Array.isArray(graph?.entries) ? graph.entries : [])
|
|
1403
1429
|
.filter((row) => typeof row?.id === 'string' && row.id !== '')
|
|
@@ -1427,7 +1453,11 @@ export async function verifyStartupRows(graph, fetchBody, rows) {
|
|
|
1427
1453
|
const leftOut = new Set()
|
|
1428
1454
|
const listed = new Set()
|
|
1429
1455
|
const bodies = []
|
|
1456
|
+
const began = Date.now()
|
|
1430
1457
|
for (const item of wanted) {
|
|
1458
|
+
if (Date.now() - began > budgetMs) {
|
|
1459
|
+
return { status: 'blocked', reason: 'slow', detail: 'the startup list took longer than this check waits' }
|
|
1460
|
+
}
|
|
1431
1461
|
for (const id of item.ids) if (served.has(id)) listed.add(id)
|
|
1432
1462
|
for (const id of item.ids) if (!served.has(id)) leftOut.add(id)
|
|
1433
1463
|
let response = null
|
|
@@ -1575,6 +1605,9 @@ function serveButton(ctx, controller, config) {
|
|
|
1575
1605
|
} catch (error) {
|
|
1576
1606
|
verdict = { status: 'blocked', reason: 'list', detail: String(error?.message ?? error) }
|
|
1577
1607
|
}
|
|
1608
|
+
if (verdict?.status !== 'ok') {
|
|
1609
|
+
log(`a startup check refused the page: ${String(verdict?.reason ?? 'list')} (${String(verdict?.detail ?? 'no detail')})`)
|
|
1610
|
+
}
|
|
1578
1611
|
if (Array.isArray(verdict?.leftOut) && verdict.leftOut.length > 0) {
|
|
1579
1612
|
log(`a startup row names a plugin this app no longer serves: ${verdict.leftOut.join(', ')}; the page comes up without it`)
|
|
1580
1613
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-unlag",
|
|
3
|
-
"version": "1.9.
|
|
3
|
+
"version": "1.9.26",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "A press applies plugin edits right away and brings a laggy interface back; automatic reloading stays off unless you turn it on, so the press is the only trigger, and nothing restarts.",
|
|
6
6
|
"license": "MIT",
|