Skip to content

@gameable/bundle ​

Interfaces ​

BundleFile ​

A hashed payload. manifest.json describes these files and is not itself a payload.

Example ​

ts
import type { BundleFile } from 'gameable/bundle';
const file: BundleFile = { path: 'assets/empty.bin', bytes: 0,
  sha256: 'e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855',
  contentType: 'application/octet-stream' };
console.log(file.path);

Properties ​

bytes ​
ts
readonly bytes: number;
contentType ​
ts
readonly contentType: string;
from? ​
ts
readonly optional from?: string;

Version in the same game containing this path; schema 3 only.

path ​
ts
readonly path: string;
sha256 ​
ts
readonly sha256: string;

BundleIdentity ​

Game identity independent of the build payloads.

Example ​

ts
import type { BundleIdentity } from 'gameable/bundle';
const identity: BundleIdentity = { gameId: 'tiny-game', version: '1.0.0', slug: 'tiny-game' };
console.log(identity.gameId);

Properties ​

gameId ​
ts
readonly gameId: string;
slug ​
ts
readonly slug: string;
version ​
ts
readonly version: string;

EngineComposition ​

Exact versions of the implementations included in a runtime.

Example ​

ts
const composition: EngineComposition = { compositionId: '0123456789abcdef', core: '1.0.0', modules: [], guestContract: 'gameable:engine@0.2.0' };
console.log(composition.core);

Properties ​

compositionId ​
ts
readonly compositionId: string;
core ​
ts
readonly core: string;
guestContract ​
ts
readonly guestContract: string;
modules ​
ts
readonly modules: readonly object[];
runtimeDigest? ​
ts
readonly optional runtimeDigest?: string;

SHA-256 of sorted runtime paths and content hashes; absent on legacy runtimes.


GameCard ​

Slim researched card metadata used by deterministic lookup.

Example ​

ts
const card: GameCard = gameIndex().games[0];
console.log(card.id);

Properties ​

aliases ​
ts
aliases: string[];
camera ​
ts
camera: string;
category ​
ts
category: string;
id ​
ts
id: string;
juice? ​
ts
optional juice?: string[];
movement ​
ts
movement: string;
name ​
ts
name: string;
players ​
ts
players: object;
local_or_online? ​
ts
optional local_or_online?: string;
max ​
ts
max: string | number;
min ​
ts
min: string | number;
mode ​
ts
mode: string;
routing ​
ts
routing: object;
genres ​
ts
genres: string[];
keywords ​
ts
keywords: string[];
template ​
ts
template: string;
template_status ​
ts
template_status: string;
ui_sources? ​
ts
optional ui_sources?: string[];
ui_style? ​
ts
optional ui_style?: object;
layout ​
ts
layout: string;
notes ​
ts
notes: string;
palette ​
ts
palette: string[];
screens ​
ts
screens: string[];
typography ​
ts
typography: string;

GameIndex ​

Replaceable routing index; full specifications remain in games/<id>.md.

Example ​

ts
const index: GameIndex = gameIndex();
console.log(index.templates.kart.base);

Properties ​

ambiguous_aliases ​
ts
ambiguous_aliases: Record<string, string[]>;
games ​
ts
games: GameCard[];
templates ​
ts
templates: Record<string, {
  base: string;
  camera: string;
  status: string;
}>;

GameLookup ​

JSON lookup contract, including evidence and the starting template.

Example ​

ts
const result: GameLookup = findGames('pacman');
console.log(result.start?.card);

Properties ​

ambiguous ​
ts
ambiguous: 
  | {
  alias: string;
  ids: string[];
}
  | null;
matchedBy ​
ts
matchedBy: "name" | "mechanics" | "none";
matches ​
ts
matches: Pick<GameCard, "ui_style" | "juice" | "ui_sources"> & object[];
request ​
ts
request: string;
start ​
ts
start: 
  | {
  card: string;
  from: "none" | "template" | "base";
  instruction: string;
  template: string | null;
}
  | null;
threshold ​
ts
threshold: number;
uncovered ​
ts
uncovered: string[];
unsupported ​
ts
unsupported: boolean;
weakMatch ​
ts
weakMatch: boolean;

TemplateManifest ​

Agent routing metadata, independent of a compiled bundle's payload manifest. Empty settings means the legacy template only exposes its TypeScript rules.

Example ​

ts
const manifest = validateTemplateManifest(await (await fetch('template.json')).json());
console.log(manifest.id);

Properties ​

camera ​
ts
readonly camera: readonly ("first-person" | "orbit" | "fixed" | "third-person")[];
description ​
ts
readonly description: string;
examplePrompts ​
ts
readonly examplePrompts: readonly string[];
exclude? ​
ts
readonly optional exclude?: readonly string[];
genres ​
ts
readonly genres: readonly string[];
id ​
ts
readonly id: string;
input ​
ts
readonly input: readonly ("keyboard-mouse" | "touch" | "gamepad" | "pointer")[];
keywords ​
ts
readonly keywords: readonly string[];
limits ​
ts
readonly limits: readonly string[];
modules ​
ts
readonly modules: readonly string[];
multiplayer ​
ts
readonly multiplayer: object;
maxSeats ​
ts
readonly maxSeats: number;
minSeats ​
ts
readonly minSeats: number;
notSupported ​
ts
readonly notSupported: readonly string[];
schemaVersion ​
ts
readonly schemaVersion: 1;
settings ​
ts
readonly settings: object;
file ​
ts
readonly file: string;
keys ​
ts
readonly keys: Readonly<Record<string, TemplateSetting>>;
title ​
ts
readonly title: string;

TemplateMatch ​

Ranked candidate and the evidence behind its score on a 0–1 scale.

Example ​

ts
const matches = scoreTemplates([], { genres: ['adventure'] });
console.log(matches.length);

Properties ​

reasons ​
ts
readonly reasons: readonly string[];
score ​
ts
readonly score: number;
template ​
ts
readonly template: TemplateManifest;
weakMatch ​
ts
readonly weakMatch: boolean;

TemplateRequest ​

Structured brief; multiplayer is the requested number of simultaneous seats.

Example ​

ts
const request: TemplateRequest = { genres: ['racing'], multiplayer: 12 };
console.log(request.multiplayer);

Properties ​

camera? ​
ts
readonly optional camera?: "first-person" | "orbit" | "fixed" | "third-person";
genres? ​
ts
readonly optional genres?: readonly string[];
keywords? ​
ts
readonly optional keywords?: readonly string[];
multiplayer? ​
ts
readonly optional multiplayer?: number;

Type Aliases ​

BundleManifest ​

ts
type BundleManifest = BundleIdentity & 
  | {
  engine: {
     guestContract: string;
     version: string;
  };
  modules: readonly object[];
  schemaVersion: 1;
}
  | {
  engine: EngineComposition;
  schemaVersion: 2 | 3;
} & object;

Portable game identity, compatibility requirements and complete payload inventory.

Type Declaration ​

assets ​
ts
readonly assets: "assets.json";
files ​
ts
readonly files: readonly BundleFile[];
guest ​
ts
readonly guest: object;
guest.entry ​
ts
readonly entry: string;
settings ​
ts
readonly settings: "settings.json";

Example ​

ts
import { validateBundleManifest, type BundleManifest } from 'gameable/bundle';
const value: unknown = JSON.parse(await (await fetch('./manifest.json')).text());
const manifest: BundleManifest = validateBundleManifest(value);
console.log(manifest.gameId);

TemplateSetting ​

ts
type TemplateSetting = 
  | {
  integer?: boolean;
  max: number;
  min: number;
  type: "number";
}
  | {
  maxLength: number;
  type: "string";
}
  | {
  type: "boolean";
}
  | {
  type: "enum";
  values: readonly string[];
};

Bounded scalar settings that an agent may edit in the named JSON document.

Example ​

ts
const setting: TemplateSetting = { type: 'number', min: 0, max: 10 };
console.log(setting.type);

Functions ​

canonicalComposition() ​

ts
function canonicalComposition(composition): string;

Canonical composition JSON: exact core and modules sorted by ASCII id.

Parameters ​

ParameterTypeDescription
compositionPick<EngineComposition, "core" | "modules">Exact runtime versions.

Returns ​

string

Stable JSON to hash or compare; the guest contract is checked separately.

Example ​

ts
console.log(canonicalComposition({ core: '1.0.0', modules: [] }));

compositionId() ​

ts
function compositionId(composition): Promise<string>;

Derive the runtime id from canonical versions and the built runtime digest. Legacy compositions without a digest retain their original version-only id.

Parameters ​

ParameterTypeDescription
compositionPick<EngineComposition, "core" | "modules" | "runtimeDigest">Exact runtime versions and build digest.

Returns ​

Promise<string>

First 16 lowercase hex characters of SHA-256.

Example ​

ts
console.log(await compositionId({ core: '1.0.0', modules: [], runtimeDigest: 'a'.repeat(64) }));

findGames() ​

ts
function findGames(request, options?): GameLookup;

Look up game names first, then rank mechanics with deterministic weighted evidence. Without a name match, the top match is weak below the score threshold, with fewer than two distinct matched request terms, or when a request with at least two keywords has none covered. Mechanics matches expose this count as matched across genres, keywords, camera, movement and players. Unsupported matches are always weak. Only positive-score mechanics matches are returned, so results may contain fewer entries than the limit.

Parameters ​

ParameterTypeDescription
requeststringA game name, alias or mechanics description.
options{ index?: GameIndex; limit?: number; threshold?: number; }Result count (default 3), weak threshold (default 0.5), or replacement index.
options.index?GameIndexReplacement routing catalog.
options.limit?numberMaximum results, default 3.
options.threshold?numberWeak-match cutoff, default 0.5.

Returns ​

GameLookup

JSON-serialisable matches, template instructions and uncovered requirements.

Example ​

ts
console.log(findGames('make a mario kart').start);

gameIndex() ​

ts
function gameIndex(): GameIndex;

Return the bundled slim research index.

Returns ​

GameIndex

Routing metadata for the researched cards.

Example ​

ts
console.log(gameIndex().games.length);

isBundleVersion() ​

ts
function isBundleVersion(value): value is string;

Validate an exact semantic version, including prerelease and build metadata.

Parameters ​

ParameterTypeDescription
valueunknownThe candidate version.

Returns ​

value is string

Whether it is valid semver.

Example ​

ts
import { isBundleVersion } from 'gameable/bundle';
console.log(isBundleVersion('1.2.3-beta.1+build'));

scoreTemplates() ​

ts
function scoreTemplates(
   templates, 
   request, 
   threshold?
): TemplateMatch[];

Rank installed templates by genre (4), camera (3), seats (3), and keywords (2). Only supplied dimensions enter the denominator. Incompatible camera/seats are always weak matches; ties sort by id. No evidence scores zero.

Parameters ​

ParameterTypeDefault valueDescription
templatesreadonly TemplateManifest[]undefinedValidated manifests.
requestTemplateRequestundefinedStructured brief (keywords may contain phrases).
thresholdnumber0.5Minimum confidence, default 0.5.

Returns ​

TemplateMatch[]

All candidates, strongest first, with matching and conflicting reasons.

Example ​

ts
console.log(scoreTemplates([], { genres: ['racing'], multiplayer: 12 }));

validateBundleIdentity() ​

ts
function validateBundleIdentity(value): BundleIdentity;

Validate identity before constructing an output directory or compiling a guest.

Parameters ​

ParameterTypeDescription
valueunknownCandidate game identity.

Returns ​

BundleIdentity

The validated identity.

Example ​

ts
import { validateBundleIdentity } from 'gameable/bundle';
console.log(validateBundleIdentity({ gameId: 'tiny-game', version: '1.0.0', slug: 'tiny-game' }));

validateBundleManifest() ​

ts
function validateBundleManifest(value): BundleManifest;

Parse and validate a version 1 or 2 manifest, throwing on malformed input.

Parameters ​

ParameterTypeDescription
valueunknownParsed JSON from a bundle manifest.

Returns ​

BundleManifest

The validated manifest.

Example ​

ts
import { validateBundleManifest } from 'gameable/bundle';
const value: unknown = await (await fetch('./manifest.json')).json();
console.log(validateBundleManifest(value).guest.entry);

validateBundlePath() ​

ts
function validateBundlePath(value): asserts value is string;

Reject paths that cannot safely be resolved below a bundle directory.

Parameters ​

ParameterTypeDescription
valueunknownA bundle-relative file path.

Returns ​

asserts value is string

Example ​

ts
import { validateBundlePath } from 'gameable/bundle';
validateBundlePath('guest/game.js');

validateEngineComposition() ​

ts
function validateEngineComposition(value): EngineComposition;

Validate the readable runtime metadata, without hashing it.

Parameters ​

ParameterTypeDescription
valueunknownCandidate metadata.

Returns ​

EngineComposition

Validated metadata.

Example ​

ts
const composition = validateEngineComposition(await (await fetch('composition.json')).json());
console.log(composition.core);

validateTemplateManifest() ​

ts
function validateTemplateManifest(value): TemplateManifest;

Validate a versioned agent manifest, rejecting unknown fields and unsafe settings paths.

Parameters ​

ParameterTypeDescription
valueunknownParsed template.json.

Returns ​

TemplateManifest

Validated metadata.

Example ​

ts
const data: unknown = await (await fetch('template.json')).json();
console.log(validateTemplateManifest(data).title);

validateTemplateSettings() ​

ts
function validateTemplateSettings(manifest, patch): void;

Validate an agent's scalar settings patch against the allowlist before writing JSON.

Parameters ​

ParameterTypeDescription
manifestTemplateManifestValidated template metadata.
patchReadonly<Record<string, unknown>>Dotted keys and their proposed values.

Returns ​

void

Example ​

ts
validateTemplateSettings(validateTemplateManifest(await (await fetch('template.json')).json()), {});