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
|
@@ -327,11 +327,51 @@ export function installPluginRouteIntercept(options) {
|
|
|
327
327
|
},
|
|
328
328
|
};
|
|
329
329
|
}
|
|
330
|
-
const { webServer, registry,
|
|
330
|
+
const { webServer, registry, log } = options;
|
|
331
331
|
const adapters = options.adapters ?? [];
|
|
332
332
|
const getCurrentSession = options.getCurrentSession;
|
|
333
333
|
const getKnownRealIds = options.getKnownRealIds;
|
|
334
334
|
const onMintedVirtualIds = options.onMintedVirtualIds;
|
|
335
|
+
const { relay, getServerId, getStatus } = options;
|
|
336
|
+
const { getRelayForServer, getStatusForServer, getKnownRealIdsForServer } = options;
|
|
337
|
+
// Exactly one mode, like installIntercept: the pool faces or the single
|
|
338
|
+
// row client — a wiring that passes neither would refuse every forwarded
|
|
339
|
+
// request as server-changed / not-bridged, so it is refused here instead.
|
|
340
|
+
if ((getRelayForServer === undefined && (relay === undefined || getServerId === undefined))
|
|
341
|
+
|| (getStatusForServer === undefined && getStatus === undefined)) {
|
|
342
|
+
throw new Error('installPluginRouteIntercept requires either `relay` + `getServerId` + `getStatus` (single server) or `getRelayForServer` + `getStatusForServer` (pool)');
|
|
343
|
+
}
|
|
344
|
+
// The single-server facts, proven present by the guard above.
|
|
345
|
+
const singleRelay = relay;
|
|
346
|
+
const singleGetServerId = getServerId;
|
|
347
|
+
const singleGetStatus = getStatus;
|
|
348
|
+
/** MS-4: the relay client serving one server id, or `undefined` (the
|
|
349
|
+
* `server-changed` refusal). */
|
|
350
|
+
const relayOfServer = (serverId) => getRelayForServer !== undefined ? getRelayForServer(serverId) : serverId === singleGetServerId() ? singleRelay : undefined;
|
|
351
|
+
const statusesOfServer = (serverId) => getStatusForServer !== undefined ? getStatusForServer(serverId) : singleGetStatus();
|
|
352
|
+
const knownRealIdsOfServer = (serverId) => getKnownRealIdsForServer !== undefined ? getKnownRealIdsForServer(serverId) : getKnownRealIds?.();
|
|
353
|
+
/** MS-4: the one server every located virtual id of a request belongs to,
|
|
354
|
+
* with its relay client — or the refusal reason, judged id by id in hit
|
|
355
|
+
* order (the single-server walls' order). A request naming ids of two
|
|
356
|
+
* servers is refused like a foreign one: it has no single home. */
|
|
357
|
+
const serverOfHits = (hits) => {
|
|
358
|
+
let located;
|
|
359
|
+
for (const idHit of hits) {
|
|
360
|
+
const parts = fromVirtual(idHit.value);
|
|
361
|
+
if (parts === undefined || parts.id === '')
|
|
362
|
+
return 'bad-query';
|
|
363
|
+
if (located === undefined) {
|
|
364
|
+
const target = relayOfServer(parts.serverId);
|
|
365
|
+
if (target === undefined)
|
|
366
|
+
return 'server-changed';
|
|
367
|
+
located = { serverId: parts.serverId, relay: target };
|
|
368
|
+
}
|
|
369
|
+
else if (parts.serverId !== located.serverId) {
|
|
370
|
+
return 'server-changed';
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
return located ?? 'bad-query';
|
|
374
|
+
};
|
|
335
375
|
const target = webServer;
|
|
336
376
|
const savedMatch = target.match;
|
|
337
377
|
let installed = true;
|
|
@@ -496,7 +536,8 @@ export function installPluginRouteIntercept(options) {
|
|
|
496
536
|
answerUnbridged(res, declared.plugin, 'bad-query');
|
|
497
537
|
return;
|
|
498
538
|
}
|
|
499
|
-
|
|
539
|
+
const targetRelay = relayOfServer(parts.serverId);
|
|
540
|
+
if (targetRelay === undefined) {
|
|
500
541
|
answerUnbridged(res, declared.plugin, 'server-changed');
|
|
501
542
|
return;
|
|
502
543
|
}
|
|
@@ -522,7 +563,7 @@ export function installPluginRouteIntercept(options) {
|
|
|
522
563
|
log?.('plugin request for %s refused locally: body-too-large (%s declared)', declared.path, req.headers['content-length']);
|
|
523
564
|
return;
|
|
524
565
|
}
|
|
525
|
-
const status =
|
|
566
|
+
const status = statusesOfServer(parts.serverId).find((entry) => entry.plugin === declared.plugin);
|
|
526
567
|
if (status === undefined || !status.bridged) {
|
|
527
568
|
answerUnbridged(res, declared.plugin, status?.reason ?? 'not-on-server');
|
|
528
569
|
return;
|
|
@@ -594,7 +635,7 @@ export function installPluginRouteIntercept(options) {
|
|
|
594
635
|
bodyStream = Readable.toWeb(gate);
|
|
595
636
|
req.pipe(gate);
|
|
596
637
|
}
|
|
597
|
-
const response = await
|
|
638
|
+
const response = await targetRelay.pluginRequest({
|
|
598
639
|
plugin: declared.plugin,
|
|
599
640
|
version: declared.version,
|
|
600
641
|
digest: declared.digest,
|
|
@@ -628,7 +669,7 @@ export function installPluginRouteIntercept(options) {
|
|
|
628
669
|
// known inventory, read live right here (undefined when the wiring
|
|
629
670
|
// passed no getter — the scan stays request-local).
|
|
630
671
|
if (declared.rewriteIds) {
|
|
631
|
-
await answerRewriteIds(res, response, idMapping, declared.rewriteFields, parts.serverId,
|
|
672
|
+
await answerRewriteIds(res, response, idMapping, declared.rewriteFields, parts.serverId, knownRealIdsOfServer(parts.serverId), onMintedVirtualIds);
|
|
632
673
|
return;
|
|
633
674
|
}
|
|
634
675
|
const contentType = response.headers.get('content-type');
|
|
@@ -827,7 +868,6 @@ export function installPluginRouteIntercept(options) {
|
|
|
827
868
|
answerUnbridged(res, plugin, 'method-not-bridged');
|
|
828
869
|
return;
|
|
829
870
|
}
|
|
830
|
-
const serverId = getServerId();
|
|
831
871
|
// PB-22: the request's own real→virtual pairs, collected while the
|
|
832
872
|
// wall validates each hit — the READ-ONLY mapping a rewriteIds
|
|
833
873
|
// route's answer scan consults (`zr~` carries the real id inside, so
|
|
@@ -839,24 +879,20 @@ export function installPluginRouteIntercept(options) {
|
|
|
839
879
|
// ONE more source beside this mapping — the known-real-session
|
|
840
880
|
// inventory, read live at the answer (never copied here) and
|
|
841
881
|
// consumed read-only; nothing here writes any session table.
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
return;
|
|
849
|
-
}
|
|
850
|
-
if (parts.serverId !== serverId) {
|
|
851
|
-
answerUnbridged(res, plugin, 'server-changed');
|
|
852
|
-
return;
|
|
853
|
-
}
|
|
854
|
-
idMapping.set(parts.id, idHit.value);
|
|
855
|
-
locatedServerId = parts.serverId;
|
|
882
|
+
// MS-4: every located id must name ONE server the wiring serves;
|
|
883
|
+
// that server's relay, verdicts and inventory carry the rest.
|
|
884
|
+
const home = serverOfHits(verdict.hits);
|
|
885
|
+
if (home === 'bad-query' || home === 'server-changed') {
|
|
886
|
+
answerUnbridged(res, plugin, home);
|
|
887
|
+
return;
|
|
856
888
|
}
|
|
889
|
+
const locatedServerId = home.serverId;
|
|
890
|
+
const idMapping = new Map();
|
|
891
|
+
for (const idHit of verdict.hits)
|
|
892
|
+
idMapping.set(fromVirtual(idHit.value).id, idHit.value);
|
|
857
893
|
// The bridge verdicts judged from the SAME live table the query
|
|
858
894
|
// half reads.
|
|
859
|
-
const status =
|
|
895
|
+
const status = statusesOfServer(locatedServerId).find((entry) => entry.plugin === plugin);
|
|
860
896
|
if (status === undefined || !status.bridged) {
|
|
861
897
|
answerUnbridged(res, plugin, status?.reason ?? 'not-on-server');
|
|
862
898
|
return;
|
|
@@ -919,7 +955,7 @@ export function installPluginRouteIntercept(options) {
|
|
|
919
955
|
if (Number.isFinite(declaredLength) && declaredLength > 0)
|
|
920
956
|
contentLength = declaredLength;
|
|
921
957
|
}
|
|
922
|
-
const response = await relay.pluginRequest({
|
|
958
|
+
const response = await home.relay.pluginRequest({
|
|
923
959
|
plugin,
|
|
924
960
|
version: declared.version,
|
|
925
961
|
digest: declared.digest,
|
|
@@ -942,7 +978,7 @@ export function installPluginRouteIntercept(options) {
|
|
|
942
978
|
return;
|
|
943
979
|
}
|
|
944
980
|
if (declared.rewriteIds) {
|
|
945
|
-
await answerRewriteIds(res, response, idMapping, declared.rewriteFields, locatedServerId,
|
|
981
|
+
await answerRewriteIds(res, response, idMapping, declared.rewriteFields, locatedServerId, knownRealIdsOfServer(locatedServerId), onMintedVirtualIds);
|
|
946
982
|
return;
|
|
947
983
|
}
|
|
948
984
|
const contentType = response.headers.get('content-type');
|
|
@@ -1143,23 +1179,18 @@ export function installPluginRouteIntercept(options) {
|
|
|
1143
1179
|
answerUnbridged(res, plugin, 'method-not-bridged');
|
|
1144
1180
|
return;
|
|
1145
1181
|
}
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
return;
|
|
1152
|
-
}
|
|
1153
|
-
if (parts.serverId !== serverId) {
|
|
1154
|
-
answerUnbridged(res, plugin, 'server-changed');
|
|
1155
|
-
return;
|
|
1156
|
-
}
|
|
1182
|
+
// MS-4: one home server for every located id.
|
|
1183
|
+
const home = serverOfHits(verdict.hits);
|
|
1184
|
+
if (home === 'bad-query' || home === 'server-changed') {
|
|
1185
|
+
answerUnbridged(res, plugin, home);
|
|
1186
|
+
return;
|
|
1157
1187
|
}
|
|
1188
|
+
const serverId = home.serverId;
|
|
1158
1189
|
// The bridge verdicts (version skew, consent, offline…) judged from
|
|
1159
1190
|
// the SAME live table the cooperative surrogate reads — the
|
|
1160
1191
|
// adapter's registry entry makes the plugin indistinguishable from
|
|
1161
1192
|
// a cooperative one here.
|
|
1162
|
-
const status =
|
|
1193
|
+
const status = statusesOfServer(serverId).find((entry) => entry.plugin === plugin);
|
|
1163
1194
|
if (status === undefined || !status.bridged) {
|
|
1164
1195
|
answerUnbridged(res, plugin, status?.reason ?? 'not-on-server');
|
|
1165
1196
|
return;
|
|
@@ -1218,7 +1249,7 @@ export function installPluginRouteIntercept(options) {
|
|
|
1218
1249
|
bodyStream = Readable.toWeb(gate);
|
|
1219
1250
|
req.pipe(gate);
|
|
1220
1251
|
}
|
|
1221
|
-
const response = await relay.pluginRequest({
|
|
1252
|
+
const response = await home.relay.pluginRequest({
|
|
1222
1253
|
plugin,
|
|
1223
1254
|
version: adapter.declaration.version,
|
|
1224
1255
|
digest: adapter.digest,
|
|
@@ -1322,7 +1353,7 @@ export function installPluginRouteIntercept(options) {
|
|
|
1322
1353
|
pathname,
|
|
1323
1354
|
body: JSON.parse(text),
|
|
1324
1355
|
virtualize: (id) => {
|
|
1325
|
-
const virtualId = toVirtual(serverId
|
|
1356
|
+
const virtualId = toVirtual(serverId, id);
|
|
1326
1357
|
if (isVirtual(virtualId))
|
|
1327
1358
|
minted.add(virtualId);
|
|
1328
1359
|
return virtualId;
|
|
@@ -1571,6 +1602,9 @@ export function installPluginRouteIntercept(options) {
|
|
|
1571
1602
|
};
|
|
1572
1603
|
// ---- the remote pipe: the PB-10 tunnel, frame by frame -------------
|
|
1573
1604
|
let tunnelHandle;
|
|
1605
|
+
// MS-4: the server the tunnel was opened on — set together with
|
|
1606
|
+
// tunnelHandle, the relay every later send and the close travel.
|
|
1607
|
+
let tunnelServer;
|
|
1574
1608
|
// The connection-wide real→virtual mapping the rewriteIds deep scan
|
|
1575
1609
|
// consults: EVERY validated remote frame's ids merge in (a watch list
|
|
1576
1610
|
// that grows mid-connection makes the later answers rewritable too —
|
|
@@ -1591,7 +1625,7 @@ export function installPluginRouteIntercept(options) {
|
|
|
1591
1625
|
* never a silent broken flag: that would leak `tunnelsCurrent` and
|
|
1592
1626
|
* leave the browser hanging on a dead tunnel. */
|
|
1593
1627
|
const sendTextUpstream = async (frame, parsedJson, hits) => {
|
|
1594
|
-
if (upstreamBroken || tunnelHandle === undefined)
|
|
1628
|
+
if (upstreamBroken || tunnelHandle === undefined || tunnelServer === undefined)
|
|
1595
1629
|
return;
|
|
1596
1630
|
const rewrite = hits.length > 0
|
|
1597
1631
|
? rewriteAdapterRequest(declared.view, declared.path, new URLSearchParams(), parsedJson, hits, (virtualId) => fromVirtual(virtualId).id)
|
|
@@ -1600,7 +1634,7 @@ export function installPluginRouteIntercept(options) {
|
|
|
1600
1634
|
const seq = upstreamSeq;
|
|
1601
1635
|
upstreamSeq += 1;
|
|
1602
1636
|
try {
|
|
1603
|
-
await relay.pluginTunnelSend(tunnelHandle.tunnel, seq, encodeRfc6455Frame(0x1, payload, true, frame.fin));
|
|
1637
|
+
await tunnelServer.relay.pluginTunnelSend(tunnelHandle.tunnel, seq, encodeRfc6455Frame(0x1, payload, true, frame.fin));
|
|
1604
1638
|
}
|
|
1605
1639
|
catch {
|
|
1606
1640
|
killExchange();
|
|
@@ -1652,7 +1686,7 @@ export function installPluginRouteIntercept(options) {
|
|
|
1652
1686
|
hooked = true;
|
|
1653
1687
|
}
|
|
1654
1688
|
else if (declared.rewriteIds) {
|
|
1655
|
-
const scanned = deepRewriteIds(parsedJson, idMapping,
|
|
1689
|
+
const scanned = deepRewriteIds(parsedJson, idMapping, knownRealIdsOfServer(serverId), serverId);
|
|
1656
1690
|
if (declared.rewriteFields !== undefined)
|
|
1657
1691
|
rewriteIdsAtFields(scanned, declared.rewriteFields, serverId);
|
|
1658
1692
|
outPayload = Buffer.from(JSON.stringify(scanned), 'utf8');
|
|
@@ -1761,25 +1795,19 @@ export function installPluginRouteIntercept(options) {
|
|
|
1761
1795
|
}
|
|
1762
1796
|
return;
|
|
1763
1797
|
}
|
|
1764
|
-
|
|
1765
|
-
|
|
1798
|
+
// MS-4: the frame's ids name one served server, and once the tunnel
|
|
1799
|
+
// is open every later frame must name the tunnel's own server.
|
|
1800
|
+
const home = serverOfHits(verdict.hits);
|
|
1801
|
+
if (home === 'bad-query' || home === 'server-changed' || (tunnelServer !== undefined && home.serverId !== tunnelServer.serverId)) {
|
|
1766
1802
|
refuseAndDie('server-changed');
|
|
1767
1803
|
return;
|
|
1768
1804
|
}
|
|
1769
|
-
const
|
|
1770
|
-
for (const idHit of verdict.hits) {
|
|
1771
|
-
const parts = fromVirtual(idHit.value);
|
|
1772
|
-
if (parts === undefined || parts.id === '' || parts.serverId !== serverId) {
|
|
1773
|
-
refuseAndDie('server-changed');
|
|
1774
|
-
return;
|
|
1775
|
-
}
|
|
1776
|
-
mapping.set(parts.id, idHit.value);
|
|
1777
|
-
}
|
|
1805
|
+
const serverId = home.serverId;
|
|
1778
1806
|
// This frame's ids join the connection-wide mapping (see idMapping).
|
|
1779
|
-
for (const
|
|
1780
|
-
idMapping.set(
|
|
1807
|
+
for (const idHit of verdict.hits)
|
|
1808
|
+
idMapping.set(fromVirtual(idHit.value).id, idHit.value);
|
|
1781
1809
|
if (tunnelHandle === undefined) {
|
|
1782
|
-
const status =
|
|
1810
|
+
const status = statusesOfServer(serverId).find((entry) => entry.plugin === plugin);
|
|
1783
1811
|
if (status === undefined || !status.bridged) {
|
|
1784
1812
|
refuseAndDie(status?.reason ?? 'not-on-server');
|
|
1785
1813
|
return;
|
|
@@ -1789,7 +1817,7 @@ export function installPluginRouteIntercept(options) {
|
|
|
1789
1817
|
let opened;
|
|
1790
1818
|
try {
|
|
1791
1819
|
log?.('opening tunnel for %s', declared.path);
|
|
1792
|
-
opened = await relay.pluginTunnelOpen({
|
|
1820
|
+
opened = await home.relay.pluginTunnelOpen({
|
|
1793
1821
|
plugin,
|
|
1794
1822
|
version: declared.version,
|
|
1795
1823
|
digest: declared.digest,
|
|
@@ -1805,6 +1833,7 @@ export function installPluginRouteIntercept(options) {
|
|
|
1805
1833
|
}
|
|
1806
1834
|
tunnelsCurrent += 1;
|
|
1807
1835
|
tunnelsOpened += 1;
|
|
1836
|
+
tunnelServer = home;
|
|
1808
1837
|
tunnelHandle = opened;
|
|
1809
1838
|
log?.('tunnel open for %s: %s', declared.path, opened.tunnel);
|
|
1810
1839
|
teardownTunnel = () => {
|
|
@@ -1813,7 +1842,7 @@ export function installPluginRouteIntercept(options) {
|
|
|
1813
1842
|
upstreamBroken = true;
|
|
1814
1843
|
tunnelsCurrent -= 1;
|
|
1815
1844
|
tunnelsClosed += 1;
|
|
1816
|
-
void relay.pluginTunnelClose(opened.tunnel).catch(() => { });
|
|
1845
|
+
void home.relay.pluginTunnelClose(opened.tunnel).catch(() => { });
|
|
1817
1846
|
};
|
|
1818
1847
|
socket.on('close', teardownTunnel);
|
|
1819
1848
|
socket.on('error', teardownTunnel);
|
|
@@ -1832,11 +1861,11 @@ export function installPluginRouteIntercept(options) {
|
|
|
1832
1861
|
localSocket.push(frame.raw);
|
|
1833
1862
|
return;
|
|
1834
1863
|
}
|
|
1835
|
-
if (tunnelHandle !== undefined && !upstreamBroken) {
|
|
1864
|
+
if (tunnelHandle !== undefined && tunnelServer !== undefined && !upstreamBroken) {
|
|
1836
1865
|
const seq = upstreamSeq;
|
|
1837
1866
|
upstreamSeq += 1;
|
|
1838
1867
|
try {
|
|
1839
|
-
await relay.pluginTunnelSend(tunnelHandle.tunnel, seq, frame.raw);
|
|
1868
|
+
await tunnelServer.relay.pluginTunnelSend(tunnelHandle.tunnel, seq, frame.raw);
|
|
1840
1869
|
}
|
|
1841
1870
|
catch {
|
|
1842
1871
|
// The send died: tear the exchange down COMPLETELY — the
|
|
@@ -1948,7 +1977,8 @@ export function installPluginRouteIntercept(options) {
|
|
|
1948
1977
|
answerUnbridgedSocket(socket, declared.plugin, 'bad-query');
|
|
1949
1978
|
return;
|
|
1950
1979
|
}
|
|
1951
|
-
|
|
1980
|
+
const tunnelRelay = relayOfServer(parts.serverId);
|
|
1981
|
+
if (tunnelRelay === undefined) {
|
|
1952
1982
|
answerUnbridgedSocket(socket, declared.plugin, 'server-changed');
|
|
1953
1983
|
return;
|
|
1954
1984
|
}
|
|
@@ -1956,7 +1986,7 @@ export function installPluginRouteIntercept(options) {
|
|
|
1956
1986
|
// the tunnel opens only for a plugin bridged RIGHT NOW — an absent
|
|
1957
1987
|
// or unbridged status refuses with its own reason, and the local
|
|
1958
1988
|
// plugin handler is never reached.
|
|
1959
|
-
const bridgeStatus =
|
|
1989
|
+
const bridgeStatus = statusesOfServer(parts.serverId).find((entry) => entry.plugin === declared.plugin);
|
|
1960
1990
|
if (bridgeStatus === undefined || !bridgeStatus.bridged) {
|
|
1961
1991
|
answerUnbridgedSocket(socket, declared.plugin, bridgeStatus?.reason ?? 'not-on-server');
|
|
1962
1992
|
return;
|
|
@@ -1977,7 +2007,7 @@ export function installPluginRouteIntercept(options) {
|
|
|
1977
2007
|
let tunnel;
|
|
1978
2008
|
try {
|
|
1979
2009
|
log?.('opening tunnel for %s', declared.path);
|
|
1980
|
-
tunnel = await
|
|
2010
|
+
tunnel = await tunnelRelay.pluginTunnelOpen({
|
|
1981
2011
|
plugin: declared.plugin,
|
|
1982
2012
|
version: declared.version,
|
|
1983
2013
|
digest: declared.digest,
|
|
@@ -2058,7 +2088,7 @@ export function installPluginRouteIntercept(options) {
|
|
|
2058
2088
|
if (upstreamBroken)
|
|
2059
2089
|
return;
|
|
2060
2090
|
try {
|
|
2061
|
-
await
|
|
2091
|
+
await tunnelRelay.pluginTunnelSend(tunnel.tunnel, seq, bytes, controller.signal);
|
|
2062
2092
|
}
|
|
2063
2093
|
catch {
|
|
2064
2094
|
upstreamBroken = true;
|
|
@@ -2070,7 +2100,7 @@ export function installPluginRouteIntercept(options) {
|
|
|
2070
2100
|
upstreamBroken = true;
|
|
2071
2101
|
tunnelsCurrent -= 1;
|
|
2072
2102
|
tunnelsClosed += 1;
|
|
2073
|
-
void
|
|
2103
|
+
void tunnelRelay.pluginTunnelClose(tunnel.tunnel).catch(() => { });
|
|
2074
2104
|
};
|
|
2075
2105
|
socket.on('close', teardownTunnel);
|
|
2076
2106
|
socket.on('error', teardownTunnel);
|