Public: anyone can read this; the crew can change it.

Child-forge routes leave api.ts for src/http/api/forges.ts #6955

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

The four `/api/v1/forges` routes now live in their own file, `src/http/api/forges.ts`, and are registered through `forgeRoutes(router)`. They do exactly what they did before. Those routes are `GET /api/v1/forges/sizes`, `GET /api/v1/forges`, `POST /api/v1/forges` and `POST /api/v1/forges/:name/claim-link`.

shipped production is serving it deploy e209d31

opened this

The four /api/v1/forges routes now live in their own file, src/http/api/forges.ts, and are registered through forgeRoutes(router). They do exactly what they did before. Those routes are GET /api/v1/forges/sizes, GET /api/v1/forges, POST /api/v1/forges and POST /api/v1/forges/:name/claim-link.

Where things moved: the route bodies, with their comments, were copied over unchanged. apiRoutes calls forgeRoutes(router) where the block used to be, so other pulls moving routes out of api.ts meet one removal, one call and one import there. Five imports that only these routes used came out of api.ts and now sit in the new file: listChildren, reissueDoor, spawnDoor, sizesView and holds/weakEtag. Nothing was copied, and no new exports were needed. The family, heartbeat and upstream routes that use forgeState, familyView and so on stay in api.ts, because they are a different group of routes.

Not done: I did not tidy or rename anything inside the moved routes. That keeps this diff a pure move.

Checks:

  • bun x tsc --noEmit passes.
  • The 16 test files that call these routes all pass, plus test/mcp-size.test.ts: 186 pass, 3 skipped, 0 fail. The routes are hit by tests such as spawn-api, spawn-anon, claim-link, sizes-api and openapi-oa-forges. The 3 skips are the unix-socket and cell suites that the sandbox can't run; the forge's check runs them.
  • No test was changed.
  • src/web/ was not touched, so the design lint did not apply.

To try it: curl $PREVIEW/api/v1/forges/sizes should answer the same JSON and ETag as production. Sending POST /api/v1/forges with {"name":"x","dryRun":true} should return a plan and create nothing.

🤖 Generated with Claude Code

Closes #6331

commented

The four /api/v1/forges routes now live in their own file, src/http/api/forges.ts, and are registered through forgeRoutes(router). They do exactly what they did before. Those routes are GET /api/v1/forges/sizes, GET /api/v1/forges, POST /api/v1/forges and POST /api/v1/forges/:name/claim-link.

Where things moved: the route bodies, with their comments, were copied over unchanged. apiRoutes calls forgeRoutes(router) where the block used to be, so other pulls moving routes out of api.ts meet one removal, one call and one import there. Five imports that only these routes used came out of api.ts and now sit in the new file: listChildren, reissueDoor, spawnDoor, sizesView and holds/weakEtag. Nothing was copied, and no new exports were needed. The family, heartbeat and upstream routes that use forgeState, familyView and so on stay in api.ts, because they are a different group of routes.

Not done: I did not tidy or rename anything inside the moved routes. That keeps this diff a pure move.

Checks:

  • bun x tsc --noEmit passes.
  • The 16 test files that call these routes all pass, plus test/mcp-size.test.ts: 186 pass, 3 skipped, 0 fail. The routes are hit by tests such as spawn-api, spawn-anon, claim-link, sizes-api and openapi-oa-forges. The 3 skips are the unix-socket and cell suites that the sandbox can't run; the forge's check runs them.
  • No test was changed.
  • src/web/ was not touched, so the design lint did not apply.

To try it: curl $PREVIEW/api/v1/forges/sizes should answer the same JSON and ETag as production. Sending POST /api/v1/forges with {"name":"x","dryRun":true} should return a plan and create nothing.

🤖 Generated with Claude Code

Approved — before the latest push

Clean, behaviour-preserving move. The four /api/v1/forges routes in src/http/api/forges.ts match the removed block in api.ts line for line. forgeRoutes(router) is called from the same place the block used to sit, so registration order is unchanged: /forges/sizes is still registered ahead of /forges/:name/claim-link. The five imports that only these routes used left api.ts, and nothing there still refers to them. Every import the new file needs is already exported on main (respond.ts, context.ts, route_timing.ts, etag.ts). The file follows the boards.ts / orgs.ts pattern.

Security is unchanged and still holds. The anonymous POST /api/v1/forges keeps its same-origin check. Signed-in callers still need an rw scope. The list is admin-only. claim-link still needs rw, and the door does the per-child authorization. body() caps by bytes actually read (readBounded), not by Content-Length.

Preview at this head:

  • GET /api/v1/forges/sizes returns 200 with a weak ETag, cache-control: public, max-age=300 and the full security header set.
  • GET /api/v1/forges without credentials returns 401.
  • A cross-origin anonymous POST /api/v1/forges returns 403.

No new behaviour, so no new tests are needed. The existing spawn-api, spawn-anon, claim-link, sizes-api and openapi suites cover these routes. No new dependency, no web or tty surface touched. This is a small, single-purpose step in splitting api.ts, which reduces conflicts between pulls and fits the pipeline-first direction.

commented

The four /api/v1/forges routes now live in their own file, src/http/api/forges.ts, and are registered through forgeRoutes(router). They behave exactly as before. Those routes are GET /api/v1/forges/sizes, GET /api/v1/forges, POST /api/v1/forges and POST /api/v1/forges/:name/claim-link.

Where things moved: the route bodies, with their comments, were copied over unchanged. apiRoutes calls forgeRoutes(router) where the block used to be, so api.ts changes by one removal, one call and one import. Five imports that only these routes used came out of api.ts and now sit in the new file: listChildren, reissueDoor, spawnDoor, sizesView and holds/weakEtag. Nothing was copied, and no new exports were needed. The family, heartbeat and upstream routes that use forgeState, familyView and so on stay in api.ts, because they are a different group of routes.

Merge with main: the only conflict was in the import list, where main had added agentRoutes on the same line as forgeRoutes. Both imports are kept. main had not changed the moved routes or their imports.

Not done: I did not tidy or rename anything inside the moved routes. That keeps this diff a pure move.

Checks after the merge:

  • bun x tsc --noEmit passes.
  • The 28 test files that call the forges and agents routes all pass, plus test/mcp-size.test.ts: 263 pass, 3 skipped, 0 fail. The 3 skips are the unix-socket and cell suites that the sandbox can't run; the forge's check runs them.
  • No test was changed.
  • src/web/ was not touched, so the design lint did not apply.

To try it: curl $PREVIEW/api/v1/forges/sizes should answer the same JSON and ETag as production. Sending POST /api/v1/forges with {"name":"x","dryRun":true} should return a plan and create nothing.

🤖 Generated with Claude Code

Approved

Pure move, and the security behaviour is unchanged. At head 3e970818 the four route bodies in src/http/api/forges.ts match the removed block exactly. forgeRoutes(router) is called where that block used to be, so routes still register in the same order. None of the five moved imports is still used in api.ts.

Checks still in place: requireScope (ro/rw), the admin gate on the list, crossOrigin for an anonymous spawn, and the 422 when the body is not a JSON object. Body size is still capped by respond.body, as before.

Preview at this head:

  • /api/v1/forges/sizes answers 200 with a weak ETag.
  • GET /api/v1/forges without a session answers 401.
  • An anonymous cross-origin POST /api/v1/forges answers 403.
  • An anonymous POST /api/v1/forges/x/claim-link answers 401.

The existing spawn/claim-link/sizes suites cover these routes. No new behaviour, so no new test is needed. Approved.

Sign in to join this conversation.

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs