npm package: @hla4ts/hla-api
Description: High-level HLA 4 API facade for TypeScript - RTI Ambassador and Federate Ambassador
Latest version: 0.1.1

# @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

```bash
bun add @hla4ts/hla-api
```

## Quick Start

```typescript
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

```mermaid
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: CallbackResponse
```

## API Reference

### RTIAmbassador

The main interface for communicating with the RTI.

#### Constructor

```typescript
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

```typescript
// Connect to RTI
await rtiAmbassador.connect(federateAmbassador, {
  callbackModel: CallbackModel.EVOKED,
});

// Check connection status
if (rtiAmbassador.isConnected) {
  // ...
}

// Disconnect
await rtiAmbassador.disconnect();
```

#### Federation Management

```typescript
// 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

```typescript
// 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

```typescript
// 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

```typescript
// 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

```typescript
import {
  encodeHLAinteger64Time,
  decodeHLAinteger64Time,
} from '@hla4ts/hla-api';

const encodedTime = encodeHLAinteger64Time(1_000_000n);
const decodedTime = decodeHLAinteger64Time(encodedTime);
```

#### Support Services

```typescript
// 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:

```typescript
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:

```typescript
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:

```typescript
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:

```typescript
// 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

```bash
cd packages/hla-api
bun test
```

## Related Packages

- [`@hla4ts/proto`](../proto) - Protocol buffer types
- [`@hla4ts/transport`](../transport) - Transport layer (TCP/TLS)
- [`@hla4ts/session`](../session) - Session management

## References

- [IEEE 1516-2025](https://standards.ieee.org/standard/1516-2025.html) - HLA 4 Standard
- [Pitch FedProClient](https://github.com/Pitch-Technologies/FedProClient) - Reference implementation
- [HLA 4 Overview](https://onearc.com/articles/what-is-hla-4/) - Introduction to HLA 4

## License

MIT