@linxin666/dsh-remote-web-ui 0.3.6 → 0.3.9

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 (238) hide show
  1. package/README.i18n.yaml +2 -2
  2. package/README.md +77 -468
  3. package/README.zh.md +83 -113
  4. package/lib/client.js +955 -203
  5. package/lib/client.js.map +1 -1
  6. package/lib/index.js +1136 -1466
  7. package/lib/types/client/FooterRemoteEntry.d.ts +6 -7
  8. package/lib/types/client/FooterRemoteEntry.d.ts.map +1 -1
  9. package/lib/types/client/FooterRemoteEntry.js +1 -1
  10. package/lib/types/client/RemoteEntry.d.ts +7 -4
  11. package/lib/types/client/RemoteEntry.d.ts.map +1 -1
  12. package/lib/types/client/RemoteEntry.js +7 -10
  13. package/lib/types/client/RemotePanel.d.ts +2 -2
  14. package/lib/types/client/RemotePanel.d.ts.map +1 -1
  15. package/lib/types/client/RemotePanel.js +2 -2
  16. package/lib/types/client/RemoteSettingsCard.d.ts +9 -5
  17. package/lib/types/client/RemoteSettingsCard.d.ts.map +1 -1
  18. package/lib/types/client/RemoteSettingsCard.js +56 -3
  19. package/lib/types/client/deep-link.d.ts +10 -13
  20. package/lib/types/client/deep-link.d.ts.map +1 -1
  21. package/lib/types/client/deep-link.js +14 -74
  22. package/lib/types/client/index.d.ts +2 -6
  23. package/lib/types/client/index.d.ts.map +1 -1
  24. package/lib/types/client/index.js +73 -39
  25. package/lib/types/client/locales.d.ts +26 -12
  26. package/lib/types/client/locales.d.ts.map +1 -1
  27. package/lib/types/client/locales.js +36 -22
  28. package/lib/types/client/mobile-adapt.d.ts +40 -0
  29. package/lib/types/client/mobile-adapt.d.ts.map +1 -0
  30. package/lib/types/client/mobile-adapt.js +967 -0
  31. package/lib/types/client/pair-api.d.ts +24 -6
  32. package/lib/types/client/pair-api.d.ts.map +1 -1
  33. package/lib/types/client/pair-api.js +9 -14
  34. package/lib/types/client/remote-channel.d.ts +3 -0
  35. package/lib/types/client/remote-channel.d.ts.map +1 -1
  36. package/lib/types/client/remote-channel.js +35 -3
  37. package/lib/types/client/settings-form.d.ts +35 -43
  38. package/lib/types/client/settings-form.d.ts.map +1 -1
  39. package/lib/types/client/settings-form.js +60 -53
  40. package/lib/types/firewall.d.ts +75 -0
  41. package/lib/types/firewall.d.ts.map +1 -0
  42. package/lib/types/firewall.js +184 -0
  43. package/lib/types/gate.d.ts +11 -5
  44. package/lib/types/gate.d.ts.map +1 -1
  45. package/lib/types/gate.js +11 -5
  46. package/lib/types/index.d.ts +39 -10
  47. package/lib/types/index.d.ts.map +1 -1
  48. package/lib/types/index.js +206 -58
  49. package/lib/types/inner-auth.d.ts +32 -0
  50. package/lib/types/inner-auth.d.ts.map +1 -0
  51. package/lib/types/inner-auth.js +72 -0
  52. package/lib/types/lan-bind-plan.d.ts +55 -0
  53. package/lib/types/lan-bind-plan.d.ts.map +1 -0
  54. package/lib/types/lan-bind-plan.js +60 -0
  55. package/lib/types/lan-bind.d.ts +69 -0
  56. package/lib/types/lan-bind.d.ts.map +1 -0
  57. package/lib/types/lan-bind.js +128 -0
  58. package/lib/types/loopback-proxy.d.ts +9 -2
  59. package/lib/types/loopback-proxy.d.ts.map +1 -1
  60. package/lib/types/loopback-proxy.js +24 -2
  61. package/lib/types/pairing.d.ts +15 -3
  62. package/lib/types/pairing.d.ts.map +1 -1
  63. package/lib/types/pairing.js +20 -6
  64. package/lib/types/remote-api.d.ts +30 -13
  65. package/lib/types/remote-api.d.ts.map +1 -1
  66. package/lib/types/remote-api.js +55 -42
  67. package/lib/types/remote-channel-boot.d.ts +21 -2
  68. package/lib/types/remote-channel-boot.d.ts.map +1 -1
  69. package/lib/types/remote-channel-boot.js +65 -3
  70. package/lib/types/remote-channel-rules.d.ts +8 -0
  71. package/lib/types/remote-channel-rules.d.ts.map +1 -1
  72. package/lib/types/remote-channel-rules.js +9 -2
  73. package/lib/types/remote-methods.d.ts +45 -11
  74. package/lib/types/remote-methods.d.ts.map +1 -1
  75. package/lib/types/remote-methods.js +56 -27
  76. package/lib/types/remote-presence-pet.d.ts +51 -0
  77. package/lib/types/remote-presence-pet.d.ts.map +1 -0
  78. package/lib/types/remote-presence-pet.js +101 -0
  79. package/lib/types/routes.d.ts +76 -4
  80. package/lib/types/routes.d.ts.map +1 -1
  81. package/lib/types/routes.js +336 -19
  82. package/lib/types/tunnel.d.ts.map +1 -1
  83. package/lib/types/tunnel.js +7 -1
  84. package/package.json +20 -18
  85. package/src/client/FooterRemoteEntry.tsx +9 -10
  86. package/src/client/RemoteEntry.tsx +13 -14
  87. package/src/client/RemotePanel.tsx +5 -16
  88. package/src/client/RemoteSettingsCard.tsx +72 -13
  89. package/src/client/deep-link.ts +14 -75
  90. package/src/client/index.ts +77 -39
  91. package/src/client/locales.ts +36 -22
  92. package/src/client/mobile-adapt.ts +913 -0
  93. package/src/client/pair-api.ts +26 -15
  94. package/src/client/remote-channel.ts +31 -3
  95. package/src/client/settings-form.ts +78 -92
  96. package/src/dsh-home.ts +1 -1
  97. package/src/firewall.ts +230 -0
  98. package/src/gate.ts +11 -5
  99. package/src/index.ts +235 -65
  100. package/src/inner-auth.ts +85 -0
  101. package/src/lan-bind-plan.ts +81 -0
  102. package/src/lan-bind.ts +145 -0
  103. package/src/loopback-proxy.ts +34 -0
  104. package/src/pairing.persist.test.ts +1 -1
  105. package/src/pairing.ts +20 -6
  106. package/src/remote-api.ts +67 -45
  107. package/src/remote-channel-boot.ts +70 -3
  108. package/src/remote-channel-rules.ts +17 -2
  109. package/src/remote-methods.ts +58 -27
  110. package/src/remote-presence-pet.ts +129 -0
  111. package/src/routes.ts +358 -19
  112. package/src/tunnel.ts +7 -1
  113. package/assets/apple-touch-icon.png +0 -0
  114. package/assets/mobile-icon-192.png +0 -0
  115. package/assets/mobile-icon-512.png +0 -0
  116. package/assets/mobile-service-worker.js +0 -63
  117. package/lib/mobile.js +0 -17658
  118. package/lib/mobile.js.map +0 -1
  119. package/lib/types/mobile/PairRequiredView.d.ts +0 -7
  120. package/lib/types/mobile/PairRequiredView.d.ts.map +0 -1
  121. package/lib/types/mobile/PairRequiredView.js +0 -28
  122. package/lib/types/mobile/PairRequiredView.test.d.ts +0 -2
  123. package/lib/types/mobile/PairRequiredView.test.d.ts.map +0 -1
  124. package/lib/types/mobile/PairRequiredView.test.js +0 -24
  125. package/lib/types/mobile/api.d.ts +0 -145
  126. package/lib/types/mobile/api.d.ts.map +0 -1
  127. package/lib/types/mobile/api.js +0 -103
  128. package/lib/types/mobile/index.d.ts +0 -10
  129. package/lib/types/mobile/index.d.ts.map +0 -1
  130. package/lib/types/mobile/index.js +0 -38
  131. package/lib/types/mobile/markdown.d.ts +0 -34
  132. package/lib/types/mobile/markdown.d.ts.map +0 -1
  133. package/lib/types/mobile/markdown.js +0 -285
  134. package/lib/types/mobile/markdown.test.d.ts +0 -2
  135. package/lib/types/mobile/markdown.test.d.ts.map +0 -1
  136. package/lib/types/mobile/markdown.test.js +0 -79
  137. package/lib/types/mobile/messages.d.ts +0 -149
  138. package/lib/types/mobile/messages.d.ts.map +0 -1
  139. package/lib/types/mobile/messages.js +0 -561
  140. package/lib/types/mobile/messages.test.d.ts +0 -2
  141. package/lib/types/mobile/messages.test.d.ts.map +0 -1
  142. package/lib/types/mobile/messages.test.js +0 -356
  143. package/lib/types/mobile/mobile-styles.d.ts +0 -6
  144. package/lib/types/mobile/mobile-styles.d.ts.map +0 -1
  145. package/lib/types/mobile/mobile-styles.js +0 -1438
  146. package/lib/types/mobile/mobile-theme.d.ts +0 -22
  147. package/lib/types/mobile/mobile-theme.d.ts.map +0 -1
  148. package/lib/types/mobile/mobile-theme.js +0 -70
  149. package/lib/types/mobile/mobile-theme.test.d.ts +0 -2
  150. package/lib/types/mobile/mobile-theme.test.d.ts.map +0 -1
  151. package/lib/types/mobile/mobile-theme.test.js +0 -71
  152. package/lib/types/mobile/mux.d.ts +0 -128
  153. package/lib/types/mobile/mux.d.ts.map +0 -1
  154. package/lib/types/mobile/mux.js +0 -305
  155. package/lib/types/mobile/mux.test.d.ts +0 -2
  156. package/lib/types/mobile/mux.test.d.ts.map +0 -1
  157. package/lib/types/mobile/mux.test.js +0 -267
  158. package/lib/types/mobile/pairing.d.ts +0 -31
  159. package/lib/types/mobile/pairing.d.ts.map +0 -1
  160. package/lib/types/mobile/pairing.js +0 -62
  161. package/lib/types/mobile/rpc.d.ts +0 -38
  162. package/lib/types/mobile/rpc.d.ts.map +0 -1
  163. package/lib/types/mobile/rpc.js +0 -83
  164. package/lib/types/mobile/theme-toggle.d.ts +0 -12
  165. package/lib/types/mobile/theme-toggle.d.ts.map +0 -1
  166. package/lib/types/mobile/theme-toggle.js +0 -26
  167. package/lib/types/mobile/views/App.d.ts +0 -57
  168. package/lib/types/mobile/views/App.d.ts.map +0 -1
  169. package/lib/types/mobile/views/App.js +0 -150
  170. package/lib/types/mobile/views/App.test.d.ts +0 -2
  171. package/lib/types/mobile/views/App.test.d.ts.map +0 -1
  172. package/lib/types/mobile/views/App.test.js +0 -52
  173. package/lib/types/mobile/views/ChatView.d.ts +0 -63
  174. package/lib/types/mobile/views/ChatView.d.ts.map +0 -1
  175. package/lib/types/mobile/views/ChatView.js +0 -821
  176. package/lib/types/mobile/views/ChatView.stream.test.d.ts +0 -2
  177. package/lib/types/mobile/views/ChatView.stream.test.d.ts.map +0 -1
  178. package/lib/types/mobile/views/ChatView.stream.test.js +0 -236
  179. package/lib/types/mobile/views/ChatView.test.d.ts +0 -2
  180. package/lib/types/mobile/views/ChatView.test.d.ts.map +0 -1
  181. package/lib/types/mobile/views/ChatView.test.js +0 -718
  182. package/lib/types/mobile/views/SessionListView.d.ts +0 -27
  183. package/lib/types/mobile/views/SessionListView.d.ts.map +0 -1
  184. package/lib/types/mobile/views/SessionListView.js +0 -139
  185. package/lib/types/mobile/views/SessionListView.test.d.ts +0 -2
  186. package/lib/types/mobile/views/SessionListView.test.d.ts.map +0 -1
  187. package/lib/types/mobile/views/SessionListView.test.js +0 -167
  188. package/lib/types/mobile/views/WorkspaceView.d.ts +0 -21
  189. package/lib/types/mobile/views/WorkspaceView.d.ts.map +0 -1
  190. package/lib/types/mobile/views/WorkspaceView.js +0 -93
  191. package/lib/types/mobile/views/WorkspaceView.test.d.ts +0 -2
  192. package/lib/types/mobile/views/WorkspaceView.test.d.ts.map +0 -1
  193. package/lib/types/mobile/views/WorkspaceView.test.js +0 -183
  194. package/lib/types/mobile-api.d.ts +0 -65
  195. package/lib/types/mobile-api.d.ts.map +0 -1
  196. package/lib/types/mobile-api.js +0 -404
  197. package/lib/types/mobile-pending.d.ts +0 -38
  198. package/lib/types/mobile-pending.d.ts.map +0 -1
  199. package/lib/types/mobile-pending.js +0 -59
  200. package/lib/types/mobile-pwa.d.ts +0 -6
  201. package/lib/types/mobile-pwa.d.ts.map +0 -1
  202. package/lib/types/mobile-pwa.js +0 -17
  203. package/lib/types/mobile-routes.d.ts +0 -13
  204. package/lib/types/mobile-routes.d.ts.map +0 -1
  205. package/lib/types/mobile-routes.js +0 -217
  206. package/lib/types/paired-model-catalog.d.ts +0 -17
  207. package/lib/types/paired-model-catalog.d.ts.map +0 -1
  208. package/lib/types/paired-model-catalog.js +0 -311
  209. package/src/mobile/PairRequiredView.test.tsx +0 -28
  210. package/src/mobile/PairRequiredView.tsx +0 -58
  211. package/src/mobile/api.ts +0 -229
  212. package/src/mobile/index.tsx +0 -41
  213. package/src/mobile/markdown.test.ts +0 -91
  214. package/src/mobile/markdown.ts +0 -291
  215. package/src/mobile/messages.test.ts +0 -402
  216. package/src/mobile/messages.ts +0 -685
  217. package/src/mobile/mobile-styles.ts +0 -1439
  218. package/src/mobile/mobile-theme.test.ts +0 -84
  219. package/src/mobile/mobile-theme.ts +0 -76
  220. package/src/mobile/mux.test.ts +0 -314
  221. package/src/mobile/mux.ts +0 -336
  222. package/src/mobile/pairing.ts +0 -77
  223. package/src/mobile/rpc.ts +0 -90
  224. package/src/mobile/theme-toggle.tsx +0 -47
  225. package/src/mobile/views/App.test.tsx +0 -62
  226. package/src/mobile/views/App.tsx +0 -213
  227. package/src/mobile/views/ChatView.stream.test.tsx +0 -268
  228. package/src/mobile/views/ChatView.test.tsx +0 -816
  229. package/src/mobile/views/ChatView.tsx +0 -1342
  230. package/src/mobile/views/SessionListView.test.tsx +0 -207
  231. package/src/mobile/views/SessionListView.tsx +0 -244
  232. package/src/mobile/views/WorkspaceView.test.tsx +0 -227
  233. package/src/mobile/views/WorkspaceView.tsx +0 -245
  234. package/src/mobile-api.ts +0 -418
  235. package/src/mobile-pending.ts +0 -88
  236. package/src/mobile-pwa.ts +0 -19
  237. package/src/mobile-routes.ts +0 -231
  238. package/src/paired-model-catalog.ts +0 -272
@@ -1,38 +0,0 @@
1
- import type { MuxFrame } from '@deepseek-ai/dsh-host-apiproxy/api/events';
2
- import type { RpcRequest } from '@deepseek-ai/dsh-host-apiproxy/api/rpc';
3
- export interface PendingApproval {
4
- rpcId: string;
5
- approvalId: string;
6
- toolName: string;
7
- callId?: string;
8
- reason?: string;
9
- }
10
- export interface PendingQuestion {
11
- rpcId: string;
12
- questions: Array<{
13
- id: string;
14
- question: string;
15
- detail?: string;
16
- header?: string;
17
- options?: Array<{
18
- label: string;
19
- description?: string;
20
- }>;
21
- multiSelect?: boolean;
22
- }>;
23
- }
24
- export interface PendingState {
25
- approvals: PendingApproval[];
26
- questions: PendingQuestion[];
27
- }
28
- export declare class PendingTracker {
29
- private readonly sessions;
30
- /** Process one mux frame and update the pending state. */
31
- onFrame(frame: RpcRequest<MuxFrame>): void;
32
- private _getOrInit;
33
- /** Query pending items for a session. */
34
- pending(sessionId: string): PendingState;
35
- /** Clear all pending state for a session. */
36
- clear(sessionId: string): void;
37
- }
38
- //# sourceMappingURL=mobile-pending.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"mobile-pending.d.ts","sourceRoot":"","sources":["../../src/mobile-pending.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,2CAA2C,CAAA;AACzE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,wCAAwC,CAAA;AAExE,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAA;IACb,UAAU,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAA;IACb,SAAS,EAAE,KAAK,CAAC;QACf,EAAE,EAAE,MAAM,CAAA;QACV,QAAQ,EAAE,MAAM,CAAA;QAChB,MAAM,CAAC,EAAE,MAAM,CAAA;QACf,MAAM,CAAC,EAAE,MAAM,CAAA;QACf,OAAO,CAAC,EAAE,KAAK,CAAC;YAAE,KAAK,EAAE,MAAM,CAAC;YAAC,WAAW,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC,CAAA;QACxD,WAAW,CAAC,EAAE,OAAO,CAAA;KACtB,CAAC,CAAA;CACH;AAED,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,eAAe,EAAE,CAAA;IAC5B,SAAS,EAAE,eAAe,EAAE,CAAA;CAC7B;AAED,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA+F;IAExH,0DAA0D;IAC1D,OAAO,CAAC,KAAK,EAAE,UAAU,CAAC,QAAQ,CAAC,GAAG,IAAI;IA8B1C,OAAO,CAAC,UAAU;IASlB,yCAAyC;IACzC,OAAO,CAAC,SAAS,EAAE,MAAM,GAAG,YAAY;IAWxC,6CAA6C;IAC7C,KAAK,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI;CAG/B"}
@@ -1,59 +0,0 @@
1
- export class PendingTracker {
2
- sessions = new Map();
3
- /** Process one mux frame and update the pending state. */
4
- onFrame(frame) {
5
- const payload = frame.payload;
6
- if (payload.type === 'approval/requested') {
7
- const state = this._getOrInit(payload.sessionId);
8
- state.approvals.set(payload.approvalId, {
9
- rpcId: frame.rpcId,
10
- approvalId: payload.approvalId,
11
- toolName: payload.toolName,
12
- callId: payload.callId,
13
- reason: payload.reason,
14
- });
15
- }
16
- else if (payload.type === 'approval/resolved') {
17
- const state = this.sessions.get(payload.sessionId);
18
- if (state) {
19
- state.approvals.delete(payload.approvalId);
20
- }
21
- }
22
- else if (payload.type === 'question/requested') {
23
- const state = this._getOrInit(payload.sessionId);
24
- state.questions.push({
25
- rpcId: frame.rpcId,
26
- questions: payload.questions,
27
- });
28
- }
29
- else if (payload.type === 'question/resolved') {
30
- const state = this.sessions.get(payload.sessionId);
31
- if (state) {
32
- state.questions = state.questions.filter(q => q.rpcId !== payload.questionRpcId);
33
- }
34
- }
35
- }
36
- _getOrInit(sessionId) {
37
- let state = this.sessions.get(sessionId);
38
- if (!state) {
39
- state = { approvals: new Map(), questions: [] };
40
- this.sessions.set(sessionId, state);
41
- }
42
- return state;
43
- }
44
- /** Query pending items for a session. */
45
- pending(sessionId) {
46
- const state = this.sessions.get(sessionId);
47
- if (!state) {
48
- return { approvals: [], questions: [] };
49
- }
50
- return {
51
- approvals: Array.from(state.approvals.values()),
52
- questions: state.questions,
53
- };
54
- }
55
- /** Clear all pending state for a session. */
56
- clear(sessionId) {
57
- this.sessions.delete(sessionId);
58
- }
59
- }
@@ -1,6 +0,0 @@
1
- /** PWA registration for the standalone /m mobile surface. */
2
- export declare const MOBILE_PWA_SCOPE = "/m/";
3
- export declare const MOBILE_SERVICE_WORKER_URL = "/m/service-worker.js";
4
- /** Register the mobile shell worker when the current browser supports it. */
5
- export declare function registerMobilePwa(serviceWorker?: Pick<ServiceWorkerContainer, 'register'> | undefined): Promise<void>;
6
- //# sourceMappingURL=mobile-pwa.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"mobile-pwa.d.ts","sourceRoot":"","sources":["../../src/mobile-pwa.ts"],"names":[],"mappings":"AAAA,6DAA6D;AAC7D,eAAO,MAAM,gBAAgB,QAAQ,CAAA;AACrC,eAAO,MAAM,yBAAyB,yBAAyB,CAAA;AAE/D,6EAA6E;AAC7E,wBAAsB,iBAAiB,CACrC,aAAa,GAAE,IAAI,CAAC,sBAAsB,EAAE,UAAU,CAAC,GAAG,SAAkF,GAC3I,OAAO,CAAC,IAAI,CAAC,CAWf"}
@@ -1,17 +0,0 @@
1
- /** PWA registration for the standalone /m mobile surface. */
2
- export const MOBILE_PWA_SCOPE = '/m/';
3
- export const MOBILE_SERVICE_WORKER_URL = '/m/service-worker.js';
4
- /** Register the mobile shell worker when the current browser supports it. */
5
- export async function registerMobilePwa(serviceWorker = typeof navigator === 'undefined' ? undefined : navigator.serviceWorker) {
6
- if (serviceWorker === undefined)
7
- return;
8
- try {
9
- await serviceWorker.register(MOBILE_SERVICE_WORKER_URL, {
10
- scope: MOBILE_PWA_SCOPE,
11
- updateViaCache: 'none',
12
- });
13
- }
14
- catch {
15
- // HTTP LAN origins cannot register workers; the online mobile UI still works.
16
- }
17
- }
@@ -1,13 +0,0 @@
1
- /**
2
- * The mobile surface's page routes: /m canonicalizes to /m/, which serves the
3
- * standalone phone UI. The page and worker live in the /m/ scope so the PWA
4
- * can cache only its static shell; the paired-device data channel remains at
5
- * /m/api and is never handled by the worker.
6
- */
7
- import type { WebRoute } from '@deepseek-ai/dsh-host-webserver';
8
- /**
9
- * Build the mobile page routes.
10
- * @returns Exact routes for the canonical page, static shell, and PWA assets.
11
- */
12
- export declare function makeMobileRoutes(): WebRoute[];
13
- //# sourceMappingURL=mobile-routes.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"mobile-routes.d.ts","sourceRoot":"","sources":["../../src/mobile-routes.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAOH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iCAAiC,CAAA;AAwH/D;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,QAAQ,EAAE,CA8F7C"}
@@ -1,217 +0,0 @@
1
- /**
2
- * The mobile surface's page routes: /m canonicalizes to /m/, which serves the
3
- * standalone phone UI. The page and worker live in the /m/ scope so the PWA
4
- * can cache only its static shell; the paired-device data channel remains at
5
- * /m/api and is never handled by the worker.
6
- */
7
- import { readFile } from 'node:fs/promises';
8
- import { existsSync } from 'node:fs';
9
- import { fileURLToPath } from 'node:url';
10
- import { gzipSync } from 'node:zlib';
11
- const MOBILE_ROOT = '/m/';
12
- const MOBILE_BUNDLE_URL = '/m/mobile.js';
13
- const MOBILE_MANIFEST_URL = '/m/manifest.webmanifest';
14
- const MOBILE_WORKER_URL = '/m/service-worker.js';
15
- const MOBILE_OFFLINE_URL = '/m/offline.html';
16
- /** The standalone mobile bundle (built artifact, next to this file's own lib output). */
17
- function mobileBundlePath() {
18
- return fileURLToPath(new URL('../lib/mobile.js', import.meta.url));
19
- }
20
- /** A package asset available to the host after a registry or git install. */
21
- function mobileAssetPath(name) {
22
- return fileURLToPath(new URL('../assets/' + name, import.meta.url));
23
- }
24
- /** The mobile page shell: self-contained, with no document-level user data. */
25
- function pageHtml(bundleUrl) {
26
- return [
27
- '<!doctype html>',
28
- '<html lang="zh-CN">',
29
- '<head>',
30
- '<meta charset="utf-8">',
31
- '<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no, viewport-fit=cover">',
32
- '<meta name="theme-color" content="#f3f5f9">',
33
- '<meta name="referrer" content="no-referrer">',
34
- '<meta name="mobile-web-app-capable" content="yes">',
35
- '<meta name="apple-mobile-web-app-capable" content="yes">',
36
- '<meta name="apple-mobile-web-app-title" content="DSH Remote">',
37
- '<link rel="manifest" href="/m/manifest.webmanifest">',
38
- '<link rel="apple-touch-icon" href="/m/apple-touch-icon.png">',
39
- '<title>远程访问</title>',
40
- '</head>',
41
- '<body>',
42
- '<div id="root"></div>',
43
- '<script type="module" src="' + bundleUrl + '"></script>',
44
- '</body>',
45
- '</html>',
46
- ].join('');
47
- }
48
- /** The installable app identity and icon declarations for the /m scope. */
49
- function manifestJson() {
50
- return JSON.stringify({
51
- id: MOBILE_ROOT,
52
- name: 'DSH Remote',
53
- short_name: 'DSH Remote',
54
- start_url: MOBILE_ROOT,
55
- scope: MOBILE_ROOT,
56
- display: 'standalone',
57
- background_color: '#151424',
58
- theme_color: '#f3f5f9',
59
- icons: [
60
- { src: '/m/icon-192.png', sizes: '192x192', type: 'image/png', purpose: 'any' },
61
- { src: '/m/icon-512.png', sizes: '512x512', type: 'image/png', purpose: 'any maskable' },
62
- ],
63
- }, null, 2);
64
- }
65
- /** A static fallback that contains no paired-device, session, or workspace data. */
66
- function offlineHtml() {
67
- return [
68
- '<!doctype html>',
69
- '<html lang="zh-CN">',
70
- '<head>',
71
- '<meta charset="utf-8">',
72
- '<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">',
73
- '<meta name="theme-color" content="#151424">',
74
- '<title>DSH Remote</title>',
75
- '<style>body{margin:0;background:#151424;color:#f3f5f9;font:16px system-ui,sans-serif}main{box-sizing:border-box;display:grid;min-height:100vh;place-content:center;padding:32px;text-align:center}h1{margin:0 0 12px;font-size:24px}p{margin:0;color:#c4c7d8;line-height:1.5}</style>',
76
- '</head>',
77
- '<body><main><h1>DSH Remote</h1><p>Cannot reach the running DSH host. Restore the connection and reopen the app.</p></main></body>',
78
- '</html>',
79
- ].join('');
80
- }
81
- /** Send a small static UTF-8 body with revalidation headers. */
82
- function writeStatic(res, status, type, body) {
83
- res.writeHead(status, {
84
- 'content-type': type + '; charset=utf-8',
85
- 'cache-control': 'no-cache',
86
- 'referrer-policy': 'no-referrer',
87
- });
88
- res.end(body);
89
- }
90
- /** Send the worker with the same scope it registers for, without HTTP caching. */
91
- function writeServiceWorker(res, body) {
92
- res.writeHead(200, {
93
- 'content-type': 'text/javascript; charset=utf-8',
94
- 'cache-control': 'no-cache',
95
- 'referrer-policy': 'no-referrer',
96
- 'service-worker-allowed': MOBILE_ROOT,
97
- });
98
- res.end(body);
99
- }
100
- /** Send a PNG body without decoding it to UTF-8. */
101
- function writePng(res, status, body) {
102
- res.writeHead(status, {
103
- 'content-type': 'image/png',
104
- 'cache-control': 'public, max-age=31536000, immutable',
105
- 'referrer-policy': 'no-referrer',
106
- });
107
- res.end(body);
108
- }
109
- /** Canonicalize the old /m route while retaining pair and workspace query parameters. */
110
- function redirectToMobileRoot(req, res) {
111
- const url = new URL(req.url ?? '/m', 'http://x');
112
- res.writeHead(308, {
113
- location: MOBILE_ROOT + url.search,
114
- 'cache-control': 'no-store',
115
- 'referrer-policy': 'no-referrer',
116
- });
117
- res.end();
118
- }
119
- /**
120
- * Build the mobile page routes.
121
- * @returns Exact routes for the canonical page, static shell, and PWA assets.
122
- */
123
- export function makeMobileRoutes() {
124
- const handlePage = (_req, res) => {
125
- writeStatic(res, 200, 'text/html', pageHtml(MOBILE_BUNDLE_URL));
126
- };
127
- const handleManifest = (_req, res) => {
128
- writeStatic(res, 200, 'application/manifest+json', manifestJson());
129
- };
130
- const handleOffline = (_req, res) => {
131
- writeStatic(res, 200, 'text/html', offlineHtml());
132
- };
133
- // The bundle is immutable for the process lifetime (a rebuild requires a
134
- // host restart), so the body is read from disk once, not per phone.
135
- let bundleBody;
136
- let bundleGzip;
137
- const handleBundle = async (req, res) => {
138
- if (bundleBody === undefined) {
139
- const path = mobileBundlePath();
140
- if (!existsSync(path)) {
141
- writeStatic(res, 503, 'text/plain', 'mobile bundle not built: run pnpm --filter @linxin666/dsh-remote-web-ui build');
142
- return;
143
- }
144
- try {
145
- bundleBody = await readFile(path, 'utf8');
146
- bundleGzip = gzipSync(Buffer.from(bundleBody, 'utf8'));
147
- }
148
- catch {
149
- writeStatic(res, 500, 'text/plain', 'failed to read the mobile bundle');
150
- return;
151
- }
152
- }
153
- const acceptEncoding = req.headers['accept-encoding'] ?? '';
154
- const acceptsGzip = typeof acceptEncoding === 'string' && acceptEncoding.includes('gzip') && bundleGzip !== undefined;
155
- if (acceptsGzip) {
156
- res.writeHead(200, {
157
- 'content-type': 'text/javascript; charset=utf-8',
158
- 'content-encoding': 'gzip',
159
- 'cache-control': 'no-cache',
160
- vary: 'Accept-Encoding',
161
- 'referrer-policy': 'no-referrer',
162
- });
163
- res.end(bundleGzip);
164
- }
165
- else {
166
- res.writeHead(200, {
167
- 'content-type': 'text/javascript; charset=utf-8',
168
- 'cache-control': 'no-cache',
169
- vary: 'Accept-Encoding',
170
- 'referrer-policy': 'no-referrer',
171
- });
172
- res.end(bundleBody);
173
- }
174
- };
175
- let workerBody;
176
- const handleWorker = async (_req, res) => {
177
- if (workerBody === undefined) {
178
- const path = mobileAssetPath('mobile-service-worker.js');
179
- if (!existsSync(path)) {
180
- writeStatic(res, 503, 'text/plain', 'mobile service worker not found');
181
- return;
182
- }
183
- try {
184
- workerBody = await readFile(path, 'utf8');
185
- }
186
- catch {
187
- writeStatic(res, 500, 'text/plain', 'failed to read the mobile service worker');
188
- return;
189
- }
190
- }
191
- writeServiceWorker(res, workerBody);
192
- };
193
- const makeIconHandler = (asset) => async (_req, res) => {
194
- const path = mobileAssetPath(asset);
195
- if (!existsSync(path)) {
196
- writeStatic(res, 404, 'text/plain', asset + ' not found');
197
- return;
198
- }
199
- try {
200
- writePng(res, 200, await readFile(path));
201
- }
202
- catch {
203
- writeStatic(res, 500, 'text/plain', 'failed to read ' + asset);
204
- }
205
- };
206
- return [
207
- { kind: 'exact', path: '/m', handler: redirectToMobileRoot },
208
- { kind: 'exact', path: MOBILE_ROOT, handler: handlePage },
209
- { kind: 'exact', path: MOBILE_BUNDLE_URL, handler: handleBundle },
210
- { kind: 'exact', path: MOBILE_MANIFEST_URL, handler: handleManifest },
211
- { kind: 'exact', path: MOBILE_WORKER_URL, handler: handleWorker },
212
- { kind: 'exact', path: MOBILE_OFFLINE_URL, handler: handleOffline },
213
- { kind: 'exact', path: '/m/apple-touch-icon.png', handler: makeIconHandler('apple-touch-icon.png') },
214
- { kind: 'exact', path: '/m/icon-192.png', handler: makeIconHandler('mobile-icon-192.png') },
215
- { kind: 'exact', path: '/m/icon-512.png', handler: makeIconHandler('mobile-icon-512.png') },
216
- ];
217
- }
@@ -1,17 +0,0 @@
1
- import type { ApiProxy } from '@deepseek-ai/dsh-host-apiproxy/api';
2
- import type { WebRoute } from '@deepseek-ai/dsh-host-webserver';
3
- import type { PairingService } from './pairing.ts';
4
- export declare const PAIRED_MODEL_CATALOG_PATHS: {
5
- readonly catalog: "/api/pair/model-catalog";
6
- readonly discover: "/api/pair/model-catalog/discover";
7
- readonly upsert: "/api/pair/model-catalog/upsert";
8
- };
9
- export interface PairedModelCatalogDeps {
10
- service: PairingService;
11
- apiProxy: ApiProxy;
12
- /** The LAN IP literals the host fence accepts, mirroring the /api/pair fence. */
13
- lanAddresses: readonly string[];
14
- }
15
- /** Build the narrow paired-device model catalog routes. */
16
- export declare function makePairedModelCatalogRoutes(deps: PairedModelCatalogDeps): WebRoute[];
17
- //# sourceMappingURL=paired-model-catalog.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"paired-model-catalog.d.ts","sourceRoot":"","sources":["../../src/paired-model-catalog.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,QAAQ,EAAqF,MAAM,oCAAoC,CAAA;AACrJ,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iCAAiC,CAAA;AAE/D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAA;AA6BlD,eAAO,MAAM,0BAA0B;;;;CAI7B,CAAA;AAEV,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,cAAc,CAAA;IACvB,QAAQ,EAAE,QAAQ,CAAA;IAClB,iFAAiF;IACjF,YAAY,EAAE,SAAS,MAAM,EAAE,CAAA;CAChC;AAsJD,2DAA2D;AAC3D,wBAAgB,4BAA4B,CAAC,IAAI,EAAE,sBAAsB,GAAG,QAAQ,EAAE,CA2ErF"}