@uptimizr/collector-server 0.1.0

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.
Files changed (67) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +169 -0
  3. package/dist/app.d.ts +22 -0
  4. package/dist/app.d.ts.map +1 -0
  5. package/dist/app.js +96 -0
  6. package/dist/app.js.map +1 -0
  7. package/dist/cli.d.ts +3 -0
  8. package/dist/cli.d.ts.map +1 -0
  9. package/dist/cli.js +148 -0
  10. package/dist/cli.js.map +1 -0
  11. package/dist/config.d.ts +59 -0
  12. package/dist/config.d.ts.map +1 -0
  13. package/dist/config.js +55 -0
  14. package/dist/config.js.map +1 -0
  15. package/dist/csp.d.ts +18 -0
  16. package/dist/csp.d.ts.map +1 -0
  17. package/dist/csp.js +91 -0
  18. package/dist/csp.js.map +1 -0
  19. package/dist/duckdbStore.d.ts +14 -0
  20. package/dist/duckdbStore.d.ts.map +1 -0
  21. package/dist/duckdbStore.js +69 -0
  22. package/dist/duckdbStore.js.map +1 -0
  23. package/dist/enrich.d.ts +8 -0
  24. package/dist/enrich.d.ts.map +1 -0
  25. package/dist/enrich.js +9 -0
  26. package/dist/enrich.js.map +1 -0
  27. package/dist/liveBus.d.ts +86 -0
  28. package/dist/liveBus.d.ts.map +1 -0
  29. package/dist/liveBus.js +195 -0
  30. package/dist/liveBus.js.map +1 -0
  31. package/dist/liveToken.d.ts +11 -0
  32. package/dist/liveToken.d.ts.map +1 -0
  33. package/dist/liveToken.js +44 -0
  34. package/dist/liveToken.js.map +1 -0
  35. package/dist/memoryStore.d.ts +22 -0
  36. package/dist/memoryStore.d.ts.map +1 -0
  37. package/dist/memoryStore.js +207 -0
  38. package/dist/memoryStore.js.map +1 -0
  39. package/dist/routes/collect.d.ts +25 -0
  40. package/dist/routes/collect.d.ts.map +1 -0
  41. package/dist/routes/collect.js +55 -0
  42. package/dist/routes/collect.js.map +1 -0
  43. package/dist/routes/live.d.ts +18 -0
  44. package/dist/routes/live.d.ts.map +1 -0
  45. package/dist/routes/live.js +179 -0
  46. package/dist/routes/live.js.map +1 -0
  47. package/dist/routes/query.d.ts +14 -0
  48. package/dist/routes/query.d.ts.map +1 -0
  49. package/dist/routes/query.js +610 -0
  50. package/dist/routes/query.js.map +1 -0
  51. package/dist/serve.d.ts +18 -0
  52. package/dist/serve.d.ts.map +1 -0
  53. package/dist/serve.js +48 -0
  54. package/dist/serve.js.map +1 -0
  55. package/dist/server.d.ts +3 -0
  56. package/dist/server.d.ts.map +1 -0
  57. package/dist/server.js +12 -0
  58. package/dist/server.js.map +1 -0
  59. package/dist/store.d.ts +263 -0
  60. package/dist/store.d.ts.map +1 -0
  61. package/dist/store.js +2 -0
  62. package/dist/store.js.map +1 -0
  63. package/dist/visitor.d.ts +12 -0
  64. package/dist/visitor.d.ts.map +1 -0
  65. package/dist/visitor.js +18 -0
  66. package/dist/visitor.js.map +1 -0
  67. package/package.json +64 -0
@@ -0,0 +1,179 @@
1
+ import { z } from "zod";
2
+ import { mintLiveToken, verifyLiveToken } from "../liveToken.js";
3
+ const HEARTBEAT_MS = 15_000;
4
+ const tokenQuery = z.object({ token: z.string().min(1).optional() });
5
+ const streamQuery = tokenQuery.extend({
6
+ /** Optional comma-separated event-type allow-list for the firehose. */
7
+ types: z.string().max(512).optional(),
8
+ });
9
+ /**
10
+ * Resolve the project for a live SSE request from a `?token=` (ADR 0032 §7).
11
+ * Sends a 401 and returns `null` when the token is missing/invalid/expired.
12
+ */
13
+ function authLiveToken(request, reply, config) {
14
+ const token = request.query.token;
15
+ if (!token) {
16
+ void reply.code(401).send({ error: "missing live token" });
17
+ return null;
18
+ }
19
+ const projectId = verifyLiveToken(token, config.liveTokenSecret);
20
+ if (!projectId) {
21
+ void reply.code(401).send({ error: "invalid or expired live token" });
22
+ return null;
23
+ }
24
+ return projectId;
25
+ }
26
+ /**
27
+ * Reflect an allowed request `Origin` for a raw (hijacked) SSE response. The CORS
28
+ * plugin sets `Access-Control-Allow-Origin` via `reply.header`, but SSE bypasses
29
+ * Fastify's send path (`reply.raw.writeHead` + `reply.hijack`), so those headers
30
+ * are never flushed. Without this, a cross-origin `EventSource` (e.g. the
31
+ * dashboard on a different origin than the collector) is blocked by the browser.
32
+ */
33
+ function sseCorsHeaders(request, config) {
34
+ const origin = request.headers.origin;
35
+ if (typeof origin === "string" && config.corsOrigins.includes(origin)) {
36
+ return { "access-control-allow-origin": origin, vary: "Origin" };
37
+ }
38
+ return {};
39
+ }
40
+ /** Open an SSE response on the raw socket. Returns a writer + a teardown hook. */
41
+ function openSse(request, reply, config) {
42
+ reply.raw.writeHead(200, {
43
+ "content-type": "text/event-stream; charset=utf-8",
44
+ "cache-control": "no-cache, no-transform",
45
+ connection: "keep-alive",
46
+ "x-accel-buffering": "no",
47
+ ...sseCorsHeaders(request, config),
48
+ });
49
+ // Defeat proxy buffering and prompt the browser to open the stream.
50
+ reply.raw.write(": connected\n\n");
51
+ reply.hijack();
52
+ const send = (data, event) => {
53
+ if (reply.raw.writableEnded)
54
+ return;
55
+ if (event)
56
+ reply.raw.write(`event: ${event}\n`);
57
+ reply.raw.write(`data: ${data}\n\n`);
58
+ };
59
+ const comment = (text) => {
60
+ if (!reply.raw.writableEnded)
61
+ reply.raw.write(`: ${text}\n\n`);
62
+ };
63
+ void request;
64
+ return { send, comment };
65
+ }
66
+ /**
67
+ * Live SSE endpoints (ADR 0032 §3): presence (aggregate, always on), the
68
+ * project firehose (drives live dashboard updates), and the per-session
69
+ * live-follow tail (gated by raw-session retention, like replay). All fan out
70
+ * from the in-process bus and are bounded (ADR §6).
71
+ */
72
+ export const liveRoutes = async (app, { store, config, liveBus }) => {
73
+ const r = app.withTypeProvider();
74
+ let connections = 0;
75
+ /** Reserve a live connection slot, or send 503 when at capacity (ADR §6). */
76
+ function acquireSlot(reply) {
77
+ if (connections >= config.liveMaxConnections) {
78
+ void reply.code(503).send({ error: "live connection limit reached" });
79
+ return false;
80
+ }
81
+ connections += 1;
82
+ return true;
83
+ }
84
+ // Server-to-server: exchange an API key for a short-lived live token (ADR §7).
85
+ r.post("/api/v1/live/token", async (req, reply) => {
86
+ const key = req.headers["x-api-key"];
87
+ if (typeof key !== "string" || key.length === 0) {
88
+ return reply.code(401).send({ error: "missing api key" });
89
+ }
90
+ const projectId = await store.resolveApiKey(key);
91
+ if (!projectId) {
92
+ return reply.code(401).send({ error: "invalid api key" });
93
+ }
94
+ // The live feed is a read surface — require a `query`-capable key.
95
+ if (projectId.capability !== "query") {
96
+ return reply.code(403).send({ error: "api key not permitted to read" });
97
+ }
98
+ const { token, expiresAt } = mintLiveToken(projectId.projectId, config.liveTokenSecret, config.liveTokenTtlMs);
99
+ return reply.send({ token, expiresAt });
100
+ });
101
+ // Aggregate presence: pushes a snapshot immediately, then on an interval that
102
+ // doubles as the heartbeat. Privacy-safe → not gated by raw retention (ADR §3a).
103
+ r.get("/api/v1/live/presence", { schema: { querystring: tokenQuery } }, (req, reply) => {
104
+ const projectId = authLiveToken(req, reply, config);
105
+ if (!projectId)
106
+ return;
107
+ if (!acquireSlot(reply))
108
+ return;
109
+ const { send } = openSse(req, reply, config);
110
+ const push = () => send(JSON.stringify(liveBus.presence(projectId)), "presence");
111
+ push();
112
+ const timer = setInterval(push, config.livePresenceIntervalMs);
113
+ req.raw.on("close", () => {
114
+ clearInterval(timer);
115
+ connections -= 1;
116
+ });
117
+ });
118
+ // Project firehose: every arriving event (optionally filtered by type). Drives
119
+ // the dashboard's in-place panel/feed updates (ADR §3). Payloads carry no more
120
+ // than the aggregate read API already exposes unless raw retention is on.
121
+ r.get("/api/v1/live/stream", { schema: { querystring: streamQuery } }, (req, reply) => {
122
+ const projectId = authLiveToken(req, reply, config);
123
+ if (!projectId)
124
+ return;
125
+ if (!acquireSlot(reply))
126
+ return;
127
+ const types = req.query.types
128
+ ? new Set(req.query.types
129
+ .split(",")
130
+ .map((t) => t.trim())
131
+ .filter(Boolean))
132
+ : undefined;
133
+ const { send, comment } = openSse(req, reply, config);
134
+ const sub = liveBus.subscribe({ projectId, types });
135
+ const heartbeat = setInterval(() => comment("ping"), HEARTBEAT_MS);
136
+ const pump = async () => {
137
+ for await (const event of sub)
138
+ send(JSON.stringify(event), "event");
139
+ };
140
+ void pump();
141
+ req.raw.on("close", () => {
142
+ clearInterval(heartbeat);
143
+ sub.close();
144
+ connections -= 1;
145
+ });
146
+ });
147
+ // Per-session live-follow tail for live replay. Gated by raw-session retention,
148
+ // identical to historical replay (ADR 0003/0006). Sends connect-time backfill
149
+ // from the bounded ring, then live events.
150
+ r.get("/api/v1/live/sessions/:id", { schema: { params: z.object({ id: z.string().min(1).max(128) }), querystring: tokenQuery } }, (req, reply) => {
151
+ const projectId = authLiveToken(req, reply, config);
152
+ if (!projectId)
153
+ return;
154
+ if (!config.enableRawSessionRetention) {
155
+ void reply.code(403).send({ error: "raw session retention is disabled" });
156
+ return;
157
+ }
158
+ if (!acquireSlot(reply))
159
+ return;
160
+ const sessionId = req.params.id;
161
+ const { send, comment } = openSse(req, reply, config);
162
+ const sub = liveBus.subscribe({ projectId, sessionId });
163
+ for (const event of liveBus.recentForSession(projectId, sessionId)) {
164
+ send(JSON.stringify(event), "event");
165
+ }
166
+ const heartbeat = setInterval(() => comment("ping"), HEARTBEAT_MS);
167
+ const pump = async () => {
168
+ for await (const event of sub)
169
+ send(JSON.stringify(event), "event");
170
+ };
171
+ void pump();
172
+ req.raw.on("close", () => {
173
+ clearInterval(heartbeat);
174
+ sub.close();
175
+ connections -= 1;
176
+ });
177
+ });
178
+ };
179
+ //# sourceMappingURL=live.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"live.js","sourceRoot":"","sources":["../../src/routes/live.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ import type { FastifyPluginAsync } from "fastify";
2
+ import type { CollectorConfig } from "../config.js";
3
+ import type { CollectorStore } from "../store.js";
4
+ interface Options {
5
+ store: CollectorStore;
6
+ config: CollectorConfig;
7
+ }
8
+ /**
9
+ * Query API. All aggregations are computed at query time (v1). Every route is
10
+ * scoped to the authenticated project.
11
+ */
12
+ export declare const queryRoutes: FastifyPluginAsync<Options>;
13
+ export {};
14
+ //# sourceMappingURL=query.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"query.d.ts","sourceRoot":"","sources":["../../src/routes/query.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAgC,MAAM,SAAS,CAAC;AAKhF,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AACpD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElD,UAAU,OAAO;IACf,KAAK,EAAE,cAAc,CAAC;IACtB,MAAM,EAAE,eAAe,CAAC;CACzB;AAgQD;;;GAGG;AACH,eAAO,MAAM,WAAW,EAAE,kBAAkB,CAAC,OAAO,CA2hBnD,CAAC"}