dsh-unlag 1.9.110 → 1.9.112

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.
Files changed (3) hide show
  1. package/README.md +11 -0
  2. package/index.js +39 -1
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -76,6 +76,17 @@ dsh plugin install dsh-unlag
76
76
  - 状态:`GET /dsh-unlag/state` → `{"version":"<当前版本>","code":"<index.js 写入时间>","plugins":true,"page":true,"shim":{...}}`。`code` 用来分清「版本号没刷」和「旧代码真的还在跑」。
77
77
  - 重建后的日志带起页面代次:`interface rebuilt; the page runs the plugins as served now (page <rev>)`,据此判断新文档加载的是新脚本还是旧脚本。
78
78
 
79
+ ## 改完后让运行中的 App 用上
80
+
81
+ 不用重启 App,也不用重启页面:换掉 `index.js` 后让插件的记录重载一次即可。
82
+
83
+ 1. 改版本号,并 `touch index.js client.js`。**只改版本号是不够的**:插件的装载按文件时间判断要不要重新读,时间没变就还是旧代码在跑,`/state` 里会看到版本号没变(或变了但 `code` 是旧的)。
84
+ 2. 在插件列表里把本插件关掉再打开。这两步之后 `~/.dsh/unlag-reload.log` 会出现一行新的 `dsh-unlag <版本>`。
85
+ 3. 等约 20 秒,读 `GET /dsh-unlag/state`:`version` 是新版本、`code` 是刚才 `index.js` 的写入时间,才算真的换上了。
86
+ 4. `npm run live-smoke` 对着运行中的 App 复核一遍(见下一节)。
87
+
88
+ 页面那一半(按钮点击后的重建)不在这一步里:那是按钮本人的事,只有人能按。
89
+
79
90
  ## 测试
80
91
 
81
92
  ```sh
package/index.js CHANGED
@@ -2032,7 +2032,7 @@ function serveButton(ctx, controller, config) {
2032
2032
  const disposers = []
2033
2033
  for (const [path, handler] of handlers) {
2034
2034
  try {
2035
- const dispose = server.register({ kind: 'exact', path, handler })
2035
+ const dispose = server.register({ kind: 'exact', path, handler: guardRoute(path, handler) })
2036
2036
  if (typeof dispose === 'function') disposers.push(dispose)
2037
2037
  } catch (error) {
2038
2038
  log(`cannot answer ${path}: ${error?.message ?? error}`)
@@ -2043,6 +2043,44 @@ function serveButton(ctx, controller, config) {
2043
2043
  }
2044
2044
  }
2045
2045
 
2046
+ /**
2047
+ * Nothing a route body does may reach the server as a rejection or a throw: an answer that never
2048
+ * settles is a page that waits forever, and a rejected handler can take down the request instead of
2049
+ * saying what happened. Each body already answers from its own guard; this one is the floor under
2050
+ * them, so a future edit that misses a path still costs a status rather than the answer.
2051
+ */
2052
+ export function guardRoute(path, handler) {
2053
+ /**
2054
+ * Nothing a route body does may reach the server as a rejection or a throw: an answer that never
2055
+ * settles is a page that waits forever, and a rejected handler can take the request down instead
2056
+ * of saying what happened. Each body answers from its own guard already; this is the floor under
2057
+ * them, so a future edit that misses a path costs a status rather than the answer.
2058
+ */
2059
+ return (req, res) => {
2060
+ const fallback = (error) => {
2061
+ log(`cannot answer ${path}: ${error?.message ?? error}`)
2062
+ try {
2063
+ if (res?.headersSent !== true) sendJson(res, 503, { status: 'error' })
2064
+ else if (res?.writableEnded !== true && res?.destroyed !== true) res.end()
2065
+ } catch {
2066
+ /* the response is already gone; the log line is what is left to say */
2067
+ }
2068
+ }
2069
+ try {
2070
+ const answer = handler(req, res)
2071
+ // The answer is handed back as it came: a caller that waits on the body still waits on it,
2072
+ // and the rejection is watched here as well rather than instead.
2073
+ if (answer !== null && typeof answer === 'object' && typeof answer.then === 'function') {
2074
+ answer.then(undefined, fallback)
2075
+ }
2076
+ return answer
2077
+ } catch (error) {
2078
+ fallback(error)
2079
+ return undefined
2080
+ }
2081
+ }
2082
+ }
2083
+
2046
2084
  export function apply(ctx, config) {
2047
2085
  try {
2048
2086
  const instance = {}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-unlag",
3
- "version": "1.9.110",
3
+ "version": "1.9.112",
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",