diff --git a/deno.json b/deno.json index 1e36d3f..77f3252 100644 --- a/deno.json +++ b/deno.json @@ -1,6 +1,6 @@ { "name": "@moonlight-protocol/provider-platform", - "version": "0.7.2", + "version": "0.7.3", "license": "MIT", "exports": "./src/main.ts", "tasks": { diff --git a/src/http/v1/dashboard/routes.ts b/src/http/v1/dashboard/routes.ts index 5dc7e1e..1096588 100644 --- a/src/http/v1/dashboard/routes.ts +++ b/src/http/v1/dashboard/routes.ts @@ -1,4 +1,4 @@ -import { type Context, Router, Status } from "@oak/oak"; +import { Router } from "@oak/oak"; import type { Logger } from "@/utils/logger/index.ts"; import { handlePostChallenge } from "./auth/challenge.ts"; import { handlePostVerify } from "./auth/verify.ts"; @@ -6,26 +6,6 @@ import { handleDiscoverCouncil } from "./council.ts"; import { handleListPps, handleRegisterPp } from "./pp.ts"; import { jwtMiddleware } from "@/http/middleware/auth/index.ts"; -/** - * Per-PP endpoints whose canonical home is /providers/:ppPublicKey/... now - * answer 410 Gone here. The body names the new URL pattern so callers can - * migrate. This is a temporary deprecation surface; a follow-up PR removes - * these stubs once metrics confirm zero traffic. - * - * Two routes are bare-deleted instead of stubbed (per PM scope decision): - * - POST /dashboard/bundles/expire (no external callers; admin-only) - * - GET /dashboard/bundles (duplicated by PR #106's URL-scoped variant) - */ -function gone(newPath: string): (ctx: Context) => void { - return (ctx) => { - ctx.response.status = Status.Gone; - ctx.response.body = { - message: - `This endpoint has moved. Use ${newPath} (per-PP URL-scoped path).`, - }; - }; -} - export function buildDashboardRouter(deps: { log: Logger }): Router { const dashboardRouter = new Router(); @@ -52,69 +32,5 @@ export function buildDashboardRouter(deps: { log: Logger }): Router { handleDiscoverCouncil(deps), ); - // --- 410 Gone stubs for migrated per-PP routes --- - dashboardRouter.post( - "/dashboard/pp/delete", - gone("DELETE /api/v1/providers/:ppPublicKey"), - ); - dashboardRouter.get( - "/dashboard/channels", - gone("GET /api/v1/providers/:ppPublicKey/channels"), - ); - dashboardRouter.get( - "/dashboard/mempool", - gone("GET /api/v1/providers/:ppPublicKey/mempool"), - ); - dashboardRouter.get( - "/dashboard/operations", - gone("GET /api/v1/providers/:ppPublicKey/operations"), - ); - dashboardRouter.get( - "/dashboard/treasury", - gone("GET /api/v1/providers/:ppPublicKey/treasury"), - ); - dashboardRouter.get( - "/dashboard/utxos", - gone("GET /api/v1/providers/:ppPublicKey/utxos?channelContractId=..."), - ); - dashboardRouter.get( - "/dashboard/transactions", - gone("GET /api/v1/providers/:ppPublicKey/transactions"), - ); - dashboardRouter.get( - "/dashboard/transactions/:id", - gone("GET /api/v1/providers/:ppPublicKey/transactions/:id"), - ); - dashboardRouter.get( - "/dashboard/bundles/:id", - gone("GET /api/v1/providers/:ppPublicKey/bundles/:id"), - ); - dashboardRouter.get( - "/dashboard/audit-export", - gone("GET /api/v1/providers/:ppPublicKey/audit-export"), - ); - dashboardRouter.get( - "/dashboard/metrics", - gone("GET /api/v1/providers/:ppPublicKey/metrics"), - ); - dashboardRouter.post( - "/dashboard/council/join", - gone("POST /api/v1/providers/:ppPublicKey/council/join"), - ); - dashboardRouter.get( - "/dashboard/council/membership", - gone("GET /api/v1/providers/:ppPublicKey/council/membership"), - ); - dashboardRouter.post( - "/dashboard/council/membership", - gone("POST /api/v1/providers/:ppPublicKey/council/membership"), - ); - - // NOTE: POST /dashboard/bundles/expire and GET /dashboard/bundles (query - // variant) are intentionally NOT registered here — bare-deleted per PM - // scope. The canonical bundle list endpoints are URL-scoped: - // GET /providers/:ppPublicKey/bundles (provider/operator view) - // GET /providers/:ppPublicKey/entity/bundles (entity/submitter view) - return dashboardRouter; } diff --git a/src/http/v1/entities/routes.ts b/src/http/v1/entities/routes.ts deleted file mode 100644 index c742541..0000000 --- a/src/http/v1/entities/routes.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { type Context, Router, Status } from "@oak/oak"; -import type { Logger } from "@/utils/logger/index.ts"; - -/** - * Legacy /entities surface. The canonical KYC/KYB endpoint is now - * POST /api/v1/providers/:ppPublicKey/entities (with a SEP-53 signedChallenge). - * This stub returns 410 Gone so callers migrate. - */ -function gone(newPath: string): (ctx: Context) => void { - return (ctx) => { - ctx.response.status = Status.Gone; - ctx.response.body = { - message: - `This endpoint has moved. Use ${newPath} (per-PP URL-scoped path).`, - }; - }; -} - -export function buildEntitiesRouter(_deps: { log: Logger }): Router { - const entitiesRouter = new Router(); - entitiesRouter.post( - "/entities", - gone("POST /api/v1/providers/:ppPublicKey/entities"), - ); - return entitiesRouter; -} diff --git a/src/http/v1/events/routes.ts b/src/http/v1/events/routes.ts deleted file mode 100644 index 738dca1..0000000 --- a/src/http/v1/events/routes.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { type Context, Router, Status } from "@oak/oak"; -import type { Logger } from "@/utils/logger/index.ts"; - -/** - * Legacy /events/ws surface. The canonical event stream is now - * GET /api/v1/providers/:ppPublicKey/events/ws. This stub returns 410 Gone - * so callers migrate. - */ -function gone(newPath: string): (ctx: Context) => void { - return (ctx) => { - ctx.response.status = Status.Gone; - ctx.response.body = { - message: - `This endpoint has moved. Use ${newPath} (per-PP URL-scoped path).`, - }; - }; -} - -export function buildEventsRouter(_deps: { log: Logger }): Router { - const eventsRouter = new Router(); - eventsRouter.get( - "/events/ws", - gone("GET /api/v1/providers/:ppPublicKey/events/ws"), - ); - return eventsRouter; -} diff --git a/src/http/v1/v1.routes.ts b/src/http/v1/v1.routes.ts index ad5d348..1733b12 100644 --- a/src/http/v1/v1.routes.ts +++ b/src/http/v1/v1.routes.ts @@ -7,8 +7,6 @@ import { buildPayRouter } from "@/http/v1/pay/routes.ts"; import healthRouter from "@/http/v1/health/routes.ts"; import { buildWaitlistRouter } from "@/http/v1/waitlist/routes.ts"; import { buildCouncilRouter } from "@/http/v1/council/routes.ts"; -import { buildEventsRouter } from "@/http/v1/events/routes.ts"; -import { buildEntitiesRouter } from "@/http/v1/entities/routes.ts"; import { buildProvidersRouter } from "@/http/v1/providers/routes.ts"; export function buildApiRouter(deps: { log: Logger }): Router { @@ -20,8 +18,6 @@ export function buildApiRouter(deps: { log: Logger }): Router { const payRouter = buildPayRouter(deps); const waitlistRouter = buildWaitlistRouter(deps); const councilRouter = buildCouncilRouter(deps); - const eventsRouter = buildEventsRouter(deps); - const entitiesRouter = buildEntitiesRouter(deps); const providersRouter = buildProvidersRouter(deps); apiRouter.use( @@ -55,16 +51,6 @@ export function buildApiRouter(deps: { log: Logger }): Router { waitlistRouter.routes(), waitlistRouter.allowedMethods(), ); - apiRouter.use( - "/api/v1", - eventsRouter.routes(), - eventsRouter.allowedMethods(), - ); - apiRouter.use( - "/api/v1", - entitiesRouter.routes(), - entitiesRouter.allowedMethods(), - ); apiRouter.use( "/api/v1", providersRouter.routes(), diff --git a/tests/integration/http/bundle-admin.test.ts b/tests/integration/http/bundle-admin.test.ts index 66921af..4492f39 100644 --- a/tests/integration/http/bundle-admin.test.ts +++ b/tests/integration/http/bundle-admin.test.ts @@ -1,6 +1,5 @@ import "../../ensure_test_env.ts"; import { Application, Router } from "@oak/oak"; -import { assertEquals } from "@std/assert"; import { newNoop } from "@/utils/logger/index.ts"; import { buildDashboardRouter } from "@/http/v1/dashboard/routes.ts"; import { ensureInitialized, resetDb } from "../../test_helpers.ts"; @@ -76,12 +75,3 @@ Deno.test("GET /dashboard/bundles (query variant) is not routed (bare-deleted)", throw new Error(`expected 404/405, got ${res.status}`); } }); - -Deno.test("GET /dashboard/bundles/:id is 410 Gone", async () => { - const app = await setup(); - const res = await app.handle( - new Request(`${LIST_PATH}/some-id`, { method: "GET" }), - ); - if (!res) throw new Error("No response from Oak app"); - assertEquals(res.status, 410); -}); diff --git a/tests/integration/http/dashboard-metrics.test.ts b/tests/integration/http/dashboard-metrics.test.ts index c504274..cbf1f71 100644 --- a/tests/integration/http/dashboard-metrics.test.ts +++ b/tests/integration/http/dashboard-metrics.test.ts @@ -237,28 +237,3 @@ Deno.test("returns 401 when JWT is missing", async () => { if (!response) throw new Error("No response from Oak app"); assertEquals(response.status, 401); }); - -Deno.test("legacy /dashboard/metrics returns 410 Gone", async () => { - // Wired in the dashboard router; we just confirm the path-shape contract. - // Full coverage of the dashboard 410-stub surface lives in dashboard-routes - // — this assertion is here to flag any accidental re-enable. - const { buildDashboardRouter } = await import( - "@/http/v1/dashboard/routes.ts" - ); - const app = new Application(); - const apiRouter = new Router(); - const dashboardRouter = buildDashboardRouter({ log: newNoop() }); - apiRouter.use( - "/api/v1", - dashboardRouter.routes(), - dashboardRouter.allowedMethods(), - ); - app.use(apiRouter.routes()); - app.use(apiRouter.allowedMethods()); - - const res = await app.handle( - new Request("http://localhost/api/v1/dashboard/metrics", { method: "GET" }), - ); - if (!res) throw new Error("No response"); - assertEquals(res.status, 410); -}); diff --git a/tests/integration/http/events-ws.test.ts b/tests/integration/http/events-ws.test.ts index 679a8a4..077da0f 100644 --- a/tests/integration/http/events-ws.test.ts +++ b/tests/integration/http/events-ws.test.ts @@ -273,23 +273,3 @@ Deno.test({ } }, }); - -Deno.test("legacy /events/ws returns 410 Gone", async () => { - const { buildEventsRouter } = await import("@/http/v1/events/routes.ts"); - const app = new Application(); - const apiRouter = new Router(); - const eventsRouter = buildEventsRouter({ log: newNoop() }); - apiRouter.use( - "/api/v1", - eventsRouter.routes(), - eventsRouter.allowedMethods(), - ); - app.use(apiRouter.routes()); - app.use(apiRouter.allowedMethods()); - - const res = await app.handle( - new Request("http://localhost/api/v1/events/ws", { method: "GET" }), - ); - if (!res) throw new Error("No response"); - assertEquals(res.status, 410); -});