@hla4ts/hla-api
v0.1.1
Published
High-level HLA 4 API facade for TypeScript - RTI Ambassador and Federate Ambassador
Maintainers
Readme
@hla4ts/hla-api
High-level HLA 4 API for TypeScript
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.
Overview
The HLA API package provides:
- RTIAmbassador - Main interface for federate-to-RTI communication
- FederateAmbassador - Callback interface for RTI-to-federate communication
- Exception classes - Type-safe HLA exception handling
- Type definitions - Handle types, value maps, and configuration types
Installation
bun add @hla4ts/hla-apiQuick Start
import {
RTIAmbassador,
BaseFederateAmbassador,
CallbackModel,
ResignAction,
} from '@hla4ts/hla-api';
// 1. Create your Federate Ambassador by extending the base class
class MyFederateAmbassador extends BaseFederateAmbassador {
override discoverObjectInstance(
objectInstance: Uint8Array,
objectClass: Uint8Array,
objectInstanceName: string,
producingFederate: Uint8Array
): void {
console.log(`Discovered object: ${objectInstanceName}`);
}
override reflectAttributeValues(
objectInstance: Uint8Array,
attributeValues: Array<{ attributeHandle: Uint8Array; value: Uint8Array }>,
userSuppliedTag: Uint8Array,
transportationType: Uint8Array,
producingFederate: Uint8Array
): void {
console.log(`Received ${attributeValues.length} attribute updates`);
}
override receiveInteraction(
interactionClass: Uint8Array,
parameterValues: Array<{ parameterHandle: Uint8Array; value: Uint8Array }>,
userSuppliedTag: Uint8Array,
transportationType: Uint8Array,
producingFederate: Uint8Array
): void {
console.log(`Received interaction with ${parameterValues.length} parameters`);
}
}
// 2. Create the RTI Ambassador
const rtiAmbassador = new RTIAmbassador({
host: 'rti.example.com',
port: 15165, // TLS port (default)
useTls: true,
});
// 3. Connect to the RTI
const federateAmbassador = new MyFederateAmbassador();
await rtiAmbassador.connect(federateAmbassador, {
callbackModel: CallbackModel.EVOKED,
});
// 4. Join a federation
const joinResult = await rtiAmbassador.joinFederationExecution(
'MyFederateType',
'TestFederation'
);
console.log(`Joined as federate with handle: ${joinResult.federateHandle}`);
// 5. Get handles for FOM elements
const objectClassHandle = await rtiAmbassador.getObjectClassHandle(
'HLAobjectRoot.MyClass'
);
const attributeHandle = await rtiAmbassador.getAttributeHandle(
objectClassHandle,
'MyAttribute'
);
// 6. Publish and subscribe
await rtiAmbassador.publishObjectClassAttributes(objectClassHandle, [attributeHandle]);
await rtiAmbassador.subscribeObjectClassAttributes(objectClassHandle, [attributeHandle]);
// 7. Register an object instance
const objectInstance = await rtiAmbassador.registerObjectInstance(objectClassHandle);
// 8. Update attributes
await rtiAmbassador.updateAttributeValues(
objectInstance,
[{ attributeHandle, value: new TextEncoder().encode('Hello HLA!') }],
new Uint8Array() // user-supplied tag
);
// 9. Send an interaction
const interactionClass = await rtiAmbassador.getInteractionClassHandle(
'HLAinteractionRoot.MyInteraction'
);
const parameterHandle = await rtiAmbassador.getParameterHandle(
interactionClass,
'MyParameter'
);
await rtiAmbassador.publishInteractionClass(interactionClass);
await rtiAmbassador.sendInteraction(
interactionClass,
[{ parameterHandle, value: new TextEncoder().encode('Hello!') }],
new Uint8Array()
);
// 10. Clean up
await rtiAmbassador.resignFederationExecution(ResignAction.DELETE_OBJECTS_THEN_DIVEST);
await rtiAmbassador.disconnect();Sequence Diagram
sequenceDiagram
participant App as Federate Code
participant RTI as RTI
participant RTIA as RTIAmbassador
participant Session
participant CB as CallbackDispatcher
participant FA as FederateAmbassador
App->>RTIA: connect(federateAmbassador)
RTIA->>Session: start()
Session-->>RTI: HLA_CALL_REQUEST (Connect)
RTI-->>Session: HLA_CALL_RESPONSE
App->>RTIA: joinFederationExecution(...)
RTIA->>Session: HLA_CALL_REQUEST
RTI-->>Session: HLA_CALL_RESPONSE
RTI-->>Session: HLA_CALLBACK_REQUEST
Session-->>CB: callback bytes
CB-->>FA: dispatch callback
CB-->>Session: CallbackResponseAPI Reference
RTIAmbassador
The main interface for communicating with the RTI.
Constructor
new RTIAmbassador(options: RTIAmbassadorOptions)Options:
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| host | string | required | RTI host address |
| port | number | 15165 (TLS) / 15164 (TCP) | RTI port |
| useTls | boolean | true | Use TLS encryption |
| connectionTimeout | number | 30000 | Connection timeout (ms) |
| responseTimeout | number | 180000 | Response timeout (ms) |
| tlsOptions | object | {} | TLS options (ca, cert, key) |
Connection Methods
// Connect to RTI
await rtiAmbassador.connect(federateAmbassador, {
callbackModel: CallbackModel.EVOKED,
});
// Check connection status
if (rtiAmbassador.isConnected) {
// ...
}
// Disconnect
await rtiAmbassador.disconnect();Federation Management
// Create a federation
await rtiAmbassador.createFederationExecution('FederationName', fomModule);
// Join a federation
const joinResult = await rtiAmbassador.joinFederationExecution(
'FederateType',
'FederationName'
);
// Resign from a federation
await rtiAmbassador.resignFederationExecution(ResignAction.DELETE_OBJECTS_THEN_DIVEST);
// Destroy a federation
await rtiAmbassador.destroyFederationExecution('FederationName');Declaration Management
// Publish object class attributes
await rtiAmbassador.publishObjectClassAttributes(objectClass, [attr1, attr2]);
// Subscribe to object class attributes
await rtiAmbassador.subscribeObjectClassAttributes(objectClass, [attr1, attr2]);
// Publish an interaction class
await rtiAmbassador.publishInteractionClass(interactionClass);
// Subscribe to an interaction class
await rtiAmbassador.subscribeInteractionClass(interactionClass);
// Unsubscribe/unpublish
await rtiAmbassador.unpublishObjectClass(objectClass);
await rtiAmbassador.unsubscribeInteractionClass(interactionClass);Object Management
// Register an object instance
const objectHandle = await rtiAmbassador.registerObjectInstance(objectClass);
// Register with a specific name
const namedObject = await rtiAmbassador.registerObjectInstanceWithName(
objectClass,
'MyObjectName'
);
// Update attribute values
await rtiAmbassador.updateAttributeValues(
objectHandle,
[{ attributeHandle: attr1, value: new Uint8Array([1, 2, 3]) }],
userSuppliedTag
);
// Send an interaction
await rtiAmbassador.sendInteraction(
interactionClass,
[{ parameterHandle: param1, value: new Uint8Array([1, 2, 3]) }],
userSuppliedTag
);
// Delete an object instance
await rtiAmbassador.deleteObjectInstance(objectHandle, userSuppliedTag);Time Management
// Enable time regulation
await rtiAmbassador.enableTimeRegulation(lookahead);
// Enable time constrained
await rtiAmbassador.enableTimeConstrained();
// Query GALT/LITS and lookahead
const galt = await rtiAmbassador.queryGALT();
const lits = await rtiAmbassador.queryLITS();
const lookahead = await rtiAmbassador.queryLookahead();
// Request time advance
await rtiAmbassador.timeAdvanceRequest(targetTime);
// Disable time management
await rtiAmbassador.disableTimeRegulation();
await rtiAmbassador.disableTimeConstrained();HLAinteger64Time Helpers
import {
encodeHLAinteger64Time,
decodeHLAinteger64Time,
} from '@hla4ts/hla-api';
const encodedTime = encodeHLAinteger64Time(1_000_000n);
const decodedTime = decodeHLAinteger64Time(encodedTime);Support Services
// Get handles by name
const classHandle = await rtiAmbassador.getObjectClassHandle('HLAobjectRoot.MyClass');
const attrHandle = await rtiAmbassador.getAttributeHandle(classHandle, 'MyAttribute');
const interactionHandle = await rtiAmbassador.getInteractionClassHandle('HLAinteractionRoot.MyInteraction');
const paramHandle = await rtiAmbassador.getParameterHandle(interactionHandle, 'MyParameter');
// Get names by handle
const className = await rtiAmbassador.getObjectClassName(classHandle);
const attrName = await rtiAmbassador.getAttributeName(classHandle, attrHandle);FederateAmbassador
Interface for receiving callbacks from the RTI. Extend BaseFederateAmbassador and override the callbacks you need:
class MyFederateAmbassador extends BaseFederateAmbassador {
// Object discovery
override discoverObjectInstance(objectInstance, objectClass, name, producer) {
// Handle object discovery
}
// Attribute updates
override reflectAttributeValues(objectInstance, attributeValues, tag, transport, producer) {
// Handle attribute update
}
// Interactions
override receiveInteraction(interactionClass, parameters, tag, transport, producer) {
// Handle interaction
}
// Time management
override timeAdvanceGrant(time) {
// Handle time advance grant
}
// Object removal
override removeObjectInstance(objectInstance, tag, producer) {
// Handle object removal
}
}Exception Handling
All HLA exceptions are mapped to TypeScript classes:
import {
NotConnected,
FederationExecutionDoesNotExist,
ObjectClassNotDefined,
RTIinternalError,
} from '@hla4ts/hla-api';
try {
await rtiAmbassador.joinFederationExecution('Type', 'NonExistentFederation');
} catch (error) {
if (error instanceof FederationExecutionDoesNotExist) {
console.log('Federation does not exist');
} else if (error instanceof NotConnected) {
console.log('Not connected to RTI');
} else if (error instanceof RTIinternalError) {
console.log('RTI internal error:', error.message);
}
}Handle Types
Handles are opaque Uint8Array values. The package provides utility functions:
import { handlesEqual, handleToHex, handleFromHex } from '@hla4ts/hla-api';
// Compare handles
if (handlesEqual(handle1, handle2)) {
// Handles are equal
}
// Convert to hex string (for debugging)
console.log(handleToHex(handle)); // "0a1b2c3d..."
// Parse from hex string
const handle = handleFromHex("0a1b2c3d");FOM Module Types
When creating federations, you can provide FOM modules in different formats:
// Inline XML content
const inlineModule: FomModule = {
type: 'inline',
content: '<?xml version="1.0"?>...',
};
// File with binary content
const fileModule: FomModule = {
type: 'file',
name: 'myFom.xml',
content: new Uint8Array([...]),
};
// URL reference
const urlModule: FomModule = {
type: 'url',
url: 'file:///path/to/fom.xml',
};
await rtiAmbassador.createFederationExecutionWithModules(
'MyFederation',
[inlineModule, urlModule]
);Testing
cd packages/hla-api
bun testRelated Packages
@hla4ts/proto- Protocol buffer types@hla4ts/transport- Transport layer (TCP/TLS)@hla4ts/session- Session management
References
- IEEE 1516-2025 - HLA 4 Standard
- Pitch FedProClient - Reference implementation
- HLA 4 Overview - Introduction to HLA 4
License
MIT
