@quenty/studio-bridge 0.7.1 → 0.8.0
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 +12 -44
- package/README.md +166 -115
- package/dist/src/bridge/bridge-connection-remote.test.d.ts +7 -0
- package/dist/src/bridge/bridge-connection-remote.test.d.ts.map +1 -0
- package/dist/src/bridge/bridge-connection-remote.test.js +144 -0
- package/dist/src/bridge/bridge-connection-remote.test.js.map +1 -0
- package/dist/src/bridge/bridge-connection.d.ts +112 -0
- package/dist/src/bridge/bridge-connection.d.ts.map +1 -0
- package/dist/src/bridge/bridge-connection.js +528 -0
- package/dist/src/bridge/bridge-connection.js.map +1 -0
- package/dist/src/bridge/bridge-connection.test.d.ts +6 -0
- package/dist/src/bridge/bridge-connection.test.d.ts.map +1 -0
- package/dist/src/bridge/bridge-connection.test.js +773 -0
- package/dist/src/bridge/bridge-connection.test.js.map +1 -0
- package/dist/src/bridge/bridge-session.d.ts +38 -0
- package/dist/src/bridge/bridge-session.d.ts.map +1 -0
- package/dist/src/bridge/bridge-session.js +259 -0
- package/dist/src/bridge/bridge-session.js.map +1 -0
- package/dist/src/bridge/bridge-session.test.d.ts +6 -0
- package/dist/src/bridge/bridge-session.test.d.ts.map +1 -0
- package/dist/src/bridge/bridge-session.test.js +264 -0
- package/dist/src/bridge/bridge-session.test.js.map +1 -0
- package/dist/src/bridge/index.d.ts +13 -0
- package/dist/src/bridge/index.d.ts.map +1 -0
- package/dist/src/bridge/index.js +13 -0
- package/dist/src/bridge/index.js.map +1 -0
- package/dist/src/bridge/internal/__tests__/failover-crash.test.d.ts +9 -0
- package/dist/src/bridge/internal/__tests__/failover-crash.test.d.ts.map +1 -0
- package/dist/src/bridge/internal/__tests__/failover-crash.test.js +159 -0
- package/dist/src/bridge/internal/__tests__/failover-crash.test.js.map +1 -0
- package/dist/src/bridge/internal/__tests__/failover-graceful.test.d.ts +9 -0
- package/dist/src/bridge/internal/__tests__/failover-graceful.test.d.ts.map +1 -0
- package/dist/src/bridge/internal/__tests__/failover-graceful.test.js +218 -0
- package/dist/src/bridge/internal/__tests__/failover-graceful.test.js.map +1 -0
- package/dist/src/bridge/internal/__tests__/failover-inflight.test.d.ts +9 -0
- package/dist/src/bridge/internal/__tests__/failover-inflight.test.d.ts.map +1 -0
- package/dist/src/bridge/internal/__tests__/failover-inflight.test.js +246 -0
- package/dist/src/bridge/internal/__tests__/failover-inflight.test.js.map +1 -0
- package/dist/src/bridge/internal/__tests__/host-client-integration.test.d.ts +10 -0
- package/dist/src/bridge/internal/__tests__/host-client-integration.test.d.ts.map +1 -0
- package/dist/src/bridge/internal/__tests__/host-client-integration.test.js +298 -0
- package/dist/src/bridge/internal/__tests__/host-client-integration.test.js.map +1 -0
- package/dist/src/bridge/internal/bridge-client.d.ts +70 -0
- package/dist/src/bridge/internal/bridge-client.d.ts.map +1 -0
- package/dist/src/bridge/internal/bridge-client.js +344 -0
- package/dist/src/bridge/internal/bridge-client.js.map +1 -0
- package/dist/src/bridge/internal/bridge-client.test.d.ts +7 -0
- package/dist/src/bridge/internal/bridge-client.test.d.ts.map +1 -0
- package/dist/src/bridge/internal/bridge-client.test.js +301 -0
- package/dist/src/bridge/internal/bridge-client.test.js.map +1 -0
- package/dist/src/bridge/internal/bridge-host.d.ts +78 -0
- package/dist/src/bridge/internal/bridge-host.d.ts.map +1 -0
- package/dist/src/bridge/internal/bridge-host.js +383 -0
- package/dist/src/bridge/internal/bridge-host.js.map +1 -0
- package/dist/src/bridge/internal/bridge-host.test.d.ts +7 -0
- package/dist/src/bridge/internal/bridge-host.test.d.ts.map +1 -0
- package/dist/src/bridge/internal/bridge-host.test.js +377 -0
- package/dist/src/bridge/internal/bridge-host.test.js.map +1 -0
- package/dist/src/bridge/internal/environment-detection.d.ts +44 -0
- package/dist/src/bridge/internal/environment-detection.d.ts.map +1 -0
- package/dist/src/bridge/internal/environment-detection.js +91 -0
- package/dist/src/bridge/internal/environment-detection.js.map +1 -0
- package/dist/src/bridge/internal/environment-detection.test.d.ts +7 -0
- package/dist/src/bridge/internal/environment-detection.test.d.ts.map +1 -0
- package/dist/src/bridge/internal/environment-detection.test.js +150 -0
- package/dist/src/bridge/internal/environment-detection.test.js.map +1 -0
- package/dist/src/bridge/internal/hand-off.d.ts +69 -0
- package/dist/src/bridge/internal/hand-off.d.ts.map +1 -0
- package/dist/src/bridge/internal/hand-off.js +178 -0
- package/dist/src/bridge/internal/hand-off.js.map +1 -0
- package/dist/src/bridge/internal/hand-off.test.d.ts +7 -0
- package/dist/src/bridge/internal/hand-off.test.d.ts.map +1 -0
- package/dist/src/bridge/internal/hand-off.test.js +325 -0
- package/dist/src/bridge/internal/hand-off.test.js.map +1 -0
- package/dist/src/bridge/internal/health-endpoint.d.ts +32 -0
- package/dist/src/bridge/internal/health-endpoint.d.ts.map +1 -0
- package/dist/src/bridge/internal/health-endpoint.js +73 -0
- package/dist/src/bridge/internal/health-endpoint.js.map +1 -0
- package/dist/src/bridge/internal/health-endpoint.test.d.ts +6 -0
- package/dist/src/bridge/internal/health-endpoint.test.d.ts.map +1 -0
- package/dist/src/bridge/internal/health-endpoint.test.js +122 -0
- package/dist/src/bridge/internal/health-endpoint.test.js.map +1 -0
- package/dist/src/bridge/internal/host-protocol.d.ts +60 -0
- package/dist/src/bridge/internal/host-protocol.d.ts.map +1 -0
- package/dist/src/bridge/internal/host-protocol.js +184 -0
- package/dist/src/bridge/internal/host-protocol.js.map +1 -0
- package/dist/src/bridge/internal/host-protocol.test.d.ts +6 -0
- package/dist/src/bridge/internal/host-protocol.test.d.ts.map +1 -0
- package/dist/src/bridge/internal/host-protocol.test.js +307 -0
- package/dist/src/bridge/internal/host-protocol.test.js.map +1 -0
- package/dist/src/bridge/internal/session-tracker.d.ts +67 -0
- package/dist/src/bridge/internal/session-tracker.d.ts.map +1 -0
- package/dist/src/bridge/internal/session-tracker.js +138 -0
- package/dist/src/bridge/internal/session-tracker.js.map +1 -0
- package/dist/src/bridge/internal/session-tracker.test.d.ts +6 -0
- package/dist/src/bridge/internal/session-tracker.test.d.ts.map +1 -0
- package/dist/src/bridge/internal/session-tracker.test.js +342 -0
- package/dist/src/bridge/internal/session-tracker.test.js.map +1 -0
- package/dist/src/bridge/internal/transport-client.d.ts +43 -0
- package/dist/src/bridge/internal/transport-client.d.ts.map +1 -0
- package/dist/src/bridge/internal/transport-client.js +146 -0
- package/dist/src/bridge/internal/transport-client.js.map +1 -0
- package/dist/src/bridge/internal/transport-client.test.d.ts +6 -0
- package/dist/src/bridge/internal/transport-client.test.d.ts.map +1 -0
- package/dist/src/bridge/internal/transport-client.test.js +176 -0
- package/dist/src/bridge/internal/transport-client.test.js.map +1 -0
- package/dist/src/bridge/internal/transport-server.d.ts +59 -0
- package/dist/src/bridge/internal/transport-server.d.ts.map +1 -0
- package/dist/src/bridge/internal/transport-server.js +189 -0
- package/dist/src/bridge/internal/transport-server.js.map +1 -0
- package/dist/src/bridge/internal/transport-server.test.d.ts +6 -0
- package/dist/src/bridge/internal/transport-server.test.d.ts.map +1 -0
- package/dist/src/bridge/internal/transport-server.test.js +171 -0
- package/dist/src/bridge/internal/transport-server.test.js.map +1 -0
- package/dist/src/bridge/types.d.ts +117 -0
- package/dist/src/bridge/types.d.ts.map +1 -0
- package/dist/src/bridge/types.js +68 -0
- package/dist/src/bridge/types.js.map +1 -0
- package/dist/src/cli/adapters/cli-command-adapter-handler.test.d.ts +6 -0
- package/dist/src/cli/adapters/cli-command-adapter-handler.test.d.ts.map +1 -0
- package/dist/src/cli/adapters/cli-command-adapter-handler.test.js +260 -0
- package/dist/src/cli/adapters/cli-command-adapter-handler.test.js.map +1 -0
- package/dist/src/cli/adapters/cli-command-adapter.d.ts +39 -0
- package/dist/src/cli/adapters/cli-command-adapter.d.ts.map +1 -0
- package/dist/src/cli/adapters/cli-command-adapter.js +241 -0
- package/dist/src/cli/adapters/cli-command-adapter.js.map +1 -0
- package/dist/src/cli/adapters/cli-command-adapter.test.d.ts +5 -0
- package/dist/src/cli/adapters/cli-command-adapter.test.d.ts.map +1 -0
- package/dist/src/cli/adapters/cli-command-adapter.test.js +188 -0
- package/dist/src/cli/adapters/cli-command-adapter.test.js.map +1 -0
- package/dist/src/cli/adapters/group-builder.d.ts +29 -0
- package/dist/src/cli/adapters/group-builder.d.ts.map +1 -0
- package/dist/src/cli/adapters/group-builder.js +54 -0
- package/dist/src/cli/adapters/group-builder.js.map +1 -0
- package/dist/src/cli/adapters/group-builder.test.d.ts +5 -0
- package/dist/src/cli/adapters/group-builder.test.d.ts.map +1 -0
- package/dist/src/cli/adapters/group-builder.test.js +108 -0
- package/dist/src/cli/adapters/group-builder.test.js.map +1 -0
- package/dist/src/cli/adapters/help-formatter.d.ts +11 -0
- package/dist/src/cli/adapters/help-formatter.d.ts.map +1 -0
- package/dist/src/cli/adapters/help-formatter.js +78 -0
- package/dist/src/cli/adapters/help-formatter.js.map +1 -0
- package/dist/src/cli/adapters/help-formatter.test.d.ts +5 -0
- package/dist/src/cli/adapters/help-formatter.test.d.ts.map +1 -0
- package/dist/src/cli/adapters/help-formatter.test.js +79 -0
- package/dist/src/cli/adapters/help-formatter.test.js.map +1 -0
- package/dist/src/cli/adapters/target-resolver.d.ts +54 -0
- package/dist/src/cli/adapters/target-resolver.d.ts.map +1 -0
- package/dist/src/cli/adapters/target-resolver.js +90 -0
- package/dist/src/cli/adapters/target-resolver.js.map +1 -0
- package/dist/src/cli/adapters/target-resolver.test.d.ts +5 -0
- package/dist/src/cli/adapters/target-resolver.test.d.ts.map +1 -0
- package/dist/src/cli/adapters/target-resolver.test.js +169 -0
- package/dist/src/cli/adapters/target-resolver.test.js.map +1 -0
- package/dist/src/cli/args/global-args.d.ts +2 -0
- package/dist/src/cli/args/global-args.d.ts.map +1 -1
- package/dist/src/cli/cli.d.ts +6 -3
- package/dist/src/cli/cli.d.ts.map +1 -1
- package/dist/src/cli/cli.js +82 -20
- package/dist/src/cli/cli.js.map +1 -1
- package/dist/src/cli/resolve-script-content.d.ts +19 -0
- package/dist/src/cli/resolve-script-content.d.ts.map +1 -0
- package/dist/src/cli/resolve-script-content.js +22 -0
- package/dist/src/cli/resolve-script-content.js.map +1 -0
- package/dist/src/cli/resolve-session.d.ts +21 -0
- package/dist/src/cli/resolve-session.d.ts.map +1 -0
- package/dist/src/cli/resolve-session.js +40 -0
- package/dist/src/cli/resolve-session.js.map +1 -0
- package/dist/src/cli/resolve-session.test.d.ts +5 -0
- package/dist/src/cli/resolve-session.test.d.ts.map +1 -0
- package/dist/src/cli/resolve-session.test.js +112 -0
- package/dist/src/cli/resolve-session.test.js.map +1 -0
- package/dist/src/cli/script-executor.d.ts +1 -0
- package/dist/src/cli/script-executor.d.ts.map +1 -1
- package/dist/src/cli/script-executor.js +7 -1
- package/dist/src/cli/script-executor.js.map +1 -1
- package/dist/src/cli/types.d.ts +11 -0
- package/dist/src/cli/types.d.ts.map +1 -0
- package/dist/src/cli/types.js +5 -0
- package/dist/src/cli/types.js.map +1 -0
- package/dist/src/commands/connect.d.ts +16 -0
- package/dist/src/commands/connect.d.ts.map +1 -0
- package/dist/src/commands/connect.js +15 -0
- package/dist/src/commands/connect.js.map +1 -0
- package/dist/src/commands/connect.test.d.ts +5 -0
- package/dist/src/commands/connect.test.d.ts.map +1 -0
- package/dist/src/commands/connect.test.js +46 -0
- package/dist/src/commands/connect.test.js.map +1 -0
- package/dist/src/commands/console/exec/exec.d.ts +43 -0
- package/dist/src/commands/console/exec/exec.d.ts.map +1 -0
- package/dist/src/commands/console/exec/exec.js +79 -0
- package/dist/src/commands/console/exec/exec.js.map +1 -0
- package/dist/src/commands/console/exec/exec.test.d.ts +5 -0
- package/dist/src/commands/console/exec/exec.test.d.ts.map +1 -0
- package/dist/src/commands/console/exec/exec.test.js +191 -0
- package/dist/src/commands/console/exec/exec.test.js.map +1 -0
- package/dist/src/commands/console/logs/logs.d.ts +23 -0
- package/dist/src/commands/console/logs/logs.d.ts.map +1 -0
- package/dist/src/commands/console/logs/logs.js +80 -0
- package/dist/src/commands/console/logs/logs.js.map +1 -0
- package/dist/src/commands/console/logs/logs.test.d.ts +5 -0
- package/dist/src/commands/console/logs/logs.test.d.ts.map +1 -0
- package/dist/src/commands/console/logs/logs.test.js +111 -0
- package/dist/src/commands/console/logs/logs.test.js.map +1 -0
- package/dist/src/commands/disconnect.d.ts +9 -0
- package/dist/src/commands/disconnect.d.ts.map +1 -0
- package/dist/src/commands/disconnect.js +8 -0
- package/dist/src/commands/disconnect.js.map +1 -0
- package/dist/src/commands/disconnect.test.d.ts +5 -0
- package/dist/src/commands/disconnect.test.d.ts.map +1 -0
- package/dist/src/commands/disconnect.test.js +17 -0
- package/dist/src/commands/disconnect.test.js.map +1 -0
- package/dist/src/commands/explorer/query/query.d.ts +31 -0
- package/dist/src/commands/explorer/query/query.d.ts.map +1 -0
- package/dist/src/commands/explorer/query/query.js +106 -0
- package/dist/src/commands/explorer/query/query.js.map +1 -0
- package/dist/src/commands/explorer/query/query.test.d.ts +5 -0
- package/dist/src/commands/explorer/query/query.test.d.ts.map +1 -0
- package/dist/src/commands/explorer/query/query.test.js +228 -0
- package/dist/src/commands/explorer/query/query.test.js.map +1 -0
- package/dist/src/commands/formatters.test.d.ts +6 -0
- package/dist/src/commands/formatters.test.d.ts.map +1 -0
- package/dist/src/commands/formatters.test.js +211 -0
- package/dist/src/commands/formatters.test.js.map +1 -0
- package/dist/src/commands/framework/action-loader.d.ts +25 -0
- package/dist/src/commands/framework/action-loader.d.ts.map +1 -0
- package/dist/src/commands/framework/action-loader.js +46 -0
- package/dist/src/commands/framework/action-loader.js.map +1 -0
- package/dist/src/commands/framework/action-loader.test.d.ts +5 -0
- package/dist/src/commands/framework/action-loader.test.d.ts.map +1 -0
- package/dist/src/commands/framework/action-loader.test.js +89 -0
- package/dist/src/commands/framework/action-loader.test.js.map +1 -0
- package/dist/src/commands/framework/arg-builder.d.ts +92 -0
- package/dist/src/commands/framework/arg-builder.d.ts.map +1 -0
- package/dist/src/commands/framework/arg-builder.js +137 -0
- package/dist/src/commands/framework/arg-builder.js.map +1 -0
- package/dist/src/commands/framework/arg-builder.test.d.ts +5 -0
- package/dist/src/commands/framework/arg-builder.test.d.ts.map +1 -0
- package/dist/src/commands/framework/arg-builder.test.js +246 -0
- package/dist/src/commands/framework/arg-builder.test.js.map +1 -0
- package/dist/src/commands/framework/command-registry.d.ts +23 -0
- package/dist/src/commands/framework/command-registry.d.ts.map +1 -0
- package/dist/src/commands/framework/command-registry.js +42 -0
- package/dist/src/commands/framework/command-registry.js.map +1 -0
- package/dist/src/commands/framework/command-registry.test.d.ts +5 -0
- package/dist/src/commands/framework/command-registry.test.d.ts.map +1 -0
- package/dist/src/commands/framework/command-registry.test.js +158 -0
- package/dist/src/commands/framework/command-registry.test.js.map +1 -0
- package/dist/src/commands/framework/define-command.d.ts +76 -0
- package/dist/src/commands/framework/define-command.d.ts.map +1 -0
- package/dist/src/commands/framework/define-command.js +28 -0
- package/dist/src/commands/framework/define-command.js.map +1 -0
- package/dist/src/commands/framework/define-command.test.d.ts +5 -0
- package/dist/src/commands/framework/define-command.test.d.ts.map +1 -0
- package/dist/src/commands/framework/define-command.test.js +135 -0
- package/dist/src/commands/framework/define-command.test.js.map +1 -0
- package/dist/src/commands/framework/index.d.ts +8 -0
- package/dist/src/commands/framework/index.d.ts.map +1 -0
- package/dist/src/commands/framework/index.js +8 -0
- package/dist/src/commands/framework/index.js.map +1 -0
- package/dist/src/commands/index.d.ts +20 -0
- package/dist/src/commands/index.d.ts.map +1 -0
- package/dist/src/commands/index.js +20 -0
- package/dist/src/commands/index.js.map +1 -0
- package/dist/src/commands/linux/inject-credentials/inject-credentials.d.ts +15 -0
- package/dist/src/commands/linux/inject-credentials/inject-credentials.d.ts.map +1 -0
- package/dist/src/commands/linux/inject-credentials/inject-credentials.js +88 -0
- package/dist/src/commands/linux/inject-credentials/inject-credentials.js.map +1 -0
- package/dist/src/commands/linux/setup/setup.d.ts +19 -0
- package/dist/src/commands/linux/setup/setup.d.ts.map +1 -0
- package/dist/src/commands/linux/setup/setup.js +107 -0
- package/dist/src/commands/linux/setup/setup.js.map +1 -0
- package/dist/src/commands/linux/status/status.d.ts +34 -0
- package/dist/src/commands/linux/status/status.d.ts.map +1 -0
- package/dist/src/commands/linux/status/status.js +134 -0
- package/dist/src/commands/linux/status/status.js.map +1 -0
- package/dist/src/commands/plugin/install/install.d.ts +10 -0
- package/dist/src/commands/plugin/install/install.d.ts.map +1 -0
- package/dist/src/commands/plugin/install/install.js +23 -0
- package/dist/src/commands/plugin/install/install.js.map +1 -0
- package/dist/src/commands/plugin/uninstall/uninstall.d.ts +9 -0
- package/dist/src/commands/plugin/uninstall/uninstall.d.ts.map +1 -0
- package/dist/src/commands/plugin/uninstall/uninstall.js +41 -0
- package/dist/src/commands/plugin/uninstall/uninstall.js.map +1 -0
- package/dist/src/commands/process/close/close.d.ts +22 -0
- package/dist/src/commands/process/close/close.d.ts.map +1 -0
- package/dist/src/commands/process/close/close.js +34 -0
- package/dist/src/commands/process/close/close.js.map +1 -0
- package/dist/src/commands/process/format-state.d.ts +7 -0
- package/dist/src/commands/process/format-state.d.ts.map +1 -0
- package/dist/src/commands/process/format-state.js +19 -0
- package/dist/src/commands/process/format-state.js.map +1 -0
- package/dist/src/commands/process/info/info.d.ts +17 -0
- package/dist/src/commands/process/info/info.d.ts.map +1 -0
- package/dist/src/commands/process/info/info.js +38 -0
- package/dist/src/commands/process/info/info.js.map +1 -0
- package/dist/src/commands/process/info/info.test.d.ts +5 -0
- package/dist/src/commands/process/info/info.test.d.ts.map +1 -0
- package/dist/src/commands/process/info/info.test.js +58 -0
- package/dist/src/commands/process/info/info.test.js.map +1 -0
- package/dist/src/commands/process/launch/launch.d.ts +17 -0
- package/dist/src/commands/process/launch/launch.d.ts.map +1 -0
- package/dist/src/commands/process/launch/launch.js +26 -0
- package/dist/src/commands/process/launch/launch.js.map +1 -0
- package/dist/src/commands/process/launch/launch.test.d.ts +5 -0
- package/dist/src/commands/process/launch/launch.test.d.ts.map +1 -0
- package/dist/src/commands/process/launch/launch.test.js +49 -0
- package/dist/src/commands/process/launch/launch.test.js.map +1 -0
- package/dist/src/commands/process/list/list.d.ts +16 -0
- package/dist/src/commands/process/list/list.d.ts.map +1 -0
- package/dist/src/commands/process/list/list.js +56 -0
- package/dist/src/commands/process/list/list.js.map +1 -0
- package/dist/src/commands/process/list/list.test.d.ts +5 -0
- package/dist/src/commands/process/list/list.test.d.ts.map +1 -0
- package/dist/src/commands/process/list/list.test.js +71 -0
- package/dist/src/commands/process/list/list.test.js.map +1 -0
- package/dist/src/commands/process/run/run.d.ts +31 -0
- package/dist/src/commands/process/run/run.d.ts.map +1 -0
- package/dist/src/commands/process/run/run.js +63 -0
- package/dist/src/commands/process/run/run.js.map +1 -0
- package/dist/src/commands/rgba-to-png.d.ts +17 -0
- package/dist/src/commands/rgba-to-png.d.ts.map +1 -0
- package/dist/src/commands/rgba-to-png.js +85 -0
- package/dist/src/commands/rgba-to-png.js.map +1 -0
- package/dist/src/commands/serve/serve.d.ts +17 -0
- package/dist/src/commands/serve/serve.d.ts.map +1 -0
- package/dist/src/commands/serve/serve.js +128 -0
- package/dist/src/commands/serve/serve.js.map +1 -0
- package/dist/src/commands/serve/serve.test.d.ts +5 -0
- package/dist/src/commands/serve/serve.test.d.ts.map +1 -0
- package/dist/src/commands/serve/serve.test.js +100 -0
- package/dist/src/commands/serve/serve.test.js.map +1 -0
- package/dist/src/commands/viewport/screenshot/screenshot.d.ts +17 -0
- package/dist/src/commands/viewport/screenshot/screenshot.d.ts.map +1 -0
- package/dist/src/commands/viewport/screenshot/screenshot.js +45 -0
- package/dist/src/commands/viewport/screenshot/screenshot.js.map +1 -0
- package/dist/src/commands/viewport/screenshot/screenshot.test.d.ts +5 -0
- package/dist/src/commands/viewport/screenshot/screenshot.test.d.ts.map +1 -0
- package/dist/src/commands/viewport/screenshot/screenshot.test.js +143 -0
- package/dist/src/commands/viewport/screenshot/screenshot.test.js.map +1 -0
- package/dist/src/docker/docker-delegator.d.ts +30 -0
- package/dist/src/docker/docker-delegator.d.ts.map +1 -0
- package/dist/src/docker/docker-delegator.js +201 -0
- package/dist/src/docker/docker-delegator.js.map +1 -0
- package/dist/src/docker/docker-delegator.test.d.ts +2 -0
- package/dist/src/docker/docker-delegator.test.d.ts.map +1 -0
- package/dist/src/docker/docker-delegator.test.js +132 -0
- package/dist/src/docker/docker-delegator.test.js.map +1 -0
- package/dist/src/index.d.ts +9 -2
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +6 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/index.test.d.ts +2 -0
- package/dist/src/index.test.d.ts.map +1 -0
- package/dist/src/index.test.js +51 -0
- package/dist/src/index.test.js.map +1 -0
- package/dist/src/linux/index.d.ts +12 -0
- package/dist/src/linux/index.d.ts.map +1 -0
- package/dist/src/linux/index.js +11 -0
- package/dist/src/linux/index.js.map +1 -0
- package/dist/src/linux/linux-config.d.ts +37 -0
- package/dist/src/linux/linux-config.d.ts.map +1 -0
- package/dist/src/linux/linux-config.js +70 -0
- package/dist/src/linux/linux-config.js.map +1 -0
- package/dist/src/linux/linux-config.test.d.ts +2 -0
- package/dist/src/linux/linux-config.test.d.ts.map +1 -0
- package/dist/src/linux/linux-config.test.js +54 -0
- package/dist/src/linux/linux-config.test.js.map +1 -0
- package/dist/src/linux/linux-credential-writer.d.ts +35 -0
- package/dist/src/linux/linux-credential-writer.d.ts.map +1 -0
- package/dist/src/linux/linux-credential-writer.js +300 -0
- package/dist/src/linux/linux-credential-writer.js.map +1 -0
- package/dist/src/linux/linux-display-manager.d.ts +24 -0
- package/dist/src/linux/linux-display-manager.d.ts.map +1 -0
- package/dist/src/linux/linux-display-manager.js +92 -0
- package/dist/src/linux/linux-display-manager.js.map +1 -0
- package/dist/src/linux/linux-env-guard.d.ts +13 -0
- package/dist/src/linux/linux-env-guard.d.ts.map +1 -0
- package/dist/src/linux/linux-env-guard.js +31 -0
- package/dist/src/linux/linux-env-guard.js.map +1 -0
- package/dist/src/linux/linux-env-guard.test.d.ts +2 -0
- package/dist/src/linux/linux-env-guard.test.d.ts.map +1 -0
- package/dist/src/linux/linux-env-guard.test.js +48 -0
- package/dist/src/linux/linux-env-guard.test.js.map +1 -0
- package/dist/src/linux/linux-fflags.d.ts +17 -0
- package/dist/src/linux/linux-fflags.d.ts.map +1 -0
- package/dist/src/linux/linux-fflags.js +33 -0
- package/dist/src/linux/linux-fflags.js.map +1 -0
- package/dist/src/linux/linux-fflags.test.d.ts +2 -0
- package/dist/src/linux/linux-fflags.test.d.ts.map +1 -0
- package/dist/src/linux/linux-fflags.test.js +55 -0
- package/dist/src/linux/linux-fflags.test.js.map +1 -0
- package/dist/src/linux/linux-prerequisites.d.ts +24 -0
- package/dist/src/linux/linux-prerequisites.d.ts.map +1 -0
- package/dist/src/linux/linux-prerequisites.js +118 -0
- package/dist/src/linux/linux-prerequisites.js.map +1 -0
- package/dist/src/linux/linux-shader-patcher.d.ts +17 -0
- package/dist/src/linux/linux-shader-patcher.d.ts.map +1 -0
- package/dist/src/linux/linux-shader-patcher.js +48 -0
- package/dist/src/linux/linux-shader-patcher.js.map +1 -0
- package/dist/src/linux/linux-shader-patcher.test.d.ts +2 -0
- package/dist/src/linux/linux-shader-patcher.test.d.ts.map +1 -0
- package/dist/src/linux/linux-shader-patcher.test.js +55 -0
- package/dist/src/linux/linux-shader-patcher.test.js.map +1 -0
- package/dist/src/linux/linux-studio-installer.d.ts +10 -0
- package/dist/src/linux/linux-studio-installer.d.ts.map +1 -0
- package/dist/src/linux/linux-studio-installer.js +79 -0
- package/dist/src/linux/linux-studio-installer.js.map +1 -0
- package/dist/src/linux/linux-studio-launcher.d.ts +10 -0
- package/dist/src/linux/linux-studio-launcher.d.ts.map +1 -0
- package/dist/src/linux/linux-studio-launcher.js +73 -0
- package/dist/src/linux/linux-studio-launcher.js.map +1 -0
- package/dist/src/linux/linux-version-resolver.d.ts +18 -0
- package/dist/src/linux/linux-version-resolver.d.ts.map +1 -0
- package/dist/src/linux/linux-version-resolver.js +49 -0
- package/dist/src/linux/linux-version-resolver.js.map +1 -0
- package/dist/src/linux/linux-wine-env.d.ts +11 -0
- package/dist/src/linux/linux-wine-env.d.ts.map +1 -0
- package/dist/src/linux/linux-wine-env.js +33 -0
- package/dist/src/linux/linux-wine-env.js.map +1 -0
- package/dist/src/linux/linux-wine-env.test.d.ts +2 -0
- package/dist/src/linux/linux-wine-env.test.d.ts.map +1 -0
- package/dist/src/linux/linux-wine-env.test.js +47 -0
- package/dist/src/linux/linux-wine-env.test.js.map +1 -0
- package/dist/src/plugin/persistent-plugin-installer.d.ts +21 -0
- package/dist/src/plugin/persistent-plugin-installer.d.ts.map +1 -0
- package/dist/src/plugin/persistent-plugin-installer.js +69 -0
- package/dist/src/plugin/persistent-plugin-installer.js.map +1 -0
- package/dist/src/plugin/persistent-plugin-installer.test.d.ts +5 -0
- package/dist/src/plugin/persistent-plugin-installer.test.d.ts.map +1 -0
- package/dist/src/plugin/persistent-plugin-installer.test.js +109 -0
- package/dist/src/plugin/persistent-plugin-installer.test.js.map +1 -0
- package/dist/src/plugin/plugin-discovery.d.ts +7 -0
- package/dist/src/plugin/plugin-discovery.d.ts.map +1 -0
- package/dist/src/plugin/plugin-discovery.js +18 -0
- package/dist/src/plugin/plugin-discovery.js.map +1 -0
- package/dist/src/plugin/plugin-discovery.test.d.ts +5 -0
- package/dist/src/plugin/plugin-discovery.test.d.ts.map +1 -0
- package/dist/src/plugin/plugin-discovery.test.js +55 -0
- package/dist/src/plugin/plugin-discovery.test.js.map +1 -0
- package/dist/src/plugin/plugin-injector.js +1 -1
- package/dist/src/plugin/plugin-injector.js.map +1 -1
- package/dist/src/process/studio-process-manager.d.ts +7 -3
- package/dist/src/process/studio-process-manager.d.ts.map +1 -1
- package/dist/src/process/studio-process-manager.js +38 -11
- package/dist/src/process/studio-process-manager.js.map +1 -1
- package/dist/src/process/studio-process-manager.test.js +18 -1
- package/dist/src/process/studio-process-manager.test.js.map +1 -1
- package/dist/src/server/action-dispatcher.d.ts +35 -0
- package/dist/src/server/action-dispatcher.d.ts.map +1 -0
- package/dist/src/server/action-dispatcher.js +67 -0
- package/dist/src/server/action-dispatcher.js.map +1 -0
- package/dist/src/server/action-dispatcher.test.d.ts +6 -0
- package/dist/src/server/action-dispatcher.test.d.ts.map +1 -0
- package/dist/src/server/action-dispatcher.test.js +173 -0
- package/dist/src/server/action-dispatcher.test.js.map +1 -0
- package/dist/src/server/index.d.ts +1 -1
- package/dist/src/server/index.d.ts.map +1 -1
- package/dist/src/server/pending-request-map.d.ts +33 -0
- package/dist/src/server/pending-request-map.d.ts.map +1 -0
- package/dist/src/server/pending-request-map.js +69 -0
- package/dist/src/server/pending-request-map.js.map +1 -0
- package/dist/src/server/pending-request-map.test.d.ts +2 -0
- package/dist/src/server/pending-request-map.test.d.ts.map +1 -0
- package/dist/src/server/pending-request-map.test.js +192 -0
- package/dist/src/server/pending-request-map.test.js.map +1 -0
- package/dist/src/server/plugin-detection.test.d.ts +7 -0
- package/dist/src/server/plugin-detection.test.d.ts.map +1 -0
- package/dist/src/server/plugin-detection.test.js +154 -0
- package/dist/src/server/plugin-detection.test.js.map +1 -0
- package/dist/src/server/studio-bridge-server.d.ts +44 -7
- package/dist/src/server/studio-bridge-server.d.ts.map +1 -1
- package/dist/src/server/studio-bridge-server.js +341 -91
- package/dist/src/server/studio-bridge-server.js.map +1 -1
- package/dist/src/server/studio-bridge-server.test.js +231 -207
- package/dist/src/server/studio-bridge-server.test.js.map +1 -1
- package/dist/src/server/web-socket-protocol-basic.test.d.ts +2 -0
- package/dist/src/server/web-socket-protocol-basic.test.d.ts.map +1 -0
- package/dist/src/server/web-socket-protocol-basic.test.js +98 -0
- package/dist/src/server/web-socket-protocol-basic.test.js.map +1 -0
- package/dist/src/server/web-socket-protocol.d.ts +218 -20
- package/dist/src/server/web-socket-protocol.d.ts.map +1 -1
- package/dist/src/server/web-socket-protocol.js +346 -20
- package/dist/src/server/web-socket-protocol.js.map +1 -1
- package/dist/src/server/web-socket-protocol.test.js +572 -146
- package/dist/src/server/web-socket-protocol.test.js.map +1 -1
- package/dist/src/test/e2e/hand-off.test.d.ts +9 -0
- package/dist/src/test/e2e/hand-off.test.d.ts.map +1 -0
- package/dist/src/test/e2e/hand-off.test.js +274 -0
- package/dist/src/test/e2e/hand-off.test.js.map +1 -0
- package/dist/src/test/e2e/persistent-session.test.d.ts +11 -0
- package/dist/src/test/e2e/persistent-session.test.d.ts.map +1 -0
- package/dist/src/test/e2e/persistent-session.test.js +367 -0
- package/dist/src/test/e2e/persistent-session.test.js.map +1 -0
- package/dist/src/test/e2e/split-server.test.d.ts +14 -0
- package/dist/src/test/e2e/split-server.test.d.ts.map +1 -0
- package/dist/src/test/e2e/split-server.test.js +230 -0
- package/dist/src/test/e2e/split-server.test.js.map +1 -0
- package/dist/src/test/helpers/mock-plugin-client.d.ts +69 -0
- package/dist/src/test/helpers/mock-plugin-client.d.ts.map +1 -0
- package/dist/src/test/helpers/mock-plugin-client.js +213 -0
- package/dist/src/test/helpers/mock-plugin-client.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/docker/.dockerignore +2 -0
- package/docker/Dockerfile +113 -0
- package/docker/docker-compose.yml +20 -0
- package/docker/entrypoint.sh +19 -0
- package/package.json +8 -6
- package/src/bridge/bridge-connection-remote.test.ts +189 -0
- package/src/bridge/bridge-connection.test.ts +1076 -0
- package/src/bridge/bridge-connection.ts +718 -0
- package/src/bridge/bridge-session.test.ts +336 -0
- package/src/bridge/bridge-session.ts +365 -0
- package/src/bridge/index.ts +42 -0
- package/src/bridge/internal/__tests__/failover-crash.test.ts +191 -0
- package/src/bridge/internal/__tests__/failover-graceful.test.ts +268 -0
- package/src/bridge/internal/__tests__/failover-inflight.test.ts +329 -0
- package/src/bridge/internal/__tests__/host-client-integration.test.ts +387 -0
- package/src/bridge/internal/bridge-client.test.ts +399 -0
- package/src/bridge/internal/bridge-client.ts +434 -0
- package/src/bridge/internal/bridge-host.test.ts +501 -0
- package/src/bridge/internal/bridge-host.ts +531 -0
- package/src/bridge/internal/environment-detection.test.ts +180 -0
- package/src/bridge/internal/environment-detection.ts +119 -0
- package/src/bridge/internal/hand-off.test.ts +408 -0
- package/src/bridge/internal/hand-off.ts +275 -0
- package/src/bridge/internal/health-endpoint.test.ts +147 -0
- package/src/bridge/internal/health-endpoint.ts +100 -0
- package/src/bridge/internal/host-protocol.test.ts +415 -0
- package/src/bridge/internal/host-protocol.ts +255 -0
- package/src/bridge/internal/session-tracker.test.ts +535 -0
- package/src/bridge/internal/session-tracker.ts +198 -0
- package/src/bridge/internal/transport-client.test.ts +241 -0
- package/src/bridge/internal/transport-client.ts +194 -0
- package/src/bridge/internal/transport-server.test.ts +220 -0
- package/src/bridge/internal/transport-server.ts +242 -0
- package/src/bridge/types.ts +161 -0
- package/src/cli/adapters/cli-command-adapter-handler.test.ts +318 -0
- package/src/cli/adapters/cli-command-adapter.test.ts +221 -0
- package/src/cli/adapters/cli-command-adapter.ts +342 -0
- package/src/cli/adapters/group-builder.test.ts +146 -0
- package/src/cli/adapters/group-builder.ts +81 -0
- package/src/cli/adapters/help-formatter.test.ts +97 -0
- package/src/cli/adapters/help-formatter.ts +86 -0
- package/src/cli/adapters/target-resolver.test.ts +222 -0
- package/src/cli/adapters/target-resolver.ts +144 -0
- package/src/cli/args/global-args.ts +2 -0
- package/src/cli/cli.ts +100 -21
- package/src/cli/resolve-script-content.ts +36 -0
- package/src/cli/resolve-session.test.ts +141 -0
- package/src/cli/resolve-session.ts +66 -0
- package/src/cli/script-executor.ts +22 -4
- package/src/cli/types.ts +11 -0
- package/src/commands/connect.test.ts +61 -0
- package/src/commands/connect.ts +32 -0
- package/src/commands/console/exec/exec.test.ts +258 -0
- package/src/commands/console/exec/exec.ts +130 -0
- package/src/commands/console/exec/execute.luau +202 -0
- package/src/commands/console/logs/logs.test.ts +138 -0
- package/src/commands/console/logs/logs.ts +115 -0
- package/src/commands/console/logs/query-logs.luau +76 -0
- package/src/commands/disconnect.test.ts +21 -0
- package/src/commands/disconnect.ts +12 -0
- package/src/commands/explorer/query/query-data-model.luau +206 -0
- package/src/commands/explorer/query/query.test.ts +297 -0
- package/src/commands/explorer/query/query.ts +157 -0
- package/src/commands/formatters.test.ts +237 -0
- package/src/commands/framework/action-loader.test.ts +118 -0
- package/src/commands/framework/action-loader.ts +65 -0
- package/src/commands/framework/arg-builder.test.ts +298 -0
- package/src/commands/framework/arg-builder.ts +203 -0
- package/src/commands/framework/command-registry.test.ts +204 -0
- package/src/commands/framework/command-registry.ts +51 -0
- package/src/commands/framework/define-command.test.ts +161 -0
- package/src/commands/framework/define-command.ts +114 -0
- package/src/commands/framework/index.ts +33 -0
- package/src/commands/index.ts +72 -0
- package/src/commands/linux/inject-credentials/inject-credentials.ts +118 -0
- package/src/commands/linux/setup/setup.ts +145 -0
- package/src/commands/linux/status/status.ts +180 -0
- package/src/commands/plugin/install/install.ts +31 -0
- package/src/commands/plugin/uninstall/uninstall.ts +54 -0
- package/src/commands/process/close/close.ts +52 -0
- package/src/commands/process/format-state.ts +21 -0
- package/src/commands/process/info/info.test.ts +76 -0
- package/src/commands/process/info/info.ts +54 -0
- package/src/commands/process/info/query-state.luau +48 -0
- package/src/commands/process/launch/launch.test.ts +65 -0
- package/src/commands/process/launch/launch.ts +45 -0
- package/src/commands/process/list/list.test.ts +82 -0
- package/src/commands/process/list/list.ts +75 -0
- package/src/commands/process/run/run.ts +98 -0
- package/src/commands/rgba-to-png.ts +98 -0
- package/src/commands/serve/serve.test.ts +139 -0
- package/src/commands/serve/serve.ts +161 -0
- package/src/commands/viewport/screenshot/capture-screenshot.luau +247 -0
- package/src/commands/viewport/screenshot/screenshot.test.ts +181 -0
- package/src/commands/viewport/screenshot/screenshot.ts +71 -0
- package/src/docker/docker-delegator.test.ts +159 -0
- package/src/docker/docker-delegator.ts +240 -0
- package/src/index.test.ts +58 -0
- package/src/index.ts +104 -3
- package/src/linux/README.md +130 -0
- package/src/linux/index.ts +25 -0
- package/src/linux/linux-config.test.ts +66 -0
- package/src/linux/linux-config.ts +102 -0
- package/src/linux/linux-credential-writer.ts +421 -0
- package/src/linux/linux-display-manager.ts +106 -0
- package/src/linux/linux-env-guard.test.ts +62 -0
- package/src/linux/linux-env-guard.ts +38 -0
- package/src/linux/linux-fflags.test.ts +78 -0
- package/src/linux/linux-fflags.ts +48 -0
- package/src/linux/linux-prerequisites.ts +152 -0
- package/src/linux/linux-shader-patcher.test.ts +76 -0
- package/src/linux/linux-shader-patcher.ts +56 -0
- package/src/linux/linux-studio-installer.ts +113 -0
- package/src/linux/linux-studio-launcher.ts +90 -0
- package/src/linux/linux-version-resolver.ts +74 -0
- package/src/linux/linux-wine-env.test.ts +56 -0
- package/src/linux/linux-wine-env.ts +38 -0
- package/src/linux/write-cred.c +48 -0
- package/src/plugin/persistent-plugin-installer.test.ts +168 -0
- package/src/plugin/persistent-plugin-installer.ts +90 -0
- package/src/plugin/plugin-discovery.test.ts +70 -0
- package/src/plugin/plugin-discovery.ts +21 -0
- package/src/plugin/plugin-injector.ts +1 -1
- package/src/process/studio-process-manager.test.ts +22 -1
- package/src/process/studio-process-manager.ts +57 -18
- package/src/server/action-dispatcher.test.ts +240 -0
- package/src/server/action-dispatcher.ts +89 -0
- package/src/server/index.ts +0 -3
- package/src/server/pending-request-map.test.ts +261 -0
- package/src/server/pending-request-map.ts +87 -0
- package/src/server/plugin-detection.test.ts +195 -0
- package/src/server/studio-bridge-server.test.ts +321 -283
- package/src/server/studio-bridge-server.ts +469 -111
- package/src/server/web-socket-protocol-basic.test.ts +131 -0
- package/src/server/web-socket-protocol.test.ts +658 -159
- package/src/server/web-socket-protocol.ts +668 -58
- package/src/test/e2e/hand-off.test.ts +338 -0
- package/src/test/e2e/persistent-session.test.ts +442 -0
- package/src/test/e2e/split-server.test.ts +290 -0
- package/src/test/helpers/mock-plugin-client.ts +276 -0
- package/templates/studio-bridge-plugin/src/Shared/ActionRouter.luau +245 -0
- package/templates/studio-bridge-plugin/src/Shared/DiscoveryStateMachine.luau +203 -0
- package/templates/studio-bridge-plugin/src/Shared/MessageBuffer.luau +144 -0
- package/templates/studio-bridge-plugin/src/Shared/Protocol.luau +132 -0
- package/templates/studio-bridge-plugin/src/StudioBridgePlugin.server.lua +364 -133
- package/templates/studio-bridge-plugin/src/Vendor/png.luau +1247 -0
- package/templates/studio-bridge-plugin-test/test/actions.test.luau +580 -0
- package/templates/studio-bridge-plugin-test/test/discovery.test.luau +622 -0
- package/templates/studio-bridge-plugin-test/test/execute-handler.test.luau +406 -0
- package/templates/studio-bridge-plugin-test/test/hash-lifecycle.test.luau +814 -0
- package/templates/studio-bridge-plugin-test/test/integration.test.luau +1020 -0
- package/templates/studio-bridge-plugin-test/test/new-actions.test.luau +339 -0
- package/templates/studio-bridge-plugin-test/test/plugin-entry.test.luau +493 -0
- package/templates/studio-bridge-plugin-test/test/protocol.test.luau +506 -0
- package/templates/studio-bridge-plugin-test/test/roblox-mocks.luau +108 -0
- package/templates/studio-bridge-plugin-test/test/test-runner.luau +112 -0
- package/dist/src/cli/commands/exec-command.d.ts +0 -15
- package/dist/src/cli/commands/exec-command.d.ts.map +0 -1
- package/dist/src/cli/commands/exec-command.js +0 -35
- package/dist/src/cli/commands/exec-command.js.map +0 -1
- package/dist/src/cli/commands/run-command.d.ts +0 -15
- package/dist/src/cli/commands/run-command.d.ts.map +0 -1
- package/dist/src/cli/commands/run-command.js +0 -47
- package/dist/src/cli/commands/run-command.js.map +0 -1
- package/dist/src/cli/commands/terminal/terminal-command.d.ts +0 -17
- package/dist/src/cli/commands/terminal/terminal-command.d.ts.map +0 -1
- package/dist/src/cli/commands/terminal/terminal-command.js +0 -41
- package/dist/src/cli/commands/terminal/terminal-command.js.map +0 -1
- package/dist/src/cli/commands/terminal/terminal-editor.d.ts +0 -43
- package/dist/src/cli/commands/terminal/terminal-editor.d.ts.map +0 -1
- package/dist/src/cli/commands/terminal/terminal-editor.js +0 -430
- package/dist/src/cli/commands/terminal/terminal-editor.js.map +0 -1
- package/dist/src/cli/commands/terminal/terminal-mode.d.ts +0 -13
- package/dist/src/cli/commands/terminal/terminal-mode.d.ts.map +0 -1
- package/dist/src/cli/commands/terminal/terminal-mode.js +0 -141
- package/dist/src/cli/commands/terminal/terminal-mode.js.map +0 -1
- package/dist/src/server/web-socket-protocol.smoke.test.d.ts +0 -6
- package/dist/src/server/web-socket-protocol.smoke.test.d.ts.map +0 -1
- package/dist/src/server/web-socket-protocol.smoke.test.js +0 -196
- package/dist/src/server/web-socket-protocol.smoke.test.js.map +0 -1
- package/src/cli/commands/exec-command.ts +0 -48
- package/src/cli/commands/run-command.ts +0 -63
- package/src/cli/commands/terminal/terminal-command.ts +0 -54
- package/src/cli/commands/terminal/terminal-editor.ts +0 -500
- package/src/cli/commands/terminal/terminal-mode.ts +0 -184
- package/src/server/web-socket-protocol.smoke.test.ts +0 -255
|
@@ -0,0 +1,718 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public entry point for connecting to the studio-bridge network. Handles
|
|
3
|
+
* host/client role detection transparently. Consumers never create a
|
|
4
|
+
* BridgeHost, BridgeClient, TransportServer, or any other internal type.
|
|
5
|
+
*
|
|
6
|
+
* Use the static factory `connectAsync()` to create instances.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { EventEmitter } from 'events';
|
|
10
|
+
import { BridgeHost } from './internal/bridge-host.js';
|
|
11
|
+
import { BridgeClient } from './internal/bridge-client.js';
|
|
12
|
+
import {
|
|
13
|
+
SessionTracker,
|
|
14
|
+
type TrackedSession,
|
|
15
|
+
} from './internal/session-tracker.js';
|
|
16
|
+
import {
|
|
17
|
+
detectRoleAsync,
|
|
18
|
+
getDefaultRemoteHost,
|
|
19
|
+
} from './internal/environment-detection.js';
|
|
20
|
+
import { BridgeSession } from './bridge-session.js';
|
|
21
|
+
import type {
|
|
22
|
+
HostProtocolMessage,
|
|
23
|
+
ListSessionsRequest,
|
|
24
|
+
ListInstancesRequest,
|
|
25
|
+
} from './internal/host-protocol.js';
|
|
26
|
+
import type { SessionInfo, SessionContext, InstanceInfo } from './types.js';
|
|
27
|
+
import { SessionNotFoundError, ContextNotFoundError } from './types.js';
|
|
28
|
+
import type { ServerMessage } from '../server/web-socket-protocol.js';
|
|
29
|
+
import { OutputHelper } from '@quenty/cli-output-helpers';
|
|
30
|
+
export interface BridgeConnectionOptions {
|
|
31
|
+
/** Port for the bridge host. Default: 38741. */
|
|
32
|
+
port?: number;
|
|
33
|
+
/** Max time to wait for initial connection setup. Default: 30_000ms. */
|
|
34
|
+
timeoutMs?: number;
|
|
35
|
+
/** Keep the host alive even when idle. Default: false. */
|
|
36
|
+
keepAlive?: boolean;
|
|
37
|
+
/** Skip local port-bind attempt and connect directly as client (host:port). */
|
|
38
|
+
remoteHost?: string;
|
|
39
|
+
/** Force local mode -- skip devcontainer auto-detection. */
|
|
40
|
+
local?: boolean;
|
|
41
|
+
/**
|
|
42
|
+
* When true and this process becomes the host, wait for active Studios to
|
|
43
|
+
* discover and connect before returning. Use for short-lived commands that
|
|
44
|
+
* need all sessions available immediately. Default: false.
|
|
45
|
+
*/
|
|
46
|
+
waitForSessions?: boolean;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
const DEFAULT_PORT = 38741;
|
|
50
|
+
const DEFAULT_TIMEOUT_MS = 30_000;
|
|
51
|
+
const IDLE_EXIT_GRACE_MS = 5_000;
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Transport handle that relays messages to a plugin's WebSocket via BridgeHost.
|
|
55
|
+
* Used by SessionTracker in host mode so that BridgeSession.sendActionAsync()
|
|
56
|
+
* works the same way whether we're a host or a client.
|
|
57
|
+
*/
|
|
58
|
+
class HostTransportHandle extends EventEmitter {
|
|
59
|
+
private _connected = true;
|
|
60
|
+
private _sessionId: string;
|
|
61
|
+
private _host: BridgeHost;
|
|
62
|
+
|
|
63
|
+
constructor(sessionId: string, host: BridgeHost) {
|
|
64
|
+
super();
|
|
65
|
+
this._sessionId = sessionId;
|
|
66
|
+
this._host = host;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
get isConnected(): boolean {
|
|
70
|
+
return this._connected;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
async sendActionAsync<TResponse>(
|
|
74
|
+
message: ServerMessage,
|
|
75
|
+
timeoutMs: number
|
|
76
|
+
): Promise<TResponse> {
|
|
77
|
+
return this._host.sendToPluginAsync<TResponse>(
|
|
78
|
+
this._sessionId,
|
|
79
|
+
message,
|
|
80
|
+
timeoutMs
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
sendMessage(message: ServerMessage): void {
|
|
85
|
+
this._host.sendToPlugin(this._sessionId, message);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
markDisconnected(): void {
|
|
89
|
+
this._connected = false;
|
|
90
|
+
this.emit('disconnected');
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export class BridgeConnection extends EventEmitter {
|
|
95
|
+
private _role: 'host' | 'client';
|
|
96
|
+
private _isConnected: boolean = false;
|
|
97
|
+
private _keepAlive: boolean;
|
|
98
|
+
private _hasSettled: boolean = false;
|
|
99
|
+
|
|
100
|
+
// Host mode internals
|
|
101
|
+
private _host: BridgeHost | undefined;
|
|
102
|
+
private _tracker: SessionTracker | undefined;
|
|
103
|
+
private _hostSessions: Map<string, BridgeSession> = new Map();
|
|
104
|
+
private _hostHandles: Map<string, HostTransportHandle> = new Map();
|
|
105
|
+
|
|
106
|
+
// Client mode internals
|
|
107
|
+
private _client: BridgeClient | undefined;
|
|
108
|
+
|
|
109
|
+
// Idle exit
|
|
110
|
+
private _idleTimer: ReturnType<typeof setTimeout> | undefined;
|
|
111
|
+
|
|
112
|
+
private constructor(role: 'host' | 'client', keepAlive: boolean) {
|
|
113
|
+
super();
|
|
114
|
+
this._role = role;
|
|
115
|
+
this._keepAlive = keepAlive;
|
|
116
|
+
// keepAlive connections (serve mode) manage their own lifecycle —
|
|
117
|
+
// don't auto-settle in resolveSessionAsync
|
|
118
|
+
this._hasSettled = keepAlive;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Connect to the studio-bridge network and return a ready-to-use
|
|
123
|
+
* BridgeConnection.
|
|
124
|
+
*
|
|
125
|
+
* - If remoteHost is specified: connects directly as a client.
|
|
126
|
+
* - If local is specified: skips devcontainer auto-detection, uses local mode.
|
|
127
|
+
* - If no host is running: binds the port, becomes the host.
|
|
128
|
+
* - If a host is running: connects as a client.
|
|
129
|
+
*/
|
|
130
|
+
static async connectAsync(
|
|
131
|
+
options?: BridgeConnectionOptions
|
|
132
|
+
): Promise<BridgeConnection> {
|
|
133
|
+
const keepAlive = options?.keepAlive ?? false;
|
|
134
|
+
const remoteHost = options?.remoteHost;
|
|
135
|
+
|
|
136
|
+
let parsedRemoteHost: string | undefined;
|
|
137
|
+
let port = options?.port ?? DEFAULT_PORT;
|
|
138
|
+
|
|
139
|
+
if (remoteHost) {
|
|
140
|
+
if (remoteHost.includes(':')) {
|
|
141
|
+
const parts = remoteHost.split(':');
|
|
142
|
+
parsedRemoteHost = remoteHost;
|
|
143
|
+
port = parseInt(parts[parts.length - 1], 10) || DEFAULT_PORT;
|
|
144
|
+
} else {
|
|
145
|
+
parsedRemoteHost = `${remoteHost}:${port}`;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// Devcontainer auto-detection: if no explicit remoteHost and not forced local,
|
|
150
|
+
// try connecting to the default remote host with a short timeout before falling
|
|
151
|
+
// back to local mode.
|
|
152
|
+
if (!parsedRemoteHost && !options?.local) {
|
|
153
|
+
const autoRemoteHost = getDefaultRemoteHost();
|
|
154
|
+
if (autoRemoteHost) {
|
|
155
|
+
const AUTO_DETECT_TIMEOUT_MS = 3_000;
|
|
156
|
+
try {
|
|
157
|
+
const autoConn = new BridgeConnection('client', keepAlive);
|
|
158
|
+
const autoHost = autoRemoteHost.split(':')[0];
|
|
159
|
+
const autoPort =
|
|
160
|
+
parseInt(autoRemoteHost.split(':')[1], 10) || DEFAULT_PORT;
|
|
161
|
+
|
|
162
|
+
await Promise.race([
|
|
163
|
+
autoConn._initClientAsync(autoPort, autoHost),
|
|
164
|
+
new Promise<never>((_, reject) =>
|
|
165
|
+
setTimeout(
|
|
166
|
+
() => reject(new Error('Auto-detection timed out')),
|
|
167
|
+
AUTO_DETECT_TIMEOUT_MS
|
|
168
|
+
)
|
|
169
|
+
),
|
|
170
|
+
]);
|
|
171
|
+
|
|
172
|
+
return autoConn;
|
|
173
|
+
} catch {
|
|
174
|
+
console.warn(
|
|
175
|
+
`Devcontainer detected, but could not connect to bridge host at ${autoRemoteHost}. ` +
|
|
176
|
+
`Falling back to local mode. Run \`studio-bridge serve\` on the host OS, ` +
|
|
177
|
+
`or use --remote to specify a different address.`
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
const detection = await detectRoleAsync({
|
|
184
|
+
port,
|
|
185
|
+
remoteHost: parsedRemoteHost,
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
const conn = new BridgeConnection(detection.role, keepAlive);
|
|
189
|
+
OutputHelper.verbose(
|
|
190
|
+
`[bridge] Role: ${detection.role}, port: ${detection.port}`
|
|
191
|
+
);
|
|
192
|
+
|
|
193
|
+
if (detection.role === 'host') {
|
|
194
|
+
await conn._initHostAsync(detection.port);
|
|
195
|
+
} else {
|
|
196
|
+
try {
|
|
197
|
+
await conn._initClientAsync(detection.port, parsedRemoteHost);
|
|
198
|
+
} catch (err: unknown) {
|
|
199
|
+
if (parsedRemoteHost && err instanceof Error) {
|
|
200
|
+
const code = (err as NodeJS.ErrnoException).code;
|
|
201
|
+
if (code === 'ECONNREFUSED') {
|
|
202
|
+
throw new Error(
|
|
203
|
+
`Could not connect to bridge host at ${parsedRemoteHost}. ` +
|
|
204
|
+
`Is \`studio-bridge serve\` running on the host?`
|
|
205
|
+
);
|
|
206
|
+
}
|
|
207
|
+
if (
|
|
208
|
+
err.message.includes('timed out') ||
|
|
209
|
+
err.message.includes('timeout')
|
|
210
|
+
) {
|
|
211
|
+
throw new Error(
|
|
212
|
+
`Connection to bridge host at ${parsedRemoteHost} timed out after 5 seconds.`
|
|
213
|
+
);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
throw err;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// If requested, wait for active Studios to discover this host and connect
|
|
221
|
+
if (conn._role === 'host' && options?.waitForSessions) {
|
|
222
|
+
await conn._ensureSettledAsync();
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
return conn;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
async disconnectAsync(): Promise<void> {
|
|
229
|
+
if (!this._isConnected) {
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
OutputHelper.verbose(
|
|
233
|
+
`[bridge] disconnectAsync called (role=${this._role})`
|
|
234
|
+
);
|
|
235
|
+
OutputHelper.verbose(
|
|
236
|
+
`[bridge] disconnect stack: ${new Error().stack
|
|
237
|
+
?.split('\n')
|
|
238
|
+
.slice(1, 5)
|
|
239
|
+
.map((s) => s.trim())
|
|
240
|
+
.join(' <- ')}`
|
|
241
|
+
);
|
|
242
|
+
|
|
243
|
+
this._clearIdleTimer();
|
|
244
|
+
this._isConnected = false;
|
|
245
|
+
|
|
246
|
+
if (this._role === 'host' && this._host) {
|
|
247
|
+
for (const handle of this._hostHandles.values()) {
|
|
248
|
+
handle.markDisconnected();
|
|
249
|
+
}
|
|
250
|
+
await this._host.shutdownAsync();
|
|
251
|
+
this._host = undefined;
|
|
252
|
+
this._tracker = undefined;
|
|
253
|
+
this._hostSessions.clear();
|
|
254
|
+
this._hostHandles.clear();
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
if (this._role === 'client' && this._client) {
|
|
258
|
+
await this._client.disconnectAsync();
|
|
259
|
+
this._client = undefined;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/** Whether this process ended up as host or client. */
|
|
264
|
+
get role(): 'host' | 'client' {
|
|
265
|
+
return this._role;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/** Whether the connection is currently active. */
|
|
269
|
+
get isConnected(): boolean {
|
|
270
|
+
return this._isConnected;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/** The actual port the bridge is bound to (host) or connected to (client). */
|
|
274
|
+
get port(): number {
|
|
275
|
+
if (this._role === 'host' && this._host) {
|
|
276
|
+
return this._host.port;
|
|
277
|
+
}
|
|
278
|
+
return 0;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/** List all currently connected Studio sessions. */
|
|
282
|
+
listSessions(): SessionInfo[] {
|
|
283
|
+
if (this._role === 'host' && this._tracker) {
|
|
284
|
+
return this._tracker.listSessions();
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
if (this._role === 'client' && this._client) {
|
|
288
|
+
return this._client.listSessions();
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
return [];
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
/**
|
|
295
|
+
* List unique Studio instances. Each instance groups 1-3 context sessions
|
|
296
|
+
* that share the same instanceId.
|
|
297
|
+
*/
|
|
298
|
+
listInstances(): InstanceInfo[] {
|
|
299
|
+
if (this._role === 'host' && this._tracker) {
|
|
300
|
+
return this._tracker.listInstances();
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
if (this._role === 'client' && this._client) {
|
|
304
|
+
return this._client.listInstances();
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
return [];
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/** Get a session handle by ID. Returns undefined if not connected. */
|
|
311
|
+
getSession(sessionId: string): BridgeSession | undefined {
|
|
312
|
+
if (this._role === 'host') {
|
|
313
|
+
return this._hostSessions.get(sessionId);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
if (this._role === 'client' && this._client) {
|
|
317
|
+
return this._client.getSession(sessionId);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
return undefined;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* Resolve a session for command execution. Instance-aware: groups sessions
|
|
325
|
+
* by instanceId and auto-selects context within an instance.
|
|
326
|
+
*
|
|
327
|
+
* Algorithm (from tech-spec 07, section 6.7):
|
|
328
|
+
* 1. If sessionId -> return that specific session.
|
|
329
|
+
* 2. If instanceId -> select that instance, then apply context selection.
|
|
330
|
+
* 3. Collect unique instances.
|
|
331
|
+
* 4. 0 instances -> throw SessionNotFoundError.
|
|
332
|
+
* 5. 1 instance:
|
|
333
|
+
* a. If context -> return matching context. Throw ContextNotFoundError if not found.
|
|
334
|
+
* b. If 1 context -> return it.
|
|
335
|
+
* c. If N contexts (Play mode) -> return Edit context by default.
|
|
336
|
+
* 6. N instances -> throw SessionNotFoundError with instance list.
|
|
337
|
+
*/
|
|
338
|
+
async resolveSessionAsync(
|
|
339
|
+
sessionId?: string,
|
|
340
|
+
context?: SessionContext,
|
|
341
|
+
instanceId?: string
|
|
342
|
+
): Promise<BridgeSession> {
|
|
343
|
+
// Fresh host hasn't settled yet — wait for persistent plugins to discover us
|
|
344
|
+
await this._ensureSettledAsync();
|
|
345
|
+
|
|
346
|
+
if (sessionId) {
|
|
347
|
+
const session = this.getSession(sessionId);
|
|
348
|
+
if (session) {
|
|
349
|
+
return session;
|
|
350
|
+
}
|
|
351
|
+
throw new SessionNotFoundError(
|
|
352
|
+
`Session '${sessionId}' not found`,
|
|
353
|
+
sessionId
|
|
354
|
+
);
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
if (instanceId) {
|
|
358
|
+
return this._resolveByInstance(instanceId, context);
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
const instances = this.listInstances();
|
|
362
|
+
|
|
363
|
+
if (instances.length === 0) {
|
|
364
|
+
throw new SessionNotFoundError('No sessions connected');
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
if (instances.length === 1) {
|
|
368
|
+
return this._resolveByInstance(instances[0].instanceId, context);
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
// Multiple instances: list session IDs so the user can copy one into --session
|
|
372
|
+
const sessionList = this.listSessions()
|
|
373
|
+
.map((s) => ` - ${s.sessionId}: ${s.placeName} (${s.context})`)
|
|
374
|
+
.join('\n');
|
|
375
|
+
|
|
376
|
+
throw new SessionNotFoundError(
|
|
377
|
+
`Multiple Studio instances connected. Use --session <id> to select one.\n${sessionList}`
|
|
378
|
+
);
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
/** Resolves with the first connected session. Rejects after timeout. */
|
|
382
|
+
async waitForSessionAsync(timeout?: number): Promise<BridgeSession> {
|
|
383
|
+
const sessions = this.listSessions();
|
|
384
|
+
if (sessions.length > 0) {
|
|
385
|
+
const session = this.getSession(sessions[0].sessionId);
|
|
386
|
+
if (session) {
|
|
387
|
+
return session;
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
const timeoutMs = timeout ?? DEFAULT_TIMEOUT_MS;
|
|
392
|
+
|
|
393
|
+
return new Promise<BridgeSession>((resolve, reject) => {
|
|
394
|
+
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
395
|
+
|
|
396
|
+
const onSession = (session: BridgeSession) => {
|
|
397
|
+
if (timer) {
|
|
398
|
+
clearTimeout(timer);
|
|
399
|
+
}
|
|
400
|
+
resolve(session);
|
|
401
|
+
};
|
|
402
|
+
|
|
403
|
+
timer = setTimeout(() => {
|
|
404
|
+
this.off('session-connected', onSession);
|
|
405
|
+
reject(
|
|
406
|
+
new Error(
|
|
407
|
+
`Timed out waiting for a session to connect (${timeoutMs}ms)`
|
|
408
|
+
)
|
|
409
|
+
);
|
|
410
|
+
}, timeoutMs);
|
|
411
|
+
|
|
412
|
+
this.once('session-connected', onSession);
|
|
413
|
+
});
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
/**
|
|
417
|
+
* Ensure that session discovery has completed at least once for this
|
|
418
|
+
* host connection. No-op if already settled, not a host, or sessions
|
|
419
|
+
* are already connected.
|
|
420
|
+
*/
|
|
421
|
+
private async _ensureSettledAsync(): Promise<void> {
|
|
422
|
+
if (
|
|
423
|
+
this._hasSettled ||
|
|
424
|
+
this._role !== 'host' ||
|
|
425
|
+
this.listSessions().length > 0
|
|
426
|
+
) {
|
|
427
|
+
return;
|
|
428
|
+
}
|
|
429
|
+
OutputHelper.verbose(
|
|
430
|
+
'[bridge] No sessions yet — waiting for plugins to discover us'
|
|
431
|
+
);
|
|
432
|
+
await this.waitForSessionsToSettleAsync();
|
|
433
|
+
this._hasSettled = true;
|
|
434
|
+
const settled = this.listSessions();
|
|
435
|
+
OutputHelper.verbose(
|
|
436
|
+
`[bridge] Settled with ${settled.length} session(s)${
|
|
437
|
+
settled.length > 0
|
|
438
|
+
? ': ' + settled.map((s) => s.sessionId).join(', ')
|
|
439
|
+
: ''
|
|
440
|
+
}`
|
|
441
|
+
);
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
/**
|
|
445
|
+
* Wait for all active Studios to discover this host and connect. Waits for
|
|
446
|
+
* the first session, then keeps waiting until no new sessions arrive for a
|
|
447
|
+
* full plugin poll cycle (~2.5s). Guarantees all polling plugins have had
|
|
448
|
+
* a chance to find the host. Safe to call when not a host (returns immediately).
|
|
449
|
+
*/
|
|
450
|
+
async waitForSessionsToSettleAsync(options?: {
|
|
451
|
+
/** Max time to wait for the first session (ms). Default: 5000 */
|
|
452
|
+
firstSessionTimeout?: number;
|
|
453
|
+
/** How long to wait after the last connection before considering settled (ms). Default: 4000 */
|
|
454
|
+
settleMs?: number;
|
|
455
|
+
/** Absolute max wait time (ms). Default: 15000 */
|
|
456
|
+
maxMs?: number;
|
|
457
|
+
}): Promise<void> {
|
|
458
|
+
if (this._role !== 'host') {
|
|
459
|
+
return;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
const firstTimeout = options?.firstSessionTimeout ?? 5_000;
|
|
463
|
+
const settleMs = options?.settleMs ?? 4_000;
|
|
464
|
+
const maxMs = options?.maxMs ?? 15_000;
|
|
465
|
+
|
|
466
|
+
// Wait for the first session
|
|
467
|
+
try {
|
|
468
|
+
await this.waitForSessionAsync(firstTimeout);
|
|
469
|
+
} catch {
|
|
470
|
+
// No session appeared — nothing to settle
|
|
471
|
+
return;
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
// Wait for sessions to stabilize: reset timer on each new connection
|
|
475
|
+
await new Promise<void>((resolve) => {
|
|
476
|
+
const cleanup = () => {
|
|
477
|
+
clearTimeout(settleTimer);
|
|
478
|
+
clearTimeout(maxTimer);
|
|
479
|
+
this.off('session-connected', onSession);
|
|
480
|
+
resolve();
|
|
481
|
+
};
|
|
482
|
+
|
|
483
|
+
const onSession = () => {
|
|
484
|
+
clearTimeout(settleTimer);
|
|
485
|
+
settleTimer = setTimeout(cleanup, settleMs);
|
|
486
|
+
};
|
|
487
|
+
|
|
488
|
+
let settleTimer = setTimeout(cleanup, settleMs);
|
|
489
|
+
const maxTimer = setTimeout(cleanup, maxMs);
|
|
490
|
+
|
|
491
|
+
this.on('session-connected', onSession);
|
|
492
|
+
});
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
private async _initHostAsync(port: number): Promise<void> {
|
|
496
|
+
this._host = new BridgeHost();
|
|
497
|
+
this._tracker = new SessionTracker();
|
|
498
|
+
|
|
499
|
+
this._tracker.on('session-added', (tracked: TrackedSession) => {
|
|
500
|
+
const session = new BridgeSession(tracked.info, tracked.handle);
|
|
501
|
+
this._hostSessions.set(tracked.info.sessionId, session);
|
|
502
|
+
this.emit('session-connected', session);
|
|
503
|
+
this._resetIdleTimer();
|
|
504
|
+
|
|
505
|
+
this._host?.broadcastToClients({
|
|
506
|
+
type: 'session-event',
|
|
507
|
+
event: 'connected',
|
|
508
|
+
sessionId: tracked.info.sessionId,
|
|
509
|
+
session: tracked.info,
|
|
510
|
+
context: tracked.info.context,
|
|
511
|
+
instanceId: tracked.info.instanceId,
|
|
512
|
+
});
|
|
513
|
+
});
|
|
514
|
+
|
|
515
|
+
this._tracker.on('session-removed', (sessionId: string) => {
|
|
516
|
+
const removed = this._hostSessions.get(sessionId);
|
|
517
|
+
this._hostSessions.delete(sessionId);
|
|
518
|
+
this._hostHandles.delete(sessionId);
|
|
519
|
+
this.emit('session-disconnected', sessionId);
|
|
520
|
+
this._resetIdleTimer();
|
|
521
|
+
|
|
522
|
+
this._host?.broadcastToClients({
|
|
523
|
+
type: 'session-event',
|
|
524
|
+
event: 'disconnected',
|
|
525
|
+
sessionId,
|
|
526
|
+
context: removed?.info.context ?? 'edit',
|
|
527
|
+
instanceId: removed?.info.instanceId ?? sessionId,
|
|
528
|
+
});
|
|
529
|
+
});
|
|
530
|
+
|
|
531
|
+
this._tracker.on('instance-added', (instance: InstanceInfo) => {
|
|
532
|
+
this.emit('instance-connected', instance);
|
|
533
|
+
});
|
|
534
|
+
|
|
535
|
+
this._tracker.on('instance-removed', (instanceId: string) => {
|
|
536
|
+
this.emit('instance-disconnected', instanceId);
|
|
537
|
+
});
|
|
538
|
+
|
|
539
|
+
this._host.on('plugin-connected', (info) => {
|
|
540
|
+
const state = info.state ?? 'Edit';
|
|
541
|
+
const context = BridgeConnection._deriveContext(state);
|
|
542
|
+
|
|
543
|
+
const sessionInfo: SessionInfo = {
|
|
544
|
+
sessionId: info.sessionId,
|
|
545
|
+
placeName: info.placeName ?? '',
|
|
546
|
+
placeFile: info.placeFile,
|
|
547
|
+
state: state as SessionInfo['state'],
|
|
548
|
+
pluginVersion: info.pluginVersion ?? '',
|
|
549
|
+
capabilities: info.capabilities,
|
|
550
|
+
connectedAt: new Date(),
|
|
551
|
+
origin: 'user',
|
|
552
|
+
context,
|
|
553
|
+
instanceId: info.instanceId ?? info.sessionId,
|
|
554
|
+
placeId: 0,
|
|
555
|
+
gameId: 0,
|
|
556
|
+
};
|
|
557
|
+
|
|
558
|
+
const handle = new HostTransportHandle(info.sessionId, this._host!);
|
|
559
|
+
this._hostHandles.set(info.sessionId, handle);
|
|
560
|
+
this._tracker!.addSession(info.sessionId, sessionInfo, handle);
|
|
561
|
+
});
|
|
562
|
+
|
|
563
|
+
this._host.on('plugin-disconnected', (sessionId: string) => {
|
|
564
|
+
const handle = this._hostHandles.get(sessionId);
|
|
565
|
+
if (handle) {
|
|
566
|
+
handle.markDisconnected();
|
|
567
|
+
}
|
|
568
|
+
this._tracker!.removeSession(sessionId);
|
|
569
|
+
});
|
|
570
|
+
|
|
571
|
+
// Handle client protocol messages (list-sessions, list-instances, etc.)
|
|
572
|
+
this._host.on(
|
|
573
|
+
'client-message',
|
|
574
|
+
(msg: HostProtocolMessage, reply: (m: HostProtocolMessage) => void) => {
|
|
575
|
+
if (msg.type === 'list-sessions') {
|
|
576
|
+
const req = msg as ListSessionsRequest;
|
|
577
|
+
reply({
|
|
578
|
+
type: 'list-sessions-response',
|
|
579
|
+
requestId: req.requestId,
|
|
580
|
+
sessions: this._tracker!.listSessions(),
|
|
581
|
+
});
|
|
582
|
+
} else if (msg.type === 'list-instances') {
|
|
583
|
+
const req = msg as ListInstancesRequest;
|
|
584
|
+
reply({
|
|
585
|
+
type: 'list-instances-response',
|
|
586
|
+
requestId: req.requestId,
|
|
587
|
+
instances: this._tracker!.listInstances(),
|
|
588
|
+
});
|
|
589
|
+
}
|
|
590
|
+
}
|
|
591
|
+
);
|
|
592
|
+
|
|
593
|
+
await this._host.startAsync({ port });
|
|
594
|
+
this._isConnected = true;
|
|
595
|
+
// Don't start idle timer on init -- callers like `sessions` manage their
|
|
596
|
+
// own lifecycle via disconnectAsync(). The idle timer should only fire
|
|
597
|
+
// when sessions are removed (going from >0 to 0).
|
|
598
|
+
}
|
|
599
|
+
|
|
600
|
+
private async _initClientAsync(
|
|
601
|
+
port: number,
|
|
602
|
+
remoteHost?: string
|
|
603
|
+
): Promise<void> {
|
|
604
|
+
this._client = new BridgeClient();
|
|
605
|
+
|
|
606
|
+
this._client.on('session-connected', (session: BridgeSession) => {
|
|
607
|
+
this.emit('session-connected', session);
|
|
608
|
+
});
|
|
609
|
+
|
|
610
|
+
this._client.on('session-disconnected', (sessionId: string) => {
|
|
611
|
+
this.emit('session-disconnected', sessionId);
|
|
612
|
+
});
|
|
613
|
+
|
|
614
|
+
this._client.on('disconnected', () => {
|
|
615
|
+
this._isConnected = false;
|
|
616
|
+
});
|
|
617
|
+
|
|
618
|
+
this._client.on('host-promoted', () => {
|
|
619
|
+
this._role = 'host';
|
|
620
|
+
});
|
|
621
|
+
|
|
622
|
+
const host = remoteHost ? remoteHost.split(':')[0] : undefined;
|
|
623
|
+
await this._client.connectAsync(port, host);
|
|
624
|
+
this._isConnected = true;
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
private static _deriveContext(state: string): SessionContext {
|
|
628
|
+
if (state === 'Server') return 'server';
|
|
629
|
+
if (state === 'Client') return 'client';
|
|
630
|
+
return 'edit';
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
private _resolveByInstance(
|
|
634
|
+
instanceId: string,
|
|
635
|
+
context?: SessionContext
|
|
636
|
+
): BridgeSession {
|
|
637
|
+
const sessions = this.listSessions().filter(
|
|
638
|
+
(s) => s.instanceId === instanceId
|
|
639
|
+
);
|
|
640
|
+
|
|
641
|
+
if (sessions.length === 0) {
|
|
642
|
+
throw new SessionNotFoundError(`Instance '${instanceId}' not found`);
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
const contexts = sessions.map((s) => s.context);
|
|
646
|
+
|
|
647
|
+
// 5a: Context specified
|
|
648
|
+
if (context) {
|
|
649
|
+
const match = sessions.find((s) => s.context === context);
|
|
650
|
+
if (match) {
|
|
651
|
+
const session = this.getSession(match.sessionId);
|
|
652
|
+
if (session) {
|
|
653
|
+
return session;
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
throw new ContextNotFoundError(context, instanceId, contexts);
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
// 5b: Single context
|
|
660
|
+
if (sessions.length === 1) {
|
|
661
|
+
const session = this.getSession(sessions[0].sessionId);
|
|
662
|
+
if (session) {
|
|
663
|
+
return session;
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
// 5c: Multiple contexts -> return Edit
|
|
668
|
+
const editSession = sessions.find((s) => s.context === 'edit');
|
|
669
|
+
if (editSession) {
|
|
670
|
+
const session = this.getSession(editSession.sessionId);
|
|
671
|
+
if (session) {
|
|
672
|
+
return session;
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
// Fallback: return first session
|
|
677
|
+
const fallback = this.getSession(sessions[0].sessionId);
|
|
678
|
+
if (fallback) {
|
|
679
|
+
return fallback;
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
throw new SessionNotFoundError(
|
|
683
|
+
`No session found for instance '${instanceId}'`
|
|
684
|
+
);
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
private _resetIdleTimer(): void {
|
|
688
|
+
if (this._keepAlive) {
|
|
689
|
+
return;
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
this._clearIdleTimer();
|
|
693
|
+
|
|
694
|
+
// Only start idle timer if we're the host and have no sessions
|
|
695
|
+
if (this._role === 'host' && this._tracker) {
|
|
696
|
+
if (this._tracker.sessionCount === 0) {
|
|
697
|
+
OutputHelper.verbose(
|
|
698
|
+
`[bridge] Starting idle exit timer (${IDLE_EXIT_GRACE_MS}ms, sessionCount=0)`
|
|
699
|
+
);
|
|
700
|
+
this._idleTimer = setTimeout(() => {
|
|
701
|
+
OutputHelper.verbose(
|
|
702
|
+
'[bridge] Idle exit timer fired — disconnecting'
|
|
703
|
+
);
|
|
704
|
+
this.disconnectAsync().catch(() => {
|
|
705
|
+
// Ignore disconnect errors during idle shutdown
|
|
706
|
+
});
|
|
707
|
+
}, IDLE_EXIT_GRACE_MS);
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
private _clearIdleTimer(): void {
|
|
713
|
+
if (this._idleTimer !== undefined) {
|
|
714
|
+
clearTimeout(this._idleTimer);
|
|
715
|
+
this._idleTimer = undefined;
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
}
|