From 62f2f560cbd43fec28f794c9f93edfbb4b7b6236 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 13 Apr 2026 23:56:04 +0000 Subject: [PATCH 1/3] Initial plan From 8834b1d70c0a6dcb5e1729ca9bf59087a37b578f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 14 Apr 2026 00:01:29 +0000 Subject: [PATCH 2/3] refactor: pass adminApiMiddleware into createKoaApp(); rename koaMiddleware to routesMiddleware Agent-Logs-Url: https://github.com/counterfact/api-simulator/sessions/d1c59b39-f61d-4f73-931b-bd773553d881 --- .../refactor-admin-api-middleware-param.md | 5 +++++ docs/features/programmatic-api.md | 2 +- src/app.ts | 13 +++++++---- src/server/create-koa-app.ts | 21 +++++++++--------- src/server/koa-middleware.ts | 2 +- test/app.test.ts | 4 ++-- test/server/koa-middleware.test.ts | 22 +++++++++---------- 7 files changed, 39 insertions(+), 30 deletions(-) create mode 100644 .changeset/refactor-admin-api-middleware-param.md diff --git a/.changeset/refactor-admin-api-middleware-param.md b/.changeset/refactor-admin-api-middleware-param.md new file mode 100644 index 000000000..7781029dc --- /dev/null +++ b/.changeset/refactor-admin-api-middleware-param.md @@ -0,0 +1,5 @@ +--- +"counterfact": patch +--- + +Refactor `createKoaApp()` to accept `adminApiMiddleware` as a parameter instead of constructing it internally. Rename the `koaMiddleware` parameter and export to `routesMiddleware`. diff --git a/docs/features/programmatic-api.md b/docs/features/programmatic-api.md index e55aab2ab..78ea23e46 100644 --- a/docs/features/programmatic-api.md +++ b/docs/features/programmatic-api.md @@ -94,7 +94,7 @@ it("prompts for a password change when the password has expired", async () => { | `contextRegistry` | `ContextRegistry` | Registry of all context objects keyed by path. Call `.find(path)` to get the context for a given route prefix. | | `registry` | `Registry` | Registry of all loaded route modules. | | `koaApp` | `Koa` | The underlying Koa application. | -| `koaMiddleware` | `Koa.Middleware` | The Counterfact request-dispatch middleware. | +| `routesMiddleware` | `Koa.Middleware` | The Counterfact request-dispatch middleware. | | `start(config)` | `async (config) => { stop() }` | Starts the server (and optionally the file watcher and code generator). Returns a `stop()` function to gracefully shut down. | | `startRepl()` | `() => REPLServer` | Starts the interactive REPL. Returns the REPL server instance. | diff --git a/src/app.ts b/src/app.ts index bf4c670bb..886b2f566 100644 --- a/src/app.ts +++ b/src/app.ts @@ -5,11 +5,12 @@ import { createHttpTerminator, type HttpTerminator } from "http-terminator"; import { startRepl as startReplServer } from "./repl/repl.js"; import { createRouteFunction } from "./repl/route-builder.js"; +import { adminApiMiddleware } from "./server/admin-api-middleware.js"; import type { Config } from "./server/config.js"; import { ContextRegistry } from "./server/context-registry.js"; import { createKoaApp } from "./server/create-koa-app.js"; import { Dispatcher, type DispatcherRequest } from "./server/dispatcher.js"; -import { koaMiddleware } from "./server/koa-middleware.js"; +import { routesMiddleware } from "./server/koa-middleware.js"; import { loadOpenApiDocument } from "./server/load-openapi-document.js"; import { ModuleLoader } from "./server/module-loader.js"; import { Registry } from "./server/registry.js"; @@ -224,9 +225,13 @@ export async function counterfact(config: Config) { void writeScenarioContextType(modulesPath); }); - const middleware = koaMiddleware(dispatcher, config); + const middleware = routesMiddleware(dispatcher, config); - const koaApp = createKoaApp(registry, middleware, config, contextRegistry); + const adminMiddleware = config.startAdminApi + ? adminApiMiddleware(registry, contextRegistry, config) + : undefined; + + const koaApp = createKoaApp(registry, middleware, config, adminMiddleware); async function start(options: Config) { const { generate, startServer, watch, buildCache } = options; @@ -284,7 +289,7 @@ export async function counterfact(config: Config) { return { contextRegistry, koaApp, - koaMiddleware: middleware, + routesMiddleware: middleware, registry, start, startRepl: () => diff --git a/src/server/create-koa-app.ts b/src/server/create-koa-app.ts index 5647627f8..5b4a03365 100644 --- a/src/server/create-koa-app.ts +++ b/src/server/create-koa-app.ts @@ -3,9 +3,7 @@ import Koa from "koa"; import bodyParser from "koa-bodyparser"; import { koaSwagger } from "koa2-swagger-ui"; -import { adminApiMiddleware } from "./admin-api-middleware.js"; import type { Config } from "./config.js"; -import type { ContextRegistry } from "./context-registry.js"; import { openapiMiddleware } from "./openapi-middleware.js"; import type { Registry } from "./registry.js"; @@ -17,23 +15,24 @@ const debug = createDebug("counterfact:server:create-koa-app"); * The middleware stack (in order) is: * 1. OpenAPI document serving at `/counterfact/openapi` * 2. Swagger UI at `/counterfact/swagger` - * 3. Admin API (when enabled) at `/_counterfact/api/` + * 3. Admin API (when provided) at `/_counterfact/api/` * 4. Redirect `/counterfact` → `/counterfact/swagger` * 5. Body parser * 6. JSON serialisation of object bodies * 7. Route-dispatching middleware * - * @param registry - The route registry used by the admin API and dispatcher. - * @param koaMiddleware - The pre-built route-dispatching middleware. + * @param registry - The route registry used for debug logging. + * @param routesMiddleware - The pre-built route-dispatching middleware. * @param config - Server configuration. - * @param contextRegistry - The context registry used by the admin API. + * @param adminApiMiddleware - Optional pre-built admin API middleware; when + * provided it is mounted at `/_counterfact/api/`. * @returns A configured Koa application (not yet listening). */ export function createKoaApp( registry: Registry, - koaMiddleware: Koa.Middleware, + routesMiddleware: Koa.Middleware, config: Config, - contextRegistry: ContextRegistry, + adminApiMiddleware?: Koa.Middleware, ) { const app = new Koa(); @@ -54,8 +53,8 @@ export function createKoaApp( }), ); - if (config.startAdminApi) { - app.use(adminApiMiddleware(registry, contextRegistry, config)); + if (adminApiMiddleware) { + app.use(adminApiMiddleware); } debug("basePath: %s", config.basePath); @@ -87,7 +86,7 @@ export function createKoaApp( } }); - app.use(koaMiddleware); + app.use(routesMiddleware); return app; } diff --git a/src/server/koa-middleware.ts b/src/server/koa-middleware.ts index 87d480822..94b25a8ed 100644 --- a/src/server/koa-middleware.ts +++ b/src/server/koa-middleware.ts @@ -101,7 +101,7 @@ function getAuthObject( * @param proxy - Proxy factory; injectable for testing. * @returns A Koa middleware function. */ -export function koaMiddleware( +export function routesMiddleware( dispatcher: Dispatcher, config: Config, proxy = koaProxy, diff --git a/test/app.test.ts b/test/app.test.ts index 8b599655d..62f440127 100644 --- a/test/app.test.ts +++ b/test/app.test.ts @@ -79,12 +79,12 @@ describe("counterfact", () => { expect(typeof result.startRepl).toBe("function"); }); - it("returns contextRegistry, registry, koaApp, koaMiddleware, and start", async () => { + it("returns contextRegistry, registry, koaApp, routesMiddleware, and start", async () => { const result = await (app as any).counterfact(mockConfig); expect(result.contextRegistry).toBeDefined(); expect(result.registry).toBeDefined(); expect(result.koaApp).toBeDefined(); - expect(result.koaMiddleware).toBeDefined(); + expect(result.routesMiddleware).toBeDefined(); expect(typeof result.start).toBe("function"); }); diff --git a/test/server/koa-middleware.test.ts b/test/server/koa-middleware.test.ts index 3b31eeb38..a767e63e5 100644 --- a/test/server/koa-middleware.test.ts +++ b/test/server/koa-middleware.test.ts @@ -5,7 +5,7 @@ import type { IBaseKoaProxiesOptions } from "koa-proxies"; import type { Config } from "../../src/server/config.js"; import { ContextRegistry } from "../../src/server/context-registry.js"; import { Dispatcher } from "../../src/server/dispatcher.js"; -import { koaMiddleware } from "../../src/server/koa-middleware.js"; +import { routesMiddleware } from "../../src/server/koa-middleware.js"; import { Registry } from "../../src/server/registry.js"; const CONFIG: Config = { @@ -54,7 +54,7 @@ describe("koa middleware", () => { }); const dispatcher = new Dispatcher(registry, new ContextRegistry()); - const middleware = koaMiddleware(dispatcher, CONFIG); + const middleware = routesMiddleware(dispatcher, CONFIG); const ctx = { req: { @@ -91,7 +91,7 @@ describe("koa middleware", () => { }); const dispatcher = new Dispatcher(registry, new ContextRegistry()); - const middleware = koaMiddleware(dispatcher, CONFIG); + const middleware = routesMiddleware(dispatcher, CONFIG); const ctx = { request: { headers: {}, method: "GET", path: "/not-modified" }, @@ -117,7 +117,7 @@ describe("koa middleware", () => { }); const dispatcher = new Dispatcher(registry, new ContextRegistry()); - const middleware = koaMiddleware( + const middleware = routesMiddleware( dispatcher, { ...CONFIG, @@ -157,7 +157,7 @@ describe("koa middleware", () => { }); const dispatcher = new Dispatcher(registry, new ContextRegistry()); - const middleware = koaMiddleware(dispatcher, CONFIG); + const middleware = routesMiddleware(dispatcher, CONFIG); const ctx = { body: undefined, @@ -205,7 +205,7 @@ describe("koa middleware", () => { }); const dispatcher = new Dispatcher(registry, new ContextRegistry()); - const middleware = koaMiddleware(dispatcher, CONFIG); + const middleware = routesMiddleware(dispatcher, CONFIG); const ctx = { body: undefined, @@ -269,7 +269,7 @@ describe("koa middleware", () => { }); const dispatcher = new Dispatcher(registry, new ContextRegistry()); - const middleware = koaMiddleware(dispatcher, CONFIG); + const middleware = routesMiddleware(dispatcher, CONFIG); const ctx = { body: undefined, @@ -313,7 +313,7 @@ describe("koa middleware", () => { }); const dispatcher = new Dispatcher(registry, new ContextRegistry()); - const middleware = koaMiddleware(dispatcher, { + const middleware = routesMiddleware(dispatcher, { ...CONFIG, routePrefix: "/api/v1", }); @@ -353,7 +353,7 @@ describe("koa middleware", () => { }); const dispatcher = new Dispatcher(registry, new ContextRegistry()); - const middleware = koaMiddleware(dispatcher, { + const middleware = routesMiddleware(dispatcher, { ...CONFIG, routePrefix: "/api/v1", }); @@ -393,7 +393,7 @@ describe("koa middleware", () => { }); const dispatcher = new Dispatcher(registry, new ContextRegistry()); - const middleware = koaMiddleware(dispatcher, CONFIG); + const middleware = routesMiddleware(dispatcher, CONFIG); const ctx = { req: { @@ -435,7 +435,7 @@ describe("koa middleware", () => { }); const dispatcher = new Dispatcher(registry, new ContextRegistry()); - const middleware = koaMiddleware(dispatcher, CONFIG); + const middleware = routesMiddleware(dispatcher, CONFIG); const ctx = { body: undefined, From 3b561642f4584eafb3d9da6a58d6816de1e40585 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 14 Apr 2026 00:18:16 +0000 Subject: [PATCH 3/3] refactor: remove registry param from createKoaApp() and drop debug routes line Agent-Logs-Url: https://github.com/counterfact/api-simulator/sessions/6fc38d64-50f9-4277-a2ca-57b411522aee --- src/app.ts | 2 +- src/server/create-koa-app.ts | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/app.ts b/src/app.ts index 886b2f566..c89e886dc 100644 --- a/src/app.ts +++ b/src/app.ts @@ -231,7 +231,7 @@ export async function counterfact(config: Config) { ? adminApiMiddleware(registry, contextRegistry, config) : undefined; - const koaApp = createKoaApp(registry, middleware, config, adminMiddleware); + const koaApp = createKoaApp(middleware, config, adminMiddleware); async function start(options: Config) { const { generate, startServer, watch, buildCache } = options; diff --git a/src/server/create-koa-app.ts b/src/server/create-koa-app.ts index 5b4a03365..b21d9efdf 100644 --- a/src/server/create-koa-app.ts +++ b/src/server/create-koa-app.ts @@ -5,7 +5,6 @@ import { koaSwagger } from "koa2-swagger-ui"; import type { Config } from "./config.js"; import { openapiMiddleware } from "./openapi-middleware.js"; -import type { Registry } from "./registry.js"; const debug = createDebug("counterfact:server:create-koa-app"); @@ -21,7 +20,6 @@ const debug = createDebug("counterfact:server:create-koa-app"); * 6. JSON serialisation of object bodies * 7. Route-dispatching middleware * - * @param registry - The route registry used for debug logging. * @param routesMiddleware - The pre-built route-dispatching middleware. * @param config - Server configuration. * @param adminApiMiddleware - Optional pre-built admin API middleware; when @@ -29,7 +27,6 @@ const debug = createDebug("counterfact:server:create-koa-app"); * @returns A configured Koa application (not yet listening). */ export function createKoaApp( - registry: Registry, routesMiddleware: Koa.Middleware, config: Config, adminApiMiddleware?: Koa.Middleware, @@ -58,7 +55,6 @@ export function createKoaApp( } debug("basePath: %s", config.basePath); - debug("routes", registry.routes); app.use(async (ctx, next) => { if (ctx.URL.pathname === "/counterfact") {