dsh-unlag 1.9.114 → 1.9.116
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/index.js +38 -10
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -100,15 +100,19 @@ const MAX_STARTUP_ROW_CHARS = 8192
|
|
|
100
100
|
* The largest one startup script may be before a check refuses it. The app serves a whole profile as
|
|
101
101
|
* a few bundles, and those grow with every installed plugin: one profile's largest bundle measured
|
|
102
102
|
* 8.7 MB, which a smaller bound refused as if it were an attack and left the page unrebuildable.
|
|
103
|
-
*
|
|
104
|
-
*
|
|
103
|
+
* Compiling a body costs several times its size in memory before it is thrown away, and up to three
|
|
104
|
+
* checks may run at once, so the bound is set close to what a profile actually serves: this one
|
|
105
|
+
* measured 15.7 MB across three bundles, its largest 9.2 MB. A body past 24 MB is not a profile
|
|
106
|
+
* this app ships with, and reading one would let a request make the process that owns every running
|
|
107
|
+
* turn hold text no page boots from.
|
|
105
108
|
*/
|
|
106
|
-
const MAX_SCRIPT_BYTES =
|
|
109
|
+
const MAX_SCRIPT_BYTES = 24 * 1024 * 1024
|
|
107
110
|
/**
|
|
108
|
-
* The same bound for one whole startup list, so a list of large bodies cannot add up either.
|
|
109
|
-
*
|
|
111
|
+
* The same bound for one whole startup list, so a list of large bodies cannot add up either. Two
|
|
112
|
+
* measured profiles' worth: what a check keeps per body is the ids it names, never its text, so
|
|
113
|
+
* the whole list's transient text is what this bounds.
|
|
110
114
|
*/
|
|
111
|
-
const MAX_TOTAL_SCRIPT_BYTES =
|
|
115
|
+
const MAX_TOTAL_SCRIPT_BYTES = 48 * 1024 * 1024
|
|
112
116
|
/**
|
|
113
117
|
* How large the request that carries the list may be. The list itself is bounded (64 addresses of at
|
|
114
118
|
* most 8 KB, plus JSON escaping), so a bound below that would refuse a sound startup list from a
|
|
@@ -1710,11 +1714,14 @@ export async function verifyStartupRows(graph, fetchBody, rows, budgetMs = MAX_V
|
|
|
1710
1714
|
for (const id of item.ids) if (served.has(id)) listed.add(id)
|
|
1711
1715
|
for (const id of item.ids) if (!served.has(id)) leftOut.add(id)
|
|
1712
1716
|
let response = null
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
+
const read = await withDeadline(() => fetchBody(item.url), budgetMs - (Date.now() - began))
|
|
1718
|
+
if (read.timedOut === true) {
|
|
1719
|
+
return { status: 'blocked', reason: 'slow', detail: `${item.url} did not answer within the time this check waits` }
|
|
1720
|
+
}
|
|
1721
|
+
if ('error' in read) {
|
|
1722
|
+
return { status: 'blocked', reason: 'network', detail: `${item.url}: ${String(read.error?.message ?? read.error)}` }
|
|
1717
1723
|
}
|
|
1724
|
+
response = read.value
|
|
1718
1725
|
// Reading the answer is the same kind of step as fetching it: a response whose status or body
|
|
1719
1726
|
// cannot be read is one this check cannot approve, and saying which script failed beats
|
|
1720
1727
|
// abandoning the whole list without a name in the reason.
|
|
@@ -1822,6 +1829,27 @@ export async function verifyStartup(clientModules, rows) {
|
|
|
1822
1829
|
return verifyStartupRows(graph, (url) => readStartupScript(clientModules, url), rows)
|
|
1823
1830
|
}
|
|
1824
1831
|
|
|
1832
|
+
/** The sentinel a read that ran past its time resolves to: a value, never an error. */
|
|
1833
|
+
const LATE = Symbol('late')
|
|
1834
|
+
|
|
1835
|
+
/**
|
|
1836
|
+
* One read the check will not wait past. The budget is counted between rows already; a single
|
|
1837
|
+
* address that never answers would otherwise hold the press past the moment the page stops waiting
|
|
1838
|
+
* for it, and the page would be told the check timed out with nothing naming what hung. Racing the
|
|
1839
|
+
* read keeps the reason the check's own, and the read itself is left to finish with its bytes
|
|
1840
|
+
* dropped, so nothing is left half-read.
|
|
1841
|
+
*/
|
|
1842
|
+
async function withDeadline(work, ms) {
|
|
1843
|
+
let timer = null
|
|
1844
|
+
const late = new Promise((resolve) => {
|
|
1845
|
+
timer = setTimeout(() => resolve(LATE), Math.max(0, ms))
|
|
1846
|
+
})
|
|
1847
|
+
const settled = Promise.resolve().then(work).then((value) => ({ value }), (error) => ({ error }))
|
|
1848
|
+
const answer = await Promise.race([settled, late])
|
|
1849
|
+
if (timer !== null) clearTimeout(timer)
|
|
1850
|
+
return answer === LATE ? { timedOut: true } : answer
|
|
1851
|
+
}
|
|
1852
|
+
|
|
1825
1853
|
/** What one press is told when the update it waits for did not answer in time. */
|
|
1826
1854
|
const STILL_APPLYING = Object.freeze({ status: 'applying', warnings: [], pending: [], restartReason: null, failedEntries: [] });
|
|
1827
1855
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-unlag",
|
|
3
|
-
"version": "1.9.
|
|
3
|
+
"version": "1.9.116",
|
|
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",
|