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]>
1.8 KiB
zoo-cloud-api
Use
apps/edgeinstead, 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/edgeis 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.