dsh-unlag 1.9.14 → 1.9.16
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 +2 -1
- package/index.js +26 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -68,7 +68,8 @@ dsh plugin install dsh-unlag
|
|
|
68
68
|
## 排错
|
|
69
69
|
|
|
70
70
|
- 日志:`~/.dsh/unlag-reload.log`,换代码/跳过/被拦各一行,含原因。
|
|
71
|
-
- 状态:`GET /dsh-unlag/state` → `{"plugins":true,"page":true,"shim":{...}}
|
|
71
|
+
- 状态:`GET /dsh-unlag/state` → `{"version":"1.9.14","code":"<index.js 写入时间>","plugins":true,"page":true,"shim":{...}}`。`code` 用来分清「版本号没刷」和「旧代码真的还在跑」。
|
|
72
|
+
- 重建后的日志带起页面代次:`interface rebuilt; the page runs the plugins as served now (page <rev>)`,据此判断新文档加载的是新脚本还是旧脚本。
|
|
72
73
|
|
|
73
74
|
## 测试
|
|
74
75
|
|
package/index.js
CHANGED
|
@@ -83,6 +83,8 @@ const TEST_PATH = /(^|\/)(test|tests|__tests__|__mocks__)(\/|$)|[.-](test|spec)\
|
|
|
83
83
|
const DEFAULT_ROOTS = [join(homedir(), '.dsh', 'plugins')]
|
|
84
84
|
/** A turn that never goes idle must not turn this into an endless poll. */
|
|
85
85
|
const MAX_DEFERRALS = 40
|
|
86
|
+
const MAX_STARTUP_ROWS = 64
|
|
87
|
+
const MAX_STARTUP_ROW_CHARS = 4096
|
|
86
88
|
const MIN_INTERVAL_MS = 1500
|
|
87
89
|
/** The route the app publishes client bundles under; the same key the module table registers. */
|
|
88
90
|
const BUNDLE_ROUTE = '/plugins'
|
|
@@ -1131,6 +1133,7 @@ function serveBundlesAtCurrentRevision(ctx) {
|
|
|
1131
1133
|
const ask = async (url) => {
|
|
1132
1134
|
let held = null
|
|
1133
1135
|
let body
|
|
1136
|
+
let failed = false
|
|
1134
1137
|
if (url !== originalUrl) {
|
|
1135
1138
|
try {
|
|
1136
1139
|
req.url = url
|
|
@@ -1159,6 +1162,7 @@ function serveBundlesAtCurrentRevision(ctx) {
|
|
|
1159
1162
|
try {
|
|
1160
1163
|
await Promise.resolve(original(req, res))
|
|
1161
1164
|
} catch (error) {
|
|
1165
|
+
failed = true
|
|
1162
1166
|
log(`cannot answer a bundle request: ${error?.message ?? error}`)
|
|
1163
1167
|
} finally {
|
|
1164
1168
|
try {
|
|
@@ -1168,12 +1172,26 @@ function serveBundlesAtCurrentRevision(ctx) {
|
|
|
1168
1172
|
/* the response object owns its own shape */
|
|
1169
1173
|
}
|
|
1170
1174
|
}
|
|
1171
|
-
return { held, body }
|
|
1175
|
+
return { held, body, failed }
|
|
1172
1176
|
}
|
|
1173
1177
|
// The table's own answer first: it still holds the generation this page booted from.
|
|
1174
1178
|
let outcome = await ask(originalUrl)
|
|
1175
1179
|
if (outcome.held !== null && retargeted !== null) outcome = await ask(retargeted)
|
|
1176
|
-
if (outcome.held === null)
|
|
1180
|
+
if (outcome.held === null) {
|
|
1181
|
+
/**
|
|
1182
|
+
* The table started writing and then failed. A body that already sent its status cannot take
|
|
1183
|
+
* another one, and a socket left open is a document that waits for a script forever; ending it
|
|
1184
|
+
* lets the page see the failure and carry on.
|
|
1185
|
+
*/
|
|
1186
|
+
if (outcome.failed === true) {
|
|
1187
|
+
try {
|
|
1188
|
+
if (res.headersSent === true && res.writableEnded !== true && res.destroyed !== true) realEnd.call(res)
|
|
1189
|
+
} catch {
|
|
1190
|
+
/* the response is gone; nothing left to answer */
|
|
1191
|
+
}
|
|
1192
|
+
}
|
|
1193
|
+
return undefined
|
|
1194
|
+
}
|
|
1177
1195
|
// The shim resolves the set from the address the page asked for, not the retried one.
|
|
1178
1196
|
try {
|
|
1179
1197
|
req.url = originalUrl
|
|
@@ -1323,9 +1341,14 @@ export async function verifyStartupRows(graph, fetchBody, rows) {
|
|
|
1323
1341
|
.filter((row) => typeof row?.id === 'string' && row.id !== '')
|
|
1324
1342
|
.map((row) => [row.id, row]),
|
|
1325
1343
|
)
|
|
1344
|
+
// A startup list is a handful of addresses. Anything past that bound is not a list this app could
|
|
1345
|
+
// boot from, and reading it would turn one request into unbounded work on the process that owns
|
|
1346
|
+
// every running turn.
|
|
1347
|
+
const offered = Array.isArray(rows) ? rows.slice(0, MAX_STARTUP_ROWS) : []
|
|
1326
1348
|
const wanted = []
|
|
1327
|
-
for (const row of
|
|
1349
|
+
for (const row of offered) {
|
|
1328
1350
|
if (typeof row !== 'string' || row === '') continue
|
|
1351
|
+
if (row.length > MAX_STARTUP_ROW_CHARS) continue
|
|
1329
1352
|
const path = row.includes('://') ? row.replace(/^[a-z]+:\/\/[^/]+/iu, '') : row
|
|
1330
1353
|
const url = path.startsWith('/') ? path : `/${path.replace(/^\.?\//u, '')}`
|
|
1331
1354
|
const request = bundleRequest(url)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-unlag",
|
|
3
|
-
"version": "1.9.
|
|
3
|
+
"version": "1.9.16",
|
|
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",
|