@linxin666/dsh-remote-web-ui 0.1.20 → 0.2.1

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 (126) hide show
  1. package/README.i18n.yaml +2 -2
  2. package/README.md +56 -26
  3. package/README.zh.md +20 -15
  4. package/assets/mobile-icon-192.png +0 -0
  5. package/assets/mobile-icon-512.png +0 -0
  6. package/assets/mobile-service-worker.js +64 -0
  7. package/lib/client.js +272 -47
  8. package/lib/client.js.map +1 -1
  9. package/lib/index.js +316 -60
  10. package/lib/mobile.js +487 -56
  11. package/lib/mobile.js.map +1 -1
  12. package/lib/types/client/PluginSettingsCard.d.ts +28 -0
  13. package/lib/types/client/PluginSettingsCard.d.ts.map +1 -1
  14. package/lib/types/client/PluginSettingsCard.js +147 -6
  15. package/lib/types/client/RemoteEntry.d.ts.map +1 -1
  16. package/lib/types/client/RemoteEntry.js +13 -2
  17. package/lib/types/client/RemoteSettingsCard.d.ts +2 -2
  18. package/lib/types/client/RemoteSettingsCard.d.ts.map +1 -1
  19. package/lib/types/client/RemoteSettingsCard.js +1 -1
  20. package/lib/types/client/UpdateEntry.d.ts.map +1 -1
  21. package/lib/types/client/UpdateEntry.js +36 -3
  22. package/lib/types/client/UpdatePanel.d.ts.map +1 -1
  23. package/lib/types/client/UpdatePanel.js +2 -2
  24. package/lib/types/client/deep-link.js +1 -1
  25. package/lib/types/client/locales.d.ts +4 -0
  26. package/lib/types/client/locales.d.ts.map +1 -1
  27. package/lib/types/client/locales.js +4 -0
  28. package/lib/types/gate.d.ts +9 -0
  29. package/lib/types/gate.d.ts.map +1 -1
  30. package/lib/types/gate.js +17 -4
  31. package/lib/types/index.d.ts +25 -0
  32. package/lib/types/index.d.ts.map +1 -1
  33. package/lib/types/index.js +30 -13
  34. package/lib/types/mobile/PairRequiredView.d.ts +7 -0
  35. package/lib/types/mobile/PairRequiredView.d.ts.map +1 -0
  36. package/lib/types/mobile/PairRequiredView.js +28 -0
  37. package/lib/types/mobile/PairRequiredView.test.d.ts +2 -0
  38. package/lib/types/mobile/PairRequiredView.test.d.ts.map +1 -0
  39. package/lib/types/mobile/PairRequiredView.test.js +24 -0
  40. package/lib/types/mobile/api.d.ts +10 -0
  41. package/lib/types/mobile/api.d.ts.map +1 -1
  42. package/lib/types/mobile/api.js +4 -0
  43. package/lib/types/mobile/index.js +14 -1
  44. package/lib/types/mobile/messages.d.ts +24 -0
  45. package/lib/types/mobile/messages.d.ts.map +1 -1
  46. package/lib/types/mobile/messages.js +60 -23
  47. package/lib/types/mobile/messages.test.js +49 -1
  48. package/lib/types/mobile/mobile-styles.d.ts +1 -1
  49. package/lib/types/mobile/mobile-styles.d.ts.map +1 -1
  50. package/lib/types/mobile/mobile-styles.js +86 -0
  51. package/lib/types/mobile/pairing.d.ts +31 -0
  52. package/lib/types/mobile/pairing.d.ts.map +1 -0
  53. package/lib/types/mobile/pairing.js +62 -0
  54. package/lib/types/mobile/views/App.d.ts +12 -5
  55. package/lib/types/mobile/views/App.d.ts.map +1 -1
  56. package/lib/types/mobile/views/App.js +34 -7
  57. package/lib/types/mobile/views/App.test.d.ts +2 -0
  58. package/lib/types/mobile/views/App.test.d.ts.map +1 -0
  59. package/lib/types/mobile/views/App.test.js +52 -0
  60. package/lib/types/mobile/views/ChatView.d.ts.map +1 -1
  61. package/lib/types/mobile/views/ChatView.js +34 -11
  62. package/lib/types/mobile/views/SessionListView.d.ts.map +1 -1
  63. package/lib/types/mobile/views/SessionListView.js +30 -4
  64. package/lib/types/mobile/views/SessionListView.test.js +58 -1
  65. package/lib/types/mobile/views/WorkspaceView.d.ts.map +1 -1
  66. package/lib/types/mobile/views/WorkspaceView.js +4 -2
  67. package/lib/types/mobile-api.d.ts.map +1 -1
  68. package/lib/types/mobile-api.js +10 -1
  69. package/lib/types/mobile-pwa.d.ts +6 -0
  70. package/lib/types/mobile-pwa.d.ts.map +1 -0
  71. package/lib/types/mobile-pwa.js +17 -0
  72. package/lib/types/mobile-routes.d.ts +5 -8
  73. package/lib/types/mobile-routes.d.ts.map +1 -1
  74. package/lib/types/mobile-routes.js +115 -30
  75. package/lib/types/pairing-access.d.ts +28 -0
  76. package/lib/types/pairing-access.d.ts.map +1 -0
  77. package/lib/types/pairing-access.js +26 -0
  78. package/lib/types/pairing.d.ts +27 -0
  79. package/lib/types/pairing.d.ts.map +1 -1
  80. package/lib/types/pairing.js +68 -0
  81. package/lib/types/pairing.persist.test.d.ts +2 -0
  82. package/lib/types/pairing.persist.test.d.ts.map +1 -0
  83. package/lib/types/pairing.persist.test.js +128 -0
  84. package/lib/types/routes.d.ts.map +1 -1
  85. package/lib/types/routes.js +23 -3
  86. package/lib/types/tunnel.d.ts +1 -0
  87. package/lib/types/tunnel.d.ts.map +1 -1
  88. package/lib/types/tunnel.js +7 -2
  89. package/lib/types/update.d.ts +4 -4
  90. package/lib/types/update.d.ts.map +1 -1
  91. package/lib/types/update.js +35 -12
  92. package/package.json +12 -12
  93. package/src/client/PluginSettingsCard.tsx +229 -18
  94. package/src/client/RemoteEntry.tsx +12 -2
  95. package/src/client/RemoteSettingsCard.tsx +3 -2
  96. package/src/client/UpdateEntry.tsx +36 -4
  97. package/src/client/UpdatePanel.tsx +2 -0
  98. package/src/client/deep-link.ts +1 -1
  99. package/src/client/locales.ts +4 -0
  100. package/src/client/remote.module.css +26 -0
  101. package/src/client/settings-card.module.css +90 -1
  102. package/src/gate.ts +17 -3
  103. package/src/index.ts +46 -15
  104. package/src/mobile/PairRequiredView.test.tsx +28 -0
  105. package/src/mobile/PairRequiredView.tsx +58 -0
  106. package/src/mobile/api.ts +14 -1
  107. package/src/mobile/index.tsx +15 -1
  108. package/src/mobile/messages.test.ts +52 -1
  109. package/src/mobile/messages.ts +65 -22
  110. package/src/mobile/mobile-styles.ts +86 -0
  111. package/src/mobile/pairing.ts +77 -0
  112. package/src/mobile/views/App.test.tsx +62 -0
  113. package/src/mobile/views/App.tsx +53 -6
  114. package/src/mobile/views/ChatView.tsx +33 -10
  115. package/src/mobile/views/SessionListView.test.tsx +69 -1
  116. package/src/mobile/views/SessionListView.tsx +58 -5
  117. package/src/mobile/views/WorkspaceView.tsx +4 -2
  118. package/src/mobile-api.ts +9 -1
  119. package/src/mobile-pwa.ts +19 -0
  120. package/src/mobile-routes.ts +123 -30
  121. package/src/pairing-access.ts +36 -0
  122. package/src/pairing.persist.test.ts +145 -0
  123. package/src/pairing.ts +70 -1
  124. package/src/routes.ts +23 -3
  125. package/src/tunnel.ts +7 -2
  126. package/src/update.ts +42 -14
package/src/update.ts CHANGED
@@ -1,8 +1,8 @@
1
1
  /**
2
2
  * Remote update support for the dsh-web-ui family — host half. Detects the
3
- * installed aggregate package (@linxin666/dsh-web-ui-all) and its family
4
- * children, probes the npm registry for newer releases, and runs the actual
5
- * update as `pnpm update --latest` inside the owning dsh profile directory.
3
+ * installed aggregate package (@linxin666/dsh-web-ui-all), or the directly
4
+ * installed family packages when the aggregate is absent, probes npm for newer
5
+ * releases, and runs `pnpm update --latest` inside the owning dsh profile.
6
6
  *
7
7
  * Pure logic with injected seams (manifest reading, registry fetches, process
8
8
  * spawning) so the whole surface is unit-testable without touching disk,
@@ -235,10 +235,13 @@ export function resolveUpdateTarget(
235
235
  const profileManifest = readManifest(join(profile.dir, 'package.json'))
236
236
  const spec = (profileManifest?.dependencies as Record<string, DependencySpec> | undefined)?.[anchor]
237
237
  if (isLinkedSpec(spec)) return { error: 'link' }
238
+ // Standalone installs carry no aggregate: the anchor's own dependency
239
+ // list misses every sibling @linxin666/* plugin installed directly into
240
+ // the profile, so union the profile's direct family deps (#377).
238
241
  return {
239
242
  profileName: profile.name,
240
243
  profileDir: profile.dir,
241
- packages: [anchor, ...familyChildren(manifest)],
244
+ packages: familyUpdatePackages(anchor, manifest, profileManifest),
242
245
  }
243
246
  }
244
247
 
@@ -253,6 +256,21 @@ export function familyChildren(anchorManifest: Record<string, unknown>): string[
253
256
  return names
254
257
  }
255
258
 
259
+ /** Registry-managed family packages covered by one update operation. */
260
+ function familyUpdatePackages(
261
+ anchor: string,
262
+ anchorManifest: Record<string, unknown>,
263
+ profileManifest: Record<string, unknown> | undefined,
264
+ ): string[] {
265
+ const names = new Set([anchor, ...familyChildren(anchorManifest)])
266
+ const dependencies = profileManifest?.dependencies
267
+ if (typeof dependencies !== 'object' || dependencies === null) return [...names]
268
+ for (const [name, spec] of Object.entries(dependencies)) {
269
+ if (name.startsWith(FAMILY_SCOPE) && typeof spec === 'string' && !isLinkedSpec(spec)) names.add(name)
270
+ }
271
+ return [...names]
272
+ }
273
+
256
274
  /**
257
275
  * Probe the npm registry for one package's latest release.
258
276
  * @param name - the package name (scope slash URL-encoded).
@@ -262,14 +280,14 @@ export function familyChildren(anchorManifest: Record<string, unknown>): string[
262
280
  */
263
281
  export async function fetchLatestVersion(
264
282
  name: string,
265
- fetchImpl: (url: string) => Promise<{ ok: boolean; json(): Promise<unknown> }>,
283
+ fetchImpl: (url: string, init?: RequestInit) => Promise<{ ok: boolean; json(): Promise<unknown> }>,
266
284
  timeoutMs = 10_000,
267
285
  ): Promise<string | undefined> {
268
286
  try {
269
287
  const controller = new AbortController()
270
288
  const timer = setTimeout(() => { controller.abort() }, timeoutMs)
271
289
  try {
272
- const response = await fetchImpl(NPM_REGISTRY + '/' + name.replace('/', '%2F') + '/latest')
290
+ const response = await fetchImpl(NPM_REGISTRY + '/' + name.replace('/', '%2F') + '/latest', { signal: controller.signal })
273
291
  if (!response.ok) return undefined
274
292
  const body = await response.json()
275
293
  if (typeof body !== 'object' || body === null) return undefined
@@ -292,14 +310,21 @@ export async function fetchLatestVersion(
292
310
  const VERSION_UNKNOWN = '0.0.0'
293
311
 
294
312
  /** The resolved current version of one family package (probe failure tolerated). */
295
- function readInstalledVersion(resolve: (specifier: string) => string | undefined, name: string): string {
313
+ function readInstalledVersion(
314
+ resolve: (specifier: string) => string | undefined,
315
+ name: string,
316
+ profileDir?: string,
317
+ ): string {
296
318
  try {
297
319
  const path = resolve(name + '/package.json')
298
320
  const version = path === undefined ? undefined : readManifest(path)?.version
299
- return typeof version === 'string' ? version : VERSION_UNKNOWN
300
- } catch {
301
- return VERSION_UNKNOWN
302
- }
321
+ if (typeof version === 'string') return version
322
+ } catch { /* fall through to the profile's direct dependency path */ }
323
+ // Names originate in the profile dependency map, but still validate the
324
+ // npm package shape before using one as path segments.
325
+ if (profileDir === undefined || !/^@linxin666\/[a-z0-9][a-z0-9._-]*$/.test(name)) return VERSION_UNKNOWN
326
+ const version = readManifest(join(profileDir, 'node_modules', ...name.split('/'), 'package.json'))?.version
327
+ return typeof version === 'string' ? version : VERSION_UNKNOWN
303
328
  }
304
329
 
305
330
  /**
@@ -331,7 +356,10 @@ export async function checkUpdates(deps: UpdateCheckDeps): Promise<UpdateStatus>
331
356
  if (profile === undefined) {
332
357
  return { mode: 'link', packages: [], outdated: false }
333
358
  }
334
- const names = [anchor, ...familyChildren(manifest)]
359
+ // Union the profile's direct family deps so standalone installs (no
360
+ // aggregate) still check every installed @linxin666/* plugin (#377);
361
+ // familyUpdatePackages skips link:/file: development dependencies.
362
+ const names = familyUpdatePackages(anchor, manifest, profileManifest)
335
363
  // The registry probes are independent: run them together instead of
336
364
  // serializing up to N x 10s of registry latency behind one status call.
337
365
  const latestList = await Promise.all(names.map(name => deps.fetchLatest(name)))
@@ -340,7 +368,7 @@ export async function checkUpdates(deps: UpdateCheckDeps): Promise<UpdateStatus>
340
368
  names.forEach((name, index) => {
341
369
  const latest = latestList[index]
342
370
  if (latest === undefined) probeFailures++
343
- const current = readInstalledVersion(deps.resolve, name)
371
+ const current = readInstalledVersion(deps.resolve, name, profile.dir)
344
372
  packages.push({
345
373
  name,
346
374
  current,
@@ -604,7 +632,7 @@ export async function runUpdateVerified(deps: UpdateRunVerifiedDeps): Promise<Up
604
632
  // green exit that left everything in place could be mistaken for success.
605
633
  const before = new Map<string, string>()
606
634
  for (const name of deps.run.packages) {
607
- const version = readInstalledVersion(deps.check.resolve, name)
635
+ const version = readInstalledVersion(deps.check.resolve, name, deps.run.profileDir)
608
636
  if (version !== VERSION_UNKNOWN) before.set(name, version)
609
637
  }
610
638
  const result = await runUpdate(deps.run)