@obsunified/collector 2.0.1

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 (254) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +60 -0
  3. package/dist/auth.d.ts +2 -0
  4. package/dist/auth.js +9 -0
  5. package/dist/auth.js.map +1 -0
  6. package/dist/chunk-UGWDOGGH.js +319 -0
  7. package/dist/chunk-UGWDOGGH.js.map +1 -0
  8. package/dist/chunk-XKQTVIRE.js +671 -0
  9. package/dist/chunk-XKQTVIRE.js.map +1 -0
  10. package/dist/index.d.ts +1197 -0
  11. package/dist/index.js +17707 -0
  12. package/dist/index.js.map +1 -0
  13. package/dist/ingest-auth-HFVO1zIp.d.ts +165 -0
  14. package/dist/openai-FJYOQ7WO.js +384 -0
  15. package/dist/openai-FJYOQ7WO.js.map +1 -0
  16. package/package.json +73 -0
  17. package/src/ai-parity/ai-parity.acceptance.test.ts +449 -0
  18. package/src/analyses/derive.ts +642 -0
  19. package/src/analyses/index.ts +50 -0
  20. package/src/analyses/investigations.ts +277 -0
  21. package/src/analyses/tier0.ts +568 -0
  22. package/src/auth/dashboard-auth.ts +269 -0
  23. package/src/auth/ingest-auth.ts +147 -0
  24. package/src/durable-objects/tail-hub.test.ts +32 -0
  25. package/src/durable-objects/tail-hub.ts +158 -0
  26. package/src/framework/collector.ts +467 -0
  27. package/src/framework/env.ts +90 -0
  28. package/src/framework/logger.ts +81 -0
  29. package/src/index.ts +211 -0
  30. package/src/lib/action-aggregates.ts +1031 -0
  31. package/src/lib/action-identity.ts +106 -0
  32. package/src/lib/actions-store.ts +397 -0
  33. package/src/lib/ai-pricing.ts +80 -0
  34. package/src/lib/ai-store/calls.ts +148 -0
  35. package/src/lib/ai-store/evaluations.test.ts +47 -0
  36. package/src/lib/ai-store/evaluations.ts +125 -0
  37. package/src/lib/ai-store/helpers.ts +37 -0
  38. package/src/lib/ai-store/retention.ts +17 -0
  39. package/src/lib/ai-store/sessions.ts +277 -0
  40. package/src/lib/ai-store/spans.ts +109 -0
  41. package/src/lib/ai-store/types.ts +112 -0
  42. package/src/lib/ai-store.ts +76 -0
  43. package/src/lib/alerts-store.ts +458 -0
  44. package/src/lib/analyses-runner.ts +439 -0
  45. package/src/lib/analyses-store.test.ts +243 -0
  46. package/src/lib/analyses-store.ts +454 -0
  47. package/src/lib/ask.test.ts +302 -0
  48. package/src/lib/ask.ts +390 -0
  49. package/src/lib/blob-store-s3.ts +213 -0
  50. package/src/lib/blob-store.ts +366 -0
  51. package/src/lib/eval-cases-store.test.ts +171 -0
  52. package/src/lib/eval-cases-store.ts +1033 -0
  53. package/src/lib/evidence-references.test.ts +10 -0
  54. package/src/lib/evidence-references.ts +684 -0
  55. package/src/lib/hash.ts +26 -0
  56. package/src/lib/identity-index/action-lookups.ts +805 -0
  57. package/src/lib/identity-index/constants.ts +1 -0
  58. package/src/lib/identity-index/key-lookups.ts +199 -0
  59. package/src/lib/identity-index/mappers.ts +349 -0
  60. package/src/lib/identity-index/types.ts +196 -0
  61. package/src/lib/identity-index/user-lookup.ts +137 -0
  62. package/src/lib/identity-index.test.ts +624 -0
  63. package/src/lib/identity-index.ts +85 -0
  64. package/src/lib/json.ts +39 -0
  65. package/src/lib/llm.ts +263 -0
  66. package/src/lib/logs-store.ts +188 -0
  67. package/src/lib/metrics-store.test.ts +189 -0
  68. package/src/lib/metrics-store.ts +312 -0
  69. package/src/lib/narrate-gate.test.ts +260 -0
  70. package/src/lib/narrate-gate.ts +253 -0
  71. package/src/lib/openai.test.ts +300 -0
  72. package/src/lib/openai.ts +512 -0
  73. package/src/lib/otlp.ts +212 -0
  74. package/src/lib/parse-pprof.test.ts +64 -0
  75. package/src/lib/parse-pprof.ts +184 -0
  76. package/src/lib/payload-capture.ts +22 -0
  77. package/src/lib/projects-store.ts +207 -0
  78. package/src/lib/propagation-metric.test.ts +196 -0
  79. package/src/lib/propagation-metric.ts +175 -0
  80. package/src/lib/sql-db-dialect.test.ts +22 -0
  81. package/src/lib/sql-db-postgres.ts +229 -0
  82. package/src/lib/sql-db.ts +166 -0
  83. package/src/lib/stage6.test.ts +216 -0
  84. package/src/lib/store/export.ts +65 -0
  85. package/src/lib/store/helpers.ts +367 -0
  86. package/src/lib/store/ingest.ts +68 -0
  87. package/src/lib/store/issues.ts +158 -0
  88. package/src/lib/store/overview.ts +127 -0
  89. package/src/lib/store/retention.ts +10 -0
  90. package/src/lib/store/service-map.ts +384 -0
  91. package/src/lib/store/trace-detail.bench.ts +76 -0
  92. package/src/lib/store/trace-detail.test.ts +410 -0
  93. package/src/lib/store/trace-detail.ts +427 -0
  94. package/src/lib/store/trace-queries.test.ts +29 -0
  95. package/src/lib/store/trace-queries.ts +89 -0
  96. package/src/lib/store-overview.test.ts +77 -0
  97. package/src/lib/store.ts +96 -0
  98. package/src/lib/tail-publisher.ts +64 -0
  99. package/src/lib/test-utils/mem-sql-db.test.ts +93 -0
  100. package/src/lib/test-utils/mem-sql-db.ts +86 -0
  101. package/src/lib/ua-parser.ts +61 -0
  102. package/src/lib/usage-store.ts +567 -0
  103. package/src/migrations/001_telemetry_spans.sql +28 -0
  104. package/src/migrations/002_usage_events.sql +24 -0
  105. package/src/migrations/003_usage_analytics_columns.sql +13 -0
  106. package/src/migrations/004_logs.sql +19 -0
  107. package/src/migrations/005_ai_calls.sql +25 -0
  108. package/src/migrations/006_user_profiles.sql +11 -0
  109. package/src/migrations/007_session_replay_metadata.sql +10 -0
  110. package/src/migrations/008_session_replay_storage_bytes.sql +1 -0
  111. package/src/migrations/009_projects_and_keys.sql +22 -0
  112. package/src/migrations/010_signal_project_id.sql +15 -0
  113. package/src/migrations/011_default_project_seed.sql +3 -0
  114. package/src/migrations/012_alert_rules.sql +17 -0
  115. package/src/migrations/013_alert_evaluations.sql +13 -0
  116. package/src/migrations/014_alert_state.sql +9 -0
  117. package/src/migrations/015_metrics.sql +58 -0
  118. package/src/migrations/016_metrics_exp_histogram_summary.sql +5 -0
  119. package/src/migrations/017_span_dropped_counts.sql +11 -0
  120. package/src/migrations/018_log_flags.sql +8 -0
  121. package/src/migrations/019_ai_span_payloads.sql +30 -0
  122. package/src/migrations/020_ai_span_evaluations.sql +33 -0
  123. package/src/migrations/021_ai_span_session.sql +13 -0
  124. package/src/migrations/022_span_log_session_id.sql +13 -0
  125. package/src/migrations/023_service_map_indexes.sql +32 -0
  126. package/src/migrations/024_analysis_results.sql +49 -0
  127. package/src/migrations/025_stage6_autopinning_alerts.sql +38 -0
  128. package/src/migrations/026_obs_dashboard_project_seed.sql +18 -0
  129. package/src/migrations/027_identity_propagation.sql +50 -0
  130. package/src/migrations/028_profile_blobs.sql +57 -0
  131. package/src/migrations/029_telemetry_sdk_name.sql +20 -0
  132. package/src/migrations/030_analysis_claim.sql +18 -0
  133. package/src/migrations/031_agent_action_graph.sql +154 -0
  134. package/src/migrations/032_payload_capture_flags.sql +8 -0
  135. package/src/migrations/033_eval_cases.sql +52 -0
  136. package/src/migrations/034_eval_case_results.sql +23 -0
  137. package/src/migrations/035_metric_exemplars.sql +33 -0
  138. package/src/migrations/036_trace_instrumentation_gaps.sql +19 -0
  139. package/src/migrations/037_eval_runs.sql +37 -0
  140. package/src/migrations/038_tool_call_evidence.sql +11 -0
  141. package/src/migrations/039_drop_trace_instrumentation_gaps.sql +11 -0
  142. package/src/migrations/040_evidence_retrieval_refs.sql +50 -0
  143. package/src/migrations-postgres/001_telemetry_spans.sql +33 -0
  144. package/src/migrations-postgres/002_usage_events.sql +24 -0
  145. package/src/migrations-postgres/003_usage_analytics_columns.sql +13 -0
  146. package/src/migrations-postgres/004_logs.sql +19 -0
  147. package/src/migrations-postgres/005_ai_calls.sql +25 -0
  148. package/src/migrations-postgres/006_user_profiles.sql +11 -0
  149. package/src/migrations-postgres/007_session_replay_metadata.sql +10 -0
  150. package/src/migrations-postgres/008_session_replay_storage_bytes.sql +2 -0
  151. package/src/migrations-postgres/009_projects_and_keys.sql +25 -0
  152. package/src/migrations-postgres/010_signal_project_id.sql +18 -0
  153. package/src/migrations-postgres/011_default_project_seed.sql +5 -0
  154. package/src/migrations-postgres/012_alert_rules.sql +17 -0
  155. package/src/migrations-postgres/013_alert_evaluations.sql +13 -0
  156. package/src/migrations-postgres/014_alert_state.sql +9 -0
  157. package/src/migrations-postgres/015_metrics.sql +47 -0
  158. package/src/migrations-postgres/016_metrics_exp_histogram_summary.sql +1 -0
  159. package/src/migrations-postgres/017_span_dropped_counts.sql +4 -0
  160. package/src/migrations-postgres/018_log_flags.sql +2 -0
  161. package/src/migrations-postgres/019_ai_span_payloads.sql +18 -0
  162. package/src/migrations-postgres/020_ai_span_evaluations.sql +21 -0
  163. package/src/migrations-postgres/021_ai_span_session.sql +7 -0
  164. package/src/migrations-postgres/022_span_log_session_id.sql +7 -0
  165. package/src/migrations-postgres/023_service_map_indexes.sql +9 -0
  166. package/src/migrations-postgres/024_analysis_results.sql +41 -0
  167. package/src/migrations-postgres/025_stage6_autopinning_alerts.sql +17 -0
  168. package/src/migrations-postgres/026_obs_dashboard_project_seed.sql +14 -0
  169. package/src/migrations-postgres/027_identity_propagation.sql +27 -0
  170. package/src/migrations-postgres/028_profile_blobs.sql +48 -0
  171. package/src/migrations-postgres/029_telemetry_sdk_name.sql +5 -0
  172. package/src/migrations-postgres/030_analysis_claim.sql +5 -0
  173. package/src/migrations-postgres/031_agent_action_graph.sql +190 -0
  174. package/src/migrations-postgres/032_payload_capture_flags.sql +8 -0
  175. package/src/migrations-postgres/033_eval_cases.sql +55 -0
  176. package/src/migrations-postgres/034_eval_case_results.sql +26 -0
  177. package/src/migrations-postgres/035_metric_exemplars.sql +31 -0
  178. package/src/migrations-postgres/036_trace_instrumentation_gaps.sql +19 -0
  179. package/src/migrations-postgres/037_eval_runs.sql +40 -0
  180. package/src/migrations-postgres/038_tool_call_evidence.sql +11 -0
  181. package/src/migrations-postgres/039_drop_trace_instrumentation_gaps.sql +11 -0
  182. package/src/migrations-postgres/040_evidence_retrieval_refs.sql +47 -0
  183. package/src/migrations-postgres/README.md +40 -0
  184. package/src/otlp/acceptance.test.ts +373 -0
  185. package/src/otlp/decode/body.ts +127 -0
  186. package/src/otlp/decode/logs.ts +96 -0
  187. package/src/otlp/decode/metrics.ts +402 -0
  188. package/src/otlp/decode/traces.ts +92 -0
  189. package/src/otlp/decode/values.ts +150 -0
  190. package/src/otlp/decode.test.ts +800 -0
  191. package/src/otlp/decode.ts +11 -0
  192. package/src/otlp/gen/opentelemetry/proto/collector/logs/v1/logs_service_pb.ts +132 -0
  193. package/src/otlp/gen/opentelemetry/proto/collector/metrics/v1/metrics_service_pb.ts +158 -0
  194. package/src/otlp/gen/opentelemetry/proto/collector/trace/v1/trace_service_pb.ts +158 -0
  195. package/src/otlp/gen/opentelemetry/proto/common/v1/common_pb.ts +289 -0
  196. package/src/otlp/gen/opentelemetry/proto/logs/v1/logs_pb.ts +397 -0
  197. package/src/otlp/gen/opentelemetry/proto/metrics/v1/metrics_pb.ts +1329 -0
  198. package/src/otlp/gen/opentelemetry/proto/resource/v1/resource_pb.ts +86 -0
  199. package/src/otlp/gen/opentelemetry/proto/trace/v1/trace_pb.ts +710 -0
  200. package/src/otlp/response.test.ts +158 -0
  201. package/src/otlp/response.ts +129 -0
  202. package/src/plugins/_context.ts +15 -0
  203. package/src/plugins/action-graph-processor/enrichers.ts +45 -0
  204. package/src/plugins/action-graph-processor/redaction.ts +84 -0
  205. package/src/plugins/action-graph-processor.test.ts +1023 -0
  206. package/src/plugins/action-graph-processor.ts +1172 -0
  207. package/src/plugins/action-routes.test.ts +716 -0
  208. package/src/plugins/action-routes.ts +343 -0
  209. package/src/plugins/ai-receiver.ts +254 -0
  210. package/src/plugins/ai-span-payloads-processor.test.ts +90 -0
  211. package/src/plugins/ai-span-payloads-processor.ts +180 -0
  212. package/src/plugins/alerts-evaluator.test.ts +91 -0
  213. package/src/plugins/alerts-evaluator.ts +328 -0
  214. package/src/plugins/alerts-routes.ts +101 -0
  215. package/src/plugins/analyses-routes.ts +138 -0
  216. package/src/plugins/ask-routes.ts +182 -0
  217. package/src/plugins/bot-filter.ts +19 -0
  218. package/src/plugins/connected-routes/manifest.ts +531 -0
  219. package/src/plugins/connected-routes.test.ts +1791 -0
  220. package/src/plugins/connected-routes.ts +1103 -0
  221. package/src/plugins/dashboard-routes.ts +41 -0
  222. package/src/plugins/default-span-enrichment.ts +92 -0
  223. package/src/plugins/eval-cases-routes.test.ts +391 -0
  224. package/src/plugins/eval-cases-routes.ts +529 -0
  225. package/src/plugins/evidence-retrieval-routes.benchmark.test.ts +245 -0
  226. package/src/plugins/evidence-retrieval-routes.test.ts +932 -0
  227. package/src/plugins/evidence-retrieval-routes.ts +2179 -0
  228. package/src/plugins/gen-ai-normalizer.test.ts +680 -0
  229. package/src/plugins/gen-ai-normalizer.ts +302 -0
  230. package/src/plugins/identity-receiver.ts +96 -0
  231. package/src/plugins/issue-enrichment.ts +132 -0
  232. package/src/plugins/issue-insights.ts +81 -0
  233. package/src/plugins/logs-receiver.ts +160 -0
  234. package/src/plugins/metrics-receiver.ts +91 -0
  235. package/src/plugins/onboarding-routes.ts +54 -0
  236. package/src/plugins/otlp-receiver.ts +124 -0
  237. package/src/plugins/platform-routes.ts +165 -0
  238. package/src/plugins/profile-routes.ts +468 -0
  239. package/src/plugins/projects-routes.ts +92 -0
  240. package/src/plugins/query-routes.ts +220 -0
  241. package/src/plugins/redaction-processor.ts +132 -0
  242. package/src/plugins/replay-query-routes.test.ts +38 -0
  243. package/src/plugins/replay-query-routes.ts +199 -0
  244. package/src/plugins/replay-receiver.ts +81 -0
  245. package/src/plugins/tail-routes.test.ts +47 -0
  246. package/src/plugins/tail-routes.ts +42 -0
  247. package/src/plugins/timeline-routes.ts +244 -0
  248. package/src/plugins/ua-enrichment.ts +27 -0
  249. package/src/plugins/usage-normalization.ts +46 -0
  250. package/src/plugins/usage-privacy.ts +55 -0
  251. package/src/plugins/usage-query-routes.ts +102 -0
  252. package/src/plugins/usage-receiver.ts +129 -0
  253. package/src/plugins/users-query-routes.ts +78 -0
  254. package/src/plugins/utm-enrichment.ts +36 -0
@@ -0,0 +1,196 @@
1
+ import type { ActionConfidence } from "@obsunified/types/constants";
2
+
3
+ export type CausalConfidence = ActionConfidence;
4
+
5
+ export interface SpanRef {
6
+ traceId: string;
7
+ spanId: string;
8
+ parentSpanId: string | null;
9
+ serviceName: string | null;
10
+ spanName: string;
11
+ statusCode: number;
12
+ statusMessage: string | null;
13
+ startTime: string;
14
+ durationMs: number;
15
+ interactionId: string | null;
16
+ }
17
+
18
+ export interface LogRef {
19
+ logId: string;
20
+ traceId: string | null;
21
+ spanId: string | null;
22
+ serviceName: string | null;
23
+ loggerName: string | null;
24
+ severity: string;
25
+ message: string;
26
+ occurredAt: string;
27
+ interactionId: string | null;
28
+ }
29
+
30
+ export interface UsageEventRef {
31
+ eventId: string;
32
+ eventType: string;
33
+ eventName: string;
34
+ pagePath: string | null;
35
+ severity: string | null;
36
+ occurredAt: string;
37
+ interactionId: string | null;
38
+ sessionId: string | null;
39
+ }
40
+
41
+ export interface AICallRef {
42
+ callId: string;
43
+ traceId: string | null;
44
+ modelName: string;
45
+ provider: string;
46
+ totalCostUsd: number | null;
47
+ occurredAt: string;
48
+ interactionId: string | null;
49
+ }
50
+
51
+ export interface MetricExemplarRef {
52
+ id: string;
53
+ pointId: string;
54
+ seriesId: string;
55
+ metricName: string;
56
+ serviceName: string | null;
57
+ traceId: string | null;
58
+ spanId: string | null;
59
+ tsNs: string;
60
+ value: number;
61
+ receivedAt: string;
62
+ }
63
+
64
+ export interface ReplayRef {
65
+ sessionId: string;
66
+ firstChunkAt: string;
67
+ lastChunkAt: string;
68
+ chunkCount: number;
69
+ eventsCount: number;
70
+ }
71
+
72
+ export interface ReplayRow {
73
+ session_id: string;
74
+ first_chunk_at: string;
75
+ last_chunk_at: string;
76
+ chunk_count: number;
77
+ events_count: number;
78
+ }
79
+
80
+ export interface EntityManifest {
81
+ spans: SpanRef[];
82
+ logs: LogRef[];
83
+ usageEvents: UsageEventRef[];
84
+ aiCalls: AICallRef[];
85
+ metricExemplars: MetricExemplarRef[];
86
+ replay: ReplayRef | null;
87
+ }
88
+
89
+ export interface ActionRef {
90
+ id: string;
91
+ projectId: string;
92
+ rootActionId: string;
93
+ causedByActionId: string | null;
94
+ actorType: string;
95
+ actorId: string | null;
96
+ actionKind: string;
97
+ name: string | null;
98
+ status: string;
99
+ startedAt: string;
100
+ endedAt: string | null;
101
+ durationMs: number | null;
102
+ traceId: string | null;
103
+ spanId: string | null;
104
+ sessionId: string | null;
105
+ interactionId: string | null;
106
+ userId: string | null;
107
+ agentRunId: string | null;
108
+ stepId: string | null;
109
+ toolCallId: string | null;
110
+ promptVersion: string | null;
111
+ modelName: string | null;
112
+ provider: string | null;
113
+ totalCostUsd: number | null;
114
+ causalConfidence: CausalConfidence;
115
+ attrsJson: string | null;
116
+ }
117
+
118
+ export interface AgentRunRef {
119
+ id: string;
120
+ projectId: string;
121
+ agentId: string;
122
+ agentName: string;
123
+ agentVersion: string;
124
+ goal: string | null;
125
+ outcome: string | null;
126
+ autonomyLevel: string;
127
+ status: string;
128
+ errorMessage: string | null;
129
+ totalCostUsd: number | null;
130
+ totalDurationMs: number | null;
131
+ metadataJson: string | null;
132
+ }
133
+
134
+ export interface ToolCallRef {
135
+ id: string;
136
+ actionId: string;
137
+ projectId: string;
138
+ toolName: string;
139
+ argsHash: string;
140
+ resultHash: string;
141
+ errorType: string | null;
142
+ sideEffect: number;
143
+ approvalState: string | null;
144
+ argsRedacted: string | null;
145
+ resultRedacted: string | null;
146
+ mcpAuditJson: string | null;
147
+ mutationBeforeJson: string | null;
148
+ mutationAfterJson: string | null;
149
+ mutationDiffJson: string | null;
150
+ mutationArtifactId: string | null;
151
+ }
152
+
153
+ export interface RetrievalEventRef {
154
+ id: string;
155
+ actionId: string;
156
+ projectId: string;
157
+ retrieverName: string;
158
+ queryHash: string;
159
+ documentsJson: string | null;
160
+ totalResults: number;
161
+ maxRelevanceScore: number | null;
162
+ durationMs: number | null;
163
+ }
164
+
165
+ export interface EvalResultRef {
166
+ id: string;
167
+ actionId: string;
168
+ projectId: string;
169
+ evaluatorName: string;
170
+ evaluatorVersion: string;
171
+ score: number | null;
172
+ passed: number;
173
+ reasoning: string | null;
174
+ rubricJson: string | null;
175
+ }
176
+
177
+ export interface ArtifactRef {
178
+ id: string;
179
+ actionId: string;
180
+ projectId: string;
181
+ artifactName: string;
182
+ artifactType: string;
183
+ storageRef: string | null;
184
+ sizeBytes: number | null;
185
+ sha256Hash: string | null;
186
+ contentPreview: string | null;
187
+ }
188
+
189
+ export interface EntityManifestExtended extends EntityManifest {
190
+ actions: ActionRef[];
191
+ agentRuns: AgentRunRef[];
192
+ toolCalls: ToolCallRef[];
193
+ retrievalEvents: RetrievalEventRef[];
194
+ evalResults: EvalResultRef[];
195
+ artifacts: ArtifactRef[];
196
+ }
@@ -0,0 +1,137 @@
1
+ import type { SqlDb } from "../sql-db";
2
+ import { FETCH_LIMIT } from "./constants";
3
+ import { mapAi, mapLog, mapSpan, mapUsage } from "./mappers";
4
+ import type { EntityManifest } from "./types";
5
+
6
+ export async function manifestByUser(
7
+ db: SqlDb,
8
+ projectId: string,
9
+ userId: string,
10
+ opts: { limit?: number; sessions?: number } = {},
11
+ ): Promise<EntityManifest> {
12
+ const limit = Math.min(opts.limit ?? 100, FETCH_LIMIT);
13
+ const sessionLimit = Math.max(1, Math.min(opts.sessions ?? 5, 20));
14
+
15
+ // Step 1 — resolve user_id → visitor_id. user_profiles is the only
16
+ // table that owns the user_id ↔ visitor_id binding.
17
+ const profile = await db
18
+ .prepare(`SELECT visitor_id FROM user_profiles WHERE user_id = ? LIMIT 1`)
19
+ .bind(userId)
20
+ .first<{ visitor_id: string }>();
21
+ if (!profile) {
22
+ return {
23
+ spans: [],
24
+ logs: [],
25
+ usageEvents: [],
26
+ aiCalls: [],
27
+ metricExemplars: [],
28
+ replay: null,
29
+ };
30
+ }
31
+
32
+ // Step 2 — recent session_ids for that visitor. Pull from usage_events
33
+ // (the table that always carries visitor_id; ai_span_payloads has
34
+ // user_id directly but only when present in AI traffic).
35
+ const sessions = await db
36
+ .prepare(
37
+ `SELECT DISTINCT session_id, MAX(occurred_at) AS last_at
38
+ FROM usage_events
39
+ WHERE project_id = ? AND visitor_id = ? AND session_id IS NOT NULL
40
+ GROUP BY session_id
41
+ ORDER BY last_at DESC
42
+ LIMIT ?`,
43
+ )
44
+ .bind(projectId, profile.visitor_id, sessionLimit)
45
+ .all<{ session_id: string; last_at: string }>();
46
+ const sessionIds = sessions.results.map((r) => r.session_id);
47
+ if (sessionIds.length === 0) {
48
+ return {
49
+ spans: [],
50
+ logs: [],
51
+ usageEvents: [],
52
+ aiCalls: [],
53
+ metricExemplars: [],
54
+ replay: null,
55
+ };
56
+ }
57
+
58
+ // Step 3 — fan out to each signal table with IN (?, ?, …). D1 caps
59
+ // bound parameters at 100, so the sessionLimit clamp above (≤20)
60
+ // keeps us well under.
61
+ const placeholders = sessionIds.map(() => "?").join(", ");
62
+ const [spans, logs, usage, aiCalls, replay] = await Promise.all([
63
+ db
64
+ .prepare(
65
+ `SELECT trace_id, span_id, parent_span_id, service_name, span_name,
66
+ status_code, status_message, start_time, duration_ms, interaction_id
67
+ FROM telemetry_spans
68
+ WHERE project_id = ? AND session_id IN (${placeholders})
69
+ ORDER BY start_time DESC LIMIT ?`,
70
+ )
71
+ .bind(projectId, ...sessionIds, limit)
72
+ .all<Parameters<typeof mapSpan>[0]>(),
73
+ db
74
+ .prepare(
75
+ `SELECT log_id, trace_id, span_id, service_name, logger_name,
76
+ severity, message, occurred_at, interaction_id, session_id
77
+ FROM logs
78
+ WHERE project_id = ? AND session_id IN (${placeholders})
79
+ ORDER BY occurred_at DESC LIMIT ?`,
80
+ )
81
+ .bind(projectId, ...sessionIds, limit)
82
+ .all<Parameters<typeof mapLog>[0]>(),
83
+ db
84
+ .prepare(
85
+ `SELECT event_id, event_type, event_name, page_path, severity,
86
+ occurred_at, interaction_id, session_id
87
+ FROM usage_events
88
+ WHERE project_id = ? AND session_id IN (${placeholders})
89
+ ORDER BY occurred_at DESC LIMIT ?`,
90
+ )
91
+ .bind(projectId, ...sessionIds, limit)
92
+ .all<Parameters<typeof mapUsage>[0]>(),
93
+ db
94
+ .prepare(
95
+ `SELECT call_id, trace_id, model_name, provider, total_cost_usd,
96
+ occurred_at, interaction_id, session_id
97
+ FROM ai_calls
98
+ WHERE project_id = ? AND session_id IN (${placeholders})
99
+ ORDER BY occurred_at DESC LIMIT ?`,
100
+ )
101
+ .bind(projectId, ...sessionIds, limit)
102
+ .all<Parameters<typeof mapAi>[0]>(),
103
+ // Most recent replay across the user's sessions, if any.
104
+ db
105
+ .prepare(
106
+ `SELECT session_id, first_chunk_at, last_chunk_at, chunk_count, events_count
107
+ FROM session_replay_metadata
108
+ WHERE session_id IN (${placeholders})
109
+ ORDER BY last_chunk_at DESC LIMIT 1`,
110
+ )
111
+ .bind(...sessionIds)
112
+ .first<{
113
+ session_id: string;
114
+ first_chunk_at: string;
115
+ last_chunk_at: string;
116
+ chunk_count: number;
117
+ events_count: number;
118
+ }>(),
119
+ ]);
120
+
121
+ return {
122
+ spans: spans.results.map(mapSpan),
123
+ logs: logs.results.map(mapLog),
124
+ usageEvents: usage.results.map(mapUsage),
125
+ aiCalls: aiCalls.results.map(mapAi),
126
+ metricExemplars: [],
127
+ replay: replay
128
+ ? {
129
+ sessionId: replay.session_id,
130
+ firstChunkAt: replay.first_chunk_at,
131
+ lastChunkAt: replay.last_chunk_at,
132
+ chunkCount: replay.chunk_count,
133
+ eventsCount: replay.events_count,
134
+ }
135
+ : null,
136
+ };
137
+ }