@linxin666/dsh-remote-web-ui 0.4.1 → 0.4.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. package/README.i18n.yaml +2 -2
  2. package/README.md +9 -7
  3. package/README.zh.md +9 -7
  4. package/lib/client.js +282 -619
  5. package/lib/client.js.map +1 -1
  6. package/lib/index.js +418 -901
  7. package/lib/types/client/RemoteEntry.d.ts.map +1 -1
  8. package/lib/types/client/RemoteEntry.js +9 -10
  9. package/lib/types/client/RemoteSettingsCard.d.ts.map +1 -1
  10. package/lib/types/client/RemoteSettingsCard.js +1 -1
  11. package/lib/types/client/index.d.ts +32 -3
  12. package/lib/types/client/index.d.ts.map +1 -1
  13. package/lib/types/client/index.js +56 -11
  14. package/lib/types/client/locales.d.ts +0 -84
  15. package/lib/types/client/locales.d.ts.map +1 -1
  16. package/lib/types/client/locales.js +2 -86
  17. package/lib/types/client/pair-api.d.ts +4 -0
  18. package/lib/types/client/pair-api.d.ts.map +1 -1
  19. package/lib/types/client/pair-api.js +11 -7
  20. package/lib/types/client/remote-channel.d.ts +27 -7
  21. package/lib/types/client/remote-channel.d.ts.map +1 -1
  22. package/lib/types/client/remote-channel.js +25 -17
  23. package/lib/types/client/settings-entry-form.d.ts +50 -0
  24. package/lib/types/client/settings-entry-form.d.ts.map +1 -0
  25. package/lib/types/client/settings-entry-form.js +98 -0
  26. package/lib/types/index.d.ts +99 -7
  27. package/lib/types/index.d.ts.map +1 -1
  28. package/lib/types/index.js +104 -137
  29. package/lib/types/lan-bind-plan.d.ts +14 -0
  30. package/lib/types/lan-bind-plan.d.ts.map +1 -1
  31. package/lib/types/lan-bind-plan.js +16 -0
  32. package/lib/types/lan-bind.d.ts +5 -1
  33. package/lib/types/lan-bind.d.ts.map +1 -1
  34. package/lib/types/lan-bind.js +65 -2
  35. package/lib/types/mount-once.d.ts +38 -7
  36. package/lib/types/mount-once.d.ts.map +1 -1
  37. package/lib/types/mount-once.js +96 -12
  38. package/lib/types/pairing.d.ts +15 -2
  39. package/lib/types/pairing.d.ts.map +1 -1
  40. package/lib/types/pairing.js +26 -14
  41. package/lib/types/pairing.persist.test.js +43 -3
  42. package/lib/types/remote-channel-boot.d.ts.map +1 -1
  43. package/lib/types/remote-channel-boot.js +13 -3
  44. package/lib/types/remote-channel-rules.d.ts +74 -0
  45. package/lib/types/remote-channel-rules.d.ts.map +1 -1
  46. package/lib/types/remote-channel-rules.js +104 -0
  47. package/lib/types/tunnel.d.ts +60 -3
  48. package/lib/types/tunnel.d.ts.map +1 -1
  49. package/lib/types/tunnel.js +136 -3
  50. package/package.json +21 -20
  51. package/src/client/RemoteEntry.tsx +8 -10
  52. package/src/client/RemoteSettingsCard.tsx +0 -2
  53. package/src/client/index.ts +58 -12
  54. package/src/client/locales.ts +2 -86
  55. package/src/client/pair-api.ts +11 -7
  56. package/src/client/remote-channel.ts +38 -15
  57. package/src/client/remote.module.css +61 -193
  58. package/src/client/settings-entry-form.ts +142 -0
  59. package/src/index.ts +156 -152
  60. package/src/lan-bind-plan.ts +22 -0
  61. package/src/lan-bind.ts +63 -2
  62. package/src/mount-once.ts +107 -13
  63. package/src/pairing.persist.test.ts +47 -3
  64. package/src/pairing.ts +26 -12
  65. package/src/remote-channel-boot.ts +13 -3
  66. package/src/remote-channel-rules.ts +113 -0
  67. package/src/tunnel.ts +142 -3
  68. package/lib/types/client/UpdateEntry.d.ts +0 -14
  69. package/lib/types/client/UpdateEntry.d.ts.map +0 -1
  70. package/lib/types/client/UpdateEntry.js +0 -112
  71. package/lib/types/client/UpdatePanel.d.ts +0 -42
  72. package/lib/types/client/UpdatePanel.d.ts.map +0 -1
  73. package/lib/types/client/UpdatePanel.js +0 -101
  74. package/lib/types/client/update-api.d.ts +0 -29
  75. package/lib/types/client/update-api.d.ts.map +0 -1
  76. package/lib/types/client/update-api.js +0 -47
  77. package/lib/types/console-output.d.ts +0 -41
  78. package/lib/types/console-output.d.ts.map +0 -1
  79. package/lib/types/console-output.js +0 -89
  80. package/lib/types/update-routes.d.ts +0 -30
  81. package/lib/types/update-routes.d.ts.map +0 -1
  82. package/lib/types/update-routes.js +0 -47
  83. package/lib/types/update.d.ts +0 -272
  84. package/lib/types/update.d.ts.map +0 -1
  85. package/lib/types/update.js +0 -744
  86. package/src/client/UpdateEntry.tsx +0 -144
  87. package/src/client/UpdatePanel.tsx +0 -256
  88. package/src/client/update-api.ts +0 -49
  89. package/src/console-output.ts +0 -97
  90. package/src/update-routes.ts +0 -65
  91. package/src/update.ts +0 -882
@@ -21,7 +21,7 @@
21
21
  * Pure helpers are exported for unit tests; `installRemoteChannel` patches
22
22
  * the given window and returns their restore.
23
23
  */
24
- import { REMOTE_API_PREFIX, REMOTE_PREFIX } from '../remote-channel-rules.ts';
24
+ import { isLoopbackHostname as isLoopbackName, REMOTE_API_PREFIX, REMOTE_PREFIX } from '../remote-channel-rules.ts';
25
25
  export { REMOTE_API_PREFIX, REMOTE_PREFIX };
26
26
  export type { RemoteChannelBootSeat } from '../remote-channel-rules.ts';
27
27
  export { REMOTE_CHANNEL_BOOT_GLOBAL } from '../remote-channel-rules.ts';
@@ -33,15 +33,35 @@ export interface RemoteChannelSettingsSnapshot {
33
33
  requirePairingForLan?: boolean;
34
34
  };
35
35
  }
36
+ /**
37
+ * Facts about the live page that decide whether it is local. Defaults come
38
+ * from `window` so ordinary call sites stay argument-free; tests pass them
39
+ * explicitly.
40
+ */
41
+ export interface PageOriginFacts {
42
+ hostname: string;
43
+ protocol?: string;
44
+ transportOwnsHost?: boolean;
45
+ }
46
+ /**
47
+ * Read the page-origin facts from a window-like object: the hostname and
48
+ * protocol of the page itself plus the official transport's host-owner flag
49
+ * (`__DSH_TRANSPORT__.ownsHost`, set by the desktop shell before any boot
50
+ * entry, and by this plugin's own paired landing).
51
+ * @param win - the window to read (defaults to the real one).
52
+ * @returns the facts `isLocalPage`/`remoteChannelRequired` decide from.
53
+ */
54
+ export declare function pageOriginFacts(win?: Pick<Window, 'location'> & Partial<Pick<Window, 'navigator'>>): PageOriginFacts;
36
55
  /** Decide whether a remote desktop channel is required from local or host policy. */
37
- export declare function remoteChannelRequired(hostname: string, snapshot: RemoteChannelSettingsSnapshot, hostPairingPolicy: boolean | undefined): boolean;
56
+ export declare function remoteChannelRequired(origin: PageOriginFacts, snapshot: RemoteChannelSettingsSnapshot, hostPairingPolicy: boolean | undefined): boolean;
38
57
  /**
39
- * Browser-safe loopback classification for the page origin (the SDK client
40
- * exports its own; this copy keeps the module dependency-free).
41
- * @param hostname - a location hostname (IPv6 without brackets).
42
- * @returns true for localhost, IPv6 loopback, or any 127/8 literal.
58
+ * Browser-safe loopback classification for the page origin. The definition
59
+ * lives once in the rules module, which the inlined boot script mirrors
60
+ * verbatim, so the browser half and the parse-time patch can never disagree
61
+ * (an IPv6-loopback origin judged remote would rewrite every call onto a
62
+ * channel it can never pair on).
43
63
  */
44
- export declare function isLoopbackHostname(hostname: string): boolean;
64
+ export declare const isLoopbackHostname: typeof isLoopbackName;
45
65
  /**
46
66
  * Whether one same-origin path must ride the gated channel (fetch, EventSource,
47
67
  * img/script/iframe src).
@@ -1 +1 @@
1
- {"version":3,"file":"remote-channel.d.ts","sourceRoot":"","sources":["../../../src/client/remote-channel.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"remote-channel.d.ts","sourceRoot":"","sources":["../../../src/client/remote-channel.ts"],"names":[],"mappings":"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"}
@@ -21,13 +21,29 @@
21
21
  * Pure helpers are exported for unit tests; `installRemoteChannel` patches
22
22
  * the given window and returns their restore.
23
23
  */
24
- import { REMOTE_API_PREFIX, REMOTE_CHANNEL_RULES, REMOTE_PREFIX, } from "../remote-channel-rules.js";
24
+ import { isLoopbackHostname as isLoopbackName, isLocalPage, REMOTE_API_PREFIX, REMOTE_CHANNEL_RULES, REMOTE_PREFIX, } from "../remote-channel-rules.js";
25
25
  export { REMOTE_API_PREFIX, REMOTE_PREFIX };
26
26
  export { REMOTE_CHANNEL_BOOT_GLOBAL } from "../remote-channel-rules.js";
27
27
  const RULES = REMOTE_CHANNEL_RULES;
28
+ /**
29
+ * Read the page-origin facts from a window-like object: the hostname and
30
+ * protocol of the page itself plus the official transport's host-owner flag
31
+ * (`__DSH_TRANSPORT__.ownsHost`, set by the desktop shell before any boot
32
+ * entry, and by this plugin's own paired landing).
33
+ * @param win - the window to read (defaults to the real one).
34
+ * @returns the facts `isLocalPage`/`remoteChannelRequired` decide from.
35
+ */
36
+ export function pageOriginFacts(win = window) {
37
+ const transport = win.__DSH_TRANSPORT__;
38
+ return {
39
+ hostname: win.location.hostname,
40
+ protocol: win.location.protocol,
41
+ ...(transport?.ownsHost === true ? { transportOwnsHost: true } : {}),
42
+ };
43
+ }
28
44
  /** Decide whether a remote desktop channel is required from local or host policy. */
29
- export function remoteChannelRequired(hostname, snapshot, hostPairingPolicy) {
30
- if (isLoopbackHostname(hostname))
45
+ export function remoteChannelRequired(origin, snapshot, hostPairingPolicy) {
46
+ if (isLocalPage(origin.hostname, origin.protocol, origin.transportOwnsHost))
31
47
  return false;
32
48
  if (snapshot.status === 'ready') {
33
49
  return (snapshot.value?.enabled ?? true) && (snapshot.value?.requirePairingForLan ?? true);
@@ -37,21 +53,13 @@ export function remoteChannelRequired(hostname, snapshot, hostPairingPolicy) {
37
53
  return hostPairingPolicy !== false;
38
54
  }
39
55
  /**
40
- * Browser-safe loopback classification for the page origin (the SDK client
41
- * exports its own; this copy keeps the module dependency-free).
42
- * @param hostname - a location hostname (IPv6 without brackets).
43
- * @returns true for localhost, IPv6 loopback, or any 127/8 literal.
56
+ * Browser-safe loopback classification for the page origin. The definition
57
+ * lives once in the rules module, which the inlined boot script mirrors
58
+ * verbatim, so the browser half and the parse-time patch can never disagree
59
+ * (an IPv6-loopback origin judged remote would rewrite every call onto a
60
+ * channel it can never pair on).
44
61
  */
45
- export function isLoopbackHostname(hostname) {
46
- // WHATWG location.hostname keeps IPv6 literals bracketed ("[::1]"); the
47
- // host-side shared predicate accepts that spelling, so this browser copy must
48
- // too, or an IPv6-loopback origin is judged remote and rewrites every call
49
- // onto the gated channel where it can never pair.
50
- if (hostname === 'localhost' || hostname === '::1' || hostname === '[::1]')
51
- return true;
52
- const parts = hostname.split('.');
53
- return parts.length === 4 && parts[0] === '127' && parts.every(part => /^\d{1,3}$/.test(part) && Number(part) <= 255);
54
- }
62
+ export const isLoopbackHostname = isLoopbackName;
55
63
  /**
56
64
  * Whether one same-origin path must ride the gated channel (fetch, EventSource,
57
65
  * img/script/iframe src).
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Family settings form bound to the profile entry id a Host actually serves.
3
+ *
4
+ * Under the 0.1.7 settings model a form is addressed by PROFILE ENTRY ID, while
5
+ * a family card knows only its own settings namespace. The family binder
6
+ * (`ctx.get('webUiSettings')`, published by dsh-web-settings) resolves one onto
7
+ * the other and is the preferred transport; this module is the fallback for a
8
+ * page that serves no binder — the group plugin is not installed, or its client
9
+ * half has not applied yet (the aggregate mounts its children in order, and a
10
+ * child still waiting on its own injects publishes nothing).
11
+ *
12
+ * The shared describe mirror is the only local evidence of which row id this
13
+ * profile serves, but it answers asynchronously: at plugin activation it usually
14
+ * holds nothing yet. A one-shot guess therefore cannot be right for every
15
+ * deployment, and the form is bound once per session:
16
+ *
17
+ * - binding the bare namespace made every save answer `No configurable plugin
18
+ * entry "<namespace>"` on an aggregate install (the namespace is not an entry
19
+ * id there), which the card reported as "the deployment did not accept these
20
+ * values";
21
+ * - binding the aggregate row id would break a standalone install, whose row id
22
+ * is the namespace or the package's own `ui-*` row.
23
+ *
24
+ * So the fallback starts on the most likely row and REBINDS the moment the
25
+ * mirror names one of this package's rows. Until the mirror answers, the form
26
+ * reports the binding it holds (usually `loading`), which the card renders as an
27
+ * unavailable form rather than a doomed one.
28
+ */
29
+ import type { ConfigForm, ConfigForms } from '@deepseek-ai/dsh-client-ui-settings/client';
30
+ /** Options of {@link createServedEntryForm}. */
31
+ export interface ServedEntryFormOptions<T> {
32
+ /** The shared configuration forms service (`ctx.configForms`). */
33
+ forms: ConfigForms;
34
+ /**
35
+ * Profile entry ids this package's rows carry, most likely first: the
36
+ * aggregate's generated row, the package's own standalone row, then the bare
37
+ * namespace. The first is the fallback while the mirror has no answer; the
38
+ * last is the answer when the mirror serves none of them.
39
+ */
40
+ entryIds: readonly string[];
41
+ }
42
+ /**
43
+ * Create a settings form bound to the profile entry id this Host serves, and
44
+ * rebound whenever the shared describe mirror names a different one of this
45
+ * package's rows.
46
+ * @param options - the shared forms service and this package's candidate row ids.
47
+ * @returns a form delegating to the currently resolved entry's own form.
48
+ */
49
+ export declare function createServedEntryForm<T>(options: ServedEntryFormOptions<T>): ConfigForm<T>;
50
+ //# sourceMappingURL=settings-entry-form.d.ts.map
@@ -0,0 +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"}
@@ -0,0 +1,98 @@
1
+ /** The snapshot a form reports before the Host has answered with this entry. */
2
+ function pendingSnapshot() {
3
+ return {
4
+ status: 'loading',
5
+ value: undefined,
6
+ base: undefined,
7
+ user: undefined,
8
+ revision: undefined,
9
+ writable: false,
10
+ mode: 'host',
11
+ };
12
+ }
13
+ /**
14
+ * Create a settings form bound to the profile entry id this Host serves, and
15
+ * rebound whenever the shared describe mirror names a different one of this
16
+ * package's rows.
17
+ * @param options - the shared forms service and this package's candidate row ids.
18
+ * @returns a form delegating to the currently resolved entry's own form.
19
+ */
20
+ export function createServedEntryForm(options) {
21
+ const { forms, entryIds } = options;
22
+ const fallbackId = entryIds[0];
23
+ const namespaceId = entryIds[entryIds.length - 1];
24
+ const listeners = new Set();
25
+ let boundId;
26
+ let bound;
27
+ let offBound;
28
+ let snapshot = pendingSnapshot();
29
+ /** Republish: the delegated snapshot when one is bound, the pending one otherwise. */
30
+ const publish = () => {
31
+ if (bound !== undefined)
32
+ snapshot = bound.getSnapshot();
33
+ for (const listener of [...listeners])
34
+ listener();
35
+ };
36
+ /**
37
+ * The entry id the mirror currently justifies. An unanswered or empty mirror
38
+ * is not evidence of absence, so it keeps the first candidate; a mirror that
39
+ * answers without any of this package's rows leaves the namespace itself.
40
+ * @returns the entry id to bind.
41
+ */
42
+ const resolve = () => {
43
+ let served;
44
+ try {
45
+ served = forms.describe().getSnapshot().view?.namespaces.map(row => row.ns);
46
+ }
47
+ catch {
48
+ // A mirror that refuses the read is unanswered too, not absent.
49
+ served = undefined;
50
+ }
51
+ if (served === undefined || served.length === 0)
52
+ return fallbackId;
53
+ return entryIds.find(id => served.includes(id)) ?? namespaceId;
54
+ };
55
+ /** Bind (or rebind) the resolved entry's form; a no-op while it is unchanged. */
56
+ const bind = () => {
57
+ const target = resolve();
58
+ if (target === boundId)
59
+ return;
60
+ offBound?.();
61
+ offBound = undefined;
62
+ let form;
63
+ try {
64
+ form = forms.get(target);
65
+ }
66
+ catch {
67
+ // A service that refuses the id stays unbound; the next mirror answer
68
+ // retries rather than pinning a wrong entry for the session.
69
+ boundId = undefined;
70
+ return;
71
+ }
72
+ boundId = target;
73
+ bound = form;
74
+ offBound = form.subscribe(() => { publish(); });
75
+ publish();
76
+ };
77
+ // The mirror subscription lives for the page: the card owns its form for the
78
+ // session, and the ConfigForm contract carries no disposer to hang it on. The
79
+ // callback is cheap (a resolve plus a no-op while the id is unchanged). A
80
+ // mirror without a subscription seat keeps the initial binding.
81
+ try {
82
+ forms.describe().subscribe(() => { bind(); });
83
+ }
84
+ catch {
85
+ // A describe face that refuses the subscription: the initial binding stands.
86
+ }
87
+ bind();
88
+ return {
89
+ getSnapshot: () => snapshot,
90
+ subscribe: (listener) => {
91
+ listeners.add(listener);
92
+ return () => { listeners.delete(listener); };
93
+ },
94
+ set: (field, value) => bound?.set(field, value) ?? Promise.resolve(false),
95
+ unset: (field) => bound?.unset(field) ?? Promise.resolve(false),
96
+ mutate: (ops, expectedRevision) => bound?.mutate(ops, expectedRevision) ?? Promise.resolve(false),
97
+ };
98
+ }
@@ -10,10 +10,19 @@
10
10
  import type { IncomingMessage } from 'node:http';
11
11
  import type { Context } from '@deepseek-ai/cordis';
12
12
  import type { SettingsNamespace } from '@deepseek-ai/dsh-settings';
13
- import z from 'schemastery';
13
+ import z from '@deepseek-ai/schemastery';
14
14
  import { type PairingConfig } from './pairing.ts';
15
15
  declare module '@deepseek-ai/cordis' {
16
16
  interface Events {
17
+ /**
18
+ * Volatile config values were committed into the running fiber without a
19
+ * remount; dispatched to the owning fiber only. Spelled here because the
20
+ * Loader package is not a dependency of this plugin, with the Loader's own
21
+ * shape so the two declarations merge when a Host program carries both.
22
+ * @param paths - changed config paths as key arrays; every value is committed before dispatch.
23
+ * @mode emit
24
+ */
25
+ 'loader/volatile-update'(paths: readonly (readonly string[])[]): void;
17
26
  /**
18
27
  * Waterfall seam on the /api transport fence: the connection plugin
19
28
  * fires this per /api request before bridging to the API proxy on
@@ -147,16 +156,71 @@ export interface Config {
147
156
  */
148
157
  lanBind?: boolean;
149
158
  /**
150
- * The profile whose cordis.patch.yml the LAN bind toggle manages.
151
- * Defaults to the DSH_PROFILE environment variable, then "web". Must be
152
- * a single safe path segment (the DSH_PROFILE env fallback bypasses this
153
- * schema, so the path builder asserts containment independently).
159
+ * The profile whose cordis.patch.yml the LAN bind toggle manages. Defaults
160
+ * to the profile the Host booted (its `profileContext`), then to the
161
+ * DSH_PROFILE environment variable, then "web" — the Desktop client boots
162
+ * "desktop" without exporting DSH_PROFILE, so the environment alone names
163
+ * the wrong profile there. Must be a single safe path segment (the runtime
164
+ * and environment fallbacks bypass this schema, so the path builder asserts
165
+ * containment independently).
154
166
  */
155
167
  profile?: string;
156
168
  /** Master switch for the plugin (browser half + host pairing surfaces). */
157
169
  enabled?: boolean;
158
170
  }
159
- export declare const Config: z<Config>;
171
+ /**
172
+ * Plugin config schema. Under the 0.1.7 settings model this schema IS the
173
+ * entry's settings page: the Host derives one form per profile entry from it
174
+ * and serves that form only when at least one field is `volatile()`. The marker
175
+ * is also what admits a write and what keeps the edit on the live path — the
176
+ * Loader commits the new value into the field's reference and announces
177
+ * `loader/volatile-update` on this fiber instead of remounting the row, so the
178
+ * pairing service, its device sessions, the tunnel and the route registrations
179
+ * survive a settings save (see {@link applyImpl}'s sync).
180
+ *
181
+ * The schema is left to inference rather than annotated with `z<Config>`: a
182
+ * volatile field's parsed output is a live reference while its accepted input
183
+ * stays the plain value, so the two sides no longer share one shape and the
184
+ * annotation would reject the schema the Host must be given.
185
+ *
186
+ * The deployment-level fields (`trustedHosts`, `devicesFile`, `profile`) are
187
+ * deliberately NOT volatile: they belong in the profile patch, so the form
188
+ * leaves them to the operator instead of offering a card control that a
189
+ * document write could not honor.
190
+ */
191
+ export declare const Config: z<Schemastery.ObjectS<NoInfer<{
192
+ tokenTtlMs: z<number, number, "volatile-defined">;
193
+ offlineAfterMs: z<number, number, "volatile-defined">;
194
+ maxDevices: z<number, number, "volatile-defined">;
195
+ idleExpireMs: z<number, number, "volatile-defined">;
196
+ cookieName: z<string, string, "volatile-defined">;
197
+ requirePairingForLan: z<boolean, boolean, "volatile-defined">;
198
+ publicBaseUrl: z<string, string, "volatile">;
199
+ trustedHosts: z<string[], string[], "plain">;
200
+ devicesFile: z<string, string, "plain">;
201
+ autoTunnel: z<boolean, boolean, "volatile-defined">;
202
+ tunnelToken: z<string, string, "volatile">;
203
+ relay: z<boolean, boolean, "volatile-defined">;
204
+ lanBind: z<boolean, boolean, "volatile">;
205
+ profile: z<string, string, "plain">;
206
+ enabled: z<boolean, boolean, "volatile-defined">;
207
+ }>>, Schemastery.ObjectT<NoInfer<{
208
+ tokenTtlMs: z<number, number, "volatile-defined">;
209
+ offlineAfterMs: z<number, number, "volatile-defined">;
210
+ maxDevices: z<number, number, "volatile-defined">;
211
+ idleExpireMs: z<number, number, "volatile-defined">;
212
+ cookieName: z<string, string, "volatile-defined">;
213
+ requirePairingForLan: z<boolean, boolean, "volatile-defined">;
214
+ publicBaseUrl: z<string, string, "volatile">;
215
+ trustedHosts: z<string[], string[], "plain">;
216
+ devicesFile: z<string, string, "plain">;
217
+ autoTunnel: z<boolean, boolean, "volatile-defined">;
218
+ tunnelToken: z<string, string, "volatile">;
219
+ relay: z<boolean, boolean, "volatile-defined">;
220
+ lanBind: z<boolean, boolean, "volatile">;
221
+ profile: z<string, string, "plain">;
222
+ enabled: z<boolean, boolean, "volatile-defined">;
223
+ }>>, "plain">;
160
224
  /**
161
225
  * Fully resolved config: every field non-optional except `publicBaseUrl`,
162
226
  * which legitimately resolves to `undefined` when unset (the schema keeps it
@@ -171,6 +235,34 @@ type ResolvedConfig = Required<Omit<Config, 'publicBaseUrl' | 'trustedHosts' | '
171
235
  tunnelToken: string | undefined;
172
236
  profile: string;
173
237
  };
238
+ /**
239
+ * The stable reference a `volatile()` config field resolves to; its owner
240
+ * updates it in place when the user saves.
241
+ */
242
+ interface ConfigRef<T> {
243
+ /** @returns the value currently committed for the running instance. */
244
+ get(): T;
245
+ }
246
+ /** One resolved config field: a live reference, or a plain value from a hand-built context. */
247
+ type ConfigField<T> = ConfigRef<T> | T;
248
+ /** The config the Host hands {@link applyImpl} — the runtime face of {@link Config}. */
249
+ export interface ResolvedConfigFields {
250
+ tokenTtlMs?: ConfigField<number>;
251
+ offlineAfterMs?: ConfigField<number>;
252
+ maxDevices?: ConfigField<number>;
253
+ idleExpireMs?: ConfigField<number>;
254
+ cookieName?: ConfigField<string>;
255
+ requirePairingForLan?: ConfigField<boolean>;
256
+ publicBaseUrl?: ConfigField<string>;
257
+ trustedHosts?: ConfigField<string[]>;
258
+ devicesFile?: ConfigField<string>;
259
+ autoTunnel?: ConfigField<boolean>;
260
+ tunnelToken?: ConfigField<string>;
261
+ relay?: ConfigField<boolean>;
262
+ lanBind?: ConfigField<boolean>;
263
+ profile?: ConfigField<string>;
264
+ enabled?: ConfigField<boolean>;
265
+ }
174
266
  /**
175
267
  * The single mapping from resolved plugin config to the pairing service
176
268
  * config. Both the constructed service and every later apply of this row
@@ -185,6 +277,6 @@ export declare function defaultDevicesFile(home?: string): string;
185
277
  * @param config - resolved plugin config (schema defaults applied by the loader).
186
278
  */
187
279
  export declare const apply: typeof applyImpl;
188
- declare function applyImpl(ctx: Context, config?: Config): void;
280
+ declare function applyImpl(ctx: Context, config?: ResolvedConfigFields): void;
189
281
  export {};
190
282
  //# sourceMappingURL=index.d.ts.map
@@ -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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"}