green-screen-react 1.1.2 → 1.2.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/README.md CHANGED
@@ -4,6 +4,8 @@ Multi-protocol legacy terminal React component. Connects to **TN5250** (IBM i /
4
4
 
5
5
  [**Live Preview**](https://visionbridge-solutions.github.io/green-screen-react/)
6
6
 
7
+ > **v1.2.0**: per-field MDT state, `readMdt()` for cheap post-write verification, pluggable session store with `session.lost`/`session.resumed` lifecycle events, lower-level sign-on primitives. See the feature section below. Python integrators can use the new [`green-screen-client`](https://pypi.org/project/green-screen-client/) PyPI package.
8
+
7
9
  ## Install
8
10
 
9
11
  ```bash
@@ -83,12 +85,64 @@ class MyAdapter implements TerminalAdapter {
83
85
  async getStatus() { /* ... */ }
84
86
  async sendText(text: string) { /* ... */ }
85
87
  async sendKey(key: string) { /* ... */ }
88
+ async setCursor?(row: number, col: number) { /* ... */ }
89
+ async readMdt?(modifiedOnly?: boolean) { /* ... */ } // v1.2.0
86
90
  async connect(config?) { /* ... */ }
87
91
  async disconnect() { /* ... */ }
88
92
  async reconnect() { /* ... */ }
89
93
  }
90
94
  ```
91
95
 
96
+ ## v1.2.0 features
97
+
98
+ ### Post-write verification with `readMdt()`
99
+
100
+ Instead of diffing the entire screen after a batch of writes, ask the proxy which fields actually captured input:
101
+
102
+ ```tsx
103
+ import { WebSocketAdapter } from 'green-screen-react';
104
+
105
+ const adapter = new WebSocketAdapter({ workerUrl: 'http://localhost:3001' });
106
+
107
+ // ... after typing into several fields ...
108
+ const modified = await adapter.readMdt(); // only fields with MDT bit set
109
+ const all = await adapter.readMdt(false); // all input fields
110
+
111
+ for (const f of modified) {
112
+ console.log(`row ${f.row} col ${f.col}: "${f.value}"`);
113
+ }
114
+ ```
115
+
116
+ `readMdt` is optional on the `TerminalAdapter` contract — protocols without a per-field modified concept (VT, HP6530) return `[]`.
117
+
118
+ ### Session lifecycle events
119
+
120
+ `WebSocketAdapter` now exposes hooks for session-level transitions. Use them to prompt reconnect UX or surface a clean "session expired" state without string-matching errors:
121
+
122
+ ```tsx
123
+ const adapter = new WebSocketAdapter({ workerUrl: 'http://localhost:3001' });
124
+
125
+ adapter.onSessionLost((sessionId, status) => {
126
+ console.log('lost:', sessionId, status.error);
127
+ // show "Session expired, click to reconnect" UI
128
+ });
129
+
130
+ adapter.onSessionResumed((sessionId) => {
131
+ console.log('reattached:', sessionId);
132
+ });
133
+ ```
134
+
135
+ On page reload, reattach to a session that survived the refresh:
136
+
137
+ ```tsx
138
+ const sessionId = localStorage.getItem('tn5250-session-id');
139
+ if (sessionId) {
140
+ await adapter.reattach(sessionId);
141
+ }
142
+ ```
143
+
144
+ The proxy keeps the TCP connection alive across WebSocket drops within its idle timeout — `reattach` reconnects the WS and replays the current screen.
145
+
92
146
  ## Props
93
147
 
94
148
  | Prop | Type | Default | Description |
@@ -106,6 +160,9 @@ class MyAdapter implements TerminalAdapter {
106
160
  | `bootLoader` | `ReactNode \| false` | default | Custom boot loader |
107
161
  | `onSignIn` | `(config) => void` | - | Sign-in callback |
108
162
  | `onScreenChange` | `(screen) => void` | - | Screen change callback |
163
+ | `bootLoaderReady` | `boolean` | - | Explicit boot-loader dismissal (overrides default "dismiss on first screen"). |
164
+ | `headerRight` | `ReactNode` | - | Custom content in the header's right slot. |
165
+ | `statusActions` | `ReactNode` | - | Custom buttons rendered after connection status groups (e.g. disconnect button). |
109
166
  | `className` | `string` | - | CSS class |
110
167
  | `style` | `CSSProperties` | - | Inline styles |
111
168
 
package/dist/index.d.mts CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import React from 'react';
3
- import { ScreenData, ConnectionStatus, ConnectConfig, ProtocolType } from 'green-screen-types';
4
- export { ConnectConfig, ConnectionStatus, Field, ScreenData, ProtocolType as TerminalProtocol } from 'green-screen-types';
3
+ import { ScreenData, ConnectionStatus, FieldValue, ConnectConfig, ProtocolType } from 'green-screen-types';
4
+ export { ConnectConfig, ConnectionStatus, Field, FieldValue, ScreenData, ProtocolType as TerminalProtocol } from 'green-screen-types';
5
5
 
6
6
  /**
7
7
  * Protocol-specific color/rendering conventions.
@@ -67,6 +67,15 @@ interface TerminalAdapter {
67
67
  sendKey(key: string): Promise<SendResult>;
68
68
  /** Set cursor position (click-to-position) */
69
69
  setCursor?(row: number, col: number): Promise<SendResult>;
70
+ /**
71
+ * Read the current values of input fields, optionally restricted to the
72
+ * ones whose per-field modified-data-tag (MDT) bit is set. Used for cheap
73
+ * post-write verification: after entering a batch of field values, the
74
+ * caller can confirm what actually landed without re-reading the entire
75
+ * screen. Protocols without per-field MDT (VT, HP6530) return an empty
76
+ * array. Optional — adapters without this capability may omit it.
77
+ */
78
+ readMdt?(modifiedOnly?: boolean): Promise<FieldValue[]>;
70
79
  /** Establish a connection, optionally with sign-in config */
71
80
  connect(config?: ConnectConfig): Promise<SendResult>;
72
81
  /** Close the connection */
@@ -112,14 +121,18 @@ interface GreenScreenTerminalProps {
112
121
  defaultProtocol?: ProtocolType;
113
122
  /** Callback when sign-in form is submitted */
114
123
  onSignIn?: (config: ConnectConfig) => void;
115
- /** Show "press Enter to continue" hint after auto sign-in (for external adapter flows) */
116
- autoSignedIn?: boolean;
117
124
  /** Disable auto-focus on the terminal after connecting (default false) */
118
125
  autoFocusDisabled?: boolean;
119
126
  /** Custom boot loader element, or false to disable */
120
127
  bootLoader?: React.ReactNode | false;
128
+ /** When true, dismiss the boot loader. If provided, overrides the default
129
+ * "dismiss when screen data arrives" behavior. Use to keep the boot loader
130
+ * visible during sign-in, startup command execution, etc. */
131
+ bootLoaderReady?: boolean;
121
132
  /** Content for the right side of the header */
122
133
  headerRight?: React.ReactNode;
134
+ /** Content rendered after the connection status groups (WiFi+host, Key+username) */
135
+ statusActions?: React.ReactNode;
123
136
  /** Overlay content (e.g. "Extracting..." state) */
124
137
  overlay?: React.ReactNode;
125
138
  /** Callback for notifications (replaces toast) */
@@ -128,6 +141,8 @@ interface GreenScreenTerminalProps {
128
141
  onScreenChange?: (screen: ScreenData) => void;
129
142
  /** Callback for minimize action (embedded mode) */
130
143
  onMinimize?: () => void;
144
+ /** Show the keyboard-shortcuts button in the header (default true) */
145
+ showShortcutsButton?: boolean;
131
146
  /** Additional CSS class name */
132
147
  className?: string;
133
148
  /** Inline styles */
@@ -146,7 +161,7 @@ interface GreenScreenTerminalProps {
146
161
  *
147
162
  * Supports: TN5250 (IBM i), TN3270 (z/OS), VT (OpenVMS/Pick), HP 6530 (NonStop)
148
163
  */
149
- declare function GreenScreenTerminal({ adapter: externalAdapter, baseUrl, workerUrl, protocol, protocolProfile: customProfile, screenData: externalScreenData, connectionStatus: externalStatus, readOnly, pollInterval, autoReconnect: autoReconnectEnabled, maxReconnectAttempts: maxAttempts, embedded, showHeader, typingAnimation, typingBudgetMs, inlineSignIn, defaultProtocol: signInDefaultProtocol, onSignIn, autoSignedIn, autoFocusDisabled, bootLoader, headerRight, overlay, onNotification, onScreenChange, onMinimize, className, style, }: GreenScreenTerminalProps): react_jsx_runtime.JSX.Element;
164
+ declare function GreenScreenTerminal({ adapter: externalAdapter, baseUrl, workerUrl, protocol, protocolProfile: customProfile, screenData: externalScreenData, connectionStatus: externalStatus, readOnly, pollInterval, autoReconnect: autoReconnectEnabled, maxReconnectAttempts: maxAttempts, embedded, showHeader, typingAnimation, typingBudgetMs, inlineSignIn, defaultProtocol: signInDefaultProtocol, onSignIn, autoFocusDisabled, bootLoader, bootLoaderReady, headerRight, statusActions, overlay, onNotification, onScreenChange, onMinimize, showShortcutsButton, className, style, }: GreenScreenTerminalProps): react_jsx_runtime.JSX.Element;
150
165
 
151
166
  interface TerminalBootLoaderProps {
152
167
  /** Text to display during boot animation */
@@ -230,6 +245,7 @@ declare class RestAdapter implements TerminalAdapter {
230
245
  sendText(text: string): Promise<SendResult>;
231
246
  sendKey(key: string): Promise<SendResult>;
232
247
  setCursor(row: number, col: number): Promise<SendResult>;
248
+ readMdt(modifiedOnly?: boolean): Promise<FieldValue[]>;
233
249
  connect(config?: ConnectConfig): Promise<SendResult>;
234
250
  disconnect(): Promise<SendResult>;
235
251
  reconnect(): Promise<SendResult>;
@@ -260,9 +276,12 @@ declare class WebSocketAdapter implements TerminalAdapter {
260
276
  private status;
261
277
  private pendingScreenResolver;
262
278
  private pendingConnectResolver;
279
+ private pendingMdtResolver;
263
280
  private connectingPromise;
264
281
  private screenListeners;
265
282
  private statusListeners;
283
+ private sessionLostListeners;
284
+ private sessionResumedListeners;
266
285
  private _sessionId;
267
286
  constructor(options?: WebSocketAdapterOptions);
268
287
  private static detectEnvUrl;
@@ -272,11 +291,22 @@ declare class WebSocketAdapter implements TerminalAdapter {
272
291
  onScreen(listener: (screen: ScreenData) => void): () => void;
273
292
  /** Subscribe to status changes */
274
293
  onStatus(listener: (status: ConnectionStatus) => void): () => void;
294
+ /**
295
+ * Subscribe to session-lost notifications. Fires when the proxy detects
296
+ * that the server-side session has terminated (host TCP drop, idle
297
+ * timeout, explicit destroy). Integrators use this to prompt a reconnect
298
+ * or swap to a "session expired" UI without relying on error-string
299
+ * matching.
300
+ */
301
+ onSessionLost(listener: (sessionId: string, status: ConnectionStatus) => void): () => void;
302
+ /** Subscribe to session-resumed notifications (fires after a successful `reattach`). */
303
+ onSessionResumed(listener: (sessionId: string) => void): () => void;
275
304
  getScreen(): Promise<ScreenData | null>;
276
305
  getStatus(): Promise<ConnectionStatus>;
277
306
  sendText(text: string): Promise<SendResult>;
278
307
  sendKey(key: string): Promise<SendResult>;
279
308
  setCursor(row: number, col: number): Promise<SendResult>;
309
+ readMdt(modifiedOnly?: boolean): Promise<FieldValue[]>;
280
310
  connect(config?: ConnectConfig): Promise<SendResult>;
281
311
  /**
282
312
  * Reattach to an existing proxy session (e.g. after page reload).
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import React from 'react';
3
- import { ScreenData, ConnectionStatus, ConnectConfig, ProtocolType } from 'green-screen-types';
4
- export { ConnectConfig, ConnectionStatus, Field, ScreenData, ProtocolType as TerminalProtocol } from 'green-screen-types';
3
+ import { ScreenData, ConnectionStatus, FieldValue, ConnectConfig, ProtocolType } from 'green-screen-types';
4
+ export { ConnectConfig, ConnectionStatus, Field, FieldValue, ScreenData, ProtocolType as TerminalProtocol } from 'green-screen-types';
5
5
 
6
6
  /**
7
7
  * Protocol-specific color/rendering conventions.
@@ -67,6 +67,15 @@ interface TerminalAdapter {
67
67
  sendKey(key: string): Promise<SendResult>;
68
68
  /** Set cursor position (click-to-position) */
69
69
  setCursor?(row: number, col: number): Promise<SendResult>;
70
+ /**
71
+ * Read the current values of input fields, optionally restricted to the
72
+ * ones whose per-field modified-data-tag (MDT) bit is set. Used for cheap
73
+ * post-write verification: after entering a batch of field values, the
74
+ * caller can confirm what actually landed without re-reading the entire
75
+ * screen. Protocols without per-field MDT (VT, HP6530) return an empty
76
+ * array. Optional — adapters without this capability may omit it.
77
+ */
78
+ readMdt?(modifiedOnly?: boolean): Promise<FieldValue[]>;
70
79
  /** Establish a connection, optionally with sign-in config */
71
80
  connect(config?: ConnectConfig): Promise<SendResult>;
72
81
  /** Close the connection */
@@ -112,14 +121,18 @@ interface GreenScreenTerminalProps {
112
121
  defaultProtocol?: ProtocolType;
113
122
  /** Callback when sign-in form is submitted */
114
123
  onSignIn?: (config: ConnectConfig) => void;
115
- /** Show "press Enter to continue" hint after auto sign-in (for external adapter flows) */
116
- autoSignedIn?: boolean;
117
124
  /** Disable auto-focus on the terminal after connecting (default false) */
118
125
  autoFocusDisabled?: boolean;
119
126
  /** Custom boot loader element, or false to disable */
120
127
  bootLoader?: React.ReactNode | false;
128
+ /** When true, dismiss the boot loader. If provided, overrides the default
129
+ * "dismiss when screen data arrives" behavior. Use to keep the boot loader
130
+ * visible during sign-in, startup command execution, etc. */
131
+ bootLoaderReady?: boolean;
121
132
  /** Content for the right side of the header */
122
133
  headerRight?: React.ReactNode;
134
+ /** Content rendered after the connection status groups (WiFi+host, Key+username) */
135
+ statusActions?: React.ReactNode;
123
136
  /** Overlay content (e.g. "Extracting..." state) */
124
137
  overlay?: React.ReactNode;
125
138
  /** Callback for notifications (replaces toast) */
@@ -128,6 +141,8 @@ interface GreenScreenTerminalProps {
128
141
  onScreenChange?: (screen: ScreenData) => void;
129
142
  /** Callback for minimize action (embedded mode) */
130
143
  onMinimize?: () => void;
144
+ /** Show the keyboard-shortcuts button in the header (default true) */
145
+ showShortcutsButton?: boolean;
131
146
  /** Additional CSS class name */
132
147
  className?: string;
133
148
  /** Inline styles */
@@ -146,7 +161,7 @@ interface GreenScreenTerminalProps {
146
161
  *
147
162
  * Supports: TN5250 (IBM i), TN3270 (z/OS), VT (OpenVMS/Pick), HP 6530 (NonStop)
148
163
  */
149
- declare function GreenScreenTerminal({ adapter: externalAdapter, baseUrl, workerUrl, protocol, protocolProfile: customProfile, screenData: externalScreenData, connectionStatus: externalStatus, readOnly, pollInterval, autoReconnect: autoReconnectEnabled, maxReconnectAttempts: maxAttempts, embedded, showHeader, typingAnimation, typingBudgetMs, inlineSignIn, defaultProtocol: signInDefaultProtocol, onSignIn, autoSignedIn, autoFocusDisabled, bootLoader, headerRight, overlay, onNotification, onScreenChange, onMinimize, className, style, }: GreenScreenTerminalProps): react_jsx_runtime.JSX.Element;
164
+ declare function GreenScreenTerminal({ adapter: externalAdapter, baseUrl, workerUrl, protocol, protocolProfile: customProfile, screenData: externalScreenData, connectionStatus: externalStatus, readOnly, pollInterval, autoReconnect: autoReconnectEnabled, maxReconnectAttempts: maxAttempts, embedded, showHeader, typingAnimation, typingBudgetMs, inlineSignIn, defaultProtocol: signInDefaultProtocol, onSignIn, autoFocusDisabled, bootLoader, bootLoaderReady, headerRight, statusActions, overlay, onNotification, onScreenChange, onMinimize, showShortcutsButton, className, style, }: GreenScreenTerminalProps): react_jsx_runtime.JSX.Element;
150
165
 
151
166
  interface TerminalBootLoaderProps {
152
167
  /** Text to display during boot animation */
@@ -230,6 +245,7 @@ declare class RestAdapter implements TerminalAdapter {
230
245
  sendText(text: string): Promise<SendResult>;
231
246
  sendKey(key: string): Promise<SendResult>;
232
247
  setCursor(row: number, col: number): Promise<SendResult>;
248
+ readMdt(modifiedOnly?: boolean): Promise<FieldValue[]>;
233
249
  connect(config?: ConnectConfig): Promise<SendResult>;
234
250
  disconnect(): Promise<SendResult>;
235
251
  reconnect(): Promise<SendResult>;
@@ -260,9 +276,12 @@ declare class WebSocketAdapter implements TerminalAdapter {
260
276
  private status;
261
277
  private pendingScreenResolver;
262
278
  private pendingConnectResolver;
279
+ private pendingMdtResolver;
263
280
  private connectingPromise;
264
281
  private screenListeners;
265
282
  private statusListeners;
283
+ private sessionLostListeners;
284
+ private sessionResumedListeners;
266
285
  private _sessionId;
267
286
  constructor(options?: WebSocketAdapterOptions);
268
287
  private static detectEnvUrl;
@@ -272,11 +291,22 @@ declare class WebSocketAdapter implements TerminalAdapter {
272
291
  onScreen(listener: (screen: ScreenData) => void): () => void;
273
292
  /** Subscribe to status changes */
274
293
  onStatus(listener: (status: ConnectionStatus) => void): () => void;
294
+ /**
295
+ * Subscribe to session-lost notifications. Fires when the proxy detects
296
+ * that the server-side session has terminated (host TCP drop, idle
297
+ * timeout, explicit destroy). Integrators use this to prompt a reconnect
298
+ * or swap to a "session expired" UI without relying on error-string
299
+ * matching.
300
+ */
301
+ onSessionLost(listener: (sessionId: string, status: ConnectionStatus) => void): () => void;
302
+ /** Subscribe to session-resumed notifications (fires after a successful `reattach`). */
303
+ onSessionResumed(listener: (sessionId: string) => void): () => void;
275
304
  getScreen(): Promise<ScreenData | null>;
276
305
  getStatus(): Promise<ConnectionStatus>;
277
306
  sendText(text: string): Promise<SendResult>;
278
307
  sendKey(key: string): Promise<SendResult>;
279
308
  setCursor(row: number, col: number): Promise<SendResult>;
309
+ readMdt(modifiedOnly?: boolean): Promise<FieldValue[]>;
280
310
  connect(config?: ConnectConfig): Promise<SendResult>;
281
311
  /**
282
312
  * Reattach to an existing proxy session (e.g. after page reload).