green-screen-react 1.1.3 → 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,8 +121,6 @@ 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 */
@@ -134,6 +141,8 @@ interface GreenScreenTerminalProps {
134
141
  onScreenChange?: (screen: ScreenData) => void;
135
142
  /** Callback for minimize action (embedded mode) */
136
143
  onMinimize?: () => void;
144
+ /** Show the keyboard-shortcuts button in the header (default true) */
145
+ showShortcutsButton?: boolean;
137
146
  /** Additional CSS class name */
138
147
  className?: string;
139
148
  /** Inline styles */
@@ -152,7 +161,7 @@ interface GreenScreenTerminalProps {
152
161
  *
153
162
  * Supports: TN5250 (IBM i), TN3270 (z/OS), VT (OpenVMS/Pick), HP 6530 (NonStop)
154
163
  */
155
- 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, bootLoaderReady, headerRight, statusActions, 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;
156
165
 
157
166
  interface TerminalBootLoaderProps {
158
167
  /** Text to display during boot animation */
@@ -236,6 +245,7 @@ declare class RestAdapter implements TerminalAdapter {
236
245
  sendText(text: string): Promise<SendResult>;
237
246
  sendKey(key: string): Promise<SendResult>;
238
247
  setCursor(row: number, col: number): Promise<SendResult>;
248
+ readMdt(modifiedOnly?: boolean): Promise<FieldValue[]>;
239
249
  connect(config?: ConnectConfig): Promise<SendResult>;
240
250
  disconnect(): Promise<SendResult>;
241
251
  reconnect(): Promise<SendResult>;
@@ -266,9 +276,12 @@ declare class WebSocketAdapter implements TerminalAdapter {
266
276
  private status;
267
277
  private pendingScreenResolver;
268
278
  private pendingConnectResolver;
279
+ private pendingMdtResolver;
269
280
  private connectingPromise;
270
281
  private screenListeners;
271
282
  private statusListeners;
283
+ private sessionLostListeners;
284
+ private sessionResumedListeners;
272
285
  private _sessionId;
273
286
  constructor(options?: WebSocketAdapterOptions);
274
287
  private static detectEnvUrl;
@@ -278,11 +291,22 @@ declare class WebSocketAdapter implements TerminalAdapter {
278
291
  onScreen(listener: (screen: ScreenData) => void): () => void;
279
292
  /** Subscribe to status changes */
280
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;
281
304
  getScreen(): Promise<ScreenData | null>;
282
305
  getStatus(): Promise<ConnectionStatus>;
283
306
  sendText(text: string): Promise<SendResult>;
284
307
  sendKey(key: string): Promise<SendResult>;
285
308
  setCursor(row: number, col: number): Promise<SendResult>;
309
+ readMdt(modifiedOnly?: boolean): Promise<FieldValue[]>;
286
310
  connect(config?: ConnectConfig): Promise<SendResult>;
287
311
  /**
288
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,8 +121,6 @@ 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 */
@@ -134,6 +141,8 @@ interface GreenScreenTerminalProps {
134
141
  onScreenChange?: (screen: ScreenData) => void;
135
142
  /** Callback for minimize action (embedded mode) */
136
143
  onMinimize?: () => void;
144
+ /** Show the keyboard-shortcuts button in the header (default true) */
145
+ showShortcutsButton?: boolean;
137
146
  /** Additional CSS class name */
138
147
  className?: string;
139
148
  /** Inline styles */
@@ -152,7 +161,7 @@ interface GreenScreenTerminalProps {
152
161
  *
153
162
  * Supports: TN5250 (IBM i), TN3270 (z/OS), VT (OpenVMS/Pick), HP 6530 (NonStop)
154
163
  */
155
- 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, bootLoaderReady, headerRight, statusActions, 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;
156
165
 
157
166
  interface TerminalBootLoaderProps {
158
167
  /** Text to display during boot animation */
@@ -236,6 +245,7 @@ declare class RestAdapter implements TerminalAdapter {
236
245
  sendText(text: string): Promise<SendResult>;
237
246
  sendKey(key: string): Promise<SendResult>;
238
247
  setCursor(row: number, col: number): Promise<SendResult>;
248
+ readMdt(modifiedOnly?: boolean): Promise<FieldValue[]>;
239
249
  connect(config?: ConnectConfig): Promise<SendResult>;
240
250
  disconnect(): Promise<SendResult>;
241
251
  reconnect(): Promise<SendResult>;
@@ -266,9 +276,12 @@ declare class WebSocketAdapter implements TerminalAdapter {
266
276
  private status;
267
277
  private pendingScreenResolver;
268
278
  private pendingConnectResolver;
279
+ private pendingMdtResolver;
269
280
  private connectingPromise;
270
281
  private screenListeners;
271
282
  private statusListeners;
283
+ private sessionLostListeners;
284
+ private sessionResumedListeners;
272
285
  private _sessionId;
273
286
  constructor(options?: WebSocketAdapterOptions);
274
287
  private static detectEnvUrl;
@@ -278,11 +291,22 @@ declare class WebSocketAdapter implements TerminalAdapter {
278
291
  onScreen(listener: (screen: ScreenData) => void): () => void;
279
292
  /** Subscribe to status changes */
280
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;
281
304
  getScreen(): Promise<ScreenData | null>;
282
305
  getStatus(): Promise<ConnectionStatus>;
283
306
  sendText(text: string): Promise<SendResult>;
284
307
  sendKey(key: string): Promise<SendResult>;
285
308
  setCursor(row: number, col: number): Promise<SendResult>;
309
+ readMdt(modifiedOnly?: boolean): Promise<FieldValue[]>;
286
310
  connect(config?: ConnectConfig): Promise<SendResult>;
287
311
  /**
288
312
  * Reattach to an existing proxy session (e.g. after page reload).