| 1 | // Run after building apps/api. All rate-limit exhaustion is local, never production. |
| 2 | import assert from "node:assert/strict"; |
| 3 | import { readFileSync } from "node:fs"; |
| 4 | import { resolve } from "node:path"; |
| 5 | import { Miniflare, convertV4MiniflareOptions } from "miniflare"; |
| 6 | |
| 7 | const root = resolve("apps/api/build"); |
| 8 | const config = readFileSync("apps/api/wrangler.jsonc", "utf8"); |
| 9 | const services = [...config.matchAll(/"binding":\s*"([^"]+)"\s*,\s*"service"/g)].map((m) => m[1]); |
| 10 | let calls = 0; |
| 11 | const runtime = new Miniflare( |
| 12 | convertV4MiniflareOptions({ |
| 13 | name: "api-agent-protocol", |
| 14 | cf: false, |
| 15 | modulesRoot: root, |
| 16 | modules: [ |
| 17 | { type: "ESModule", path: resolve(root, "index.js") }, |
| 18 | { type: "CompiledWasm", path: resolve(root, "index_bg.wasm") }, |
| 19 | ], |
| 20 | compatibilityDate: "2026-09-26", |
| 21 | serviceBindings: Object.fromEntries( |
| 22 | services.map((name) => [ |
| 23 | name, |
| 24 | async () => { |
| 25 | calls++; |
| 26 | return Response.json(null); |
| 27 | }, |
| 28 | ]), |
| 29 | ), |
| 30 | ratelimits: { |
| 31 | API_ANONYMOUS_LIMIT: { namespace_id: "4401", simple: { limit: 60, period: 60 } }, |
| 32 | API_TOKEN_LIMIT: { namespace_id: "4402", simple: { limit: 1000, period: 60 } }, |
| 33 | }, |
| 34 | }), |
| 35 | ); |
| 36 | try { |
| 37 | const origin = await runtime.ready; |
| 38 | const request = (path, init) => fetch(new URL(path, origin), { ...init, signal: AbortSignal.timeout(15_000) }); |
| 39 | const openapi = await request("/openapi.json"); |
| 40 | assert.equal(openapi.status, 200); |
| 41 | assert.equal(openapi.headers.get("x-g1t-api-version"), "1"); |
| 42 | assert.equal(openapi.headers.get("ratelimit-policy"), '"anonymous";q=60;w=60'); |
| 43 | assert.equal(openapi.headers.get("ratelimit"), null, "no fabricated remaining count"); |
| 44 | const spec = await openapi.json(); |
| 45 | assert.ok(spec.components.securitySchemes.oauth.flows.authorizationCode.scopes["repo:read"]); |
| 46 | assert.equal((await request("/", { headers: { "X-G1t-Api-Version": "1" } })).status, 200); |
| 47 | assert.equal((await request("/v1/")).status, 200); |
| 48 | const before = calls; |
| 49 | assert.equal( |
| 50 | ( |
| 51 | await request("/workspaces/example/work", { |
| 52 | method: "POST", |
| 53 | headers: { "X-G1t-Api-Version": "unsupported", "content-type": "application/json" }, |
| 54 | body: "{}", |
| 55 | }) |
| 56 | ).status, |
| 57 | 422, |
| 58 | ); |
| 59 | assert.equal(calls, before, "unsupported versions cannot execute a mutation"); |
| 60 | const cors = await request("/repos", { method: "OPTIONS" }); |
| 61 | assert.equal(cors.status, 204); |
| 62 | assert.match(cors.headers.get("access-control-allow-headers"), /x-g1t-api-version/); |
| 63 | assert.match(cors.headers.get("access-control-expose-headers"), /ratelimit-policy/); |
| 64 | let exhausted; |
| 65 | for (let i = 0; i < 65; i++) { |
| 66 | const answer = await request("/"); |
| 67 | await answer.text(); |
| 68 | if (answer.status === 429) { |
| 69 | exhausted = answer; |
| 70 | break; |
| 71 | } |
| 72 | } |
| 73 | assert.ok(exhausted, "local quota must be exhausted"); |
| 74 | assert.equal(exhausted.headers.get("retry-after"), "60"); |
| 75 | assert.equal(exhausted.headers.get("ratelimit"), '"anonymous";r=0;t=60'); |
| 76 | assert.equal(exhausted.headers.get("ratelimit-policy"), '"anonymous";q=60;w=60'); |
| 77 | console.log("API Worker: OpenAPI, version selection, mutation rejection, CORS, policy and actual 429 headers verified."); |
| 78 | } finally { |
| 79 | await runtime.dispose(); |
| 80 | } |