@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,1197 @@
1
+ import * as hono from 'hono';
2
+ import { MiddlewareHandler, Hono } from 'hono';
3
+ import * as hono_types from 'hono/types';
4
+ import * as _obsunified_types from '@obsunified/types';
5
+ import { StoredSpan, TelemetryOverviewOptions, TelemetryOverviewResponse, TelemetryTraceDetailResponse, TelemetryInstrumentationGapsResponse, TelemetryIssueOptions, TelemetryIssueOverviewResponse, TelemetryIssueDetailResponse, UsageEventRecord, UsageOverviewOptions, UsageOverviewResponse, UsageSessionDetailResponse, UsageSessionSummary, AlertRuleInput, AlertRule, AlertStateRow, AlertState, AlertEvaluationsListResponse, AlertComparison, JsonValue, EvidenceReference, EvidenceReferenceContract, Project, IngestKey, IngestKeyWithPlaintext } from '@obsunified/types';
6
+ import { b as CollectorEnv, c as CollectorRouteContext, L as Logger, C as ChildSpanRunner } from './ingest-auth-HFVO1zIp.js';
7
+ export { a as CollectorApp, d as consoleLogger, e as createIngestAuth } from './ingest-auth-HFVO1zIp.js';
8
+ import { ActionConfidence } from '@obsunified/types/constants';
9
+ import { Pool } from 'pg';
10
+
11
+ /**
12
+ * Storage seam for the collector — RFC 0008.
13
+ *
14
+ * Stores and plugins target this interface instead of `D1Database` directly,
15
+ * so a future Node / better-sqlite3 / ClickHouse runtime is one new adapter
16
+ * away rather than a fork-and-rewrite. The shape is deliberately D1's
17
+ * existing `prepare → bind → first|all|run` chain so the migration of
18
+ * existing stores is mechanical (search-and-replace the constructor type).
19
+ *
20
+ * Today there is one implementation, `D1Adapter`. A `MemSqlDb` test double
21
+ * lives next door under `test-utils/`; `BetterSqliteAdapter` and
22
+ * `ClickHouseAdapter` are deferred until they have a real runtime to serve.
23
+ */
24
+ interface SqlDb {
25
+ readonly dialect?: SqlDialect;
26
+ prepare(sql: string): SqlStatement;
27
+ /**
28
+ * Run multiple prepared statements as a batch. On D1 this maps to a
29
+ * single network round-trip; on a future better-sqlite3 adapter it
30
+ * wraps the calls in a transaction. Returns one result per statement
31
+ * in input order, mirroring D1's `batch`.
32
+ *
33
+ * Statements MUST have been produced by this same `SqlDb` instance —
34
+ * mixing adapters is an error and runtime behavior is undefined.
35
+ */
36
+ batch(statements: SqlStatement[]): Promise<Array<{
37
+ meta: {
38
+ changes: number;
39
+ };
40
+ }>>;
41
+ }
42
+ type SqlDialectName = "sqlite" | "postgres";
43
+ interface SqlDialect {
44
+ readonly name: SqlDialectName;
45
+ now(): string;
46
+ sinceHours(param: string): string;
47
+ sinceMinutes(param: string): string;
48
+ jsonText(expr: string, path: string): string;
49
+ }
50
+ interface SqlStatement {
51
+ bind(...args: unknown[]): SqlStatement;
52
+ first<T = Record<string, unknown>>(): Promise<T | null>;
53
+ all<T = Record<string, unknown>>(): Promise<{
54
+ results: T[];
55
+ }>;
56
+ run(): Promise<{
57
+ meta: {
58
+ changes: number;
59
+ };
60
+ }>;
61
+ }
62
+ /**
63
+ * D1 already conforms to this shape almost exactly; the adapter normalizes
64
+ * two small differences:
65
+ * - `all()` on D1 returns `results?: T[]` (optional). We coerce to `[]`.
66
+ * - `run()`'s `meta.changes` is optional on D1. We coerce to `0`.
67
+ * Both differences are runtime-undetectable for the queries this codebase
68
+ * issues (every successful all() returns results; every run() against an
69
+ * INSERT/UPDATE/DELETE reports changes), but coercing keeps the typed
70
+ * interface honest.
71
+ */
72
+ declare class D1Adapter implements SqlDb {
73
+ private readonly d1;
74
+ readonly dialect: SqlDialect;
75
+ constructor(d1: D1Database);
76
+ prepare(sql: string): SqlStatement;
77
+ batch(statements: SqlStatement[]): Promise<Array<{
78
+ meta: {
79
+ changes: number;
80
+ };
81
+ }>>;
82
+ }
83
+
84
+ interface ServiceMapOptions {
85
+ projectId: string;
86
+ hours: number;
87
+ source?: "all" | "sdk" | "ebpf";
88
+ }
89
+ interface ServiceOperationsOptions {
90
+ projectId: string;
91
+ service: string;
92
+ hours: number;
93
+ }
94
+
95
+ interface TelemetryInstrumentationGapCalibrationOptions {
96
+ projectId: string;
97
+ hours: number;
98
+ limit?: number;
99
+ }
100
+
101
+ declare class TelemetryStore {
102
+ private readonly db;
103
+ constructor(db: SqlDb);
104
+ ingest(spans: StoredSpan[]): Promise<{
105
+ inserted: number;
106
+ traceCount: number;
107
+ }>;
108
+ getOverview(options: TelemetryOverviewOptions): Promise<TelemetryOverviewResponse>;
109
+ getTraceDetail(traceId: string, projectId: string): Promise<TelemetryTraceDetailResponse | null>;
110
+ getTraceGaps(traceId: string, projectId: string): Promise<TelemetryInstrumentationGapsResponse | null>;
111
+ calibrateTraceGaps(options: TelemetryInstrumentationGapCalibrationOptions): Promise<{
112
+ thresholds: _obsunified_types.InstrumentationGapThresholds;
113
+ windowHours: number;
114
+ sampledSpanCount: number;
115
+ traceCount: number;
116
+ flaggedTraceCount: number;
117
+ blindspotCount: number;
118
+ uninstrumentedTimeMs: number;
119
+ flaggedTraceRate: number;
120
+ status: string;
121
+ topTraces: {
122
+ traceId: string;
123
+ rootSpanName: string;
124
+ serviceName: string;
125
+ totalDurationMs: number;
126
+ blindspotCount: number;
127
+ uninstrumentedTimeMs: number;
128
+ ratio: number;
129
+ topBlindspot: _obsunified_types.TelemetryInstrumentationGap | null;
130
+ }[];
131
+ timestamp: string;
132
+ }>;
133
+ getIssueOverview(options: TelemetryIssueOptions): Promise<TelemetryIssueOverviewResponse>;
134
+ getIssueDetail(issueId: string, options: TelemetryIssueOptions): Promise<TelemetryIssueDetailResponse | null>;
135
+ getExportRows(options: TelemetryOverviewOptions): Promise<string>;
136
+ getServiceMap(options: ServiceMapOptions): Promise<{
137
+ nodes: {
138
+ service: string;
139
+ spanCount: number;
140
+ errorCount: number;
141
+ traceCount: number;
142
+ errorRate: number;
143
+ }[];
144
+ edges: {
145
+ source: string;
146
+ target: string;
147
+ calls: number;
148
+ errors: number;
149
+ errorRate: number;
150
+ p50DurationMs: number;
151
+ p95DurationMs: number;
152
+ rps: number;
153
+ isEbpf: boolean;
154
+ }[];
155
+ }>;
156
+ getServiceOperations(options: ServiceOperationsOptions): Promise<{
157
+ service: string;
158
+ spanCount: number;
159
+ traceCount: number;
160
+ errorCount: number;
161
+ operations: {
162
+ spanName: string;
163
+ calls: number;
164
+ errors: number;
165
+ errorRate: number;
166
+ p50DurationMs: number;
167
+ p95DurationMs: number;
168
+ }[];
169
+ recentErrors: {
170
+ traceId: string;
171
+ spanId: string;
172
+ spanName: string;
173
+ statusMessage: string | null;
174
+ durationMs: number;
175
+ startTime: string;
176
+ }[];
177
+ }>;
178
+ purgeExpired(): Promise<number>;
179
+ }
180
+
181
+ /**
182
+ * UsageStore — union of all repos.
183
+ * - A's in-memory aggregation approach (more flexible, handles legacy load time keys)
184
+ * - A's broader error detection (event_type='frontend_error' OR severity='error')
185
+ * - A's multi-key load time parsing (loadTimeMs, load_time_ms, durationMs)
186
+ * - A's purgeExpired()
187
+ * - A's summarizeMap helper
188
+ */
189
+
190
+ declare class UsageStore {
191
+ private readonly db;
192
+ constructor(db: SqlDb);
193
+ ingest(events: UsageEventRecord[]): Promise<{
194
+ inserted: number;
195
+ sessionCount: number;
196
+ }>;
197
+ getOverview(options: UsageOverviewOptions): Promise<UsageOverviewResponse>;
198
+ getSessionDetail(sessionId: string, projectId: string): Promise<UsageSessionDetailResponse | null>;
199
+ /**
200
+ * List sessions with an optional qualitative filter.
201
+ *
202
+ * Aggregates per session_id in a single query; supports three filters
203
+ * derived from session-level rollups: sessions that errored, sessions
204
+ * with no interactions (engagement drop-off), and sessions with slow
205
+ * page loads.
206
+ */
207
+ listSessions(options: {
208
+ projectId: string;
209
+ hours: number;
210
+ filter: "all" | "ended_in_error" | "dropoff" | "slow";
211
+ slowMs?: number;
212
+ limit?: number;
213
+ }): Promise<{
214
+ sessions: Array<UsageSessionSummary & {
215
+ interactionCount: number;
216
+ maxLoadTimeMs: number | null;
217
+ }>;
218
+ }>;
219
+ purgeExpired(): Promise<number>;
220
+ }
221
+
222
+ /**
223
+ * Factory that materializes an `SqlDb` for the request's `env`. Per-request
224
+ * because Cloudflare's `D1Database` binding only exists once `env` is in
225
+ * scope; on Workers this is essentially free since `D1Adapter` is a thin
226
+ * wrapper. Hosts override this to inject a fake DB in tests, a different
227
+ * engine in alternate runtimes, or a tracing wrapper at the storage layer.
228
+ */
229
+ type SqlDbFactory = (env: CollectorEnv) => SqlDb;
230
+ interface SpanProcessorPlugin {
231
+ name: string;
232
+ process(spans: StoredSpan[], context: CollectorRouteContext): Promise<StoredSpan[]> | StoredSpan[];
233
+ }
234
+ interface UsageEventProcessorPlugin {
235
+ name: string;
236
+ process(events: UsageEventRecord[], context: CollectorRouteContext): Promise<UsageEventRecord[]> | UsageEventRecord[];
237
+ }
238
+ interface CollectorPluginContext {
239
+ addSpanProcessor(processor: SpanProcessorPlugin): void;
240
+ addUsageEventProcessor(processor: UsageEventProcessorPlugin): void;
241
+ getRegisteredPluginNames(): string[];
242
+ }
243
+ interface CollectorPlugin {
244
+ name: string;
245
+ register(app: Hono<{
246
+ Bindings: CollectorEnv;
247
+ }>, context: CollectorRuntime): void;
248
+ }
249
+ interface CollectorAuthConfig {
250
+ /** Single middleware applied to both /v1/* (ingest) and /internal/* (query) routes */
251
+ middleware?: MiddlewareHandler<{
252
+ Bindings: CollectorEnv;
253
+ Variables: any;
254
+ }>;
255
+ /** @deprecated Use middleware instead. Ingest-only auth for /v1/* routes. */
256
+ ingest?: MiddlewareHandler<{
257
+ Bindings: CollectorEnv;
258
+ Variables: any;
259
+ }>;
260
+ /** @deprecated Use middleware instead. Query-only auth for /internal/* routes. */
261
+ query?: MiddlewareHandler<{
262
+ Bindings: CollectorEnv;
263
+ Variables: any;
264
+ }>;
265
+ }
266
+ interface CollectorConfig {
267
+ plugins: CollectorPlugin[];
268
+ auth?: CollectorAuthConfig;
269
+ /** Comma-separated allowed origins for CORS on ingest endpoints */
270
+ allowedOrigins?: string;
271
+ /** Register dashboard auth routes and middleware */
272
+ dashboardAuth?: {
273
+ middleware: MiddlewareHandler<{
274
+ Bindings: CollectorEnv;
275
+ Variables: any;
276
+ }>;
277
+ registerRoutes: (app: Hono<{
278
+ Bindings: CollectorEnv;
279
+ }>) => void;
280
+ };
281
+ /**
282
+ * Pluggable structured logger. Defaults to console output. Pass a logger
283
+ * from `@obsunified/telemetry-sdk` to ship the collector's own log output as
284
+ * OTLP — see apps/collector/SELF_INSTRUMENTATION.md.
285
+ */
286
+ logger?: Logger;
287
+ /**
288
+ * Wraps async work in a child span on the active request span. Wire this
289
+ * to `@obsunified/telemetry-sdk`'s `withChildSpan` from the worker entrypoint to
290
+ * surface LLM hops + DB-heavy paths as nested spans. Defaults to
291
+ * pass-through.
292
+ */
293
+ withChildSpan?: ChildSpanRunner;
294
+ /**
295
+ * RFC 0008 — override the storage adapter. Per-request factory because
296
+ * `env.DB` only exists once a request lands. Defaults to wrapping
297
+ * `env.DB` in `D1Adapter`. Override in tests (use `MemSqlDb`) or to add
298
+ * a tracing layer at the storage seam.
299
+ */
300
+ sqlDb?: SqlDbFactory;
301
+ }
302
+ declare class CollectorRuntime implements CollectorPluginContext {
303
+ private readonly spanProcessors;
304
+ private readonly usageEventProcessors;
305
+ private readonly plugins;
306
+ private readonly sqlDbFactory;
307
+ readonly logger: Logger;
308
+ readonly withChildSpan: ChildSpanRunner;
309
+ constructor(logger?: Logger, withChildSpan?: ChildSpanRunner, sqlDbFactory?: SqlDbFactory);
310
+ /**
311
+ * Materialize an `SqlDb` for this request. Stores will accept this
312
+ * directly once Phase 1.5 of RFC 0008 lands; until then plugins that
313
+ * want to bypass `c.env.DB` can call this to opt in early.
314
+ */
315
+ getSqlDb(env: CollectorEnv): SqlDb;
316
+ registerPlugin(plugin: CollectorPlugin): void;
317
+ addSpanProcessor(processor: SpanProcessorPlugin): void;
318
+ addUsageEventProcessor(processor: UsageEventProcessorPlugin): void;
319
+ getRegisteredPluginNames(): string[];
320
+ createRouteContext(env: CollectorEnv, hono: CollectorRouteContext["hono"]): CollectorRouteContext;
321
+ createStore(env: CollectorEnv): TelemetryStore;
322
+ createUsageStore(env: CollectorEnv): UsageStore;
323
+ runSpanProcessors(spans: StoredSpan[], context: CollectorRouteContext): Promise<StoredSpan[]>;
324
+ runUsageEventProcessors(events: UsageEventRecord[], context: CollectorRouteContext): Promise<UsageEventRecord[]>;
325
+ }
326
+ declare const createTelemetryCollectorApp: (pluginsOrConfig: CollectorPlugin[] | CollectorConfig) => Hono<{
327
+ Bindings: CollectorEnv;
328
+ }>;
329
+ /**
330
+ * Scheduled handler that purges expired telemetry and usage rows.
331
+ * Wire into wrangler.toml: `[triggers] crons = ["0 * * * *"]`
332
+ * Source: AgentOwl + DecisionOps
333
+ */
334
+ declare const createRetentionCleanupHandler: (options?: {
335
+ logger?: Logger;
336
+ }) => {
337
+ scheduled(_event: ScheduledEvent, env: CollectorEnv, _ctx: ExecutionContext): Promise<void>;
338
+ };
339
+ /**
340
+ * RFC 0002 Stage 1 — run any due Analyses. Cheap to call frequently because
341
+ * `runAllDueAnalyses` filters by `last_run + refreshSeconds < now` before
342
+ * touching D1.
343
+ *
344
+ * Wire to a per-minute trigger in wrangler.toml: `crons = ["* * * * *"]`.
345
+ * Kept distinct from retention so the per-minute tick doesn't sweep every
346
+ * retention table every cycle.
347
+ */
348
+ declare const createAnalysesRunHandler: (options?: {
349
+ logger?: Logger;
350
+ tracer?: ChildSpanRunner;
351
+ }) => {
352
+ scheduled(_event: ScheduledEvent, env: CollectorEnv, _ctx: ExecutionContext): Promise<void>;
353
+ };
354
+
355
+ declare const actionRoutesPlugin: CollectorPlugin;
356
+
357
+ declare const aiReceiverPlugin: CollectorPlugin;
358
+
359
+ /**
360
+ * Span processor that routes large AI payloads to the ai_span_payloads
361
+ * side table.
362
+ *
363
+ * For every span that has an `openinference.span.kind` attribute, we look
364
+ * for `ai.payload.input` / `ai.payload.output`, write them (plus the kind)
365
+ * to `ai_span_payloads`, and strip them from the span's attributes_json
366
+ * before it hits `telemetry_spans`.
367
+ *
368
+ * This keeps the hot spans table lean while preserving full replay data
369
+ * for AI calls.
370
+ */
371
+
372
+ declare const aiSpanPayloadsProcessorPlugin: CollectorPlugin;
373
+
374
+ declare function evaluateAllRules(env: CollectorEnv, options?: {
375
+ logger?: Logger;
376
+ tracer?: ChildSpanRunner;
377
+ concurrency?: number;
378
+ ruleTimeoutMs?: number;
379
+ }): Promise<{
380
+ evaluated: number;
381
+ fired: number;
382
+ resolved: number;
383
+ }>;
384
+ /**
385
+ * Scheduled handler suitable for wrangler cron triggers. Dispatches on the
386
+ * cron expression so multiple triggers can share this handler.
387
+ */
388
+ declare function createAlertEvaluatorHandler(): {
389
+ scheduled(_event: {
390
+ cron: string;
391
+ }, env: CollectorEnv, ctx: {
392
+ waitUntil(promise: Promise<unknown>): void;
393
+ }): Promise<void>;
394
+ };
395
+
396
+ declare const alertsRoutesPlugin: CollectorPlugin;
397
+
398
+ /**
399
+ * RFC 0002 — HTTP surface for application-aware Analyses.
400
+ *
401
+ * GET /internal/analyses — list registered definitions
402
+ * GET /internal/analyses/:id/result — definition + latest result
403
+ * GET /internal/analyses/results — bulk: every definition + latest
404
+ * POST /internal/analyses/:id/run — Stage 4: on-demand re-run for
405
+ * view: "page" investigations
406
+ *
407
+ * Cron writes happen via the scheduled handler (see analyses-runner.ts).
408
+ * The on-demand POST exists so an investigation page's [Re-run] button
409
+ * doesn't have to wait for the next 5-min tick.
410
+ */
411
+
412
+ declare const analysesRoutesPlugin: CollectorPlugin;
413
+
414
+ /**
415
+ * RFC 0002 Stage 5 — Ask box HTTP surface.
416
+ *
417
+ * POST /internal/ask { question } → AskResponse
418
+ *
419
+ * The dashboard's top-bar AskBox calls this once per question. Single-turn
420
+ * for v1; the conversational `/ask` thread (with follow-ups + "Save as
421
+ * panel") lands in a follow-up commit.
422
+ *
423
+ * The route does no SQL itself — it composes runAsk() from the catalog
424
+ * lookups (AnalysesStore + getAllAnalysesForProject) and the LLM config.
425
+ * If ANTHROPIC_API_KEY is unset we return a structured error rather than
426
+ * 500-ing, so the dashboard can render a "set ANTHROPIC_API_KEY to
427
+ * enable Ask" hint instead of a generic failure.
428
+ */
429
+
430
+ declare const askRoutesPlugin: CollectorPlugin;
431
+
432
+ declare const botFilterPlugin: CollectorPlugin;
433
+
434
+ type CausalConfidence = ActionConfidence;
435
+ interface ActionRef {
436
+ id: string;
437
+ projectId: string;
438
+ rootActionId: string;
439
+ causedByActionId: string | null;
440
+ actorType: string;
441
+ actorId: string | null;
442
+ actionKind: string;
443
+ name: string | null;
444
+ status: string;
445
+ startedAt: string;
446
+ endedAt: string | null;
447
+ durationMs: number | null;
448
+ traceId: string | null;
449
+ spanId: string | null;
450
+ sessionId: string | null;
451
+ interactionId: string | null;
452
+ userId: string | null;
453
+ agentRunId: string | null;
454
+ stepId: string | null;
455
+ toolCallId: string | null;
456
+ promptVersion: string | null;
457
+ modelName: string | null;
458
+ provider: string | null;
459
+ totalCostUsd: number | null;
460
+ causalConfidence: CausalConfidence;
461
+ attrsJson: string | null;
462
+ }
463
+ interface AgentRunRef {
464
+ id: string;
465
+ projectId: string;
466
+ agentId: string;
467
+ agentName: string;
468
+ agentVersion: string;
469
+ goal: string | null;
470
+ outcome: string | null;
471
+ autonomyLevel: string;
472
+ status: string;
473
+ errorMessage: string | null;
474
+ totalCostUsd: number | null;
475
+ totalDurationMs: number | null;
476
+ metadataJson: string | null;
477
+ }
478
+ interface ToolCallRef {
479
+ id: string;
480
+ actionId: string;
481
+ projectId: string;
482
+ toolName: string;
483
+ argsHash: string;
484
+ resultHash: string;
485
+ errorType: string | null;
486
+ sideEffect: number;
487
+ approvalState: string | null;
488
+ argsRedacted: string | null;
489
+ resultRedacted: string | null;
490
+ mcpAuditJson: string | null;
491
+ mutationBeforeJson: string | null;
492
+ mutationAfterJson: string | null;
493
+ mutationDiffJson: string | null;
494
+ mutationArtifactId: string | null;
495
+ }
496
+ interface RetrievalEventRef {
497
+ id: string;
498
+ actionId: string;
499
+ projectId: string;
500
+ retrieverName: string;
501
+ queryHash: string;
502
+ documentsJson: string | null;
503
+ totalResults: number;
504
+ maxRelevanceScore: number | null;
505
+ durationMs: number | null;
506
+ }
507
+ interface EvalResultRef {
508
+ id: string;
509
+ actionId: string;
510
+ projectId: string;
511
+ evaluatorName: string;
512
+ evaluatorVersion: string;
513
+ score: number | null;
514
+ passed: number;
515
+ reasoning: string | null;
516
+ rubricJson: string | null;
517
+ }
518
+ interface ArtifactRef {
519
+ id: string;
520
+ actionId: string;
521
+ projectId: string;
522
+ artifactName: string;
523
+ artifactType: string;
524
+ storageRef: string | null;
525
+ sizeBytes: number | null;
526
+ sha256Hash: string | null;
527
+ contentPreview: string | null;
528
+ }
529
+
530
+ /**
531
+ * RFC 0006 Phase 3.1 — Connected rail manifest endpoint.
532
+ *
533
+ * GET /internal/connected/:kind/:id
534
+ *
535
+ * Returns the entity's identity-graph neighbors (Up / Across / Down) +
536
+ * topic neighbors (Related), bundled into the shape the dashboard's
537
+ * <ConnectedRail /> renders directly. Built on `IdentityIndex` so the
538
+ * underlying SQL is shared with `/internal/timeline/:sessionId` and any
539
+ * future cross-signal consumer.
540
+ *
541
+ * The handler is the single read path the rail uses. Sections that have
542
+ * no neighbors render as `links: []` with an `emptyReason` explaining
543
+ * why — never absent. This is the "informative absence" pattern from
544
+ * RFC 0006 § Connected rail / Empty-state.
545
+ */
546
+
547
+ declare const connectedRoutesPlugin: CollectorPlugin;
548
+
549
+ /**
550
+ * Serves the dashboard SPA.
551
+ *
552
+ * For Cloudflare Workers: configure [assets] in wrangler.toml pointing to
553
+ * the @obsunified/dashboard build output. The Workers runtime handles static file
554
+ * serving automatically; this plugin provides the fallback route for SPA
555
+ * client-side routing.
556
+ *
557
+ * For Node.js / other runtimes: serve static files from @obsunified/dashboard/dist
558
+ * using your framework's static file middleware, then mount this plugin for
559
+ * the SPA fallback.
560
+ */
561
+ declare const dashboardRoutesPlugin: CollectorPlugin;
562
+
563
+ declare const defaultSpanEnrichmentPlugin: CollectorPlugin;
564
+
565
+ declare const evalCasesRoutesPlugin: CollectorPlugin;
566
+
567
+ declare const evidenceRetrievalRoutesPlugin: CollectorPlugin;
568
+
569
+ /**
570
+ * Normalize OpenTelemetry `gen_ai.*` semantic-convention attributes, OTel MCP attributes,
571
+ * and OpenInference span kinds into the canonical obs-unified Agent Action Graph schema.
572
+ *
573
+ * References:
574
+ * https://opentelemetry.io/docs/specs/semconv/gen-ai/
575
+ * https://github.com/Arize-ai/openinference/blob/main/spec/
576
+ *
577
+ * Must run BEFORE ai-span-payloads-processor — that processor assumes
578
+ * `openinference.span.kind` and `ai.payload.*` are already set.
579
+ */
580
+
581
+ declare const genAiNormalizerPlugin: CollectorPlugin;
582
+
583
+ declare const identityReceiverPlugin: CollectorPlugin;
584
+
585
+ declare const issueEnrichmentPlugin: CollectorPlugin;
586
+
587
+ declare const issueInsightsPlugin: CollectorPlugin;
588
+
589
+ declare const logsReceiverPlugin: CollectorPlugin;
590
+
591
+ /** OTLP/HTTP metrics receiver. Accepts JSON or protobuf, with gzip. */
592
+
593
+ declare const metricsReceiverPlugin: CollectorPlugin;
594
+
595
+ /**
596
+ * Drives the in-dashboard Onboarding tab — returns counts of signal
597
+ * types, used to decide which "you need to wire X" snippets to show
598
+ * the user.
599
+ *
600
+ * Returns zeros for tables that don't yet exist (e.g. fresh DB) rather
601
+ * than 500ing — onboarding has to work on day zero.
602
+ */
603
+ declare const onboardingRoutesPlugin: CollectorPlugin;
604
+
605
+ /** OTLP/HTTP trace receiver. Accepts JSON or protobuf, with gzip. */
606
+
607
+ declare const otlpReceiverPlugin: CollectorPlugin;
608
+
609
+ declare const platformRoutesPlugin: CollectorPlugin;
610
+
611
+ /**
612
+ * RFC 0007 — pprof profiling receiver + read endpoints.
613
+ *
614
+ * POST /v1/profiles/pprof — accepts gzipped pprof blob
615
+ * GET /internal/profiles/:id — proxies the blob back
616
+ * GET /internal/profiles/:id?trace_id=… — Phase 4.5 server-side filter
617
+ *
618
+ * Phase 4 minimal scope: ingest-time pprof parsing is deferred. The
619
+ * receiver writes the blob verbatim to R2 / filesystem and reads
620
+ * trace_ids from an `x-obs-trace-ids` header (comma-separated). The
621
+ * @obsunified/telemetry-sdk profile helper will stamp this; eBPF agents that
622
+ * don't emit the header just don't populate `profile_trace_index`,
623
+ * which means the trace waterfall's 🔥 badge won't fire for those
624
+ * profiles. Aggregate views still work.
625
+ *
626
+ * A follow-on commit can add server-side pprof parsing using a Buf-
627
+ * generated schema or pprof-format. The endpoint shape doesn't change
628
+ * when that lands.
629
+ */
630
+
631
+ declare const profileRoutesPlugin: CollectorPlugin;
632
+
633
+ declare const projectsRoutesPlugin: CollectorPlugin;
634
+
635
+ declare const queryRoutesPlugin: CollectorPlugin;
636
+
637
+ declare const redactionProcessorPlugin: CollectorPlugin;
638
+
639
+ declare const replayQueryRoutesPlugin: CollectorPlugin;
640
+
641
+ declare const replayReceiverPlugin: CollectorPlugin;
642
+
643
+ /**
644
+ * Live tail SSE endpoint. The dashboard opens an EventSource here; the
645
+ * collector proxies to the TailHub Durable Object which holds the open
646
+ * stream and fans out broadcasts from ingest.
647
+ */
648
+ declare const tailRoutesPlugin: CollectorPlugin;
649
+
650
+ declare const timelineRoutesPlugin: CollectorPlugin;
651
+
652
+ declare const uaEnrichmentPlugin: CollectorPlugin;
653
+
654
+ declare const usageNormalizationPlugin: CollectorPlugin;
655
+
656
+ declare const usagePrivacyPlugin: CollectorPlugin;
657
+
658
+ declare const usageQueryRoutesPlugin: CollectorPlugin;
659
+
660
+ /** Union: A's JSON error handling, event limit, env-based retention. P/D's dynamic CORS. */
661
+
662
+ declare const usageReceiverPlugin: CollectorPlugin;
663
+
664
+ declare const usersQueryRoutesPlugin: CollectorPlugin;
665
+
666
+ declare const utmEnrichmentPlugin: CollectorPlugin;
667
+
668
+ /**
669
+ * Creates auth routes and middleware for dashboard password login.
670
+ *
671
+ * Routes added:
672
+ * POST /auth/login — accepts { password }, sets session cookie
673
+ * GET /auth/check — returns { authenticated: true/false }
674
+ * POST /auth/logout — clears session cookie
675
+ *
676
+ * The returned middleware validates the session cookie on protected routes.
677
+ */
678
+ declare function createDashboardAuth(config: {
679
+ password: string;
680
+ }): {
681
+ middleware: MiddlewareHandler<{
682
+ Bindings: CollectorEnv;
683
+ Variables: {
684
+ projectId: string;
685
+ };
686
+ }>;
687
+ registerRoutes: (app: hono.Hono<{
688
+ Bindings: CollectorEnv;
689
+ }>) => void;
690
+ };
691
+
692
+ /**
693
+ * In-memory SSE pub/sub hub for live-tailing spans and logs.
694
+ *
695
+ * Ingest plugins call `/publish` after writing to D1; the dashboard opens an
696
+ * EventSource on `/internal/telemetry/tail` which proxies here via `/subscribe`.
697
+ *
698
+ * One singleton DO instance is used (idFromName("singleton")); it fans out to
699
+ * every connected subscriber, filtering by projectId and kind server-side so
700
+ * clients don't see other tenants' data.
701
+ *
702
+ * Heartbeat frames keep the connection alive through proxies with idle
703
+ * timeouts (Vite dev proxy, Cloudflare edge).
704
+ */
705
+ type TailKind = "span" | "log";
706
+ interface TailEvent {
707
+ kind: TailKind;
708
+ projectId: string;
709
+ row: Record<string, unknown>;
710
+ t: string;
711
+ }
712
+ declare class TailHub {
713
+ private readonly subscribers;
714
+ private readonly encoder;
715
+ fetch(req: Request): Promise<Response>;
716
+ private subscribe;
717
+ private drop;
718
+ private broadcast;
719
+ }
720
+
721
+ type ActionRecord = Omit<ActionRef, "projectId"> & {
722
+ projectId: string;
723
+ };
724
+ type AgentRunRecord = Omit<AgentRunRef, "projectId"> & {
725
+ projectId: string;
726
+ };
727
+ type ToolCallRecord = Omit<ToolCallRef, "projectId" | "sideEffect"> & {
728
+ projectId: string;
729
+ sideEffect: boolean | number;
730
+ };
731
+ type RetrievalEventRecord = Omit<RetrievalEventRef, "projectId"> & {
732
+ projectId: string;
733
+ };
734
+ type EvalResultRecord = Omit<EvalResultRef, "projectId" | "passed"> & {
735
+ projectId: string;
736
+ passed: boolean | number;
737
+ };
738
+ type ArtifactRecord = Omit<ArtifactRef, "projectId"> & {
739
+ projectId: string;
740
+ };
741
+ declare class ActionStore {
742
+ private readonly db;
743
+ constructor(db: SqlDb);
744
+ upsertAction(action: ActionRecord): Promise<void>;
745
+ upsertAgentRun(run: AgentRunRecord): Promise<void>;
746
+ upsertToolCall(toolCall: ToolCallRecord): Promise<void>;
747
+ upsertRetrievalEvent(event: RetrievalEventRecord): Promise<void>;
748
+ upsertEvalResult(result: EvalResultRecord): Promise<void>;
749
+ upsertArtifact(artifact: ArtifactRecord): Promise<void>;
750
+ getAction(projectId: string, actionId: string): Promise<ActionRef | null>;
751
+ listActionsByRoot(projectId: string, rootActionId: string, limit?: number): Promise<ActionRef[]>;
752
+ getAgentRun(projectId: string, agentRunId: string): Promise<AgentRunRef | null>;
753
+ listToolCallsByAction(projectId: string, actionId: string, limit?: number): Promise<ToolCallRef[]>;
754
+ listRetrievalEventsByAction(projectId: string, actionId: string, limit?: number): Promise<RetrievalEventRef[]>;
755
+ listEvalResultsByAction(projectId: string, actionId: string, limit?: number): Promise<EvalResultRef[]>;
756
+ listArtifactsByAction(projectId: string, actionId: string, limit?: number): Promise<ArtifactRef[]>;
757
+ }
758
+
759
+ declare function compareValue(value: number, threshold: number, comparison: AlertComparison): boolean;
760
+ declare class AlertsStore {
761
+ private readonly db;
762
+ constructor(db: SqlDb);
763
+ validateInput(input: AlertRuleInput): void;
764
+ listRules(projectId: string): Promise<AlertRule[]>;
765
+ getRule(id: string, projectId: string): Promise<AlertRule | null>;
766
+ createRule(projectId: string, input: AlertRuleInput): Promise<AlertRule>;
767
+ updateRule(id: string, projectId: string, patch: Partial<AlertRuleInput>): Promise<AlertRule | null>;
768
+ deleteRule(id: string, projectId: string): Promise<boolean>;
769
+ listEnabledRules(): Promise<AlertRule[]>;
770
+ getState(ruleId: string): Promise<AlertStateRow | null>;
771
+ transitionState(ruleId: string, projectId: string, newState: AlertState, now: string): Promise<void>;
772
+ recordEvaluation(ruleId: string, projectId: string, value: number, state: AlertState, notified: boolean): Promise<void>;
773
+ listEvaluations(params: {
774
+ ruleId: string;
775
+ projectId?: string;
776
+ hours: number;
777
+ limit?: number;
778
+ }): Promise<AlertEvaluationsListResponse>;
779
+ evaluateRule(rule: AlertRule): Promise<number>;
780
+ /**
781
+ * Stage 6 — fetch the latest narrative associated with this rule's
782
+ * bound analysis. Used by the evaluator when firing an analysis-bound
783
+ * alert so the webhook payload includes the human-readable
784
+ * narrative, not just a threshold crossing.
785
+ */
786
+ getAnalysisNarrative(projectId: string, analysisId: string): Promise<{
787
+ narrative: string | null;
788
+ status: string | null;
789
+ } | null>;
790
+ private evaluateSpanRule;
791
+ private evaluateLogRule;
792
+ private evaluateUsageRule;
793
+ private evaluateAIRule;
794
+ }
795
+
796
+ /**
797
+ * Storage seam for opaque blob payloads — replay rrweb chunks and
798
+ * pprof profiles.
799
+ *
800
+ * Two implementations:
801
+ * - `R2BlobStore` — Cloudflare R2 binding (default on Workers).
802
+ * - `S3BlobStore` (sibling file) — AWS S3 / MinIO / any S3-compatible.
803
+ *
804
+ * Replay chunks live under `replays/<session_id>/<chunk_id>`; pprof
805
+ * profiles live under `profiles/<service>/<trace_id>/<span_id>`. The
806
+ * adapter never sees these paths — they're constructed by the callers
807
+ * (`replay-receiver`, `profile-routes`).
808
+ */
809
+ interface BlobStore {
810
+ put(key: string, body: ArrayBuffer | Uint8Array | ReadableStream<Uint8Array>, options?: BlobPutOptions): Promise<void>;
811
+ get(key: string): Promise<BlobObject | null>;
812
+ delete(key: string): Promise<void>;
813
+ list(prefix: string, options?: BlobListOptions): Promise<BlobListResult>;
814
+ }
815
+ interface BlobPutOptions {
816
+ httpMetadata?: {
817
+ contentType?: string;
818
+ contentEncoding?: string;
819
+ };
820
+ customMetadata?: Record<string, string>;
821
+ }
822
+ interface BlobListOptions {
823
+ limit?: number;
824
+ cursor?: string;
825
+ }
826
+ interface BlobObject {
827
+ body: ReadableStream<Uint8Array>;
828
+ bytes(): Promise<Uint8Array>;
829
+ /**
830
+ * Object size in bytes when the store knows it cheaply (S3 `ContentLength`,
831
+ * R2 `size`). Undefined when it can't be determined without reading the body.
832
+ */
833
+ size?: number;
834
+ httpMetadata?: {
835
+ contentType?: string;
836
+ contentEncoding?: string;
837
+ };
838
+ customMetadata?: Record<string, string>;
839
+ }
840
+ interface BlobListResult {
841
+ objects: Array<{
842
+ key: string;
843
+ size: number;
844
+ uploaded: Date;
845
+ }>;
846
+ cursor?: string;
847
+ truncated: boolean;
848
+ }
849
+ /**
850
+ * R2 adapter. R2's binding shape is already very close to this
851
+ * interface; the adapter normalizes the differences (cursor type,
852
+ * list pagination shape).
853
+ */
854
+ declare class R2BlobStore implements BlobStore {
855
+ private readonly bucket;
856
+ constructor(bucket: R2Bucket);
857
+ put(key: string, body: ArrayBuffer | Uint8Array | ReadableStream<Uint8Array>, options?: BlobPutOptions): Promise<void>;
858
+ get(key: string): Promise<BlobObject | null>;
859
+ delete(key: string): Promise<void>;
860
+ list(prefix: string, options?: BlobListOptions): Promise<BlobListResult>;
861
+ }
862
+ declare class BlobStoreToR2Adapter implements R2Bucket {
863
+ private readonly store;
864
+ constructor(store: BlobStore);
865
+ put(key: string, value: ReadableStream | ArrayBuffer | ArrayBufferView | string | Blob | null, options?: R2PutOptions): Promise<R2Object>;
866
+ get(key: string, _options?: R2GetOptions): Promise<R2ObjectBody | null>;
867
+ delete(keys: string | string[]): Promise<void>;
868
+ list(options?: R2ListOptions): Promise<R2Objects>;
869
+ head(key: string): Promise<R2Object | null>;
870
+ createMultipartUpload(_key: string, _options?: R2MultipartOptions): Promise<R2MultipartUpload>;
871
+ resumeMultipartUpload(_key: string, _uploadId: string): R2MultipartUpload;
872
+ }
873
+
874
+ /**
875
+ * S3-compatible adapter for `BlobStore`. Works against AWS S3, MinIO,
876
+ * Cloudflare R2's S3 API, Backblaze B2, etc.
877
+ *
878
+ * Uses `@aws-sdk/client-s3` v3. The adapter is intentionally thin —
879
+ * just enough to satisfy `BlobStore` for replay + pprof payloads. We
880
+ * deliberately do NOT expose pre-signed URLs, ACLs, or storage-class
881
+ * tuning — those belong in a richer storage adapter for users that
882
+ * outgrow the default.
883
+ */
884
+
885
+ type S3Body = Uint8Array | ArrayBuffer | ReadableStream<Uint8Array>;
886
+ type S3CommandBody = Exclude<S3Body, ArrayBuffer>;
887
+ interface S3ClientShape {
888
+ send(command: unknown): Promise<unknown>;
889
+ }
890
+ interface S3SdkConstructors {
891
+ PutObjectCommand: new (input: {
892
+ Bucket: string;
893
+ Key: string;
894
+ Body?: S3CommandBody;
895
+ ContentType?: string;
896
+ ContentEncoding?: string;
897
+ Metadata?: Record<string, string>;
898
+ }) => unknown;
899
+ GetObjectCommand: new (input: {
900
+ Bucket: string;
901
+ Key: string;
902
+ }) => unknown;
903
+ DeleteObjectCommand: new (input: {
904
+ Bucket: string;
905
+ Key: string;
906
+ }) => unknown;
907
+ ListObjectsV2Command: new (input: {
908
+ Bucket: string;
909
+ Prefix: string;
910
+ MaxKeys?: number;
911
+ ContinuationToken?: string;
912
+ }) => unknown;
913
+ }
914
+ interface S3BlobStoreOptions {
915
+ client: S3ClientShape;
916
+ commands: S3SdkConstructors;
917
+ bucket: string;
918
+ }
919
+ declare class S3BlobStore implements BlobStore {
920
+ private readonly opts;
921
+ constructor(opts: S3BlobStoreOptions);
922
+ put(key: string, body: S3Body, options?: BlobPutOptions): Promise<void>;
923
+ get(key: string): Promise<BlobObject | null>;
924
+ delete(key: string): Promise<void>;
925
+ list(prefix: string, options?: BlobListOptions): Promise<BlobListResult>;
926
+ }
927
+
928
+ type EvalCaseSourceType = "agent_run" | "action" | "ai_call" | "tool_call" | "trace";
929
+ interface EvalCaseSourceLinks {
930
+ sourceAgentRunId?: string | null;
931
+ sourceActionId?: string | null;
932
+ sourceAiCallId?: string | null;
933
+ sourceToolCallId?: string | null;
934
+ sourceTraceId?: string | null;
935
+ sourceSpanId?: string | null;
936
+ }
937
+ interface EvalCaseInput {
938
+ sourceEntityType: EvalCaseSourceType;
939
+ sourceEntityId: string;
940
+ name: string;
941
+ expectedOutcome?: string | null;
942
+ rubric?: JsonValue | null;
943
+ redactedPrompt?: JsonValue | null;
944
+ referencePayload?: JsonValue | null;
945
+ metadata?: Record<string, JsonValue>;
946
+ source?: EvalCaseSourceLinks;
947
+ }
948
+ interface EvalCase extends Required<EvalCaseSourceLinks> {
949
+ id: string;
950
+ projectId: string;
951
+ sourceEntityType: EvalCaseSourceType;
952
+ sourceEntityId: string;
953
+ name: string;
954
+ expectedOutcome: string | null;
955
+ rubric: JsonValue | null;
956
+ redactedPrompt: JsonValue | null;
957
+ referencePayload: JsonValue | null;
958
+ metadata: Record<string, JsonValue>;
959
+ createdAt: string;
960
+ updatedAt: string;
961
+ evidenceReferences?: EvidenceReference[];
962
+ evidenceContract?: EvidenceReferenceContract;
963
+ }
964
+ interface EvalCaseListOptions {
965
+ projectId: string;
966
+ sourceEntityType?: EvalCaseSourceType;
967
+ sourceEntityId?: string;
968
+ limit?: number;
969
+ }
970
+ type EvalRunStatus = "pending" | "running" | "completed" | "failed" | "canceled";
971
+ interface EvalRunCandidate {
972
+ agentId: string | null;
973
+ agentVersion: string | null;
974
+ promptId: string | null;
975
+ promptVersion: string | null;
976
+ modelProvider: string | null;
977
+ model: string | null;
978
+ modelVersion: string | null;
979
+ }
980
+ interface EvalRunSourceCase {
981
+ id: string;
982
+ name: string;
983
+ sourceEntityType: string;
984
+ sourceEntityId: string;
985
+ sourceAgentRunId: string | null;
986
+ sourceActionId: string | null;
987
+ sourceAiCallId: string | null;
988
+ sourceToolCallId: string | null;
989
+ sourceTraceId: string | null;
990
+ sourceSpanId: string | null;
991
+ evidenceReferences?: EvidenceReference[];
992
+ evidenceContract?: EvidenceReferenceContract;
993
+ }
994
+ interface EvalRun {
995
+ id: string;
996
+ projectId: string;
997
+ evalCaseId: string | null;
998
+ status: EvalRunStatus;
999
+ candidate: EvalRunCandidate;
1000
+ startedAt: string | null;
1001
+ endedAt: string | null;
1002
+ totalCount: number;
1003
+ passCount: number;
1004
+ failCount: number;
1005
+ averageScore: number | null;
1006
+ metadata: Record<string, JsonValue>;
1007
+ createdAt: string;
1008
+ sourceEvalCase?: EvalRunSourceCase | null;
1009
+ evidenceReferences?: EvidenceReference[];
1010
+ evidenceContract?: EvidenceReferenceContract;
1011
+ }
1012
+ interface EvalRunInput {
1013
+ id?: string;
1014
+ evalCaseId?: string | null;
1015
+ status?: EvalRunStatus;
1016
+ candidate?: Partial<EvalRunCandidate>;
1017
+ startedAt?: string | null;
1018
+ endedAt?: string | null;
1019
+ totalCount?: number;
1020
+ passCount?: number;
1021
+ failCount?: number;
1022
+ averageScore?: number | null;
1023
+ metadata?: Record<string, JsonValue>;
1024
+ }
1025
+ interface EvalRunsListOptions {
1026
+ projectId: string;
1027
+ evalCaseId?: string;
1028
+ status?: EvalRunStatus;
1029
+ limit?: number;
1030
+ }
1031
+ declare class EvalCaseSourceNotFoundError extends Error {
1032
+ readonly projectId: string;
1033
+ readonly sourceEntityType: EvalCaseSourceType;
1034
+ readonly sourceEntityId: string;
1035
+ constructor(projectId: string, sourceEntityType: EvalCaseSourceType, sourceEntityId: string);
1036
+ }
1037
+ declare const isEvalCaseSourceType: (value: unknown) => value is EvalCaseSourceType;
1038
+ declare const isEvalRunStatus: (value: unknown) => value is EvalRunStatus;
1039
+ declare class EvalCasesStore {
1040
+ private readonly db;
1041
+ constructor(db: SqlDb);
1042
+ createCase(projectId: string, input: EvalCaseInput): Promise<EvalCase>;
1043
+ getCase(projectId: string, id: string): Promise<EvalCase | null>;
1044
+ listCases(options: EvalCaseListOptions): Promise<EvalCase[]>;
1045
+ createRun(projectId: string, input: EvalRunInput): Promise<EvalRun>;
1046
+ getRun(projectId: string, id: string): Promise<EvalRun | null>;
1047
+ listRuns(options: EvalRunsListOptions): Promise<EvalRun[]>;
1048
+ refreshRunSummary(projectId: string, id: string): Promise<void>;
1049
+ private evalRunSelectSql;
1050
+ private hydrateSource;
1051
+ private getActionSource;
1052
+ private getToolCallSource;
1053
+ private findPayload;
1054
+ private buildMetadata;
1055
+ }
1056
+
1057
+ type MetricType = "gauge" | "sum" | "histogram" | "exp_histogram" | "summary";
1058
+ /**
1059
+ * A metric data point normalized for storage. Series-identifying fields
1060
+ * (name, resource/scope context, attributes) are repeated on each point so
1061
+ * the store can do series upsert in a single pass.
1062
+ */
1063
+ interface DecodedMetricPoint {
1064
+ name: string;
1065
+ description: string | null;
1066
+ unit: string | null;
1067
+ type: MetricType;
1068
+ isMonotonic: boolean | null;
1069
+ temporality: number | null;
1070
+ scopeName: string | null;
1071
+ scopeVersion: string | null;
1072
+ serviceName: string | null;
1073
+ resourceAttrsJson: string | null;
1074
+ attributesJson: string | null;
1075
+ identity: string;
1076
+ tsNs: string;
1077
+ startTsNs: string | null;
1078
+ value: number | null;
1079
+ count: number | null;
1080
+ sum: number | null;
1081
+ min: number | null;
1082
+ max: number | null;
1083
+ boundsJson: string | null;
1084
+ bucketCountsJson: string | null;
1085
+ /**
1086
+ * Type-specific fields that don't fit the column schema:
1087
+ * - exp_histogram: { scale, zeroCount, zeroThreshold, positive: {offset, bucketCounts}, negative: {offset, bucketCounts} }
1088
+ * - summary: { quantileValues: [{quantile, value}, ...] }
1089
+ */
1090
+ extraJson: string | null;
1091
+ exemplarsJson: string | null;
1092
+ }
1093
+
1094
+ /**
1095
+ * Metrics storage.
1096
+ *
1097
+ * Each ingest collapses points to their series identity, upserts the series
1098
+ * row, then batch-inserts points. Series upsert is per-unique-identity per
1099
+ * request — at small batch sizes this is cheap; a followup can switch to a
1100
+ * single SELECT-many + batched INSERT-missing when volume demands it.
1101
+ */
1102
+
1103
+ interface MetricExemplarPoint {
1104
+ id: string;
1105
+ pointId: string;
1106
+ seriesId: string;
1107
+ metricName: string;
1108
+ serviceName: string | null;
1109
+ traceId: string | null;
1110
+ spanId: string | null;
1111
+ tsNs: string;
1112
+ value: number;
1113
+ receivedAt: string;
1114
+ }
1115
+ declare class MetricsStore {
1116
+ private readonly db;
1117
+ constructor(db: SqlDb);
1118
+ purgeExpired(): Promise<number>;
1119
+ ingestBatch(opts: {
1120
+ projectId: string;
1121
+ points: DecodedMetricPoint[];
1122
+ receivedAt: string;
1123
+ expiresAt: string;
1124
+ }): Promise<void>;
1125
+ exemplarsForTrace(projectId: string, traceId: string, limit?: number): Promise<MetricExemplarPoint[]>;
1126
+ recentExemplars(opts: {
1127
+ projectId: string;
1128
+ serviceName?: string | null;
1129
+ metricPrefix?: string | null;
1130
+ limit?: number;
1131
+ }): Promise<MetricExemplarPoint[]>;
1132
+ /**
1133
+ * Ensures a `metric_series` row exists for every unique identity in the
1134
+ * batch. Returns a map of identity → series row for point linking.
1135
+ */
1136
+ private resolveSeries;
1137
+ }
1138
+
1139
+ declare class ProjectsStore {
1140
+ private readonly db;
1141
+ constructor(db: SqlDb);
1142
+ listProjects(): Promise<Project[]>;
1143
+ getProject(id: string): Promise<Project | null>;
1144
+ createProject(input: {
1145
+ name: string;
1146
+ slug: string;
1147
+ }): Promise<Project>;
1148
+ updateProject(id: string, patch: {
1149
+ name?: string;
1150
+ payloadCaptureEnabled?: boolean;
1151
+ }): Promise<Project | null>;
1152
+ ensureDefaultProject(): Promise<void>;
1153
+ listKeys(projectId: string): Promise<IngestKey[]>;
1154
+ createKey(projectId: string, name: string): Promise<IngestKeyWithPlaintext>;
1155
+ revokeKey(keyId: string): Promise<boolean>;
1156
+ findByKeyHash(keyHash: string): Promise<{
1157
+ projectId: string;
1158
+ keyId: string;
1159
+ } | null>;
1160
+ /**
1161
+ * Idempotently register the legacy env INGEST_KEY as a bootstrap key on the
1162
+ * default project, so existing deployments keep working without manual migration.
1163
+ */
1164
+ bootstrapEnvKey(plaintext: string): Promise<void>;
1165
+ }
1166
+
1167
+ interface PostgresAdapterOptions {
1168
+ /**
1169
+ * Statement-level timeout in milliseconds. Defaults to 30s. Issued
1170
+ * via `SET statement_timeout` at the start of each query (session-level;
1171
+ * `SET LOCAL` outside a transaction would be a no-op).
1172
+ */
1173
+ statementTimeoutMs?: number;
1174
+ }
1175
+ declare class PostgresAdapter implements SqlDb {
1176
+ private readonly pool;
1177
+ readonly dialect: SqlDialect;
1178
+ private readonly statementTimeoutMs;
1179
+ constructor(pool: Pool, options?: PostgresAdapterOptions);
1180
+ prepare(sql: string): SqlStatement;
1181
+ batch(statements: SqlStatement[]): Promise<Array<{
1182
+ meta: {
1183
+ changes: number;
1184
+ };
1185
+ }>>;
1186
+ }
1187
+
1188
+ /** All built-in plugins in recommended registration order */
1189
+ declare const allPlugins: CollectorPlugin[];
1190
+ declare const createDefaultCollectorApp: (config?: Partial<CollectorConfig>) => hono.Hono<{
1191
+ Bindings: CollectorEnv;
1192
+ }, hono_types.BlankSchema, "/">;
1193
+ declare const _default: hono.Hono<{
1194
+ Bindings: CollectorEnv;
1195
+ }, hono_types.BlankSchema, "/">;
1196
+
1197
+ export { type ActionRecord, ActionStore, type AgentRunRecord, AlertsStore, type ArtifactRecord, type BlobListOptions, type BlobListResult, type BlobObject, type BlobPutOptions, type BlobStore, BlobStoreToR2Adapter, type CollectorAuthConfig, type CollectorConfig, CollectorEnv, type CollectorPlugin, CollectorRouteContext, CollectorRuntime, D1Adapter, type EvalCase, type EvalCaseInput, type EvalCaseListOptions, type EvalCaseSourceLinks, EvalCaseSourceNotFoundError, type EvalCaseSourceType, EvalCasesStore, type EvalResultRecord, type EvalRun, type EvalRunCandidate, type EvalRunInput, type EvalRunSourceCase, type EvalRunStatus, type EvalRunsListOptions, Logger, MetricsStore, PostgresAdapter, type PostgresAdapterOptions, ProjectsStore, R2BlobStore, type RetrievalEventRecord, S3BlobStore, type S3BlobStoreOptions, type SpanProcessorPlugin, type SqlDb, type SqlDbFactory, type SqlStatement, type TailEvent, TailHub, type TailKind, type ToolCallRecord, type UsageEventProcessorPlugin, actionRoutesPlugin, aiReceiverPlugin, aiSpanPayloadsProcessorPlugin, alertsRoutesPlugin, allPlugins, analysesRoutesPlugin, askRoutesPlugin, botFilterPlugin, compareValue, connectedRoutesPlugin, createAlertEvaluatorHandler, createAnalysesRunHandler, createDashboardAuth, createDefaultCollectorApp, createRetentionCleanupHandler, createTelemetryCollectorApp, dashboardRoutesPlugin, _default as default, defaultSpanEnrichmentPlugin, evalCasesRoutesPlugin, evaluateAllRules, evidenceRetrievalRoutesPlugin, genAiNormalizerPlugin, identityReceiverPlugin, isEvalCaseSourceType, isEvalRunStatus, issueEnrichmentPlugin, issueInsightsPlugin, logsReceiverPlugin, metricsReceiverPlugin, onboardingRoutesPlugin, otlpReceiverPlugin, platformRoutesPlugin, profileRoutesPlugin, projectsRoutesPlugin, queryRoutesPlugin, redactionProcessorPlugin, replayQueryRoutesPlugin, replayReceiverPlugin, tailRoutesPlugin, timelineRoutesPlugin, uaEnrichmentPlugin, usageNormalizationPlugin, usagePrivacyPlugin, usageQueryRoutesPlugin, usageReceiverPlugin, usersQueryRoutesPlugin, utmEnrichmentPlugin };