@linxin666/dsh-remote-web-ui 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (118) hide show
  1. package/LICENSE +28 -0
  2. package/README.md +346 -0
  3. package/cordis.patch.yml +10 -0
  4. package/lib/client.js +2817 -0
  5. package/lib/index.js +1455 -0
  6. package/lib/invariant.js +21 -0
  7. package/lib/types/client/PairFailedNotice.d.ts +12 -0
  8. package/lib/types/client/PairFailedNotice.d.ts.map +1 -0
  9. package/lib/types/client/PhoneIcon.d.ts +19 -0
  10. package/lib/types/client/PhoneIcon.d.ts.map +1 -0
  11. package/lib/types/client/PluginSettingsCard.d.ts +78 -0
  12. package/lib/types/client/PluginSettingsCard.d.ts.map +1 -0
  13. package/lib/types/client/RemoteEntry.d.ts +10 -0
  14. package/lib/types/client/RemoteEntry.d.ts.map +1 -0
  15. package/lib/types/client/RemotePanel.d.ts +50 -0
  16. package/lib/types/client/RemotePanel.d.ts.map +1 -0
  17. package/lib/types/client/RemoteSettingsCard.d.ts +75 -0
  18. package/lib/types/client/RemoteSettingsCard.d.ts.map +1 -0
  19. package/lib/types/client/deep-link.d.ts +40 -0
  20. package/lib/types/client/deep-link.d.ts.map +1 -0
  21. package/lib/types/client/index.d.ts +54 -0
  22. package/lib/types/client/index.d.ts.map +1 -0
  23. package/lib/types/client/locales.d.ts +144 -0
  24. package/lib/types/client/locales.d.ts.map +1 -0
  25. package/lib/types/client/pair-api.d.ts +100 -0
  26. package/lib/types/client/pair-api.d.ts.map +1 -0
  27. package/lib/types/client/settings-form.d.ts +119 -0
  28. package/lib/types/client/settings-form.d.ts.map +1 -0
  29. package/lib/types/gate.d.ts +58 -0
  30. package/lib/types/gate.d.ts.map +1 -0
  31. package/lib/types/index.d.ts +78 -0
  32. package/lib/types/index.d.ts.map +1 -0
  33. package/lib/types/invariant.d.ts +16 -0
  34. package/lib/types/invariant.d.ts.map +1 -0
  35. package/lib/types/lan.d.ts +15 -0
  36. package/lib/types/lan.d.ts.map +1 -0
  37. package/lib/types/mobile/api.d.ts +64 -0
  38. package/lib/types/mobile/api.d.ts.map +1 -0
  39. package/lib/types/mobile/index.d.ts +10 -0
  40. package/lib/types/mobile/index.d.ts.map +1 -0
  41. package/lib/types/mobile/messages.d.ts +103 -0
  42. package/lib/types/mobile/messages.d.ts.map +1 -0
  43. package/lib/types/mobile/messages.test.d.ts +2 -0
  44. package/lib/types/mobile/messages.test.d.ts.map +1 -0
  45. package/lib/types/mobile/mobile-styles.d.ts +6 -0
  46. package/lib/types/mobile/mobile-styles.d.ts.map +1 -0
  47. package/lib/types/mobile/mobile-theme.d.ts +22 -0
  48. package/lib/types/mobile/mobile-theme.d.ts.map +1 -0
  49. package/lib/types/mobile/mobile-theme.test.d.ts +2 -0
  50. package/lib/types/mobile/mobile-theme.test.d.ts.map +1 -0
  51. package/lib/types/mobile/mux.d.ts +52 -0
  52. package/lib/types/mobile/mux.d.ts.map +1 -0
  53. package/lib/types/mobile/rpc.d.ts +38 -0
  54. package/lib/types/mobile/rpc.d.ts.map +1 -0
  55. package/lib/types/mobile/theme-toggle.d.ts +12 -0
  56. package/lib/types/mobile/theme-toggle.d.ts.map +1 -0
  57. package/lib/types/mobile/views/App.d.ts +59 -0
  58. package/lib/types/mobile/views/App.d.ts.map +1 -0
  59. package/lib/types/mobile/views/ChatView.d.ts +39 -0
  60. package/lib/types/mobile/views/ChatView.d.ts.map +1 -0
  61. package/lib/types/mobile/views/ChatView.test.d.ts +2 -0
  62. package/lib/types/mobile/views/ChatView.test.d.ts.map +1 -0
  63. package/lib/types/mobile/views/SessionListView.d.ts +27 -0
  64. package/lib/types/mobile/views/SessionListView.d.ts.map +1 -0
  65. package/lib/types/mobile/views/SessionListView.test.d.ts +2 -0
  66. package/lib/types/mobile/views/SessionListView.test.d.ts.map +1 -0
  67. package/lib/types/mobile/views/WorkspaceView.d.ts +19 -0
  68. package/lib/types/mobile/views/WorkspaceView.d.ts.map +1 -0
  69. package/lib/types/mobile-api.d.ts +41 -0
  70. package/lib/types/mobile-api.d.ts.map +1 -0
  71. package/lib/types/mobile-routes.d.ts +16 -0
  72. package/lib/types/mobile-routes.d.ts.map +1 -0
  73. package/lib/types/pairing.d.ts +215 -0
  74. package/lib/types/pairing.d.ts.map +1 -0
  75. package/lib/types/routes.d.ts +58 -0
  76. package/lib/types/routes.d.ts.map +1 -0
  77. package/lib/types/tunnel.d.ts +99 -0
  78. package/lib/types/tunnel.d.ts.map +1 -0
  79. package/package.json +104 -0
  80. package/src/client/PairFailedNotice.tsx +33 -0
  81. package/src/client/PhoneIcon.tsx +31 -0
  82. package/src/client/PluginSettingsCard.tsx +207 -0
  83. package/src/client/RemoteEntry.tsx +202 -0
  84. package/src/client/RemotePanel.tsx +186 -0
  85. package/src/client/RemoteSettingsCard.tsx +220 -0
  86. package/src/client/deep-link.ts +137 -0
  87. package/src/client/index.ts +167 -0
  88. package/src/client/locales.ts +149 -0
  89. package/src/client/pair-api.ts +176 -0
  90. package/src/client/remote.module.css +422 -0
  91. package/src/client/settings-card.module.css +296 -0
  92. package/src/client/settings-form.ts +294 -0
  93. package/src/css-modules.d.ts +6 -0
  94. package/src/gate.ts +121 -0
  95. package/src/index.ts +299 -0
  96. package/src/invariant.ts +32 -0
  97. package/src/lan.ts +21 -0
  98. package/src/mobile/api.ts +106 -0
  99. package/src/mobile/index.tsx +27 -0
  100. package/src/mobile/messages.test.ts +222 -0
  101. package/src/mobile/messages.ts +555 -0
  102. package/src/mobile/mobile-styles.ts +853 -0
  103. package/src/mobile/mobile-theme.test.ts +84 -0
  104. package/src/mobile/mobile-theme.ts +76 -0
  105. package/src/mobile/mux.ts +126 -0
  106. package/src/mobile/rpc.ts +90 -0
  107. package/src/mobile/theme-toggle.tsx +47 -0
  108. package/src/mobile/views/App.tsx +152 -0
  109. package/src/mobile/views/ChatView.test.tsx +243 -0
  110. package/src/mobile/views/ChatView.tsx +650 -0
  111. package/src/mobile/views/SessionListView.test.tsx +139 -0
  112. package/src/mobile/views/SessionListView.tsx +186 -0
  113. package/src/mobile/views/WorkspaceView.tsx +108 -0
  114. package/src/mobile-api.ts +271 -0
  115. package/src/mobile-routes.ts +77 -0
  116. package/src/pairing.ts +390 -0
  117. package/src/routes.ts +346 -0
  118. package/src/tunnel.ts +264 -0
@@ -0,0 +1,21 @@
1
+ //#region src/invariant.ts
2
+ const PACKAGE_NAME = "@linxin666/dsh-remote-web-ui";
3
+ /** Cordis companion plugin name. */
4
+ const name = "remote-web-ui-invariant";
5
+ /** Service required before the companion can reserve package ownership. */
6
+ const inject = ["invariants"];
7
+ /**
8
+ * No runtime invariant: this package owns no durable package-local event
9
+ * stream; its route-table and device-session relationships are asserted by
10
+ * the package's own specs (route register/dispose symmetry via the
11
+ * webServer disposer contract, token/revocation semantics on the service).
12
+ */
13
+ const install = () => {};
14
+ /**
15
+ * Register this package's invariant companion.
16
+ * @param ctx - Cordis context carrying the invariant service.
17
+ * @returns the installed registration's disposer after setup succeeds.
18
+ */
19
+ const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install));
20
+ //#endregion
21
+ export { apply, inject, name };
@@ -0,0 +1,12 @@
1
+ import type { TranslateNS } from '@deepseek-ai/dsh-client-ui-slots';
2
+ /** Notice props: localized copy. */
3
+ export interface PairFailedNoticeProps {
4
+ t: TranslateNS<'remote'>;
5
+ }
6
+ /**
7
+ * Render the failed-pair toast (auto-dismisses).
8
+ * @param props - localized copy.
9
+ * @returns the toast element.
10
+ */
11
+ export declare function PairFailedNotice({ t }: PairFailedNoticeProps): import("react").JSX.Element | null;
12
+ //# sourceMappingURL=PairFailedNotice.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PairFailedNotice.d.ts","sourceRoot":"","sources":["../../../src/client/PairFailedNotice.tsx"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAA;AAGnE,oCAAoC;AACpC,MAAM,WAAW,qBAAqB;IACpC,CAAC,EAAE,WAAW,CAAC,QAAQ,CAAC,CAAA;CACzB;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,EAAE,CAAC,EAAE,EAAE,qBAAqB,sCAY5D"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Phone glyph for the sidebar remote-control trigger. Not part of the
3
+ * shared icon set (ui-primitives has no phone icon); matches the outline
4
+ * style with currentColor strokes.
5
+ */
6
+ /** Icon props mirroring ui-primitives' IconProps. */
7
+ export interface PhoneIconProps {
8
+ /** Glyph size in px (default 16). */
9
+ size?: number;
10
+ /** Extra class for layout placement. */
11
+ className?: string;
12
+ }
13
+ /**
14
+ * Render the phone icon.
15
+ * @param props - size and optional class.
16
+ * @returns the svg element.
17
+ */
18
+ export declare function PhoneIcon({ size, className }: PhoneIconProps): import("react").JSX.Element;
19
+ //# sourceMappingURL=PhoneIcon.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PhoneIcon.d.ts","sourceRoot":"","sources":["../../../src/client/PhoneIcon.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,qDAAqD;AACrD,MAAM,WAAW,cAAc;IAC7B,qCAAqC;IACrC,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,wCAAwC;IACxC,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,EAAE,IAAS,EAAE,SAAS,EAAE,EAAE,cAAc,+BAWjE"}
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Shared chrome for the plugin settings card: a disclosure header naming the
3
+ * plugin and what its settings govern, the controls inside, and the save that
4
+ * writes them. Renders nothing while the namespace is unavailable — a
5
+ * deployment that does not compose the owning plugin should show no trace of
6
+ * it. Mirrors the official ui-plugin-config PluginCard in a self-contained
7
+ * slice (this package must not depend on a sibling UI package).
8
+ */
9
+ import { type ReactNode } from 'react';
10
+ import type { CardShell } from './settings-form.ts';
11
+ import type { SettingsCardKey } from './locales.ts';
12
+ /** Card chrome shared by every plugin settings card. */
13
+ export interface PluginSettingsCardProps {
14
+ /** Locale reader for this card's copy. */
15
+ t: (key: SettingsCardKey) => string;
16
+ /** Locale key of the plugin's name. */
17
+ titleKey: SettingsCardKey;
18
+ /** Locale key of the line describing what this plugin's settings govern. */
19
+ descriptionKey: SettingsCardKey;
20
+ /** The card's form state: availability, writability, and what a save would do. */
21
+ state: CardShell;
22
+ /** Write every staged edit. */
23
+ onSave: () => void;
24
+ /** Drop every staged edit. */
25
+ onDiscard: () => void;
26
+ /** The plugin's controls. */
27
+ children: ReactNode;
28
+ }
29
+ /**
30
+ * Render one plugin settings card.
31
+ * @param props - the plugin's copy keys, its form state, and its controls.
32
+ * @returns the card, or nothing when the namespace is unavailable.
33
+ */
34
+ export declare function PluginSettingsCard(props: PluginSettingsCardProps): import("react").JSX.Element | null;
35
+ /** Props every field control needs regardless of its value type. */
36
+ export interface FieldProps {
37
+ /** Stable id associating the label with its control. */
38
+ id: string;
39
+ /** Visible label. */
40
+ label: string;
41
+ /** One-line explanation rendered under the control. */
42
+ hint: string;
43
+ /** Draft text this control renders. */
44
+ text: string;
45
+ /** True when saving would leave a user-layer entry for this field. */
46
+ overridden: boolean;
47
+ /** True when the draft is not a value this field accepts. */
48
+ invalid: boolean;
49
+ /** Copy for the overridden badge. */
50
+ overriddenLabel: string;
51
+ /** Copy for the reset control. */
52
+ resetLabel: string;
53
+ /** Copy shown in place of the hint while the draft is invalid. */
54
+ invalidLabel: string;
55
+ /** Disables every control (read-only document, or an unavailable namespace). */
56
+ disabled: boolean;
57
+ /** Stage draft text. */
58
+ onEdit: (text: string) => void;
59
+ /** Stage a clear so the field re-inherits the composition layer. */
60
+ onReset: () => void;
61
+ }
62
+ /** A staged value field. `numeric` only hints the keypad: which drafts a field accepts is decided by its spec. */
63
+ export declare function ValueField(props: FieldProps & {
64
+ /** Hints a numeric keypad without narrowing what the control accepts. */
65
+ numeric?: boolean;
66
+ /** Placeholder shown while the draft is empty. */
67
+ placeholder?: string;
68
+ }): import("react").JSX.Element;
69
+ /** A staged boolean field: 继承 / 开 / 关. */
70
+ export declare function BooleanField(props: FieldProps & {
71
+ /** Copy for the inherit option. */
72
+ inheritLabel: string;
73
+ /** Copy for the on option. */
74
+ onLabel: string;
75
+ /** Copy for the off option. */
76
+ offLabel: string;
77
+ }): import("react").JSX.Element;
78
+ //# sourceMappingURL=PluginSettingsCard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PluginSettingsCard.d.ts","sourceRoot":"","sources":["../../../src/client/PluginSettingsCard.tsx"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAY,KAAK,SAAS,EAAE,MAAM,OAAO,CAAA;AAChD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAA;AACnD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AAGnD,wDAAwD;AACxD,MAAM,WAAW,uBAAuB;IACtC,0CAA0C;IAC1C,CAAC,EAAE,CAAC,GAAG,EAAE,eAAe,KAAK,MAAM,CAAA;IACnC,uCAAuC;IACvC,QAAQ,EAAE,eAAe,CAAA;IACzB,4EAA4E;IAC5E,cAAc,EAAE,eAAe,CAAA;IAC/B,kFAAkF;IAClF,KAAK,EAAE,SAAS,CAAA;IAChB,+BAA+B;IAC/B,MAAM,EAAE,MAAM,IAAI,CAAA;IAClB,8BAA8B;IAC9B,SAAS,EAAE,MAAM,IAAI,CAAA;IACrB,6BAA6B;IAC7B,QAAQ,EAAE,SAAS,CAAA;CACpB;AAED;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,uBAAuB,sCAmDhE;AAED,oEAAoE;AACpE,MAAM,WAAW,UAAU;IACzB,wDAAwD;IACxD,EAAE,EAAE,MAAM,CAAA;IACV,qBAAqB;IACrB,KAAK,EAAE,MAAM,CAAA;IACb,uDAAuD;IACvD,IAAI,EAAE,MAAM,CAAA;IACZ,uCAAuC;IACvC,IAAI,EAAE,MAAM,CAAA;IACZ,sEAAsE;IACtE,UAAU,EAAE,OAAO,CAAA;IACnB,6DAA6D;IAC7D,OAAO,EAAE,OAAO,CAAA;IAChB,qCAAqC;IACrC,eAAe,EAAE,MAAM,CAAA;IACvB,kCAAkC;IAClC,UAAU,EAAE,MAAM,CAAA;IAClB,kEAAkE;IAClE,YAAY,EAAE,MAAM,CAAA;IACpB,gFAAgF;IAChF,QAAQ,EAAE,OAAO,CAAA;IACjB,wBAAwB;IACxB,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IAC9B,oEAAoE;IACpE,OAAO,EAAE,MAAM,IAAI,CAAA;CACpB;AAED,kHAAkH;AAClH,wBAAgB,UAAU,CAAC,KAAK,EAAE,UAAU,GAAG;IAC7C,yEAAyE;IACzE,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,kDAAkD;IAClD,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB,+BAqCA;AAED,0CAA0C;AAC1C,wBAAgB,YAAY,CAAC,KAAK,EAAE,UAAU,GAAG;IAC/C,mCAAmC;IACnC,YAAY,EAAE,MAAM,CAAA;IACpB,8BAA8B;IAC9B,OAAO,EAAE,MAAM,CAAA;IACf,+BAA+B;IAC/B,QAAQ,EAAE,MAAM,CAAA;CACjB,+BAmCA"}
@@ -0,0 +1,10 @@
1
+ import type { PropsLocale, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots';
2
+ /** Entry props: the sidebar column state + the standard locale seat. */
3
+ export type RemoteEntryProps = PropsRuntime<'sidebar.remote'> & PropsLocale<'remote'>;
4
+ /**
5
+ * Render the remote-control trigger and panel.
6
+ * @param props - composed slot props (contract in this package).
7
+ * @returns the entry element tree.
8
+ */
9
+ export declare function RemoteEntry({ wide, useWorkspaces, t }: RemoteEntryProps): import("react").JSX.Element;
10
+ //# sourceMappingURL=RemoteEntry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RemoteEntry.d.ts","sourceRoot":"","sources":["../../../src/client/RemoteEntry.tsx"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAA;AAOjF,wEAAwE;AACxE,MAAM,MAAM,gBAAgB,GAAG,YAAY,CAAC,gBAAgB,CAAC,GAAG,WAAW,CAAC,QAAQ,CAAC,CAAA;AAcrF;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,CAAC,EAAE,EAAE,gBAAgB,+BAoJvE"}
@@ -0,0 +1,50 @@
1
+ import type { TranslateNS } from '@deepseek-ai/dsh-client-ui-slots';
2
+ import type { PairingPhase } from '../pairing.ts';
3
+ import { type TunnelStatusFrame } from './pair-api.ts';
4
+ /** The panel's view state, owned by the entry component. */
5
+ export type PanelState = {
6
+ kind: 'lan-required';
7
+ } | {
8
+ kind: 'loopback-required';
9
+ } | {
10
+ kind: 'unreachable';
11
+ } | {
12
+ kind: 'ready';
13
+ url: string;
14
+ expiresAt: number;
15
+ expired: boolean;
16
+ phase: PairingPhase;
17
+ deviceCount: number;
18
+ onlineCount: number;
19
+ /** The LAN literal the current QR was built from. */
20
+ address: string;
21
+ /** Every constructible LAN literal (interface order). */
22
+ lanAddresses: string[];
23
+ /** Whether this QR is built on the configured public (tunneled) base. */
24
+ public: boolean;
25
+ /** The configured public (tunneled) base URL, when present. */
26
+ publicBaseUrl?: string;
27
+ /** Auto-tunnel status, while the auto-tunnel feature is active. */
28
+ tunnel?: TunnelStatusFrame;
29
+ };
30
+ /** Full panel props: copy + view state + actions. */
31
+ export interface RemotePanelProps {
32
+ t: TranslateNS<'remote'>;
33
+ state: PanelState;
34
+ copied: boolean;
35
+ onClose(): void;
36
+ onStop(): void;
37
+ onRefresh(): void;
38
+ onCopy(): void;
39
+ /** Re-mint the QR against a different LAN address. */
40
+ onPickAddress(address: string): void;
41
+ /** Re-mint the QR against the configured public (tunneled) base. */
42
+ onPickPublic(): void;
43
+ }
44
+ /**
45
+ * Render the pairing panel.
46
+ * @param props - copy, state, and actions.
47
+ * @returns the panel element tree.
48
+ */
49
+ export declare function RemotePanel({ t, state, copied, onClose, onStop, onRefresh, onCopy, onPickAddress, onPickPublic }: RemotePanelProps): import("react").JSX.Element;
50
+ //# sourceMappingURL=RemotePanel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RemotePanel.d.ts","sourceRoot":"","sources":["../../../src/client/RemotePanel.tsx"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kCAAkC,CAAA;AACnE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAA;AACjD,OAAO,EAAe,KAAK,iBAAiB,EAAE,MAAM,eAAe,CAAA;AAGnE,4DAA4D;AAC5D,MAAM,MAAM,UAAU,GAClB;IAAE,IAAI,EAAE,cAAc,CAAA;CAAE,GACxB;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,qDAAqD;IACrD,OAAO,EAAE,MAAM,CAAA;IACf,yDAAyD;IACzD,YAAY,EAAE,MAAM,EAAE,CAAA;IACtB,yEAAyE;IACzE,MAAM,EAAE,OAAO,CAAA;IACf,+DAA+D;IAC/D,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,mEAAmE;IACnE,MAAM,CAAC,EAAE,iBAAiB,CAAA;CAC3B,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,OAAO,IAAI,IAAI,CAAA;IACf,MAAM,IAAI,IAAI,CAAA;IACd,SAAS,IAAI,IAAI,CAAA;IACjB,MAAM,IAAI,IAAI,CAAA;IACd,sDAAsD;IACtD,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;IACpC,oEAAoE;IACpE,YAAY,IAAI,IAAI,CAAA;CACrB;AAgBD;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,aAAa,EAAE,YAAY,EAAE,EAAE,gBAAgB,+BA8GlI"}
@@ -0,0 +1,75 @@
1
+ /**
2
+ * The remote-control settings card: pairing security and device limits.
3
+ * Registers into the `settings.plugin.item` slot the plugin-configuration
4
+ * section renders, bound to the `remote-web-ui` settings namespace.
5
+ */
6
+ import type { InjectFace, PropsLocale, PropsRuntime } from '@deepseek-ai/dsh-client-ui-slots';
7
+ import type { SettingsScope, SnapshotStore } from '@deepseek-ai/dsh-client-runtime/client';
8
+ import { type CardActions, type CardShell, type FieldState as CardFieldState } from './settings-form.ts';
9
+ /** The remote-control fields this card edits (the namespace's full schema). */
10
+ export interface RemoteSettings {
11
+ /** Master switch for the plugin. */
12
+ enabled?: boolean;
13
+ /** Token lifetime in ms; the QR link dies after this. */
14
+ tokenTtlMs?: number;
15
+ /** A device is "online" while its lastSeenAt is newer than this (ms). */
16
+ offlineAfterMs?: number;
17
+ /** Hard cap on paired device sessions (oldest evicted when full). */
18
+ maxDevices?: number;
19
+ /** Cookie name carrying the paired device id. */
20
+ cookieName?: string;
21
+ /** Fence flag: whether non-loopback /api requests must carry a live paired-device cookie. */
22
+ requirePairingForLan?: boolean;
23
+ /** Public (tunneled) base URL the QR link is built from when set. */
24
+ publicBaseUrl?: string;
25
+ /** When on, the plugin runs its own Cloudflare quick tunnel automatically. */
26
+ autoTunnel?: boolean;
27
+ }
28
+ /** What the remote-control card renders. */
29
+ export interface RemoteSettingsCardState extends CardShell {
30
+ /** Master switch. */
31
+ enabled: CardFieldState;
32
+ /** Token lifetime. */
33
+ tokenTtlMs: CardFieldState;
34
+ /** Device offline threshold. */
35
+ offlineAfterMs: CardFieldState;
36
+ /** Paired-device cap. */
37
+ maxDevices: CardFieldState;
38
+ /** Device cookie name. */
39
+ cookieName: CardFieldState;
40
+ /** LAN fence flag. */
41
+ requirePairingForLan: CardFieldState;
42
+ /** Public (tunneled) base URL. */
43
+ publicBaseUrl: CardFieldState;
44
+ /** Auto public tunnel switch. */
45
+ autoTunnel: CardFieldState;
46
+ }
47
+ /** The registration-side face the card's slot entry injects. */
48
+ export interface RemoteSettingsCardFace extends CardActions {
49
+ hooks: {
50
+ /** Card snapshot bound by the renderer as useRemoteSettingsCard. */
51
+ remoteSettingsCard: SnapshotStore<RemoteSettingsCardState>;
52
+ };
53
+ }
54
+ /** Bridges the `remote-web-ui` scope onto the card's staged form. */
55
+ export declare class RemoteSettingsCardController {
56
+ private readonly form;
57
+ private readonly store;
58
+ /** @param scope - the bound settings scope for the `remote-web-ui` namespace. */
59
+ constructor(scope: SettingsScope<RemoteSettings>);
60
+ private projection;
61
+ /**
62
+ * Build the face the card's slot registration injects.
63
+ * @returns the card's snapshot and its form actions.
64
+ */
65
+ inject(): RemoteSettingsCardFace;
66
+ }
67
+ /** Props the renderer binds for the remote-control card. */
68
+ export type RemoteSettingsCardProps = PropsRuntime<'web-ui.plugin.item'> & PropsLocale<'remote'> & InjectFace<RemoteSettingsCardFace>;
69
+ /**
70
+ * Render the remote-control card.
71
+ * @param props - locale copy, the card snapshot, and its form actions.
72
+ * @returns the card.
73
+ */
74
+ export declare function RemoteSettingsCard(props: RemoteSettingsCardProps): import("react").JSX.Element;
75
+ //# sourceMappingURL=RemoteSettingsCard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"RemoteSettingsCard.d.ts","sourceRoot":"","sources":["../../../src/client/RemoteSettingsCard.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAA;AAC7F,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,wCAAwC,CAAA;AAE1F,OAAO,EAAkD,KAAK,WAAW,EAAE,KAAK,SAAS,EAAE,KAAK,UAAU,IAAI,cAAc,EAAE,MAAM,oBAAoB,CAAA;AAExJ,+EAA+E;AAC/E,MAAM,WAAW,cAAc;IAC7B,oCAAoC;IACpC,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,yDAAyD;IACzD,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,yEAAyE;IACzE,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,qEAAqE;IACrE,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,iDAAiD;IACjD,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,6FAA6F;IAC7F,oBAAoB,CAAC,EAAE,OAAO,CAAA;IAC9B,qEAAqE;IACrE,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,8EAA8E;IAC9E,UAAU,CAAC,EAAE,OAAO,CAAA;CACrB;AAED,4CAA4C;AAC5C,MAAM,WAAW,uBAAwB,SAAQ,SAAS;IACxD,qBAAqB;IACrB,OAAO,EAAE,cAAc,CAAA;IACvB,sBAAsB;IACtB,UAAU,EAAE,cAAc,CAAA;IAC1B,gCAAgC;IAChC,cAAc,EAAE,cAAc,CAAA;IAC9B,yBAAyB;IACzB,UAAU,EAAE,cAAc,CAAA;IAC1B,0BAA0B;IAC1B,UAAU,EAAE,cAAc,CAAA;IAC1B,sBAAsB;IACtB,oBAAoB,EAAE,cAAc,CAAA;IACpC,kCAAkC;IAClC,aAAa,EAAE,cAAc,CAAA;IAC7B,iCAAiC;IACjC,UAAU,EAAE,cAAc,CAAA;CAC3B;AAED,gEAAgE;AAChE,MAAM,WAAW,sBAAuB,SAAQ,WAAW;IACzD,KAAK,EAAE;QACL,oEAAoE;QACpE,kBAAkB,EAAE,aAAa,CAAC,uBAAuB,CAAC,CAAA;KAC3D,CAAA;CACF;AAED,qEAAqE;AACrE,qBAAa,4BAA4B;IACvC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAA0B;IAC/C,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAwC;IAE9D,iFAAiF;gBACrE,KAAK,EAAE,aAAa,CAAC,cAAc,CAAC;IAchD,OAAO,CAAC,UAAU;IAclB;;;OAGG;IACH,MAAM,IAAI,sBAAsB;CAGjC;AAED,4DAA4D;AAC5D,MAAM,MAAM,uBAAuB,GACjC,YAAY,CAAC,oBAAoB,CAAC,GAChC,WAAW,CAAC,QAAQ,CAAC,GACrB,UAAU,CAAC,sBAAsB,CAAC,CAAA;AAEtC;;;;GAIG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,uBAAuB,+BA0GhE"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Phone-side boot flow: the QR link's `pair` + `workspace` parameters.
3
+ * Runs from the client apply on every page load, on any device:
4
+ * - `pair` present → accept the token, then reload so the whole SPA boots
5
+ * with the device cookie (the accept endpoint is exempt from the pairing
6
+ * gate; every other /api request needs the cookie).
7
+ * - `workspace` present (and paired) → deep-link: connect that workspace's
8
+ * session and open it, then strip the parameter.
9
+ * Failure of accept leaves a sessionStorage marker the entry renders as a
10
+ * one-time notice.
11
+ */
12
+ import type { Context } from '@deepseek-ai/cordis';
13
+ /** sessionStorage key for the failed-pair notice. */
14
+ export declare const PAIR_FAILED_MARKER = "dsh-remote-pair-failed";
15
+ /**
16
+ * The page-navigation surface the boot flow drives. Browser pages use the
17
+ * default (window.location/history); tests inject a fake.
18
+ */
19
+ export interface PageSurface {
20
+ /** The current page URL (read fresh on each access). */
21
+ href: string;
22
+ /** Replace the URL without reloading. */
23
+ replaceState(url: string): void;
24
+ /** Navigate to a URL (a fresh page load). */
25
+ navigate(url: string): void;
26
+ /** Reload the page. */
27
+ reload(): void;
28
+ }
29
+ /** The browser implementation of {@link PageSurface}. */
30
+ export declare const browserPage: PageSurface;
31
+ /** Whether this browser looks like a phone/tablet (the simplified mobile surface). */
32
+ export declare function isMobileSurface(): boolean;
33
+ /**
34
+ * Run the pair/workspace boot flow for this page load.
35
+ * @param ctx - client root context (workspaces/sessions read at need time).
36
+ * @param search - the current location.search.
37
+ * @param page - the page surface (defaults to the browser).
38
+ */
39
+ export declare function runPairBootFlow(ctx: Context, search: string, page?: PageSurface): void;
40
+ //# sourceMappingURL=deep-link.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deep-link.d.ts","sourceRoot":"","sources":["../../../src/client/deep-link.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAA;AAIlD,qDAAqD;AACrD,eAAO,MAAM,kBAAkB,2BAA2B,CAAA;AAK1D;;;GAGG;AACH,MAAM,WAAW,WAAW;IAC1B,wDAAwD;IACxD,IAAI,EAAE,MAAM,CAAA;IACZ,yCAAyC;IACzC,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAA;IAC/B,6CAA6C;IAC7C,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3B,uBAAuB;IACvB,MAAM,IAAI,IAAI,CAAA;CACf;AAED,yDAAyD;AACzD,eAAO,MAAM,WAAW,EAAE,WAazB,CAAA;AAED,sFAAsF;AACtF,wBAAgB,eAAe,IAAI,OAAO,CAGzC;AAED;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,GAAE,WAAyB,GAAG,IAAI,CASnG"}
@@ -0,0 +1,54 @@
1
+ import type { ClientContext } from '@deepseek-ai/dsh-client-runtime/client';
2
+ import { type RemoteKey } from './locales.ts';
3
+ export type { RemoteEntryProps } from './RemoteEntry.tsx';
4
+ export type { PanelState, RemotePanelProps } from './RemotePanel.tsx';
5
+ export type { PairFailedNoticeProps } from './PairFailedNotice.tsx';
6
+ export type { RemoteKey } from './locales.ts';
7
+ export type { RemoteSettingsCardFace, RemoteSettingsCardState } from './RemoteSettingsCard.tsx';
8
+ declare module '@deepseek-ai/dsh-client-ui-slots' {
9
+ interface LocaleNamespaceMap {
10
+ /** Mobile remote-control surface copy. */
11
+ remote: RemoteKey;
12
+ }
13
+ interface SlotMap {
14
+ /**
15
+ * The sidebar foot seat beside the settings trigger, declared by the
16
+ * sidebar shell on deployments that carry the feature seat; the shell
17
+ * passes only its column display state.
18
+ */
19
+ 'sidebar.remote': {
20
+ kind: 'single';
21
+ scope: 'root';
22
+ owner: SidebarRemoteOwnerProps;
23
+ };
24
+ /**
25
+ * The child slot the Web UI plugin group declares; this card registers
26
+ * into the group instead of the top-level `settings.plugin.item` list.
27
+ * Spelled here with the same shape so this package can register without
28
+ * depending on the sibling UI package.
29
+ */
30
+ 'web-ui.plugin.item': {
31
+ kind: 'list';
32
+ scope: 'root';
33
+ owner: SettingsPluginItemOwnerProps;
34
+ };
35
+ }
36
+ }
37
+ /** Owner share of the sidebar remote-control seat: the column display state the trigger renders against. */
38
+ export interface SidebarRemoteOwnerProps {
39
+ /** Whether the sidebar renders wide content (false = 56px rail). */
40
+ wide: boolean;
41
+ }
42
+ /** Owner share of a plugin card (the section supplies nothing). */
43
+ export interface SettingsPluginItemOwnerProps {
44
+ /** Marker field: card owner props are intentionally empty. */
45
+ children?: never;
46
+ }
47
+ /** Services required by this plugin. */
48
+ export declare const inject: string[];
49
+ /**
50
+ * Register the remote-control surface.
51
+ * @param ctx - client root context.
52
+ */
53
+ export declare function apply(ctx: ClientContext): void;
54
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/client/index.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wCAAwC,CAAA;AAY3E,OAAO,EAAU,KAAK,SAAS,EAAE,MAAM,cAAc,CAAA;AAIrD,YAAY,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AACzD,YAAY,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AACrE,YAAY,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAA;AACnE,YAAY,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA;AAC7C,YAAY,EAAE,sBAAsB,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAA;AAE/F,OAAO,QAAQ,kCAAkC,CAAC;IAChD,UAAU,kBAAkB;QAC1B,0CAA0C;QAC1C,MAAM,EAAE,SAAS,CAAA;KAClB;IAED,UAAU,OAAO;QACf;;;;WAIG;QACH,gBAAgB,EAAE;YAAE,IAAI,EAAE,QAAQ,CAAC;YAAC,KAAK,EAAE,MAAM,CAAC;YAAC,KAAK,EAAE,uBAAuB,CAAA;SAAE,CAAA;QACnF;;;;;WAKG;QACH,oBAAoB,EAAE;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,KAAK,EAAE,MAAM,CAAC;YAAC,KAAK,EAAE,4BAA4B,CAAA;SAAE,CAAA;KAC3F;CACF;AAED,4GAA4G;AAC5G,MAAM,WAAW,uBAAuB;IACtC,oEAAoE;IACpE,IAAI,EAAE,OAAO,CAAA;CACd;AAED,mEAAmE;AACnE,MAAM,WAAW,4BAA4B;IAC3C,8DAA8D;IAC9D,QAAQ,CAAC,EAAE,KAAK,CAAA;CACjB;AAWD,wCAAwC;AACxC,eAAO,MAAM,MAAM,UAA+D,CAAA;AAElF;;;GAGG;AACH,wBAAgB,KAAK,CAAC,GAAG,EAAE,aAAa,GAAG,IAAI,CAmF9C"}
@@ -0,0 +1,144 @@
1
+ /** `remote` namespace dictionaries: the mobile remote-control surface copy. */
2
+ /** Simplified Chinese dictionary (the key-set source of truth). */
3
+ export declare const zh: {
4
+ 'entry.label': string;
5
+ title: string;
6
+ subtitle: string;
7
+ 'card.title': string;
8
+ 'public.badge': string;
9
+ 'status.waiting': string;
10
+ 'status.connected': string;
11
+ 'status.disconnected': string;
12
+ 'status.stopped': string;
13
+ 'status.lanRequired': string;
14
+ 'status.lanRequiredHint': string;
15
+ 'status.loopbackRequired': string;
16
+ 'status.loopbackRequiredHint': string;
17
+ 'status.unreachable': string;
18
+ 'status.unreachableHint': string;
19
+ 'pair.hint': string;
20
+ 'pair.publicHint': string;
21
+ 'address.label': string;
22
+ 'address.public': string;
23
+ 'address.lan': string;
24
+ 'address.hint': string;
25
+ 'pair.expires': string;
26
+ 'pair.expired': string;
27
+ 'pair.failed.title': string;
28
+ 'pair.failed.detail': string;
29
+ 'action.stop': string;
30
+ 'action.refresh': string;
31
+ 'action.copy': string;
32
+ 'action.copied': string;
33
+ 'stopped.hint': string;
34
+ 'tunnel.starting': string;
35
+ 'tunnel.failed': string;
36
+ 'tunnel.unknownError': string;
37
+ 'close.label': string;
38
+ 'settings.title': string;
39
+ 'settings.description': string;
40
+ 'settings.enabled': string;
41
+ 'settings.enabledHint': string;
42
+ 'settings.tokenTtlMs': string;
43
+ 'settings.tokenTtlMsHint': string;
44
+ 'settings.offlineAfterMs': string;
45
+ 'settings.offlineAfterMsHint': string;
46
+ 'settings.maxDevices': string;
47
+ 'settings.maxDevicesHint': string;
48
+ 'settings.cookieName': string;
49
+ 'settings.cookieNameHint': string;
50
+ 'settings.requirePairingForLan': string;
51
+ 'settings.requirePairingForLanHint': string;
52
+ 'settings.publicBaseUrl': string;
53
+ 'settings.publicBaseUrlHint': string;
54
+ 'settings.autoTunnel': string;
55
+ 'settings.autoTunnelHint': string;
56
+ 'settings.inherit': string;
57
+ 'settings.on': string;
58
+ 'settings.off': string;
59
+ 'settings.overridden': string;
60
+ 'settings.reset': string;
61
+ 'settings.readOnly': string;
62
+ 'settings.expand': string;
63
+ 'settings.collapse': string;
64
+ 'settings.save': string;
65
+ 'settings.saving': string;
66
+ 'settings.discard': string;
67
+ 'settings.unsaved': string;
68
+ 'settings.saveFailed': string;
69
+ 'settings.invalidNumber': string;
70
+ };
71
+ /** The remote namespace key union. */
72
+ export type RemoteKey = keyof typeof zh;
73
+ /** The settings-card slice of the remote dictionary. */
74
+ export type SettingsCardKey = RemoteKey;
75
+ /** English dictionary, checked complete against the zh key set. */
76
+ export declare const en: {
77
+ 'entry.label': string;
78
+ title: string;
79
+ subtitle: string;
80
+ 'card.title': string;
81
+ 'public.badge': string;
82
+ 'status.waiting': string;
83
+ 'status.connected': string;
84
+ 'status.disconnected': string;
85
+ 'status.stopped': string;
86
+ 'status.lanRequired': string;
87
+ 'status.lanRequiredHint': string;
88
+ 'status.loopbackRequired': string;
89
+ 'status.loopbackRequiredHint': string;
90
+ 'status.unreachable': string;
91
+ 'status.unreachableHint': string;
92
+ 'pair.hint': string;
93
+ 'pair.publicHint': string;
94
+ 'address.label': string;
95
+ 'address.public': string;
96
+ 'address.lan': string;
97
+ 'address.hint': string;
98
+ 'pair.expires': string;
99
+ 'pair.expired': string;
100
+ 'pair.failed.title': string;
101
+ 'pair.failed.detail': string;
102
+ 'action.stop': string;
103
+ 'action.refresh': string;
104
+ 'action.copy': string;
105
+ 'action.copied': string;
106
+ 'stopped.hint': string;
107
+ 'tunnel.starting': string;
108
+ 'tunnel.failed': string;
109
+ 'tunnel.unknownError': string;
110
+ 'close.label': string;
111
+ 'settings.title': string;
112
+ 'settings.description': string;
113
+ 'settings.enabled': string;
114
+ 'settings.enabledHint': string;
115
+ 'settings.tokenTtlMs': string;
116
+ 'settings.tokenTtlMsHint': string;
117
+ 'settings.offlineAfterMs': string;
118
+ 'settings.offlineAfterMsHint': string;
119
+ 'settings.maxDevices': string;
120
+ 'settings.maxDevicesHint': string;
121
+ 'settings.cookieName': string;
122
+ 'settings.cookieNameHint': string;
123
+ 'settings.requirePairingForLan': string;
124
+ 'settings.requirePairingForLanHint': string;
125
+ 'settings.publicBaseUrl': string;
126
+ 'settings.publicBaseUrlHint': string;
127
+ 'settings.autoTunnel': string;
128
+ 'settings.autoTunnelHint': string;
129
+ 'settings.inherit': string;
130
+ 'settings.on': string;
131
+ 'settings.off': string;
132
+ 'settings.overridden': string;
133
+ 'settings.reset': string;
134
+ 'settings.readOnly': string;
135
+ 'settings.expand': string;
136
+ 'settings.collapse': string;
137
+ 'settings.save': string;
138
+ 'settings.saving': string;
139
+ 'settings.discard': string;
140
+ 'settings.unsaved': string;
141
+ 'settings.saveFailed': string;
142
+ 'settings.invalidNumber': string;
143
+ };
144
+ //# sourceMappingURL=locales.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"locales.d.ts","sourceRoot":"","sources":["../../../src/client/locales.ts"],"names":[],"mappings":"AAAA,+EAA+E;AAE/E,mEAAmE;AACnE,eAAO,MAAM,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAoEmB,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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAoEsB,CAAA"}
@@ -0,0 +1,100 @@
1
+ /**
2
+ * Browser-side wire helpers for the /api/pair surface. Plain fetch over
3
+ * same-origin /api (like the connection client); JSON bodies, string
4
+ * responses for the error codes.
5
+ */
6
+ /** issue() response. */
7
+ export interface IssueResult {
8
+ ok: true;
9
+ url: string;
10
+ token: string;
11
+ expiresAt: number;
12
+ /** Every constructible LAN base address (interface order). */
13
+ lanAddresses: string[];
14
+ /** The configured public (tunneled) base URL, when present. */
15
+ publicBaseUrl?: string;
16
+ }
17
+ /** issue() refusal: the server is not LAN-reachable. */
18
+ export interface IssueLanRequired {
19
+ ok: false;
20
+ code: 'lan-required';
21
+ }
22
+ /** issue() refusal: the requested LAN address is not constructible. */
23
+ export interface IssueUnknownAddress {
24
+ ok: false;
25
+ code: 'unknown-address';
26
+ }
27
+ /** issue() refusal: the loopback-only fence rejected this origin. */
28
+ export interface IssueLoopbackRequired {
29
+ ok: false;
30
+ code: 'forbidden';
31
+ }
32
+ export type IssueResponse = IssueResult | IssueLanRequired | IssueUnknownAddress | IssueLoopbackRequired;
33
+ /** accept() refusal codes. */
34
+ export type AcceptFailure = {
35
+ ok: false;
36
+ code: 'invalid' | 'used' | 'forbidden';
37
+ };
38
+ /** One auto-tunnel status frame (absent while the feature is off). */
39
+ export interface TunnelStatusFrame {
40
+ state: 'starting' | 'running' | 'failed';
41
+ url?: string;
42
+ error?: string;
43
+ }
44
+ /** One /api/pair/events frame. */
45
+ export interface PairStateFrame {
46
+ type: 'state';
47
+ phase: 'lan-required' | 'stopped' | 'waiting' | 'connected' | 'disconnected';
48
+ lanAvailable: boolean;
49
+ tokenId?: string;
50
+ tokenExpiresAt?: number;
51
+ deviceCount: number;
52
+ onlineCount: number;
53
+ /** Auto-tunnel status, while the auto-tunnel feature is active. */
54
+ tunnel?: TunnelStatusFrame;
55
+ }
56
+ /**
57
+ * Mint a fresh pairing token (one active token at a time — this invalidates
58
+ * any previous link).
59
+ * @param workspaceId - optional current workspace to deep-link the phone into.
60
+ * @param address - optional LAN IP literal the QR must be built from (the
61
+ * default is the first interface); unknown literals refuse with
62
+ * 'unknown-address'.
63
+ * @returns the issued link, the lan-required refusal (server never bound
64
+ * 0.0.0.0), or the forbidden refusal (the loopback-only fence rejected this
65
+ * origin — the panel is a desktop control endpoint).
66
+ */
67
+ export declare function issuePair(workspaceId?: string, address?: string): Promise<IssueResponse>;
68
+ /**
69
+ * Accept a pairing token (the phone's first open of the QR link). Success
70
+ * sets the device cookie; the page then reloads to boot with it.
71
+ * @param token - the token from the URL.
72
+ * @returns the wire result.
73
+ */
74
+ export declare function acceptPair(token: string): Promise<{
75
+ ok: true;
76
+ } | AcceptFailure>;
77
+ /** Revoke mobile access (paired devices + the current token). */
78
+ export declare function stopPair(): Promise<void>;
79
+ /** Presence heartbeat from a paired phone (unpaired heartbeats 401 harmlessly). */
80
+ export declare function sendHeartbeat(): Promise<void>;
81
+ /** Whether the current page URL carries a pairing token / workspace target. */
82
+ export declare function readPairParams(search: string): {
83
+ pair?: string;
84
+ workspace?: string;
85
+ };
86
+ /**
87
+ * Strip one query parameter from the current URL without reloading.
88
+ * @param name - the parameter to remove.
89
+ * @returns the new search string ('' when empty).
90
+ */
91
+ export declare function stripParam(name: string): string; /** Human-readable expiry clock, e.g. "10:35". */
92
+ export declare function formatClock(epochMs: number): string;
93
+ /**
94
+ * Copy text to the clipboard with a fallback for insecure contexts
95
+ * (plain-HTTP LAN origins lack navigator.clipboard).
96
+ * @param text - the text to copy.
97
+ * @returns whether the copy succeeded.
98
+ */
99
+ export declare function copyText(text: string): Promise<boolean>;
100
+ //# sourceMappingURL=pair-api.d.ts.map