Files
zooqueenandHanzo Dev 37e2719185 Run the proxy where the sites already run
The DigitalOcean account was suspended, so everything on DOKS is gone:
api.zoo.cloud, api.zoo.network, gym.zoo.ngo and iam/kms.hanzo.ai all answer
525 — Cloudflare reaching for an origin that is not there — and zoolabs.id
and zoo.id do not resolve at all. apps/api is a Fastify process that wants a
cluster, so it has nowhere to go and Blue stays unreachable.

The sites themselves never noticed, because Pages serves them from
Cloudflare's own edge. So this does the same job from the same place: hold
the tenant credential, allow only our origins, meter what one caller spends,
stream the reply through. No origin, nothing to keep alive, and it sits
beside the sites it serves rather than in a cluster they do not depend on.

Two things it does better than the process it stands in for. The rate limit
is Cloudflare's, counted across the whole edge rather than per replica — the
ceiling apps/api could only approximate and said so. And the upstream is a
binding rather than a constant, so the tests point it at a real server and
check what actually crosses the wire.

Seven tests, all against a live upstream: preflight allowed for our sites,
refused for a stranger — including zoolabs.io.evil.test, which passes a
prefix check and must not pass this one — the tenant key added upstream and
never asked of the browser, a reply arriving as a stream rather than a lump,
and a missing credential answering 503 rather than pretending.

Deploying needs `wrangler secret put HANZO_API_KEY` and `wrangler deploy`.
api.hanzo.ai is still up, so the moment that lands, chat works on both sites
with no change to either.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-02 16:58:13 -07:00

1.8 KiB

zoo-cloud-api

Use apps/edge instead, for now. This one is a Fastify process and needs a cluster to run in; the DigitalOcean account is down, which is why api.zoo.cloud answers 525. apps/edge is the same proxy as a Cloudflare Worker, running where the sites already run, with no origin to keep alive.

api.zoo.cloud — the Zoo-branded way to reach the Hanzo API from a browser.

Why it exists

zoolabs.io and zoo.ngo are static sites, so every call they make is a browser call, and a browser call to api.hanzo.ai fails twice over:

  • the gateway sends no Access-Control-Allow-Origin, so the request never leaves
  • it answers anonymous callers 402 — a billable tenant is required

Neither is fixable from a static bundle: a key shipped to the browser is a published key. So the tenant credential lives here and the browser talks to this.

Running it

HANZO_API_KEY=<tenant key from KMS> node --experimental-strip-types src/index.ts
Variable Default Meaning
HANZO_API_KEY — tenant credential. Without it every /v1 call answers 503.
HANZO_API https://api.hanzo.ai upstream
RATE_PER_MINUTE 20 per-address ceiling
PORT 8080

GET /health reports whether the credential is present.

What it does and does not protect

Requests are allowed only from the foundation's own origins (src/origins.ts) and are rate limited per address (src/budget.ts). That is a floor, not a fix: the count is per process, so with N replicas the real ceiling is N times the limit, and a caller rotating addresses gets past it.

The durable answer is a signed-in identity — Hanzo IAM issues the token and usage bills to the person rather than to the foundation. Until that is wired, this endpoint spends Zoo Labs' money and should be watched.