green-screen-react 0.3.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -20,10 +20,18 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/index.ts
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
+ AlertTriangleIcon: () => AlertTriangleIcon,
23
24
  GreenScreenTerminal: () => GreenScreenTerminal,
25
+ InlineSignIn: () => InlineSignIn,
26
+ KeyIcon: () => KeyIcon,
27
+ MinimizeIcon: () => MinimizeIcon,
28
+ RefreshIcon: () => RefreshIcon,
24
29
  RestAdapter: () => RestAdapter,
25
- TN5250Terminal: () => TN5250Terminal,
26
30
  TerminalBootLoader: () => TerminalBootLoader,
31
+ TerminalIcon: () => TerminalIcon,
32
+ WebSocketAdapter: () => WebSocketAdapter,
33
+ WifiIcon: () => WifiIcon,
34
+ WifiOffIcon: () => WifiOffIcon,
27
35
  getProtocolProfile: () => getProtocolProfile,
28
36
  getRowColorClass: () => getRowColorClass,
29
37
  hp6530Profile: () => hp6530Profile,
@@ -32,9 +40,6 @@ __export(index_exports, {
32
40
  positionToRowCol: () => positionToRowCol,
33
41
  tn3270Profile: () => tn3270Profile,
34
42
  tn5250Profile: () => tn5250Profile,
35
- useTN5250Connection: () => useTN5250Connection,
36
- useTN5250Screen: () => useTN5250Screen,
37
- useTN5250Terminal: () => useTN5250Terminal,
38
43
  useTerminalConnection: () => useTerminalConnection,
39
44
  useTerminalInput: () => useTerminalInput,
40
45
  useTerminalScreen: () => useTerminalScreen,
@@ -44,9 +49,295 @@ __export(index_exports, {
44
49
  module.exports = __toCommonJS(index_exports);
45
50
 
46
51
  // src/components/GreenScreenTerminal.tsx
47
- var import_react4 = require("react");
52
+ var import_react5 = require("react");
53
+
54
+ // src/adapters/RestAdapter.ts
55
+ var RestAdapter = class {
56
+ constructor(options) {
57
+ this.baseUrl = options.baseUrl.replace(/\/+$/, "");
58
+ this.staticHeaders = options.headers || {};
59
+ this.getHeaders = options.getHeaders;
60
+ }
61
+ async buildHeaders() {
62
+ const dynamic = this.getHeaders ? await this.getHeaders() : {};
63
+ return {
64
+ "Content-Type": "application/json",
65
+ ...this.staticHeaders,
66
+ ...dynamic
67
+ };
68
+ }
69
+ async request(method, path, body) {
70
+ const headers = await this.buildHeaders();
71
+ const response = await fetch(`${this.baseUrl}${path}`, {
72
+ method,
73
+ headers,
74
+ body: body ? JSON.stringify(body) : void 0
75
+ });
76
+ if (!response.ok) {
77
+ const detail = await response.json().catch(() => ({}));
78
+ throw new Error(detail?.detail || `HTTP ${response.status}`);
79
+ }
80
+ return response.json();
81
+ }
82
+ async getScreen() {
83
+ try {
84
+ return await this.request("GET", "/screen");
85
+ } catch (e) {
86
+ const message = e instanceof Error ? e.message : String(e);
87
+ if (message.includes("503") || message.includes("404")) {
88
+ return null;
89
+ }
90
+ throw e;
91
+ }
92
+ }
93
+ async getStatus() {
94
+ return this.request("GET", "/status");
95
+ }
96
+ async sendText(text) {
97
+ return this.request("POST", "/send-text", { text });
98
+ }
99
+ async sendKey(key) {
100
+ return this.request("POST", "/send-key", { key });
101
+ }
102
+ async connect(config) {
103
+ return this.request("POST", "/connect", config);
104
+ }
105
+ async disconnect() {
106
+ return this.request("POST", "/disconnect");
107
+ }
108
+ async reconnect() {
109
+ return this.request("POST", "/reconnect");
110
+ }
111
+ };
112
+
113
+ // src/adapters/WebSocketAdapter.ts
114
+ var import_meta = {};
115
+ var WebSocketAdapter = class _WebSocketAdapter {
116
+ constructor(options = {}) {
117
+ this.ws = null;
118
+ this.screen = null;
119
+ this.status = { connected: false, status: "disconnected" };
120
+ this.pendingScreenResolver = null;
121
+ this.pendingConnectResolver = null;
122
+ this.connectingPromise = null;
123
+ this.screenListeners = /* @__PURE__ */ new Set();
124
+ this.statusListeners = /* @__PURE__ */ new Set();
125
+ this._sessionId = null;
126
+ this.workerUrl = (options.workerUrl || _WebSocketAdapter.detectEnvUrl() || "http://localhost:3001").replace(/\/+$/, "");
127
+ }
128
+ static detectEnvUrl() {
129
+ try {
130
+ if (typeof import_meta !== "undefined" && import_meta.env) {
131
+ const env = import_meta.env;
132
+ return env.VITE_GREEN_SCREEN_URL || env.VITE_WORKER_URL || void 0;
133
+ }
134
+ } catch {
135
+ }
136
+ try {
137
+ const p = typeof globalThis !== "undefined" && globalThis.process;
138
+ if (p && p.env) {
139
+ return p.env.NEXT_PUBLIC_GREEN_SCREEN_URL || p.env.REACT_APP_GREEN_SCREEN_URL || void 0;
140
+ }
141
+ } catch {
142
+ }
143
+ return void 0;
144
+ }
145
+ /** The proxy-side session ID (available after connect or reattach) */
146
+ get sessionId() {
147
+ return this._sessionId;
148
+ }
149
+ /** Subscribe to real-time screen updates */
150
+ onScreen(listener) {
151
+ this.screenListeners.add(listener);
152
+ return () => this.screenListeners.delete(listener);
153
+ }
154
+ /** Subscribe to status changes */
155
+ onStatus(listener) {
156
+ this.statusListeners.add(listener);
157
+ return () => this.statusListeners.delete(listener);
158
+ }
159
+ async getScreen() {
160
+ return this.screen;
161
+ }
162
+ async getStatus() {
163
+ return this.status;
164
+ }
165
+ async sendText(text) {
166
+ return this.sendAndWaitForScreen({ type: "text", text });
167
+ }
168
+ async sendKey(key) {
169
+ return this.sendAndWaitForScreen({ type: "key", key });
170
+ }
171
+ async connect(config) {
172
+ await this.ensureWebSocket();
173
+ if (!config) {
174
+ return { success: false, error: "ConnectConfig required" };
175
+ }
176
+ return new Promise((resolve) => {
177
+ const timeout = setTimeout(() => {
178
+ this.pendingConnectResolver = null;
179
+ resolve({ success: false, error: "Connection timeout" });
180
+ }, 3e4);
181
+ this.pendingConnectResolver = (result) => {
182
+ clearTimeout(timeout);
183
+ resolve(result);
184
+ };
185
+ this.wsSend({
186
+ type: "connect",
187
+ host: config.host,
188
+ port: config.port,
189
+ protocol: config.protocol,
190
+ username: config.username,
191
+ password: config.password
192
+ });
193
+ });
194
+ }
195
+ /**
196
+ * Reattach to an existing proxy session (e.g. after page reload).
197
+ * The proxy keeps the TCP connection alive; this just reconnects the
198
+ * WebSocket and receives the current screen.
199
+ */
200
+ async reattach(sessionId) {
201
+ await this.ensureWebSocket();
202
+ return new Promise((resolve) => {
203
+ const timeout = setTimeout(() => {
204
+ this.pendingConnectResolver = null;
205
+ resolve({ success: false, error: "Reattach timeout" });
206
+ }, 1e4);
207
+ this.pendingConnectResolver = (result) => {
208
+ clearTimeout(timeout);
209
+ resolve(result);
210
+ };
211
+ this.wsSend({ type: "reattach", sessionId });
212
+ });
213
+ }
214
+ async disconnect() {
215
+ this.wsSend({ type: "disconnect" });
216
+ this.status = { connected: false, status: "disconnected" };
217
+ this._sessionId = null;
218
+ if (this.ws) {
219
+ this.ws.close();
220
+ this.ws = null;
221
+ }
222
+ return { success: true };
223
+ }
224
+ async reconnect() {
225
+ return { success: false, error: "Use disconnect() then connect() instead" };
226
+ }
227
+ /** Close the WebSocket without sending disconnect (session stays alive on proxy) */
228
+ dispose() {
229
+ if (this.ws) {
230
+ this.ws.close();
231
+ this.ws = null;
232
+ }
233
+ }
234
+ async ensureWebSocket() {
235
+ if (this.ws && this.ws.readyState === WebSocket.OPEN) return;
236
+ if (this.connectingPromise) return this.connectingPromise;
237
+ this.connectingPromise = new Promise((resolve, reject) => {
238
+ const wsUrl = this.workerUrl.replace(/^http/, "ws") + "/ws";
239
+ this.ws = new WebSocket(wsUrl);
240
+ this.ws.onopen = () => resolve();
241
+ this.ws.onerror = () => reject(new Error("WebSocket connection failed"));
242
+ this.ws.onmessage = (event) => {
243
+ try {
244
+ const msg = JSON.parse(event.data);
245
+ this.handleMessage(msg);
246
+ } catch {
247
+ }
248
+ };
249
+ this.ws.onclose = () => {
250
+ this.status = { connected: false, status: "disconnected" };
251
+ for (const listener of this.statusListeners) listener(this.status);
252
+ };
253
+ }).finally(() => {
254
+ this.connectingPromise = null;
255
+ });
256
+ return this.connectingPromise;
257
+ }
258
+ handleMessage(msg) {
259
+ switch (msg.type) {
260
+ case "screen": {
261
+ this.screen = msg.data;
262
+ for (const listener of this.screenListeners) listener(msg.data);
263
+ if (this.pendingScreenResolver) {
264
+ const resolver = this.pendingScreenResolver;
265
+ this.pendingScreenResolver = null;
266
+ resolver(msg.data);
267
+ }
268
+ break;
269
+ }
270
+ case "status":
271
+ this.status = msg.data;
272
+ for (const listener of this.statusListeners) listener(msg.data);
273
+ break;
274
+ case "connected":
275
+ this._sessionId = msg.sessionId ?? null;
276
+ if (this.pendingConnectResolver) {
277
+ const resolver = this.pendingConnectResolver;
278
+ this.pendingConnectResolver = null;
279
+ resolver({ success: true });
280
+ }
281
+ break;
282
+ case "error": {
283
+ if (this.pendingConnectResolver) {
284
+ const resolver = this.pendingConnectResolver;
285
+ this.pendingConnectResolver = null;
286
+ resolver({ success: false, error: msg.message });
287
+ } else if (this.pendingScreenResolver) {
288
+ const resolver = this.pendingScreenResolver;
289
+ this.pendingScreenResolver = null;
290
+ resolver(null);
291
+ }
292
+ break;
293
+ }
294
+ }
295
+ }
296
+ sendAndWaitForScreen(msg) {
297
+ return new Promise((resolve) => {
298
+ if (this.pendingScreenResolver) {
299
+ const old = this.pendingScreenResolver;
300
+ this.pendingScreenResolver = null;
301
+ old(this.screen);
302
+ }
303
+ const timeout = setTimeout(() => {
304
+ this.pendingScreenResolver = null;
305
+ resolve({ success: true, ...this.screenToResult() });
306
+ }, 5e3);
307
+ this.pendingScreenResolver = (screen) => {
308
+ clearTimeout(timeout);
309
+ if (screen) {
310
+ resolve({
311
+ success: true,
312
+ cursor_row: screen.cursor_row,
313
+ cursor_col: screen.cursor_col,
314
+ content: screen.content,
315
+ screen_signature: screen.screen_signature
316
+ });
317
+ } else {
318
+ resolve({ success: false, error: "No screen data received" });
319
+ }
320
+ };
321
+ this.wsSend(msg);
322
+ });
323
+ }
324
+ screenToResult() {
325
+ if (!this.screen) return {};
326
+ return {
327
+ cursor_row: this.screen.cursor_row,
328
+ cursor_col: this.screen.cursor_col,
329
+ content: this.screen.content,
330
+ screen_signature: this.screen.screen_signature
331
+ };
332
+ }
333
+ wsSend(data) {
334
+ if (this.ws && this.ws.readyState === WebSocket.OPEN) {
335
+ this.ws.send(JSON.stringify(data));
336
+ }
337
+ }
338
+ };
48
339
 
49
- // src/hooks/useTN5250.ts
340
+ // src/hooks/useTerminal.ts
50
341
  var import_react = require("react");
51
342
  function useTerminalConnection(adapter) {
52
343
  const [status, setStatus] = (0, import_react.useState)(null);
@@ -167,9 +458,6 @@ function useTerminalInput(adapter) {
167
458
  }, [adapter]);
168
459
  return { loading, error, sendText, sendKey };
169
460
  }
170
- var useTN5250Connection = useTerminalConnection;
171
- var useTN5250Screen = useTerminalScreen;
172
- var useTN5250Terminal = useTerminalInput;
173
461
 
174
462
  // src/hooks/useTypingAnimation.ts
175
463
  var import_react2 = require("react");
@@ -617,7 +905,7 @@ function TerminalBootLoader({
617
905
  );
618
906
  }
619
907
 
620
- // src/components/GreenScreenTerminal.tsx
908
+ // src/components/Icons.tsx
621
909
  var import_jsx_runtime2 = require("react/jsx-runtime");
622
910
  var TerminalIcon = ({ size = 14 }) => /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
623
911
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("polyline", { points: "4 17 10 11 4 5" }),
@@ -650,26 +938,33 @@ var RefreshIcon = ({ size = 12, className }) => /* @__PURE__ */ (0, import_jsx_r
650
938
  ] });
651
939
  var KeyIcon = ({ size = 12, style: s }) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", style: s, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M21 2l-2 2m-7.61 7.61a5.5 5.5 0 1 1-7.778 7.778 5.5 5.5 0 0 1 7.777-7.777zm0 0L15.5 7.5m0 0l3 3L22 7l-3-3m-3.5 3.5L19 4" }) });
652
940
  var MinimizeIcon = () => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("svg", { width: 14, height: 14, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("path", { d: "M4 14h6v6M3 21l7-7M20 10h-6V4M21 3l-7 7" }) });
941
+
942
+ // src/components/InlineSignIn.tsx
943
+ var import_react4 = require("react");
944
+ var import_jsx_runtime3 = require("react/jsx-runtime");
653
945
  var PROTOCOL_OPTIONS = [
654
946
  { value: "tn5250", label: "TN5250 (IBM i)" },
655
947
  { value: "tn3270", label: "TN3270 (Mainframe)" },
656
948
  { value: "vt", label: "VT220" },
657
949
  { value: "hp6530", label: "HP 6530 (NonStop)" }
658
950
  ];
659
- function InlineSignIn({ defaultProtocol, loading, error, onConnect }) {
951
+ function InlineSignIn({ defaultProtocol, loading: externalLoading, error, onConnect }) {
660
952
  const [host, setHost] = (0, import_react4.useState)("");
661
953
  const [port, setPort] = (0, import_react4.useState)("");
662
954
  const [selectedProtocol, setSelectedProtocol] = (0, import_react4.useState)(defaultProtocol);
663
955
  const [username, setUsername] = (0, import_react4.useState)("");
664
956
  const [password, setPassword] = (0, import_react4.useState)("");
957
+ const [submitted, setSubmitted] = (0, import_react4.useState)(false);
958
+ const loading = externalLoading || submitted;
665
959
  const handleSubmit = (e) => {
666
960
  e.preventDefault();
961
+ setSubmitted(true);
667
962
  onConnect({
668
963
  host,
669
- port: port ? parseInt(port, 10) : void 0,
964
+ port: port ? parseInt(port, 10) : 23,
670
965
  protocol: selectedProtocol,
671
- username,
672
- password
966
+ ...username.trim() ? { username: username.trim() } : {},
967
+ ...password ? { password } : {}
673
968
  });
674
969
  };
675
970
  const inputStyle = {
@@ -692,42 +987,73 @@ function InlineSignIn({ defaultProtocol, loading, error, onConnect }) {
692
987
  color: "var(--gs-muted, #94a3b8)",
693
988
  fontFamily: "var(--gs-font)"
694
989
  };
695
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("form", { onSubmit: handleSubmit, className: "gs-signin", children: [
696
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { textAlign: "center", marginBottom: "16px" }, children: [
697
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(TerminalIcon, { size: 28 }),
698
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { fontSize: "11px", letterSpacing: "0.15em", textTransform: "uppercase", color: "var(--gs-muted)", marginTop: "8px" }, children: "Connect to Host" })
990
+ if (loading) {
991
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "gs-signin", style: { display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", gap: "12px" }, children: [
992
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(RefreshIcon, { size: 28, className: "gs-spin" }),
993
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { fontSize: "11px", letterSpacing: "0.15em", textTransform: "uppercase", color: "var(--gs-muted)", fontFamily: "var(--gs-font)" }, children: [
994
+ "Connecting to ",
995
+ host || "host",
996
+ "..."
997
+ ] })
998
+ ] });
999
+ }
1000
+ return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("form", { onSubmit: handleSubmit, className: "gs-signin", children: [
1001
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { textAlign: "center", marginBottom: "16px" }, children: [
1002
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(TerminalIcon, { size: 28 }),
1003
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("div", { style: { fontSize: "11px", letterSpacing: "0.15em", textTransform: "uppercase", color: "var(--gs-muted)", marginTop: "8px" }, children: "Connect to Host" })
699
1004
  ] }),
700
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "gs-signin-row", children: [
701
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { flex: 1 }, children: [
702
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { style: labelStyle, children: "Host" }),
703
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("input", { style: inputStyle, value: host, onChange: (e) => setHost(e.target.value), placeholder: "192.168.1.100", required: true, autoFocus: true })
1005
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { className: "gs-signin-row", children: [
1006
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { flex: 1 }, children: [
1007
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("label", { style: labelStyle, children: [
1008
+ "Host ",
1009
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { style: { color: "#ef4444" }, children: "*" })
1010
+ ] }),
1011
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("input", { style: inputStyle, value: host, onChange: (e) => setHost(e.target.value), placeholder: "192.168.1.100", required: true, autoFocus: true })
704
1012
  ] }),
705
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { width: "72px" }, children: [
706
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { style: labelStyle, children: "Port" }),
707
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("input", { style: inputStyle, value: port, onChange: (e) => setPort(e.target.value), placeholder: "23", type: "number", min: "1", max: "65535" })
1013
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { width: "72px" }, children: [
1014
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("label", { style: labelStyle, children: "Port" }),
1015
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("input", { style: inputStyle, value: port, onChange: (e) => setPort(e.target.value), placeholder: "23", type: "number", min: "1", max: "65535" })
708
1016
  ] })
709
1017
  ] }),
710
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
711
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { style: labelStyle, children: "Protocol" }),
712
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("select", { style: { ...inputStyle, appearance: "none" }, value: selectedProtocol, onChange: (e) => setSelectedProtocol(e.target.value), children: PROTOCOL_OPTIONS.map((o) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("option", { value: o.value, children: o.label }, o.value)) })
1018
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { children: [
1019
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("label", { style: labelStyle, children: [
1020
+ "Protocol ",
1021
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { style: { color: "#ef4444" }, children: "*" })
1022
+ ] }),
1023
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("select", { style: { ...inputStyle, appearance: "none" }, value: selectedProtocol, onChange: (e) => setSelectedProtocol(e.target.value), children: PROTOCOL_OPTIONS.map((o) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("option", { value: o.value, children: o.label }, o.value)) })
713
1024
  ] }),
714
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
715
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { style: labelStyle, children: "Username" }),
716
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("input", { style: inputStyle, value: username, onChange: (e) => setUsername(e.target.value), required: true, autoComplete: "username" })
1025
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { children: [
1026
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("label", { style: labelStyle, children: "Username" }),
1027
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("input", { style: inputStyle, value: username, onChange: (e) => setUsername(e.target.value), autoComplete: "username" })
717
1028
  ] }),
718
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { children: [
719
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("label", { style: labelStyle, children: "Password" }),
720
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("input", { style: inputStyle, type: "password", value: password, onChange: (e) => setPassword(e.target.value), required: true, autoComplete: "current-password" })
1029
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { children: [
1030
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("label", { style: labelStyle, children: "Password" }),
1031
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("input", { style: inputStyle, type: "password", value: password, onChange: (e) => setPassword(e.target.value), autoComplete: "current-password" })
721
1032
  ] }),
722
- error && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { color: "#FF6B00", fontSize: "11px", fontFamily: "var(--gs-font)", display: "flex", alignItems: "center", gap: "6px" }, children: [
723
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(AlertTriangleIcon, { size: 12 }),
724
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: error })
1033
+ error && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { color: "#FF6B00", fontSize: "11px", fontFamily: "var(--gs-font)", display: "flex", alignItems: "center", gap: "6px" }, children: [
1034
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(AlertTriangleIcon, { size: 12 }),
1035
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { children: error })
725
1036
  ] }),
726
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { type: "submit", disabled: loading || !host || !username || !password, className: "gs-signin-btn", children: loading ? "Connecting..." : "Connect" })
1037
+ /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("button", { type: "submit", disabled: !host, className: "gs-signin-btn", children: "Connect" })
727
1038
  ] });
728
1039
  }
1040
+
1041
+ // src/components/GreenScreenTerminal.tsx
1042
+ var import_jsx_runtime4 = require("react/jsx-runtime");
1043
+ var noopResult = { success: false, error: "No adapter configured" };
1044
+ var noopAdapter = {
1045
+ getScreen: async () => null,
1046
+ getStatus: async () => ({ connected: false, status: "disconnected" }),
1047
+ sendText: async () => noopResult,
1048
+ sendKey: async () => noopResult,
1049
+ connect: async () => noopResult,
1050
+ disconnect: async () => noopResult,
1051
+ reconnect: async () => noopResult
1052
+ };
729
1053
  function GreenScreenTerminal({
730
- adapter,
1054
+ adapter: externalAdapter,
1055
+ baseUrl,
1056
+ workerUrl,
731
1057
  protocol,
732
1058
  protocolProfile: customProfile,
733
1059
  screenData: externalScreenData,
@@ -740,9 +1066,11 @@ function GreenScreenTerminal({
740
1066
  showHeader = true,
741
1067
  typingAnimation = true,
742
1068
  typingBudgetMs = 60,
743
- inlineSignIn = false,
1069
+ inlineSignIn = true,
744
1070
  defaultProtocol: signInDefaultProtocol,
745
1071
  onSignIn,
1072
+ autoSignedIn,
1073
+ autoFocusDisabled = false,
746
1074
  bootLoader,
747
1075
  headerRight,
748
1076
  overlay,
@@ -753,6 +1081,21 @@ function GreenScreenTerminal({
753
1081
  style
754
1082
  }) {
755
1083
  const profile = customProfile ?? getProtocolProfile(protocol);
1084
+ const [internalAdapter, setInternalAdapter] = (0, import_react5.useState)(null);
1085
+ const baseUrlAdapter = (0, import_react5.useMemo)(
1086
+ () => baseUrl ? new RestAdapter({ baseUrl }) : null,
1087
+ [baseUrl]
1088
+ );
1089
+ const workerUrlAdapter = (0, import_react5.useMemo)(
1090
+ () => workerUrl ? new WebSocketAdapter({ workerUrl }) : null,
1091
+ [workerUrl]
1092
+ );
1093
+ const defaultWsAdapter = (0, import_react5.useMemo)(
1094
+ () => !externalAdapter && !baseUrl && !workerUrl ? new WebSocketAdapter() : null,
1095
+ [externalAdapter, baseUrl, workerUrl]
1096
+ );
1097
+ const adapter = externalAdapter ?? baseUrlAdapter ?? workerUrlAdapter ?? internalAdapter ?? defaultWsAdapter ?? noopAdapter;
1098
+ const isUsingDefaultAdapter = adapter === defaultWsAdapter;
756
1099
  const shouldPoll = pollInterval > 0 && !externalScreenData;
757
1100
  const { data: polledScreenData, error: screenError } = useTerminalScreen(adapter, pollInterval, shouldPoll);
758
1101
  const { sendText: _sendText, sendKey: _sendKey } = useTerminalInput(adapter);
@@ -764,42 +1107,49 @@ function GreenScreenTerminal({
764
1107
  typingAnimation,
765
1108
  typingBudgetMs
766
1109
  );
767
- const screenData = (0, import_react4.useMemo)(() => {
1110
+ const screenData = (0, import_react5.useMemo)(() => {
768
1111
  if (!rawScreenData) return null;
769
1112
  return { ...rawScreenData, content: displayedContent };
770
1113
  }, [rawScreenData, displayedContent]);
771
- const prevScreenSigRef = (0, import_react4.useRef)(void 0);
772
- (0, import_react4.useEffect)(() => {
1114
+ const prevScreenSigRef = (0, import_react5.useRef)(void 0);
1115
+ (0, import_react5.useEffect)(() => {
773
1116
  if (screenData && onScreenChange && screenData.screen_signature !== prevScreenSigRef.current) {
774
1117
  prevScreenSigRef.current = screenData.screen_signature;
775
1118
  onScreenChange(screenData);
776
1119
  }
777
1120
  }, [screenData, onScreenChange]);
778
- const sendText = (0, import_react4.useCallback)(async (text) => _sendText(text), [_sendText]);
779
- const sendKey = (0, import_react4.useCallback)(async (key) => _sendKey(key), [_sendKey]);
780
- const [inputText, setInputText] = (0, import_react4.useState)("");
781
- const [isFocused, setIsFocused] = (0, import_react4.useState)(false);
782
- const terminalRef = (0, import_react4.useRef)(null);
783
- const inputRef = (0, import_react4.useRef)(null);
784
- const [syncedCursor, setSyncedCursor] = (0, import_react4.useState)(null);
785
- const prevRawContentRef = (0, import_react4.useRef)("");
786
- (0, import_react4.useEffect)(() => {
1121
+ const sendText = (0, import_react5.useCallback)(async (text) => _sendText(text), [_sendText]);
1122
+ const sendKey = (0, import_react5.useCallback)(async (key) => _sendKey(key), [_sendKey]);
1123
+ const [inputText, setInputText] = (0, import_react5.useState)("");
1124
+ const [isFocused, setIsFocused] = (0, import_react5.useState)(false);
1125
+ const [showSignInHint, setShowSignInHint] = (0, import_react5.useState)(false);
1126
+ const prevAutoSignedIn = (0, import_react5.useRef)(false);
1127
+ (0, import_react5.useEffect)(() => {
1128
+ if (autoSignedIn && !prevAutoSignedIn.current) setShowSignInHint(true);
1129
+ prevAutoSignedIn.current = !!autoSignedIn;
1130
+ }, [autoSignedIn]);
1131
+ const terminalRef = (0, import_react5.useRef)(null);
1132
+ const inputRef = (0, import_react5.useRef)(null);
1133
+ const [syncedCursor, setSyncedCursor] = (0, import_react5.useState)(null);
1134
+ const prevRawContentRef = (0, import_react5.useRef)("");
1135
+ (0, import_react5.useEffect)(() => {
787
1136
  const newContent = rawScreenData?.content || "";
788
1137
  if (prevRawContentRef.current && newContent && newContent !== prevRawContentRef.current) {
789
1138
  setSyncedCursor(null);
790
1139
  setInputText("");
1140
+ if (showSignInHint) setShowSignInHint(false);
791
1141
  }
792
1142
  prevRawContentRef.current = newContent;
793
1143
  }, [rawScreenData?.content]);
794
- const [autoReconnectAttempt, setAutoReconnectAttempt] = (0, import_react4.useState)(0);
795
- const [isAutoReconnecting, setIsAutoReconnecting] = (0, import_react4.useState)(false);
796
- const reconnectTimeoutRef = (0, import_react4.useRef)(null);
797
- const wasConnectedRef = (0, import_react4.useRef)(false);
798
- const isConnectedRef = (0, import_react4.useRef)(false);
799
- (0, import_react4.useEffect)(() => {
1144
+ const [autoReconnectAttempt, setAutoReconnectAttempt] = (0, import_react5.useState)(0);
1145
+ const [isAutoReconnecting, setIsAutoReconnecting] = (0, import_react5.useState)(false);
1146
+ const reconnectTimeoutRef = (0, import_react5.useRef)(null);
1147
+ const wasConnectedRef = (0, import_react5.useRef)(false);
1148
+ const isConnectedRef = (0, import_react5.useRef)(false);
1149
+ (0, import_react5.useEffect)(() => {
800
1150
  isConnectedRef.current = connStatus?.connected ?? false;
801
1151
  }, [connStatus?.connected]);
802
- (0, import_react4.useEffect)(() => {
1152
+ (0, import_react5.useEffect)(() => {
803
1153
  if (!autoReconnectEnabled) return;
804
1154
  const isConnected = connStatus?.connected;
805
1155
  if (isConnected) {
@@ -835,13 +1185,37 @@ function GreenScreenTerminal({
835
1185
  if (reconnectTimeoutRef.current) clearTimeout(reconnectTimeoutRef.current);
836
1186
  };
837
1187
  }, [connStatus?.connected, autoReconnectAttempt, isAutoReconnecting, reconnecting, reconnect, autoReconnectEnabled, maxAttempts, onNotification]);
838
- const handleSignIn = (0, import_react4.useCallback)(async (config) => {
839
- onSignIn?.(config);
840
- await connect(config);
841
- }, [connect, onSignIn]);
842
- const [showBootLoader, setShowBootLoader] = (0, import_react4.useState)(bootLoader !== false);
843
- const [bootFadingOut, setBootFadingOut] = (0, import_react4.useState)(false);
844
- (0, import_react4.useEffect)(() => {
1188
+ const [connecting, setConnecting] = (0, import_react5.useState)(false);
1189
+ const [signInError, setSignInError] = (0, import_react5.useState)(null);
1190
+ const handleSignIn = (0, import_react5.useCallback)(async (config) => {
1191
+ if (onSignIn) {
1192
+ onSignIn(config);
1193
+ return;
1194
+ }
1195
+ setConnecting(true);
1196
+ setSignInError(null);
1197
+ try {
1198
+ if (!externalAdapter && !baseUrlAdapter) {
1199
+ const port = config.port ? `:${config.port}` : "";
1200
+ const newAdapter = new RestAdapter({ baseUrl: `http://${config.host}${port}` });
1201
+ setInternalAdapter(newAdapter);
1202
+ await newAdapter.connect(config);
1203
+ if (config.username && config.password) setShowSignInHint(true);
1204
+ return;
1205
+ }
1206
+ await connect(config);
1207
+ if (config.username && config.password) setShowSignInHint(true);
1208
+ } catch (err) {
1209
+ setSignInError(err instanceof Error ? err.message : String(err));
1210
+ setConnecting(false);
1211
+ }
1212
+ }, [connect, onSignIn, externalAdapter, baseUrlAdapter]);
1213
+ (0, import_react5.useEffect)(() => {
1214
+ if (connecting && screenData?.content) setConnecting(false);
1215
+ }, [connecting, screenData?.content]);
1216
+ const [showBootLoader, setShowBootLoader] = (0, import_react5.useState)(bootLoader !== false);
1217
+ const [bootFadingOut, setBootFadingOut] = (0, import_react5.useState)(false);
1218
+ (0, import_react5.useEffect)(() => {
845
1219
  if (screenData?.content && showBootLoader) {
846
1220
  setBootFadingOut(true);
847
1221
  setShowBootLoader(false);
@@ -849,25 +1223,54 @@ function GreenScreenTerminal({
849
1223
  return () => clearTimeout(timer);
850
1224
  }
851
1225
  }, [screenData?.content, showBootLoader]);
852
- (0, import_react4.useEffect)(() => {
1226
+ const FOCUS_STORAGE_KEY = "gs-terminal-focused";
1227
+ (0, import_react5.useEffect)(() => {
1228
+ if (!autoFocusDisabled && !readOnly) {
1229
+ try {
1230
+ if (localStorage.getItem(FOCUS_STORAGE_KEY) === "true") {
1231
+ setIsFocused(true);
1232
+ }
1233
+ } catch {
1234
+ }
1235
+ }
1236
+ }, []);
1237
+ (0, import_react5.useEffect)(() => {
1238
+ if (autoFocusDisabled) return;
1239
+ try {
1240
+ localStorage.setItem(FOCUS_STORAGE_KEY, String(isFocused));
1241
+ } catch {
1242
+ }
1243
+ }, [isFocused, autoFocusDisabled]);
1244
+ (0, import_react5.useEffect)(() => {
1245
+ if (isFocused) inputRef.current?.focus();
1246
+ }, [isFocused]);
1247
+ const hadScreenData = (0, import_react5.useRef)(false);
1248
+ (0, import_react5.useEffect)(() => {
1249
+ if (screenData?.content && !hadScreenData.current && !autoFocusDisabled && !readOnly) {
1250
+ hadScreenData.current = true;
1251
+ setIsFocused(true);
1252
+ }
1253
+ if (!screenData?.content) hadScreenData.current = false;
1254
+ }, [screenData?.content, autoFocusDisabled, readOnly]);
1255
+ (0, import_react5.useEffect)(() => {
853
1256
  const handleClickOutside = (event) => {
854
1257
  if (terminalRef.current && !terminalRef.current.contains(event.target)) setIsFocused(false);
855
1258
  };
856
1259
  if (isFocused) document.addEventListener("mousedown", handleClickOutside);
857
1260
  return () => document.removeEventListener("mousedown", handleClickOutside);
858
1261
  }, [isFocused]);
859
- (0, import_react4.useEffect)(() => {
1262
+ (0, import_react5.useEffect)(() => {
860
1263
  if (readOnly && isFocused) {
861
1264
  setIsFocused(false);
862
1265
  inputRef.current?.blur();
863
1266
  }
864
1267
  }, [readOnly, isFocused]);
865
- const handleTerminalClick = (0, import_react4.useCallback)(() => {
1268
+ const handleTerminalClick = (0, import_react5.useCallback)(() => {
866
1269
  if (readOnly) return;
867
1270
  setIsFocused(true);
868
1271
  inputRef.current?.focus();
869
1272
  }, [readOnly]);
870
- const getCurrentField = (0, import_react4.useCallback)(() => {
1273
+ const getCurrentField = (0, import_react5.useCallback)(() => {
871
1274
  const fields = screenData?.fields || [];
872
1275
  const cursorRow = syncedCursor?.row ?? screenData?.cursor_row ?? 0;
873
1276
  const cursorCol = syncedCursor?.col ?? screenData?.cursor_col ?? 0;
@@ -876,7 +1279,7 @@ function GreenScreenTerminal({
876
1279
  }
877
1280
  return null;
878
1281
  }, [screenData, syncedCursor]);
879
- const canTypeMore = (0, import_react4.useCallback)((additionalChars = 1) => {
1282
+ const canTypeMore = (0, import_react5.useCallback)((additionalChars = 1) => {
880
1283
  const currentField = getCurrentField();
881
1284
  if (!currentField) return true;
882
1285
  const cursorCol = (syncedCursor?.col ?? screenData?.cursor_col ?? 0) + inputText.length;
@@ -978,28 +1381,28 @@ function GreenScreenTerminal({
978
1381
  }
979
1382
  return { row: cursorRow, col: cursorCol };
980
1383
  };
981
- const renderTextWithUnderlines = (0, import_react4.useCallback)((text, keyPrefix) => {
1384
+ const renderTextWithUnderlines = (0, import_react5.useCallback)((text, keyPrefix) => {
982
1385
  const underscoreRegex = /_{2,}/g;
983
1386
  const segments = [];
984
1387
  let lastIndex = 0;
985
1388
  let match;
986
1389
  let segmentIndex = 0;
987
1390
  while ((match = underscoreRegex.exec(text)) !== null) {
988
- if (match.index > lastIndex) segments.push(/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: text.substring(lastIndex, match.index) }, `${keyPrefix}-t-${segmentIndex}`));
1391
+ if (match.index > lastIndex) segments.push(/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: text.substring(lastIndex, match.index) }, `${keyPrefix}-t-${segmentIndex}`));
989
1392
  const count = match[0].length;
990
- segments.push(/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: { borderBottom: "1px solid var(--gs-green, #10b981)", display: "inline-block", width: `${count}ch` }, children: " ".repeat(count) }, `${keyPrefix}-u-${segmentIndex}`));
1393
+ segments.push(/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { borderBottom: "1px solid var(--gs-green, #10b981)", display: "inline-block", width: `${count}ch` }, children: " ".repeat(count) }, `${keyPrefix}-u-${segmentIndex}`));
991
1394
  lastIndex = match.index + match[0].length;
992
1395
  segmentIndex++;
993
1396
  }
994
- if (lastIndex < text.length) segments.push(/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: text.substring(lastIndex) }, `${keyPrefix}-e`));
995
- return segments.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_jsx_runtime2.Fragment, { children: segments }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_jsx_runtime2.Fragment, { children: text });
1397
+ if (lastIndex < text.length) segments.push(/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: text.substring(lastIndex) }, `${keyPrefix}-e`));
1398
+ return segments.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_jsx_runtime4.Fragment, { children: segments }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_jsx_runtime4.Fragment, { children: text });
996
1399
  }, []);
997
- const renderRowWithFields = (0, import_react4.useCallback)((line, rowIndex, fields) => {
1400
+ const renderRowWithFields = (0, import_react5.useCallback)((line, rowIndex, fields) => {
998
1401
  const inputFields = fields.filter((f) => f.row === rowIndex && f.is_input);
999
1402
  const highlightedFields = fields.filter((f) => f.row === rowIndex && f.is_protected && f.is_highlighted);
1000
1403
  const reverseFields = fields.filter((f) => f.row === rowIndex && f.is_protected && f.is_reverse);
1001
1404
  const allRowFields = [...inputFields, ...highlightedFields, ...reverseFields];
1002
- if (allRowFields.length === 0) return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: renderTextWithUnderlines(line, `r${rowIndex}`) });
1405
+ if (allRowFields.length === 0) return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: line });
1003
1406
  const sorted = [...allRowFields].sort((a, b) => a.col - b.col);
1004
1407
  const segs = [];
1005
1408
  let lastEnd = 0;
@@ -1007,35 +1410,42 @@ function GreenScreenTerminal({
1007
1410
  sorted.forEach((field, idx) => {
1008
1411
  const fs = field.col;
1009
1412
  const fe = Math.min(field.col + field.length, cols);
1010
- if (fs > lastEnd) segs.push(/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: renderTextWithUnderlines(line.substring(lastEnd, fs), `r${rowIndex}p${idx}`) }, `t${idx}`));
1413
+ if (fs > lastEnd) segs.push(/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: line.substring(lastEnd, fs) }, `t${idx}`));
1011
1414
  const fc = line.substring(fs, fe);
1012
1415
  if (field.is_input) {
1013
- const w = field.length >= 30 ? Math.max(field.length, 40) : field.length;
1014
- segs.push(/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "gs-input-field", style: { borderBottom: "2px solid var(--gs-green, #10b981)", display: "inline-block", minWidth: `${w}ch` }, children: fc }, `f${idx}`));
1416
+ const fieldWidth = Math.min(field.length, cols - fs);
1417
+ const fieldClass = showSignInHint ? "gs-confirmed-field" : field.is_underscored ? "gs-input-field" : void 0;
1418
+ segs.push(/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: fieldClass || void 0, style: { display: "inline-block", width: `${fieldWidth}ch`, overflow: "hidden" }, children: fc }, `f${idx}`));
1015
1419
  } else if (field.is_reverse) {
1016
- segs.push(/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: { color: "#ef4444", fontWeight: "bold" }, children: fc }, `v${idx}`));
1420
+ segs.push(/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { color: "#ef4444", fontWeight: "bold" }, children: fc }, `v${idx}`));
1421
+ } else if (field.is_highlighted) {
1422
+ segs.push(/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { style: { color: "var(--gs-white, #FFFFFF)" }, children: fc }, `h${idx}`));
1017
1423
  } else {
1018
- segs.push(/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: { color: "var(--gs-white, #FFFFFF)" }, children: fc }, `h${idx}`));
1424
+ segs.push(/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: fc }, `h${idx}`));
1019
1425
  }
1020
1426
  lastEnd = fe;
1021
1427
  });
1022
- if (lastEnd < line.length) segs.push(/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: renderTextWithUnderlines(line.substring(lastEnd), `r${rowIndex}e`) }, "te"));
1023
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_jsx_runtime2.Fragment, { children: segs });
1024
- }, [renderTextWithUnderlines, screenData?.cols, profile.defaultCols]);
1428
+ if (lastEnd < line.length) segs.push(/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: line.substring(lastEnd) }, "te"));
1429
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_jsx_runtime4.Fragment, { children: segs });
1430
+ }, [renderTextWithUnderlines, screenData?.cols, profile.defaultCols, showSignInHint]);
1025
1431
  const renderScreen = () => {
1026
1432
  if (showBootLoader && !screenData?.content) {
1027
1433
  if (bootLoader === false) return null;
1028
- if (bootLoader) return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_jsx_runtime2.Fragment, { children: bootLoader });
1029
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(TerminalBootLoader, { brandText: profile.bootText });
1434
+ if (bootLoader) return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_jsx_runtime4.Fragment, { children: bootLoader });
1435
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(TerminalBootLoader, { brandText: profile.bootText });
1030
1436
  }
1031
- if (bootFadingOut && screenData?.content) return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "gs-fade-in", children: renderScreenContent() });
1437
+ if (bootFadingOut && screenData?.content) return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "gs-fade-in", children: renderScreenContent() });
1032
1438
  if (!screenData?.content) {
1033
1439
  if (inlineSignIn && !connStatus?.connected) {
1034
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { width: `${screenData?.cols || profile.defaultCols}ch`, height: `${(screenData?.rows || profile.defaultRows) * 21}px`, display: "flex", alignItems: "center", justifyContent: "center" }, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(InlineSignIn, { defaultProtocol: signInDefaultProtocol || protocol || "tn5250", loading: reconnecting, error: connectError, onConnect: handleSignIn }) });
1440
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { width: "100%", height: `${(screenData?.rows || profile.defaultRows) * 21}px`, display: "flex", alignItems: "center", justifyContent: "center" }, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(InlineSignIn, { defaultProtocol: signInDefaultProtocol || protocol || "tn5250", loading: connecting || reconnecting, error: signInError || connectError, onConnect: handleSignIn }) });
1035
1441
  }
1036
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { width: `${screenData?.cols || profile.defaultCols}ch`, height: `${(screenData?.rows || profile.defaultRows) * 21}px`, display: "flex", alignItems: "center", justifyContent: "center" }, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { textAlign: "center" }, children: [
1037
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { color: "#808080", marginBottom: "12px" }, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(TerminalIcon, { size: 40 }) }),
1038
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("p", { style: { fontFamily: "var(--gs-font)", fontSize: "12px", color: "#808080" }, children: connStatus?.connected ? "Waiting for screen data..." : "Not connected" })
1442
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { width: `${screenData?.cols || profile.defaultCols}ch`, height: `${(screenData?.rows || profile.defaultRows) * 21}px`, display: "flex", alignItems: "center", justifyContent: "center" }, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { textAlign: "center" }, children: [
1443
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { color: "#808080", marginBottom: "12px" }, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(TerminalIcon, { size: 40 }) }),
1444
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("p", { style: { fontFamily: "var(--gs-font)", fontSize: "12px", color: "#808080" }, children: connStatus?.connected ? "Waiting for screen data..." : "Not connected" }),
1445
+ !connStatus?.connected && isUsingDefaultAdapter && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("p", { style: { fontFamily: "var(--gs-font)", fontSize: "11px", color: "#606060", marginTop: "8px" }, children: [
1446
+ "Start the proxy: ",
1447
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("code", { style: { color: "#10b981" }, children: "npx green-screen-proxy --mock" })
1448
+ ] })
1039
1449
  ] }) });
1040
1450
  }
1041
1451
  return renderScreenContent();
@@ -1050,9 +1460,8 @@ function GreenScreenTerminal({
1050
1460
  const fields = screenData.fields || [];
1051
1461
  const ROW_HEIGHT = 21;
1052
1462
  const cursor = getCursorPos();
1053
- const hasInputFields = fields.some((f) => f.is_input);
1054
- const hasCursor = screenData.cursor_row !== void 0 && screenData.cursor_col !== void 0 && (hasInputFields || screenData.cursor_row !== 0 || screenData.cursor_col !== 0);
1055
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { fontFamily: "var(--gs-font)", fontSize: "13px", position: "relative", width: `${cols}ch` }, children: [
1463
+ const hasCursor = screenData.cursor_row !== void 0 && screenData.cursor_col !== void 0;
1464
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { style: { fontFamily: "var(--gs-font)", fontSize: "13px", position: "relative", width: `${cols}ch` }, children: [
1056
1465
  rows.map((line, index) => {
1057
1466
  let displayLine = line;
1058
1467
  if (hasCursor && index === cursor.row && inputText && !animatedCursorPos) {
@@ -1060,12 +1469,13 @@ function GreenScreenTerminal({
1060
1469
  displayLine = (line.substring(0, baseCol) + inputText + line.substring(baseCol + inputText.length)).substring(0, cols).padEnd(cols, " ");
1061
1470
  }
1062
1471
  const headerSegments = index === 0 ? profile.colors.parseHeaderRow(displayLine) : null;
1063
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: headerSegments ? "" : profile.colors.getRowColorClass(index, displayLine, termRows), style: { height: `${ROW_HEIGHT}px`, lineHeight: `${ROW_HEIGHT}px`, whiteSpace: "pre", position: "relative" }, children: [
1064
- headerSegments ? headerSegments.map((seg, i) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: seg.colorClass, children: seg.text }, i)) : renderRowWithFields(displayLine, index, fields),
1065
- hasCursor && index === cursor.row && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "gs-cursor", style: { position: "absolute", left: `${cursor.col}ch`, width: "1ch", height: `${ROW_HEIGHT}px`, top: 0, pointerEvents: "none" } })
1472
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: headerSegments ? "" : profile.colors.getRowColorClass(index, displayLine, termRows), style: { height: `${ROW_HEIGHT}px`, lineHeight: `${ROW_HEIGHT}px`, whiteSpace: "pre", position: "relative" }, children: [
1473
+ headerSegments ? headerSegments.map((seg, i) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: seg.colorClass, children: seg.text }, i)) : renderRowWithFields(displayLine, index, fields),
1474
+ hasCursor && !showSignInHint && index === cursor.row && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "gs-cursor", style: { position: "absolute", left: `${cursor.col}ch`, width: "1ch", height: `${ROW_HEIGHT}px`, top: 0, pointerEvents: "none" } })
1066
1475
  ] }, index);
1067
1476
  }),
1068
- screenData.cursor_row !== void 0 && screenData.cursor_col !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { style: { position: "absolute", bottom: 0, right: 0, fontFamily: "var(--gs-font)", fontSize: "10px", color: "var(--gs-green, #10b981)", pointerEvents: "none", opacity: 0.6 }, children: [
1477
+ showSignInHint && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "gs-signin-hint", children: "Signed in \u2014 press Enter to continue" }),
1478
+ screenData.cursor_row !== void 0 && screenData.cursor_col !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { style: { position: "absolute", bottom: 0, right: 0, fontFamily: "var(--gs-font)", fontSize: "10px", color: "var(--gs-green, #10b981)", pointerEvents: "none", opacity: 0.6 }, children: [
1069
1479
  String(screenData.cursor_row + 1).padStart(2, "0"),
1070
1480
  "/",
1071
1481
  String(screenData.cursor_col + 1).padStart(3, "0")
@@ -1095,49 +1505,49 @@ function GreenScreenTerminal({
1095
1505
  return "#64748b";
1096
1506
  }
1097
1507
  };
1098
- return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: `gs-terminal ${isFocused ? "gs-terminal-focused" : ""} ${className || ""}`, style, children: [
1099
- showHeader && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "gs-header", children: embedded ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
1100
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "gs-header-left", children: [
1101
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(TerminalIcon, { size: 14 }),
1102
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: "TERMINAL" }),
1103
- isFocused && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "gs-badge-focused", children: "FOCUSED" }),
1104
- screenData?.timestamp && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "gs-timestamp", children: new Date(screenData.timestamp).toLocaleTimeString() }),
1105
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "gs-hint", children: readOnly ? "Read-only" : isFocused ? "ESC to exit focus" : "Click to control" })
1508
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: `gs-terminal ${isFocused ? "gs-terminal-focused" : ""} ${className || ""}`, style, children: [
1509
+ showHeader && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "gs-header", children: embedded ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
1510
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: "gs-header-left", children: [
1511
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(TerminalIcon, { size: 14 }),
1512
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: "TERMINAL" }),
1513
+ isFocused && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "gs-badge-focused", children: "FOCUSED" }),
1514
+ screenData?.timestamp && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "gs-timestamp", children: new Date(screenData.timestamp).toLocaleTimeString() }),
1515
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "gs-hint", children: readOnly ? "Read-only" : isFocused ? "ESC to exit focus" : "Click to control" })
1106
1516
  ] }),
1107
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "gs-header-right", children: [
1108
- connStatus?.status && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(KeyIcon, { size: 12, style: { color: getStatusColor(connStatus.status) } }),
1109
- connStatus && (connStatus.connected ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(WifiIcon, { size: 12, style: { color: "var(--gs-green, #10b981)" } }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(WifiOffIcon, { size: 12, style: { color: "#FF6B00" } })),
1110
- onMinimize && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { onClick: (e) => {
1517
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "gs-header-right", children: [
1518
+ connStatus?.status && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(KeyIcon, { size: 12, style: { color: getStatusColor(connStatus.status) } }),
1519
+ connStatus && (connStatus.connected ? /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(WifiIcon, { size: 12, style: { color: "var(--gs-green, #10b981)" } }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(WifiOffIcon, { size: 12, style: { color: "#FF6B00" } })),
1520
+ onMinimize && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { onClick: (e) => {
1111
1521
  e.stopPropagation();
1112
1522
  onMinimize();
1113
- }, className: "gs-btn-icon", title: "Minimize terminal", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(MinimizeIcon, {}) }),
1523
+ }, className: "gs-btn-icon", title: "Minimize terminal", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(MinimizeIcon, {}) }),
1114
1524
  headerRight
1115
1525
  ] })
1116
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
1117
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { className: "gs-header-left", children: [
1118
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(TerminalIcon, { size: 14 }),
1119
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: profile.headerLabel }),
1120
- isFocused && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "gs-badge-focused", children: "FOCUSED" }),
1121
- screenData?.timestamp && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "gs-timestamp", children: new Date(screenData.timestamp).toLocaleTimeString() }),
1122
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "gs-hint", children: readOnly ? "Read-only mode" : isFocused ? "ESC to exit focus" : "Click terminal to control" })
1526
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
1527
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("span", { className: "gs-header-left", children: [
1528
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(TerminalIcon, { size: 14 }),
1529
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: profile.headerLabel }),
1530
+ isFocused && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "gs-badge-focused", children: "FOCUSED" }),
1531
+ screenData?.timestamp && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "gs-timestamp", children: new Date(screenData.timestamp).toLocaleTimeString() }),
1532
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "gs-hint", children: readOnly ? "Read-only mode" : isFocused ? "ESC to exit focus" : "Click terminal to control" })
1123
1533
  ] }),
1124
- /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "gs-header-right", children: [
1125
- connStatus && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "gs-status-group", children: connStatus.connected ? /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
1126
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(WifiIcon, { size: 12, style: { color: "var(--gs-green, #10b981)" } }),
1127
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "gs-host", children: connStatus.host })
1128
- ] }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
1129
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(WifiOffIcon, { size: 12, style: { color: "#FF6B00" } }),
1130
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "gs-disconnected-text", children: isAutoReconnecting || reconnecting ? `RECONNECTING${autoReconnectAttempt > 0 ? ` (${autoReconnectAttempt}/${maxAttempts})` : "..."}` : autoReconnectAttempt >= maxAttempts ? "DISCONNECTED (auto-retry exhausted)" : "DISCONNECTED" }),
1131
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("button", { onClick: handleReconnect, disabled: reconnecting || isAutoReconnecting, className: "gs-btn-icon", title: "Reconnect", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(RefreshIcon, { size: 12, className: reconnecting || isAutoReconnecting ? "gs-spin" : "" }) })
1534
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "gs-header-right", children: [
1535
+ connStatus && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "gs-status-group", children: connStatus.connected ? /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
1536
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(WifiIcon, { size: 12, style: { color: "var(--gs-green, #10b981)" } }),
1537
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "gs-host", children: connStatus.host })
1538
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [
1539
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(WifiOffIcon, { size: 12, style: { color: "#FF6B00" } }),
1540
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "gs-disconnected-text", children: isAutoReconnecting || reconnecting ? `RECONNECTING${autoReconnectAttempt > 0 ? ` (${autoReconnectAttempt}/${maxAttempts})` : "..."}` : autoReconnectAttempt >= maxAttempts ? "DISCONNECTED (auto-retry exhausted)" : "DISCONNECTED" }),
1541
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("button", { onClick: handleReconnect, disabled: reconnecting || isAutoReconnecting, className: "gs-btn-icon", title: "Reconnect", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(RefreshIcon, { size: 12, className: reconnecting || isAutoReconnecting ? "gs-spin" : "" }) })
1132
1542
  ] }) }),
1133
- connStatus?.status && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "gs-status-group", children: [
1134
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(KeyIcon, { size: 12, style: { color: getStatusColor(connStatus.status) } }),
1135
- connStatus.username && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { className: "gs-host", children: connStatus.username })
1543
+ connStatus?.status && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "gs-status-group", children: [
1544
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(KeyIcon, { size: 12, style: { color: getStatusColor(connStatus.status) } }),
1545
+ connStatus.username && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "gs-host", children: connStatus.username })
1136
1546
  ] }),
1137
1547
  headerRight
1138
1548
  ] })
1139
1549
  ] }) }),
1140
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "gs-body", children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
1550
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "gs-body", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
1141
1551
  "div",
1142
1552
  {
1143
1553
  ref: terminalRef,
@@ -1145,17 +1555,17 @@ function GreenScreenTerminal({
1145
1555
  className: `gs-screen ${embedded ? "gs-screen-embedded" : ""}`,
1146
1556
  style: !embedded ? { width: `calc(${screenData?.cols || profile.defaultCols}ch + 24px)`, fontSize: (screenData?.cols ?? profile.defaultCols) > 80 ? "11px" : "13px", fontFamily: "var(--gs-font)" } : void 0,
1147
1557
  children: [
1148
- screenError != null && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "gs-error-banner", children: [
1149
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(AlertTriangleIcon, { size: 14 }),
1150
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: String(screenError) })
1558
+ screenError != null && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "gs-error-banner", children: [
1559
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(AlertTriangleIcon, { size: 14 }),
1560
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: String(screenError) })
1151
1561
  ] }),
1152
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { className: "gs-screen-content", children: renderScreen() }),
1562
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "gs-screen-content", children: renderScreen() }),
1153
1563
  overlay,
1154
- connStatus && !connStatus.connected && screenData && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { className: "gs-overlay", children: [
1155
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(WifiOffIcon, { size: 28 }),
1156
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { children: isAutoReconnecting || reconnecting ? "Reconnecting..." : "Disconnected" })
1564
+ connStatus && !connStatus.connected && screenData && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "gs-overlay", children: [
1565
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(WifiOffIcon, { size: 28 }),
1566
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { children: isAutoReconnecting || reconnecting ? "Reconnecting..." : "Disconnected" })
1157
1567
  ] }),
1158
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1568
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
1159
1569
  "input",
1160
1570
  {
1161
1571
  ref: inputRef,
@@ -1175,66 +1585,6 @@ function GreenScreenTerminal({
1175
1585
  ) })
1176
1586
  ] });
1177
1587
  }
1178
- var TN5250Terminal = GreenScreenTerminal;
1179
-
1180
- // src/adapters/RestAdapter.ts
1181
- var RestAdapter = class {
1182
- constructor(options) {
1183
- this.baseUrl = options.baseUrl.replace(/\/+$/, "");
1184
- this.staticHeaders = options.headers || {};
1185
- this.getHeaders = options.getHeaders;
1186
- }
1187
- async buildHeaders() {
1188
- const dynamic = this.getHeaders ? await this.getHeaders() : {};
1189
- return {
1190
- "Content-Type": "application/json",
1191
- ...this.staticHeaders,
1192
- ...dynamic
1193
- };
1194
- }
1195
- async request(method, path, body) {
1196
- const headers = await this.buildHeaders();
1197
- const response = await fetch(`${this.baseUrl}${path}`, {
1198
- method,
1199
- headers,
1200
- body: body ? JSON.stringify(body) : void 0
1201
- });
1202
- if (!response.ok) {
1203
- const detail = await response.json().catch(() => ({}));
1204
- throw new Error(detail?.detail || `HTTP ${response.status}`);
1205
- }
1206
- return response.json();
1207
- }
1208
- async getScreen() {
1209
- try {
1210
- return await this.request("GET", "/screen");
1211
- } catch (e) {
1212
- const message = e instanceof Error ? e.message : String(e);
1213
- if (message.includes("503") || message.includes("404")) {
1214
- return null;
1215
- }
1216
- throw e;
1217
- }
1218
- }
1219
- async getStatus() {
1220
- return this.request("GET", "/status");
1221
- }
1222
- async sendText(text) {
1223
- return this.request("POST", "/send-text", { text });
1224
- }
1225
- async sendKey(key) {
1226
- return this.request("POST", "/send-key", { key });
1227
- }
1228
- async connect(config) {
1229
- return this.request("POST", "/connect", config);
1230
- }
1231
- async disconnect() {
1232
- return this.request("POST", "/disconnect");
1233
- }
1234
- async reconnect() {
1235
- return this.request("POST", "/reconnect");
1236
- }
1237
- };
1238
1588
 
1239
1589
  // src/utils/rendering.ts
1240
1590
  function getRowColorClass(rowIndex, rowContent) {
@@ -1245,10 +1595,18 @@ function parseHeaderRow(line) {
1245
1595
  }
1246
1596
  // Annotate the CommonJS export names for ESM import in node:
1247
1597
  0 && (module.exports = {
1598
+ AlertTriangleIcon,
1248
1599
  GreenScreenTerminal,
1600
+ InlineSignIn,
1601
+ KeyIcon,
1602
+ MinimizeIcon,
1603
+ RefreshIcon,
1249
1604
  RestAdapter,
1250
- TN5250Terminal,
1251
1605
  TerminalBootLoader,
1606
+ TerminalIcon,
1607
+ WebSocketAdapter,
1608
+ WifiIcon,
1609
+ WifiOffIcon,
1252
1610
  getProtocolProfile,
1253
1611
  getRowColorClass,
1254
1612
  hp6530Profile,
@@ -1257,9 +1615,6 @@ function parseHeaderRow(line) {
1257
1615
  positionToRowCol,
1258
1616
  tn3270Profile,
1259
1617
  tn5250Profile,
1260
- useTN5250Connection,
1261
- useTN5250Screen,
1262
- useTN5250Terminal,
1263
1618
  useTerminalConnection,
1264
1619
  useTerminalInput,
1265
1620
  useTerminalScreen,