From bb8194c1ec5eb461564937c26f658ed4c681ef71 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 11 Feb 2026 13:18:03 +0000 Subject: [PATCH 1/2] Initial plan From cbfa46407c14629450dc6b77c89365bd8281d68a Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 11 Feb 2026 13:25:18 +0000 Subject: [PATCH 2/2] fix: register discovery endpoint at /api/v1/discovery in addition to /api/v1 Both RestServer and DispatcherPlugin now register discovery at the /discovery sub-path so that GET /api/v1/discovery returns the API discovery payload alongside the existing /api/v1 and /.well-known/objectstack endpoints. Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com> --- packages/rest/src/rest-server.ts | 22 ++++++++++++++++++---- packages/rest/src/rest.test.ts | 5 +++-- packages/runtime/src/dispatcher-plugin.ts | 5 +++++ 3 files changed, 26 insertions(+), 6 deletions(-) diff --git a/packages/rest/src/rest-server.ts b/packages/rest/src/rest-server.ts index 2bc9e253f1..8eff0c4941 100644 --- a/packages/rest/src/rest-server.ts +++ b/packages/rest/src/rest-server.ts @@ -216,10 +216,7 @@ export class RestServer { * Register discovery endpoints */ private registerDiscoveryEndpoints(basePath: string): void { - this.routeManager.register({ - method: 'GET', - path: basePath, - handler: async (_req: any, res: any) => { + const discoveryHandler = async (_req: any, res: any) => { try { const discovery = await this.protocol.getDiscovery(); @@ -250,7 +247,24 @@ export class RestServer { } catch (error: any) { res.status(500).json({ error: error.message }); } + }; + + // Register at basePath (e.g. /api/v1) + this.routeManager.register({ + method: 'GET', + path: basePath, + handler: discoveryHandler, + metadata: { + summary: 'Get API discovery information', + tags: ['discovery'], }, + }); + + // Register at basePath/discovery (e.g. /api/v1/discovery) + this.routeManager.register({ + method: 'GET', + path: `${basePath}/discovery`, + handler: discoveryHandler, metadata: { summary: 'Get API discovery information', tags: ['discovery'], diff --git a/packages/rest/src/rest.test.ts b/packages/rest/src/rest.test.ts index 47233493c0..89a407ebdc 100644 --- a/packages/rest/src/rest.test.ts +++ b/packages/rest/src/rest.test.ts @@ -309,8 +309,9 @@ describe('RestServer', () => { // Expect at least discovery + metadata + CRUD routes const paths = routes.map((r) => r.path); - // Discovery + // Discovery (both basePath and basePath/discovery) expect(paths).toContain('/api/v1'); + expect(paths).toContain('/api/v1/discovery'); // Metadata expect(paths.some((p) => p.includes('/meta'))).toBe(true); // CRUD @@ -356,7 +357,7 @@ describe('RestServer', () => { rest.registerRoutes(); const routes = rest.getRoutes(); - // Discovery route is the basePath itself (e.g. /api/v1) + // Neither basePath nor basePath/discovery should be registered const discoveryRoutes = routes.filter((r) => r.metadata?.tags?.includes('discovery'), ); diff --git a/packages/runtime/src/dispatcher-plugin.ts b/packages/runtime/src/dispatcher-plugin.ts index 70380b6e9a..0a9e780ec5 100644 --- a/packages/runtime/src/dispatcher-plugin.ts +++ b/packages/runtime/src/dispatcher-plugin.ts @@ -91,6 +91,11 @@ export function createDispatcherPlugin(config: DispatcherPluginConfig = {}): Plu res.json({ data: dispatcher.getDiscoveryInfo(prefix) }); }); + // ── Discovery (versioned API path) ────────────────────────── + server.get(`${prefix}/discovery`, async (_req: any, res: any) => { + res.json({ data: dispatcher.getDiscoveryInfo(prefix) }); + }); + // ── Auth ──────────────────────────────────────────────────── server.post(`${prefix}/auth/login`, async (req: any, res: any) => { try {