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

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 (91) hide show
  1. package/README.i18n.yaml +2 -2
  2. package/README.md +41 -19
  3. package/README.zh.md +17 -12
  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 +37 -10
  8. package/lib/client.js.map +1 -1
  9. package/lib/index.js +290 -53
  10. package/lib/mobile.js +278 -17
  11. package/lib/mobile.js.map +1 -1
  12. package/lib/types/client/PluginSettingsCard.d.ts +6 -0
  13. package/lib/types/client/PluginSettingsCard.d.ts.map +1 -1
  14. package/lib/types/client/PluginSettingsCard.js +5 -3
  15. package/lib/types/client/RemoteEntry.js +2 -2
  16. package/lib/types/client/RemoteSettingsCard.d.ts.map +1 -1
  17. package/lib/types/client/RemoteSettingsCard.js +1 -1
  18. package/lib/types/client/UpdateEntry.d.ts.map +1 -1
  19. package/lib/types/client/UpdateEntry.js +36 -3
  20. package/lib/types/client/deep-link.js +1 -1
  21. package/lib/types/client/locales.d.ts +2 -0
  22. package/lib/types/client/locales.d.ts.map +1 -1
  23. package/lib/types/client/locales.js +2 -0
  24. package/lib/types/gate.d.ts +9 -0
  25. package/lib/types/gate.d.ts.map +1 -1
  26. package/lib/types/gate.js +15 -4
  27. package/lib/types/index.d.ts +25 -0
  28. package/lib/types/index.d.ts.map +1 -1
  29. package/lib/types/index.js +30 -13
  30. package/lib/types/mobile/PairRequiredView.d.ts +7 -0
  31. package/lib/types/mobile/PairRequiredView.d.ts.map +1 -0
  32. package/lib/types/mobile/PairRequiredView.js +28 -0
  33. package/lib/types/mobile/PairRequiredView.test.d.ts +2 -0
  34. package/lib/types/mobile/PairRequiredView.test.d.ts.map +1 -0
  35. package/lib/types/mobile/PairRequiredView.test.js +24 -0
  36. package/lib/types/mobile/index.js +14 -1
  37. package/lib/types/mobile/mobile-styles.d.ts +1 -1
  38. package/lib/types/mobile/mobile-styles.d.ts.map +1 -1
  39. package/lib/types/mobile/mobile-styles.js +48 -0
  40. package/lib/types/mobile/pairing.d.ts +31 -0
  41. package/lib/types/mobile/pairing.d.ts.map +1 -0
  42. package/lib/types/mobile/pairing.js +62 -0
  43. package/lib/types/mobile/views/App.d.ts +12 -5
  44. package/lib/types/mobile/views/App.d.ts.map +1 -1
  45. package/lib/types/mobile/views/App.js +34 -7
  46. package/lib/types/mobile/views/App.test.d.ts +2 -0
  47. package/lib/types/mobile/views/App.test.d.ts.map +1 -0
  48. package/lib/types/mobile/views/App.test.js +52 -0
  49. package/lib/types/mobile-pwa.d.ts +6 -0
  50. package/lib/types/mobile-pwa.d.ts.map +1 -0
  51. package/lib/types/mobile-pwa.js +17 -0
  52. package/lib/types/mobile-routes.d.ts +5 -8
  53. package/lib/types/mobile-routes.d.ts.map +1 -1
  54. package/lib/types/mobile-routes.js +115 -30
  55. package/lib/types/pairing-access.d.ts +28 -0
  56. package/lib/types/pairing-access.d.ts.map +1 -0
  57. package/lib/types/pairing-access.js +26 -0
  58. package/lib/types/pairing.d.ts +27 -0
  59. package/lib/types/pairing.d.ts.map +1 -1
  60. package/lib/types/pairing.js +68 -0
  61. package/lib/types/pairing.persist.test.d.ts +2 -0
  62. package/lib/types/pairing.persist.test.d.ts.map +1 -0
  63. package/lib/types/pairing.persist.test.js +128 -0
  64. package/lib/types/routes.js +1 -1
  65. package/lib/types/update.d.ts +3 -3
  66. package/lib/types/update.d.ts.map +1 -1
  67. package/lib/types/update.js +34 -11
  68. package/package.json +12 -12
  69. package/src/client/PluginSettingsCard.tsx +10 -0
  70. package/src/client/RemoteEntry.tsx +2 -2
  71. package/src/client/RemoteSettingsCard.tsx +1 -0
  72. package/src/client/UpdateEntry.tsx +36 -4
  73. package/src/client/deep-link.ts +1 -1
  74. package/src/client/locales.ts +2 -0
  75. package/src/client/remote.module.css +26 -0
  76. package/src/gate.ts +15 -3
  77. package/src/index.ts +46 -15
  78. package/src/mobile/PairRequiredView.test.tsx +28 -0
  79. package/src/mobile/PairRequiredView.tsx +58 -0
  80. package/src/mobile/index.tsx +15 -1
  81. package/src/mobile/mobile-styles.ts +48 -0
  82. package/src/mobile/pairing.ts +77 -0
  83. package/src/mobile/views/App.test.tsx +62 -0
  84. package/src/mobile/views/App.tsx +53 -6
  85. package/src/mobile-pwa.ts +19 -0
  86. package/src/mobile-routes.ts +123 -30
  87. package/src/pairing-access.ts +36 -0
  88. package/src/pairing.persist.test.ts +145 -0
  89. package/src/pairing.ts +70 -1
  90. package/src/routes.ts +1 -1
  91. package/src/update.ts +40 -12
package/lib/mobile.js CHANGED
@@ -11958,7 +11958,7 @@ function superRefine(fn, params) {
11958
11958
  return /* @__PURE__ */ _superRefine(fn, params);
11959
11959
  }
11960
11960
  //#endregion
11961
- //#region ../../node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_8335eca05d5647f26dcc0c8fd5a39ec0/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/rpc.schema.js
11961
+ //#region ../../node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_36988429fa7c61ceeac966dddad3597f/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/rpc.schema.js
11962
11962
  /**
11963
11963
  * Message-layer zod schemas: the four wire full forms + error body +
11964
11964
  * carrier receipt. The payload slot is unknown in the full-form schemas — business payloads
@@ -12139,11 +12139,6 @@ const rpcErrorSchema = discriminatedUnion("code", [
12139
12139
  message: string(),
12140
12140
  details: object({ ns: string() })
12141
12141
  }),
12142
- object({
12143
- code: literal("settings-not-exposed"),
12144
- message: string(),
12145
- details: object({ ns: string() })
12146
- }),
12147
12142
  object({
12148
12143
  code: literal("settings-conflict"),
12149
12144
  message: string(),
@@ -12272,7 +12267,7 @@ union([object({ accepted: literal(true) }), object({
12272
12267
  reason: union([literal("not-pending"), literal("bad-response")])
12273
12268
  })]);
12274
12269
  //#endregion
12275
- //#region ../../node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_8335eca05d5647f26dcc0c8fd5a39ec0/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/session-search.js
12270
+ //#region ../../node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_36988429fa7c61ceeac966dddad3597f/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/session-search.js
12276
12271
  /**
12277
12272
  * Return the longest prefix containing at most `maximum` Unicode code points.
12278
12273
  * @param value - text to bound.
@@ -12290,7 +12285,7 @@ function truncateUnicodeCodePoints(value, maximum) {
12290
12285
  return value;
12291
12286
  }
12292
12287
  //#endregion
12293
- //#region ../../node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_8335eca05d5647f26dcc0c8fd5a39ec0/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/sessions.schema.js
12288
+ //#region ../../node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_36988429fa7c61ceeac966dddad3597f/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/sessions.schema.js
12294
12289
  /**
12295
12290
  * sessions domain zod schemas (names derived from map keys: sessionListRequestSchema /
12296
12291
  * sessionListValueSchema). SessionEvent passthrough = strict envelope (type/seq/time) + wide
@@ -12526,7 +12521,7 @@ object({ accepted: literal(true) });
12526
12521
  object({ sessionId: sessionIdSchema });
12527
12522
  object({ accepted: literal(true) });
12528
12523
  //#endregion
12529
- //#region ../../node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_8335eca05d5647f26dcc0c8fd5a39ec0/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/approvals.schema.js
12524
+ //#region ../../node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_36988429fa7c61ceeac966dddad3597f/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/approvals.schema.js
12530
12525
  /**
12531
12526
  * approvals domain zod schemas (respond is a client-response; the payload schema serves
12532
12527
  * the /api/respond endpoint's second parse after routing via the pending table).
@@ -12560,7 +12555,7 @@ const taskViewSchema = object({
12560
12555
  finishedAt: number().int().nonnegative().optional()
12561
12556
  });
12562
12557
  //#endregion
12563
- //#region ../../node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_8335eca05d5647f26dcc0c8fd5a39ec0/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/workspace.schema.js
12558
+ //#region ../../node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_36988429fa7c61ceeac966dddad3597f/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/workspace.schema.js
12564
12559
  /**
12565
12560
  * workspace domain zod schemas (names derived from map keys). The
12566
12561
  * WorkspaceId brand cast lives in sessions.schema (see the note there) and
@@ -12606,7 +12601,7 @@ object({ workspace: workspaceViewSchema });
12606
12601
  object({ sessionId: sessionIdSchema });
12607
12602
  object({ archivedSessionIds: array(sessionIdSchema) });
12608
12603
  //#endregion
12609
- //#region ../../node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.6_8335eca05d5647f26dcc0c8fd5a39ec0/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/events.schema.js
12604
+ //#region ../../node_modules/.pnpm/@deepseek-ai+dsh-host-apiproxy@0.1.0-rc.7_36988429fa7c61ceeac966dddad3597f/node_modules/@deepseek-ai/dsh-host-apiproxy/lib/types/api/events.schema.js
12610
12605
  /**
12611
12606
  * events domain zod schemas: MuxFrame / HostFrame unions (discriminatedUnion('type')).
12612
12607
  * A frame is the payload slot of the ServerRequest full form; the SessionEvent inside
@@ -15136,6 +15131,154 @@ function WorkspaceView({ initialWorkspaceId, onPick }) {
15136
15131
  });
15137
15132
  }
15138
15133
  //#endregion
15134
+ //#region src/mobile/pairing.ts
15135
+ const MOBILE_ROOT = "/m/";
15136
+ /** Parse a pairing token or a copied pairing link without following its origin. */
15137
+ function parseMobilePairInput(value) {
15138
+ const trimmed = value.trim();
15139
+ if (trimmed === "") return void 0;
15140
+ try {
15141
+ const url = new URL(trimmed);
15142
+ const token = url.searchParams.get("pair");
15143
+ if (token === null || token === "") return void 0;
15144
+ const workspaceId = url.searchParams.get("workspace");
15145
+ return {
15146
+ token,
15147
+ ...workspaceId !== null && workspaceId !== "" ? { workspaceId } : {}
15148
+ };
15149
+ } catch {
15150
+ return { token: trimmed };
15151
+ }
15152
+ }
15153
+ /** Build the safe, token-free mobile destination after successful pairing. */
15154
+ function mobilePairPath(workspaceId) {
15155
+ return workspaceId === void 0 ? MOBILE_ROOT : "/m/?workspace=" + encodeURIComponent(workspaceId);
15156
+ }
15157
+ /** Accept one pairing token on this exact browser or installed-web-app context. */
15158
+ async function acceptMobilePair(token, fetcher = fetch) {
15159
+ try {
15160
+ const response = await fetcher("/api/pair/accept", {
15161
+ method: "POST",
15162
+ headers: { "content-type": "application/json" },
15163
+ body: JSON.stringify({ token })
15164
+ });
15165
+ if (response.ok) return { ok: true };
15166
+ if (response.status === 404) return {
15167
+ ok: false,
15168
+ message: "配对链接无效或已过期。"
15169
+ };
15170
+ if (response.status === 409) return {
15171
+ ok: false,
15172
+ message: "配对链接已被使用。"
15173
+ };
15174
+ return {
15175
+ ok: false,
15176
+ message: "此设备无法使用该配对链接。"
15177
+ };
15178
+ } catch {
15179
+ return {
15180
+ ok: false,
15181
+ message: "无法连接到配对服务。"
15182
+ };
15183
+ }
15184
+ }
15185
+ /** Consume a QR pairing token before the mobile application starts making RPC calls. */
15186
+ async function consumeMobilePairUrl(href, fetcher = fetch) {
15187
+ let url;
15188
+ try {
15189
+ url = new URL(href);
15190
+ } catch {
15191
+ return { kind: "none" };
15192
+ }
15193
+ const token = url.searchParams.get("pair");
15194
+ if (token === null || token === "") return { kind: "none" };
15195
+ const workspaceId = url.searchParams.get("workspace");
15196
+ const path = mobilePairPath(workspaceId === null || workspaceId === "" ? void 0 : workspaceId);
15197
+ const result = await acceptMobilePair(token, fetcher);
15198
+ return result.ok ? {
15199
+ kind: "accepted",
15200
+ path
15201
+ } : {
15202
+ kind: "failed",
15203
+ path,
15204
+ message: result.message
15205
+ };
15206
+ }
15207
+ //#endregion
15208
+ //#region src/mobile/PairRequiredView.tsx
15209
+ /** Device-pairing gate for installed mobile web-app contexts with isolated storage. */
15210
+ /** Collect a fresh desktop-issued pairing link when this client has no paired cookie. */
15211
+ function PairRequiredView({ initialError, onPaired }) {
15212
+ const [value, setValue] = (0, import_react.useState)("");
15213
+ const [error, setError] = (0, import_react.useState)(initialError);
15214
+ const [submitting, setSubmitting] = (0, import_react.useState)(false);
15215
+ const submit = async (event) => {
15216
+ event.preventDefault();
15217
+ const input = parseMobilePairInput(value);
15218
+ if (input === void 0) {
15219
+ setError("请输入有效的配对链接。");
15220
+ return;
15221
+ }
15222
+ setSubmitting(true);
15223
+ setError(void 0);
15224
+ const result = await acceptMobilePair(input.token);
15225
+ setSubmitting(false);
15226
+ if (!result.ok) {
15227
+ setError(result.message);
15228
+ return;
15229
+ }
15230
+ onPaired(mobilePairPath(input.workspaceId));
15231
+ };
15232
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("main", {
15233
+ className: "mobile mobile-pair",
15234
+ "aria-labelledby": "mobile-pair-title",
15235
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("form", {
15236
+ className: "mobile-pairCard",
15237
+ onSubmit: (event) => {
15238
+ submit(event);
15239
+ },
15240
+ children: [
15241
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("h1", {
15242
+ id: "mobile-pair-title",
15243
+ className: "mobile-title",
15244
+ children: "设备配对"
15245
+ }),
15246
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
15247
+ className: "mobile-muted",
15248
+ children: "粘贴桌面端复制的配对链接以连接此设备。"
15249
+ }),
15250
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("label", {
15251
+ className: "mobile-pairLabel",
15252
+ htmlFor: "mobile-pair-link",
15253
+ children: "配对链接"
15254
+ }),
15255
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("input", {
15256
+ id: "mobile-pair-link",
15257
+ className: "mobile-pairInput",
15258
+ value,
15259
+ onChange: (event) => {
15260
+ setValue(event.target.value);
15261
+ },
15262
+ autoComplete: "off",
15263
+ autoCapitalize: "off",
15264
+ spellCheck: false
15265
+ }),
15266
+ error === void 0 ? null : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
15267
+ className: "mobile-error",
15268
+ role: "alert",
15269
+ children: error
15270
+ }),
15271
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
15272
+ className: "mobile-new mobile-pairSubmit",
15273
+ type: "submit",
15274
+ disabled: submitting,
15275
+ children: submitting ? "正在配对" : "配对"
15276
+ })
15277
+ ]
15278
+ })
15279
+ });
15280
+ }
15281
+ //#endregion
15139
15282
  //#region src/mobile/views/App.tsx
15140
15283
  /**
15141
15284
  * Mobile surface root: the view state machine (workspaces → sessions →
@@ -15172,11 +15315,60 @@ function formatTime(epochMs) {
15172
15315
  if (date.toDateString() === yesterday.toDateString()) return `昨天 ${clock}`;
15173
15316
  return `${String(date.getMonth() + 1)}月${String(date.getDate())}日 ${clock}`;
15174
15317
  }
15175
- /**
15176
- * The surface root.
15177
- * @returns the app tree.
15178
- */
15179
- function App() {
15318
+ /** Whether the mobile gateway rejected this browser for lack of a paired cookie. */
15319
+ function isUnpairedMobileError(error) {
15320
+ return error instanceof RpcTransportError && error.message === "HTTP 403";
15321
+ }
15322
+ /** Classify an initial mobile preference failure without treating outage as authorization. */
15323
+ function mobilePairStateForError(error) {
15324
+ return isUnpairedMobileError(error) ? "unpaired" : "unavailable";
15325
+ }
15326
+ /** Gate the independent mobile bundle until its own browser context is paired. */
15327
+ function App({ initialPairError }) {
15328
+ const [pairState, setPairState] = (0, import_react.useState)("checking");
15329
+ (0, import_react.useEffect)(() => {
15330
+ let current = true;
15331
+ fetchMobilePreferences().then(() => {
15332
+ if (current) setPairState("paired");
15333
+ }, (error) => {
15334
+ if (current) setPairState(mobilePairStateForError(error));
15335
+ });
15336
+ return () => {
15337
+ current = false;
15338
+ };
15339
+ }, []);
15340
+ if (pairState === "checking") return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("main", {
15341
+ className: "mobile mobile-empty",
15342
+ children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
15343
+ className: "mobile-muted",
15344
+ children: "正在连接..."
15345
+ })
15346
+ });
15347
+ if (pairState === "unpaired") return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PairRequiredView, {
15348
+ initialError: initialPairError,
15349
+ onPaired: (path) => {
15350
+ window.location.replace(path);
15351
+ }
15352
+ });
15353
+ if (pairState === "unavailable") return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("main", {
15354
+ className: "mobile mobile-empty",
15355
+ children: [/* @__PURE__ */ (0, import_jsx_runtime.jsx)("p", {
15356
+ className: "mobile-error",
15357
+ role: "alert",
15358
+ children: "无法连接到运行中的 DSH host。"
15359
+ }), /* @__PURE__ */ (0, import_jsx_runtime.jsx)("button", {
15360
+ className: "mobile-new",
15361
+ type: "button",
15362
+ onClick: () => {
15363
+ window.location.reload();
15364
+ },
15365
+ children: "重试"
15366
+ })]
15367
+ });
15368
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PairedApp, {});
15369
+ }
15370
+ /** The existing remote mobile surface, mounted only after device pairing succeeds. */
15371
+ function PairedApp() {
15180
15372
  const [route, setRoute] = (0, import_react.useState)({ kind: "workspaces" });
15181
15373
  const [initialWorkspaceId, setInitialWorkspaceId] = (0, import_react.useState)(() => mobileWorkspaceTarget(window.location.search));
15182
15374
  const muxRef = (0, import_react.useRef)(void 0);
@@ -16283,7 +16475,66 @@ body {
16283
16475
  transition: none;
16284
16476
  }
16285
16477
  }
16478
+
16479
+ /* ── installed-app pairing ───────────────────────────────────────────── */
16480
+
16481
+ .mobile-pair {
16482
+ min-height: 100dvh;
16483
+ display: grid;
16484
+ place-items: center;
16485
+ padding: 24px;
16486
+ }
16487
+
16488
+ .mobile-pairCard {
16489
+ display: grid;
16490
+ width: min(100%, 420px);
16491
+ gap: 12px;
16492
+ padding: 24px;
16493
+ border: 1px solid var(--m-border);
16494
+ border-radius: 12px;
16495
+ background: var(--m-bg-raised);
16496
+ box-shadow: var(--m-shadow-raise);
16497
+ }
16498
+
16499
+ .mobile-pairLabel {
16500
+ color: var(--m-text-secondary);
16501
+ font-size: 13px;
16502
+ font-weight: 600;
16503
+ }
16504
+
16505
+ .mobile-pairInput {
16506
+ width: 100%;
16507
+ min-height: 42px;
16508
+ box-sizing: border-box;
16509
+ padding: 9px 12px;
16510
+ border: 1px solid var(--m-border);
16511
+ border-radius: 8px;
16512
+ background: var(--m-bg-input);
16513
+ color: var(--m-text);
16514
+ font: inherit;
16515
+ outline: none;
16516
+ }
16517
+
16518
+ .mobile-pairInput:focus-visible {
16519
+ border-color: var(--m-accent);
16520
+ box-shadow: 0 0 0 2px var(--m-bg), 0 0 0 4px var(--m-accent);
16521
+ }
16522
+
16523
+ .mobile-pairSubmit {
16524
+ width: 100%;
16525
+ }
16286
16526
  `;
16527
+ const MOBILE_SERVICE_WORKER_URL = "/m/service-worker.js";
16528
+ /** Register the mobile shell worker when the current browser supports it. */
16529
+ async function registerMobilePwa(serviceWorker = typeof navigator === "undefined" ? void 0 : navigator.serviceWorker) {
16530
+ if (serviceWorker === void 0) return;
16531
+ try {
16532
+ await serviceWorker.register(MOBILE_SERVICE_WORKER_URL, {
16533
+ scope: "/m/",
16534
+ updateViaCache: "none"
16535
+ });
16536
+ } catch {}
16537
+ }
16287
16538
  //#endregion
16288
16539
  //#region src/mobile/index.tsx
16289
16540
  /**
@@ -16301,7 +16552,17 @@ style.textContent = mobileCss;
16301
16552
  document.head.appendChild(style);
16302
16553
  const root = document.getElementById("root");
16303
16554
  if (root === null) throw new Error("mobile: #root missing");
16304
- (0, import_client.createRoot)(root).render(/* @__PURE__ */ (0, import_jsx_runtime.jsx)(App, {}));
16555
+ bootMobile(root);
16556
+ async function bootMobile(mount) {
16557
+ const pair = await consumeMobilePairUrl(window.location.href);
16558
+ if (pair.kind === "accepted") {
16559
+ window.location.replace(pair.path);
16560
+ return;
16561
+ }
16562
+ if (pair.kind === "failed") window.history.replaceState(null, "", pair.path);
16563
+ registerMobilePwa();
16564
+ (0, import_client.createRoot)(mount).render(/* @__PURE__ */ (0, import_jsx_runtime.jsx)(App, { initialPairError: pair.kind === "failed" ? pair.message : void 0 }));
16565
+ }
16305
16566
  //#endregion
16306
16567
 
16307
16568
  //# sourceMappingURL=mobile.js.map