@neat.is/web 0.2.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,54 @@
1
+ import { NextRequest } from 'next/server'
2
+ import { CORE_URL } from '../../../lib/proxy'
3
+
4
+ // ADR-057 #5 — SSE stream is project-scoped per ADR-026 + ADR-051.
5
+ export async function GET(request: NextRequest): Promise<Response> {
6
+ const project = new URL(request.url).searchParams.get('project') ?? ''
7
+ const base = project && project !== 'default'
8
+ ? `/projects/${encodeURIComponent(project)}/events`
9
+ : '/events'
10
+ try {
11
+ const upstream = await fetch(`${CORE_URL}${base}`, {
12
+ cache: 'no-store',
13
+ headers: { Accept: 'text/event-stream' },
14
+ })
15
+
16
+ if (!upstream.ok || !upstream.body) {
17
+ // Core doesn't have SSE yet (pre-v0.2.8) — send a single unavailable event and close
18
+ const body = new ReadableStream({
19
+ start(controller) {
20
+ controller.enqueue(
21
+ new TextEncoder().encode('event: error\ndata: {"reason":"unavailable"}\n\n'),
22
+ )
23
+ controller.close()
24
+ },
25
+ })
26
+ return new Response(body, {
27
+ status: 200,
28
+ headers: { 'content-type': 'text/event-stream', 'cache-control': 'no-cache' },
29
+ })
30
+ }
31
+
32
+ return new Response(upstream.body, {
33
+ status: 200,
34
+ headers: {
35
+ 'content-type': 'text/event-stream',
36
+ 'cache-control': 'no-cache',
37
+ 'x-accel-buffering': 'no',
38
+ },
39
+ })
40
+ } catch {
41
+ const body = new ReadableStream({
42
+ start(controller) {
43
+ controller.enqueue(
44
+ new TextEncoder().encode('event: error\ndata: {"reason":"unavailable"}\n\n'),
45
+ )
46
+ controller.close()
47
+ },
48
+ })
49
+ return new Response(body, {
50
+ status: 200,
51
+ headers: { 'content-type': 'text/event-stream', 'cache-control': 'no-cache' },
52
+ })
53
+ }
54
+ }
@@ -0,0 +1,19 @@
1
+ import { CORE_URL, proxyGet } from '../../../../../lib/proxy'
2
+ import { fixtureBlastRadius } from '../../../../../lib/fixtures'
3
+
4
+ // ADR-057 #5 — blast-radius forwards `project` per ADR-026.
5
+ export async function GET(
6
+ request: Request,
7
+ { params }: { params: { id: string } },
8
+ ): Promise<Response> {
9
+ const { searchParams } = new URL(request.url)
10
+ const depth = searchParams.get('depth') ?? '10'
11
+ const project = searchParams.get('project') ?? ''
12
+ const base = project && project !== 'default'
13
+ ? `/projects/${encodeURIComponent(project)}/graph/blast-radius`
14
+ : '/graph/blast-radius'
15
+ return proxyGet(
16
+ `${CORE_URL}${base}/${encodeURIComponent(params.id)}?depth=${depth}`,
17
+ () => Response.json(fixtureBlastRadius(params.id)),
18
+ )
19
+ }
@@ -0,0 +1,17 @@
1
+ import { CORE_URL, proxyGet } from '../../../../../lib/proxy'
2
+ import { fixtureNodeDetail } from '../../../../../lib/fixtures'
3
+
4
+ // ADR-057 #5 — node detail forwards `project` per ADR-026.
5
+ export async function GET(
6
+ request: Request,
7
+ { params }: { params: { id: string } },
8
+ ): Promise<Response> {
9
+ const project = new URL(request.url).searchParams.get('project') ?? ''
10
+ const base = project && project !== 'default'
11
+ ? `/projects/${encodeURIComponent(project)}/graph/node`
12
+ : '/graph/node'
13
+ return proxyGet(
14
+ `${CORE_URL}${base}/${encodeURIComponent(params.id)}`,
15
+ () => Response.json(fixtureNodeDetail(params.id)),
16
+ )
17
+ }
@@ -0,0 +1,17 @@
1
+ import { CORE_URL, proxyGet } from '../../../../../lib/proxy'
2
+ import { fixtureRootCause } from '../../../../../lib/fixtures'
3
+
4
+ // ADR-057 #5 — root-cause forwards `project` per ADR-026.
5
+ export async function GET(
6
+ request: Request,
7
+ { params }: { params: { id: string } },
8
+ ): Promise<Response> {
9
+ const project = new URL(request.url).searchParams.get('project') ?? ''
10
+ const base = project && project !== 'default'
11
+ ? `/projects/${encodeURIComponent(project)}/graph/root-cause`
12
+ : '/graph/root-cause'
13
+ return proxyGet(
14
+ `${CORE_URL}${base}/${encodeURIComponent(params.id)}`,
15
+ () => Response.json(fixtureRootCause(params.id)),
16
+ )
17
+ }
@@ -0,0 +1,12 @@
1
+ import { CORE_URL, proxyGet } from '../../../lib/proxy'
2
+ import { FIXTURE_GRAPH } from '../../../lib/fixtures'
3
+
4
+ export async function GET(request: Request): Promise<Response> {
5
+ const { searchParams } = new URL(request.url)
6
+ const project = searchParams.get('project')
7
+ const path =
8
+ project && project !== 'default'
9
+ ? `/projects/${encodeURIComponent(project)}/graph`
10
+ : '/graph'
11
+ return proxyGet(`${CORE_URL}${path}`, () => Response.json(FIXTURE_GRAPH))
12
+ }
@@ -0,0 +1,13 @@
1
+ import { CORE_URL, proxyGet } from '../../../lib/proxy'
2
+ import { FIXTURE_HEALTH } from '../../../lib/fixtures'
3
+
4
+ // ADR-057 #5 — health is project-aware so the dashboard reflects the project
5
+ // the operator is actually viewing.
6
+ export async function GET(request: Request): Promise<Response> {
7
+ const { searchParams } = new URL(request.url)
8
+ const project = searchParams.get('project') ?? ''
9
+ const path = project && project !== 'default'
10
+ ? `/projects/${encodeURIComponent(project)}/health`
11
+ : '/health'
12
+ return proxyGet(`${CORE_URL}${path}`, () => Response.json(FIXTURE_HEALTH))
13
+ }
@@ -0,0 +1,16 @@
1
+ import { CORE_URL, proxyGet } from '../../../lib/proxy'
2
+ import { FIXTURE_INCIDENTS } from '../../../lib/fixtures'
3
+
4
+ // ADR-057 #5 — incidents are scoped to a project per ADR-026's dual-mount.
5
+ export async function GET(request: Request): Promise<Response> {
6
+ const { searchParams } = new URL(request.url)
7
+ const limit = searchParams.get('limit') ?? '50'
8
+ const project = searchParams.get('project') ?? ''
9
+ const base = project && project !== 'default'
10
+ ? `/projects/${encodeURIComponent(project)}/incidents`
11
+ : '/incidents'
12
+ return proxyGet(
13
+ `${CORE_URL}${base}?limit=${limit}`,
14
+ () => Response.json(FIXTURE_INCIDENTS),
15
+ )
16
+ }
@@ -0,0 +1,11 @@
1
+ import { CORE_URL, proxyGet } from '../../../../lib/proxy'
2
+ import { FIXTURE_VIOLATIONS } from '../../../../lib/fixtures'
3
+
4
+ // ADR-057 #5 — policies are evaluated per project per ADR-043.
5
+ export async function GET(request: Request): Promise<Response> {
6
+ const project = new URL(request.url).searchParams.get('project') ?? ''
7
+ const path = project && project !== 'default'
8
+ ? `/projects/${encodeURIComponent(project)}/policies/violations`
9
+ : '/policies/violations'
10
+ return proxyGet(`${CORE_URL}${path}`, () => Response.json(FIXTURE_VIOLATIONS))
11
+ }
@@ -0,0 +1,11 @@
1
+ import { CORE_URL, proxyGet } from '../../../lib/proxy'
2
+ import { FIXTURE_PROJECTS } from '../../../lib/fixtures'
3
+
4
+ // ADR-051 — registry endpoint. The list itself is not project-scoped (it's the
5
+ // list of projects), but we still accept the query param so the route surface
6
+ // is uniform with the rest of the proxy (ADR-057 #5).
7
+ export async function GET(request: Request): Promise<Response> {
8
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
9
+ const project = new URL(request.url).searchParams.get('project')
10
+ return proxyGet(`${CORE_URL}/projects`, () => Response.json(FIXTURE_PROJECTS))
11
+ }
@@ -0,0 +1,17 @@
1
+ import { CORE_URL, proxyGet } from '../../../lib/proxy'
2
+ import { fixtureSearch } from '../../../lib/fixtures'
3
+
4
+ // ADR-057 #5 — search forwards `project` so results are scoped to the active
5
+ // graph instead of the daemon's default.
6
+ export async function GET(request: Request): Promise<Response> {
7
+ const { searchParams } = new URL(request.url)
8
+ const q = searchParams.get('q') ?? ''
9
+ const project = searchParams.get('project') ?? ''
10
+ const base = project && project !== 'default'
11
+ ? `/projects/${encodeURIComponent(project)}/search`
12
+ : '/search'
13
+ return proxyGet(
14
+ `${CORE_URL}${base}?q=${encodeURIComponent(q)}`,
15
+ () => Response.json(fixtureSearch(q)),
16
+ )
17
+ }
@@ -0,0 +1,15 @@
1
+ import { CORE_URL, proxyGet } from '../../../lib/proxy'
2
+
3
+ // ADR-057 #5 — stale-events stream is project-scoped per ADR-024 + ADR-026.
4
+ export async function GET(request: Request): Promise<Response> {
5
+ const { searchParams } = new URL(request.url)
6
+ const limit = searchParams.get('limit') ?? '50'
7
+ const project = searchParams.get('project') ?? ''
8
+ const base = project && project !== 'default'
9
+ ? `/projects/${encodeURIComponent(project)}/stale-events`
10
+ : '/stale-events'
11
+ return proxyGet(
12
+ `${CORE_URL}${base}?limit=${limit}`,
13
+ () => Response.json({ events: [], count: 0, total: 0 }),
14
+ )
15
+ }