@hla4ts/hla-api 0.1.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 +436 -0
- package/package.json +48 -0
- package/src/callback-dispatcher.ts +673 -0
- package/src/converters.ts +449 -0
- package/src/encoding.ts +52 -0
- package/src/exceptions.ts +971 -0
- package/src/federate-ambassador.ts +874 -0
- package/src/index.ts +378 -0
- package/src/rti-ambassador.ts +1441 -0
- package/src/types.ts +440 -0
package/README.md
ADDED
|
@@ -0,0 +1,436 @@
|
|
|
1
|
+
# @hla4ts/hla-api
|
|
2
|
+
|
|
3
|
+
**High-level HLA 4 API for TypeScript**
|
|
4
|
+
|
|
5
|
+
This package provides a TypeScript-friendly API for building HLA 4 (IEEE 1516-2025) federates using the Federate Protocol. It wraps the low-level session and transport layers with a familiar RTI Ambassador / Federate Ambassador pattern.
|
|
6
|
+
|
|
7
|
+
## Overview
|
|
8
|
+
|
|
9
|
+
The HLA API package provides:
|
|
10
|
+
|
|
11
|
+
- **RTIAmbassador** - Main interface for federate-to-RTI communication
|
|
12
|
+
- **FederateAmbassador** - Callback interface for RTI-to-federate communication
|
|
13
|
+
- **Exception classes** - Type-safe HLA exception handling
|
|
14
|
+
- **Type definitions** - Handle types, value maps, and configuration types
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
bun add @hla4ts/hla-api
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Quick Start
|
|
23
|
+
|
|
24
|
+
```typescript
|
|
25
|
+
import {
|
|
26
|
+
RTIAmbassador,
|
|
27
|
+
BaseFederateAmbassador,
|
|
28
|
+
CallbackModel,
|
|
29
|
+
ResignAction,
|
|
30
|
+
} from '@hla4ts/hla-api';
|
|
31
|
+
|
|
32
|
+
// 1. Create your Federate Ambassador by extending the base class
|
|
33
|
+
class MyFederateAmbassador extends BaseFederateAmbassador {
|
|
34
|
+
override discoverObjectInstance(
|
|
35
|
+
objectInstance: Uint8Array,
|
|
36
|
+
objectClass: Uint8Array,
|
|
37
|
+
objectInstanceName: string,
|
|
38
|
+
producingFederate: Uint8Array
|
|
39
|
+
): void {
|
|
40
|
+
console.log(`Discovered object: ${objectInstanceName}`);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
override reflectAttributeValues(
|
|
44
|
+
objectInstance: Uint8Array,
|
|
45
|
+
attributeValues: Array<{ attributeHandle: Uint8Array; value: Uint8Array }>,
|
|
46
|
+
userSuppliedTag: Uint8Array,
|
|
47
|
+
transportationType: Uint8Array,
|
|
48
|
+
producingFederate: Uint8Array
|
|
49
|
+
): void {
|
|
50
|
+
console.log(`Received ${attributeValues.length} attribute updates`);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
override receiveInteraction(
|
|
54
|
+
interactionClass: Uint8Array,
|
|
55
|
+
parameterValues: Array<{ parameterHandle: Uint8Array; value: Uint8Array }>,
|
|
56
|
+
userSuppliedTag: Uint8Array,
|
|
57
|
+
transportationType: Uint8Array,
|
|
58
|
+
producingFederate: Uint8Array
|
|
59
|
+
): void {
|
|
60
|
+
console.log(`Received interaction with ${parameterValues.length} parameters`);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// 2. Create the RTI Ambassador
|
|
65
|
+
const rtiAmbassador = new RTIAmbassador({
|
|
66
|
+
host: 'rti.example.com',
|
|
67
|
+
port: 15165, // TLS port (default)
|
|
68
|
+
useTls: true,
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
// 3. Connect to the RTI
|
|
72
|
+
const federateAmbassador = new MyFederateAmbassador();
|
|
73
|
+
await rtiAmbassador.connect(federateAmbassador, {
|
|
74
|
+
callbackModel: CallbackModel.EVOKED,
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
// 4. Join a federation
|
|
78
|
+
const joinResult = await rtiAmbassador.joinFederationExecution(
|
|
79
|
+
'MyFederateType',
|
|
80
|
+
'TestFederation'
|
|
81
|
+
);
|
|
82
|
+
console.log(`Joined as federate with handle: ${joinResult.federateHandle}`);
|
|
83
|
+
|
|
84
|
+
// 5. Get handles for FOM elements
|
|
85
|
+
const objectClassHandle = await rtiAmbassador.getObjectClassHandle(
|
|
86
|
+
'HLAobjectRoot.MyClass'
|
|
87
|
+
);
|
|
88
|
+
const attributeHandle = await rtiAmbassador.getAttributeHandle(
|
|
89
|
+
objectClassHandle,
|
|
90
|
+
'MyAttribute'
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
// 6. Publish and subscribe
|
|
94
|
+
await rtiAmbassador.publishObjectClassAttributes(objectClassHandle, [attributeHandle]);
|
|
95
|
+
await rtiAmbassador.subscribeObjectClassAttributes(objectClassHandle, [attributeHandle]);
|
|
96
|
+
|
|
97
|
+
// 7. Register an object instance
|
|
98
|
+
const objectInstance = await rtiAmbassador.registerObjectInstance(objectClassHandle);
|
|
99
|
+
|
|
100
|
+
// 8. Update attributes
|
|
101
|
+
await rtiAmbassador.updateAttributeValues(
|
|
102
|
+
objectInstance,
|
|
103
|
+
[{ attributeHandle, value: new TextEncoder().encode('Hello HLA!') }],
|
|
104
|
+
new Uint8Array() // user-supplied tag
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
// 9. Send an interaction
|
|
108
|
+
const interactionClass = await rtiAmbassador.getInteractionClassHandle(
|
|
109
|
+
'HLAinteractionRoot.MyInteraction'
|
|
110
|
+
);
|
|
111
|
+
const parameterHandle = await rtiAmbassador.getParameterHandle(
|
|
112
|
+
interactionClass,
|
|
113
|
+
'MyParameter'
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
await rtiAmbassador.publishInteractionClass(interactionClass);
|
|
117
|
+
await rtiAmbassador.sendInteraction(
|
|
118
|
+
interactionClass,
|
|
119
|
+
[{ parameterHandle, value: new TextEncoder().encode('Hello!') }],
|
|
120
|
+
new Uint8Array()
|
|
121
|
+
);
|
|
122
|
+
|
|
123
|
+
// 10. Clean up
|
|
124
|
+
await rtiAmbassador.resignFederationExecution(ResignAction.DELETE_OBJECTS_THEN_DIVEST);
|
|
125
|
+
await rtiAmbassador.disconnect();
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## Sequence Diagram
|
|
129
|
+
|
|
130
|
+
```mermaid
|
|
131
|
+
sequenceDiagram
|
|
132
|
+
participant App as Federate Code
|
|
133
|
+
participant RTI as RTI
|
|
134
|
+
participant RTIA as RTIAmbassador
|
|
135
|
+
participant Session
|
|
136
|
+
participant CB as CallbackDispatcher
|
|
137
|
+
participant FA as FederateAmbassador
|
|
138
|
+
App->>RTIA: connect(federateAmbassador)
|
|
139
|
+
RTIA->>Session: start()
|
|
140
|
+
Session-->>RTI: HLA_CALL_REQUEST (Connect)
|
|
141
|
+
RTI-->>Session: HLA_CALL_RESPONSE
|
|
142
|
+
App->>RTIA: joinFederationExecution(...)
|
|
143
|
+
RTIA->>Session: HLA_CALL_REQUEST
|
|
144
|
+
RTI-->>Session: HLA_CALL_RESPONSE
|
|
145
|
+
RTI-->>Session: HLA_CALLBACK_REQUEST
|
|
146
|
+
Session-->>CB: callback bytes
|
|
147
|
+
CB-->>FA: dispatch callback
|
|
148
|
+
CB-->>Session: CallbackResponse
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## API Reference
|
|
152
|
+
|
|
153
|
+
### RTIAmbassador
|
|
154
|
+
|
|
155
|
+
The main interface for communicating with the RTI.
|
|
156
|
+
|
|
157
|
+
#### Constructor
|
|
158
|
+
|
|
159
|
+
```typescript
|
|
160
|
+
new RTIAmbassador(options: RTIAmbassadorOptions)
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
**Options:**
|
|
164
|
+
|
|
165
|
+
| Option | Type | Default | Description |
|
|
166
|
+
|--------|------|---------|-------------|
|
|
167
|
+
| `host` | `string` | *required* | RTI host address |
|
|
168
|
+
| `port` | `number` | `15165` (TLS) / `15164` (TCP) | RTI port |
|
|
169
|
+
| `useTls` | `boolean` | `true` | Use TLS encryption |
|
|
170
|
+
| `connectionTimeout` | `number` | `30000` | Connection timeout (ms) |
|
|
171
|
+
| `responseTimeout` | `number` | `180000` | Response timeout (ms) |
|
|
172
|
+
| `tlsOptions` | `object` | `{}` | TLS options (ca, cert, key) |
|
|
173
|
+
|
|
174
|
+
#### Connection Methods
|
|
175
|
+
|
|
176
|
+
```typescript
|
|
177
|
+
// Connect to RTI
|
|
178
|
+
await rtiAmbassador.connect(federateAmbassador, {
|
|
179
|
+
callbackModel: CallbackModel.EVOKED,
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
// Check connection status
|
|
183
|
+
if (rtiAmbassador.isConnected) {
|
|
184
|
+
// ...
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Disconnect
|
|
188
|
+
await rtiAmbassador.disconnect();
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
#### Federation Management
|
|
192
|
+
|
|
193
|
+
```typescript
|
|
194
|
+
// Create a federation
|
|
195
|
+
await rtiAmbassador.createFederationExecution('FederationName', fomModule);
|
|
196
|
+
|
|
197
|
+
// Join a federation
|
|
198
|
+
const joinResult = await rtiAmbassador.joinFederationExecution(
|
|
199
|
+
'FederateType',
|
|
200
|
+
'FederationName'
|
|
201
|
+
);
|
|
202
|
+
|
|
203
|
+
// Resign from a federation
|
|
204
|
+
await rtiAmbassador.resignFederationExecution(ResignAction.DELETE_OBJECTS_THEN_DIVEST);
|
|
205
|
+
|
|
206
|
+
// Destroy a federation
|
|
207
|
+
await rtiAmbassador.destroyFederationExecution('FederationName');
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
#### Declaration Management
|
|
211
|
+
|
|
212
|
+
```typescript
|
|
213
|
+
// Publish object class attributes
|
|
214
|
+
await rtiAmbassador.publishObjectClassAttributes(objectClass, [attr1, attr2]);
|
|
215
|
+
|
|
216
|
+
// Subscribe to object class attributes
|
|
217
|
+
await rtiAmbassador.subscribeObjectClassAttributes(objectClass, [attr1, attr2]);
|
|
218
|
+
|
|
219
|
+
// Publish an interaction class
|
|
220
|
+
await rtiAmbassador.publishInteractionClass(interactionClass);
|
|
221
|
+
|
|
222
|
+
// Subscribe to an interaction class
|
|
223
|
+
await rtiAmbassador.subscribeInteractionClass(interactionClass);
|
|
224
|
+
|
|
225
|
+
// Unsubscribe/unpublish
|
|
226
|
+
await rtiAmbassador.unpublishObjectClass(objectClass);
|
|
227
|
+
await rtiAmbassador.unsubscribeInteractionClass(interactionClass);
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
#### Object Management
|
|
231
|
+
|
|
232
|
+
```typescript
|
|
233
|
+
// Register an object instance
|
|
234
|
+
const objectHandle = await rtiAmbassador.registerObjectInstance(objectClass);
|
|
235
|
+
|
|
236
|
+
// Register with a specific name
|
|
237
|
+
const namedObject = await rtiAmbassador.registerObjectInstanceWithName(
|
|
238
|
+
objectClass,
|
|
239
|
+
'MyObjectName'
|
|
240
|
+
);
|
|
241
|
+
|
|
242
|
+
// Update attribute values
|
|
243
|
+
await rtiAmbassador.updateAttributeValues(
|
|
244
|
+
objectHandle,
|
|
245
|
+
[{ attributeHandle: attr1, value: new Uint8Array([1, 2, 3]) }],
|
|
246
|
+
userSuppliedTag
|
|
247
|
+
);
|
|
248
|
+
|
|
249
|
+
// Send an interaction
|
|
250
|
+
await rtiAmbassador.sendInteraction(
|
|
251
|
+
interactionClass,
|
|
252
|
+
[{ parameterHandle: param1, value: new Uint8Array([1, 2, 3]) }],
|
|
253
|
+
userSuppliedTag
|
|
254
|
+
);
|
|
255
|
+
|
|
256
|
+
// Delete an object instance
|
|
257
|
+
await rtiAmbassador.deleteObjectInstance(objectHandle, userSuppliedTag);
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
#### Time Management
|
|
261
|
+
|
|
262
|
+
```typescript
|
|
263
|
+
// Enable time regulation
|
|
264
|
+
await rtiAmbassador.enableTimeRegulation(lookahead);
|
|
265
|
+
|
|
266
|
+
// Enable time constrained
|
|
267
|
+
await rtiAmbassador.enableTimeConstrained();
|
|
268
|
+
|
|
269
|
+
// Query GALT/LITS and lookahead
|
|
270
|
+
const galt = await rtiAmbassador.queryGALT();
|
|
271
|
+
const lits = await rtiAmbassador.queryLITS();
|
|
272
|
+
const lookahead = await rtiAmbassador.queryLookahead();
|
|
273
|
+
|
|
274
|
+
// Request time advance
|
|
275
|
+
await rtiAmbassador.timeAdvanceRequest(targetTime);
|
|
276
|
+
|
|
277
|
+
// Disable time management
|
|
278
|
+
await rtiAmbassador.disableTimeRegulation();
|
|
279
|
+
await rtiAmbassador.disableTimeConstrained();
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
#### HLAinteger64Time Helpers
|
|
283
|
+
|
|
284
|
+
```typescript
|
|
285
|
+
import {
|
|
286
|
+
encodeHLAinteger64Time,
|
|
287
|
+
decodeHLAinteger64Time,
|
|
288
|
+
} from '@hla4ts/hla-api';
|
|
289
|
+
|
|
290
|
+
const encodedTime = encodeHLAinteger64Time(1_000_000n);
|
|
291
|
+
const decodedTime = decodeHLAinteger64Time(encodedTime);
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
#### Support Services
|
|
295
|
+
|
|
296
|
+
```typescript
|
|
297
|
+
// Get handles by name
|
|
298
|
+
const classHandle = await rtiAmbassador.getObjectClassHandle('HLAobjectRoot.MyClass');
|
|
299
|
+
const attrHandle = await rtiAmbassador.getAttributeHandle(classHandle, 'MyAttribute');
|
|
300
|
+
const interactionHandle = await rtiAmbassador.getInteractionClassHandle('HLAinteractionRoot.MyInteraction');
|
|
301
|
+
const paramHandle = await rtiAmbassador.getParameterHandle(interactionHandle, 'MyParameter');
|
|
302
|
+
|
|
303
|
+
// Get names by handle
|
|
304
|
+
const className = await rtiAmbassador.getObjectClassName(classHandle);
|
|
305
|
+
const attrName = await rtiAmbassador.getAttributeName(classHandle, attrHandle);
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
### FederateAmbassador
|
|
309
|
+
|
|
310
|
+
Interface for receiving callbacks from the RTI. Extend `BaseFederateAmbassador` and override the callbacks you need:
|
|
311
|
+
|
|
312
|
+
```typescript
|
|
313
|
+
class MyFederateAmbassador extends BaseFederateAmbassador {
|
|
314
|
+
// Object discovery
|
|
315
|
+
override discoverObjectInstance(objectInstance, objectClass, name, producer) {
|
|
316
|
+
// Handle object discovery
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
// Attribute updates
|
|
320
|
+
override reflectAttributeValues(objectInstance, attributeValues, tag, transport, producer) {
|
|
321
|
+
// Handle attribute update
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
// Interactions
|
|
325
|
+
override receiveInteraction(interactionClass, parameters, tag, transport, producer) {
|
|
326
|
+
// Handle interaction
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// Time management
|
|
330
|
+
override timeAdvanceGrant(time) {
|
|
331
|
+
// Handle time advance grant
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
// Object removal
|
|
335
|
+
override removeObjectInstance(objectInstance, tag, producer) {
|
|
336
|
+
// Handle object removal
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
```
|
|
340
|
+
|
|
341
|
+
### Exception Handling
|
|
342
|
+
|
|
343
|
+
All HLA exceptions are mapped to TypeScript classes:
|
|
344
|
+
|
|
345
|
+
```typescript
|
|
346
|
+
import {
|
|
347
|
+
NotConnected,
|
|
348
|
+
FederationExecutionDoesNotExist,
|
|
349
|
+
ObjectClassNotDefined,
|
|
350
|
+
RTIinternalError,
|
|
351
|
+
} from '@hla4ts/hla-api';
|
|
352
|
+
|
|
353
|
+
try {
|
|
354
|
+
await rtiAmbassador.joinFederationExecution('Type', 'NonExistentFederation');
|
|
355
|
+
} catch (error) {
|
|
356
|
+
if (error instanceof FederationExecutionDoesNotExist) {
|
|
357
|
+
console.log('Federation does not exist');
|
|
358
|
+
} else if (error instanceof NotConnected) {
|
|
359
|
+
console.log('Not connected to RTI');
|
|
360
|
+
} else if (error instanceof RTIinternalError) {
|
|
361
|
+
console.log('RTI internal error:', error.message);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
## Handle Types
|
|
367
|
+
|
|
368
|
+
Handles are opaque `Uint8Array` values. The package provides utility functions:
|
|
369
|
+
|
|
370
|
+
```typescript
|
|
371
|
+
import { handlesEqual, handleToHex, handleFromHex } from '@hla4ts/hla-api';
|
|
372
|
+
|
|
373
|
+
// Compare handles
|
|
374
|
+
if (handlesEqual(handle1, handle2)) {
|
|
375
|
+
// Handles are equal
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
// Convert to hex string (for debugging)
|
|
379
|
+
console.log(handleToHex(handle)); // "0a1b2c3d..."
|
|
380
|
+
|
|
381
|
+
// Parse from hex string
|
|
382
|
+
const handle = handleFromHex("0a1b2c3d");
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
## FOM Module Types
|
|
386
|
+
|
|
387
|
+
When creating federations, you can provide FOM modules in different formats:
|
|
388
|
+
|
|
389
|
+
```typescript
|
|
390
|
+
// Inline XML content
|
|
391
|
+
const inlineModule: FomModule = {
|
|
392
|
+
type: 'inline',
|
|
393
|
+
content: '<?xml version="1.0"?>...',
|
|
394
|
+
};
|
|
395
|
+
|
|
396
|
+
// File with binary content
|
|
397
|
+
const fileModule: FomModule = {
|
|
398
|
+
type: 'file',
|
|
399
|
+
name: 'myFom.xml',
|
|
400
|
+
content: new Uint8Array([...]),
|
|
401
|
+
};
|
|
402
|
+
|
|
403
|
+
// URL reference
|
|
404
|
+
const urlModule: FomModule = {
|
|
405
|
+
type: 'url',
|
|
406
|
+
url: 'file:///path/to/fom.xml',
|
|
407
|
+
};
|
|
408
|
+
|
|
409
|
+
await rtiAmbassador.createFederationExecutionWithModules(
|
|
410
|
+
'MyFederation',
|
|
411
|
+
[inlineModule, urlModule]
|
|
412
|
+
);
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
## Testing
|
|
416
|
+
|
|
417
|
+
```bash
|
|
418
|
+
cd packages/hla-api
|
|
419
|
+
bun test
|
|
420
|
+
```
|
|
421
|
+
|
|
422
|
+
## Related Packages
|
|
423
|
+
|
|
424
|
+
- [`@hla4ts/proto`](../proto) - Protocol buffer types
|
|
425
|
+
- [`@hla4ts/transport`](../transport) - Transport layer (TCP/TLS)
|
|
426
|
+
- [`@hla4ts/session`](../session) - Session management
|
|
427
|
+
|
|
428
|
+
## References
|
|
429
|
+
|
|
430
|
+
- [IEEE 1516-2025](https://standards.ieee.org/standard/1516-2025.html) - HLA 4 Standard
|
|
431
|
+
- [Pitch FedProClient](https://github.com/Pitch-Technologies/FedProClient) - Reference implementation
|
|
432
|
+
- [HLA 4 Overview](https://onearc.com/articles/what-is-hla-4/) - Introduction to HLA 4
|
|
433
|
+
|
|
434
|
+
## License
|
|
435
|
+
|
|
436
|
+
MIT
|
package/package.json
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@hla4ts/hla-api",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "High-level HLA 4 API facade for TypeScript - RTI Ambassador and Federate Ambassador",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "src/index.ts",
|
|
7
|
+
"types": "src/index.ts",
|
|
8
|
+
"files": [
|
|
9
|
+
"README.md",
|
|
10
|
+
"src"
|
|
11
|
+
],
|
|
12
|
+
"exports": {
|
|
13
|
+
".": {
|
|
14
|
+
"import": "./src/index.ts",
|
|
15
|
+
"types": "./src/index.ts"
|
|
16
|
+
}
|
|
17
|
+
},
|
|
18
|
+
"publishConfig": {
|
|
19
|
+
"access": "public"
|
|
20
|
+
},
|
|
21
|
+
"scripts": {
|
|
22
|
+
"typecheck": "tsc --noEmit",
|
|
23
|
+
"test": "bun test",
|
|
24
|
+
"build": "tsc",
|
|
25
|
+
"clean": "rm -rf dist"
|
|
26
|
+
},
|
|
27
|
+
"dependencies": {
|
|
28
|
+
"@hla4ts/proto": "^0.1.0",
|
|
29
|
+
"@hla4ts/transport": "^0.1.0",
|
|
30
|
+
"@hla4ts/session": "^0.1.0"
|
|
31
|
+
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"@types/bun": "latest",
|
|
34
|
+
"typescript": "^5.3.3"
|
|
35
|
+
},
|
|
36
|
+
"peerDependencies": {
|
|
37
|
+
"protobufjs": "^7.2.6"
|
|
38
|
+
},
|
|
39
|
+
"keywords": [
|
|
40
|
+
"hla",
|
|
41
|
+
"hla4",
|
|
42
|
+
"ieee-1516",
|
|
43
|
+
"simulation",
|
|
44
|
+
"federate",
|
|
45
|
+
"rti"
|
|
46
|
+
],
|
|
47
|
+
"license": "MIT"
|
|
48
|
+
}
|