dsh-zen-remote 2.3.11 → 2.4.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.
- package/CHANGELOG.md +45 -78
- package/README.md +94 -84
- package/README.zh-CN.md +90 -81
- package/bin/zen-remote.mjs +5 -0
- package/docs/interface.md +6 -6
- package/docs/remote-access.en.md +6 -4
- package/docs/remote-access.md +6 -4
- package/dsh-push.mjs +96 -10
- package/lib/adapters/dsh-better-sidebar/index.js +7 -3
- package/lib/adapters/dsh-better-sidebar/index.js.map +1 -1
- package/lib/admin-routes.js +10 -2
- package/lib/admin-routes.js.map +1 -1
- package/lib/cli/args.js +251 -0
- package/lib/cli/args.js.map +1 -0
- package/lib/cli/bootstrap.js +449 -0
- package/lib/cli/bootstrap.js.map +1 -0
- package/lib/cli/command-setup.js +484 -0
- package/lib/cli/command-setup.js.map +1 -0
- package/lib/cli/commands-client.js +359 -0
- package/lib/cli/commands-client.js.map +1 -0
- package/lib/cli/commands-host.js +1108 -0
- package/lib/cli/commands-host.js.map +1 -0
- package/lib/cli/commands-status.js +279 -0
- package/lib/cli/commands-status.js.map +1 -0
- package/lib/cli/config-writer.js +334 -0
- package/lib/cli/config-writer.js.map +1 -0
- package/lib/cli/context.js +10 -0
- package/lib/cli/context.js.map +1 -0
- package/lib/cli/i18n.js +620 -0
- package/lib/cli/i18n.js.map +1 -0
- package/lib/cli/ipc-client.js +160 -0
- package/lib/cli/ipc-client.js.map +1 -0
- package/lib/cli/ipc-server.js +464 -0
- package/lib/cli/ipc-server.js.map +1 -0
- package/lib/cli/main.js +245 -0
- package/lib/cli/main.js.map +1 -0
- package/lib/cli/qr-terminal.js +48 -0
- package/lib/cli/qr-terminal.js.map +1 -0
- package/lib/client-data/qr.js +286 -0
- package/lib/client-data/qr.js.map +1 -0
- package/lib/client-routes.js +308 -25
- package/lib/client-routes.js.map +1 -1
- package/lib/client.js +1013 -229
- package/lib/config.js +50 -12
- package/lib/config.js.map +1 -1
- package/lib/debug-report.js +28 -1
- package/lib/debug-report.js.map +1 -1
- package/lib/fetch-route-intercept.js +334 -26
- package/lib/fetch-route-intercept.js.map +1 -1
- package/lib/index.js +608 -375
- package/lib/index.js.map +1 -1
- package/lib/intercept.js +1833 -280
- package/lib/intercept.js.map +1 -1
- package/lib/lan-gate-server.cjs +36 -10
- package/lib/merge-streams.js +103 -11
- package/lib/merge-streams.js.map +1 -1
- package/lib/plugin-route-intercept.js +93 -63
- package/lib/plugin-route-intercept.js.map +1 -1
- package/lib/relay-access.js +8 -1
- package/lib/relay-access.js.map +1 -1
- package/lib/relay-client.js +133 -4
- package/lib/relay-client.js.map +1 -1
- package/lib/relay-pool.js +275 -0
- package/lib/relay-pool.js.map +1 -0
- package/lib/relay-server.js +269 -17
- package/lib/relay-server.js.map +1 -1
- package/lib/restart-fields.js +6 -4
- package/lib/restart-fields.js.map +1 -1
- package/lib/share-ops.js +68 -0
- package/lib/share-ops.js.map +1 -1
- package/lib/share-store.js +65 -27
- package/lib/share-store.js.map +1 -1
- package/lib/state-store.js +400 -0
- package/lib/state-store.js.map +1 -0
- package/lib/types/adapters/dsh-better-sidebar/index.d.ts +3 -2
- package/lib/types/adapters/dsh-better-sidebar/index.d.ts.map +1 -1
- package/lib/types/admin-routes.d.ts.map +1 -1
- package/lib/types/cli/args.d.ts +78 -0
- package/lib/types/cli/args.d.ts.map +1 -0
- package/lib/types/cli/bootstrap.d.ts +170 -0
- package/lib/types/cli/bootstrap.d.ts.map +1 -0
- package/lib/types/cli/command-setup.d.ts +72 -0
- package/lib/types/cli/command-setup.d.ts.map +1 -0
- package/lib/types/cli/commands-client.d.ts +36 -0
- package/lib/types/cli/commands-client.d.ts.map +1 -0
- package/lib/types/cli/commands-host.d.ts +82 -0
- package/lib/types/cli/commands-host.d.ts.map +1 -0
- package/lib/types/cli/commands-status.d.ts +46 -0
- package/lib/types/cli/commands-status.d.ts.map +1 -0
- package/lib/types/cli/config-writer.d.ts +92 -0
- package/lib/types/cli/config-writer.d.ts.map +1 -0
- package/lib/types/cli/context.d.ts +39 -0
- package/lib/types/cli/context.d.ts.map +1 -0
- package/lib/types/cli/i18n.d.ts +32 -0
- package/lib/types/cli/i18n.d.ts.map +1 -0
- package/lib/types/cli/ipc-client.d.ts +83 -0
- package/lib/types/cli/ipc-client.d.ts.map +1 -0
- package/lib/types/cli/ipc-server.d.ts +113 -0
- package/lib/types/cli/ipc-server.d.ts.map +1 -0
- package/lib/types/cli/main.d.ts +57 -0
- package/lib/types/cli/main.d.ts.map +1 -0
- package/lib/types/cli/qr-terminal.d.ts +17 -0
- package/lib/types/cli/qr-terminal.d.ts.map +1 -0
- package/lib/types/client/RemoteStatusIcon.d.ts.map +1 -1
- package/lib/types/client/current-session-report.d.ts +4 -0
- package/lib/types/client/current-session-report.d.ts.map +1 -1
- package/lib/types/client/effects/model-group-side.d.ts.map +1 -1
- package/lib/types/client/effects/remote-session.d.ts.map +1 -1
- package/lib/types/client/locales.d.ts +47 -3
- package/lib/types/client/locales.d.ts.map +1 -1
- package/lib/types/client/settings/SettingsSection.d.ts.map +1 -1
- package/lib/types/client/settings/settings-css.d.ts +1 -1
- package/lib/types/client/settings/settings-css.d.ts.map +1 -1
- package/lib/types/client/styles/remote-session.css.d.ts +1 -1
- package/lib/types/client/styles/remote-session.css.d.ts.map +1 -1
- package/lib/types/client/wizard/GatewayWizard.d.ts.map +1 -1
- package/lib/types/client/wizard/cards/ProxyCard.d.ts.map +1 -1
- package/lib/types/client/wizard/wizard-css.d.ts +1 -1
- package/lib/types/client/wizard/wizard-css.d.ts.map +1 -1
- package/lib/types/client-data/model-group-side.d.ts +23 -2
- package/lib/types/client-data/model-group-side.d.ts.map +1 -1
- package/lib/types/client-data/remote-status.d.ts +47 -1
- package/lib/types/client-data/remote-status.d.ts.map +1 -1
- package/lib/types/client-data/settings-form.d.ts +85 -1
- package/lib/types/client-data/settings-form.d.ts.map +1 -1
- package/lib/types/client-data/wizard.d.ts +56 -1
- package/lib/types/client-data/wizard.d.ts.map +1 -1
- package/lib/types/client-routes.d.ts +25 -1
- package/lib/types/client-routes.d.ts.map +1 -1
- package/lib/types/config.d.ts +40 -14
- package/lib/types/config.d.ts.map +1 -1
- package/lib/types/debug-report.d.ts.map +1 -1
- package/lib/types/fetch-route-intercept.d.ts +66 -8
- package/lib/types/fetch-route-intercept.d.ts.map +1 -1
- package/lib/types/index.d.ts +9 -2
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/intercept.d.ts +72 -10
- package/lib/types/intercept.d.ts.map +1 -1
- package/lib/types/merge-streams.d.ts +79 -1
- package/lib/types/merge-streams.d.ts.map +1 -1
- package/lib/types/plugin-route-intercept.d.ts +25 -9
- package/lib/types/plugin-route-intercept.d.ts.map +1 -1
- package/lib/types/relay-access.d.ts +3 -1
- package/lib/types/relay-access.d.ts.map +1 -1
- package/lib/types/relay-client.d.ts +23 -2
- package/lib/types/relay-client.d.ts.map +1 -1
- package/lib/types/relay-pool.d.ts +148 -0
- package/lib/types/relay-pool.d.ts.map +1 -0
- package/lib/types/relay-server.d.ts +30 -3
- package/lib/types/relay-server.d.ts.map +1 -1
- package/lib/types/restart-fields.d.ts +5 -5
- package/lib/types/restart-fields.d.ts.map +1 -1
- package/lib/types/share-ops.d.ts +47 -1
- package/lib/types/share-ops.d.ts.map +1 -1
- package/lib/types/share-store.d.ts.map +1 -1
- package/lib/types/state-store.d.ts +179 -0
- package/lib/types/state-store.d.ts.map +1 -0
- package/lib/types/upload-limits.d.ts +15 -0
- package/lib/types/upload-limits.d.ts.map +1 -1
- package/lib/types/virtual-id.d.ts +21 -0
- package/lib/types/virtual-id.d.ts.map +1 -1
- package/lib/types/wizard/probe.d.ts.map +1 -1
- package/lib/types/wizard/proxy-snippets.d.ts +3 -0
- package/lib/types/wizard/proxy-snippets.d.ts.map +1 -1
- package/lib/types/wizard/routes.d.ts +1 -0
- package/lib/types/wizard/routes.d.ts.map +1 -1
- package/lib/types/wizard/status.d.ts +9 -0
- package/lib/types/wizard/status.d.ts.map +1 -1
- package/lib/types/wizard/verify.d.ts +3 -0
- package/lib/types/wizard/verify.d.ts.map +1 -1
- package/lib/upload-limits.js +15 -0
- package/lib/upload-limits.js.map +1 -1
- package/lib/virtual-id.js +60 -0
- package/lib/virtual-id.js.map +1 -1
- package/lib/wizard/probe.js +46 -1
- package/lib/wizard/probe.js.map +1 -1
- package/lib/wizard/proxy-snippets.js +14 -1
- package/lib/wizard/proxy-snippets.js.map +1 -1
- package/lib/wizard/routes.js +23 -4
- package/lib/wizard/routes.js.map +1 -1
- package/lib/wizard/status.js +21 -0
- package/lib/wizard/status.js.map +1 -1
- package/lib/wizard/verify.js +31 -8
- package/lib/wizard/verify.js.map +1 -1
- package/package.json +8 -4
- package/pwa/icons/badge-96.png +0 -0
- package/pwa/icons/badge.svg +1 -0
- package/pwa/manifest.json +2 -1
- package/pwa/sw.js +3 -1
- package/scripts/check-debug-report.mjs +41 -1
- package/scripts/check-settings-form.mjs +14 -3
- package/scripts/check-settings-view.mjs +247 -0
- package/scripts/check-wizard-ui.mjs +37 -0
- package/src/adapters/dsh-better-sidebar/index.ts +7 -3
- package/src/admin-routes.ts +10 -2
- package/src/cli/args.ts +289 -0
- package/src/cli/bootstrap.ts +569 -0
- package/src/cli/command-setup.ts +540 -0
- package/src/cli/commands-client.ts +369 -0
- package/src/cli/commands-host.ts +1127 -0
- package/src/cli/commands-status.ts +296 -0
- package/src/cli/config-writer.ts +354 -0
- package/src/cli/context.ts +38 -0
- package/src/cli/i18n.ts +645 -0
- package/src/cli/ipc-client.ts +216 -0
- package/src/cli/ipc-server.ts +531 -0
- package/src/cli/main.ts +285 -0
- package/src/cli/qr-terminal.ts +49 -0
- package/src/client/RemoteStatusIcon.tsx +4 -1
- package/src/client/current-session-report.ts +28 -4
- package/src/client/effects/model-group-side.ts +19 -5
- package/src/client/effects/remote-session.ts +26 -6
- package/src/client/locales.ts +96 -6
- package/src/client/settings/SettingsSection.tsx +287 -92
- package/src/client/settings/settings-css.ts +18 -0
- package/src/client/styles/remote-session.css.ts +15 -1
- package/src/client/wizard/GatewayWizard.tsx +470 -109
- package/src/client/wizard/cards/ProxyCard.tsx +2 -1
- package/src/client/wizard/wizard-css.ts +23 -0
- package/src/client-data/model-group-side.ts +37 -10
- package/src/client-data/remote-status.ts +112 -17
- package/src/client-data/settings-form.ts +164 -8
- package/src/client-data/wizard.ts +112 -2
- package/src/client-routes.ts +334 -26
- package/src/config.ts +62 -16
- package/src/debug-report.ts +27 -1
- package/src/fetch-route-intercept.ts +381 -32
- package/src/index.ts +608 -380
- package/src/intercept.ts +1866 -286
- package/src/merge-streams.ts +155 -10
- package/src/plugin-route-intercept.ts +120 -71
- package/src/relay-access.ts +14 -3
- package/src/relay-client.ts +163 -5
- package/src/relay-pool.ts +387 -0
- package/src/relay-server.ts +312 -16
- package/src/restart-fields.ts +6 -4
- package/src/share-ops.ts +82 -1
- package/src/share-store.ts +59 -26
- package/src/state-store.ts +428 -0
- package/src/upload-limits.ts +16 -0
- package/src/virtual-id.ts +57 -0
- package/src/wizard/probe.ts +54 -2
- package/src/wizard/proxy-snippets.ts +17 -2
- package/src/wizard/routes.ts +24 -5
- package/src/wizard/status.ts +28 -0
- package/src/wizard/verify.ts +33 -11
- package/AGENTS.md +0 -185
- package/docs/adr/0001-plugin-bridge-forwards-plugin-routes.md +0 -15
- package/docs/adr/0002-relay-emulates-websocket.md +0 -8
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"qr.js","sourceRoot":"","sources":["../../src/client-data/qr.ts"],"names":[],"mappings":"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"}
|
package/lib/client-routes.js
CHANGED
|
@@ -30,6 +30,7 @@ import { assembleDebugReport } from './debug-report.js';
|
|
|
30
30
|
import { responseJson, sameOriginPost } from './http.js';
|
|
31
31
|
import { RELAY_HTTP_ROUTES } from './relay-access.js';
|
|
32
32
|
import { relayCredentialsDigest, RelayError } from './relay-client.js';
|
|
33
|
+
import { MAX_PAIRED_SERVERS } from './relay-pool.js';
|
|
33
34
|
import { resolveDshVersion } from './relay-server.js';
|
|
34
35
|
import { fromVirtual } from './virtual-id.js';
|
|
35
36
|
/** Prefix all client routes live under (one webServer prefix registration). */
|
|
@@ -85,6 +86,12 @@ export const CLIENT_UNSHARE_ROUTE = `${CLIENT_ROUTE_PREFIX}/unshare`;
|
|
|
85
86
|
* means a readable signal says nothing is open; the sink stores the value
|
|
86
87
|
* and re-judges the mergers immediately. */
|
|
87
88
|
export const CLIENT_CURRENT_SESSION_ROUTE = `${CLIENT_ROUTE_PREFIX}/current-session`;
|
|
89
|
+
/** POST `{entryId?: string, all?: boolean}` (MS-5): remove one paired server
|
|
90
|
+
* by its entry id, or every paired server at once (`all: true`). The paired
|
|
91
|
+
* list lives in `zen-remote-state.json`; this route goes through the pool so
|
|
92
|
+
* the live clients stop with their records. Pool-mode only — a mount without
|
|
93
|
+
* a pool has no paired list to edit and answers the unknown-path 404. */
|
|
94
|
+
export const CLIENT_UNPAIR_ROUTE = `${CLIENT_ROUTE_PREFIX}/unpair`;
|
|
88
95
|
/** Longest `sessionId` the current-session route accepts (T62): real ids —
|
|
89
96
|
* a local `session-<uuid>` or a `zr~<serverId>~<id>` virtual id — are far
|
|
90
97
|
* shorter; the cap bounds garbage, not reality. */
|
|
@@ -321,28 +328,20 @@ function remoteStatusStateOf(relay) {
|
|
|
321
328
|
}
|
|
322
329
|
}
|
|
323
330
|
/**
|
|
324
|
-
* The
|
|
325
|
-
*
|
|
326
|
-
*
|
|
327
|
-
*
|
|
328
|
-
*
|
|
329
|
-
*
|
|
331
|
+
* The diagnostics decorator shared by the single-client and pool status
|
|
332
|
+
* bodies (CU-3's extraction, extended by MS-5): every interception getter is
|
|
333
|
+
* read live per call, and the compat verdict rides whenever there is
|
|
334
|
+
* something to report — from `compatRelay`'s last handshake (the single
|
|
335
|
+
* client, or in pool mode the FIRST entry's client) or from the interceptor's
|
|
336
|
+
* incompatible-call ring. `pluginBridgeOverride` replaces the single-client
|
|
337
|
+
* verdict source in pool mode (the first entry's per-server verdicts, keeping
|
|
338
|
+
* the top-level field's shape).
|
|
330
339
|
*/
|
|
331
|
-
|
|
332
|
-
const fetchImpl = options.fetchImpl ?? ((url, init) => fetch(url, init));
|
|
333
|
-
// The typert interception's view (T23b-1) rides on EVERY status
|
|
334
|
-
// answer, whatever the connection state — the settings surface needs
|
|
335
|
-
// it to explain a refused install even while unpaired. The interface
|
|
336
|
-
// compat verdict (T42) appears once there is something to report: a
|
|
337
|
-
// stored comparison from the relay client's last handshake, or any
|
|
338
|
-
// incompatible call the interceptor recorded. Absent otherwise —
|
|
339
|
-
// nothing to show, and the settings block presence-gates on exactly
|
|
340
|
-
// that.
|
|
340
|
+
function diagnosticsDecorator(options, compatRelay, pluginBridgeOverride) {
|
|
341
341
|
const intercept = options.getIntercept?.();
|
|
342
342
|
const fetchRouteIntercept = options.getFetchRouteIntercept?.();
|
|
343
343
|
const serviceProbe = options.getServiceProbe?.();
|
|
344
344
|
const pluginRouteIntercept = options.getPluginRouteIntercept?.();
|
|
345
|
-
const compatRelay = options.getRelayClient?.();
|
|
346
345
|
const compat = compatRelay?.compat !== undefined || (intercept?.incompatibleCalls.length ?? 0) > 0
|
|
347
346
|
? {
|
|
348
347
|
identical: compatRelay?.compat?.identical ?? [],
|
|
@@ -351,11 +350,11 @@ async function statusBodyOf(options) {
|
|
|
351
350
|
incompatibleCalls: intercept?.incompatibleCalls ?? [],
|
|
352
351
|
}
|
|
353
352
|
: undefined;
|
|
354
|
-
|
|
353
|
+
return (body) => {
|
|
355
354
|
// PB-2: the per-plugin bridge verdict rides EVERY status answer —
|
|
356
355
|
// the settings surface explains a not-bridged plugin whatever the
|
|
357
356
|
// connection state (unpaired reads all-offline, the honest verdict).
|
|
358
|
-
let next = { ...body, pluginBridge: options.getPluginBridgeStatus?.() ?? [] };
|
|
357
|
+
let next = { ...body, pluginBridge: pluginBridgeOverride ?? options.getPluginBridgeStatus?.() ?? [] };
|
|
359
358
|
if (intercept !== undefined)
|
|
360
359
|
next = { ...next, intercept };
|
|
361
360
|
if (fetchRouteIntercept !== undefined)
|
|
@@ -366,6 +365,81 @@ async function statusBodyOf(options) {
|
|
|
366
365
|
next = { ...next, pluginRouteIntercept };
|
|
367
366
|
return compat === undefined ? next : { ...next, compat };
|
|
368
367
|
};
|
|
368
|
+
}
|
|
369
|
+
/**
|
|
370
|
+
* One pool entry's per-server status row (MS-5): the live client facts and
|
|
371
|
+
* the entry's own identity — NEVER the token, which the route never even
|
|
372
|
+
* sees (it lives in the state file, behind the pool). `compat` appears only
|
|
373
|
+
* once that client has a handshake verdict to report; `pluginBridge` comes
|
|
374
|
+
* from the per-server verdict getter ([] unwired).
|
|
375
|
+
*/
|
|
376
|
+
function poolServerStatus(entry, options) {
|
|
377
|
+
const client = entry.client;
|
|
378
|
+
const body = {
|
|
379
|
+
entryId: entry.entryId,
|
|
380
|
+
serverId: entry.serverId,
|
|
381
|
+
serverUrl: entry.serverUrl,
|
|
382
|
+
serverName: entry.serverName ?? '',
|
|
383
|
+
displayName: entry.displayName,
|
|
384
|
+
state: client.state,
|
|
385
|
+
nextRetryAt: client.nextRetryAt ?? null,
|
|
386
|
+
...(client.lastError !== undefined ? { lastError: client.lastError } : {}),
|
|
387
|
+
...(client.compat !== undefined
|
|
388
|
+
? { compat: { identical: client.compat.identical, different: client.compat.different, unavailable: client.compat.unavailable } }
|
|
389
|
+
: {}),
|
|
390
|
+
pluginBridge: options.getPluginBridgeStatusForServer?.(entry.serverId, client) ?? [],
|
|
391
|
+
};
|
|
392
|
+
return body;
|
|
393
|
+
}
|
|
394
|
+
/**
|
|
395
|
+
* The POOL status body (MS-5): the paired list is the truth — the row's
|
|
396
|
+
* serverUrl/deviceToken are never consulted. The top level keeps the FIRST
|
|
397
|
+
* entry's compatibility fields (the old single-server page keeps rendering)
|
|
398
|
+
* and every entry reports as one `servers` row; `maxServers` names the cap.
|
|
399
|
+
* An empty pool answers `unpaired` — the honest "nothing paired".
|
|
400
|
+
*/
|
|
401
|
+
async function poolStatusBodyOf(options) {
|
|
402
|
+
const pool = options.pool;
|
|
403
|
+
const entries = pool.entries();
|
|
404
|
+
const first = entries[0];
|
|
405
|
+
const bridgeOverride = first !== undefined
|
|
406
|
+
? options.getPluginBridgeStatusForServer?.(first.serverId, first.client) ?? []
|
|
407
|
+
: [];
|
|
408
|
+
const withDiagnostics = diagnosticsDecorator(options, first?.client, bridgeOverride);
|
|
409
|
+
const servers = entries.map((entry) => poolServerStatus(entry, options));
|
|
410
|
+
if (first === undefined) {
|
|
411
|
+
return withDiagnostics({ state: 'unpaired', maxServers: MAX_PAIRED_SERVERS, servers });
|
|
412
|
+
}
|
|
413
|
+
const body = deviceStatusBody(first.client.state, { serverName: first.serverName ?? '', deviceName: first.client.handshakeInfo?.deviceName }, first.serverUrl, first.client.deviceNameSyncing);
|
|
414
|
+
if (first.client.nextRetryAt !== null && first.client.nextRetryAt !== undefined)
|
|
415
|
+
body.nextRetryAt = first.client.nextRetryAt;
|
|
416
|
+
if (first.client.lastError !== undefined)
|
|
417
|
+
body.lastError = first.client.lastError;
|
|
418
|
+
return withDiagnostics({ ...body, maxServers: MAX_PAIRED_SERVERS, servers });
|
|
419
|
+
}
|
|
420
|
+
/**
|
|
421
|
+
* The status route's body, computed exactly as the CLIENT_STATUS_ROUTE
|
|
422
|
+
* branch always has — extracted (CU-3) so the debug-report route can embed
|
|
423
|
+
* the same diagnostics aggregation without a second implementation. All
|
|
424
|
+
* reads are live per call: volatile row fields, the interception getters,
|
|
425
|
+
* the relay client's current state. May await one bounded probe or connect
|
|
426
|
+
* (never longer than the probe timeout). In pool mode the paired list is
|
|
427
|
+
* the truth instead ({@link poolStatusBodyOf}); the row is not consulted.
|
|
428
|
+
*/
|
|
429
|
+
async function statusBodyOf(options) {
|
|
430
|
+
const fetchImpl = options.fetchImpl ?? ((url, init) => fetch(url, init));
|
|
431
|
+
if (options.pool !== undefined)
|
|
432
|
+
return poolStatusBodyOf(options);
|
|
433
|
+
// The typert interception's view (T23b-1) rides on EVERY status
|
|
434
|
+
// answer, whatever the connection state — the settings surface needs
|
|
435
|
+
// it to explain a refused install even while unpaired. The interface
|
|
436
|
+
// compat verdict (T42) appears once there is something to report: a
|
|
437
|
+
// stored comparison from the relay client's last handshake, or any
|
|
438
|
+
// incompatible call the interceptor recorded. Absent otherwise —
|
|
439
|
+
// nothing to show, and the settings block presence-gates on exactly
|
|
440
|
+
// that.
|
|
441
|
+
const compatRelay = options.getRelayClient?.();
|
|
442
|
+
const withDiagnostics = diagnosticsDecorator(options, compatRelay);
|
|
369
443
|
// The ROW decides its own two shapes first, per request (both fields
|
|
370
444
|
// are volatile { get() } wrappers — only the row object apply()
|
|
371
445
|
// received is a live source): without both credentials nothing is
|
|
@@ -427,6 +501,11 @@ async function statusBodyOf(options) {
|
|
|
427
501
|
*/
|
|
428
502
|
export function createClientHandler(options) {
|
|
429
503
|
const fetchImpl = options.fetchImpl ?? ((url, init) => fetch(url, init));
|
|
504
|
+
const resolveLang = () => {
|
|
505
|
+
const value = typeof options.lang === 'function' ? options.lang() : options.lang;
|
|
506
|
+
return value === 'en' ? 'en' : 'zh';
|
|
507
|
+
};
|
|
508
|
+
const mismatchMessage = () => resolveLang() === 'en' ? 'This remote session belongs to another server' : '此远程会话属于其他主服务端';
|
|
430
509
|
return async (req, res) => {
|
|
431
510
|
// Wall 1: DSH's own admission, relaying its refusal verbatim.
|
|
432
511
|
const admission = options.admit(req);
|
|
@@ -449,7 +528,10 @@ export function createClientHandler(options) {
|
|
|
449
528
|
if (route === CLIENT_DEBUG_REPORT_ROUTE && req.headers['x-zen-remote-via'] !== undefined) {
|
|
450
529
|
responseJson(res, 403, {
|
|
451
530
|
ok: false,
|
|
452
|
-
error: {
|
|
531
|
+
error: {
|
|
532
|
+
code: 'via-gateway',
|
|
533
|
+
message: resolveLang() === 'en' ? 'Diagnostics report can only be exported on this machine' : '诊断报告只能在本机导出',
|
|
534
|
+
},
|
|
453
535
|
});
|
|
454
536
|
return;
|
|
455
537
|
}
|
|
@@ -480,6 +562,23 @@ export function createClientHandler(options) {
|
|
|
480
562
|
responseJson(res, 400, { ok: false, code: normalized.reason });
|
|
481
563
|
return;
|
|
482
564
|
}
|
|
565
|
+
// MS-5 pool mode: the 8-server cap is judged BEFORE the pairing
|
|
566
|
+
// round-trip — a refusal the user can fix locally (remove a server,
|
|
567
|
+
// or re-enter an already-paired address) must not spend a claim code
|
|
568
|
+
// on the wire. An address that is ALREADY paired is always allowed
|
|
569
|
+
// through: re-pairing it just refreshes the token in place, at 8/8
|
|
570
|
+
// too. The pool stays the single writer afterwards: the gateway's
|
|
571
|
+
// token goes straight into `zen-remote-state.json` and NEVER reaches
|
|
572
|
+
// the browser — this response carries only the entry id and the
|
|
573
|
+
// address echo.
|
|
574
|
+
const pool = options.pool;
|
|
575
|
+
if (pool !== undefined) {
|
|
576
|
+
const known = pool.entries().some((entry) => entry.serverUrl === normalized.url);
|
|
577
|
+
if (!known && pool.entries().length >= MAX_PAIRED_SERVERS) {
|
|
578
|
+
responseJson(res, 409, { ok: false, code: 'limit-reached' });
|
|
579
|
+
return;
|
|
580
|
+
}
|
|
581
|
+
}
|
|
483
582
|
const payload = JSON.stringify({
|
|
484
583
|
code: stringOrEmpty(body.code),
|
|
485
584
|
name: stringOrEmpty(body.name),
|
|
@@ -516,7 +615,68 @@ export function createClientHandler(options) {
|
|
|
516
615
|
responseJson(res, 502, { ok: false, code: 'unreachable' });
|
|
517
616
|
return;
|
|
518
617
|
}
|
|
519
|
-
|
|
618
|
+
const outcome = classifyClaimResponse(status, gatewayBody);
|
|
619
|
+
if (pool === undefined || !outcome.ok) {
|
|
620
|
+
respondClaim(res, outcome, normalized.url);
|
|
621
|
+
return;
|
|
622
|
+
}
|
|
623
|
+
// Pool mode, redemption succeeded: land the pairing in the state
|
|
624
|
+
// file through the pool (which also starts/refreshes the live
|
|
625
|
+
// client) and answer without the token. The pair() can only refuse
|
|
626
|
+
// past the pre-check on a concurrent writer — the same envelopes.
|
|
627
|
+
const paired = await pool.pair({
|
|
628
|
+
serverUrl: normalized.url,
|
|
629
|
+
token: outcome.token,
|
|
630
|
+
deviceId: outcome.deviceId,
|
|
631
|
+
deviceName: outcome.deviceName,
|
|
632
|
+
});
|
|
633
|
+
if (!paired.ok) {
|
|
634
|
+
responseJson(res, paired.code === 'limit-reached' ? 409 : 400, { ok: false, code: paired.code });
|
|
635
|
+
return;
|
|
636
|
+
}
|
|
637
|
+
responseJson(res, 200, {
|
|
638
|
+
ok: true,
|
|
639
|
+
entryId: paired.entry.entryId,
|
|
640
|
+
deviceId: outcome.deviceId,
|
|
641
|
+
deviceName: outcome.deviceName,
|
|
642
|
+
serverUrl: normalized.url,
|
|
643
|
+
});
|
|
644
|
+
return;
|
|
645
|
+
}
|
|
646
|
+
if (route === CLIENT_UNPAIR_ROUTE) {
|
|
647
|
+
// MS-5: remove one paired server or all of them. Pool-mode only —
|
|
648
|
+
// a mount without a pool has no paired list to edit (the old
|
|
649
|
+
// single-server pairing lived in the ROW, which the browser writes
|
|
650
|
+
// directly), and answers the same 404 an unknown path would.
|
|
651
|
+
const pool = options.pool;
|
|
652
|
+
if (pool === undefined) {
|
|
653
|
+
responseJson(res, 404, { ok: false, error: { code: 'not-found', message: 'Unknown client route' } });
|
|
654
|
+
return;
|
|
655
|
+
}
|
|
656
|
+
if (method !== 'POST') {
|
|
657
|
+
res.setHeader('Allow', 'POST');
|
|
658
|
+
responseJson(res, 405, { ok: false, error: { code: 'method-not-allowed', message: 'Use POST' } });
|
|
659
|
+
return;
|
|
660
|
+
}
|
|
661
|
+
if (!sameOriginPost(req)) {
|
|
662
|
+
responseJson(res, 403, {
|
|
663
|
+
ok: false,
|
|
664
|
+
error: { code: 'origin-rejected', message: 'The request must originate from this DSH Web application' },
|
|
665
|
+
});
|
|
666
|
+
return;
|
|
667
|
+
}
|
|
668
|
+
const body = await readJsonBody(req);
|
|
669
|
+
if (body.all === true) {
|
|
670
|
+
const removed = pool.unpairAll();
|
|
671
|
+
responseJson(res, 200, { ok: true, removed });
|
|
672
|
+
return;
|
|
673
|
+
}
|
|
674
|
+
if (typeof body.entryId === 'string' && body.entryId !== '') {
|
|
675
|
+
const removed = pool.unpair(body.entryId);
|
|
676
|
+
responseJson(res, 200, { ok: true, removed: removed ? 1 : 0 });
|
|
677
|
+
return;
|
|
678
|
+
}
|
|
679
|
+
responseJson(res, 400, { ok: false, error: { code: 'bad-request', message: 'entryId (non-empty string) or all (true) is required' } });
|
|
520
680
|
return;
|
|
521
681
|
}
|
|
522
682
|
if (route === CLIENT_STATUS_ROUTE) {
|
|
@@ -574,6 +734,8 @@ export function createClientHandler(options) {
|
|
|
574
734
|
pushSummary: values.pushSummary,
|
|
575
735
|
pushTurnEnd: values.pushTurnEnd,
|
|
576
736
|
pushTool: values.pushTool,
|
|
737
|
+
pushEnabled: values.pushEnabled,
|
|
738
|
+
pushSessionName: values.pushSessionName,
|
|
577
739
|
serverUrl: stringOrEmpty(unwrapVolatile(record.serverUrl)).trim(),
|
|
578
740
|
},
|
|
579
741
|
statusBody: await statusBodyOf(options),
|
|
@@ -598,6 +760,31 @@ export function createClientHandler(options) {
|
|
|
598
760
|
return;
|
|
599
761
|
}
|
|
600
762
|
const relay = options.getRelayClient?.();
|
|
763
|
+
// MS-5 pool mode: an optional { entryId } names ONE server — the
|
|
764
|
+
// same offline-only, 409-on-conflict contract the single client's
|
|
765
|
+
// button has, per entry; without it every OFFLINE server gets one
|
|
766
|
+
// attempt (an online server is not "reconnected", it is fine).
|
|
767
|
+
const pool = options.pool;
|
|
768
|
+
if (pool !== undefined) {
|
|
769
|
+
const body = await readJsonBody(req);
|
|
770
|
+
const entryId = typeof body.entryId === 'string' && body.entryId !== '' ? body.entryId : undefined;
|
|
771
|
+
if (entryId === undefined) {
|
|
772
|
+
const started = await pool.reconnect();
|
|
773
|
+
responseJson(res, 200, { ok: true, started });
|
|
774
|
+
return;
|
|
775
|
+
}
|
|
776
|
+
const entry = pool.getByEntryId(entryId);
|
|
777
|
+
if (entry === undefined) {
|
|
778
|
+
responseJson(res, 404, { ok: false, error: { code: 'not-found', message: 'No such paired server' } });
|
|
779
|
+
return;
|
|
780
|
+
}
|
|
781
|
+
if (entry.client.state !== 'offline' || !entry.client.reconnect()) {
|
|
782
|
+
responseJson(res, 409, { ok: false, error: { code: 'not-offline', message: 'The client is not offline' } });
|
|
783
|
+
return;
|
|
784
|
+
}
|
|
785
|
+
responseJson(res, 200, { ok: true });
|
|
786
|
+
return;
|
|
787
|
+
}
|
|
601
788
|
// No relay client (a composition that never built one): there is
|
|
602
789
|
// nothing to reconnect, and the probe-shaped status route is the
|
|
603
790
|
// only connection surface this deployment has.
|
|
@@ -631,6 +818,16 @@ export function createClientHandler(options) {
|
|
|
631
818
|
return;
|
|
632
819
|
}
|
|
633
820
|
const relay = options.getRelayClient?.();
|
|
821
|
+
// MS-5 pool mode: the same QUESTION per server — one authenticated
|
|
822
|
+
// ping sweep over the offline clients, the reachable ones get the
|
|
823
|
+
// controlled `networkRestored()` (probe-first, no storm, offline
|
|
824
|
+
// only — the pool method enforces the same rules per client).
|
|
825
|
+
const pool = options.pool;
|
|
826
|
+
if (pool !== undefined) {
|
|
827
|
+
const outcome = await pool.probeAndRestoreAll();
|
|
828
|
+
responseJson(res, 200, { ok: true, reachable: outcome.reachable, reconnected: outcome.reconnected });
|
|
829
|
+
return;
|
|
830
|
+
}
|
|
634
831
|
if (relay === undefined) {
|
|
635
832
|
responseJson(res, 503, { ok: false, error: { code: 'unavailable', message: 'No relay client is running' } });
|
|
636
833
|
return;
|
|
@@ -664,8 +861,41 @@ export function createClientHandler(options) {
|
|
|
664
861
|
// sort is pinned here so the field's shape never depends on the
|
|
665
862
|
// registry's internal order). The host mount — no verdict source —
|
|
666
863
|
// answers [].
|
|
667
|
-
|
|
864
|
+
// MS-5 pool mode: the SAME shape per server, under `servers` keyed
|
|
865
|
+
// by the handshake serverId (an entry that never handshook owns no
|
|
866
|
+
// virtual ids and is not addressable — skipped). The top level
|
|
867
|
+
// mirrors the FIRST entry so the old page keeps rendering.
|
|
868
|
+
const pool = options.pool;
|
|
668
869
|
const intercept = options.getIntercept?.();
|
|
870
|
+
const bridgedOf = (serverId, client) => (options.getPluginBridgeStatusForServer?.(serverId, client) ?? [])
|
|
871
|
+
.filter((status) => status.bridged)
|
|
872
|
+
.map((status) => status.plugin)
|
|
873
|
+
.sort();
|
|
874
|
+
if (pool !== undefined) {
|
|
875
|
+
const entries = pool.entries();
|
|
876
|
+
const first = entries[0];
|
|
877
|
+
const servers = {};
|
|
878
|
+
for (const entry of entries) {
|
|
879
|
+
if (entry.serverId === undefined)
|
|
880
|
+
continue;
|
|
881
|
+
servers[entry.serverId] = {
|
|
882
|
+
state: remoteStatusStateOf(entry.client),
|
|
883
|
+
versionMismatch: (entry.client.compat?.different?.length ?? 0) > 0,
|
|
884
|
+
serverName: entry.serverName ?? '',
|
|
885
|
+
bridgedPlugins: bridgedOf(entry.serverId, entry.client),
|
|
886
|
+
};
|
|
887
|
+
}
|
|
888
|
+
responseJson(res, 200, {
|
|
889
|
+
state: remoteStatusStateOf(first?.client),
|
|
890
|
+
versionMismatch: (first?.client.compat?.different?.length ?? 0) > 0,
|
|
891
|
+
serverName: first?.serverName ?? '',
|
|
892
|
+
closed: Object.fromEntries((intercept?.closedSessions ?? []).map((record) => [record.sessionId, record.reason])),
|
|
893
|
+
bridgedPlugins: first !== undefined ? bridgedOf(first.serverId, first.client) : [],
|
|
894
|
+
servers,
|
|
895
|
+
});
|
|
896
|
+
return;
|
|
897
|
+
}
|
|
898
|
+
const relay = options.getRelayClient?.();
|
|
669
899
|
responseJson(res, 200, {
|
|
670
900
|
state: remoteStatusStateOf(relay),
|
|
671
901
|
versionMismatch: (relay?.compat?.different?.length ?? 0) > 0,
|
|
@@ -709,7 +939,8 @@ export function createClientHandler(options) {
|
|
|
709
939
|
return;
|
|
710
940
|
}
|
|
711
941
|
const read = raw === null ? { kind: 'none' } : { kind: 'open', sessionId: raw };
|
|
712
|
-
|
|
942
|
+
const reportedLang = body.lang === 'en' ? 'en' : body.lang === 'zh' ? 'zh' : undefined;
|
|
943
|
+
sink(read, reportedLang);
|
|
713
944
|
responseJson(res, 200, { ok: true });
|
|
714
945
|
return;
|
|
715
946
|
}
|
|
@@ -734,6 +965,26 @@ export function createClientHandler(options) {
|
|
|
734
965
|
responseJson(res, 400, { ok: false, error: { code: 'not-virtual', message: 'sessionId must be a remote (virtual) session id' } });
|
|
735
966
|
return;
|
|
736
967
|
}
|
|
968
|
+
// MS-5 pool mode: the id's serverId half names the server — its own
|
|
969
|
+
// client closes the session with the ORIGINAL id. A server the pool
|
|
970
|
+
// does not hold is the same remote-mismatch the interceptor answers.
|
|
971
|
+
const pool = options.pool;
|
|
972
|
+
if (pool !== undefined) {
|
|
973
|
+
const entry = pool.getByServerId(parts.serverId);
|
|
974
|
+
if (entry === undefined) {
|
|
975
|
+
responseJson(res, 200, { ok: false, error: { code: 'remote-mismatch', message: mismatchMessage() } });
|
|
976
|
+
return;
|
|
977
|
+
}
|
|
978
|
+
try {
|
|
979
|
+
await entry.client.unshare(parts.id);
|
|
980
|
+
responseJson(res, 200, { ok: true });
|
|
981
|
+
}
|
|
982
|
+
catch (error) {
|
|
983
|
+
const code = error instanceof RelayError ? error.code : 'internal';
|
|
984
|
+
responseJson(res, 200, { ok: false, error: { code, message: error instanceof Error ? error.message : String(error) } });
|
|
985
|
+
}
|
|
986
|
+
return;
|
|
987
|
+
}
|
|
737
988
|
const relay = options.getRelayClient?.();
|
|
738
989
|
if (relay === undefined) {
|
|
739
990
|
responseJson(res, 503, { ok: false, error: { code: 'unavailable', message: 'No relay client is running' } });
|
|
@@ -743,7 +994,7 @@ export function createClientHandler(options) {
|
|
|
743
994
|
// just answer not-shared out there — the mismatch is answerable
|
|
744
995
|
// locally, with the code the interceptor uses for the same fact.
|
|
745
996
|
if (relay.handshakeInfo === undefined || relay.handshakeInfo.serverId !== parts.serverId) {
|
|
746
|
-
responseJson(res, 200, { ok: false, error: { code: 'remote-mismatch', message:
|
|
997
|
+
responseJson(res, 200, { ok: false, error: { code: 'remote-mismatch', message: mismatchMessage() } });
|
|
747
998
|
return;
|
|
748
999
|
}
|
|
749
1000
|
try {
|
|
@@ -791,13 +1042,45 @@ export function createClientHandler(options) {
|
|
|
791
1042
|
responseJson(res, 400, { ok: false, error: { code: 'not-virtual', message: 'sessionId is not a remote session id' } });
|
|
792
1043
|
return;
|
|
793
1044
|
}
|
|
1045
|
+
// MS-5 pool mode: route by the id's serverId half. A server the pool
|
|
1046
|
+
// does not hold refuses like a foreign one; its client must be the
|
|
1047
|
+
// ONLINE one before the query travels with the original id restored.
|
|
1048
|
+
const pool = options.pool;
|
|
1049
|
+
if (pool !== undefined) {
|
|
1050
|
+
const entry = pool.getByServerId(parts.serverId);
|
|
1051
|
+
if (entry === undefined) {
|
|
1052
|
+
responseJson(res, 400, { ok: false, error: { code: 'remote-mismatch', message: mismatchMessage() } });
|
|
1053
|
+
return;
|
|
1054
|
+
}
|
|
1055
|
+
if (entry.client.state !== 'online') {
|
|
1056
|
+
responseJson(res, 503, { ok: false, error: { code: 'remote-offline' } });
|
|
1057
|
+
return;
|
|
1058
|
+
}
|
|
1059
|
+
url.searchParams.set('sessionId', parts.id);
|
|
1060
|
+
// A browser walk-off cancels the round-trip mid-flight; the write
|
|
1061
|
+
// guard in the catch keeps a settled answer from racing the close.
|
|
1062
|
+
const hangUp = new AbortController();
|
|
1063
|
+
res.once('close', () => {
|
|
1064
|
+
if (!res.writableEnded)
|
|
1065
|
+
hangUp.abort();
|
|
1066
|
+
});
|
|
1067
|
+
try {
|
|
1068
|
+
const result = await entry.client.http(httpRoute, url.searchParams.toString(), hangUp.signal);
|
|
1069
|
+
respondUpstream(res, result);
|
|
1070
|
+
}
|
|
1071
|
+
catch (error) {
|
|
1072
|
+
if (!res.writableEnded && !res.destroyed)
|
|
1073
|
+
respondRelayFailure(res, error);
|
|
1074
|
+
}
|
|
1075
|
+
return;
|
|
1076
|
+
}
|
|
794
1077
|
const relay = options.getRelayClient?.();
|
|
795
1078
|
if (relay === undefined || relay.state !== 'online') {
|
|
796
1079
|
responseJson(res, 503, { ok: false, error: { code: 'remote-offline' } });
|
|
797
1080
|
return;
|
|
798
1081
|
}
|
|
799
1082
|
if (relay.handshakeInfo?.serverId !== parts.serverId) {
|
|
800
|
-
responseJson(res, 400, { ok: false, error: { code: 'remote-mismatch', message:
|
|
1083
|
+
responseJson(res, 400, { ok: false, error: { code: 'remote-mismatch', message: mismatchMessage() } });
|
|
801
1084
|
return;
|
|
802
1085
|
}
|
|
803
1086
|
url.searchParams.set('sessionId', parts.id);
|