Skip to content

erphq/erpai-pages-runtime

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

@erpai/pages-runtime

Browser runtime SDK for ERPAI custom HTML pages. The contract between agent-generated pages and the iframe they execute in.

runtime API surface types status

What is this?

Every "custom page" inside an ERPAI app is a standalone HTML document loaded in a sandboxed iframe. Those pages need a way to:

  • Query the app's data (records, SQL views)
  • Format numbers / dates / cells consistently with the app shell
  • Render dropdowns, tables, charts, modals that look like the rest of the product
  • Read theme colors and respect light/dark mode
  • Open the parent app's record-edit dialog without reinventing it
  • Gracefully handle 403s and missing data

This package is the runtime that exposes all of that on window.erpai inside the iframe. Pages are usually generated by an AI agent (Neo's build-page skill); the agent's prompt is built from the same JSDoc that documents this package, so the agent can only call functions that actually exist.

Why a dedicated package?

Before this package existed, the runtime lived in three places that drifted independently:

  • erpai-ui/public/runtime/ (what users actually loaded)
  • Neo's bundled skill (what the agent generated against)
  • The build-page skill docs (what the agent thought it was generating against)

When any one of those three forks moved, agent-generated pages crashed in production with erpai.X is not a function. Three deploys in one day, all the same shape.

Now there's one source of truth, with:

  • Typesdist/erpai-pages-runtime.d.ts ships with the package. Consumers using TypeScript (Neo's bundler, future SDK users) get compile-time errors for missing methods instead of runtime crashes.
  • Generated docsdist/runtime.md is regenerated from JSDoc on every build. Neo's agent prompt reads this file directly. The docs cannot lie.
  • API surface locknpm test asserts every public export is present and working. Adding/removing exports requires an explicit edit to the test, which is the point.
  • Semver — version pinned per release (v2.2.0, v2.3.0, …). Consumers can lock to a known-good version. Breaking changes get a major bump and a migration path.

What's in window.erpai

Group Examples
API layer runSQL, getRecords, createRecord, updateRecord, getTable, …
Formatters compactNumber("1.5M"), fmt$, fmtPct, fmtDate, formatCell
Cell decoders selectName, joinByKey
UI helpers createDropdown, renderRecordTable, renderStatCard, renderPagination, renderPermissionDenied, initTabs
Icons icon('chevron-down'), hasIcon, listIcons (Tabler catalog, ~250 icons)
State / loading cached, sectionLoading, withPrefetch, loadSections
Record modals openRecord, openCreateForm (delegate to parent app shell)
Theme getThemeColors() returns { blue, green, amber, red, surface, ... }
Navigation erpaiUrl, navigateTo (top-frame nav from inside iframe)

Full reference: dist/runtime.md (regenerated on every build).

Install

This is a private package; consumers install via git URL pinned to a tag:

// package.json
{
  "dependencies": {
    "@erpai/pages-runtime": "github:erphq/erpai-pages-runtime#v2.2.0"
  }
}
npm install

Consume

Static asset (e.g. erpai-ui serves it for browsers)

// vite.config.ts — copy the bundle into public/runtime/ on build
import { copyFileSync } from 'node:fs';
import { resolve } from 'node:path';

export default defineConfig({
  plugins: [{
    name: 'copy-erpai-runtime',
    buildStart() {
      const pkg = require.resolve('@erpai/pages-runtime/package.json');
      const dir = resolve(pkg, '../dist');
      const out = resolve(__dirname, 'public/runtime');
      copyFileSync(`${dir}/erpai-pages-runtime.js`, `${out}/erpai-pages-runtime.js`);
      copyFileSync(`${dir}/erpai-pages-runtime.css`, `${out}/erpai-pages-runtime.css`);
    },
  }],
});

The pages then load the runtime via <link> + <script> from /runtime/.

Embedded into an agent skill bundle (e.g. Neo's build-page)

// scripts/sync-runtime.mjs (Neo)
import { readFile, writeFile, mkdir } from 'node:fs/promises';
import { dirname } from 'node:path';
import { createRequire } from 'node:module';

const require = createRequire(import.meta.url);
const pkg = require.resolve('@erpai/pages-runtime/package.json');
const dir = dirname(pkg) + '/dist';
const stage = './src/lib/skills/builtin/build-page/stage';

await mkdir(`${stage}/runtime`, { recursive: true });
for (const f of ['erpai-pages-runtime.js', 'erpai-pages-runtime.css']) {
  await writeFile(`${stage}/runtime/${f}`, await readFile(`${dir}/${f}`));
}
// runtime.md becomes part of the agent prompt
await writeFile(`${stage}/runtime.md`, await readFile(`${dir}/runtime.md`));

TypeScript autocomplete in pages

/// <reference types="@erpai/pages-runtime" />

const { rows } = await window.erpai.runSQL('SELECT count() FROM accounts');
const label = window.erpai.compactNumber(rows[0].count);   // typed → string

The .d.ts is loaded automatically when the package is installed.

Development

npm install         # no runtime deps; tests use Node's built-in vm + fs
npm run build       # cp src/* → dist/, write d.ts, generate runtime.md
npm test            # API surface + smoke tests for formatters
npm run docs        # regenerate dist/runtime.md from JSDoc

Editing the runtime

  1. Modify src/erpai-pages-runtime.js (or .css).
  2. Add/update JSDoc above any export — that's what runtime.md shows agents.
  3. If you added/removed an export from window.erpai = {…}, update EXPECTED_API in tests/api-surface.test.mjs AND types/erpai-pages-runtime.d.ts in the same commit.
  4. npm run build && npm test must both pass.
  5. Bump the version in package.json:
    • Patch (e.g. 2.2.02.2.1) for bug fixes that don't change the API.
    • Minor (e.g. 2.2.02.3.0) for additive changes (new exports).
    • Major (e.g. 2.2.03.0.0) for renames, removals, signature changes.
  6. Add a CHANGELOG.md entry.
  7. Tag the release: git tag v2.3.0 && git push --tags.
  8. Bump the version in consumers (erpai-ui, neo).

Releases

Version Highlights
2.2.0 First standalone release. Adds compactNumber, branchId export, X-Branch-Id header, --blue theme token, dropdown CSS, dedup.

See CHANGELOG.md for full history.

License

UNLICENSED — internal Deskera/ERPAI use only. Do not distribute.

About

Browser runtime SDK for ERPAI custom HTML pages — the contract between agent-generated pages and the iframe they execute in. Provides window.erpai (SQL/records API, formatters, dropdowns, theme, Tabler icons, charts).

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors