@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
| Parameter | Type | Description |
|---|---|---|
composition | Pick<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
| Parameter | Type | Description |
|---|---|---|
composition | Pick<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
| Parameter | Type | Description |
|---|---|---|
request | string | A 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? | GameIndex | Replacement routing catalog. |
options.limit? | number | Maximum results, default 3. |
options.threshold? | number | Weak-match cutoff, default 0.5. |
Returns
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
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
| Parameter | Type | Description |
|---|---|---|
value | unknown | The 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
| Parameter | Type | Default value | Description |
|---|---|---|---|
templates | readonly TemplateManifest[] | undefined | Validated manifests. |
request | TemplateRequest | undefined | Structured brief (keywords may contain phrases). |
threshold | number | 0.5 | Minimum confidence, default 0.5. |
Returns
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
| Parameter | Type | Description |
|---|---|---|
value | unknown | Candidate game identity. |
Returns
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
| Parameter | Type | Description |
|---|---|---|
value | unknown | Parsed JSON from a bundle manifest. |
Returns
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
| Parameter | Type | Description |
|---|---|---|
value | unknown | A 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
| Parameter | Type | Description |
|---|---|---|
value | unknown | Candidate metadata. |
Returns
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
| Parameter | Type | Description |
|---|---|---|
value | unknown | Parsed template.json. |
Returns
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
| Parameter | Type | Description |
|---|---|---|
manifest | TemplateManifest | Validated template metadata. |
patch | Readonly<Record<string, unknown>> | Dotted keys and their proposed values. |
Returns
void
Example
ts
validateTemplateSettings(validateTemplateManifest(await (await fetch('template.json')).json()), {});