overmux 0.0.4 → 0.0.5

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 (141) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/README.md +2 -2
  3. package/dist/bin.js +140 -127
  4. package/dist/bin.js.map +1 -1
  5. package/dist/docs/000-index.md +2 -4
  6. package/dist/docs/100-introduction/200-how-overmux-works.md +126 -2
  7. package/dist/docs/100-introduction/{300-why-overmux.md → 300-why-i-built-overmux.md} +1 -1
  8. package/dist/docs/200-getting-started/100-install-and-run-overmux.md +2 -2
  9. package/dist/docs/200-getting-started/400-secure-with-https/200-tailscale-serve.md +3 -3
  10. package/dist/docs/200-getting-started/400-secure-with-https/300-cloudflare-tunnel.md +2 -2
  11. package/dist/docs/200-getting-started/400-secure-with-https/400-self-hosted-reverse-proxy.md +2 -2
  12. package/dist/docs/400-reference/100-project-structure.md +83 -0
  13. package/dist/docs/400-reference/200-configuration.md +257 -0
  14. package/dist/docs/400-reference/300-storage-locations.md +46 -0
  15. package/dist/docs/400-reference/400-authentication-and-security.md +37 -0
  16. package/dist/docs/400-reference/500-server/000-index.md +13 -0
  17. package/dist/docs/400-reference/500-server/100-resources.md +191 -0
  18. package/dist/docs/400-reference/500-server/200-operations.md +111 -0
  19. package/dist/docs/400-reference/500-server/300-streams.md +140 -0
  20. package/dist/docs/400-reference/500-server/400-notifications.md +32 -0
  21. package/dist/docs/400-reference/500-server/500-api.md +118 -0
  22. package/dist/docs/400-reference/600-client/000-index.md +9 -0
  23. package/dist/docs/400-reference/600-client/100-api.md +370 -0
  24. package/dist/docs/400-reference/600-client/200-theming.md +94 -0
  25. package/dist/docs/400-reference/600-client/300-tech-stack-recommendations.md +12 -0
  26. package/dist/docs/400-reference/{400-cli → 700-cli}/050-init.md +2 -4
  27. package/{docs/400-reference/400-cli → dist/docs/400-reference/700-cli}/100-serve.md +9 -4
  28. package/{docs/400-reference/400-cli → dist/docs/400-reference/700-cli}/200-auth.md +1 -4
  29. package/dist/docs/400-reference/{400-cli → 700-cli}/300-call.md +1 -4
  30. package/dist/docs/400-reference/{400-cli → 700-cli}/350-instance.md +1 -4
  31. package/dist/docs/400-reference/700-cli/600-docs.md +128 -0
  32. package/dist/docs/400-reference/{400-cli → 700-cli}/700-desktop.md +1 -3
  33. package/dist/docs/500-hosted-pages.md +0 -1
  34. package/dist/exports/client.d.ts +5 -14
  35. package/dist/exports/client.d.ts.map +1 -1
  36. package/dist/exports/client.js +141 -46
  37. package/dist/exports/client.js.map +1 -1
  38. package/dist/exports/{index-DS70rKzo.d.ts → index-Cz3xkCa4.d.ts} +50 -36
  39. package/dist/exports/index-Cz3xkCa4.d.ts.map +1 -0
  40. package/dist/exports/index.d.ts +1 -1
  41. package/dist/exports/index.js +19 -5
  42. package/dist/exports/index.js.map +1 -1
  43. package/dist/exports/{notifications-av0FK0yZ.js → notifications-BFAD3QQl.js} +29 -4
  44. package/dist/exports/notifications-BFAD3QQl.js.map +1 -0
  45. package/dist/exports/server.d.ts +1 -44
  46. package/dist/exports/server.d.ts.map +1 -1
  47. package/dist/exports/server.js +9 -1061
  48. package/dist/exports/server.js.map +1 -1
  49. package/dist/internal/server/coordinator/server-child.js +47 -43
  50. package/dist/internal/server/coordinator/server-child.js.map +1 -1
  51. package/docs/000-index.md +2 -4
  52. package/docs/100-introduction/200-how-overmux-works.md +126 -2
  53. package/docs/100-introduction/{300-why-overmux.md → 300-why-i-built-overmux.md} +1 -1
  54. package/docs/200-getting-started/100-install-and-run-overmux.md +2 -2
  55. package/docs/200-getting-started/400-secure-with-https/200-tailscale-serve.md +3 -3
  56. package/docs/200-getting-started/400-secure-with-https/300-cloudflare-tunnel.md +2 -2
  57. package/docs/200-getting-started/400-secure-with-https/400-self-hosted-reverse-proxy.md +2 -2
  58. package/docs/400-reference/100-project-structure.md +83 -0
  59. package/docs/400-reference/200-configuration.md +257 -0
  60. package/docs/400-reference/300-storage-locations.md +46 -0
  61. package/docs/400-reference/400-authentication-and-security.md +37 -0
  62. package/docs/400-reference/500-server/000-index.md +13 -0
  63. package/docs/400-reference/500-server/100-resources.md +191 -0
  64. package/docs/400-reference/500-server/200-operations.md +111 -0
  65. package/docs/400-reference/500-server/300-streams.md +140 -0
  66. package/docs/400-reference/500-server/400-notifications.md +32 -0
  67. package/docs/400-reference/500-server/500-api.md +118 -0
  68. package/docs/400-reference/600-client/000-index.md +9 -0
  69. package/docs/400-reference/600-client/100-api.md +370 -0
  70. package/docs/400-reference/600-client/200-theming.md +94 -0
  71. package/docs/400-reference/600-client/300-tech-stack-recommendations.md +12 -0
  72. package/docs/400-reference/{400-cli → 700-cli}/050-init.md +2 -4
  73. package/{dist/docs/400-reference/400-cli → docs/400-reference/700-cli}/100-serve.md +9 -4
  74. package/{dist/docs/400-reference/400-cli → docs/400-reference/700-cli}/200-auth.md +1 -4
  75. package/docs/400-reference/{400-cli → 700-cli}/300-call.md +1 -4
  76. package/docs/400-reference/{400-cli → 700-cli}/350-instance.md +1 -4
  77. package/docs/400-reference/700-cli/600-docs.md +128 -0
  78. package/docs/400-reference/{400-cli → 700-cli}/700-desktop.md +1 -3
  79. package/docs/500-hosted-pages.md +0 -1
  80. package/package.json +3 -2
  81. package/src/internal/cli/app.ts +3 -5
  82. package/src/internal/cli/commands/docs-ai-context.ts +33 -0
  83. package/src/internal/cli/commands/docs.ts +19 -2
  84. package/src/internal/cli/commands/init-template.ts +1 -1
  85. package/src/internal/cli/commands/serve.ts +3 -0
  86. package/src/internal/cli/login.ts +9 -9
  87. package/src/internal/client/client-definition.ts +6 -8
  88. package/src/internal/client/host/deep-link-navigation.ts +75 -0
  89. package/src/internal/client/host/overmux-host.tsx +9 -0
  90. package/src/internal/client/index.ts +0 -6
  91. package/src/internal/client/overmux-react.ts +71 -40
  92. package/src/internal/server/auth/auth-service.ts +2 -2
  93. package/src/internal/server/auth/instance-control.ts +65 -14
  94. package/src/internal/server/coordinator/ipc-protocol.ts +0 -1
  95. package/src/internal/server/runtime/create-runtime.ts +5 -3
  96. package/src/internal/server/runtime/runtime-instance.ts +5 -4
  97. package/src/internal/server/runtime/runtime-operations.ts +9 -3
  98. package/src/internal/server/runtime/runtime-resources.ts +12 -32
  99. package/src/internal/server/runtime/runtime-streams.ts +5 -6
  100. package/src/internal/server/server-logger.ts +5 -10
  101. package/src/internal/server/server-startup-options.ts +5 -10
  102. package/src/internal/server/start-application-server.ts +4 -7
  103. package/src/public/ai-context.ts +7 -29
  104. package/src/public/client.ts +0 -6
  105. package/src/public/config.ts +156 -31
  106. package/src/public/server.ts +1 -16
  107. package/dist/docs/100-introduction/100-what-is-overmux.md +0 -7
  108. package/dist/docs/300-fundamentals/100-project-structure.md +0 -23
  109. package/dist/docs/300-fundamentals/200-configuration.md +0 -3
  110. package/dist/docs/300-fundamentals/300-theming.md +0 -54
  111. package/dist/docs/300-fundamentals/400-server.md +0 -3
  112. package/dist/docs/300-fundamentals/500-client.md +0 -3
  113. package/dist/docs/300-fundamentals/600-operations.md +0 -3
  114. package/dist/docs/300-fundamentals/700-resources.md +0 -3
  115. package/dist/docs/300-fundamentals/800-streams.md +0 -3
  116. package/dist/docs/300-fundamentals/900-authentication-and-security.md +0 -3
  117. package/dist/docs/400-reference/100-configuration.md +0 -23
  118. package/dist/docs/400-reference/200-server-api.md +0 -21
  119. package/dist/docs/400-reference/300-client-api.md +0 -39
  120. package/dist/docs/400-reference/400-cli/400-check.md +0 -20
  121. package/dist/docs/400-reference/400-cli/500-ai-context.md +0 -102
  122. package/dist/docs/400-reference/400-cli/600-docs.md +0 -23
  123. package/dist/exports/index-DS70rKzo.d.ts.map +0 -1
  124. package/dist/exports/notifications-av0FK0yZ.js.map +0 -1
  125. package/docs/100-introduction/100-what-is-overmux.md +0 -7
  126. package/docs/300-fundamentals/100-project-structure.md +0 -23
  127. package/docs/300-fundamentals/200-configuration.md +0 -3
  128. package/docs/300-fundamentals/300-theming.md +0 -54
  129. package/docs/300-fundamentals/400-server.md +0 -3
  130. package/docs/300-fundamentals/500-client.md +0 -3
  131. package/docs/300-fundamentals/600-operations.md +0 -3
  132. package/docs/300-fundamentals/700-resources.md +0 -3
  133. package/docs/300-fundamentals/800-streams.md +0 -3
  134. package/docs/300-fundamentals/900-authentication-and-security.md +0 -3
  135. package/docs/400-reference/100-configuration.md +0 -23
  136. package/docs/400-reference/200-server-api.md +0 -21
  137. package/docs/400-reference/300-client-api.md +0 -39
  138. package/docs/400-reference/400-cli/400-check.md +0 -20
  139. package/docs/400-reference/400-cli/500-ai-context.md +0 -102
  140. package/docs/400-reference/400-cli/600-docs.md +0 -23
  141. package/src/internal/cli/commands/ai.ts +0 -44
@@ -0,0 +1,191 @@
1
+ ---
2
+ title: Resources
3
+ ---
4
+
5
+ Resources expose server-side data to your Overmux UI.
6
+
7
+ There are three kinds of resource: [query](#query), [subscription](#subscription), and [derived](#derived).
8
+
9
+ ## Query
10
+
11
+ Query resources read server-side data on request.
12
+
13
+ For example, to run `ls /` on your server and expose the result:
14
+
15
+ ```ts
16
+ // server.ts
17
+ defineOvermuxServer({
18
+ resources: {
19
+ ls: {
20
+ kind: "query",
21
+ contract: defineResourceContract({
22
+ input: noInputSchema,
23
+ output: z.array(z.string()),
24
+ }),
25
+ read: async () => {
26
+ const { stdout } = await execFileAsync("ls", ["/"]);
27
+ return stdout.split("\n").filter(Boolean);
28
+ },
29
+ },
30
+ },
31
+ });
32
+ ```
33
+
34
+ See [Accessing resources from your Overmux UI](#accessing-resources-from-your-overmux-ui) to display the listing in React.
35
+
36
+ ## Subscription
37
+
38
+ Subscription resources read server-side data and notify clients when it changes.
39
+
40
+ To keep the `ls /` listing up to date, watch the directory for changes:
41
+
42
+ ```ts
43
+ import { watch } from "node:fs";
44
+
45
+ // server.ts
46
+ defineOvermuxServer({
47
+ resources: {
48
+ ls: {
49
+ kind: "subscription",
50
+ contract: defineResourceContract({
51
+ input: noInputSchema,
52
+ output: z.array(z.string()),
53
+ }),
54
+ read: async () => {
55
+ const { stdout } = await execFileAsync("ls", ["/"]);
56
+ return stdout.split("\n").filter(Boolean);
57
+ },
58
+ subscribe: (_input, invalidate) => {
59
+ // Watch the root directory for filesystem changes.
60
+ const watcher = watch("/", () => {
61
+ // Tell Overmux the data may have changed so it reads it again.
62
+ invalidate();
63
+ });
64
+ // Subscription cleanup function.
65
+ return () => watcher.close();
66
+ },
67
+ },
68
+ },
69
+ });
70
+ ```
71
+
72
+ When the subscription ends, Overmux calls the cleanup function returned by `subscribe`. In this example, it closes the filesystem watcher.
73
+
74
+ The React code stays the same: `useResource({ id: "ls" })`.
75
+
76
+ ## Derived
77
+
78
+ Derived resources compute a value from other resources.
79
+
80
+ For example, count the entries returned by the `ls` resource above. Add `entryCount` alongside `ls` in your `resources` object:
81
+
82
+ ```ts
83
+ defineOvermuxServer({
84
+ resources: {
85
+ ls: {
86
+ // The subscription resource above:
87
+ // reads ls / and watches for directory changes.
88
+ },
89
+ entryCount: {
90
+ kind: "derived",
91
+ contract: defineResourceContract({
92
+ input: noInputSchema,
93
+ output: z.number(),
94
+ }),
95
+ dependencies: { ls: "ls" },
96
+ combine: ({ ls }) => ls.length,
97
+ },
98
+ },
99
+ });
100
+ ```
101
+
102
+ `dependencies` maps the names used in `combine` to resource IDs. Here, `combine` receives the value of `ls` and returns its length.
103
+
104
+ If `ls` returns `["bin", "etc", "home"]`, `entryCount` returns `3`. With the subscription version of `ls`, the count updates when the directory listing changes.
105
+
106
+ Access it from your UI with `useResource({ id: "entryCount" })`.
107
+
108
+ ## Accessing resources from your Overmux UI
109
+
110
+ Use `useResource` to access query, subscription, and derived resources. Create your typed hooks with `createOvermuxHooks` from `overmux/client`:
111
+
112
+ ```ts
113
+ // hooks.ts
114
+ import { createOvermuxHooks } from "overmux/client";
115
+ import type { serverConfig } from "./server";
116
+
117
+ export const { useResource } = createOvermuxHooks<typeof serverConfig>();
118
+ ```
119
+
120
+ Here, `serverConfig` is the exported result of `defineOvermuxServer`. The type-only import provides type checking without including your server code in the browser.
121
+
122
+ Use the hook inside a component under your Overmux provider:
123
+
124
+ ```tsx
125
+ import { useResource } from "./hooks";
126
+
127
+ const DirectoryListing = () => {
128
+ const ls = useResource({ id: "ls" });
129
+
130
+ if (ls.status === "pending") return <p>Loading...</p>;
131
+ if (ls.status === "error") return <p>{ls.error.message}</p>;
132
+
133
+ return (
134
+ <div>
135
+ {ls.data.map((name) => (
136
+ <div key={name}>{name}</div>
137
+ ))}
138
+ </div>
139
+ );
140
+ };
141
+ ```
142
+
143
+ The same component works with either `ls` example above. Overmux handles reads and change notifications, updating your component when fresh data arrives.
144
+
145
+ See [Client API: Resources](../600-client/100-api.md#resources) for input arguments, return values, and manual refreshes.
146
+
147
+ ## Invalidating resources
148
+
149
+ After server-side data changes, call `invalidate()` to tell clients: **“Your data may be out of date. Read this resource again.”**
150
+
151
+ Clients will request the data by calling the resource's `read` function again.
152
+
153
+ ### From a subscription
154
+
155
+ Call the `invalidate` callback provided to `subscribe` when your watcher detects a change:
156
+
157
+ ```ts
158
+ subscribe: (_input, invalidate) => {
159
+ const watcher = watch("/", () => {
160
+ // Tell clients to read the directory listing again.
161
+ invalidate();
162
+ });
163
+
164
+ return () => watcher.close();
165
+ },
166
+ ```
167
+
168
+ ### From an operation
169
+
170
+ After changing server-side state in an [operation](./200-operations.md), call `context.invalidate(resourceId)`:
171
+
172
+ ```ts
173
+ handle: async ({ path }, context) => {
174
+ await mkdir(path);
175
+
176
+ // Refresh clients using the directory listing resource.
177
+ context.invalidate("ls");
178
+ },
179
+ ```
180
+
181
+ Pass the resource's key in `resources`. Here, `"ls"` identifies the directory listing.
182
+
183
+ Omit the second argument to invalidate all inputs. For a resource that accepts input, pass it to refresh only matching data: `context.invalidate("files", { path: "/" })`.
184
+
185
+ ## How resources work
186
+
187
+ Resources communicate over a persistent WebSocket connection between your browser and server. This connection lets the client request data and the server send change notifications.
188
+
189
+ When you call `useResource`, the client requests the resource's value. For subscription resources, it also listens for change notifications.
190
+
191
+ Calling `invalidate()` tells the client its data may be stale. It does not send the updated value; the client requests a fresh read, and React updates with the result.
@@ -0,0 +1,111 @@
1
+ ---
2
+ title: Operations
3
+ ---
4
+
5
+ Operations expose server-side functions you can call from your UI or the `overmux call` CLI.
6
+
7
+ ## Defining an operation
8
+
9
+ Define operations in your server's `operations` object:
10
+
11
+ ```ts
12
+ // server.ts
13
+ export const serverConfig = defineOvermuxServer({
14
+ operations: {
15
+ echo: {
16
+ input: z.object({ message: z.string() }),
17
+ output: z.string(),
18
+ handle: ({ message }) => message,
19
+ },
20
+ },
21
+ });
22
+ ```
23
+
24
+ The object key, `echo`, is the operation's ID. `handle` runs on your Overmux server machine and returns the message it receives.
25
+
26
+ ### Input and output
27
+
28
+ Use [Zod schemas](https://zod.dev/) to define the input an operation accepts and the result it returns. Here, `echo` accepts an object with a `message` string and returns that string unchanged.
29
+
30
+ Handlers can be asynchronous, so you can run commands, access files, or call other services before returning a result.
31
+
32
+ ### Handler API
33
+
34
+ The `handle` function receives the operation's input and a `context` object:
35
+
36
+ ```ts
37
+ handle: async (input, context) => {
38
+ // Run your server-side logic here.
39
+ },
40
+ ```
41
+
42
+ `context` provides:
43
+
44
+ - **`invalidate(resourceId, input?)`**: tells clients to read an affected resource again after you change server-side data. See [Invalidating resources](./100-resources.md#invalidating-resources).
45
+ - **[`notifications.send(...)`](./400-notifications.md)**: sends a notification through Overmux.
46
+
47
+ See [Server API](./500-api.md#handler-context) for the full handler context.
48
+
49
+ ## Calling operations from your Overmux UI
50
+
51
+ Create typed hooks with `createOvermuxHooks` from `overmux/client`:
52
+
53
+ ```ts
54
+ // hooks.ts
55
+ import { createOvermuxHooks } from "overmux/client";
56
+ import type { serverConfig } from "./server";
57
+
58
+ export const { useOperation } = createOvermuxHooks<typeof serverConfig>();
59
+ ```
60
+
61
+ The type-only import provides type checking without including server code in the browser.
62
+
63
+ Use the hook inside a component under your Overmux provider:
64
+
65
+ ```tsx
66
+ import { useOperation } from "./hooks";
67
+
68
+ const EchoButton = () => {
69
+ const echo = useOperation({ id: "echo" });
70
+
71
+ return (
72
+ <button onClick={() => echo.mutate({ message: "Hello world" })}>
73
+ Echo message
74
+ </button>
75
+ );
76
+ };
77
+ ```
78
+
79
+ Pass the operation's input to `mutate`.
80
+
81
+ Use `mutateAsync` when you need to await the result:
82
+
83
+ ```ts
84
+ const message = await echo.mutateAsync({ message: "Hello world" });
85
+ ```
86
+
87
+ See [Client API](../600-client/100-api.md) for operation hooks, pending state, errors, and results.
88
+
89
+ ## Calling operations from the CLI
90
+
91
+ Call an operation by its ID and pass input as JSON:
92
+
93
+ ```sh
94
+ overmux call echo --input '{"message":"Hello world"}'
95
+ ```
96
+
97
+ The CLI prints the returned result as JSON:
98
+
99
+ ```json
100
+ "Hello world"
101
+ ```
102
+
103
+ Agents can use the same CLI commands to call your operations.
104
+
105
+ ## How operations work
106
+
107
+ Each call sends an HTTP `POST` to `/api/operations/{operationName}`, with any input encoded as JSON.
108
+
109
+ Overmux handles authentication, validates the input, and calls your handler. If an output schema is defined, Overmux validates the result before returning it.
110
+
111
+ Unlike resource subscriptions, an operation is a single request and response. It returns a result or an error; it does not keep listening for updates.
@@ -0,0 +1,140 @@
1
+ ---
2
+ title: Streams
3
+ ---
4
+
5
+ Streams send and receive messages between your Overmux UI and server over a persistent connection. Use them for ongoing communication, such as terminal input and output or live logs.
6
+
7
+ Unlike [operations](./200-operations.md), streams can send and receive multiple messages. Unlike [resources](./100-resources.md), they deliver individual messages rather than a value clients read again when it changes.
8
+
9
+ ## Defining a stream
10
+
11
+ Define streams in your server's `streams` object:
12
+
13
+ ```ts
14
+ // server.ts
15
+ import {
16
+ defineOvermuxServer,
17
+ defineStreamContract,
18
+ defineStreamHandler,
19
+ noInputSchema,
20
+ } from "overmux";
21
+ import { z } from "zod";
22
+
23
+ const echoContract = defineStreamContract({
24
+ input: noInputSchema,
25
+ clientMessage: z.object({ message: z.string() }),
26
+ serverMessage: z.object({ message: z.string() }),
27
+ });
28
+
29
+ export const serverConfig = defineOvermuxServer({
30
+ streams: {
31
+ echo: defineStreamHandler(echoContract, (_input, { emit }) => ({
32
+ onMessage: ({ message }) => {
33
+ emit({ message });
34
+ },
35
+ })),
36
+ },
37
+ });
38
+ ```
39
+
40
+ The object key, `echo`, is the stream's ID. Each time a client opens the stream, Overmux calls its handler to create a session.
41
+
42
+ Here, `onMessage` receives a message from the client and `emit` sends it back to that client.
43
+
44
+ ### Input and messages
45
+
46
+ Use [Zod schemas](https://zod.dev/) to define:
47
+
48
+ - **`input`**: the input provided when opening the stream.
49
+ - **`clientMessage`**: messages sent from the UI to the server.
50
+ - **`serverMessage`**: messages sent from the server to the UI.
51
+
52
+ This example needs no opening input. Other streams might accept a terminal ID or a log file name.
53
+
54
+ The server can also call `emit` independently of client messages, for example when a process produces output.
55
+
56
+ ## Accessing streams from your Overmux UI
57
+
58
+ Create typed hooks with `createOvermuxHooks` from `overmux/client`:
59
+
60
+ ```ts
61
+ // hooks.ts
62
+ import { createOvermuxHooks } from "overmux/client";
63
+ import type { serverConfig } from "./server";
64
+
65
+ export const { useStream } = createOvermuxHooks<typeof serverConfig>();
66
+ ```
67
+
68
+ The type-only import provides type checking without including server code in the browser.
69
+
70
+ Use the hook inside a component under your Overmux provider:
71
+
72
+ ```tsx
73
+ import { useEffect, useState } from "react";
74
+ import { useStream } from "./hooks";
75
+
76
+ const Echo = () => {
77
+ const { status, error, send, subscribe } = useStream({ id: "echo" });
78
+ const [message, setMessage] = useState("");
79
+
80
+ useEffect(
81
+ () => subscribe(({ message }) => setMessage(message)),
82
+ [subscribe],
83
+ );
84
+
85
+ if (error) return <p>{error.message}</p>;
86
+
87
+ return (
88
+ <div>
89
+ <button
90
+ disabled={status !== "open"}
91
+ onClick={() => send({ message: "Hello world" })}
92
+ >
93
+ Send message
94
+ </button>
95
+ <p>{message}</p>
96
+ </div>
97
+ );
98
+ };
99
+ ```
100
+
101
+ `send` sends a client message. `subscribe` registers a listener for server messages and returns a function that removes it, which the effect uses for cleanup.
102
+
103
+ Unlike `useResource`, `useStream` does not store the latest message as `data`. Your component decides how to display or process incoming messages.
104
+
105
+ See [Client API: Streams](../600-client/100-api.md#streams) for connection state and reconnection details.
106
+
107
+ ## Cleaning up a stream
108
+
109
+ Return `dispose` from your handler to release resources when the session closes:
110
+
111
+ ```ts
112
+ defineStreamHandler(echoContract, (_input, { emit }) => {
113
+ const timer = setInterval(() => {
114
+ emit({ message: "Still connected" });
115
+ }, 1_000);
116
+
117
+ return {
118
+ onMessage: ({ message }) => {
119
+ emit({ message });
120
+ },
121
+ dispose: () => {
122
+ clearInterval(timer);
123
+ },
124
+ };
125
+ });
126
+ ```
127
+
128
+ Overmux calls `dispose` once when the session closes. Use it to stop timers, remove listeners, or release other session-owned resources.
129
+
130
+ `useStream` closes its session when the component unmounts. You can also close it explicitly with `close()`.
131
+
132
+ The handler context provides an abort `signal` for cancelling background work and `fail(cause)` for failing and closing the session. See [Server API: Stream handlers](./500-api.md#stream-handlers).
133
+
134
+ ## How streams work
135
+
136
+ Streams communicate over a persistent WebSocket connection between your browser and server.
137
+
138
+ Overmux validates the opening input and messages against the stream contract. Client messages are passed to `onMessage` in order; calls to `emit` send messages to that session's client.
139
+
140
+ A restored stream after a WebSocket reconnect creates a new server session. Do not assume that state held by the previous session survives.
@@ -0,0 +1,32 @@
1
+ ---
2
+ title: Notifications
3
+ ---
4
+
5
+ Send notifications from an [operation handler](./200-operations.md#handler-api) using `context.notifications.send()`. There is no separate notification API to import; Overmux provides it through the handler's `context`:
6
+
7
+ ```ts
8
+ // server.ts
9
+ import { defineOperation, defineOvermuxServer, noInputSchema } from "overmux";
10
+
11
+ export const serverConfig = defineOvermuxServer({
12
+ resources: {},
13
+ operations: {
14
+ myOperation: defineOperation({
15
+ input: noInputSchema,
16
+ handle: async (_input, context) => {
17
+ await context.notifications.send({
18
+ title: "Task finished",
19
+ body: "Your results are ready.",
20
+ open: { link: "/results" },
21
+ });
22
+ },
23
+ }),
24
+ },
25
+ });
26
+ ```
27
+
28
+ - `title`: required, non-empty text.
29
+ - `body`: optional text.
30
+ - `open.link`: optional destination to open when the notification is activated. Use an app-relative path starting with `/` or an HTTP(S) URL without credentials.
31
+
32
+ Each text field and link has a maximum length of 4,096 characters. `send()` returns `Promise<void>`.
@@ -0,0 +1,118 @@
1
+ ---
2
+ title: Server API
3
+ ---
4
+
5
+ ## Server definitions
6
+
7
+ Import definition helpers from `overmux`:
8
+
9
+ ```ts
10
+ import {
11
+ defineOperation,
12
+ defineOvermuxServer,
13
+ defineResourceContract,
14
+ defineStreamContract,
15
+ defineStreamHandler,
16
+ } from "overmux";
17
+ ```
18
+
19
+ `defineOvermuxServer()` defines the capabilities available from one server. It preserves types for `overmux/client` hooks and defaults omitted operation output schemas to `z.void()`.
20
+
21
+ ```ts
22
+ export const serverConfig = defineOvermuxServer({
23
+ resources: {
24
+ // Resource definitions, keyed by resource ID.
25
+ },
26
+ operations: {
27
+ // defineOperation(...) values, keyed by operation ID.
28
+ },
29
+ streams: {
30
+ // defineStreamHandler(...) values, keyed by stream ID.
31
+ },
32
+ });
33
+ ```
34
+
35
+ | Option | Required | Value |
36
+ | --- | --- | --- |
37
+ | `resources` | Yes | An object of query, subscription, or derived resource definitions. |
38
+ | `operations` | No | Inline operation definitions or reusable `defineOperation(...)` values. |
39
+ | `streams` | No | An object of `defineStreamHandler(...)` definitions. |
40
+
41
+ Object keys are the IDs used by clients. See [Resources](./100-resources.md), [Operations](./200-operations.md), and [Streams](./300-streams.md) for usage guides.
42
+
43
+ ## Resource handlers
44
+
45
+ A resource definition has a `contract` created with `defineResourceContract({ input, output })`. Overmux parses handler input with `input` and validates every result with `output`.
46
+
47
+ | Kind | Required handler API |
48
+ | --- | --- |
49
+ | `query` | `read(input, context) => output \| Promise<output>` |
50
+ | `subscription` | `read(input, context)` and `subscribe(input, invalidate, context) => disposer` |
51
+ | `derived` | `dependencies` and `combine(dependencies) => output` |
52
+
53
+ ```ts
54
+ const count = defineResourceContract({
55
+ input: noInputSchema,
56
+ output: z.number(),
57
+ });
58
+
59
+ const resources = {
60
+ count: {
61
+ kind: "subscription",
62
+ contract: count,
63
+ read: () => readCount(),
64
+ subscribe: (_input, invalidate) => {
65
+ const stop = watchCount(invalidate);
66
+ return () => stop();
67
+ },
68
+ },
69
+ };
70
+ ```
71
+
72
+ `subscribe` must synchronously return a cleanup function. Overmux calls it when that client subscription, or the server runtime, closes. A derived resource reads the resources named by `dependencies`; invalidating a dependency also invalidates its dependants. See [Resources](./100-resources.md) for contracts, derived dependencies, and invalidation.
73
+
74
+ ## Stream handlers
75
+
76
+ A stream contract defines `input`, `clientMessage`, and `serverMessage` schemas. Define its handler with:
77
+
78
+ ```ts
79
+ const terminal = defineStreamHandler(contract, (input, context) => ({
80
+ onMessage: async (message) => {
81
+ // Handle a validated client message.
82
+ },
83
+ dispose: async () => {
84
+ // Release per-session resources.
85
+ },
86
+ }));
87
+ ```
88
+
89
+ `open(input, context)` may return the session object or a promise for it. Its context extends the [handler context](#handler-context) with:
90
+
91
+ | API | Purpose |
92
+ | --- | --- |
93
+ | `emit(message)` | Validate and send a server message to this session. Calls after closure are ignored. |
94
+ | `fail(cause)` | Fail and close this session. A later call has no effect. |
95
+
96
+ The returned `StreamSession` may contain:
97
+
98
+ | API | Purpose |
99
+ | --- | --- |
100
+ | `onMessage(message)` | Receive validated client messages. Calls are processed in order. |
101
+ | `dispose()` | Release session resources. It may be async and is called once when the session closes. |
102
+
103
+ The stream `signal` aborts when its session or the runtime closes. Stop background work in response to it, and put resource cleanup in `dispose`. See [Streams](./300-streams.md) for stream usage from the client.
104
+
105
+ ## Handler context
106
+
107
+ Inline resource, operation, and stream handlers infer valid resource IDs and inputs.
108
+
109
+ Resource and stream handlers receive a context with:
110
+
111
+ | API | Purpose |
112
+ | --- | --- |
113
+ | `invalidate(resourceId, input?)` | Ask clients to [read a resource again](./100-resources.md#invalidating-resources). Pass the resource's key in `resources`. Omit `input` to invalidate all inputs; otherwise it is validated and only matching inputs are invalidated. Unknown IDs throw. |
114
+ | `signal` | An `AbortSignal` that aborts when the request or session, or the server runtime, closes. |
115
+ | `instance.getInstanceId()` | Get this server instance's ID. |
116
+ | `instance.getDeepLinkPrefix()` | Get this instance's Overmux deep-link prefix. |
117
+
118
+ Operation handlers receive the same context plus `notifications.send(notification)`, which returns `Promise<void>`. See [Notifications](./400-notifications.md).
@@ -0,0 +1,9 @@
1
+ ---
2
+ title: Client
3
+ ---
4
+
5
+ Overmux's client is your React application, running in a browser or Overmux Desktop.
6
+
7
+ - [Client API](./100-api.md): Define your application, connect to the server, and register commands.
8
+ - [Theming](./200-theming.md): Customize your application's appearance.
9
+ - [Tech Stack Recommendations](./300-tech-stack-recommendations.md): Choose libraries for your UI.