@aosengine/assets-aam
Classes
AamError
An AAM request that could not be completed.
The message names the path and the status but never the key — an error that reaches a log must not carry the credential.
Example
ts
import { AamError } from '@aosengine/assets-aam';
const err = new AamError('/api/characters/myra/ogs', 'not found', 404);
console.log(err.status, err.path); // 404 '/api/characters/myra/ogs'Extends
Error
Constructors
Constructor
ts
new AamError(
path,
message,
status?,
options?
): AamError;Build an AAM error.
Parameters
| Parameter | Type | Description |
|---|---|---|
path | string | AAM path or URL involved. |
message | string | What went wrong. |
status? | number | HTTP status, when there was one. |
options? | ErrorOptions | Standard Error options, used to keep the cause. |
Returns
Overrides
ts
Error.constructorProperties
path
ts
readonly path: string;AAM path or URL the failure belongs to.
status?
ts
readonly optional status?: number;HTTP status, when the failure came back as a response.
Interfaces
AamBundleFile
One file of a character's /ogs inference bundle.
Properties
name
ts
readonly name: string;Bare filename, for example scene.json.
size?
ts
readonly optional size?: number;Size in bytes, when the server reports one.
updatedAt?
ts
readonly optional updatedAt?: string;Last-modified stamp, when the server reports one.
url
ts
readonly url: string;Absolute URL the bytes are served from.
AamCharacterBundle
The listing of GET /api/characters/{slug}/ogs.
Properties
files
ts
readonly files: readonly AamBundleFile[];Every file in the character's bundle, in server order.
AamCharacterEntries
What buildCharacterManifestEntries produces.
Properties
characterId
ts
readonly characterId: string;Id of the character entry, for convenience.
entries
ts
readonly entries: readonly AssetEntry[];The character entry plus one gltf entry per body clip.
faceClips
ts
readonly faceClips: readonly AamFaceClip[];Face clips, which have no manifest type of their own.
AamClient
A typed AAM client bound to one deployment and one key.
Properties
baseUrl
ts
readonly baseUrl: string;The normalised base URL, without a trailing slash.
Methods
fetchFile()
ts
fetchFile(url, options?): Promise<ArrayBuffer>;Fetch one file's bytes, through the cache layer when it is enabled.
Parameters
| Parameter | Type | Description |
|---|---|---|
url | string | File URL or AAM path. |
options? | AamFetchFileOptions | Abort signal and cache version token. |
Returns
Promise<ArrayBuffer>
The bytes.
listAnimationAssets()
ts
listAnimationAssets(slug): Promise<AnimationAssetRow[]>;List a character's animation clips.
Parameters
| Parameter | Type | Description |
|---|---|---|
slug | string | Character slug. |
Returns
Promise<AnimationAssetRow[]>
Every clip row, body and face.
listCharacterBundle()
ts
listCharacterBundle(slug): Promise<AamCharacterBundle>;List a character's /ogs inference bundle.
Parameters
| Parameter | Type | Description |
|---|---|---|
slug | string | Character slug. |
Returns
Promise<AamCharacterBundle>
The bundle listing.
owns()
ts
owns(url): boolean;Whether a URL belongs to this AAM deployment.
Parameters
| Parameter | Type | Description |
|---|---|---|
url | string | Absolute URL, or a path when baseUrl is itself a path. |
Returns
boolean
True when the key may be attached to it.
request()
ts
request(input, init?): Promise<Response>;fetch with the key attached (same-origin only) and 5xx retried.
Parameters
| Parameter | Type | Description |
|---|---|---|
input | RequestInfo | URL | URL, URL or Request to fetch. |
init? | RequestInit | Standard fetch init; its headers are preserved. |
Returns
Promise<Response>
The final Response, whatever its status.
resolveFileUrl()
ts
resolveFileUrl(path): string;Join an AAM path onto baseUrl.
Parameters
| Parameter | Type | Description |
|---|---|---|
path | string | Server path such as /api/characters/myra/ogs, or a URL. |
Returns
string
An absolute URL when baseUrl is absolute, else a prefixed path.
AamClientOptions
Options accepted by createAamClient.
Properties
apiKey
ts
readonly apiKey: string;The X-API-Key value. Empty means "send no header" (cookie auth).
backoffMs?
ts
readonly optional backoffMs?: number;First-retry delay in milliseconds; doubled on each further attempt.
baseUrl
ts
readonly baseUrl: string;AAM origin or proxy prefix, for example https://aam.example or /aam.
cache?
ts
readonly optional cache?: AamCacheMode;Where file bytes may be served from. Defaults to none.
fetch?
ts
readonly optional fetch?: (input, init?) => Promise<Response>;fetch implementation. Defaults to the global one.
Parameters
| Parameter | Type |
|---|---|
input | RequestInfo | URL |
init? | RequestInit |
Returns
Promise<Response>
retries?
ts
readonly optional retries?: number;Retries after the first attempt, on a network error or a 5xx.
AamEnvConfig
A usable AAM configuration read from the environment.
Properties
apiKey
ts
readonly apiKey: string;Value of VITE_ASSET_MANAGER_API_KEY, or '' when it is unset.
Empty is legitimate: a deployment served from the same site authenticates with its session cookie, and the client then sends no X-API-Key header at all. The key is the localhost-development affordance, because a domain-scoped cookie cannot reach localhost.
baseUrl
ts
readonly baseUrl: string;Value of VITE_ASSET_MANAGER_URL, with any trailing slash removed.
AamFaceClip
One face clip, as a JSON-serialisable record.
Face clips are ARKit weight tracks in JSON, not glTF, so they are not manifest entries — assets.json has no json type and inventing one would be a schema change. They come back as their own list instead, ready to be written into a game's own data file or handed to the animator directly.
Example
ts
import type { AamFaceClip } from '@aosengine/assets-aam';
const clip: AamFaceClip = {
id: 'char.myra.smile',
name: 'smile',
url: 'https://aam.example/api/character-assets/7/smile.json',
additive: false,
additiveType: 'none',
basePoseType: 'none',
basePoseAssetId: null,
refFrameIndex: 0,
updatedAt: null,
};
console.log(clip.id); // 'char.myra.smile'Properties
additive
ts
readonly additive: boolean;Whether the clip plays as an additive layer.
additiveType
ts
readonly additiveType: AdditiveType;Additive space.
basePoseAssetId
ts
readonly basePoseAssetId: string | null;Row id of the clip supplying the base pose.
basePoseType
ts
readonly basePoseType: BasePoseType;Which pose the additive bake subtracts.
id
ts
readonly id: string;Manifest-style id, built from the same prefix as the body clips.
name
ts
readonly name: string;The server's clip name.
refFrameIndex
ts
readonly refFrameIndex: number;Frame index of the reference pose.
updatedAt
ts
readonly updatedAt: string | null;Last-modified stamp, for cache versioning.
url
ts
readonly url: string;Absolute URL the ARKit track is served from.
AamFetchFileOptions
Per-call options for AamClient.fetchFile.
Properties
signal?
ts
readonly optional signal?: AbortSignal;Abort signal forwarded to fetch.
version?
ts
readonly optional version?: string | number | null;Cache version token, normally the row's updatedAt or size. Changing it invalidates the Cache Storage entry, so a re-uploaded file is refetched instead of being replayed from the previous bytes.
AamResolver
A drop-in fetch bound to one AAM deployment.
Properties
fetch
ts
readonly fetch: (input, init?) => Promise<Response>;fetch, with the key attached to AAM URLs only.
Parameters
| Parameter | Type |
|---|---|
input | RequestInfo | URL |
init? | RequestInit |
Returns
Promise<Response>
AnimationAssetRow
One row of GET /api/characters/{slug}/animation-assets.
The field names are the server's, not this package's: file_url is snake case and the additive settings are camel case, exactly as AAM sends them. Renaming them here would make the row un-greppable against the service.
Example
ts
import type { AnimationAssetRow } from '@aosengine/assets-aam';
const row: AnimationAssetRow = {
id: '42',
name: 'wave',
kind: 'body',
additive: true,
file_url: '/api/character-assets/42/wave.glb',
updatedAt: '2026-09-01T10:00:00Z',
additiveType: 'local',
basePoseType: 'local_frame',
basePoseAssetId: null,
refFrameIndex: 0,
};
console.log(row.kind); // 'body'Properties
additive
ts
readonly additive: boolean;Whether the clip is played as an additive layer.
additiveType
ts
readonly additiveType: AdditiveType;Additive space. none when the clip is not additive.
basePoseAssetId
ts
readonly basePoseAssetId: string | null;Row id of the clip supplying the base pose, for anim_frame.
basePoseType
ts
readonly basePoseType: BasePoseType;Which pose the additive bake subtracts.
file_url
ts
readonly file_url: string;Path or URL the bytes are served from.
id
ts
readonly id: string;Server-assigned row id.
kind
ts
readonly kind: AnimationClipKind;Body clip (a GLB) or face clip (an ARKit JSON track).
name
ts
readonly name: string;Human-facing clip name; the manifest id is derived from it.
refFrameIndex
ts
readonly refFrameIndex: number;Frame index of the reference pose inside the base clip.
updatedAt
ts
readonly updatedAt: string | null;Last-modified stamp, used as the cache version. null when unknown.
BuildCharacterManifestOptions
Options accepted by buildCharacterManifestEntries.
Properties
idPrefix?
ts
readonly optional idPrefix?: string;Id prefix for every entry. Defaults to char.<slug>.
rig?
ts
readonly optional rig?: AssetRig;Rig for the character entry. Defaults to { backend: 'orl' }.
tags?
ts
readonly optional tags?: readonly string[];Tags added to every generated entry. Defaults to ['aam', <slug>].
Type Aliases
AamCacheMode
ts
type AamCacheMode = "none" | "cache-storage";Where AamClient.fetchFile may serve bytes from.
AdditiveType
ts
type AdditiveType = "none" | "local" | "mesh";Which pose space an additive clip was baked in.
AnimationClipKind
ts
type AnimationClipKind = "body" | "face";Whether a clip drives the body rig or the face.
BasePoseType
ts
type BasePoseType = "none" | "local_frame" | "anim_frame" | "ref_pose";Which pose an additive clip subtracts to become a delta.
Variables
PACKAGE
ts
const PACKAGE: "@aosengine/assets-aam";Package identity marker.
Example
ts
import { PACKAGE } from '@aosengine/assets-aam';
console.log(PACKAGE); // '@aosengine/assets-aam'Functions
aamConfigFromEnv()
ts
function aamConfigFromEnv(env?): AamEnvConfig | null;Read the AAM configuration from a Vite-style environment.
Parameters
| Parameter | Type | Description |
|---|---|---|
env | Record<string, string | undefined> | Environment record. Defaults to import.meta.env. |
Returns
AamEnvConfig | null
The configuration, or null when VITE_ASSET_MANAGER_URL is unset or blank — which means the adapter is simply not in use.
Example
ts
import { aamConfigFromEnv, createAamClient } from '@aosengine/assets-aam';
const config = aamConfigFromEnv({ VITE_ASSET_MANAGER_URL: 'https://aam.example' });
const client = config === null ? null : createAamClient(config);
console.log(config?.baseUrl); // 'https://aam.example'buildCharacterManifestEntries()
ts
function buildCharacterManifestEntries(
client,
slug,
options?
): Promise<AamCharacterEntries>;Read a character's listings and turn them into manifest entries.
The character entry's src is a virtual directory URL — <baseUrl>/api/characters/<slug>/ogs/ — not a single file. The character loader appends a filename to it (scene.json, mesh.json, the decoders) and fetches each one, exactly as it would from a static directory; the only difference is that the directory is served by AAM and needs the key, which is what createAamResolver supplies.
The bundle listing is fetched as well as the directory being named, so an empty or missing bundle fails here, with the character's slug in the message, rather than deep inside the loader on a 404 for scene.json.
Parameters
| Parameter | Type | Description |
|---|---|---|
client | AamClient | Client for the deployment the character lives in. |
slug | string | Character slug. |
options | BuildCharacterManifestOptions | Id prefix, rig and tags. |
Returns
Promise<AamCharacterEntries>
The character entry, the body-clip entries and the face clips.
Example
ts
import { buildCharacterManifestEntries, createAamClient } from '@aosengine/assets-aam';
const client = createAamClient({ baseUrl: 'https://aam.example', apiKey: key });
const built = await buildCharacterManifestEntries(client, 'myra');
console.log(built.characterId); // 'char.myra'createAamClient()
ts
function createAamClient(options): AamClient;Build a client for one AAM deployment.
Parameters
| Parameter | Type | Description |
|---|---|---|
options | AamClientOptions | Base URL, key, and the injectable fetch, retry and cache policy. |
Returns
The client.
Example
ts
import { createAamClient } from '@aosengine/assets-aam';
const client = createAamClient({ baseUrl: 'https://aam.example', apiKey: key });
console.log(client.resolveFileUrl('/api/characters/myra/ogs'));
// 'https://aam.example/api/characters/myra/ogs'createAamResolver()
ts
function createAamResolver(client): AamResolver;Build the fetch option for loadManifest and loadCharacterBundle.
Parameters
| Parameter | Type | Description |
|---|---|---|
client | AamClient | Client for the deployment that holds the key. |
Returns
An object with a single fetch, assignable anywhere the engine accepts a fetch override.
Example
ts
import { loadManifest } from '@aosengine/assets';
import { createAamClient, createAamResolver } from '@aosengine/assets-aam';
const client = createAamClient({ baseUrl: 'https://aam.example', apiKey: key });
const resolver = createAamResolver(client);
const manifest = await loadManifest('/assets/assets.json', { fetch: resolver.fetch });
console.log(manifest.assets.length);mergeManifests()
ts
function mergeManifests(base, extra): AssetManifest;Merge generated entries into a game's manifest.
Entries built by buildCharacterManifestEntries carry absolute URLs, so the base manifest's baseUrl does not apply to them and is preserved untouched for everything that was already there. A duplicate id throws: an id is the guest/host contract, and silently letting one definition win would change what a running game loads without changing a line of its code.
Parameters
| Parameter | Type | Description |
|---|---|---|
base | AssetManifest | The game's manifest. |
extra | | AssetManifest | readonly AssetEntry[] | Entries to add, or another manifest to take entries from. |
Returns
A new frozen manifest.
Example
ts
import { parseManifest } from '@aosengine/assets';
import { mergeManifests } from '@aosengine/assets-aam';
const base = parseManifest({ version: 1, baseUrl: '/assets/', assets: [] });
const merged = mergeManifests(base, [
{ id: 'char.myra.wave', type: 'gltf', src: 'https://aam.example/f/wave.glb' },
]);
console.log(merged.assets.length); // 1