@linxin666/dsh-remote-web-ui 0.4.5 → 0.4.7

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 (65) hide show
  1. package/README.i18n.yaml +2 -2
  2. package/README.md +13 -13
  3. package/README.zh.md +13 -13
  4. package/lib/client.js +25 -92
  5. package/lib/client.js.map +1 -1
  6. package/lib/index.js +408 -53
  7. package/lib/types/client/RemoteEntry.d.ts.map +1 -1
  8. package/lib/types/client/RemoteEntry.js +3 -15
  9. package/lib/types/client/RemotePanel.d.ts +1 -9
  10. package/lib/types/client/RemotePanel.d.ts.map +1 -1
  11. package/lib/types/client/RemotePanel.js +7 -4
  12. package/lib/types/client/locales.d.ts +4 -8
  13. package/lib/types/client/locales.d.ts.map +1 -1
  14. package/lib/types/client/locales.js +4 -8
  15. package/lib/types/client/mobile-adapt.d.ts.map +1 -1
  16. package/lib/types/client/mobile-adapt.js +30 -3
  17. package/lib/types/client/plugin-card-seat.d.ts +5 -0
  18. package/lib/types/client/plugin-card-seat.d.ts.map +1 -1
  19. package/lib/types/client/plugin-card-seat.js +2 -0
  20. package/lib/types/client/settings-entry-form.d.ts.map +1 -1
  21. package/lib/types/client/settings-entry-form.js +0 -1
  22. package/lib/types/detached-work.d.ts +7 -7
  23. package/lib/types/detached-work.d.ts.map +1 -1
  24. package/lib/types/detached-work.js +9 -8
  25. package/lib/types/index.d.ts +14 -0
  26. package/lib/types/index.d.ts.map +1 -1
  27. package/lib/types/index.js +67 -17
  28. package/lib/types/lan-source.d.ts +65 -0
  29. package/lib/types/lan-source.d.ts.map +1 -0
  30. package/lib/types/lan-source.js +113 -0
  31. package/lib/types/lan.d.ts +49 -3
  32. package/lib/types/lan.d.ts.map +1 -1
  33. package/lib/types/lan.js +120 -6
  34. package/lib/types/remote-api.d.ts +7 -2
  35. package/lib/types/remote-api.d.ts.map +1 -1
  36. package/lib/types/remote-api.js +17 -2
  37. package/lib/types/remote-channel-boot.d.ts.map +1 -1
  38. package/lib/types/remote-channel-boot.js +4 -1
  39. package/lib/types/routes.d.ts +71 -9
  40. package/lib/types/routes.d.ts.map +1 -1
  41. package/lib/types/routes.js +157 -27
  42. package/lib/types/tunnel-plan.d.ts +8 -2
  43. package/lib/types/tunnel-plan.d.ts.map +1 -1
  44. package/lib/types/tunnel-plan.js +9 -1
  45. package/package.json +20 -25
  46. package/src/client/RemoteEntry.tsx +2 -18
  47. package/src/client/RemotePanel.tsx +9 -43
  48. package/src/client/locales.ts +4 -8
  49. package/src/client/mobile-adapt.ts +30 -3
  50. package/src/client/plugin-card-seat.ts +7 -0
  51. package/src/client/remote.module.css +2 -48
  52. package/src/client/settings-entry-form.ts +0 -1
  53. package/src/detached-work.ts +9 -8
  54. package/src/index.ts +77 -17
  55. package/src/lan-source.ts +132 -0
  56. package/src/lan.ts +126 -6
  57. package/src/remote-api.ts +24 -4
  58. package/src/remote-channel-boot.ts +4 -1
  59. package/src/routes.ts +178 -27
  60. package/src/tunnel-plan.ts +9 -2
  61. package/lib/invariant.js +0 -21
  62. package/lib/types/invariant.d.ts +0 -16
  63. package/lib/types/invariant.d.ts.map +0 -1
  64. package/lib/types/invariant.js +0 -23
  65. package/src/invariant.ts +0 -32
@@ -1 +1 @@
1
- {"version":3,"file":"RemoteEntry.d.ts","sourceRoot":"","sources":["../../../src/client/RemoteEntry.tsx"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAA;AAOnE,0EAA0E;AAC1E,MAAM,MAAM,gBAAgB,GAAG,WAAW,CAAC,QAAQ,CAAC,GAAG;IACrD,oEAAoE;IACpE,IAAI,EAAE,OAAO,CAAA;CACd,CAAA;AA2BD;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE,gBAAgB,+BA2MxD"}
1
+ {"version":3,"file":"RemoteEntry.d.ts","sourceRoot":"","sources":["../../../src/client/RemoteEntry.tsx"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAA;AAOnE,0EAA0E;AAC1E,MAAM,MAAM,gBAAgB,GAAG,WAAW,CAAC,QAAQ,CAAC,GAAG;IACrD,oEAAoE;IACpE,IAAI,EAAE,OAAO,CAAA;CACd,CAAA;AA2BD;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE,gBAAgB,+BA2LxD"}
@@ -63,10 +63,10 @@ export function RemoteEntry({ wide, t }) {
63
63
  eventSource.current?.close();
64
64
  eventSource.current = undefined;
65
65
  }, []);
66
- const mint = useCallback(async (address) => {
66
+ const mint = useCallback(async () => {
67
67
  let result;
68
68
  try {
69
- result = await issuePair(address);
69
+ result = await issuePair();
70
70
  }
71
71
  catch {
72
72
  // Fetch/network failure: show an explicit state instead of silently
@@ -97,10 +97,6 @@ export function RemoteEntry({ wide, t }) {
97
97
  // Whether this QR is built on the configured public (tunneled) base.
98
98
  public: publicBaseUrl !== undefined && result.url.startsWith(publicBaseUrl),
99
99
  ...(publicBaseUrl !== undefined ? { publicBaseUrl } : {}),
100
- // The issued URL names the requested (or default first) literal; the
101
- // public link has no LAN literal, so no radio row is selected then.
102
- address: address ?? result.lanAddresses[0] ?? '',
103
- lanAddresses: result.lanAddresses,
104
100
  };
105
101
  }, []);
106
102
  const openPanel = useCallback(async () => {
@@ -192,14 +188,6 @@ export function RemoteEntry({ wide, t }) {
192
188
  const handleRefresh = useCallback(() => {
193
189
  void mint().then(setState);
194
190
  }, [mint]);
195
- /** Re-mint against another LAN literal (multi-homed machines). */
196
- const handlePickAddress = useCallback((address) => {
197
- void mint(address).then(setState);
198
- }, [mint]);
199
- /** Re-mint against the configured public (tunneled) base. */
200
- const handlePickPublic = useCallback(() => {
201
- void mint().then(setState);
202
- }, [mint]);
203
191
  const handleCopy = useCallback((url) => {
204
192
  void copyText(url).then((ok) => {
205
193
  if (!ok)
@@ -216,7 +204,7 @@ export function RemoteEntry({ wide, t }) {
216
204
  window.setTimeout(() => { setCopiedToken(false); }, 1500);
217
205
  });
218
206
  }, []);
219
- return (_jsxs(_Fragment, { children: [_jsx("div", { className: css.entryRow, "data-rail": wide ? undefined : 'rail', children: _jsx(TooltipAnchor, { wide: wide, label: t('entry.label'), onClick: openPanel, expanded: open }) }), open && createPortal((_jsxs("div", { className: css.overlay, role: "presentation", children: [_jsx("div", { className: css.mask, "aria-hidden": "true", onClick: closePanel }), _jsx(RemotePanel, { t: t, state: state, copied: copied, copiedToken: copiedToken, onClose: closePanel, onStop: handleStop, onRefresh: handleRefresh, onCopy: handleCopy, onCopyToken: handleCopyToken, onPickAddress: handlePickAddress, onPickPublic: handlePickPublic, onRevoke: handleRevoke })] })), document.body)] }));
207
+ return (_jsxs(_Fragment, { children: [_jsx("div", { className: css.entryRow, "data-rail": wide ? undefined : 'rail', children: _jsx(TooltipAnchor, { wide: wide, label: t('entry.label'), onClick: openPanel, expanded: open }) }), open && createPortal((_jsxs("div", { className: css.overlay, role: "presentation", children: [_jsx("div", { className: css.mask, "aria-hidden": "true", onClick: closePanel }), _jsx(RemotePanel, { t: t, state: state, copied: copied, copiedToken: copiedToken, onClose: closePanel, onStop: handleStop, onRefresh: handleRefresh, onCopy: handleCopy, onCopyToken: handleCopyToken, onRevoke: handleRevoke })] })), document.body)] }));
220
208
  }
221
209
  /** The trigger: an icon-only control with a persistent accessible label. */
222
210
  function TooltipAnchor({ wide, label, onClick, expanded }) {
@@ -19,10 +19,6 @@ export type PanelState = {
19
19
  onlineCount: number;
20
20
  /** Authorized devices for the roster under the QR card. */
21
21
  devices: DeviceFrame[];
22
- /** The LAN literal the current QR was built from. */
23
- address: string;
24
- /** Every constructible LAN literal (interface order). */
25
- lanAddresses: string[];
26
22
  /** The active pairing token itself (useful in Docker/reverse proxy topologies). */
27
23
  token?: string;
28
24
  /** Whether this QR is built on the configured public (tunneled) base. */
@@ -47,10 +43,6 @@ export interface RemotePanelProps {
47
43
  onRefresh(): void;
48
44
  onCopy(url: string): void;
49
45
  onCopyToken?(token: string): void;
50
- /** Re-mint the QR against a different LAN address. */
51
- onPickAddress(address: string): void;
52
- /** Re-mint the QR against the configured public (tunneled) base. */
53
- onPickPublic(): void;
54
46
  /** Revoke one paired device. */
55
47
  onRevoke(deviceId: string): void;
56
48
  }
@@ -59,5 +51,5 @@ export interface RemotePanelProps {
59
51
  * @param props - copy, state, and actions.
60
52
  * @returns the panel element tree.
61
53
  */
62
- export declare function RemotePanel({ t, state, copied, copiedToken, onClose, onStop, onRefresh, onCopy, onCopyToken, onPickAddress, onPickPublic, onRevoke, }: RemotePanelProps): import("react").JSX.Element;
54
+ export declare function RemotePanel({ t, state, copied, copiedToken, onClose, onStop, onRefresh, onCopy, onCopyToken, onRevoke, }: RemotePanelProps): import("react").JSX.Element;
63
55
  //# sourceMappingURL=RemotePanel.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"RemotePanel.d.ts","sourceRoot":"","sources":["../../../src/client/RemotePanel.tsx"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAA;AACnE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AACjD,OAAO,EAGL,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,KAAK,gBAAgB,EACrB,KAAK,iBAAiB,EACvB,MAAM,eAAe,CAAA;AAatB,4DAA4D;AAC5D,MAAM,MAAM,UAAU,GAClB;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,MAAM,CAAC,EAAE,iBAAiB,CAAA;CAAE,GACpD;IAAE,IAAI,EAAE,mBAAmB,CAAA;CAAE,GAC7B;IAAE,IAAI,EAAE,aAAa,CAAA;CAAE,GACvB;IACE,IAAI,EAAE,OAAO,CAAA;IACb,GAAG,EAAE,MAAM,CAAA;IACX,SAAS,EAAE,MAAM,CAAA;IACjB,OAAO,EAAE,OAAO,CAAA;IAChB,KAAK,EAAE,YAAY,CAAA;IACnB,WAAW,EAAE,MAAM,CAAA;IACnB,WAAW,EAAE,MAAM,CAAA;IACnB,2DAA2D;IAC3D,OAAO,EAAE,WAAW,EAAE,CAAA;IACtB,qDAAqD;IACrD,OAAO,EAAE,MAAM,CAAA;IACf,yDAAyD;IACzD,YAAY,EAAE,MAAM,EAAE,CAAA;IACtB,mFAAmF;IACnF,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,yEAAyE;IACzE,MAAM,EAAE,OAAO,CAAA;IACf,+DAA+D;IAC/D,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,mEAAmE;IACnE,MAAM,CAAC,EAAE,iBAAiB,CAAA;IAC1B,uEAAuE;IACvE,KAAK,CAAC,EAAE,gBAAgB,CAAA;IACxB,6DAA6D;IAC7D,OAAO,CAAC,EAAE,YAAY,CAAA;CACvB,CAAA;AAEL,qDAAqD;AACrD,MAAM,WAAW,gBAAgB;IAC/B,CAAC,EAAE,WAAW,CAAC,QAAQ,CAAC,CAAA;IACxB,KAAK,EAAE,UAAU,CAAA;IACjB,MAAM,EAAE,OAAO,CAAA;IACf,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,OAAO,IAAI,IAAI,CAAA;IACf,MAAM,IAAI,IAAI,CAAA;IACd,SAAS,IAAI,IAAI,CAAA;IACjB,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,WAAW,CAAC,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACjC,sDAAsD;IACtD,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;IACpC,oEAAoE;IACpE,YAAY,IAAI,IAAI,CAAA;IACpB,gCAAgC;IAChC,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;CACjC;AAgBD;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,EAC1B,CAAC,EACD,KAAK,EACL,MAAM,EACN,WAAW,EACX,OAAO,EACP,MAAM,EACN,SAAS,EACT,MAAM,EACN,WAAW,EACX,aAAa,EACb,YAAY,EACZ,QAAQ,GACT,EAAE,gBAAgB,+BAyLlB"}
1
+ {"version":3,"file":"RemotePanel.d.ts","sourceRoot":"","sources":["../../../src/client/RemotePanel.tsx"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAA;AACnE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AACjD,OAAO,EAGL,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,KAAK,gBAAgB,EACrB,KAAK,iBAAiB,EACvB,MAAM,eAAe,CAAA;AAatB,4DAA4D;AAC5D,MAAM,MAAM,UAAU,GAClB;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,MAAM,CAAC,EAAE,iBAAiB,CAAA;CAAE,GACpD;IAAE,IAAI,EAAE,mBAAmB,CAAA;CAAE,GAC7B;IAAE,IAAI,EAAE,aAAa,CAAA;CAAE,GACvB;IACE,IAAI,EAAE,OAAO,CAAA;IACb,GAAG,EAAE,MAAM,CAAA;IACX,SAAS,EAAE,MAAM,CAAA;IACjB,OAAO,EAAE,OAAO,CAAA;IAChB,KAAK,EAAE,YAAY,CAAA;IACnB,WAAW,EAAE,MAAM,CAAA;IACnB,WAAW,EAAE,MAAM,CAAA;IACnB,2DAA2D;IAC3D,OAAO,EAAE,WAAW,EAAE,CAAA;IACtB,mFAAmF;IACnF,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,yEAAyE;IACzE,MAAM,EAAE,OAAO,CAAA;IACf,+DAA+D;IAC/D,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,mEAAmE;IACnE,MAAM,CAAC,EAAE,iBAAiB,CAAA;IAC1B,uEAAuE;IACvE,KAAK,CAAC,EAAE,gBAAgB,CAAA;IACxB,6DAA6D;IAC7D,OAAO,CAAC,EAAE,YAAY,CAAA;CACvB,CAAA;AAEL,qDAAqD;AACrD,MAAM,WAAW,gBAAgB;IAC/B,CAAC,EAAE,WAAW,CAAC,QAAQ,CAAC,CAAA;IACxB,KAAK,EAAE,UAAU,CAAA;IACjB,MAAM,EAAE,OAAO,CAAA;IACf,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,OAAO,IAAI,IAAI,CAAA;IACf,MAAM,IAAI,IAAI,CAAA;IACd,SAAS,IAAI,IAAI,CAAA;IACjB,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAA;IACzB,WAAW,CAAC,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACjC,gCAAgC;IAChC,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAA;CACjC;AAgBD;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,EAC1B,CAAC,EACD,KAAK,EACL,MAAM,EACN,WAAW,EACX,OAAO,EACP,MAAM,EACN,SAAS,EACT,MAAM,EACN,WAAW,EACX,QAAQ,GACT,EAAE,gBAAgB,+BA8JlB"}
@@ -1,8 +1,11 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  /**
3
3
  * The mobile remote-control panel body: status card (state text + badge),
4
- * the QR code, the open-on-phone hint with the link text, and the three
5
- * actions (stop / refresh / copy). Pure presentation — all state and
4
+ * the QR code, the open-on-phone hint with the link text, and the two
5
+ * actions (stop / refresh / copy). The advertised network is not a choice:
6
+ * the QR names the public base and the landing page decides at connect time
7
+ * whether to move to a LAN origin (lan-source.ts), so the panel only states
8
+ * which source the current link carries. Pure presentation — all state and
6
9
  * actions arrive through props from the entry's behavior component.
7
10
  */
8
11
  import clsx from 'clsx';
@@ -35,10 +38,10 @@ function statusOf(t, state) {
35
38
  * @param props - copy, state, and actions.
36
39
  * @returns the panel element tree.
37
40
  */
38
- export function RemotePanel({ t, state, copied, copiedToken, onClose, onStop, onRefresh, onCopy, onCopyToken, onPickAddress, onPickPublic, onRevoke, }) {
41
+ export function RemotePanel({ t, state, copied, copiedToken, onClose, onStop, onRefresh, onCopy, onCopyToken, onRevoke, }) {
39
42
  return (_jsxs("div", { className: css.panel, role: "dialog", "aria-modal": "true", "aria-label": t('title'), children: [_jsxs("div", { className: css.header, children: [_jsxs("div", { className: css.heading, children: [_jsx("h2", { className: css.title, children: t('title') }), _jsx("p", { className: css.subtitle, children: t('subtitle') })] }), _jsx("button", { type: "button", className: css.close, "aria-label": t('close.label'), onClick: onClose, children: _jsx(IconCloseOutlineRegular, { size: 14 }) })] }), state.kind === 'lan-required' ? (_jsxs("div", { className: css.banner, role: "alert", children: [_jsx("p", { className: css.bannerTitle, children: t('status.lanRequired') }), _jsx("p", { className: css.bannerHint, children: t('status.lanRequiredHint') })] })) : state.kind === 'loopback-required' ? (_jsxs("div", { className: css.banner, role: "alert", children: [_jsx("p", { className: css.bannerTitle, children: t('status.loopbackRequired') }), _jsx("p", { className: css.bannerHint, children: t('status.loopbackRequiredHint') })] })) : state.kind === 'unreachable' ? (_jsxs("div", { className: css.banner, role: "alert", children: [_jsx("p", { className: css.bannerTitle, children: t('status.unreachable') }), _jsx("p", { className: css.bannerHint, children: t('status.unreachableHint') })] })) : (_jsxs(_Fragment, { children: [state.posture !== undefined && state.posture.hosts.some(host => host.exposed) && (_jsxs("div", { className: css.banner, role: "alert", children: [_jsx("p", { className: css.bannerTitle, children: t('posture.exposed') }), _jsx("p", { className: css.bannerHint, children: t('posture.exposedHint', { hosts: state.posture.hosts.filter(host => host.exposed).map(host => host.host).join(', ') }) })] })), _jsxs("div", { className: css.card, children: [_jsxs("div", { className: css.cardHeader, children: [_jsx("span", { className: css.cardTitle, children: t('card.title') }), _jsxs("span", { className: css.badges, children: [state.public && _jsx("span", { className: clsx(css.badge, css.badgePublic), children: t('public.badge') }), _jsx("span", { className: clsx(css.badge, css[`badge-${statusOf(t, state).tone}`]), children: statusOf(t, state).text })] })] }), _jsx("div", { className: css.qrWrap, "data-testid": "remote-qr", children: _jsx(PairQrCode, { url: state.url, className: css.qr }) }), state.expired
40
43
  ? _jsx("p", { className: css.expired, children: t('pair.expired') })
41
44
  : _jsx("p", { className: css.expiry, children: t('pair.expires', { time: formatClock(state.expiresAt) }) })] }), _jsx("p", { className: css.hint, children: state.public ? t('pair.publicHint') : t('pair.hint') }), _jsxs("div", { className: css.pairLinks, children: [_jsxs("div", { className: css.pairLinkRow, children: [_jsxs("div", { className: css.pairLinkText, children: [_jsx("span", { className: css.pairLinkLabel, children: t('pair.linkLabel') }), _jsx("code", { className: css.link, title: state.url, children: state.url })] }), _jsxs("button", { type: "button", className: css.copyLink, onClick: () => onCopy(state.url), children: [_jsx(IconCopyOutlineRegular, { size: 14 }), copied ? t('action.copied') : t('action.copyLink')] })] }), state.token !== undefined && state.token !== '' && (_jsxs("div", { className: css.pairLinkRow, children: [_jsxs("div", { className: css.pairLinkText, children: [_jsx("span", { className: css.pairLinkLabel, children: t('pair.tokenLabel') }), _jsx("code", { className: css.link, title: state.token, children: state.token })] }), _jsxs("button", { type: "button", className: css.copyLink, onClick: () => onCopyToken ? onCopyToken(state.token) : onCopy(state.token), children: [_jsx(IconCopyOutlineRegular, { size: 14 }), copiedToken ? t('action.copiedToken') : t('action.copyToken')] })] }))] }), _jsxs("p", { className: css.oneTimeHint, children: [t('pair.oneTimeHint'), " ", t('pair.dockerHint')] }), state.phase === 'stopped' && _jsx("p", { className: css.stoppedHint, children: t('stopped.hint') }), state.tunnel !== undefined && state.tunnel.state !== 'running' && (_jsx("p", { className: state.tunnel.state === 'failed' ? css.tunnelFailed : css.tunnelNote, role: "status", children: state.tunnel.state === 'failed'
42
45
  ? t('tunnel.failed', { error: state.tunnel.error ?? t('tunnel.unknownError') })
43
- : t('tunnel.starting') })), state.relay?.state === 'registering' && (_jsx("p", { className: css.tunnelNote, role: "status", children: t('relay.registering') })), state.relay?.state === 'failed' && (_jsx("p", { className: css.tunnelFailed, role: "status", children: t('relay.failed', { error: state.relay.error ?? t('tunnel.unknownError') }) })), (state.publicBaseUrl !== undefined || state.lanAddresses.length > 1) && (_jsxs("fieldset", { className: css.addresses, children: [_jsx("legend", { children: t('address.label') }), state.publicBaseUrl !== undefined && (_jsxs("label", { className: css.address, children: [_jsx("input", { type: "radio", name: "lan-address", "aria-label": t('address.public'), checked: state.public, onChange: onPickPublic }), _jsx("span", { children: t('address.public') }), _jsx("code", { className: css.addressValue, children: state.publicBaseUrl })] }, "public")), state.lanAddresses.map(address => (_jsxs("label", { className: css.address, children: [_jsx("input", { type: "radio", name: "lan-address", "aria-label": address, checked: !state.public && address === state.address, onChange: () => onPickAddress(address) }), _jsx("span", { children: t('address.lan') }), _jsx("code", { className: css.addressValue, children: address })] }, address))), _jsx("p", { className: css.addressHint, children: t('address.hint') })] })), _jsxs("div", { className: css.actions, children: [_jsxs("button", { type: "button", className: css.action, onClick: onStop, children: [_jsx(IconStopFillRegular, { size: 14 }), t('action.stop')] }), _jsxs("button", { type: "button", className: css.action, onClick: onRefresh, children: [_jsx(IconRefreshOutlineRegular, { size: 14 }), t('action.refresh')] })] }), _jsxs("section", { className: css.devices, "data-testid": "remote-devices", "aria-label": t('devices.title'), children: [_jsx("h3", { className: css.devicesTitle, children: t('devices.title') }), state.devices.length === 0 ? (_jsx("p", { className: css.devicesEmpty, children: t('devices.empty') })) : (_jsx("ul", { className: css.deviceList, children: state.devices.map(device => (_jsxs("li", { className: css.deviceRow, children: [_jsxs("div", { className: css.deviceMeta, children: [_jsx("span", { className: css.deviceName, children: deviceNameFromUserAgent(device.userAgent) ?? t('devices.unknown') }), _jsx("span", { className: clsx(css.devicePresence, device.online ? css.deviceOnline : css.deviceOffline), children: device.online ? t('devices.online') : t('devices.offline') }), _jsx("span", { className: css.deviceSeen, children: t('devices.lastSeen', { time: formatLastSeen(device.lastSeenAt) }) })] }), _jsx("button", { type: "button", className: css.deviceRevoke, "aria-label": t('devices.revoke.label'), onClick: () => { onRevoke(device.id); }, children: t('devices.revoke') })] }, device.id))) }))] })] }))] }));
46
+ : t('tunnel.starting') })), state.relay?.state === 'registering' && (_jsx("p", { className: css.tunnelNote, role: "status", children: t('relay.registering') })), state.relay?.state === 'failed' && (_jsx("p", { className: css.tunnelFailed, role: "status", children: t('relay.failed', { error: state.relay.error ?? t('tunnel.unknownError') }) })), (state.publicBaseUrl !== undefined || !state.public) && (_jsx("p", { className: css.addressHint, children: state.public ? t('address.auto') : t('address.pinnedLan') })), _jsxs("div", { className: css.actions, children: [_jsxs("button", { type: "button", className: css.action, onClick: onStop, children: [_jsx(IconStopFillRegular, { size: 14 }), t('action.stop')] }), _jsxs("button", { type: "button", className: css.action, onClick: onRefresh, children: [_jsx(IconRefreshOutlineRegular, { size: 14 }), t('action.refresh')] })] }), _jsxs("section", { className: css.devices, "data-testid": "remote-devices", "aria-label": t('devices.title'), children: [_jsx("h3", { className: css.devicesTitle, children: t('devices.title') }), state.devices.length === 0 ? (_jsx("p", { className: css.devicesEmpty, children: t('devices.empty') })) : (_jsx("ul", { className: css.deviceList, children: state.devices.map(device => (_jsxs("li", { className: css.deviceRow, children: [_jsxs("div", { className: css.deviceMeta, children: [_jsx("span", { className: css.deviceName, children: deviceNameFromUserAgent(device.userAgent) ?? t('devices.unknown') }), _jsx("span", { className: clsx(css.devicePresence, device.online ? css.deviceOnline : css.deviceOffline), children: device.online ? t('devices.online') : t('devices.offline') }), _jsx("span", { className: css.deviceSeen, children: t('devices.lastSeen', { time: formatLastSeen(device.lastSeenAt) }) })] }), _jsx("button", { type: "button", className: css.deviceRevoke, "aria-label": t('devices.revoke.label'), onClick: () => { onRevoke(device.id); }, children: t('devices.revoke') })] }, device.id))) }))] })] }))] }));
44
47
  }
@@ -19,10 +19,8 @@ export declare const zh: {
19
19
  'status.unreachableHint': string;
20
20
  'pair.hint': string;
21
21
  'pair.publicHint': string;
22
- 'address.label': string;
23
- 'address.public': string;
24
- 'address.lan': string;
25
- 'address.hint': string;
22
+ 'address.auto': string;
23
+ 'address.pinnedLan': string;
26
24
  'pair.expires': string;
27
25
  'pair.expired': string;
28
26
  'pair.linkLabel': string;
@@ -143,10 +141,8 @@ export declare const en: {
143
141
  'status.unreachableHint': string;
144
142
  'pair.hint': string;
145
143
  'pair.publicHint': string;
146
- 'address.label': string;
147
- 'address.public': string;
148
- 'address.lan': string;
149
- 'address.hint': string;
144
+ 'address.auto': string;
145
+ 'address.pinnedLan': string;
150
146
  'pair.expires': string;
151
147
  'pair.expired': string;
152
148
  'pair.linkLabel': string;
@@ -1 +1 @@
1
- {"version":3,"file":"locales.d.ts","sourceRoot":"","sources":["../../../src/client/locales.ts"],"names":[],"mappings":"AAAA,uEAAuE;AAEvE,mEAAmE;AACnE,eAAO,MAAM,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwHmB,CAAA;AAElC,sCAAsC;AACtC,MAAM,MAAM,SAAS,GAAG,MAAM,OAAO,EAAE,CAAA;AAEvC,wDAAwD;AACxD,MAAM,MAAM,eAAe,GAAG,SAAS,CAAA;AAEvC,mEAAmE;AACnE,eAAO,MAAM,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwHsB,CAAA"}
1
+ {"version":3,"file":"locales.d.ts","sourceRoot":"","sources":["../../../src/client/locales.ts"],"names":[],"mappings":"AAAA,uEAAuE;AAEvE,mEAAmE;AACnE,eAAO,MAAM,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsHmB,CAAA;AAElC,sCAAsC;AACtC,MAAM,MAAM,SAAS,GAAG,MAAM,OAAO,EAAE,CAAA;AAEvC,wDAAwD;AACxD,MAAM,MAAM,eAAe,GAAG,SAAS,CAAA;AAEvC,mEAAmE;AACnE,eAAO,MAAM,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsHsB,CAAA"}
@@ -19,10 +19,8 @@ export const zh = {
19
19
  'status.unreachableHint': '请刷新页面后重试。',
20
20
  'pair.hint': '无法扫码?可直接打开下方配对链接',
21
21
  'pair.publicHint': '公网链接:设备无需与本机处于同一网络',
22
- 'address.label': '选择二维码指向的网络',
23
- 'address.public': '公网地址',
24
- 'address.lan': '局域网',
25
- 'address.hint': '远程设备不在同一网络时请使用公网地址;局域网地址仅限同一网络内使用。',
22
+ 'address.auto': '二维码固定指向公网地址;手机与本机处于同一网络时会自动切换到局域网地址。',
23
+ 'address.pinnedLan': '二维码固定指向局域网地址。',
26
24
  'pair.expires': '二维码有效至 {time}',
27
25
  'pair.expired': '二维码已过期,请刷新',
28
26
  'pair.linkLabel': '配对链接',
@@ -141,10 +139,8 @@ export const en = {
141
139
  'status.unreachableHint': 'Refresh the page and try again.',
142
140
  'pair.hint': 'Cannot scan? Open one of the pairing links below',
143
141
  'pair.publicHint': 'Public links work when the device is not on the same network',
144
- 'address.label': 'Network the QR code points to',
145
- 'address.public': 'Public',
146
- 'address.lan': 'LAN',
147
- 'address.hint': 'Use the public address when the remote device is on another network; LAN addresses only work on the same network.',
142
+ 'address.auto': 'The QR code always points at the public address; a phone on the same network switches to the LAN address by itself.',
143
+ 'address.pinnedLan': 'The QR code points at a LAN address.',
148
144
  'pair.expires': 'QR code valid until {time}',
149
145
  'pair.expired': 'QR code expired — refresh it',
150
146
  'pair.linkLabel': 'Pairing link',
@@ -1 +1 @@
1
- {"version":3,"file":"mobile-adapt.d.ts","sourceRoot":"","sources":["../../../src/client/mobile-adapt.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA;AAE7C,0EAA0E;AAC1E,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,IAAI,CAAA;IACpB,yDAAyD;IACzD,aAAa,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,IAAI,CAAA;IAClC,yDAAyD;IACzD,YAAY,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,IAAI,CAAA;IACjC;;;;;;OAMG;IACH,SAAS,EAAE,CAAC,CAAC,GAAG,EAAE,SAAS,KAAK,MAAM,CAAC,GAAG,IAAI,CAAA;IAC9C,wEAAwE;IACxE,UAAU,CAAC,EAAE,EAAE,OAAO,GAAG,IAAI,CAAA;IAC7B,4GAA4G;IAC5G,iBAAiB,IAAI,IAAI,CAAA;CAC1B;AAoQD;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,IAAI,CAi8BvC"}
1
+ {"version":3,"file":"mobile-adapt.d.ts","sourceRoot":"","sources":["../../../src/client/mobile-adapt.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA;AAE7C,0EAA0E;AAC1E,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,MAAM,IAAI,CAAA;IACpB,yDAAyD;IACzD,aAAa,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,IAAI,CAAA;IAClC,yDAAyD;IACzD,YAAY,EAAE,CAAC,MAAM,IAAI,CAAC,GAAG,IAAI,CAAA;IACjC;;;;;;OAMG;IACH,SAAS,EAAE,CAAC,CAAC,GAAG,EAAE,SAAS,KAAK,MAAM,CAAC,GAAG,IAAI,CAAA;IAC9C,wEAAwE;IACxE,UAAU,CAAC,EAAE,EAAE,OAAO,GAAG,IAAI,CAAA;IAC7B,4GAA4G;IAC5G,iBAAiB,IAAI,IAAI,CAAA;CAC1B;AA+RD;;;GAGG;AACH,wBAAgB,gBAAgB,IAAI,IAAI,CAi8BvC"}
@@ -150,14 +150,41 @@ const ADAPT_CSS = [
150
150
  '[class$="_headerUtilities"]{display:none}',
151
151
  // v52 composer: the two lines (permission / model) stay stacked with zero
152
152
  // row gap; the command, context-meter and send/stop buttons float at the
153
- // left/right edges vertically centered over both lines.
153
+ // left/right edges vertically centered over both lines. "Both lines" is what
154
+ // makes _row the containing block for those three floats: _row is the one box
155
+ // that wraps the lines, so nothing between a float and _row may claim it.
154
156
  '[class$="_composerSeat"] [class$="_card"]{margin-bottom:1px}',
155
157
  '[class$="_composerSeat"] [class$="_row"]{flex-wrap:wrap;row-gap:0;padding:2px 8px 1px;position:relative}',
156
- '[class$="_composerSeat"] [class$="_add"]{position:absolute;left:8px;top:50%;transform:translateY(-50%)}',
158
+ // The attach button is the only file-picker entry on the portrait composer,
159
+ // and taking it out of flow costs it the paint order it had inline: a
160
+ // positioned sibling painted after it (the trailing line, see below) covers
161
+ // it and eats the taps on the covered half. Its own z-index makes the hit
162
+ // layer a property of the button instead of a side effect of a sibling
163
+ // (#1829). It clears the composer's own stacking ladder and stays far below
164
+ // the bottom-sheet menus (2147482000), which own the overlay above it.
165
+ '[class$="_composerSeat"] [class$="_add"]{position:absolute;left:8px;top:50%;transform:translateY(-50%);z-index:10}',
157
166
  '[class$="_composerSeat"] [class$="_modes"]{min-width:0;padding-left:38px}',
158
167
  // Model line left-aligned with the permission line (same command-button
159
168
  // clearance), rows stay tightly stacked.
160
- '[class$="_composerSeat"] [class$="_trailing"]{flex-basis:100%;position:relative;min-height:32px;justify-content:flex-start;padding-left:38px;padding-right:78px}',
169
+ // The trailing line is forced onto its own row at flex-basis:100% and carries
170
+ // 116px of side padding (38 left for the command button, 78 right for the
171
+ // send button). Under the default content-box that padding is ADDED to the
172
+ // 100% basis, so the line's own box overflowed the card by exactly 116px and
173
+ // dragged the absolutely-positioned send button out with it: on a 393px phone
174
+ // the card ended at x=367 while the button sat at x=433..467, past the
175
+ // viewport's right edge, which is the unreachable button the reporter
176
+ // measured (#1818). border-box contains the padding inside the basis, so the
177
+ // line stays within the card and the button lands back inside it.
178
+ //
179
+ // The line stays UNPOSITIONED on purpose. position:relative arrived here with
180
+ // the compact picker and outlived it, but this box is the LAST line only: as
181
+ // the nearest positioned ancestor it took the containing block from _row, so
182
+ // the send button and the context meter centered inside the trailing line
183
+ // instead of over both lines - the send button rode the input's bottom edge,
184
+ // out of line with the attach button - and, painted after the out-of-flow
185
+ // attach button, the line covered that button's lower half and swallowed the
186
+ // taps there (#1829).
187
+ '[class$="_composerSeat"] [class$="_trailing"]{box-sizing:border-box;flex-basis:100%;min-height:32px;justify-content:flex-start;padding-left:38px;padding-right:78px}',
161
188
  '[class$="_composerSeat"] [class$="_trailing"] *{font-size:12px}',
162
189
  // v54: smaller permission/model buttons (font + height). v79: the
163
190
  // permission trigger collapses to its shield icon on phones — the label
@@ -78,6 +78,11 @@ export interface PluginCardSeat {
78
78
  label?: () => string;
79
79
  /** Locale namespace the card renders with. */
80
80
  locale: string;
81
+ /**
82
+ * Child slots this card declares and renders. Forwarded to whichever seat
83
+ * the host renders; absent for a card that declares none.
84
+ */
85
+ children?: Record<string, unknown>;
81
86
  /** Business-face factory of the registration. */
82
87
  inject?: () => object;
83
88
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"plugin-card-seat.d.ts","sourceRoot":"","sources":["../../../src/client/plugin-card-seat.ts"],"names":[],"mappings":"AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AAEH,gCAAgC;AAChC,eAAO,MAAM,uBAAuB,uBAAuB,CAAA;AAE3D,uFAAuF;AACvF,eAAO,MAAM,yBAAyB,0BAA0B,CAAA;AAEhE,iEAAiE;AACjE,eAAO,MAAM,oBAAoB,kBAAkB,CAAA;AAEnD,uFAAuF;AACvF,MAAM,WAAW,eAAe;IAC9B,sCAAsC;IACtC,QAAQ,CAAC,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,GAAG,OAAO,CAAA;CACpD;AAED,iEAAiE;AACjE,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,eAAe,CAAA;IACtB,6EAA6E;IAC7E,GAAG,CAAC,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAA;IAC3B,oEAAoE;IACpE,EAAE,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,KAAK,EAAE,KAAK,IAAI,GAAG,OAAO,CAAA;CAClE;AAED,2EAA2E;AAC3E,MAAM,WAAW,4BAA4B;IAC3C,8DAA8D;IAC9D,QAAQ,CAAC,EAAE,KAAK,CAAA;CACjB;AAED,6CAA6C;AAC7C,MAAM,WAAW,cAAc;IAC7B;;;;;OAKG;IACH,MAAM,EAAE,MAAM,CAAA;IACd,iCAAiC;IACjC,EAAE,EAAE,MAAM,CAAA;IACV,mCAAmC;IACnC,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,4EAA4E;IAC5E,KAAK,CAAC,EAAE,MAAM,MAAM,CAAA;IACpB,8CAA8C;IAC9C,MAAM,EAAE,MAAM,CAAA;IACd,iDAAiD;IACjD,MAAM,CAAC,EAAE,MAAM,MAAM,CAAA;IACrB;;;;OAIG;IACH,SAAS,EAAE,OAAO,CAAA;CACnB;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,iBAAiB,GAAG,OAAO,CAUjE;AAWD;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,iBAAiB,EAAE,IAAI,EAAE,cAAc,GAAG,IAAI,CA4DpF"}
1
+ {"version":3,"file":"plugin-card-seat.d.ts","sourceRoot":"","sources":["../../../src/client/plugin-card-seat.ts"],"names":[],"mappings":"AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AAEH,gCAAgC;AAChC,eAAO,MAAM,uBAAuB,uBAAuB,CAAA;AAE3D,uFAAuF;AACvF,eAAO,MAAM,yBAAyB,0BAA0B,CAAA;AAEhE,iEAAiE;AACjE,eAAO,MAAM,oBAAoB,kBAAkB,CAAA;AAEnD,uFAAuF;AACvF,MAAM,WAAW,eAAe;IAC9B,sCAAsC;IACtC,QAAQ,CAAC,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,GAAG,OAAO,CAAA;CACpD;AAED,iEAAiE;AACjE,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,eAAe,CAAA;IACtB,6EAA6E;IAC7E,GAAG,CAAC,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAA;IAC3B,oEAAoE;IACpE,EAAE,CAAC,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,GAAG,IAAI,EAAE,KAAK,EAAE,KAAK,IAAI,GAAG,OAAO,CAAA;CAClE;AAED,2EAA2E;AAC3E,MAAM,WAAW,4BAA4B;IAC3C,8DAA8D;IAC9D,QAAQ,CAAC,EAAE,KAAK,CAAA;CACjB;AAED,6CAA6C;AAC7C,MAAM,WAAW,cAAc;IAC7B;;;;;OAKG;IACH,MAAM,EAAE,MAAM,CAAA;IACd,iCAAiC;IACjC,EAAE,EAAE,MAAM,CAAA;IACV,mCAAmC;IACnC,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,4EAA4E;IAC5E,KAAK,CAAC,EAAE,MAAM,MAAM,CAAA;IACpB,8CAA8C;IAC9C,MAAM,EAAE,MAAM,CAAA;IACd;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAClC,iDAAiD;IACjD,MAAM,CAAC,EAAE,MAAM,MAAM,CAAA;IACrB;;;;OAIG;IACH,SAAS,EAAE,OAAO,CAAA;CACnB;AAED;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,iBAAiB,GAAG,OAAO,CAUjE;AAWD;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,iBAAiB,EAAE,IAAI,EAAE,cAAc,GAAG,IAAI,CA8DpF"}
@@ -111,12 +111,14 @@ export function installPluginCard(ctx, seat) {
111
111
  ...(seat.order === undefined ? {} : { order: seat.order }),
112
112
  ...(seat.label === undefined ? {} : { label: seat.label }),
113
113
  locale: seat.locale,
114
+ ...(seat.children === undefined ? {} : { children: seat.children }),
114
115
  ...(seat.inject === undefined ? {} : { inject }),
115
116
  }
116
117
  : {
117
118
  name: OFFICIAL_PLUGIN_CARD_SEAT,
118
119
  key: seat.bundle,
119
120
  locale: seat.locale,
121
+ ...(seat.children === undefined ? {} : { children: seat.children }),
120
122
  ...(seat.inject === undefined ? {} : { inject }),
121
123
  }), component);
122
124
  current = target;
@@ -1 +1 @@
1
- {"version":3,"file":"settings-entry-form.d.ts","sourceRoot":"","sources":["../../../src/client/settings-entry-form.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,OAAO,KAAK,EAAE,UAAU,EAAsB,WAAW,EAAE,MAAM,4CAA4C,CAAA;AAE7G,gDAAgD;AAChD,MAAM,WAAW,sBAAsB,CAAC,CAAC;IACvC,kEAAkE;IAClE,KAAK,EAAE,WAAW,CAAA;IAClB;;;;;OAKG;IACH,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAA;CAC5B;AAeD;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,CAAC,EAAE,OAAO,EAAE,sBAAsB,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,CA4E1F"}
1
+ {"version":3,"file":"settings-entry-form.d.ts","sourceRoot":"","sources":["../../../src/client/settings-entry-form.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,OAAO,KAAK,EAAE,UAAU,EAAsB,WAAW,EAAE,MAAM,4CAA4C,CAAA;AAE7G,gDAAgD;AAChD,MAAM,WAAW,sBAAsB,CAAC,CAAC;IACvC,kEAAkE;IAClE,KAAK,EAAE,WAAW,CAAA;IAClB;;;;;OAKG;IACH,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAA;CAC5B;AAcD;;;;;;GAMG;AACH,wBAAgB,qBAAqB,CAAC,CAAC,EAAE,OAAO,EAAE,sBAAsB,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,CA4E1F"}
@@ -7,7 +7,6 @@ function pendingSnapshot() {
7
7
  user: undefined,
8
8
  revision: undefined,
9
9
  writable: false,
10
- mode: 'host',
11
10
  };
12
11
  }
13
12
  /**
@@ -1,12 +1,12 @@
1
1
  /**
2
2
  * Run one piece of work outside the caller's async context.
3
3
  *
4
- * The Host performs a settings mutation inside `hmr.runExclusive`, which marks
5
- * the running async context with an AsyncLocalStorage store. Side effects that
6
- * live on that path - writing `cordis.patch.yml`, the very file the HMR config
7
- * watcher refreshes from - must not run under that mark, or the watcher's
8
- * refresh can re-enter the exclusive transaction and be refused with "HMR
9
- * transactions cannot be nested" (#1751, #1754).
4
+ * A Host mutation that runs inside `hmr.runExclusive` marks the running async
5
+ * context with an AsyncLocalStorage store. Side effects on that path that write
6
+ * a file the HMR config watcher refreshes from - `cordis.patch.yml` above all -
7
+ * must not run under that mark, or the watcher's refresh re-enters the
8
+ * exclusive transaction and is refused with "HMR transactions cannot be nested"
9
+ * (#1751, #1754, #1816).
10
10
  *
11
11
  * Deferring is NOT enough, and the earlier belt that this one replaces was
12
12
  * built on a disproven premise: Node propagates an AsyncLocalStorage store into
@@ -28,7 +28,7 @@
28
28
  * // -> undefined
29
29
  * ```
30
30
  *
31
- * @module
31
+ * @module dsh-web-shared/host/detached-work
32
32
  */
33
33
  /**
34
34
  * Run `work` outside the caller's AsyncLocalStorage context.
@@ -1 +1 @@
1
- {"version":3,"file":"detached-work.d.ts","sourceRoot":"","sources":["../../src/detached-work.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAYH;;;;;;;;;;GAUG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,GAAG,CAAC,CAE/C"}
1
+ {"version":3,"file":"detached-work.d.ts","sourceRoot":"","sources":["../../src/detached-work.ts"],"names":[],"mappings":"AACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAYH;;;;;;;;;;GAUG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,GAAG,CAAC,CAE/C"}
@@ -1,12 +1,13 @@
1
+ // Generated by scripts/sync-shared.mjs from shared/host/detached-work.ts. Do not edit this copy; edit the shared source and run "node scripts/sync-shared.mjs".
1
2
  /**
2
3
  * Run one piece of work outside the caller's async context.
3
4
  *
4
- * The Host performs a settings mutation inside `hmr.runExclusive`, which marks
5
- * the running async context with an AsyncLocalStorage store. Side effects that
6
- * live on that path - writing `cordis.patch.yml`, the very file the HMR config
7
- * watcher refreshes from - must not run under that mark, or the watcher's
8
- * refresh can re-enter the exclusive transaction and be refused with "HMR
9
- * transactions cannot be nested" (#1751, #1754).
5
+ * A Host mutation that runs inside `hmr.runExclusive` marks the running async
6
+ * context with an AsyncLocalStorage store. Side effects on that path that write
7
+ * a file the HMR config watcher refreshes from - `cordis.patch.yml` above all -
8
+ * must not run under that mark, or the watcher's refresh re-enters the
9
+ * exclusive transaction and is refused with "HMR transactions cannot be nested"
10
+ * (#1751, #1754, #1816).
10
11
  *
11
12
  * Deferring is NOT enough, and the earlier belt that this one replaces was
12
13
  * built on a disproven premise: Node propagates an AsyncLocalStorage store into
@@ -28,7 +29,7 @@
28
29
  * // -> undefined
29
30
  * ```
30
31
  *
31
- * @module
32
+ * @module dsh-web-shared/host/detached-work
32
33
  */
33
34
  import { AsyncResource } from 'node:async_hooks';
34
35
  /**
@@ -37,7 +38,7 @@ import { AsyncResource } from 'node:async_hooks';
37
38
  * instance is the only one the module ever needs. It carries no context of its
38
39
  * own, so every job run through it starts from the process's root context.
39
40
  */
40
- const DETACHED = new AsyncResource('dsh-remote-web-ui:detached-work', { triggerAsyncId: 0 });
41
+ const DETACHED = new AsyncResource('dsh-web:detached-work', { triggerAsyncId: 0 });
41
42
  /**
42
43
  * Run `work` outside the caller's AsyncLocalStorage context.
43
44
  *
@@ -12,6 +12,7 @@ import type { Context } from '@deepseek-ai/cordis';
12
12
  import type { SettingsNamespace } from '@deepseek-ai/dsh-settings';
13
13
  import z from '@deepseek-ai/schemastery';
14
14
  import { type PairingConfig } from './pairing.ts';
15
+ import { type PairingSourcePreference } from './routes.ts';
15
16
  declare module '@deepseek-ai/cordis' {
16
17
  interface Events {
17
18
  /**
@@ -167,6 +168,16 @@ export interface Config {
167
168
  profile?: string;
168
169
  /** Master switch for the plugin (browser half + host pairing surfaces). */
169
170
  enabled?: boolean;
171
+ /**
172
+ * The manual override of the automatic pairing-network choice, for the case
173
+ * where the phone's own probe misjudges (see `PairingSourcePreference` in
174
+ * routes.ts). `auto` (default) names the public base in the QR link and lets
175
+ * the landing page switch to a LAN origin when one answers; `public` pins the
176
+ * public base and disables the probe; `lan` pins the first LAN literal and
177
+ * skips the public hop entirely. Set through the profile patch — the settings
178
+ * card carries no control for it, so a save from that card leaves it alone.
179
+ */
180
+ pairingSource?: PairingSourcePreference;
170
181
  }
171
182
  /**
172
183
  * Plugin config schema. Under the 0.1.7 settings model this schema IS the
@@ -204,6 +215,7 @@ export declare const Config: z<Schemastery.ObjectS<NoInfer<{
204
215
  lanBind: z<boolean, boolean, "volatile">;
205
216
  profile: z<string, string, "plain">;
206
217
  enabled: z<boolean, boolean, "volatile-defined">;
218
+ pairingSource: z<"auto" | "public" | "lan", "auto" | "public" | "lan", "volatile-defined">;
207
219
  }>>, Schemastery.ObjectT<NoInfer<{
208
220
  tokenTtlMs: z<number, number, "volatile-defined">;
209
221
  offlineAfterMs: z<number, number, "volatile-defined">;
@@ -220,6 +232,7 @@ export declare const Config: z<Schemastery.ObjectS<NoInfer<{
220
232
  lanBind: z<boolean, boolean, "volatile">;
221
233
  profile: z<string, string, "plain">;
222
234
  enabled: z<boolean, boolean, "volatile-defined">;
235
+ pairingSource: z<"auto" | "public" | "lan", "auto" | "public" | "lan", "volatile-defined">;
223
236
  }>>, "plain">;
224
237
  /**
225
238
  * Fully resolved config: every field non-optional except `publicBaseUrl`,
@@ -262,6 +275,7 @@ export interface ResolvedConfigFields {
262
275
  lanBind?: ConfigField<boolean>;
263
276
  profile?: ConfigField<string>;
264
277
  enabled?: ConfigField<boolean>;
278
+ pairingSource?: ConfigField<PairingSourcePreference>;
265
279
  }
266
280
  /**
267
281
  * The single mapping from resolved plugin config to the pairing service
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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"}