overmux 0.0.2 → 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.
- package/CHANGELOG.md +21 -0
- package/dist/auth/.vite/manifest.json +2 -2
- package/dist/auth/assets/{index-Bx8JhwVi.css → index-BM9gETvx.css} +1 -1
- package/dist/auth/assets/{index-CHIE7qYj.js → index-DabAfcs1.js} +1 -1
- package/dist/auth/index.html +2 -2
- package/dist/bin.js +430 -18
- package/dist/bin.js.map +1 -1
- package/dist/docs/200-getting-started/100-install-and-run-overmux.md +1 -2
- package/dist/docs/300-fundamentals/100-project-structure.md +20 -0
- package/dist/docs/300-fundamentals/300-theming.md +51 -0
- package/dist/docs/400-reference/100-configuration.md +20 -0
- package/dist/docs/400-reference/200-server-api.md +18 -0
- package/dist/docs/400-reference/300-client-api.md +36 -0
- package/dist/docs/400-reference/400-cli/050-init.md +17 -0
- package/dist/docs/400-reference/400-cli/350-instance.md +24 -0
- package/dist/exports/client.d.ts +33 -3
- package/dist/exports/client.d.ts.map +1 -1
- package/dist/exports/client.js +123 -14
- package/dist/exports/client.js.map +1 -1
- package/dist/exports/{index-D3_Dpy_T.d.ts → index-DS70rKzo.d.ts} +14 -2
- package/dist/exports/index-DS70rKzo.d.ts.map +1 -0
- package/dist/exports/index.d.ts +2 -2
- package/dist/exports/index.js +1 -1
- package/dist/exports/index.js.map +1 -1
- package/dist/exports/{notifications-kDp16bU_.js → notifications-av0FK0yZ.js} +7 -2
- package/dist/exports/{notifications-kDp16bU_.js.map → notifications-av0FK0yZ.js.map} +1 -1
- package/dist/exports/server.d.ts.map +1 -1
- package/dist/exports/server.js +52 -10
- package/dist/exports/server.js.map +1 -1
- package/dist/internal/server/coordinator/server-child.js +110 -46
- package/dist/internal/server/coordinator/server-child.js.map +1 -1
- package/docs/200-getting-started/100-install-and-run-overmux.md +1 -2
- package/docs/300-fundamentals/100-project-structure.md +20 -0
- package/docs/300-fundamentals/300-theming.md +51 -0
- package/docs/400-reference/100-configuration.md +20 -0
- package/docs/400-reference/200-server-api.md +18 -0
- package/docs/400-reference/300-client-api.md +36 -0
- package/docs/400-reference/400-cli/050-init.md +17 -0
- package/docs/400-reference/400-cli/350-instance.md +24 -0
- package/package.json +2 -2
- package/src/internal/cli/app.ts +7 -1
- package/src/internal/cli/commands/init-template.ts +146 -0
- package/src/internal/cli/commands/init.ts +267 -0
- package/src/internal/cli/commands/instance.ts +58 -0
- package/src/internal/cli/commands/integration.ts +15 -0
- package/src/internal/cli/commands/zellij-install.ts +96 -0
- package/src/internal/cli/parse-port.ts +2 -1
- package/src/internal/client/auth/auth-shell.css +17 -1
- package/src/internal/client/auth/auth-shell.tsx +2 -11
- package/src/internal/client/auth/login-code-input.tsx +140 -0
- package/src/internal/client/browser-api.ts +17 -3
- package/src/internal/client/clipboard.ts +22 -0
- package/src/internal/client/host/desktop-host.ts +15 -0
- package/src/internal/client/host/environment.ts +67 -0
- package/src/internal/client/host/instance-forwarding.ts +21 -0
- package/src/internal/client/host/notification-forwarding.ts +1 -10
- package/src/internal/client/host/overmux-host.tsx +8 -0
- package/src/internal/client/overmux-react.ts +24 -2
- package/src/internal/client/websocket.ts +48 -20
- package/src/internal/server/auth/instance-control.ts +24 -3
- package/src/internal/server/runtime/create-runtime.ts +12 -1
- package/src/internal/server/runtime/runtime-instance.ts +46 -0
- package/src/internal/server/runtime/runtime-resources.ts +3 -0
- package/src/internal/server/server-startup-options.ts +9 -4
- package/src/internal/server/start-application-server.ts +20 -12
- package/src/internal/server/websocket-server.ts +7 -0
- package/src/internal/shared/index.ts +2 -0
- package/src/internal/shared/protocol.ts +10 -1
- package/src/public/client.ts +5 -0
- package/src/public/config.ts +7 -0
- package/src/public/index.ts +2 -0
- package/dist/exports/index-D3_Dpy_T.d.ts.map +0 -1
|
@@ -37,7 +37,7 @@ Once the CLI is installed, create your Overmux setup:
|
|
|
37
37
|
overmux init
|
|
38
38
|
```
|
|
39
39
|
|
|
40
|
-
This
|
|
40
|
+
This validates your toolchain, creates a minimal application in `$XDG_CONFIG_HOME/overmux`, installs its dependencies, and checks the result. Existing scaffold files are left unchanged. Read more in the [`overmux init` reference](../400-reference/400-cli/050-init.md) and [project structure](../300-fundamentals/100-project-structure.md).
|
|
41
41
|
|
|
42
42
|
## Start the server
|
|
43
43
|
|
|
@@ -48,4 +48,3 @@ overmux serve
|
|
|
48
48
|
Open Overmux in your browser to confirm it works.
|
|
49
49
|
|
|
50
50
|
To configure hosts and ports, see [Configuration](../300-fundamentals/200-configuration.md).
|
|
51
|
-
|
|
@@ -1,3 +1,23 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: Project Structure
|
|
3
3
|
---
|
|
4
|
+
|
|
5
|
+
`overmux init` creates this minimal userland application:
|
|
6
|
+
|
|
7
|
+
```text
|
|
8
|
+
.gitignore
|
|
9
|
+
mise.toml Mise installations only
|
|
10
|
+
package.json
|
|
11
|
+
pnpm-lock.yaml
|
|
12
|
+
overmux.config.ts authentication, server, Vite, and production settings
|
|
13
|
+
src/server/index.ts trusted resources, streams, and operations
|
|
14
|
+
src/ui/app.tsx browser application definition
|
|
15
|
+
src/ui/index.html browser document
|
|
16
|
+
src/ui/main.tsx React and Overmux host entry point
|
|
17
|
+
src/ui/styles.css application styles
|
|
18
|
+
vite.config.ts browser development and production build configuration
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
The server and UI are separate trust boundaries. `src/server/index.ts` runs as trusted Node.js code. Files under `src/ui` run in the browser and communicate with the server through Overmux's public APIs.
|
|
22
|
+
|
|
23
|
+
The generated application has no shared directory. Add browser-safe shared schemas only when both sides need them.
|
|
@@ -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.
|
|
@@ -1,3 +1,39 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: Client API
|
|
3
3
|
---
|
|
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
|
+
|
|
24
|
+
## Clipboard
|
|
25
|
+
|
|
26
|
+
```ts
|
|
27
|
+
import { readClipboardText, writeClipboardText } from "overmux/client";
|
|
28
|
+
|
|
29
|
+
await writeClipboardText("Text to copy");
|
|
30
|
+
const text = await readClipboardText();
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
`readClipboardText(): Promise<string>` reads the system clipboard through `navigator.clipboard.readText()`. It never reads through the desktop bridge.
|
|
34
|
+
|
|
35
|
+
`writeClipboardText(text: string): Promise<void>` uses Overmux's version-1 desktop write bridge when present, otherwise `navigator.clipboard.writeText()`. Desktop writes are fire-and-forget: resolution confirms dispatch, not completion or acceptance by the host. Existing host origin and active-frame checks still apply.
|
|
36
|
+
|
|
37
|
+
Both reject on unavailable browser APIs, browser permission failures, or synchronous desktop dispatch failures. Browser secure-context, focus, permissions, and user-activation restrictions still apply. These APIs target the system clipboard, not the X11 primary selection. Only read clipboard data you need and trust the source of text you write.
|
|
38
|
+
|
|
39
|
+
For terminal-program access via OSC 52, use the opt-in factories from `@overmux/xterm/client` rather than wiring platform bridges in application code.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: "overmux init"
|
|
3
|
+
---
|
|
4
|
+
|
|
5
|
+
# `overmux init`
|
|
6
|
+
|
|
7
|
+
Create a minimal, runnable Overmux application without prompting.
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
overmux init
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
The application is created in `$XDG_CONFIG_HOME/overmux`.
|
|
14
|
+
|
|
15
|
+
The command validates the toolchain before writing files. When Mise is installed, it must be [activated in the shell](https://mise.jdx.dev/getting-started.html#activate-mise); the generated `mise.toml` pins Node 22, pnpm 10, and the latest published Overmux version. Without Mise, pnpm 10 or newer must already be available and `mise.toml` is omitted.
|
|
16
|
+
|
|
17
|
+
The initializer pins the exact latest published `overmux` version in `package.json`, installs dependencies, generates `pnpm-lock.yaml`, and runs `overmux check`. Existing scaffold files cause the command to fail without changing them. Unrelated files are preserved.
|
|
@@ -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.
|
package/dist/exports/client.d.ts
CHANGED
|
@@ -1,10 +1,35 @@
|
|
|
1
|
-
import {
|
|
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";
|
|
5
5
|
import { KeyBinding, KeyBinding as KeyBinding$1, formatKeyBinding, keyBindingSchema, matchesKeyBinding } from "@overmux/keybindings";
|
|
6
6
|
declare const enableBackgroundNotifications: () => Promise<boolean>;
|
|
7
7
|
declare const disableBackgroundNotifications: () => Promise<void>;
|
|
8
|
+
type DesktopHost = {
|
|
9
|
+
version: 1;
|
|
10
|
+
platform: string;
|
|
11
|
+
instance?: {
|
|
12
|
+
report: (identity: {
|
|
13
|
+
instanceId: string;
|
|
14
|
+
}) => void;
|
|
15
|
+
version: 1;
|
|
16
|
+
};
|
|
17
|
+
clipboard?: {
|
|
18
|
+
writeText: (text: string) => void;
|
|
19
|
+
version: 1;
|
|
20
|
+
};
|
|
21
|
+
notifications?: {
|
|
22
|
+
show: (notification: unknown) => void;
|
|
23
|
+
version: 1;
|
|
24
|
+
};
|
|
25
|
+
};
|
|
26
|
+
declare global {
|
|
27
|
+
interface Window {
|
|
28
|
+
overmuxHost?: DesktopHost;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
declare const readClipboardText: () => Promise<string>;
|
|
32
|
+
declare const writeClipboardText: (text: string) => Promise<void>;
|
|
8
33
|
type Operations$1<TConfig> = TConfig extends {
|
|
9
34
|
operations?: infer TOperations;
|
|
10
35
|
} ? NonNullable<TOperations> : never;
|
|
@@ -18,7 +43,11 @@ type OperationId<TConfig> = Extract<keyof Operations$1<TConfig>, string>;
|
|
|
18
43
|
type OperationInput<TConfig, TId extends OperationId<TConfig>> = InputOf$1<Operations$1<TConfig>[TId]>;
|
|
19
44
|
type OperationOutput<TConfig, TId extends OperationId<TConfig>> = OutputOf$1<Operations$1<TConfig>[TId]>;
|
|
20
45
|
type OperationArguments<TInput extends z.ZodType> = [...ContractInputArguments<TInput>, signal?: AbortSignal];
|
|
21
|
-
type
|
|
46
|
+
type InstanceGetters = {
|
|
47
|
+
getInstanceId: () => string | undefined;
|
|
48
|
+
getDeepLinkPrefix: () => string | undefined;
|
|
49
|
+
};
|
|
50
|
+
type OvermuxServerApi<TServerConfig> = InstanceGetters & {
|
|
22
51
|
executeOperation: <TId extends OperationId<TServerConfig>>(id: TId, ...args: OperationArguments<OperationInput<TServerConfig, TId>>) => Promise<OperationOutput<TServerConfig, TId>>;
|
|
23
52
|
};
|
|
24
53
|
type OvermuxScheme = "dark" | "light" | "system";
|
|
@@ -218,6 +247,7 @@ type OperationResult<TInputSchema extends z.ZodType, TOutput> = Omit<UseMutation
|
|
|
218
247
|
mutateAsync: (...args: ContractInputArguments<TInputSchema>) => Promise<TOutput>;
|
|
219
248
|
};
|
|
220
249
|
declare const createOvermuxHooks: <TServerConfig>() => {
|
|
250
|
+
useInstance: () => InstanceIdentity | undefined;
|
|
221
251
|
useOperation: <TId extends Extract<keyof Operations<TServerConfig>, string>>({ id, signal }: {
|
|
222
252
|
id: TId;
|
|
223
253
|
signal?: AbortSignal;
|
|
@@ -233,5 +263,5 @@ type ShortcutInputTarget = {
|
|
|
233
263
|
input: RefObject<HTMLElement | null>;
|
|
234
264
|
};
|
|
235
265
|
declare const useShortcutInputTarget: (target: ShortcutInputTarget) => void;
|
|
236
|
-
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, shortcutBindingSchema, skipToken, useCommand, useCommands, useShortcutInputTarget };
|
|
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 };
|
|
237
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/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":";;;;;;cAyJa,qCAA6B;cAkB7B,sCAA8B;;;
|
|
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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"}
|
package/dist/exports/client.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import "./style.css";
|
|
2
|
-
import {
|
|
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(
|
|
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,
|
|
@@ -299,6 +304,21 @@ const reconciledStatus = async () => {
|
|
|
299
304
|
return "enabled";
|
|
300
305
|
};
|
|
301
306
|
//#endregion
|
|
307
|
+
//#region src/internal/client/clipboard.ts
|
|
308
|
+
const readClipboardText = async () => {
|
|
309
|
+
if (!globalThis.navigator?.clipboard?.readText) throw new Error("Clipboard reading is unavailable in this browser context");
|
|
310
|
+
return navigator.clipboard.readText();
|
|
311
|
+
};
|
|
312
|
+
const writeClipboardText = async (text) => {
|
|
313
|
+
const desktopClipboard = globalThis.window?.overmuxHost?.clipboard;
|
|
314
|
+
if (desktopClipboard?.version === 1) {
|
|
315
|
+
desktopClipboard.writeText(text);
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
if (!globalThis.navigator?.clipboard?.writeText) throw new Error("Clipboard writing is unavailable in this browser context");
|
|
319
|
+
await navigator.clipboard.writeText(text);
|
|
320
|
+
};
|
|
321
|
+
//#endregion
|
|
302
322
|
//#region src/internal/client/client-definition.ts
|
|
303
323
|
const shortcutBindingSchema = z.union([keyBindingSchema$1, z.array(keyBindingSchema$1).min(2)]);
|
|
304
324
|
const commandBindingSchema = z.union([shortcutBindingSchema, z.object({
|
|
@@ -552,7 +572,13 @@ const useStreamById = (id, input) => {
|
|
|
552
572
|
subscribe
|
|
553
573
|
};
|
|
554
574
|
};
|
|
575
|
+
const undiscoveredInstance = () => void 0;
|
|
576
|
+
const useInstance = () => {
|
|
577
|
+
const { overmuxServerApi } = useRuntime();
|
|
578
|
+
return useSyncExternalStore(overmuxServerApi.subscribeInstance, overmuxServerApi.getInstance, undiscoveredInstance);
|
|
579
|
+
};
|
|
555
580
|
const createOvermuxHooks = () => ({
|
|
581
|
+
useInstance,
|
|
556
582
|
useOperation: ({ id, signal }) => {
|
|
557
583
|
return useOperationById(id, signal);
|
|
558
584
|
},
|
|
@@ -599,6 +625,10 @@ const availableName = (names, kind, name) => {
|
|
|
599
625
|
return name;
|
|
600
626
|
};
|
|
601
627
|
const createOvermuxServerApi = ({ manifest, transport }) => ({
|
|
628
|
+
getInstance: transport.getInstance,
|
|
629
|
+
subscribeInstance: transport.subscribeInstance,
|
|
630
|
+
getInstanceId: () => transport.getInstance()?.instanceId,
|
|
631
|
+
getDeepLinkPrefix: () => transport.getInstance()?.deepLinkPrefix,
|
|
602
632
|
executeOperation: (id, input, signal) => {
|
|
603
633
|
if (!manifest.operations.includes(id)) throw new Error(`Operation is not available: ${id}`);
|
|
604
634
|
return transport.invokeOperation({
|
|
@@ -716,6 +746,23 @@ const installNotificationForwarding = (transport) => transport.subscribeNotifica
|
|
|
716
746
|
if (notification.success) window.overmuxHost?.notifications?.show(notification.data);
|
|
717
747
|
});
|
|
718
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
|
|
719
766
|
//#region src/internal/client/shortcuts.tsx
|
|
720
767
|
const bindingSequence = (binding) => typeof binding === "string" ? [binding] : [...binding];
|
|
721
768
|
const normalizedBinding = (binding) => bindingSequence(binding).map((key) => platformBinding(key));
|
|
@@ -926,6 +973,12 @@ const createWebSocketTransport = ({ createSocket = () => new WebSocket(socketUrl
|
|
|
926
973
|
let reconnectTimer;
|
|
927
974
|
let socket;
|
|
928
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
|
+
};
|
|
929
982
|
const diagnosticQueue = [];
|
|
930
983
|
const requests = /* @__PURE__ */ new Map();
|
|
931
984
|
const subscriptions = /* @__PURE__ */ new Map();
|
|
@@ -939,7 +992,7 @@ const createWebSocketTransport = ({ createSocket = () => new WebSocket(socketUrl
|
|
|
939
992
|
statusListeners.forEach((listener) => listener(status));
|
|
940
993
|
};
|
|
941
994
|
const send = (message) => {
|
|
942
|
-
if (socket?.readyState !== WebSocket.OPEN) return false;
|
|
995
|
+
if (socket?.readyState !== WebSocket.OPEN || !instance) return false;
|
|
943
996
|
if (socket.bufferedAmount > maxWebSocketBufferedBytes) {
|
|
944
997
|
socket.close(1013, "client could not keep up");
|
|
945
998
|
return false;
|
|
@@ -993,6 +1046,7 @@ const createWebSocketTransport = ({ createSocket = () => new WebSocket(socketUrl
|
|
|
993
1046
|
requests.clear();
|
|
994
1047
|
};
|
|
995
1048
|
const reportDisconnect = () => {
|
|
1049
|
+
setInstance(void 0);
|
|
996
1050
|
const error = disconnected();
|
|
997
1051
|
rejectRequests(error);
|
|
998
1052
|
subscriptions.forEach(({ onError }) => onError(error));
|
|
@@ -1008,15 +1062,8 @@ const createWebSocketTransport = ({ createSocket = () => new WebSocket(socketUrl
|
|
|
1008
1062
|
const next = createSocket();
|
|
1009
1063
|
next.binaryType = "arraybuffer";
|
|
1010
1064
|
socket = next;
|
|
1011
|
-
next.addEventListener("open", () => {
|
|
1012
|
-
if (socket !== next) return;
|
|
1013
|
-
reconnectDelay = 250;
|
|
1014
|
-
setStatus("connected");
|
|
1015
|
-
flushDiagnostics();
|
|
1016
|
-
restore();
|
|
1017
|
-
});
|
|
1018
1065
|
next.addEventListener("message", (event) => {
|
|
1019
|
-
if (socket !== next) return;
|
|
1066
|
+
if (socket !== next || disposed) return;
|
|
1020
1067
|
let decoded;
|
|
1021
1068
|
try {
|
|
1022
1069
|
decoded = decodeProtocolFrame(event.data);
|
|
@@ -1034,6 +1081,19 @@ const createWebSocketTransport = ({ createSocket = () => new WebSocket(socketUrl
|
|
|
1034
1081
|
return;
|
|
1035
1082
|
}
|
|
1036
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
|
+
}
|
|
1037
1097
|
if (message.type === "update-available" || message.type === "restarting") lifecycleListeners.forEach((listener) => listener(message));
|
|
1038
1098
|
if (message.type === "notification") notificationListeners.forEach((listener) => listener(message));
|
|
1039
1099
|
if (message.type === "resource-invalidated") subscriptions.get(message.subscriptionId)?.onInvalidate();
|
|
@@ -1087,6 +1147,11 @@ const createWebSocketTransport = ({ createSocket = () => new WebSocket(socketUrl
|
|
|
1087
1147
|
});
|
|
1088
1148
|
};
|
|
1089
1149
|
return {
|
|
1150
|
+
getInstance: () => instance,
|
|
1151
|
+
subscribeInstance: (listener) => {
|
|
1152
|
+
instanceListeners.add(listener);
|
|
1153
|
+
return () => instanceListeners.delete(listener);
|
|
1154
|
+
},
|
|
1090
1155
|
activate: () => {
|
|
1091
1156
|
active = true;
|
|
1092
1157
|
connect();
|
|
@@ -1101,6 +1166,13 @@ const createWebSocketTransport = ({ createSocket = () => new WebSocket(socketUrl
|
|
|
1101
1166
|
socket?.close();
|
|
1102
1167
|
},
|
|
1103
1168
|
openStream: ({ input, onClose, onError, onMessage, onOpen, streamName }) => {
|
|
1169
|
+
if (!active || disposed) {
|
|
1170
|
+
onError(disconnected());
|
|
1171
|
+
return {
|
|
1172
|
+
close: () => {},
|
|
1173
|
+
send: () => false
|
|
1174
|
+
};
|
|
1175
|
+
}
|
|
1104
1176
|
const streamId = operationId();
|
|
1105
1177
|
const stream = {
|
|
1106
1178
|
input,
|
|
@@ -1113,7 +1185,7 @@ const createWebSocketTransport = ({ createSocket = () => new WebSocket(socketUrl
|
|
|
1113
1185
|
streamName
|
|
1114
1186
|
};
|
|
1115
1187
|
streams.set(streamId, stream);
|
|
1116
|
-
stream.status = send({
|
|
1188
|
+
stream.status = status === "connecting" || send({
|
|
1117
1189
|
input,
|
|
1118
1190
|
operationId: streamId,
|
|
1119
1191
|
streamId,
|
|
@@ -1539,7 +1611,43 @@ const UpdatePopover = ({ transport }) => {
|
|
|
1539
1611
|
});
|
|
1540
1612
|
};
|
|
1541
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
|
|
1542
1648
|
//#region src/internal/client/host/overmux-host.tsx
|
|
1649
|
+
const disposeEnvironment = typeof window === "undefined" ? void 0 : installEnvironmentSelectors();
|
|
1650
|
+
import.meta.hot?.dispose(() => disposeEnvironment?.());
|
|
1543
1651
|
var RootErrorBoundary = class extends Component {
|
|
1544
1652
|
state = {};
|
|
1545
1653
|
static getDerivedStateFromError(error) {
|
|
@@ -1594,6 +1702,7 @@ const OvermuxRuntime = ({ definition }) => {
|
|
|
1594
1702
|
transport.dispose();
|
|
1595
1703
|
}, [transport]);
|
|
1596
1704
|
useEffect(() => installNotificationForwarding(transport), [transport]);
|
|
1705
|
+
useEffect(() => installInstanceForwarding(transport), [transport]);
|
|
1597
1706
|
const refreshCommands = useCallback(() => setRegistrationRevision((revision) => revision + 1), []);
|
|
1598
1707
|
const registerCommand = useCallback((registration) => {
|
|
1599
1708
|
registrations.add(registration);
|
|
@@ -1638,6 +1747,6 @@ const OvermuxHost = ({ definition }) => /* @__PURE__ */ jsx(OvermuxThemeScope, {
|
|
|
1638
1747
|
children: location.pathname === "/_overmux/settings" ? /* @__PURE__ */ jsx(HostedSettingsPage, {}) : location.pathname === "/_overmux/logout" ? /* @__PURE__ */ jsx(HostedLogoutPage, {}) : /* @__PURE__ */ jsx(OvermuxRuntime, { definition })
|
|
1639
1748
|
});
|
|
1640
1749
|
//#endregion
|
|
1641
|
-
export { OvermuxHost, OvermuxPortal, OvermuxThemeScope, chordPrefixSchema, commandBindingSchema, createOvermuxHooks, defineCommandRegistry, defineOvermuxClient, disableBackgroundNotifications, enableBackgroundNotifications, formatKeyBinding, formatShortcutBinding, keyBindingSchema, matchesKeyBinding, shortcutBindingSchema, skipToken, useCommand, useCommands, useShortcutInputTarget };
|
|
1750
|
+
export { OvermuxHost, OvermuxPortal, OvermuxThemeScope, chordPrefixSchema, commandBindingSchema, createOvermuxHooks, defineCommandRegistry, defineOvermuxClient, disableBackgroundNotifications, enableBackgroundNotifications, formatKeyBinding, formatShortcutBinding, keyBindingSchema, matchesKeyBinding, readClipboardText, shortcutBindingSchema, skipToken, useCommand, useCommands, useShortcutInputTarget, writeClipboardText };
|
|
1642
1751
|
|
|
1643
1752
|
//# sourceMappingURL=client.js.map
|