@hla4ts/transport 0.1.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,386 +1,386 @@
1
- # @hla4ts/transport
2
-
3
- **HLA 4 Federate Protocol Transport Layer**
4
-
5
- This package provides the transport layer for the HLA 4 Federate Protocol, handling TCP/TLS connections, message framing, and low-level communication with HLA 4 RTIs.
6
-
7
- ## Overview
8
-
9
- The Federate Protocol uses a binary framing format over TCP or TLS connections. Each message has a 24-byte header followed by an optional payload. This package handles:
10
-
11
- - **Connection management** - TCP and TLS socket connections
12
- - **Message framing** - Encoding/decoding the 24-byte header
13
- - **Stream handling** - Buffering partial messages, extracting multiple messages from a single chunk
14
-
15
- ## Installation
16
-
17
- ```bash
18
- bun add @hla4ts/transport
19
- ```
20
-
21
- ## Quick Start
22
-
23
- ```typescript
24
- import {
25
- TlsTransport,
26
- MessageType,
27
- encodeMessage,
28
- FEDERATE_PROTOCOL_VERSION,
29
- } from '@hla4ts/transport';
30
-
31
- // Create a TLS transport
32
- const transport = new TlsTransport({
33
- host: 'rti.example.com',
34
- port: 15165,
35
- });
36
-
37
- // Set up event handlers
38
- transport.setEventHandlers({
39
- onMessage: (msg) => {
40
- console.log('Received:', MessageType[msg.header.messageType]);
41
- console.log('Payload size:', msg.payload.length);
42
- },
43
- onClose: (hadError) => {
44
- console.log('Connection closed', hadError ? '(with error)' : '');
45
- },
46
- onError: (err) => {
47
- console.error('Transport error:', err);
48
- },
49
- });
50
-
51
- // Connect
52
- await transport.connect();
53
-
54
- // Send a CTRL_NEW_SESSION message
55
- const payload = new Uint8Array(4);
56
- new DataView(payload.buffer).setUint32(0, FEDERATE_PROTOCOL_VERSION, false);
57
-
58
- const message = encodeMessage(
59
- 1, // sequence number
60
- 0n, // session ID (0 for new session)
61
- 0, // last received sequence number
62
- MessageType.CTRL_NEW_SESSION, // message type
63
- payload // payload
64
- );
65
-
66
- await transport.send(message);
67
-
68
- // Later: disconnect
69
- await transport.disconnect();
70
- ```
71
-
72
- ## Sequence Diagram
73
-
74
- ```mermaid
75
- sequenceDiagram
76
- participant RTI
77
- participant Transport as Tcp/TlsTransport
78
- participant Decoder as FrameDecoder
79
- participant App as Federate Code
80
- RTI-->>Transport: TCP/TLS bytes
81
- Transport-->>Decoder: push(chunk)
82
- Decoder-->>App: onMessage(header, payload)
83
- App->>Transport: send(encoded message)
84
- Transport-->>RTI: TCP/TLS bytes
85
- ```
86
-
87
- ## Message Format
88
-
89
- Every Federate Protocol message has a **24-byte header**:
90
-
91
- ```
92
- ┌─────────────────────────────────────────────────────────────────┐
93
- │ Offset │ Size │ Field │ Description │
94
- ├────────┼───────┼──────────────────────────┼─────────────────────┤
95
- │ 0 │ 4 │ packetSize │ Total message size │
96
- │ 4 │ 4 │ sequenceNumber │ Message sequence # │
97
- │ 8 │ 8 │ sessionId │ Session identifier │
98
- │ 16 │ 4 │ lastReceivedSequenceNum │ ACK for flow ctrl │
99
- │ 20 │ 4 │ messageType │ Type of message │
100
- ├────────┴───────┴──────────────────────────┴─────────────────────┤
101
- │ 24 │ var │ payload │ Message payload │
102
- └─────────────────────────────────────────────────────────────────┘
103
- ```
104
-
105
- All integers are **big-endian** (network byte order).
106
-
107
- ## Message Types
108
-
109
- ### Control Messages (Session Management)
110
-
111
- | Code | Name | Direction | Description |
112
- |------|------|-----------|-------------|
113
- | 1 | `CTRL_NEW_SESSION` | C → S | Request new session |
114
- | 2 | `CTRL_NEW_SESSION_STATUS` | S → C | Session creation result |
115
- | 3 | `CTRL_HEARTBEAT` | Both | Keep-alive ping |
116
- | 4 | `CTRL_HEARTBEAT_RESPONSE` | Both | Keep-alive pong |
117
- | 5 | `CTRL_TERMINATE_SESSION` | C → S | Request session end |
118
- | 6 | `CTRL_SESSION_TERMINATED` | S → C | Session ended |
119
- | 10 | `CTRL_RESUME_REQUEST` | C → S | Resume dropped session |
120
- | 11 | `CTRL_RESUME_STATUS` | S → C | Resume result |
121
-
122
- ### HLA Messages
123
-
124
- | Code | Name | Direction | Description |
125
- |------|------|-----------|-------------|
126
- | 20 | `HLA_CALL_REQUEST` | C → S | RTI service call (protobuf `CallRequest`) |
127
- | 21 | `HLA_CALL_RESPONSE` | S → C | RTI response (protobuf `CallResponse`) |
128
- | 22 | `HLA_CALLBACK_REQUEST` | S → C | Federate callback (protobuf `CallbackRequest`) |
129
- | 23 | `HLA_CALLBACK_RESPONSE` | C → S | Callback ACK (protobuf `CallbackResponse`) |
130
-
131
- ## API Reference
132
-
133
- ### Transports
134
-
135
- #### `TlsTransport`
136
-
137
- Secure TLS connection (recommended for production):
138
-
139
- ```typescript
140
- import { TlsTransport, Ports } from '@hla4ts/transport';
141
-
142
- const transport = new TlsTransport({
143
- host: 'rti.example.com',
144
- port: Ports.TLS, // 15165 (default)
145
- connectionTimeout: 10000, // 10 seconds (default)
146
- noDelay: true, // TCP_NODELAY (default)
147
-
148
- // TLS options
149
- rejectUnauthorized: true, // Verify server cert (default)
150
- ca: '/path/to/ca.pem', // Custom CA (optional)
151
- cert: '/path/to/client.pem', // Client cert for mTLS (optional)
152
- key: '/path/to/client-key.pem', // Client key for mTLS (optional)
153
- serverName: 'rti.example.com', // SNI hostname (optional)
154
- });
155
- ```
156
-
157
- #### `TcpTransport`
158
-
159
- Plain TCP connection (for development/testing only):
160
-
161
- ```typescript
162
- import { TcpTransport, Ports } from '@hla4ts/transport';
163
-
164
- const transport = new TcpTransport({
165
- host: 'localhost',
166
- port: Ports.TCP, // 15164 (default)
167
- });
168
- ```
169
-
170
- ### Transport Interface
171
-
172
- Both transports implement the `Transport` interface:
173
-
174
- ```typescript
175
- interface Transport {
176
- connect(): Promise<void>;
177
- disconnect(): Promise<void>;
178
- isConnected(): boolean;
179
- send(data: Uint8Array): Promise<void>;
180
- setEventHandlers(handlers: TransportEvents): void;
181
- getProtocolName(): string;
182
- getRemoteAddress(): string | null;
183
- }
184
-
185
- interface TransportEvents {
186
- onMessage?: (message: ReceivedMessage) => void;
187
- onClose?: (hadError: boolean) => void;
188
- onError?: (error: Error) => void;
189
- }
190
-
191
- interface ReceivedMessage {
192
- header: MessageHeader;
193
- payload: Uint8Array;
194
- }
195
- ```
196
-
197
- ### Message Header Functions
198
-
199
- ```typescript
200
- import {
201
- encodeHeader,
202
- decodeHeader,
203
- encodeMessage,
204
- getPayloadSize,
205
- HEADER_SIZE, // 24
206
- NO_SESSION_ID, // 0n
207
- NO_SEQUENCE_NUMBER, // 0
208
- } from '@hla4ts/transport';
209
-
210
- // Encode just the header (24 bytes)
211
- const header = encodeHeader(
212
- payloadSize, // payload size in bytes
213
- sequenceNumber, // sequence number
214
- sessionId, // session ID (bigint)
215
- lastReceivedSequenceNum, // ACK
216
- messageType // MessageType enum
217
- );
218
-
219
- // Encode header + payload
220
- const message = encodeMessage(
221
- sequenceNumber,
222
- sessionId,
223
- lastReceivedSequenceNum,
224
- messageType,
225
- payload // optional Uint8Array
226
- );
227
-
228
- // Decode a header
229
- const header = decodeHeader(buffer); // throws on invalid data
230
- console.log(header.packetSize);
231
- console.log(header.sequenceNumber);
232
- console.log(header.sessionId);
233
- console.log(header.messageType);
234
-
235
- // Get payload size from header
236
- const payloadSize = getPayloadSize(header);
237
- ```
238
-
239
- ### Frame Decoder
240
-
241
- For advanced use cases, you can use the `FrameDecoder` directly:
242
-
243
- ```typescript
244
- import { FrameDecoder } from '@hla4ts/transport';
245
-
246
- const decoder = new FrameDecoder();
247
-
248
- decoder.onMessage = (msg) => {
249
- console.log('Complete message received');
250
- console.log('Type:', msg.header.messageType);
251
- console.log('Payload:', msg.payload);
252
- };
253
-
254
- decoder.onError = (err) => {
255
- console.error('Decode error:', err);
256
- };
257
-
258
- // Feed data as it arrives (handles fragmentation automatically)
259
- socket.on('data', (chunk) => {
260
- decoder.push(new Uint8Array(chunk));
261
- });
262
-
263
- // Check buffered data
264
- console.log('Bytes waiting:', decoder.bufferedBytes);
265
-
266
- // Reset after connection reset
267
- decoder.reset();
268
- ```
269
-
270
- ### Constants
271
-
272
- ```typescript
273
- import {
274
- FEDERATE_PROTOCOL_VERSION, // 1
275
- Ports,
276
- Protocol,
277
- NewSessionStatus,
278
- ResumeStatus,
279
- } from '@hla4ts/transport';
280
-
281
- // Default ports
282
- Ports.TCP // 15164
283
- Ports.TLS // 15165
284
- Ports.WS // 80
285
- Ports.WSS // 443
286
-
287
- // Protocol names
288
- Protocol.TCP // "tcp"
289
- Protocol.TLS // "tls"
290
- Protocol.WS // "websocket"
291
- Protocol.WSS // "websocketsecure"
292
-
293
- // Session status codes
294
- NewSessionStatus.SUCCESS // 0
295
- NewSessionStatus.UNSUPPORTED_PROTOCOL_VERSION // 1
296
- NewSessionStatus.OUT_OF_RESOURCES // 2
297
- NewSessionStatus.BAD_MESSAGE // 3
298
- NewSessionStatus.OTHER_ERROR // 99
299
-
300
- // Resume status codes
301
- ResumeStatus.SUCCESS // 0
302
- ResumeStatus.SESSION_NOT_FOUND // 1
303
- ResumeStatus.NOT_ALLOWED // 2
304
- ```
305
-
306
- ## Session Protocol Flow
307
-
308
- ```
309
- ┌─────────────┐ ┌─────────────┐
310
- │ Federate │ │ RTI │
311
- └──────┬──────┘ └──────┬──────┘
312
- │ │
313
- │──── TCP/TLS Connect ──────────────────────>│
314
- │ │
315
- │──── CTRL_NEW_SESSION (version=1) ─────────>│
316
- │ │
317
- │<─── CTRL_NEW_SESSION_STATUS (sessionId) ───│
318
- │ │
319
- │──── HLA_CALL_REQUEST (Connect) ───────────>│
320
- │<─── HLA_CALL_RESPONSE ─────────────────────│
321
- │ │
322
- │──── HLA_CALL_REQUEST (JoinFederation) ────>│
323
- │<─── HLA_CALL_RESPONSE ─────────────────────│
324
- │ │
325
- │ ... HLA calls and callbacks ... │
326
- │ │
327
- │<─── HLA_CALLBACK_REQUEST (Discover...) ────│
328
- │──── HLA_CALLBACK_RESPONSE ────────────────>│
329
- │ │
330
- │──── CTRL_HEARTBEAT ───────────────────────>│
331
- │<─── CTRL_HEARTBEAT_RESPONSE ──────────────│
332
- │ │
333
- │──── CTRL_TERMINATE_SESSION ───────────────>│
334
- │<─── CTRL_SESSION_TERMINATED ──────────────│
335
- │ │
336
- │──── TCP/TLS Disconnect ───────────────────>│
337
- │ │
338
- ```
339
-
340
- ## Error Handling
341
-
342
- ```typescript
343
- try {
344
- await transport.connect();
345
- } catch (err) {
346
- if (err.message.includes('Connection timeout')) {
347
- console.error('RTI not reachable');
348
- } else if (err.message.includes('certificate')) {
349
- console.error('TLS certificate error');
350
- }
351
- }
352
-
353
- transport.setEventHandlers({
354
- onError: (err) => {
355
- console.error('Transport error:', err);
356
- // Attempt reconnection...
357
- },
358
- onClose: (hadError) => {
359
- if (hadError) {
360
- console.error('Connection lost unexpectedly');
361
- }
362
- },
363
- });
364
- ```
365
-
366
- ## Testing
367
-
368
- ```bash
369
- cd packages/transport
370
- bun test
371
- ```
372
-
373
- ## Related Packages
374
-
375
- - [`@hla4ts/proto`](../proto) - Protocol buffer types
376
- - [`@hla4ts/session`](../session) - Session management
377
- - [`@hla4ts/hla-api`](../hla-api) - High-level HLA API facade
378
-
379
- ## References
380
-
381
- - [IEEE 1516-2025](https://standards.ieee.org/standard/1516-2025.html) - HLA 4 Standard
382
- - [Pitch FedProClient](https://github.com/Pitch-Technologies/FedProClient) - Reference implementation
383
-
384
- ## License
385
-
386
- MIT
1
+ # @hla4ts/transport
2
+
3
+ **HLA 4 Federate Protocol Transport Layer**
4
+
5
+ This package provides the transport layer for the HLA 4 Federate Protocol, handling TCP/TLS connections, message framing, and low-level communication with HLA 4 RTIs.
6
+
7
+ ## Overview
8
+
9
+ The Federate Protocol uses a binary framing format over TCP or TLS connections. Each message has a 24-byte header followed by an optional payload. This package handles:
10
+
11
+ - **Connection management** - TCP and TLS socket connections
12
+ - **Message framing** - Encoding/decoding the 24-byte header
13
+ - **Stream handling** - Buffering partial messages, extracting multiple messages from a single chunk
14
+
15
+ ## Installation
16
+
17
+ ```bash
18
+ bun add @hla4ts/transport
19
+ ```
20
+
21
+ ## Quick Start
22
+
23
+ ```typescript
24
+ import {
25
+ TlsTransport,
26
+ MessageType,
27
+ encodeMessage,
28
+ FEDERATE_PROTOCOL_VERSION,
29
+ } from '@hla4ts/transport';
30
+
31
+ // Create a TLS transport
32
+ const transport = new TlsTransport({
33
+ host: 'rti.example.com',
34
+ port: 15165,
35
+ });
36
+
37
+ // Set up event handlers
38
+ transport.setEventHandlers({
39
+ onMessage: (msg) => {
40
+ console.log('Received:', MessageType[msg.header.messageType]);
41
+ console.log('Payload size:', msg.payload.length);
42
+ },
43
+ onClose: (hadError) => {
44
+ console.log('Connection closed', hadError ? '(with error)' : '');
45
+ },
46
+ onError: (err) => {
47
+ console.error('Transport error:', err);
48
+ },
49
+ });
50
+
51
+ // Connect
52
+ await transport.connect();
53
+
54
+ // Send a CTRL_NEW_SESSION message
55
+ const payload = new Uint8Array(4);
56
+ new DataView(payload.buffer).setUint32(0, FEDERATE_PROTOCOL_VERSION, false);
57
+
58
+ const message = encodeMessage(
59
+ 1, // sequence number
60
+ 0n, // session ID (0 for new session)
61
+ 0, // last received sequence number
62
+ MessageType.CTRL_NEW_SESSION, // message type
63
+ payload // payload
64
+ );
65
+
66
+ await transport.send(message);
67
+
68
+ // Later: disconnect
69
+ await transport.disconnect();
70
+ ```
71
+
72
+ ## Sequence Diagram
73
+
74
+ ```mermaid
75
+ sequenceDiagram
76
+ participant RTI
77
+ participant Transport as Tcp/TlsTransport
78
+ participant Decoder as FrameDecoder
79
+ participant App as Federate Code
80
+ RTI-->>Transport: TCP/TLS bytes
81
+ Transport-->>Decoder: push(chunk)
82
+ Decoder-->>App: onMessage(header, payload)
83
+ App->>Transport: send(encoded message)
84
+ Transport-->>RTI: TCP/TLS bytes
85
+ ```
86
+
87
+ ## Message Format
88
+
89
+ Every Federate Protocol message has a **24-byte header**:
90
+
91
+ ```
92
+ ┌─────────────────────────────────────────────────────────────────┐
93
+ │ Offset │ Size │ Field │ Description │
94
+ ├────────┼───────┼──────────────────────────┼─────────────────────┤
95
+ │ 0 │ 4 │ packetSize │ Total message size │
96
+ │ 4 │ 4 │ sequenceNumber │ Message sequence # │
97
+ │ 8 │ 8 │ sessionId │ Session identifier │
98
+ │ 16 │ 4 │ lastReceivedSequenceNum │ ACK for flow ctrl │
99
+ │ 20 │ 4 │ messageType │ Type of message │
100
+ ├────────┴───────┴──────────────────────────┴─────────────────────┤
101
+ │ 24 │ var │ payload │ Message payload │
102
+ └─────────────────────────────────────────────────────────────────┘
103
+ ```
104
+
105
+ All integers are **big-endian** (network byte order).
106
+
107
+ ## Message Types
108
+
109
+ ### Control Messages (Session Management)
110
+
111
+ | Code | Name | Direction | Description |
112
+ |------|------|-----------|-------------|
113
+ | 1 | `CTRL_NEW_SESSION` | C → S | Request new session |
114
+ | 2 | `CTRL_NEW_SESSION_STATUS` | S → C | Session creation result |
115
+ | 3 | `CTRL_HEARTBEAT` | Both | Keep-alive ping |
116
+ | 4 | `CTRL_HEARTBEAT_RESPONSE` | Both | Keep-alive pong |
117
+ | 5 | `CTRL_TERMINATE_SESSION` | C → S | Request session end |
118
+ | 6 | `CTRL_SESSION_TERMINATED` | S → C | Session ended |
119
+ | 10 | `CTRL_RESUME_REQUEST` | C → S | Resume dropped session |
120
+ | 11 | `CTRL_RESUME_STATUS` | S → C | Resume result |
121
+
122
+ ### HLA Messages
123
+
124
+ | Code | Name | Direction | Description |
125
+ |------|------|-----------|-------------|
126
+ | 20 | `HLA_CALL_REQUEST` | C → S | RTI service call (protobuf `CallRequest`) |
127
+ | 21 | `HLA_CALL_RESPONSE` | S → C | RTI response (protobuf `CallResponse`) |
128
+ | 22 | `HLA_CALLBACK_REQUEST` | S → C | Federate callback (protobuf `CallbackRequest`) |
129
+ | 23 | `HLA_CALLBACK_RESPONSE` | C → S | Callback ACK (protobuf `CallbackResponse`) |
130
+
131
+ ## API Reference
132
+
133
+ ### Transports
134
+
135
+ #### `TlsTransport`
136
+
137
+ Secure TLS connection (recommended for production):
138
+
139
+ ```typescript
140
+ import { TlsTransport, Ports } from '@hla4ts/transport';
141
+
142
+ const transport = new TlsTransport({
143
+ host: 'rti.example.com',
144
+ port: Ports.TLS, // 15165 (default)
145
+ connectionTimeout: 10000, // 10 seconds (default)
146
+ noDelay: true, // TCP_NODELAY (default)
147
+
148
+ // TLS options
149
+ rejectUnauthorized: true, // Verify server cert (default)
150
+ ca: '/path/to/ca.pem', // Custom CA (optional)
151
+ cert: '/path/to/client.pem', // Client cert for mTLS (optional)
152
+ key: '/path/to/client-key.pem', // Client key for mTLS (optional)
153
+ serverName: 'rti.example.com', // SNI hostname (optional)
154
+ });
155
+ ```
156
+
157
+ #### `TcpTransport`
158
+
159
+ Plain TCP connection (for development/testing only):
160
+
161
+ ```typescript
162
+ import { TcpTransport, Ports } from '@hla4ts/transport';
163
+
164
+ const transport = new TcpTransport({
165
+ host: 'localhost',
166
+ port: Ports.TCP, // 15164 (default)
167
+ });
168
+ ```
169
+
170
+ ### Transport Interface
171
+
172
+ Both transports implement the `Transport` interface:
173
+
174
+ ```typescript
175
+ interface Transport {
176
+ connect(): Promise<void>;
177
+ disconnect(): Promise<void>;
178
+ isConnected(): boolean;
179
+ send(data: Uint8Array): Promise<void>;
180
+ setEventHandlers(handlers: TransportEvents): void;
181
+ getProtocolName(): string;
182
+ getRemoteAddress(): string | null;
183
+ }
184
+
185
+ interface TransportEvents {
186
+ onMessage?: (message: ReceivedMessage) => void;
187
+ onClose?: (hadError: boolean) => void;
188
+ onError?: (error: Error) => void;
189
+ }
190
+
191
+ interface ReceivedMessage {
192
+ header: MessageHeader;
193
+ payload: Uint8Array;
194
+ }
195
+ ```
196
+
197
+ ### Message Header Functions
198
+
199
+ ```typescript
200
+ import {
201
+ encodeHeader,
202
+ decodeHeader,
203
+ encodeMessage,
204
+ getPayloadSize,
205
+ HEADER_SIZE, // 24
206
+ NO_SESSION_ID, // 0n
207
+ NO_SEQUENCE_NUMBER, // 0
208
+ } from '@hla4ts/transport';
209
+
210
+ // Encode just the header (24 bytes)
211
+ const header = encodeHeader(
212
+ payloadSize, // payload size in bytes
213
+ sequenceNumber, // sequence number
214
+ sessionId, // session ID (bigint)
215
+ lastReceivedSequenceNum, // ACK
216
+ messageType // MessageType enum
217
+ );
218
+
219
+ // Encode header + payload
220
+ const message = encodeMessage(
221
+ sequenceNumber,
222
+ sessionId,
223
+ lastReceivedSequenceNum,
224
+ messageType,
225
+ payload // optional Uint8Array
226
+ );
227
+
228
+ // Decode a header
229
+ const header = decodeHeader(buffer); // throws on invalid data
230
+ console.log(header.packetSize);
231
+ console.log(header.sequenceNumber);
232
+ console.log(header.sessionId);
233
+ console.log(header.messageType);
234
+
235
+ // Get payload size from header
236
+ const payloadSize = getPayloadSize(header);
237
+ ```
238
+
239
+ ### Frame Decoder
240
+
241
+ For advanced use cases, you can use the `FrameDecoder` directly:
242
+
243
+ ```typescript
244
+ import { FrameDecoder } from '@hla4ts/transport';
245
+
246
+ const decoder = new FrameDecoder();
247
+
248
+ decoder.onMessage = (msg) => {
249
+ console.log('Complete message received');
250
+ console.log('Type:', msg.header.messageType);
251
+ console.log('Payload:', msg.payload);
252
+ };
253
+
254
+ decoder.onError = (err) => {
255
+ console.error('Decode error:', err);
256
+ };
257
+
258
+ // Feed data as it arrives (handles fragmentation automatically)
259
+ socket.on('data', (chunk) => {
260
+ decoder.push(new Uint8Array(chunk));
261
+ });
262
+
263
+ // Check buffered data
264
+ console.log('Bytes waiting:', decoder.bufferedBytes);
265
+
266
+ // Reset after connection reset
267
+ decoder.reset();
268
+ ```
269
+
270
+ ### Constants
271
+
272
+ ```typescript
273
+ import {
274
+ FEDERATE_PROTOCOL_VERSION, // 1
275
+ Ports,
276
+ Protocol,
277
+ NewSessionStatus,
278
+ ResumeStatus,
279
+ } from '@hla4ts/transport';
280
+
281
+ // Default ports
282
+ Ports.TCP // 15164
283
+ Ports.TLS // 15165
284
+ Ports.WS // 80
285
+ Ports.WSS // 443
286
+
287
+ // Protocol names
288
+ Protocol.TCP // "tcp"
289
+ Protocol.TLS // "tls"
290
+ Protocol.WS // "websocket"
291
+ Protocol.WSS // "websocketsecure"
292
+
293
+ // Session status codes
294
+ NewSessionStatus.SUCCESS // 0
295
+ NewSessionStatus.UNSUPPORTED_PROTOCOL_VERSION // 1
296
+ NewSessionStatus.OUT_OF_RESOURCES // 2
297
+ NewSessionStatus.BAD_MESSAGE // 3
298
+ NewSessionStatus.OTHER_ERROR // 99
299
+
300
+ // Resume status codes
301
+ ResumeStatus.SUCCESS // 0
302
+ ResumeStatus.SESSION_NOT_FOUND // 1
303
+ ResumeStatus.NOT_ALLOWED // 2
304
+ ```
305
+
306
+ ## Session Protocol Flow
307
+
308
+ ```
309
+ ┌─────────────┐ ┌─────────────┐
310
+ │ Federate │ │ RTI │
311
+ └──────┬──────┘ └──────┬──────┘
312
+ │ │
313
+ │──── TCP/TLS Connect ──────────────────────>│
314
+ │ │
315
+ │──── CTRL_NEW_SESSION (version=1) ─────────>│
316
+ │ │
317
+ │<─── CTRL_NEW_SESSION_STATUS (sessionId) ───│
318
+ │ │
319
+ │──── HLA_CALL_REQUEST (Connect) ───────────>│
320
+ │<─── HLA_CALL_RESPONSE ─────────────────────│
321
+ │ │
322
+ │──── HLA_CALL_REQUEST (JoinFederation) ────>│
323
+ │<─── HLA_CALL_RESPONSE ─────────────────────│
324
+ │ │
325
+ │ ... HLA calls and callbacks ... │
326
+ │ │
327
+ │<─── HLA_CALLBACK_REQUEST (Discover...) ────│
328
+ │──── HLA_CALLBACK_RESPONSE ────────────────>│
329
+ │ │
330
+ │──── CTRL_HEARTBEAT ───────────────────────>│
331
+ │<─── CTRL_HEARTBEAT_RESPONSE ──────────────│
332
+ │ │
333
+ │──── CTRL_TERMINATE_SESSION ───────────────>│
334
+ │<─── CTRL_SESSION_TERMINATED ──────────────│
335
+ │ │
336
+ │──── TCP/TLS Disconnect ───────────────────>│
337
+ │ │
338
+ ```
339
+
340
+ ## Error Handling
341
+
342
+ ```typescript
343
+ try {
344
+ await transport.connect();
345
+ } catch (err) {
346
+ if (err.message.includes('Connection timeout')) {
347
+ console.error('RTI not reachable');
348
+ } else if (err.message.includes('certificate')) {
349
+ console.error('TLS certificate error');
350
+ }
351
+ }
352
+
353
+ transport.setEventHandlers({
354
+ onError: (err) => {
355
+ console.error('Transport error:', err);
356
+ // Attempt reconnection...
357
+ },
358
+ onClose: (hadError) => {
359
+ if (hadError) {
360
+ console.error('Connection lost unexpectedly');
361
+ }
362
+ },
363
+ });
364
+ ```
365
+
366
+ ## Testing
367
+
368
+ ```bash
369
+ cd packages/transport
370
+ bun test
371
+ ```
372
+
373
+ ## Related Packages
374
+
375
+ - [`@hla4ts/proto`](../proto) - Protocol buffer types
376
+ - [`@hla4ts/session`](../session) - Session management
377
+ - [`@hla4ts/hla-api`](../hla-api) - High-level HLA API facade
378
+
379
+ ## References
380
+
381
+ - [IEEE 1516-2025](https://standards.ieee.org/standard/1516-2025.html) - HLA 4 Standard
382
+ - [Pitch FedProClient](https://github.com/Pitch-Technologies/FedProClient) - Reference implementation
383
+
384
+ ## License
385
+
386
+ MIT