Skip to content

shayc/open-board-format

Repository files navigation

@shayc/open-board-format

A TypeScript toolkit for Open Board Format — the open standard for Augmentative and Alternative Communication (AAC) boards. Parse, validate, and create OBF boards and OBZ packages, all backed by Zod schemas with full TypeScript types inferred.

npm version CI License: MIT

OBF (.obf) is a JSON file describing a single communication board — buttons, images, sounds, grid layout, metadata. OBZ (.obz) is a ZIP archive bundling one or more .obf boards with their media and a manifest.json.

Install

npm install @shayc/open-board-format

Quick start

import { parseOBF } from "@shayc/open-board-format";

const board = parseOBF(jsonString);
console.log(board.id, board.buttons.length);

parseOBF throws on invalid input; the returned value is a fully typed OBFBoard. For other input shapes (already-parsed object, browser File, OBZ archive), see Overview.

Overview

Two file types; pick the entry point by what you have:

  • OBF is a single board (a JSON object). Use parseOBF for a JSON string, validateOBF for an already-parsed object, loadOBF for a browser File. stringifyOBF serializes back out.
  • OBZ is a package of boards plus media (a ZIP archive). Use loadOBZ for a File, extractOBZ for an ArrayBuffer, createOBZ to build a new one.

Every OBF type ships with a matching *Schema Zod schema (e.g. OBFBoardSchema, OBFManifestSchema), so you can validate inline with safeParse or wire the schema straight into an API contract — the TypeScript types are inferred from those schemas.

Validation preserves unknown fields rather than stripping them, so vendor extensions allowed by the OBF spec survive a parseOBFstringifyOBF round trip.

Requirements

  • Module format: ESM only.
  • Runtime: browser or Node 22+ — works against File, ArrayBuffer, and Blob.

Examples

Extract an OBZ package

import { loadOBZ, extractOBZ } from "@shayc/open-board-format";

// From a File (e.g. drag-and-drop)
const { manifest, boards, resources } = await loadOBZ(file);

// Or from an ArrayBuffer (e.g. fetch response)
const parsed = await extractOBZ(buffer);

const homeBoard = parsed.boards.get("1");
const imageBytes = parsed.resources.get("images/logo.png");

Create an OBZ package

import { createOBZ } from "@shayc/open-board-format";
import type { OBFBoard } from "@shayc/open-board-format";

const boards: OBFBoard[] = [
  {
    format: "open-board-0.1",
    id: "board-1",
    buttons: [{ id: "btn-1", label: "Hello" }],
    grid: { rows: 1, columns: 1, order: [["btn-1"]] },
  },
];

const pngBytes = new Uint8Array(/* ... */);
const resources = new Map([["images/logo.png", pngBytes]]);
const blob = await createOBZ(boards, "board-1", resources);

Validate with Zod directly

import { OBFBoardSchema } from "@shayc/open-board-format";

const result = OBFBoardSchema.safeParse(data);

if (result.success) {
  console.log(result.data.buttons);
} else {
  console.error(result.error.issues);
}

API

OBF (single board)

Function Description
parseOBF(json) Parse a JSON string into a validated OBFBoard
validateOBF(data) Validate an unknown object as OBFBoard (throws on failure)
stringifyOBF(board) Serialize an OBFBoard to a JSON string
loadOBF(file) Load an OBFBoard from a browser File

OBZ (board package)

Function Description
loadOBZ(file) Load an OBZ package from a browser File
extractOBZ(archive) Extract boards, manifest, and resources from an ArrayBuffer
createOBZ(boards, rootBoardId, resources?) Create an OBZ package as a Blob
parseManifest(json) Parse a manifest.json string into a validated OBFManifest

Utilities

Function Description
isZip(archive) Check if an ArrayBuffer starts with a ZIP magic number
zip(entries) Create a ZIP from a map of paths to buffers
unzip(archive) Extract a ZIP into a map of paths to Uint8Array

Types

Type Description
OBFBoard A single communication board
OBFGrid Grid layout (rows, columns, order)
OBFButton A button on the board
OBFButtonAction Button action (spelling or specialty)
OBFSpellingAction Spelling action (e.g., +s)
OBFSpecialtyAction Specialty action (e.g., :clear)
OBFLoadBoard Reference to load another board
OBFMedia Common media properties (base for OBFImage and OBFSound)
OBFImage An image resource (extends OBFMedia)
OBFSound A sound resource (extends OBFMedia)
OBFSymbolInfo Symbol set reference
OBFManifest OBZ package manifest
ParsedOBZ Return type of extractOBZ / loadOBZ{ manifest, boards, resources }
OBFID Unique identifier (string, coerced from number)
OBFFormatVersion Format version string (e.g., open-board-0.1)
OBFLicense Licensing information
OBFLocaleCode BCP 47 locale code
OBFLocalizedStrings Key-value string translations
OBFStrings Multi-locale string translations

Schemas

Every type above except ParsedOBZ is exported alongside a matching Zod schema with a Schema suffix — OBFBoardOBFBoardSchema, OBFManifestOBFManifestSchema, and so on. Import any of them to validate with safeParse/parse or to compose into your own schemas:

import { OBFButtonSchema, OBFManifestSchema } from "@shayc/open-board-format";

Errors

All failures throw plain Error. The message identifies what failed, typically with one of these prefixes:

  • Invalid OBF: — schema validation rejected an OBF board.
  • Invalid OBZ: — the package was rejected. On read: not a ZIP, missing manifest, or the manifest references a board file not in the archive. On write (createOBZ): rootBoardId matches no board, a board fails validation, two boards map the same media id to conflicting paths, a declared image/sound path has no matching resource, or a resource would overwrite a generated entry.
  • Invalid manifest:manifest.json failed to parse or validate.

When the root cause is a JSON.parse failure, the original error is preserved as error.cause. For finer-grained validation, drop one level down and use the Zod schemas directly with safeParse — the issues array tells you exactly which field failed.

Security

OBZ archives are untrusted input. This library does not enforce limits on entry size or count, and does not sanitize entry paths — if you write extracted resources to disk, validate paths yourself first to avoid directory traversal. For stronger guarantees against zip-bomb-style payloads, run extraction in a sandboxed context (Web Worker, isolated process).

Found a security issue? Open a private advisory at github.com/shayc/open-board-format/security/advisories/new.

Versioning

Semver; see CHANGELOG.md.

Contributing

See CONTRIBUTING.md for development setup (Node 22+, Vitest, the changeset workflow).

Related

License

MIT © Shay Cojocaru

About

Parse, validate, and create Open Board Format (OBF/OBZ) files for AAC applications.

Topics

Resources

License

Contributing

Stars

Watchers

Forks

Packages

 
 
 

Contributors