dsh-mobile-plugin 0.1.60 → 0.1.62

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/lib/index.js CHANGED
@@ -15,11 +15,16 @@
15
15
  * 这一层同时是**故障边界**:代装载失败时外壳回滚到上一代并把错误暴露出去,而不是让整个
16
16
  * 插件从宿主里消失(那会让手机连不上,且日志里只剩一行 pending)。
17
17
  *
18
- * ## 更新从哪儿来(2026-10 改)
18
+ * ## 更新从哪儿来(2026-10 改,2026-10-11 再分一刀)
19
19
  *
20
- * 分发交给 DSH 插件市场:它在 profile 里跑 pnpm,装完会把 `<profile>/node_modules/
21
- * dsh-mobile-plugin` 指向一个新的 store 目录。外壳照着新 realpath 重新 import 一代即可,
22
- * **不需要重启 DSH**。自动更新(默认关)按 `AUTO_INTERVAL_MS` 轮询,见 `shell/updater.js`。
20
+ * **查与装都归实现自己**:查直接问 npm 注册表、装在 profile 里跑它自己的包管理器
21
+ * (`lib/update-registry.cjs` / `lib/update-install.cjs`),市场不再是这条路上的任何一环。
22
+ * 装完会把 `<profile>/node_modules/dsh-mobile-plugin` 指向一个新的 store 目录,外壳照着新
23
+ * realpath 重新 import 一代即可,**不需要重启 DSH**。自动更新(默认关)按 `AUTO_INTERVAL_MS`
24
+ * 轮询,见 `shell/updater.js`。
25
+ *
26
+ * 这里那个 `updateState` 对象记的是「最近一次查/装的结果」。名字里别再叫 market:里面那份
27
+ * 市场信息(`marketResult`)只是外壳从市场那条老路继承下来的兜底,装的时候用不到它。
23
28
  */
24
29
 
25
30
  import path from 'node:path'
@@ -32,7 +37,7 @@ export const name = 'dsh-mobile-plugin'
32
37
  export const inject = ['webServer', 'sessions']
33
38
 
34
39
  /**
35
- * 装载当前代,并把「问市场 / 换代码」这套动作暴露成服务。
40
+ * 装载当前代,并把「查 / 装 / 换代码」这套动作暴露成服务。
36
41
  *
37
42
  * 对照 `lib/impl.js` 的 `apply`:那边签名也是 `(ctx)`,只是它注册的是真正的移动 API;
38
43
  * 这里注册的是「装载它」。两者的 effect 各自归属自己那层 fiber —— 外壳被卸载时,代的
@@ -42,7 +47,7 @@ export function apply(ctx) {
42
47
  const runtime = createRuntime()
43
48
  // 跑着的外壳的指纹。它必须在**启动时**算:之后盘上那份可能已经被市场换掉了。
44
49
  const runningShellHash = updater.shellFingerprint(path.dirname(path.dirname(fileURLToPath(import.meta.url))))
45
- const market = {
50
+ const updateState = {
46
51
  checking: false,
47
52
  lastCheckedAt: null,
48
53
  lastError: null,
@@ -55,32 +60,43 @@ export function apply(ctx) {
55
60
  const fn = ctx.logger?.[level]
56
61
  if (typeof fn === 'function') fn.call(ctx.logger, message, ...rest)
57
62
  }
63
+ /** 取一个宿主服务,拿不到就当没有(更新的两道判据都要它,缺了只降级、不抛)。 */
64
+ const hostService = key => {
65
+ try { return typeof ctx.get === 'function' ? ctx.get(key) ?? null : null } catch { return null }
66
+ }
58
67
 
59
68
  /** 查一次有没有新版。只记结果,装不装由开关或人来决定。 */
60
69
  async function check({ force = false } = {}) {
61
- if (market.checking) return market.result
62
- market.checking = true
70
+ if (updateState.checking) return updateState.result
71
+ updateState.checking = true
63
72
  try {
64
- market.result = await updater.checkUpdate(base())
65
- market.lastError = null
73
+ updateState.result = await updater.checkUpdate(base())
74
+ updateState.lastError = null
66
75
  } catch (error) {
67
- market.result = null
68
- market.lastError = String(error?.message || error)
76
+ updateState.result = null
77
+ updateState.lastError = String(error?.message || error)
69
78
  } finally {
70
- market.checking = false
71
- market.lastCheckedAt = new Date().toISOString()
79
+ updateState.checking = false
80
+ updateState.lastCheckedAt = new Date().toISOString()
72
81
  }
73
- return market.result
82
+ return updateState.result
74
83
  }
75
84
 
76
85
  /**
77
- * 请市场装新版,装完**就地换代**。
86
+ * 装新版(实现自己装,见 `shell/updater.js`),装完**就地换代**。
78
87
  *
79
- * 手动与自动走的是同一条路:手动只是「现在就做一次」。市场报的 `restartRequired` 一律
88
+ * 手动与自动走的是同一条路:手动只是「现在就做一次」。装的那一步报的 `restartRequired` 一律
80
89
  * 不照做 —— 外壳自己换代码,这正是这个文件存在的全部理由。
81
90
  */
82
91
  async function applyUpdate({ force = false } = {}) {
83
- const outcome = await updater.installIfNeeded(base(), { force })
92
+ const outcome = await updater.installIfNeeded(base(), {
93
+ force,
94
+ // 宿主发布的包管理器优先(PATH 上那个的版本可能和 profile 的 store 对不上,实测
95
+ // 10.x 装 11.x 的 profile 直接 `ERR_PNPM_UNEXPECTED_STORE`);agents 是「有对话在跑
96
+ // 就别换文件」那道闸的判据。自动更新永远不带 force。
97
+ packageManager: () => hostService('profileContext')?.packageManager ?? null,
98
+ agents: () => hostService('agents'),
99
+ })
84
100
  let swapped = false
85
101
  let status = runtime.status()
86
102
  if (outcome.installed) {
@@ -90,9 +106,9 @@ export function apply(ctx) {
90
106
  } else if (outcome.state && outcome.state !== 'succeeded') {
91
107
  log('warn', 'dsh-mobile-plugin: 更新没有成功(%s)%s', outcome.state, outcome.failure?.message || '')
92
108
  }
93
- market.lastApply = { ...outcome, swapped }
94
- market.appliedAt = new Date().toISOString()
95
- if (outcome.installed) market.lastError = null
109
+ updateState.lastApply = { ...outcome, swapped }
110
+ updateState.appliedAt = new Date().toISOString()
111
+ if (outcome.installed) updateState.lastError = null
96
112
  return { ...outcome, swapped, status }
97
113
  }
98
114
 
@@ -128,11 +144,11 @@ export function apply(ctx) {
128
144
  autoUpdate: updater.autoUpdateEnabled(),
129
145
  autoIntervalMs: updater.AUTO_INTERVAL_MS,
130
146
  marketBase: base(),
131
- marketLastCheckedAt: market.lastCheckedAt,
132
- marketLastError: market.lastError,
133
- marketResult: market.result,
134
- lastApply: market.lastApply,
135
- appliedAt: market.appliedAt,
147
+ marketLastCheckedAt: updateState.lastCheckedAt,
148
+ marketLastError: updateState.lastError,
149
+ marketResult: updateState.result,
150
+ lastApply: updateState.lastApply,
151
+ appliedAt: updateState.appliedAt,
136
152
  }),
137
153
  check,
138
154
  apply: applyUpdate,
@@ -148,12 +164,12 @@ export function apply(ctx) {
148
164
  .start(ctx)
149
165
  .then(() => {
150
166
  log('info', 'dsh-mobile-plugin: 已装载 %s(来源 %s)', runtime.status().version, runtime.status().source)
151
- // 自动更新:默认关。开了才轮询;每次都是「问市场 → 装 → 就地换代」。
167
+ // 自动更新:默认关。开了才轮询;每次都是「查一次 → 有新版就自己装 → 就地换代」。
152
168
  const timer = setInterval(() => {
153
169
  if (!updater.autoUpdateEnabled()) return
154
170
  applyUpdate().catch(error => {
155
- market.lastError = String(error?.message || error)
156
- log('warn', 'dsh-mobile-plugin: 自动更新失败:%s', market.lastError)
171
+ updateState.lastError = String(error?.message || error)
172
+ log('warn', 'dsh-mobile-plugin: 自动更新失败:%s', updateState.lastError)
157
173
  })
158
174
  }, updater.AUTO_INTERVAL_MS)
159
175
  if (typeof timer.unref === 'function') timer.unref()
@@ -162,8 +178,8 @@ export function apply(ctx) {
162
178
  if (updater.autoUpdateEnabled()) {
163
179
  const kick = setTimeout(() => {
164
180
  applyUpdate().catch(error => {
165
- market.lastError = String(error?.message || error)
166
- log('warn', 'dsh-mobile-plugin: 启动时的自动更新失败:%s', market.lastError)
181
+ updateState.lastError = String(error?.message || error)
182
+ log('warn', 'dsh-mobile-plugin: 启动时的自动更新失败:%s', updateState.lastError)
167
183
  })
168
184
  }, 10000)
169
185
  if (typeof kick.unref === 'function') kick.unref()