# `goja/` — @hanzo/plans inside the unified cloud binary

`bundle.js` is a **self-contained, ESM-free** companion to `index.mjs` +
`entitlements.mjs`, authored so it runs verbatim inside the
[`dop251/goja`](https://github.com/dop251/goja) JavaScript engine embedded in
[`hanzoai/cloud`](https://github.com/hanzoai/cloud) per HIP-0106.

## Why a bundle?

goja supports ES2020 (spread, destructuring, optional chaining, nullish,
`Object.fromEntries`, …) but **not** ES-module `import`/`export` and **not**
`node:` builtins. So `index.mjs`/`entitlements.mjs` (ESM + `createRequire`)
cannot be loaded directly. Rather than reimplement the entitlement vocabulary in
Go, the **exact transform logic** from `entitlements.mjs` lives here as CommonJS
and runs in goja. The catalog JSON is **injected by the Go host** at VM init via
`globalThis.__PLANS_DATA__`, so the `*.json` files stay the single source of
truth — the bundle carries logic, not a copy of the data.

## Host contract

```
globalThis.__PLANS_DATA__ = { "subscription.json": <obj>, "plans.json": <obj>, … }
globalThis.handle({ route, params, query, tenant }) -> { status, body }
globalThis.plans = { fromLegacy, toPriceRefStub, toLicenseFeatures, resolvePlan, … }
```

The Go wrapper (`hanzoai/cloud/clients/plansvc`) injects the data, registers the
`/v1/plans/*` zip routes, and calls `handle()` per request with `tenant` set to
the gateway-minted `X-Org-Id` (per-reseller catalog scoping).

## Parity guarantee

`test/bundle.test.mjs` runs this bundle in a Node `vm` context and asserts its
`resolvePlan` / `fromLegacy` / `toLicenseFeatures` output is **byte-for-byte
identical** to the canonical `entitlements.mjs` source for every real
subscription plan. `npm test` runs it. Edit `entitlements.mjs`? Mirror it here or
the parity test fails.
