@anvia/react-ui 1.3.0 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (131) hide show
  1. package/dist/attachment/index.d.ts +3 -21
  2. package/dist/attachment/index.js +3 -12
  3. package/dist/attachment-DsKTPumt.js +89 -0
  4. package/dist/attachment-DsKTPumt.js.map +1 -0
  5. package/dist/chat/index.d.ts +3 -152
  6. package/dist/chat/index.js +3 -25
  7. package/dist/chat-CAnvUEAv.js +1210 -0
  8. package/dist/chat-CAnvUEAv.js.map +1 -0
  9. package/dist/completion/index.d.ts +3 -29
  10. package/dist/completion/index.js +3 -16
  11. package/dist/completion-DDTKoZRJ.js +124 -0
  12. package/dist/completion-DDTKoZRJ.js.map +1 -0
  13. package/dist/connection-DeNq8wHS.js +203 -0
  14. package/dist/connection-DeNq8wHS.js.map +1 -0
  15. package/dist/contexts-B4ijG24z.js +212 -0
  16. package/dist/contexts-B4ijG24z.js.map +1 -0
  17. package/dist/elements-D4vmkkF8.js +19 -0
  18. package/dist/elements-D4vmkkF8.js.map +1 -0
  19. package/dist/graph-explorer/index.d.ts +54 -73
  20. package/dist/graph-explorer/index.d.ts.map +1 -0
  21. package/dist/graph-explorer/index.js +181 -248
  22. package/dist/graph-explorer/index.js.map +1 -1
  23. package/dist/human-input/index.d.ts +3 -78
  24. package/dist/human-input/index.js +3 -21
  25. package/dist/human-input-CsCbZomZ.js +314 -0
  26. package/dist/human-input-CsCbZomZ.js.map +1 -0
  27. package/dist/image/index.d.ts +3 -40
  28. package/dist/image/index.js +3 -12
  29. package/dist/image-D_7vaQCR.js +302 -0
  30. package/dist/image-D_7vaQCR.js.map +1 -0
  31. package/dist/index-B1Qs2Cjv.d.ts +145 -0
  32. package/dist/index-B1Qs2Cjv.d.ts.map +1 -0
  33. package/dist/index-BCBVcl0D.d.ts +277 -0
  34. package/dist/index-BCBVcl0D.d.ts.map +1 -0
  35. package/dist/index-CE22tsua.d.ts +20 -0
  36. package/dist/index-CE22tsua.d.ts.map +1 -0
  37. package/dist/index-CGqtpc6b.d.ts +25 -0
  38. package/dist/index-CGqtpc6b.d.ts.map +1 -0
  39. package/dist/index-DqdyM0Jm.d.ts +7 -0
  40. package/dist/index-DqdyM0Jm.d.ts.map +1 -0
  41. package/dist/index-Mw3ltwSG.d.ts +318 -0
  42. package/dist/index-Mw3ltwSG.d.ts.map +1 -0
  43. package/dist/index.d.ts +7 -40
  44. package/dist/index.js +34 -118
  45. package/dist/index.js.map +1 -1
  46. package/dist/message/index.d.ts +3 -105
  47. package/dist/message/index.js +3 -20
  48. package/dist/message-Dn3wW6yy.js +783 -0
  49. package/dist/message-Dn3wW6yy.js.map +1 -0
  50. package/dist/primitives-xfE7zfwJ.js +15 -0
  51. package/dist/primitives-xfE7zfwJ.js.map +1 -0
  52. package/dist/refs-Djj9rSvB.js +10 -0
  53. package/dist/refs-Djj9rSvB.js.map +1 -0
  54. package/dist/sandbox-desktop/index.d.ts +100 -104
  55. package/dist/sandbox-desktop/index.d.ts.map +1 -0
  56. package/dist/sandbox-desktop/index.js +344 -342
  57. package/dist/sandbox-desktop/index.js.map +1 -1
  58. package/dist/sandbox-terminal/index.d.ts +52 -56
  59. package/dist/sandbox-terminal/index.d.ts.map +1 -0
  60. package/dist/sandbox-terminal/index.js +217 -208
  61. package/dist/sandbox-terminal/index.js.map +1 -1
  62. package/dist/selection-toolbar/index.d.ts +3 -21
  63. package/dist/selection-toolbar/index.js +3 -13
  64. package/dist/selection-toolbar-CIkOoM-7.js +171 -0
  65. package/dist/selection-toolbar-CIkOoM-7.js.map +1 -0
  66. package/dist/shared-BSYElFU2.d.ts +2 -0
  67. package/dist/shared.d.ts +4 -14
  68. package/dist/shared.js +1 -43
  69. package/dist/stream/index.d.ts +2 -22
  70. package/dist/stream/index.js +1 -8
  71. package/dist/stream-CAO0x8_1.js +298 -0
  72. package/dist/stream-CAO0x8_1.js.map +1 -0
  73. package/dist/thread-list/index.d.ts +3 -47
  74. package/dist/thread-list/index.js +3 -18
  75. package/dist/thread-list-xJbGXFrE.js +228 -0
  76. package/dist/thread-list-xJbGXFrE.js.map +1 -0
  77. package/dist/ticket-CoJHBpdF.d.ts +32 -0
  78. package/dist/ticket-CoJHBpdF.d.ts.map +1 -0
  79. package/dist/value-BGGrx72L.js +13 -0
  80. package/dist/value-BGGrx72L.js.map +1 -0
  81. package/package.json +22 -22
  82. package/dist/attachment/index.js.map +0 -1
  83. package/dist/attachment-mbjsroli.d.ts +0 -9
  84. package/dist/chat/index.js.map +0 -1
  85. package/dist/chat-PSj1Fo4W.d.ts +0 -88
  86. package/dist/chunk-22EZJUPM.js +0 -120
  87. package/dist/chunk-22EZJUPM.js.map +0 -1
  88. package/dist/chunk-5FZKTDZR.js +0 -201
  89. package/dist/chunk-5FZKTDZR.js.map +0 -1
  90. package/dist/chunk-6XOJFLX4.js +0 -22
  91. package/dist/chunk-6XOJFLX4.js.map +0 -1
  92. package/dist/chunk-CKA4CE26.js +0 -25
  93. package/dist/chunk-CKA4CE26.js.map +0 -1
  94. package/dist/chunk-DLBNFBXQ.js +0 -425
  95. package/dist/chunk-DLBNFBXQ.js.map +0 -1
  96. package/dist/chunk-E73S3SOF.js +0 -404
  97. package/dist/chunk-E73S3SOF.js.map +0 -1
  98. package/dist/chunk-F6AKBUO3.js +0 -380
  99. package/dist/chunk-F6AKBUO3.js.map +0 -1
  100. package/dist/chunk-HGOPGZNQ.js +0 -195
  101. package/dist/chunk-HGOPGZNQ.js.map +0 -1
  102. package/dist/chunk-KHB5CHAU.js +0 -220
  103. package/dist/chunk-KHB5CHAU.js.map +0 -1
  104. package/dist/chunk-LHABOAOP.js +0 -316
  105. package/dist/chunk-LHABOAOP.js.map +0 -1
  106. package/dist/chunk-N5XQU36W.js +0 -410
  107. package/dist/chunk-N5XQU36W.js.map +0 -1
  108. package/dist/chunk-T3ZFZ3NP.js +0 -30
  109. package/dist/chunk-T3ZFZ3NP.js.map +0 -1
  110. package/dist/chunk-T4IYUEPH.js +0 -1612
  111. package/dist/chunk-T4IYUEPH.js.map +0 -1
  112. package/dist/chunk-W2AHKMRS.js +0 -1092
  113. package/dist/chunk-W2AHKMRS.js.map +0 -1
  114. package/dist/completion/index.js.map +0 -1
  115. package/dist/completion-input-DHlwrhxB.d.ts +0 -24
  116. package/dist/composer-6iCSIq6L.d.ts +0 -111
  117. package/dist/human-input/index.js.map +0 -1
  118. package/dist/human-input-CkLrZ8IC.d.ts +0 -27
  119. package/dist/image/index.js.map +0 -1
  120. package/dist/image-VZv6Ddsn.d.ts +0 -14
  121. package/dist/message/index.js.map +0 -1
  122. package/dist/message-CNRnZQwU.d.ts +0 -14
  123. package/dist/render-CRKWam2v.d.ts +0 -8
  124. package/dist/selection-toolbar/index.js.map +0 -1
  125. package/dist/selection-toolbar-Cwjbuv5S.d.ts +0 -14
  126. package/dist/shared.js.map +0 -1
  127. package/dist/stream/index.js.map +0 -1
  128. package/dist/thread-Bz6-1zaJ.d.ts +0 -12
  129. package/dist/thread-list/index.js.map +0 -1
  130. package/dist/thread-list-On8db4XL.d.ts +0 -34
  131. package/dist/ticket-pexI1zIa.d.ts +0 -33
@@ -1,216 +1,225 @@
1
- import {
2
- DefaultStatus,
3
- RelayConnection,
4
- resolveTicket,
5
- ticketSubprotocolPrefix
6
- } from "../chunk-5FZKTDZR.js";
7
-
8
- // src/sandbox-terminal/terminal.tsx
9
- import {
10
- forwardRef,
11
- useEffect,
12
- useImperativeHandle,
13
- useRef,
14
- useState
15
- } from "react";
16
-
1
+ import { i as DefaultStatus, n as ticketSubprotocolPrefix, r as resolveTicket, t as RelayConnection } from "../connection-DeNq8wHS.js";
2
+ import { forwardRef, useEffect, useImperativeHandle, useRef, useState } from "react";
3
+ import { jsx, jsxs } from "react/jsx-runtime";
17
4
  // src/sandbox-terminal/connection.ts
18
- var terminalSubprotocol = "anvia.terminal.v1";
19
- var retryableCodes = /* @__PURE__ */ new Set(["sandbox_unavailable", "timeout"]);
5
+ /** Subprotocol the hub's `handleTerminalUpgrade` requires. */
6
+ const terminalSubprotocol = "anvia.terminal.v1";
7
+ /** Errors worth another attempt: the sandbox may simply not be reachable yet. */
8
+ const retryableCodes = /* @__PURE__ */ new Set(["sandbox_unavailable", "timeout"]);
9
+ /**
10
+ * One browser terminal link: speaks the hub's terminal relay protocol over a {@link
11
+ * RelayConnection}. It knows nothing about xterm, so it is testable on its own.
12
+ */
20
13
  var TerminalConnection = class {
21
- relay;
22
- constructor(options) {
23
- let ready = false;
24
- const protocol = {
25
- subprotocol: terminalSubprotocol,
26
- label: "terminal",
27
- open: (socket) => {
28
- ready = false;
29
- const { cols, rows } = options.size();
30
- socket.send(JSON.stringify({ type: "open", cols, rows }));
31
- },
32
- message: (event, session) => {
33
- if (typeof event.data !== "string") {
34
- if (ready) options.onOutput(new Uint8Array(event.data));
35
- return;
36
- }
37
- const message = parseMessage(event.data);
38
- if (message === void 0) return;
39
- if (message.type === "ready") {
40
- ready = true;
41
- options.onOpen(session.ready());
42
- } else if (message.type === "exit") {
43
- session.ended({ message: message.reason ?? "exited", exitCode: message.exitCode });
44
- } else if (!retryableCodes.has(message.code ?? "")) {
45
- session.fatal(message.message ?? "The terminal could not be opened.");
46
- }
47
- }
48
- };
49
- this.relay = new RelayConnection({
50
- url: options.url,
51
- sessionName: options.sessionName,
52
- getTicket: options.getTicket,
53
- onStatus: options.onStatus,
54
- reconnect: options.reconnect,
55
- protocol
56
- });
57
- }
58
- start() {
59
- this.relay.start();
60
- }
61
- /** Try again now, for a link that gave up. */
62
- retry() {
63
- this.relay.retry();
64
- }
65
- sendInput(data) {
66
- this.relay.sendJson({ type: "input", data });
67
- }
68
- sendResize(cols, rows) {
69
- this.relay.sendJson({ type: "resize", cols, rows });
70
- }
71
- dispose() {
72
- this.relay.dispose();
73
- }
14
+ relay;
15
+ constructor(options) {
16
+ let ready = false;
17
+ const protocol = {
18
+ subprotocol: terminalSubprotocol,
19
+ label: "terminal",
20
+ open: (socket) => {
21
+ ready = false;
22
+ const { cols, rows } = options.size();
23
+ socket.send(JSON.stringify({
24
+ type: "open",
25
+ cols,
26
+ rows
27
+ }));
28
+ },
29
+ message: (event, session) => {
30
+ if (typeof event.data !== "string") {
31
+ if (ready) options.onOutput(new Uint8Array(event.data));
32
+ return;
33
+ }
34
+ const message = parseMessage(event.data);
35
+ if (message === void 0) return;
36
+ if (message.type === "ready") {
37
+ ready = true;
38
+ options.onOpen(session.ready());
39
+ } else if (message.type === "exit") session.ended({
40
+ message: message.reason ?? "exited",
41
+ exitCode: message.exitCode
42
+ });
43
+ else if (!retryableCodes.has(message.code ?? "")) session.fatal(message.message ?? "The terminal could not be opened.");
44
+ }
45
+ };
46
+ this.relay = new RelayConnection({
47
+ url: options.url,
48
+ sessionName: options.sessionName,
49
+ getTicket: options.getTicket,
50
+ onStatus: options.onStatus,
51
+ reconnect: options.reconnect,
52
+ protocol
53
+ });
54
+ }
55
+ start() {
56
+ this.relay.start();
57
+ }
58
+ /** Try again now, for a link that gave up. */
59
+ retry() {
60
+ this.relay.retry();
61
+ }
62
+ sendInput(data) {
63
+ this.relay.sendJson({
64
+ type: "input",
65
+ data
66
+ });
67
+ }
68
+ sendResize(cols, rows) {
69
+ this.relay.sendJson({
70
+ type: "resize",
71
+ cols,
72
+ rows
73
+ });
74
+ }
75
+ dispose() {
76
+ this.relay.dispose();
77
+ }
74
78
  };
75
79
  function parseMessage(text) {
76
- try {
77
- const value = JSON.parse(text);
78
- if (typeof value !== "object" || value === null) return void 0;
79
- const type = value.type;
80
- return type === "ready" || type === "exit" || type === "error" ? value : void 0;
81
- } catch {
82
- return void 0;
83
- }
80
+ try {
81
+ const value = JSON.parse(text);
82
+ if (typeof value !== "object" || value === null) return void 0;
83
+ const type = value.type;
84
+ return type === "ready" || type === "exit" || type === "error" ? value : void 0;
85
+ } catch {
86
+ return;
87
+ }
84
88
  }
85
-
86
89
  // src/sandbox-terminal/terminal.tsx
87
- import { jsx, jsxs } from "react/jsx-runtime";
88
- var rootStyle = { position: "relative", width: "100%", height: "100%" };
89
- var screenStyle = { width: "100%", height: "100%" };
90
- var SandboxTerminal = forwardRef(
91
- function SandboxTerminal2({
92
- url,
93
- sessionName,
94
- ticket,
95
- readOnly = false,
96
- reconnect,
97
- terminalOptions,
98
- onStatusChange,
99
- renderStatus,
100
- style,
101
- ...rest
102
- }, ref) {
103
- const screen = useRef(null);
104
- const connection = useRef(void 0);
105
- const terminal = useRef(void 0);
106
- const [status, setStatus] = useState({ state: "loading" });
107
- const latest = useRef({ ticket, reconnect, terminalOptions, onStatusChange });
108
- latest.current = { ticket, reconnect, terminalOptions, onStatusChange };
109
- useImperativeHandle(
110
- ref,
111
- () => ({
112
- focus: () => terminal.current?.focus(),
113
- reconnect: () => connection.current?.retry()
114
- }),
115
- []
116
- );
117
- useEffect(() => {
118
- const container = screen.current;
119
- if (container === null) return void 0;
120
- let disposed = false;
121
- let teardown;
122
- const publish = (next) => {
123
- if (disposed) return;
124
- setStatus(next);
125
- latest.current.onStatusChange?.(next);
126
- };
127
- publish({ state: "loading" });
128
- void (async () => {
129
- const [{ Terminal: XTerm }, { FitAddon }] = await Promise.all([
130
- import("@xterm/xterm"),
131
- import("@xterm/addon-fit")
132
- ]);
133
- if (disposed) return;
134
- const xterm = new XTerm({
135
- cursorBlink: !readOnly,
136
- disableStdin: readOnly,
137
- scrollback: 5e3,
138
- ...latest.current.terminalOptions
139
- });
140
- const fit = new FitAddon();
141
- xterm.loadAddon(fit);
142
- xterm.open(container);
143
- fit.fit();
144
- terminal.current = xterm;
145
- const link = new TerminalConnection({
146
- url,
147
- sessionName,
148
- getTicket: resolveTicket(() => latest.current.ticket),
149
- size: () => ({ cols: xterm.cols, rows: xterm.rows }),
150
- onOutput: (bytes) => xterm.write(bytes),
151
- // The hub redraws the session on every attach, so start from a clean screen.
152
- onOpen: (reconnected) => {
153
- if (reconnected) xterm.reset();
154
- if (!readOnly) xterm.focus();
155
- },
156
- onStatus: publish,
157
- reconnect: latest.current.reconnect
158
- });
159
- connection.current = link;
160
- const input = xterm.onData((data) => {
161
- if (!readOnly) link.sendInput(data);
162
- });
163
- const resized = xterm.onResize(({ cols, rows }) => {
164
- if (!readOnly) link.sendResize(cols, rows);
165
- });
166
- let frame = 0;
167
- const observer = new ResizeObserver(() => {
168
- cancelAnimationFrame(frame);
169
- frame = requestAnimationFrame(() => fit.fit());
170
- });
171
- observer.observe(container);
172
- link.start();
173
- teardown = () => {
174
- cancelAnimationFrame(frame);
175
- observer.disconnect();
176
- input.dispose();
177
- resized.dispose();
178
- link.dispose();
179
- xterm.dispose();
180
- connection.current = void 0;
181
- terminal.current = void 0;
182
- };
183
- })().catch((error) => {
184
- publish({
185
- state: "failed",
186
- message: error instanceof Error ? error.message : "Could not load the terminal."
187
- });
188
- });
189
- return () => {
190
- disposed = true;
191
- teardown?.();
192
- };
193
- }, [url, sessionName, readOnly]);
194
- const retry = () => connection.current?.retry();
195
- const statusNode = renderStatus === void 0 ? /* @__PURE__ */ jsx(DefaultStatus, { status, retry }) : renderStatus(status, retry);
196
- return /* @__PURE__ */ jsxs(
197
- "div",
198
- {
199
- ...rest,
200
- "data-state": status.state,
201
- "data-readonly": readOnly ? "" : void 0,
202
- style: { ...rootStyle, ...style },
203
- children: [
204
- /* @__PURE__ */ jsx("div", { ref: screen, style: screenStyle }),
205
- statusNode
206
- ]
207
- }
208
- );
209
- }
210
- );
211
- export {
212
- SandboxTerminal,
213
- terminalSubprotocol,
214
- ticketSubprotocolPrefix
90
+ const rootStyle = {
91
+ position: "relative",
92
+ width: "100%",
93
+ height: "100%"
215
94
  };
95
+ const screenStyle = {
96
+ width: "100%",
97
+ height: "100%"
98
+ };
99
+ /**
100
+ * A terminal for a remote sandbox session, drawn with xterm.js. xterm is loaded on demand, so it
101
+ * costs nothing until a terminal mounts. Import `@xterm/xterm/css/xterm.css` once in your app.
102
+ */
103
+ const SandboxTerminal = forwardRef(function SandboxTerminal({ url, sessionName, ticket, readOnly = false, reconnect, terminalOptions, onStatusChange, renderStatus, style, ...rest }, ref) {
104
+ const screen = useRef(null);
105
+ const connection = useRef(void 0);
106
+ const terminal = useRef(void 0);
107
+ const [status, setStatus] = useState({ state: "loading" });
108
+ const latest = useRef({
109
+ ticket,
110
+ reconnect,
111
+ terminalOptions,
112
+ onStatusChange
113
+ });
114
+ latest.current = {
115
+ ticket,
116
+ reconnect,
117
+ terminalOptions,
118
+ onStatusChange
119
+ };
120
+ useImperativeHandle(ref, () => ({
121
+ focus: () => terminal.current?.focus(),
122
+ reconnect: () => connection.current?.retry()
123
+ }), []);
124
+ useEffect(() => {
125
+ const container = screen.current;
126
+ if (container === null) return void 0;
127
+ let disposed = false;
128
+ let teardown;
129
+ const publish = (next) => {
130
+ if (disposed) return;
131
+ setStatus(next);
132
+ latest.current.onStatusChange?.(next);
133
+ };
134
+ publish({ state: "loading" });
135
+ (async () => {
136
+ const [{ Terminal: XTerm }, { FitAddon }] = await Promise.all([import("@xterm/xterm"), import("@xterm/addon-fit")]);
137
+ if (disposed) return;
138
+ const xterm = new XTerm({
139
+ cursorBlink: !readOnly,
140
+ disableStdin: readOnly,
141
+ scrollback: 5e3,
142
+ ...latest.current.terminalOptions
143
+ });
144
+ const fit = new FitAddon();
145
+ xterm.loadAddon(fit);
146
+ xterm.open(container);
147
+ fit.fit();
148
+ terminal.current = xterm;
149
+ const link = new TerminalConnection({
150
+ url,
151
+ sessionName,
152
+ getTicket: resolveTicket(() => latest.current.ticket),
153
+ size: () => ({
154
+ cols: xterm.cols,
155
+ rows: xterm.rows
156
+ }),
157
+ onOutput: (bytes) => xterm.write(bytes),
158
+ onOpen: (reconnected) => {
159
+ if (reconnected) xterm.reset();
160
+ if (!readOnly) xterm.focus();
161
+ },
162
+ onStatus: publish,
163
+ reconnect: latest.current.reconnect
164
+ });
165
+ connection.current = link;
166
+ const input = xterm.onData((data) => {
167
+ if (!readOnly) link.sendInput(data);
168
+ });
169
+ const resized = xterm.onResize(({ cols, rows }) => {
170
+ if (!readOnly) link.sendResize(cols, rows);
171
+ });
172
+ let frame = 0;
173
+ const observer = new ResizeObserver(() => {
174
+ cancelAnimationFrame(frame);
175
+ frame = requestAnimationFrame(() => fit.fit());
176
+ });
177
+ observer.observe(container);
178
+ link.start();
179
+ teardown = () => {
180
+ cancelAnimationFrame(frame);
181
+ observer.disconnect();
182
+ input.dispose();
183
+ resized.dispose();
184
+ link.dispose();
185
+ xterm.dispose();
186
+ connection.current = void 0;
187
+ terminal.current = void 0;
188
+ };
189
+ })().catch((error) => {
190
+ publish({
191
+ state: "failed",
192
+ message: error instanceof Error ? error.message : "Could not load the terminal."
193
+ });
194
+ });
195
+ return () => {
196
+ disposed = true;
197
+ teardown?.();
198
+ };
199
+ }, [
200
+ url,
201
+ sessionName,
202
+ readOnly
203
+ ]);
204
+ const retry = () => connection.current?.retry();
205
+ const statusNode = renderStatus === void 0 ? /* @__PURE__ */ jsx(DefaultStatus, {
206
+ status,
207
+ retry
208
+ }) : renderStatus(status, retry);
209
+ return /* @__PURE__ */ jsxs("div", {
210
+ ...rest,
211
+ "data-state": status.state,
212
+ "data-readonly": readOnly ? "" : void 0,
213
+ style: {
214
+ ...rootStyle,
215
+ ...style
216
+ },
217
+ children: [/* @__PURE__ */ jsx("div", {
218
+ ref: screen,
219
+ style: screenStyle
220
+ }), statusNode]
221
+ });
222
+ });
223
+ export { SandboxTerminal, terminalSubprotocol, ticketSubprotocolPrefix };
224
+
216
225
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/sandbox-terminal/terminal.tsx","../../src/sandbox-terminal/connection.ts"],"sourcesContent":["import type { ITerminalOptions, Terminal } from \"@xterm/xterm\";\nimport {\n forwardRef,\n useEffect,\n useImperativeHandle,\n useRef,\n useState,\n type CSSProperties,\n type ReactNode,\n} from \"react\";\n\nimport { type PrimitiveProps } from \"../primitives\";\nimport { DefaultStatus } from \"../relay/status\";\nimport { type TicketSource, resolveTicket } from \"../relay/ticket\";\nimport {\n type SandboxTerminalReconnectOptions,\n type SandboxTerminalStatus,\n TerminalConnection,\n} from \"./connection\";\n\nexport interface SandboxTerminalHandle {\n focus(): void;\n /** Reconnect now, after the terminal gave up. */\n reconnect(): void;\n}\n\nexport type SandboxTerminalProps = Omit<PrimitiveProps<\"div\">, \"children\" | \"onError\"> & {\n /**\n * The hub's terminal endpoint (`hub.handleTerminalUpgrade`): `ws:`/`wss:`, `http:`/`https:`, or a\n * path relative to this page.\n */\n url: string;\n /** Sent as `?session=` so your `authorizeTerminal` can choose the session. The server decides. */\n sessionName?: string;\n /**\n * A one-time ticket, or a function returning one. Pass a function: tickets are single use, so\n * each reconnect needs a fresh one. It travels as a WebSocket subprotocol, not in the URL.\n */\n ticket?: TicketSource;\n /** Show output only. The server enforces it too; this also stops the terminal taking input. */\n readOnly?: boolean;\n reconnect?: SandboxTerminalReconnectOptions;\n /** xterm options, such as `fontSize` or `theme`. Applied when the terminal is created. */\n terminalOptions?: ITerminalOptions;\n onStatusChange?: (status: SandboxTerminalStatus) => void;\n /** Replace the default status line. Return null to show nothing. */\n renderStatus?: (status: SandboxTerminalStatus, retry: () => void) => ReactNode;\n};\n\nconst rootStyle: CSSProperties = { position: \"relative\", width: \"100%\", height: \"100%\" };\nconst screenStyle: CSSProperties = { width: \"100%\", height: \"100%\" };\n\n/**\n * A terminal for a remote sandbox session, drawn with xterm.js. xterm is loaded on demand, so it\n * costs nothing until a terminal mounts. Import `@xterm/xterm/css/xterm.css` once in your app.\n */\nexport const SandboxTerminal = forwardRef<SandboxTerminalHandle, SandboxTerminalProps>(\n function SandboxTerminal(\n {\n url,\n sessionName,\n ticket,\n readOnly = false,\n reconnect,\n terminalOptions,\n onStatusChange,\n renderStatus,\n style,\n ...rest\n },\n ref,\n ) {\n const screen = useRef<HTMLDivElement>(null);\n const connection = useRef<TerminalConnection | undefined>(undefined);\n const terminal = useRef<Terminal | undefined>(undefined);\n const [status, setStatus] = useState<SandboxTerminalStatus>({ state: \"loading\" });\n\n // The latest props, read by long-lived callbacks without restarting the terminal.\n const latest = useRef({ ticket, reconnect, terminalOptions, onStatusChange });\n latest.current = { ticket, reconnect, terminalOptions, onStatusChange };\n\n useImperativeHandle(\n ref,\n () => ({\n focus: () => terminal.current?.focus(),\n reconnect: () => connection.current?.retry(),\n }),\n [],\n );\n\n useEffect(() => {\n const container = screen.current;\n if (container === null) return undefined;\n let disposed = false;\n let teardown: (() => void) | undefined;\n\n const publish = (next: SandboxTerminalStatus) => {\n if (disposed) return;\n setStatus(next);\n latest.current.onStatusChange?.(next);\n };\n publish({ state: \"loading\" });\n\n void (async () => {\n const [{ Terminal: XTerm }, { FitAddon }] = await Promise.all([\n import(\"@xterm/xterm\"),\n import(\"@xterm/addon-fit\"),\n ]);\n if (disposed) return;\n\n const xterm = new XTerm({\n cursorBlink: !readOnly,\n disableStdin: readOnly,\n scrollback: 5_000,\n ...latest.current.terminalOptions,\n });\n const fit = new FitAddon();\n xterm.loadAddon(fit);\n xterm.open(container);\n fit.fit();\n terminal.current = xterm;\n\n const link = new TerminalConnection({\n url,\n sessionName,\n getTicket: resolveTicket(() => latest.current.ticket),\n size: () => ({ cols: xterm.cols, rows: xterm.rows }),\n onOutput: (bytes) => xterm.write(bytes),\n // The hub redraws the session on every attach, so start from a clean screen.\n onOpen: (reconnected) => {\n if (reconnected) xterm.reset();\n if (!readOnly) xterm.focus();\n },\n onStatus: publish,\n reconnect: latest.current.reconnect,\n });\n connection.current = link;\n\n const input = xterm.onData((data) => {\n if (!readOnly) link.sendInput(data);\n });\n const resized = xterm.onResize(({ cols, rows }) => {\n if (!readOnly) link.sendResize(cols, rows);\n });\n let frame = 0;\n const observer = new ResizeObserver(() => {\n cancelAnimationFrame(frame);\n frame = requestAnimationFrame(() => fit.fit());\n });\n observer.observe(container);\n\n link.start();\n teardown = () => {\n cancelAnimationFrame(frame);\n observer.disconnect();\n input.dispose();\n resized.dispose();\n link.dispose();\n xterm.dispose();\n connection.current = undefined;\n terminal.current = undefined;\n };\n })().catch((error: unknown) => {\n publish({\n state: \"failed\",\n message: error instanceof Error ? error.message : \"Could not load the terminal.\",\n });\n });\n\n return () => {\n disposed = true;\n teardown?.();\n };\n }, [url, sessionName, readOnly]);\n\n const retry = () => connection.current?.retry();\n const statusNode =\n renderStatus === undefined ? (\n <DefaultStatus status={status} retry={retry} />\n ) : (\n renderStatus(status, retry)\n );\n\n return (\n <div\n {...rest}\n data-state={status.state}\n data-readonly={readOnly ? \"\" : undefined}\n style={{ ...rootStyle, ...style }}\n >\n <div ref={screen} style={screenStyle} />\n {statusNode}\n </div>\n );\n },\n);\n","import {\n type RelayProtocol,\n type RelayReconnectOptions,\n type RelaySession,\n type RelayState,\n type RelayStatus,\n RelayConnection,\n} from \"../relay/connection\";\n\nexport { ticketSubprotocolPrefix } from \"../relay/connection\";\n\n/** Subprotocol the hub's `handleTerminalUpgrade` requires. */\nexport const terminalSubprotocol = \"anvia.terminal.v1\";\n\nexport type SandboxTerminalState = RelayState;\nexport type SandboxTerminalStatus = RelayStatus;\nexport type SandboxTerminalReconnectOptions = RelayReconnectOptions;\n\nexport interface TerminalConnectionOptions {\n /** `ws:`, `wss:`, `http:`, `https:`, or a path relative to the page. */\n url: string;\n /** Appended as `?session=` so the server can pick the session. The server stays in charge. */\n sessionName?: string | undefined;\n /** Called for every attempt, because tickets are single use. */\n getTicket?: (() => string | Promise<string>) | undefined;\n size: () => { cols: number; rows: number };\n onOutput: (bytes: Uint8Array) => void;\n /** The terminal is attached. `reconnected` is true when an earlier attachment existed. */\n onOpen: (reconnected: boolean) => void;\n onStatus: (status: SandboxTerminalStatus) => void;\n reconnect?: SandboxTerminalReconnectOptions | undefined;\n}\n\n/** Errors worth another attempt: the sandbox may simply not be reachable yet. */\nconst retryableCodes = new Set([\"sandbox_unavailable\", \"timeout\"]);\n\ntype ServerMessage =\n | { type: \"ready\"; readOnly?: boolean }\n | { type: \"exit\"; reason?: string; exitCode?: number }\n | { type: \"error\"; code?: string; message?: string };\n\n/**\n * One browser terminal link: speaks the hub's terminal relay protocol over a {@link\n * RelayConnection}. It knows nothing about xterm, so it is testable on its own.\n */\nexport class TerminalConnection {\n private readonly relay: RelayConnection;\n\n constructor(options: TerminalConnectionOptions) {\n // The relay only sends output once it has opened the terminal, which starts with our size.\n let ready = false;\n const protocol: RelayProtocol = {\n subprotocol: terminalSubprotocol,\n label: \"terminal\",\n open: (socket) => {\n ready = false;\n const { cols, rows } = options.size();\n socket.send(JSON.stringify({ type: \"open\", cols, rows }));\n },\n message: (event, session: RelaySession) => {\n if (typeof event.data !== \"string\") {\n if (ready) options.onOutput(new Uint8Array(event.data as ArrayBuffer));\n return;\n }\n const message = parseMessage(event.data);\n if (message === undefined) return;\n if (message.type === \"ready\") {\n ready = true;\n options.onOpen(session.ready());\n } else if (message.type === \"exit\") {\n session.ended({ message: message.reason ?? \"exited\", exitCode: message.exitCode });\n } else if (!retryableCodes.has(message.code ?? \"\")) {\n session.fatal(message.message ?? \"The terminal could not be opened.\");\n }\n },\n };\n this.relay = new RelayConnection({\n url: options.url,\n sessionName: options.sessionName,\n getTicket: options.getTicket,\n onStatus: options.onStatus,\n reconnect: options.reconnect,\n protocol,\n });\n }\n\n start(): void {\n this.relay.start();\n }\n\n /** Try again now, for a link that gave up. */\n retry(): void {\n this.relay.retry();\n }\n\n sendInput(data: string): void {\n this.relay.sendJson({ type: \"input\", data });\n }\n\n sendResize(cols: number, rows: number): void {\n this.relay.sendJson({ type: \"resize\", cols, rows });\n }\n\n dispose(): void {\n this.relay.dispose();\n }\n}\n\nfunction parseMessage(text: string): ServerMessage | undefined {\n try {\n const value: unknown = JSON.parse(text);\n if (typeof value !== \"object\" || value === null) return undefined;\n const type = (value as { type?: unknown }).type;\n return type === \"ready\" || type === \"exit\" || type === \"error\"\n ? (value as ServerMessage)\n : undefined;\n } catch {\n return undefined;\n }\n}\n"],"mappings":"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","names":["SandboxTerminal"]}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/sandbox-terminal/connection.ts","../../src/sandbox-terminal/terminal.tsx"],"sourcesContent":["import {\n type RelayProtocol,\n type RelayReconnectOptions,\n type RelaySession,\n type RelayState,\n type RelayStatus,\n RelayConnection,\n} from \"../relay/connection\";\n\nexport { ticketSubprotocolPrefix } from \"../relay/connection\";\n\n/** Subprotocol the hub's `handleTerminalUpgrade` requires. */\nexport const terminalSubprotocol = \"anvia.terminal.v1\";\n\nexport type SandboxTerminalState = RelayState;\nexport type SandboxTerminalStatus = RelayStatus;\nexport type SandboxTerminalReconnectOptions = RelayReconnectOptions;\n\nexport interface TerminalConnectionOptions {\n /** `ws:`, `wss:`, `http:`, `https:`, or a path relative to the page. */\n url: string;\n /** Appended as `?session=` so the server can pick the session. The server stays in charge. */\n sessionName?: string | undefined;\n /** Called for every attempt, because tickets are single use. */\n getTicket?: (() => string | Promise<string>) | undefined;\n size: () => { cols: number; rows: number };\n onOutput: (bytes: Uint8Array) => void;\n /** The terminal is attached. `reconnected` is true when an earlier attachment existed. */\n onOpen: (reconnected: boolean) => void;\n onStatus: (status: SandboxTerminalStatus) => void;\n reconnect?: SandboxTerminalReconnectOptions | undefined;\n}\n\n/** Errors worth another attempt: the sandbox may simply not be reachable yet. */\nconst retryableCodes = new Set([\"sandbox_unavailable\", \"timeout\"]);\n\ntype ServerMessage =\n | { type: \"ready\"; readOnly?: boolean }\n | { type: \"exit\"; reason?: string; exitCode?: number }\n | { type: \"error\"; code?: string; message?: string };\n\n/**\n * One browser terminal link: speaks the hub's terminal relay protocol over a {@link\n * RelayConnection}. It knows nothing about xterm, so it is testable on its own.\n */\nexport class TerminalConnection {\n private readonly relay: RelayConnection;\n\n constructor(options: TerminalConnectionOptions) {\n // The relay only sends output once it has opened the terminal, which starts with our size.\n let ready = false;\n const protocol: RelayProtocol = {\n subprotocol: terminalSubprotocol,\n label: \"terminal\",\n open: (socket) => {\n ready = false;\n const { cols, rows } = options.size();\n socket.send(JSON.stringify({ type: \"open\", cols, rows }));\n },\n message: (event, session: RelaySession) => {\n if (typeof event.data !== \"string\") {\n if (ready) options.onOutput(new Uint8Array(event.data as ArrayBuffer));\n return;\n }\n const message = parseMessage(event.data);\n if (message === undefined) return;\n if (message.type === \"ready\") {\n ready = true;\n options.onOpen(session.ready());\n } else if (message.type === \"exit\") {\n session.ended({ message: message.reason ?? \"exited\", exitCode: message.exitCode });\n } else if (!retryableCodes.has(message.code ?? \"\")) {\n session.fatal(message.message ?? \"The terminal could not be opened.\");\n }\n },\n };\n this.relay = new RelayConnection({\n url: options.url,\n sessionName: options.sessionName,\n getTicket: options.getTicket,\n onStatus: options.onStatus,\n reconnect: options.reconnect,\n protocol,\n });\n }\n\n start(): void {\n this.relay.start();\n }\n\n /** Try again now, for a link that gave up. */\n retry(): void {\n this.relay.retry();\n }\n\n sendInput(data: string): void {\n this.relay.sendJson({ type: \"input\", data });\n }\n\n sendResize(cols: number, rows: number): void {\n this.relay.sendJson({ type: \"resize\", cols, rows });\n }\n\n dispose(): void {\n this.relay.dispose();\n }\n}\n\nfunction parseMessage(text: string): ServerMessage | undefined {\n try {\n const value: unknown = JSON.parse(text);\n if (typeof value !== \"object\" || value === null) return undefined;\n const type = (value as { type?: unknown }).type;\n return type === \"ready\" || type === \"exit\" || type === \"error\"\n ? (value as ServerMessage)\n : undefined;\n } catch {\n return undefined;\n }\n}\n","import type { ITerminalOptions, Terminal } from \"@xterm/xterm\";\nimport {\n forwardRef,\n useEffect,\n useImperativeHandle,\n useRef,\n useState,\n type CSSProperties,\n type ReactNode,\n} from \"react\";\n\nimport { type PrimitiveProps } from \"../primitives\";\nimport { DefaultStatus } from \"../relay/status\";\nimport { type TicketSource, resolveTicket } from \"../relay/ticket\";\nimport {\n type SandboxTerminalReconnectOptions,\n type SandboxTerminalStatus,\n TerminalConnection,\n} from \"./connection\";\n\nexport interface SandboxTerminalHandle {\n focus(): void;\n /** Reconnect now, after the terminal gave up. */\n reconnect(): void;\n}\n\nexport type SandboxTerminalProps = Omit<PrimitiveProps<\"div\">, \"children\" | \"onError\"> & {\n /**\n * The hub's terminal endpoint (`hub.handleTerminalUpgrade`): `ws:`/`wss:`, `http:`/`https:`, or a\n * path relative to this page.\n */\n url: string;\n /** Sent as `?session=` so your `authorizeTerminal` can choose the session. The server decides. */\n sessionName?: string;\n /**\n * A one-time ticket, or a function returning one. Pass a function: tickets are single use, so\n * each reconnect needs a fresh one. It travels as a WebSocket subprotocol, not in the URL.\n */\n ticket?: TicketSource;\n /** Show output only. The server enforces it too; this also stops the terminal taking input. */\n readOnly?: boolean;\n reconnect?: SandboxTerminalReconnectOptions;\n /** xterm options, such as `fontSize` or `theme`. Applied when the terminal is created. */\n terminalOptions?: ITerminalOptions;\n onStatusChange?: (status: SandboxTerminalStatus) => void;\n /** Replace the default status line. Return null to show nothing. */\n renderStatus?: (status: SandboxTerminalStatus, retry: () => void) => ReactNode;\n};\n\nconst rootStyle: CSSProperties = { position: \"relative\", width: \"100%\", height: \"100%\" };\nconst screenStyle: CSSProperties = { width: \"100%\", height: \"100%\" };\n\n/**\n * A terminal for a remote sandbox session, drawn with xterm.js. xterm is loaded on demand, so it\n * costs nothing until a terminal mounts. Import `@xterm/xterm/css/xterm.css` once in your app.\n */\nexport const SandboxTerminal = forwardRef<SandboxTerminalHandle, SandboxTerminalProps>(\n function SandboxTerminal(\n {\n url,\n sessionName,\n ticket,\n readOnly = false,\n reconnect,\n terminalOptions,\n onStatusChange,\n renderStatus,\n style,\n ...rest\n },\n ref,\n ) {\n const screen = useRef<HTMLDivElement>(null);\n const connection = useRef<TerminalConnection | undefined>(undefined);\n const terminal = useRef<Terminal | undefined>(undefined);\n const [status, setStatus] = useState<SandboxTerminalStatus>({ state: \"loading\" });\n\n // The latest props, read by long-lived callbacks without restarting the terminal.\n const latest = useRef({ ticket, reconnect, terminalOptions, onStatusChange });\n latest.current = { ticket, reconnect, terminalOptions, onStatusChange };\n\n useImperativeHandle(\n ref,\n () => ({\n focus: () => terminal.current?.focus(),\n reconnect: () => connection.current?.retry(),\n }),\n [],\n );\n\n useEffect(() => {\n const container = screen.current;\n if (container === null) return undefined;\n let disposed = false;\n let teardown: (() => void) | undefined;\n\n const publish = (next: SandboxTerminalStatus) => {\n if (disposed) return;\n setStatus(next);\n latest.current.onStatusChange?.(next);\n };\n publish({ state: \"loading\" });\n\n void (async () => {\n const [{ Terminal: XTerm }, { FitAddon }] = await Promise.all([\n import(\"@xterm/xterm\"),\n import(\"@xterm/addon-fit\"),\n ]);\n if (disposed) return;\n\n const xterm = new XTerm({\n cursorBlink: !readOnly,\n disableStdin: readOnly,\n scrollback: 5_000,\n ...latest.current.terminalOptions,\n });\n const fit = new FitAddon();\n xterm.loadAddon(fit);\n xterm.open(container);\n fit.fit();\n terminal.current = xterm;\n\n const link = new TerminalConnection({\n url,\n sessionName,\n getTicket: resolveTicket(() => latest.current.ticket),\n size: () => ({ cols: xterm.cols, rows: xterm.rows }),\n onOutput: (bytes) => xterm.write(bytes),\n // The hub redraws the session on every attach, so start from a clean screen.\n onOpen: (reconnected) => {\n if (reconnected) xterm.reset();\n if (!readOnly) xterm.focus();\n },\n onStatus: publish,\n reconnect: latest.current.reconnect,\n });\n connection.current = link;\n\n const input = xterm.onData((data) => {\n if (!readOnly) link.sendInput(data);\n });\n const resized = xterm.onResize(({ cols, rows }) => {\n if (!readOnly) link.sendResize(cols, rows);\n });\n let frame = 0;\n const observer = new ResizeObserver(() => {\n cancelAnimationFrame(frame);\n frame = requestAnimationFrame(() => fit.fit());\n });\n observer.observe(container);\n\n link.start();\n teardown = () => {\n cancelAnimationFrame(frame);\n observer.disconnect();\n input.dispose();\n resized.dispose();\n link.dispose();\n xterm.dispose();\n connection.current = undefined;\n terminal.current = undefined;\n };\n })().catch((error: unknown) => {\n publish({\n state: \"failed\",\n message: error instanceof Error ? error.message : \"Could not load the terminal.\",\n });\n });\n\n return () => {\n disposed = true;\n teardown?.();\n };\n }, [url, sessionName, readOnly]);\n\n const retry = () => connection.current?.retry();\n const statusNode =\n renderStatus === undefined ? (\n <DefaultStatus status={status} retry={retry} />\n ) : (\n renderStatus(status, retry)\n );\n\n return (\n <div\n {...rest}\n data-state={status.state}\n data-readonly={readOnly ? \"\" : undefined}\n style={{ ...rootStyle, ...style }}\n >\n <div ref={screen} style={screenStyle} />\n {statusNode}\n </div>\n );\n },\n);\n"],"mappings":"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"}
@@ -1,21 +1,3 @@
1
- import * as react from 'react';
2
- import { a as SelectionToolbarSelection } from '../selection-toolbar-Cwjbuv5S.js';
3
- export { S as SelectionToolbarContextValue, u as useSelectionToolbar } from '../selection-toolbar-Cwjbuv5S.js';
4
- import { P as PrimitiveProps } from '../render-CRKWam2v.js';
5
-
6
- declare const SelectionToolbarPrimitive: {
7
- readonly Root: react.ForwardRefExoticComponent<Omit<PrimitiveProps<"div">, "children"> & {
8
- children?: react.ReactNode;
9
- container?: Element | DocumentFragment;
10
- onQuote?: (selection: SelectionToolbarSelection) => void;
11
- onSelectionChange?: (selection: SelectionToolbarSelection | undefined) => void;
12
- } & react.RefAttributes<HTMLDivElement>>;
13
- readonly Quote: react.ForwardRefExoticComponent<Omit<Omit<react.DetailedHTMLProps<react.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, "ref">, "asChild"> & {
14
- asChild?: boolean;
15
- } & react.RefAttributes<HTMLButtonElement>>;
16
- readonly Copy: react.ForwardRefExoticComponent<Omit<Omit<react.DetailedHTMLProps<react.ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, "ref">, "asChild"> & {
17
- asChild?: boolean;
18
- } & react.RefAttributes<HTMLButtonElement>>;
19
- };
20
-
21
- export { SelectionToolbarPrimitive, SelectionToolbarSelection };
1
+ import { d as SelectionToolbarSelection, f as useSelectionToolbar, u as SelectionToolbarContextValue } from "../index-Mw3ltwSG.js";
2
+ import { i as SelectionToolbarPrimitive } from "../index-BCBVcl0D.js";
3
+ export { type SelectionToolbarContextValue, SelectionToolbarPrimitive, type SelectionToolbarSelection, useSelectionToolbar };
@@ -1,13 +1,3 @@
1
- import {
2
- SelectionToolbarPrimitive
3
- } from "../chunk-KHB5CHAU.js";
4
- import "../chunk-6XOJFLX4.js";
5
- import "../chunk-T3ZFZ3NP.js";
6
- import {
7
- useSelectionToolbar
8
- } from "../chunk-E73S3SOF.js";
9
- export {
10
- SelectionToolbarPrimitive,
11
- useSelectionToolbar
12
- };
13
- //# sourceMappingURL=index.js.map
1
+ import { u as useSelectionToolbar } from "../contexts-B4ijG24z.js";
2
+ import { t as SelectionToolbarPrimitive } from "../selection-toolbar-CIkOoM-7.js";
3
+ export { SelectionToolbarPrimitive, useSelectionToolbar };