@uptimizr/collector-server 0.6.0 → 0.6.2
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.
- package/README.md +56 -19
- package/package.json +10 -10
package/README.md
CHANGED
|
@@ -79,9 +79,10 @@ file; back up by copying the file).
|
|
|
79
79
|
|
|
80
80
|
### Ingestion
|
|
81
81
|
|
|
82
|
-
- `POST /api/v1/collect` — accepts a batched `collectRequest`. Validates →
|
|
83
|
-
|
|
84
|
-
|
|
82
|
+
- `POST /api/v1/collect` — accepts a batched `collectRequest`. Validates → rejects
|
|
83
|
+
mixed-project or unknown-project batches → enriches (server-set cookieless
|
|
84
|
+
`visitorId = hash(ip + ua + dailySalt)`, raw IP never stored) → inserts into the
|
|
85
|
+
configured `CollectorStore` (DuckDB by default) and publishes the live feed.
|
|
85
86
|
|
|
86
87
|
### Query (require `x-api-key`)
|
|
87
88
|
|
|
@@ -89,15 +90,41 @@ Aggregations are computed **at query time** (v1) — including the heatmap/perf
|
|
|
89
90
|
aggregates, which run directly in the OSS DuckDB store. Every route is scoped to
|
|
90
91
|
the project the API key resolves to.
|
|
91
92
|
|
|
92
|
-
- `GET /api/v1/sessions`
|
|
93
|
-
|
|
94
|
-
- `GET /api/v1/heatmaps/camera`
|
|
95
|
-
|
|
96
|
-
|
|
93
|
+
- Sessions: `GET /api/v1/sessions`, `GET /api/v1/sessions/:id/meta`,
|
|
94
|
+
`GET /api/v1/sessions/:id/trajectory`.
|
|
95
|
+
- Heatmaps: `GET /api/v1/heatmaps/pointer`, `/camera`, `/position`, `/world`
|
|
96
|
+
(+ `/world/stats`), `/gaze` (+ `/gaze/stats`), `/mesh-uv`, `/click-rays`,
|
|
97
|
+
`/flow`, `/perf`, `/errors`.
|
|
98
|
+
- Mesh / interaction insights: `GET /api/v1/meshes/top`, `/sources`, `/trend`,
|
|
99
|
+
`/dwell`, `/blind-spots`, `/kinds`, `/reachability`, plus `/clicks/dead`,
|
|
100
|
+
`/clicks/rage`, `/hover/dwell`, `/camera-gestures`, `/interactions/sources`,
|
|
101
|
+
`/input-actions/top`.
|
|
102
|
+
- Performance / diagnostics: `GET /api/v1/perf`, `/perf/compile-stalls`,
|
|
103
|
+
`/perf/render-scale`, `/perf/resources`, `/perf/distribution`,
|
|
104
|
+
`/perf/fps-histogram`, `/perf/frame-time`, `/perf/jank`, `/perf/churn`,
|
|
105
|
+
`/perf/by-device`, `/perf/by-scene`, `/perf/resource-percentiles`,
|
|
106
|
+
`/perf/stability`, `/graphics-diagnostics`, `/rendering-technology`,
|
|
107
|
+
`/capabilities`.
|
|
108
|
+
- Scene / path / funnel analytics: `GET /api/v1/scenes`, `/scene-representations`,
|
|
109
|
+
`/timeseries`, `/event-counts`, `/coverage`, `/coverage/view-histogram`,
|
|
110
|
+
`/paths`, `/camera/distance`, `/navigation`, `/backtrack`, `/funnel`,
|
|
111
|
+
`/scene-retention`, `/load-bounce`, `/variant-leaderboard`, `/xr/rotation`,
|
|
112
|
+
`/xr/sources`, `/xr/abandonment`, `/xr/locomotion`.
|
|
113
|
+
- Scene representations: `PUT /api/v1/scenes/:sceneId/representation`,
|
|
114
|
+
`GET /api/v1/scenes/:sceneId/representation`.
|
|
97
115
|
- `GET /api/v1/sessions/:id/events` — ordered replay timeline, **gated by**
|
|
98
|
-
`ENABLE_RAW_SESSION_RETENTION` (returns `403` when disabled)
|
|
116
|
+
`ENABLE_RAW_SESSION_RETENTION` (returns `403` when disabled); supports buffered
|
|
117
|
+
JSON or NDJSON streaming (`Accept: application/x-ndjson` / `?format=ndjson`).
|
|
99
118
|
|
|
100
|
-
|
|
119
|
+
Live endpoints:
|
|
120
|
+
|
|
121
|
+
- `POST /api/v1/live/token` — exchange a query API key for a short-lived live token.
|
|
122
|
+
- `GET /api/v1/live/presence`, `/live/stream`, `/live/sessions/:id` — SSE streams
|
|
123
|
+
authenticated with `?token=...`; per-session live follow is also gated by raw
|
|
124
|
+
retention.
|
|
125
|
+
|
|
126
|
+
Common query params include `since`, `until` (epoch ms), `bins`, `limit`, `scene`,
|
|
127
|
+
`session`, `cameraMode`, `source`, and spatial `cellSize` / `region` where supported.
|
|
101
128
|
|
|
102
129
|
- `GET /health` — liveness probe.
|
|
103
130
|
|
|
@@ -109,11 +136,13 @@ if `VISITOR_HASH_SECRET` is missing.
|
|
|
109
136
|
|
|
110
137
|
### Authentication: which endpoints need a key
|
|
111
138
|
|
|
112
|
-
| Endpoint group
|
|
113
|
-
|
|
|
114
|
-
| `POST /api/v1/collect`
|
|
115
|
-
|
|
|
116
|
-
| `
|
|
139
|
+
| Endpoint group | Auth | Why |
|
|
140
|
+
| ----------------------------------------- | ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
141
|
+
| `POST /api/v1/collect` | **None (keyless)** | Runs in untrusted browsers; a key shipped to the client is not a secret. Ingestion is open by design and protected by validation + rate limits instead. |
|
|
142
|
+
| Query/read routes | `x-api-key` | Read access is scoped to the project the key resolves to. |
|
|
143
|
+
| `POST /api/v1/live/token` | `x-api-key` | Exchanges a project query key for a short-lived SSE token. |
|
|
144
|
+
| Live SSE routes (`/api/v1/live/*` `GET`s) | `?token=...` | Browser `EventSource` cannot attach custom headers, so live streams use short-lived bearer tokens. |
|
|
145
|
+
| `GET /health` | None | Liveness probe. |
|
|
117
146
|
|
|
118
147
|
### Threat model for keyless ingestion
|
|
119
148
|
|
|
@@ -135,10 +164,18 @@ Because `POST /api/v1/collect` accepts unauthenticated input, every request is t
|
|
|
135
164
|
|
|
136
165
|
## Configuration
|
|
137
166
|
|
|
138
|
-
Environment-driven (see [`.env.example`](../../../.env.example)):
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
167
|
+
Environment-driven (see [`.env.example`](../../../.env.example)):
|
|
168
|
+
|
|
169
|
+
- Server / browser access: `COLLECTOR_HOST` (default `0.0.0.0`), `COLLECTOR_PORT`
|
|
170
|
+
(default `4318`), `COLLECTOR_CORS_ORIGINS`, `COLLECTOR_TRUST_PROXY`,
|
|
171
|
+
`COLLECTOR_BODY_LIMIT`.
|
|
172
|
+
- Privacy / replay / live: `VISITOR_HASH_SECRET` (required),
|
|
173
|
+
`ENABLE_RAW_SESSION_RETENTION`, `LIVE_TOKEN_SECRET`, `LIVE_TOKEN_TTL_MS`,
|
|
174
|
+
`LIVE_WINDOW_MS`, `LIVE_MAX_CONNECTIONS`, `LIVE_PRESENCE_INTERVAL_MS`.
|
|
175
|
+
- Rate limits: `COLLECTOR_RATE_LIMIT_MAX`, `COLLECTOR_RATE_LIMIT_WINDOW_MS`,
|
|
176
|
+
`COLLECTOR_INGEST_RATE_LIMIT_MAX`, `COLLECTOR_INGEST_RATE_LIMIT_WINDOW_MS`.
|
|
177
|
+
- All-in-one dashboard: `COLLECTOR_DASHBOARD_DIR` (optional; see
|
|
178
|
+
[above](#all-in-one-serve-the-dashboard-too)), `COLLECTOR_CSP` (`strict` or `off`).
|
|
142
179
|
|
|
143
180
|
The storage backend is chosen with `COLLECTOR_STORE`:
|
|
144
181
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uptimizr/collector-server",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.2",
|
|
4
4
|
"description": "Uptimizr ingestion + query API (Fastify). Self-hostable collector for the OSS data-collector.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"uptimizr",
|
|
@@ -41,18 +41,18 @@
|
|
|
41
41
|
"@fastify/cors": "^11.2.0",
|
|
42
42
|
"@fastify/helmet": "^13.0.2",
|
|
43
43
|
"@fastify/rate-limit": "^11.1.0",
|
|
44
|
-
"@fastify/static": "^9.1.
|
|
45
|
-
"fastify": "^5.
|
|
44
|
+
"@fastify/static": "^9.1.3",
|
|
45
|
+
"fastify": "^5.10.0",
|
|
46
46
|
"fastify-type-provider-zod": "^7.0.0",
|
|
47
|
-
"zod": "^4.
|
|
48
|
-
"@uptimizr/
|
|
49
|
-
"@uptimizr/db
|
|
50
|
-
"@uptimizr/
|
|
47
|
+
"zod": "^4.4.3",
|
|
48
|
+
"@uptimizr/schema": "0.5.1",
|
|
49
|
+
"@uptimizr/db": "0.7.2",
|
|
50
|
+
"@uptimizr/db-clickhouse": "0.3.4"
|
|
51
51
|
},
|
|
52
52
|
"devDependencies": {
|
|
53
|
-
"@types/node": "^26.0
|
|
54
|
-
"tsx": "^4.
|
|
55
|
-
"vitest": "^4.1.
|
|
53
|
+
"@types/node": "^26.1.0",
|
|
54
|
+
"tsx": "^4.23.0",
|
|
55
|
+
"vitest": "^4.1.10"
|
|
56
56
|
},
|
|
57
57
|
"scripts": {
|
|
58
58
|
"build": "tsc -p tsconfig.json",
|