overmux 0.0.3 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/dist/auth/.vite/manifest.json +2 -2
  3. package/dist/auth/assets/{index-Bx8JhwVi.css → index-BM9gETvx.css} +1 -1
  4. package/dist/auth/assets/{index-CHIE7qYj.js → index-DabAfcs1.js} +1 -1
  5. package/dist/auth/index.html +2 -2
  6. package/dist/bin.js +91 -11
  7. package/dist/bin.js.map +1 -1
  8. package/dist/docs/300-fundamentals/300-theming.md +51 -0
  9. package/dist/docs/400-reference/100-configuration.md +20 -0
  10. package/dist/docs/400-reference/200-server-api.md +18 -0
  11. package/dist/docs/400-reference/300-client-api.md +19 -0
  12. package/dist/docs/400-reference/400-cli/350-instance.md +24 -0
  13. package/dist/exports/client.d.ts +16 -3
  14. package/dist/exports/client.d.ts.map +1 -1
  15. package/dist/exports/client.js +100 -13
  16. package/dist/exports/client.js.map +1 -1
  17. package/dist/exports/{index-D3_Dpy_T.d.ts → index-DS70rKzo.d.ts} +14 -2
  18. package/dist/exports/index-DS70rKzo.d.ts.map +1 -0
  19. package/dist/exports/index.d.ts +2 -2
  20. package/dist/exports/index.js +1 -1
  21. package/dist/exports/index.js.map +1 -1
  22. package/dist/exports/{notifications-kDp16bU_.js → notifications-av0FK0yZ.js} +7 -2
  23. package/dist/exports/{notifications-kDp16bU_.js.map → notifications-av0FK0yZ.js.map} +1 -1
  24. package/dist/exports/server.d.ts.map +1 -1
  25. package/dist/exports/server.js +52 -10
  26. package/dist/exports/server.js.map +1 -1
  27. package/dist/internal/server/coordinator/server-child.js +110 -46
  28. package/dist/internal/server/coordinator/server-child.js.map +1 -1
  29. package/docs/300-fundamentals/300-theming.md +51 -0
  30. package/docs/400-reference/100-configuration.md +20 -0
  31. package/docs/400-reference/200-server-api.md +18 -0
  32. package/docs/400-reference/300-client-api.md +19 -0
  33. package/docs/400-reference/400-cli/350-instance.md +24 -0
  34. package/package.json +1 -1
  35. package/src/internal/cli/app.ts +2 -0
  36. package/src/internal/cli/commands/instance.ts +58 -0
  37. package/src/internal/cli/parse-port.ts +2 -1
  38. package/src/internal/client/auth/auth-shell.css +17 -1
  39. package/src/internal/client/auth/auth-shell.tsx +2 -11
  40. package/src/internal/client/auth/login-code-input.tsx +140 -0
  41. package/src/internal/client/browser-api.ts +17 -3
  42. package/src/internal/client/host/desktop-host.ts +3 -0
  43. package/src/internal/client/host/environment.ts +67 -0
  44. package/src/internal/client/host/instance-forwarding.ts +21 -0
  45. package/src/internal/client/host/overmux-host.tsx +8 -0
  46. package/src/internal/client/overmux-react.ts +24 -2
  47. package/src/internal/client/websocket.ts +32 -12
  48. package/src/internal/server/auth/instance-control.ts +24 -3
  49. package/src/internal/server/runtime/create-runtime.ts +12 -1
  50. package/src/internal/server/runtime/runtime-instance.ts +46 -0
  51. package/src/internal/server/runtime/runtime-resources.ts +3 -0
  52. package/src/internal/server/server-startup-options.ts +9 -4
  53. package/src/internal/server/start-application-server.ts +20 -12
  54. package/src/internal/server/websocket-server.ts +7 -0
  55. package/src/internal/shared/index.ts +2 -0
  56. package/src/internal/shared/protocol.ts +10 -1
  57. package/src/public/client.ts +1 -0
  58. package/src/public/config.ts +7 -0
  59. package/src/public/index.ts +2 -0
  60. package/dist/exports/index-D3_Dpy_T.d.ts.map +0 -1
@@ -1,3 +1,54 @@
1
1
  ---
2
2
  title: Theming
3
3
  ---
4
+
5
+ ## Host and platform selectors
6
+
7
+ Overmux sets two independent attributes on the hosted application's `<html>` element before React mounts:
8
+
9
+ ```html
10
+ <html data-om-host="desktop" data-om-platform="macos">
11
+ ```
12
+
13
+ Use these public CSS selectors to adapt your application to its environment:
14
+
15
+ ```css
16
+ /* Hide browser-only installation guidance in native and installed apps. */
17
+ html:not([data-om-host="browser"]) .install-prompt {
18
+ display: none;
19
+ }
20
+
21
+ /* OS-specific styling also works when using Overmux in a browser. */
22
+ html[data-om-platform="macos"] .shortcut-hint {
23
+ font-family: system-ui;
24
+ }
25
+
26
+ /* Combine the independent host and platform selectors. */
27
+ html[data-om-host="desktop"][data-om-platform="windows"] .app-toolbar {
28
+ padding-inline: 1rem;
29
+ }
30
+ ```
31
+
32
+ ### Host values
33
+
34
+ | `data-om-host` | Meaning |
35
+ | --- | --- |
36
+ | `desktop` | Running inside the native Overmux desktop host, regardless of window size. |
37
+ | `browser` | Running in a regular browser tab or window. |
38
+ | `pwa` | Running as an installed web app in `standalone`, `minimal-ui`, or `window-controls-overlay` display mode, including Safari's installed standalone mode. |
39
+
40
+ A progressive web app (PWA) is a website that can run as an installed application. Visiting an installable website does not make the host `pwa`. Ordinary browser fullscreen does not qualify either. Native desktop detection takes precedence over display mode. Browser/PWA selectors update when the supported display modes change.
41
+
42
+ `desktop` describes the host, not a desktop-sized layout. Use CSS media or container queries for responsive layout. The native host's implementation technology is not a CSS value.
43
+
44
+ ### Platform values
45
+
46
+ `data-om-platform` is always one of `macos`, `windows`, `linux`, `android`, `ios`, or `unknown`.
47
+
48
+ The native desktop host supplies its OS identity through versioned preload metadata. Browsers use best-effort detection from browser-provided platform and user-agent information, including touch-capable iPads presenting a Mac identity. Missing, obscured, or unrecognized information can yield `unknown`; do not use these selectors for security decisions or feature detection.
49
+
50
+ ### Scope
51
+
52
+ These attributes belong to the hosted application document, independently of `OvermuxThemeScope`. They do not change theme tokens, color scheme, contrast, nested theme scopes, or portal inheritance. Selectors anchored at `html` also match portal content in the same document, including caller-owned external portal containers.
53
+
54
+ This API does not theme native window controls or the desktop connection screen. It requires no public JavaScript API; use the attributes directly in your application's CSS.
@@ -1,3 +1,23 @@
1
1
  ---
2
2
  title: Configuration
3
3
  ---
4
+
5
+ ## Instance identity
6
+
7
+ ```ts
8
+ import { defineOvermuxConfig } from "overmux";
9
+ import { server } from "./server";
10
+
11
+ export default defineOvermuxConfig({
12
+ server,
13
+ instanceId: ({ port }) => `rich-work-${port}`,
14
+ });
15
+ ```
16
+
17
+ `instanceId` accepts a fixed string (for example `instanceId: "rich-work"`) or a function of `{ port }`. It is resolved once at server startup using the actual listening port. Every hostname serving this running instance reports the same ID. Changing the port intentionally changes a port-dependent ID.
18
+
19
+ `port` in `overmux.config.ts` must be an integer from `1` through `65535`. Internal listeners and tests may use `0` to ask the OS for a free port; this is not a user configuration value.
20
+
21
+ The default is the machine hostname followed by `-<port>`. IDs are canonical lowercase ASCII: 1-253 characters, start and end with a letter or digit, and may contain dots or hyphens internally. Explicit IDs are validated, never silently normalized. Set an explicit ID if the machine hostname does not meet these rules.
22
+
23
+ Distinct instances require distinct IDs. IDs are names, not credentials; authentication is still required. Deep links use `overmux://<instance-id>/<application-route>`. Their authority is only a lookup key, never a network address. Use the live runtime helpers or `overmux instance --json` to produce a prefix rather than guessing it from a browser URL.
@@ -1,3 +1,21 @@
1
1
  ---
2
2
  title: Server API
3
3
  ---
4
+
5
+ ## Instance identity in handlers
6
+
7
+ Operation, resource, and stream handler contexts expose the running instance:
8
+
9
+ ```ts
10
+ import { defineOperation } from "overmux";
11
+ import { z } from "zod";
12
+
13
+ export const paneLink = defineOperation({
14
+ input: z.object({ paneId: z.string() }),
15
+ output: z.string(),
16
+ handle: ({ paneId }, context) =>
17
+ `${context.instance.getDeepLinkPrefix()}/panes/${encodeURIComponent(paneId)}`,
18
+ });
19
+ ```
20
+
21
+ `context.instance.getInstanceId(): string` and `context.instance.getDeepLinkPrefix(): string` are synchronous and ready before handlers execute. They belong to this server runtime, not process-global state. The prefix is exactly `overmux://<instance-id>` without a trailing slash. Encode route segments once, not the whole assembled URL.
@@ -2,6 +2,25 @@
2
2
  title: Client API
3
3
  ---
4
4
 
5
+ ## Instance identity
6
+
7
+ ```tsx
8
+ import { createOvermuxHooks } from "overmux/client";
9
+ import type { serverConfig } from "./server";
10
+
11
+ const { useInstance } = createOvermuxHooks<typeof serverConfig>();
12
+
13
+ const PaneLink = ({ paneId }: { paneId: string }) => {
14
+ const instance = useInstance();
15
+ if (!instance) return null;
16
+ return <a href={`${instance.deepLinkPrefix}/panes/${encodeURIComponent(paneId)}`}>Open pane in desktop</a>;
17
+ };
18
+ ```
19
+
20
+ Use these hooks under the existing Overmux provider. `useInstance()` returns `{ instanceId, deepLinkPrefix } | undefined` and rerenders when authenticated discovery arrives or changes after reconnecting.
21
+
22
+ The same scoped `overmuxServerApi` object passed to command handlers for operations also provides `overmuxServerApi.getInstanceId()` and `overmuxServerApi.getDeepLinkPrefix()`. Both return `undefined` until the authenticated server announces its identity. The prefix is exactly `overmux://<instance-id>`, without a trailing slash. Browser addresses are not instance identities. Desktop hosts receive discovery through a narrow identity bridge automatically; application code does not need to forward it.
23
+
5
24
  ## Clipboard
6
25
 
7
26
  ```ts
@@ -0,0 +1,24 @@
1
+ ---
2
+ title: "overmux instance"
3
+ description: "Read the identity of a running Overmux server"
4
+ ---
5
+
6
+ # `overmux instance`
7
+
8
+ Print the live server's `instanceId` and `deepLinkPrefix`. Like `overmux call`, this discovers a local running server through its private same-user control channel. It queries the identity resolved by that running server, never reloads local configuration, and does not verify HTTP or WebSocket reachability.
9
+
10
+ ```sh
11
+ overmux instance
12
+ overmux instance --port 4242 --json
13
+ # {"instanceId":"rich-work-4242","deepLinkPrefix":"overmux://rich-work-4242"}
14
+
15
+ prefix=$(overmux instance --json | jq -r .deepLinkPrefix)
16
+ printf '%s/tmux/$71/@647/%%25647\n' "$prefix"
17
+ ```
18
+
19
+ | Flag | Description |
20
+ | --- | --- |
21
+ | `--port <value>, -p <value>` | Select a running local server when several are available |
22
+ | `--json` | Print only a JSON object with `instanceId` and `deepLinkPrefix` |
23
+
24
+ The prefix has no trailing slash. Append your application route, encoding each path segment once: pane ID `%647` becomes `%25647`. An instance ID is a lookup key, not a hostname, network address, or credential. The desktop associates it with URLs learned from authenticated server connections.
@@ -1,4 +1,4 @@
1
- import { C as ContractInputArguments } from "./index-D3_Dpy_T.js";
1
+ import { R as InstanceIdentity, w as ContractInputArguments } from "./index-DS70rKzo.js";
2
2
  import { z } from "zod";
3
3
  import { UseMutationResult } from "@tanstack/react-query";
4
4
  import { CSSProperties, ComponentType, ReactNode, RefObject } from "react";
@@ -6,6 +6,14 @@ import { KeyBinding, KeyBinding as KeyBinding$1, formatKeyBinding, keyBindingSch
6
6
  declare const enableBackgroundNotifications: () => Promise<boolean>;
7
7
  declare const disableBackgroundNotifications: () => Promise<void>;
8
8
  type DesktopHost = {
9
+ version: 1;
10
+ platform: string;
11
+ instance?: {
12
+ report: (identity: {
13
+ instanceId: string;
14
+ }) => void;
15
+ version: 1;
16
+ };
9
17
  clipboard?: {
10
18
  writeText: (text: string) => void;
11
19
  version: 1;
@@ -35,7 +43,11 @@ type OperationId<TConfig> = Extract<keyof Operations$1<TConfig>, string>;
35
43
  type OperationInput<TConfig, TId extends OperationId<TConfig>> = InputOf$1<Operations$1<TConfig>[TId]>;
36
44
  type OperationOutput<TConfig, TId extends OperationId<TConfig>> = OutputOf$1<Operations$1<TConfig>[TId]>;
37
45
  type OperationArguments<TInput extends z.ZodType> = [...ContractInputArguments<TInput>, signal?: AbortSignal];
38
- type OvermuxServerApi<TServerConfig> = {
46
+ type InstanceGetters = {
47
+ getInstanceId: () => string | undefined;
48
+ getDeepLinkPrefix: () => string | undefined;
49
+ };
50
+ type OvermuxServerApi<TServerConfig> = InstanceGetters & {
39
51
  executeOperation: <TId extends OperationId<TServerConfig>>(id: TId, ...args: OperationArguments<OperationInput<TServerConfig, TId>>) => Promise<OperationOutput<TServerConfig, TId>>;
40
52
  };
41
53
  type OvermuxScheme = "dark" | "light" | "system";
@@ -235,6 +247,7 @@ type OperationResult<TInputSchema extends z.ZodType, TOutput> = Omit<UseMutation
235
247
  mutateAsync: (...args: ContractInputArguments<TInputSchema>) => Promise<TOutput>;
236
248
  };
237
249
  declare const createOvermuxHooks: <TServerConfig>() => {
250
+ useInstance: () => InstanceIdentity | undefined;
238
251
  useOperation: <TId extends Extract<keyof Operations<TServerConfig>, string>>({ id, signal }: {
239
252
  id: TId;
240
253
  signal?: AbortSignal;
@@ -250,5 +263,5 @@ type ShortcutInputTarget = {
250
263
  input: RefObject<HTMLElement | null>;
251
264
  };
252
265
  declare const useShortcutInputTarget: (target: ShortcutInputTarget) => void;
253
- export { type ChordPrefix, type CommandBinding, type CommandEntry, type CommandHandle, type ConditionalShortcutBinding, type KeyBinding, type KeySequence, type OvermuxClientAppearance, type OvermuxContrast, type OvermuxExternalPortalContainer, OvermuxHost, OvermuxPortal, type OvermuxPortalProps, type OvermuxScheme, type OvermuxServerApi, type OvermuxStyle, OvermuxThemeScope, type OvermuxThemeScopeProps, type OvermuxThemeToken, type ResourceResult, type ShortcutBinding, type ShortcutInputTarget, type SkipToken, type StreamResult, chordPrefixSchema, commandBindingSchema, createOvermuxHooks, defineCommandRegistry, defineOvermuxClient, disableBackgroundNotifications, enableBackgroundNotifications, formatKeyBinding, formatShortcutBinding, keyBindingSchema, matchesKeyBinding, readClipboardText, shortcutBindingSchema, skipToken, useCommand, useCommands, useShortcutInputTarget, writeClipboardText };
266
+ export { type ChordPrefix, type CommandBinding, type CommandEntry, type CommandHandle, type ConditionalShortcutBinding, type InstanceIdentity, type KeyBinding, type KeySequence, type OvermuxClientAppearance, type OvermuxContrast, type OvermuxExternalPortalContainer, OvermuxHost, OvermuxPortal, type OvermuxPortalProps, type OvermuxScheme, type OvermuxServerApi, type OvermuxStyle, OvermuxThemeScope, type OvermuxThemeScopeProps, type OvermuxThemeToken, type ResourceResult, type ShortcutBinding, type ShortcutInputTarget, type SkipToken, type StreamResult, chordPrefixSchema, commandBindingSchema, createOvermuxHooks, defineCommandRegistry, defineOvermuxClient, disableBackgroundNotifications, enableBackgroundNotifications, formatKeyBinding, formatShortcutBinding, keyBindingSchema, matchesKeyBinding, readClipboardText, shortcutBindingSchema, skipToken, useCommand, useCommands, useShortcutInputTarget, writeClipboardText };
254
267
  //# sourceMappingURL=client.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"client.d.ts","names":[],"sources":["../../src/internal/client/background-notifications.ts","../../src/internal/client/host/desktop-host.ts","../../src/internal/client/clipboard.ts","../../src/internal/client/browser-api.ts","../../src/internal/client/theme-scope.tsx","../../src/internal/client/client-definition.ts","../../src/internal/client/commands.tsx","../../src/internal/client/overmux-react.ts","../../src/internal/client/host/overmux-host.tsx","../../src/internal/client/shortcuts.tsx"],"mappings":"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"}
1
+ {"version":3,"file":"client.d.ts","names":[],"sources":["../../src/internal/client/background-notifications.ts","../../src/internal/client/host/desktop-host.ts","../../src/internal/client/clipboard.ts","../../src/internal/client/browser-api.ts","../../src/internal/client/theme-scope.tsx","../../src/internal/client/client-definition.ts","../../src/internal/client/commands.tsx","../../src/internal/client/overmux-react.ts","../../src/internal/client/host/overmux-host.tsx","../../src/internal/client/shortcuts.tsx"],"mappings":"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"}
@@ -1,8 +1,8 @@
1
1
  import "./style.css";
2
- import { i as overmuxLogoutPath, r as notificationSchema, s as resolveOvermuxReturnTo } from "./notifications-kDp16bU_.js";
2
+ import { a as notificationSchema, l as resolveOvermuxReturnTo, o as overmuxLogoutPath, r as instanceIdSchema, t as createInstanceIdentity } from "./notifications-av0FK0yZ.js";
3
3
  import { z } from "zod";
4
4
  import { QueryClient, QueryClientProvider, useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
5
- import { Component, createContext, createElement, useCallback, useContext, useEffect, useMemo, useReducer, useRef, useState } from "react";
5
+ import { Component, createContext, createElement, useCallback, useContext, useEffect, useMemo, useReducer, useRef, useState, useSyncExternalStore } from "react";
6
6
  import { formatKeyBinding, formatKeyBinding as formatKeyBinding$1, keyBindingSchema, keyBindingSchema as keyBindingSchema$1, matchesKeyBinding, matchesKeyBinding as matchesKeyBinding$1, platformBinding } from "@overmux/keybindings";
7
7
  import { createPortal } from "react-dom";
8
8
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
@@ -28,7 +28,7 @@ const webSocketCloseCode = {
28
28
  const runtimeManifestSchema = z.object({
29
29
  debug: z.boolean(),
30
30
  operations: z.array(z.string().min(1)),
31
- protocolVersion: z.literal(9),
31
+ protocolVersion: z.literal(10),
32
32
  resources: z.array(z.string().min(1)),
33
33
  streams: z.array(z.string().min(1))
34
34
  });
@@ -134,7 +134,12 @@ const protocolErrorMessageSchema = z.object({
134
134
  subscriptionId: operationIdSchema.optional(),
135
135
  type: z.literal("error")
136
136
  });
137
+ const serverInfoMessageSchema = z.object({
138
+ type: z.literal("server-info"),
139
+ instanceId: instanceIdSchema
140
+ }).strict();
137
141
  const serverProtocolMessageSchema = z.discriminatedUnion("type", [
142
+ serverInfoMessageSchema,
138
143
  resourceResultMessageSchema,
139
144
  resourceInvalidatedMessageSchema,
140
145
  streamOpenedMessageSchema,
@@ -567,7 +572,13 @@ const useStreamById = (id, input) => {
567
572
  subscribe
568
573
  };
569
574
  };
575
+ const undiscoveredInstance = () => void 0;
576
+ const useInstance = () => {
577
+ const { overmuxServerApi } = useRuntime();
578
+ return useSyncExternalStore(overmuxServerApi.subscribeInstance, overmuxServerApi.getInstance, undiscoveredInstance);
579
+ };
570
580
  const createOvermuxHooks = () => ({
581
+ useInstance,
571
582
  useOperation: ({ id, signal }) => {
572
583
  return useOperationById(id, signal);
573
584
  },
@@ -614,6 +625,10 @@ const availableName = (names, kind, name) => {
614
625
  return name;
615
626
  };
616
627
  const createOvermuxServerApi = ({ manifest, transport }) => ({
628
+ getInstance: transport.getInstance,
629
+ subscribeInstance: transport.subscribeInstance,
630
+ getInstanceId: () => transport.getInstance()?.instanceId,
631
+ getDeepLinkPrefix: () => transport.getInstance()?.deepLinkPrefix,
617
632
  executeOperation: (id, input, signal) => {
618
633
  if (!manifest.operations.includes(id)) throw new Error(`Operation is not available: ${id}`);
619
634
  return transport.invokeOperation({
@@ -731,6 +746,23 @@ const installNotificationForwarding = (transport) => transport.subscribeNotifica
731
746
  if (notification.success) window.overmuxHost?.notifications?.show(notification.data);
732
747
  });
733
748
  //#endregion
749
+ //#region src/internal/client/host/instance-forwarding.ts
750
+ const installInstanceForwarding = (transport) => {
751
+ const report = () => {
752
+ const identity = transport.getInstance();
753
+ const bridge = window.overmuxHost?.instance;
754
+ if (!identity || bridge?.version !== 1) return;
755
+ try {
756
+ bridge.report({ instanceId: identity.instanceId });
757
+ } catch (cause) {
758
+ console.error("Overmux host instance reporting failed", cause);
759
+ }
760
+ };
761
+ const unsubscribe = transport.subscribeInstance(report);
762
+ report();
763
+ return unsubscribe;
764
+ };
765
+ //#endregion
734
766
  //#region src/internal/client/shortcuts.tsx
735
767
  const bindingSequence = (binding) => typeof binding === "string" ? [binding] : [...binding];
736
768
  const normalizedBinding = (binding) => bindingSequence(binding).map((key) => platformBinding(key));
@@ -941,6 +973,12 @@ const createWebSocketTransport = ({ createSocket = () => new WebSocket(socketUrl
941
973
  let reconnectTimer;
942
974
  let socket;
943
975
  let status = "disconnected";
976
+ let instance;
977
+ const instanceListeners = /* @__PURE__ */ new Set();
978
+ const setInstance = (next) => {
979
+ instance = next;
980
+ instanceListeners.forEach((listener) => listener());
981
+ };
944
982
  const diagnosticQueue = [];
945
983
  const requests = /* @__PURE__ */ new Map();
946
984
  const subscriptions = /* @__PURE__ */ new Map();
@@ -954,7 +992,7 @@ const createWebSocketTransport = ({ createSocket = () => new WebSocket(socketUrl
954
992
  statusListeners.forEach((listener) => listener(status));
955
993
  };
956
994
  const send = (message) => {
957
- if (socket?.readyState !== WebSocket.OPEN) return false;
995
+ if (socket?.readyState !== WebSocket.OPEN || !instance) return false;
958
996
  if (socket.bufferedAmount > maxWebSocketBufferedBytes) {
959
997
  socket.close(1013, "client could not keep up");
960
998
  return false;
@@ -1008,6 +1046,7 @@ const createWebSocketTransport = ({ createSocket = () => new WebSocket(socketUrl
1008
1046
  requests.clear();
1009
1047
  };
1010
1048
  const reportDisconnect = () => {
1049
+ setInstance(void 0);
1011
1050
  const error = disconnected();
1012
1051
  rejectRequests(error);
1013
1052
  subscriptions.forEach(({ onError }) => onError(error));
@@ -1023,15 +1062,8 @@ const createWebSocketTransport = ({ createSocket = () => new WebSocket(socketUrl
1023
1062
  const next = createSocket();
1024
1063
  next.binaryType = "arraybuffer";
1025
1064
  socket = next;
1026
- next.addEventListener("open", () => {
1027
- if (socket !== next) return;
1028
- reconnectDelay = 250;
1029
- setStatus("connected");
1030
- flushDiagnostics();
1031
- restore();
1032
- });
1033
1065
  next.addEventListener("message", (event) => {
1034
- if (socket !== next) return;
1066
+ if (socket !== next || disposed) return;
1035
1067
  let decoded;
1036
1068
  try {
1037
1069
  decoded = decodeProtocolFrame(event.data);
@@ -1049,6 +1081,19 @@ const createWebSocketTransport = ({ createSocket = () => new WebSocket(socketUrl
1049
1081
  return;
1050
1082
  }
1051
1083
  const message = parsed.data;
1084
+ if (message.type === "server-info" && !instance) {
1085
+ setInstance(createInstanceIdentity(message.instanceId));
1086
+ reconnectDelay = 250;
1087
+ setStatus("connected");
1088
+ flushDiagnostics();
1089
+ restore();
1090
+ return;
1091
+ }
1092
+ if (!instance || message.type === "server-info") {
1093
+ reportDisconnect();
1094
+ next.close(1002, "expected server discovery before traffic");
1095
+ return;
1096
+ }
1052
1097
  if (message.type === "update-available" || message.type === "restarting") lifecycleListeners.forEach((listener) => listener(message));
1053
1098
  if (message.type === "notification") notificationListeners.forEach((listener) => listener(message));
1054
1099
  if (message.type === "resource-invalidated") subscriptions.get(message.subscriptionId)?.onInvalidate();
@@ -1102,6 +1147,11 @@ const createWebSocketTransport = ({ createSocket = () => new WebSocket(socketUrl
1102
1147
  });
1103
1148
  };
1104
1149
  return {
1150
+ getInstance: () => instance,
1151
+ subscribeInstance: (listener) => {
1152
+ instanceListeners.add(listener);
1153
+ return () => instanceListeners.delete(listener);
1154
+ },
1105
1155
  activate: () => {
1106
1156
  active = true;
1107
1157
  connect();
@@ -1135,7 +1185,7 @@ const createWebSocketTransport = ({ createSocket = () => new WebSocket(socketUrl
1135
1185
  streamName
1136
1186
  };
1137
1187
  streams.set(streamId, stream);
1138
- stream.status = socket?.readyState === WebSocket.CONNECTING || send({
1188
+ stream.status = status === "connecting" || send({
1139
1189
  input,
1140
1190
  operationId: streamId,
1141
1191
  streamId,
@@ -1561,7 +1611,43 @@ const UpdatePopover = ({ transport }) => {
1561
1611
  });
1562
1612
  };
1563
1613
  //#endregion
1614
+ //#region src/internal/client/host/environment.ts
1615
+ const browserPlatform = (navigator) => {
1616
+ const { userAgent, maxTouchPoints } = navigator;
1617
+ const identity = `${navigator.userAgentData?.platform ?? navigator.platform} ${userAgent}`;
1618
+ if (/iPad|iPhone|iPod/i.test(identity) || /Mac/i.test(identity) && maxTouchPoints > 1) return "ios";
1619
+ if (/Android/i.test(identity)) return "android";
1620
+ if (/Win/i.test(identity)) return "windows";
1621
+ if (/Mac/i.test(identity)) return "macos";
1622
+ return /Linux/i.test(identity) ? "linux" : "unknown";
1623
+ };
1624
+ const desktopPlatform = (platform) => {
1625
+ if (platform === "darwin") return "macos";
1626
+ if (platform === "win32") return "windows";
1627
+ return platform === "linux" ? "linux" : "unknown";
1628
+ };
1629
+ const installEnvironmentSelectors = () => {
1630
+ const html = document.documentElement;
1631
+ const host = window.overmuxHost;
1632
+ const desktop = host?.version === 1;
1633
+ const navigator = window.navigator;
1634
+ html.dataset.omPlatform = desktop ? desktopPlatform(host.platform) : browserPlatform(navigator);
1635
+ if (desktop) {
1636
+ html.dataset.omHost = "desktop";
1637
+ return () => {};
1638
+ }
1639
+ const displayMode = window.matchMedia("(display-mode: standalone), (display-mode: minimal-ui), (display-mode: window-controls-overlay)");
1640
+ const updateHost = () => {
1641
+ html.dataset.omHost = displayMode.matches || navigator.standalone === true ? "pwa" : "browser";
1642
+ };
1643
+ updateHost();
1644
+ displayMode.addEventListener("change", updateHost);
1645
+ return () => displayMode.removeEventListener("change", updateHost);
1646
+ };
1647
+ //#endregion
1564
1648
  //#region src/internal/client/host/overmux-host.tsx
1649
+ const disposeEnvironment = typeof window === "undefined" ? void 0 : installEnvironmentSelectors();
1650
+ import.meta.hot?.dispose(() => disposeEnvironment?.());
1565
1651
  var RootErrorBoundary = class extends Component {
1566
1652
  state = {};
1567
1653
  static getDerivedStateFromError(error) {
@@ -1616,6 +1702,7 @@ const OvermuxRuntime = ({ definition }) => {
1616
1702
  transport.dispose();
1617
1703
  }, [transport]);
1618
1704
  useEffect(() => installNotificationForwarding(transport), [transport]);
1705
+ useEffect(() => installInstanceForwarding(transport), [transport]);
1619
1706
  const refreshCommands = useCallback(() => setRegistrationRevision((revision) => revision + 1), []);
1620
1707
  const registerCommand = useCallback((registration) => {
1621
1708
  registrations.add(registration);