@linxin666/dsh-remote-web-ui 0.1.1 → 0.1.3

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 (79) hide show
  1. package/README.md +4 -1
  2. package/lib/client.js +35 -0
  3. package/lib/client.js.map +1 -0
  4. package/lib/mobile.js +15467 -0
  5. package/lib/mobile.js.map +1 -0
  6. package/lib/types/client/FooterRemoteEntry.d.ts +22 -0
  7. package/lib/types/client/FooterRemoteEntry.d.ts.map +1 -0
  8. package/lib/types/client/FooterRemoteEntry.js +10 -0
  9. package/lib/types/client/PairFailedNotice.js +24 -0
  10. package/lib/types/client/PairFailedNotice.js.map +1 -0
  11. package/lib/types/client/PhoneIcon.js +9 -0
  12. package/lib/types/client/PhoneIcon.js.map +1 -0
  13. package/lib/types/client/PluginSettingsCard.js +39 -0
  14. package/lib/types/client/PluginSettingsCard.js.map +1 -0
  15. package/lib/types/client/RemoteEntry.js +162 -0
  16. package/lib/types/client/RemoteEntry.js.map +1 -0
  17. package/lib/types/client/RemotePanel.js +34 -0
  18. package/lib/types/client/RemotePanel.js.map +1 -0
  19. package/lib/types/client/RemoteSettingsCard.js +59 -0
  20. package/lib/types/client/RemoteSettingsCard.js.map +1 -0
  21. package/lib/types/client/deep-link.js +118 -0
  22. package/lib/types/client/deep-link.js.map +1 -0
  23. package/lib/types/client/index.d.ts.map +1 -1
  24. package/lib/types/client/index.js +134 -0
  25. package/lib/types/client/index.js.map +1 -0
  26. package/lib/types/client/locales.js +141 -0
  27. package/lib/types/client/locales.js.map +1 -0
  28. package/lib/types/client/pair-api.js +123 -0
  29. package/lib/types/client/pair-api.js.map +1 -0
  30. package/lib/types/client/settings-form.js +211 -0
  31. package/lib/types/client/settings-form.js.map +1 -0
  32. package/lib/types/gate.js +121 -0
  33. package/lib/types/gate.js.map +1 -0
  34. package/lib/types/index.js +227 -0
  35. package/lib/types/index.js.map +1 -0
  36. package/lib/types/invariant.js +23 -0
  37. package/lib/types/invariant.js.map +1 -0
  38. package/lib/types/lan.js +19 -0
  39. package/lib/types/lan.js.map +1 -0
  40. package/lib/types/mobile/api.js +60 -0
  41. package/lib/types/mobile/api.js.map +1 -0
  42. package/lib/types/mobile/index.js +25 -0
  43. package/lib/types/mobile/index.js.map +1 -0
  44. package/lib/types/mobile/messages.js +449 -0
  45. package/lib/types/mobile/messages.js.map +1 -0
  46. package/lib/types/mobile/messages.test.js +189 -0
  47. package/lib/types/mobile/messages.test.js.map +1 -0
  48. package/lib/types/mobile/mobile-styles.js +853 -0
  49. package/lib/types/mobile/mobile-styles.js.map +1 -0
  50. package/lib/types/mobile/mobile-theme.js +70 -0
  51. package/lib/types/mobile/mobile-theme.test.js +71 -0
  52. package/lib/types/mobile/mux.js +110 -0
  53. package/lib/types/mobile/mux.js.map +1 -0
  54. package/lib/types/mobile/rpc.js +83 -0
  55. package/lib/types/mobile/rpc.js.map +1 -0
  56. package/lib/types/mobile/theme-toggle.js +26 -0
  57. package/lib/types/mobile/views/App.js +102 -0
  58. package/lib/types/mobile/views/App.js.map +1 -0
  59. package/lib/types/mobile/views/ChatView.js +348 -0
  60. package/lib/types/mobile/views/ChatView.js.map +1 -0
  61. package/lib/types/mobile/views/ChatView.test.js +215 -0
  62. package/lib/types/mobile/views/SessionListView.js +108 -0
  63. package/lib/types/mobile/views/SessionListView.js.map +1 -0
  64. package/lib/types/mobile/views/SessionListView.test.js +110 -0
  65. package/lib/types/mobile/views/WorkspaceView.js +43 -0
  66. package/lib/types/mobile/views/WorkspaceView.js.map +1 -0
  67. package/lib/types/mobile-api.js +263 -0
  68. package/lib/types/mobile-api.js.map +1 -0
  69. package/lib/types/mobile-routes.js +71 -0
  70. package/lib/types/mobile-routes.js.map +1 -0
  71. package/lib/types/pairing.js +285 -0
  72. package/lib/types/pairing.js.map +1 -0
  73. package/lib/types/routes.js +327 -0
  74. package/lib/types/routes.js.map +1 -0
  75. package/lib/types/tunnel.js +222 -0
  76. package/lib/types/tunnel.js.map +1 -0
  77. package/package.json +9 -6
  78. package/src/client/FooterRemoteEntry.tsx +31 -0
  79. package/src/client/index.ts +23 -0
@@ -0,0 +1,222 @@
1
+ /**
2
+ * Auto-tunnel manager: spawns a Cloudflare quick tunnel (`cloudflared
3
+ * tunnel --url <local>`) through the `cloudflared` npm package — its
4
+ * postinstall downloads the platform binary, so no user-side tooling is
5
+ * involved — surfaces the minted `https://xxx.trycloudflare.com` URL, and
6
+ * restarts the process after unexpected exits with exponential backoff.
7
+ *
8
+ * The cloudflared package's Tunnel is a thin spawn wrapper; this manager
9
+ * owns the lifecycle policy (binary readiness, URL timeout, restart
10
+ * backoff) around it. All seams — the tunnel factory, binary readiness,
11
+ * timers — are injectable so the whole lifecycle is unit-testable without
12
+ * a real binary or network.
13
+ */
14
+ import { existsSync } from 'node:fs';
15
+ import { bin, install, Tunnel } from 'cloudflared';
16
+ /** Default binary readiness: download the platform binary on first use. */
17
+ async function defaultEnsureBinary() {
18
+ if (existsSync(bin))
19
+ return;
20
+ await install(bin);
21
+ }
22
+ /** Default factory: the cloudflared package's quick tunnel (no account). */
23
+ function defaultFactory(targetUrl) {
24
+ // `--no-autoupdate`: the binary must never upgrade itself out from under
25
+ // the manager (a self-updated binary would break the pinned lifecycle).
26
+ return Tunnel.quick(targetUrl, { '--no-autoupdate': true });
27
+ }
28
+ /** Node timers. */
29
+ const nodeTimer = { setTimeout, clearTimeout };
30
+ /**
31
+ * Own the lifecycle of one auto-tunnel: start/stop, URL surfacing, and
32
+ * crash-restart backoff.
33
+ */
34
+ export class TunnelManager {
35
+ factory;
36
+ ensureBinary;
37
+ urlTimeoutMs;
38
+ restartBaseMs;
39
+ restartMaxMs;
40
+ timer;
41
+ phase = 'stopped';
42
+ url;
43
+ error;
44
+ targetUrl;
45
+ handle;
46
+ urlTimer;
47
+ restartTimer;
48
+ attempts = 0;
49
+ stopping = false;
50
+ urlListeners = new Set();
51
+ phaseListeners = new Set();
52
+ /**
53
+ * @param options - seams; defaults spawn the real quick tunnel.
54
+ */
55
+ constructor(options = {}) {
56
+ this.factory = options.factory ?? defaultFactory;
57
+ this.ensureBinary = options.ensureBinary ?? defaultEnsureBinary;
58
+ this.urlTimeoutMs = options.urlTimeoutMs ?? 30_000;
59
+ this.restartBaseMs = options.restartBaseMs ?? 5_000;
60
+ this.restartMaxMs = options.restartMaxMs ?? 60_000;
61
+ this.timer = options.timer ?? nodeTimer;
62
+ }
63
+ /** The current status frame. */
64
+ get info() {
65
+ return {
66
+ phase: this.phase,
67
+ ...(this.url !== undefined ? { url: this.url } : {}),
68
+ ...(this.error !== undefined ? { error: this.error } : {}),
69
+ };
70
+ }
71
+ /**
72
+ * Start (or keep) a quick tunnel toward `targetUrl`. Restarting with a
73
+ * different target tears the old tunnel down first; restarting with the
74
+ * same target while running is a no-op.
75
+ * @param targetUrl - the local URL to expose, e.g. `http://127.0.0.1:3080`.
76
+ */
77
+ start(targetUrl) {
78
+ if (this.targetUrl === targetUrl && (this.phase === 'starting' || this.phase === 'running'))
79
+ return;
80
+ this.teardown();
81
+ this.stopping = false;
82
+ this.targetUrl = targetUrl;
83
+ this.attempts = 0;
84
+ this.attempt();
85
+ }
86
+ /** Stop the tunnel for good: no restarts, no state. */
87
+ stop() {
88
+ this.teardown();
89
+ this.stopping = false;
90
+ this.targetUrl = undefined;
91
+ this.setPhase('stopped');
92
+ }
93
+ /** Alias of {@link stop} for plugin-effect disposal. */
94
+ dispose() {
95
+ this.stop();
96
+ }
97
+ /** Subscribe to minted tunnel URLs (fire-and-forget duplicates dropped). */
98
+ onUrl(listener) {
99
+ this.urlListeners.add(listener);
100
+ return () => { this.urlListeners.delete(listener); };
101
+ }
102
+ /** Subscribe to every phase change. */
103
+ onPhase(listener) {
104
+ this.phaseListeners.add(listener);
105
+ return () => { this.phaseListeners.delete(listener); };
106
+ }
107
+ attempt() {
108
+ if (this.stopping || this.targetUrl === undefined)
109
+ return;
110
+ this.setPhase('starting');
111
+ this.handle = undefined;
112
+ this.url = undefined;
113
+ this.error = undefined;
114
+ void this.ensureBinary().then(() => {
115
+ if (this.stopping || this.targetUrl === undefined)
116
+ return;
117
+ const handle = this.factory(this.targetUrl);
118
+ this.handle = handle;
119
+ this.urlTimer = this.timer.setTimeout(() => {
120
+ // The tunnel never reported a URL: kill it and retry with backoff.
121
+ this.fail('timed out waiting for the tunnel URL');
122
+ }, this.urlTimeoutMs);
123
+ handle.on('url', (value) => {
124
+ if (this.handle !== handle)
125
+ return;
126
+ this.handleUrl(value);
127
+ });
128
+ handle.on('exit', () => {
129
+ if (this.handle !== handle)
130
+ return;
131
+ this.handleExit();
132
+ });
133
+ handle.on('error', (value) => {
134
+ // Spawn/connection errors usually precede an exit; the exit path owns
135
+ // restart, this only records diagnostics while the process still lives.
136
+ if (this.handle !== handle || this.phase !== 'starting')
137
+ return;
138
+ this.error = value instanceof Error ? value.message : String(value);
139
+ });
140
+ }).catch((value) => {
141
+ // Binary install failed (no network, no platform build): report it.
142
+ if (this.stopping || this.targetUrl === undefined)
143
+ return;
144
+ const message = value instanceof Error ? value.message : String(value);
145
+ this.fail(`could not obtain the cloudflared binary: ${message}`);
146
+ });
147
+ }
148
+ handleUrl(value) {
149
+ if (this.urlTimer !== undefined) {
150
+ this.timer.clearTimeout(this.urlTimer);
151
+ this.urlTimer = undefined;
152
+ }
153
+ this.url = value;
154
+ this.error = undefined;
155
+ this.attempts = 0;
156
+ this.setPhase('running');
157
+ for (const listener of this.urlListeners) {
158
+ try {
159
+ listener(value);
160
+ }
161
+ catch {
162
+ // A throwing subscriber must not break the emit loop.
163
+ }
164
+ }
165
+ }
166
+ handleExit() {
167
+ // The exit handler is detached during teardown, so reaching this point
168
+ // means an unexpected death: fail the current phase and schedule a retry.
169
+ if (this.stopping)
170
+ return;
171
+ this.fail('the tunnel process exited unexpectedly');
172
+ }
173
+ fail(message) {
174
+ if (this.stopping)
175
+ return;
176
+ this.url = undefined;
177
+ this.error = message;
178
+ if (this.handle !== undefined) {
179
+ this.handle.stop();
180
+ this.handle = undefined;
181
+ }
182
+ if (this.urlTimer !== undefined) {
183
+ this.timer.clearTimeout(this.urlTimer);
184
+ this.urlTimer = undefined;
185
+ }
186
+ this.setPhase('failed');
187
+ this.attempts += 1;
188
+ const delay = Math.min(this.restartBaseMs * 2 ** (this.attempts - 1), this.restartMaxMs);
189
+ this.restartTimer = this.timer.setTimeout(() => {
190
+ this.restartTimer = undefined;
191
+ this.attempt();
192
+ }, delay);
193
+ }
194
+ /** Stop the current process and cancel every pending timer (no phase change). */
195
+ teardown() {
196
+ this.stopping = true;
197
+ if (this.urlTimer !== undefined) {
198
+ this.timer.clearTimeout(this.urlTimer);
199
+ this.urlTimer = undefined;
200
+ }
201
+ if (this.restartTimer !== undefined) {
202
+ this.timer.clearTimeout(this.restartTimer);
203
+ this.restartTimer = undefined;
204
+ }
205
+ if (this.handle !== undefined) {
206
+ this.handle.stop();
207
+ this.handle = undefined;
208
+ }
209
+ }
210
+ setPhase(phase) {
211
+ this.phase = phase;
212
+ const info = this.info;
213
+ for (const listener of this.phaseListeners) {
214
+ try {
215
+ listener(info);
216
+ }
217
+ catch {
218
+ // A throwing subscriber must not break the emit loop.
219
+ }
220
+ }
221
+ }
222
+ }
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tunnel.js","sourceRoot":"","sources":["../../src/tunnel.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@linxin666/dsh-remote-web-ui",
3
3
  "description": "Mobile remote control for the dsh web GUI: scan-to-pair QR entry beside the settings button, one-time pairing tokens, live device status, and revocable mobile sessions",
4
- "version": "0.1.1",
4
+ "version": "0.1.3",
5
5
  "type": "module",
6
6
  "engines": {
7
7
  "node": "^22.19.0 || >=24.0.0"
@@ -25,11 +25,10 @@
25
25
  "./package.json": "./package.json"
26
26
  },
27
27
  "files": [
28
- "lib/index.js",
29
- "lib/invariant.js",
30
- "lib/client.js",
31
- "lib/types/**/*.d.ts",
32
- "lib/types/**/*.d.ts.map",
28
+ "lib/**/*.js",
29
+ "lib/**/*.js.map",
30
+ "lib/**/*.d.ts",
31
+ "lib/**/*.d.ts.map",
33
32
  "src",
34
33
  "cordis.patch.yml"
35
34
  ],
@@ -96,6 +95,10 @@
96
95
  "vite-tsconfig-paths": "^6.1.1",
97
96
  "vitest": "^4.1.8"
98
97
  },
98
+ "repository": {
99
+ "type": "git",
100
+ "url": "https://github.com/zhu1090093659/dsh-web-ui.git"
101
+ },
99
102
  "scripts": {
100
103
  "build": "tsc -b && tsdown",
101
104
  "test": "vitest run",
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Sidebar footer-seat wrapper for the remote-control entry.
3
+ *
4
+ * Current dsh web shells declare `sidebar.footer.action` (the seat beside the
5
+ * settings trigger) instead of the legacy `sidebar.remote` seat this plugin
6
+ * was written against. The footer seat supplies `{ wide }` but not the
7
+ * `useWorkspaces` projection hook, so this wrapper substitutes a
8
+ * workspace-agnostic selector: pairing without a deep-linked workspace is
9
+ * fully supported by the host `/api/pair` routes.
10
+ */
11
+ import type { PropsLocale } from '@deepseek-ai/dsh-client-ui-slots'
12
+ import { RemoteEntry } from './RemoteEntry.tsx'
13
+
14
+ /** Entry props: the footer seat's column state + the standard locale seat. */
15
+ export type FooterRemoteEntryProps = PropsLocale<'remote'> & { wide: boolean }
16
+
17
+ /**
18
+ * Render the remote-control trigger + pairing panel from the footer seat.
19
+ * @param props - composed slot props (footer seat subset).
20
+ * @returns the entry element tree.
21
+ */
22
+ export function FooterRemoteEntry(props: FooterRemoteEntryProps) {
23
+ return (
24
+ <RemoteEntry
25
+ wide={props.wide}
26
+ useWorkspaces={() => undefined as never}
27
+ useSessions={() => undefined as never}
28
+ t={props.t}
29
+ />
30
+ )
31
+ }
@@ -17,6 +17,7 @@ import type {} from '@deepseek-ai/dsh-client-locale/client'
17
17
  import type {} from '@deepseek-ai/dsh-client-ui-settings/client'
18
18
  import type {} from '@deepseek-ai/dsh-client-ui-sidebar/client'
19
19
  import type { ConnectionHandle } from '@deepseek-ai/dsh-client-connection/client'
20
+ import { FooterRemoteEntry } from './FooterRemoteEntry.tsx'
20
21
  import { RemoteEntry } from './RemoteEntry.tsx'
21
22
  import { PairFailedNotice } from './PairFailedNotice.tsx'
22
23
  import { RemoteSettingsCard, RemoteSettingsCardController, type RemoteSettings } from './RemoteSettingsCard.tsx'
@@ -116,6 +117,28 @@ export function apply(ctx: ClientContext): void {
116
117
  }
117
118
  })
118
119
 
120
+ // Current shells declare `sidebar.footer.action` instead of the legacy
121
+ // `sidebar.remote` seat; this fallback registers the same entry there when
122
+ // the legacy seat never arrives (declaration-aware: only one of the two
123
+ // injects ever fires, so the trigger can never render twice).
124
+ ctx.slots.inject('sidebar.footer.action', () => {
125
+ let disposeEntry: (() => void) | undefined
126
+ const syncEntry = (): void => {
127
+ if (enabled() && disposeEntry === undefined) {
128
+ disposeEntry = ctx.slots.register({ name: 'sidebar.footer.action', id: 'remote-web-ui', locale: NS }, FooterRemoteEntry)
129
+ } else if (!enabled() && disposeEntry !== undefined) {
130
+ disposeEntry()
131
+ disposeEntry = undefined
132
+ }
133
+ }
134
+ const unsubscribe = settingsScope.subscribe(syncEntry)
135
+ syncEntry()
136
+ return () => {
137
+ unsubscribe()
138
+ disposeEntry?.()
139
+ }
140
+ })
141
+
119
142
  // Plugin configuration card: one staged form over the `remote-web-ui`
120
143
  // settings namespace, contributed to the Web UI plugin group.
121
144
  const remoteSettings = new RemoteSettingsCardController(settingsScope)