@agentlensai/server 0.11.0 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (633) hide show
  1. package/LICENSE +21 -0
  2. package/dist/cloud/auth/rbac.d.ts +1 -1
  3. package/dist/cloud/auth/rbac.d.ts.map +1 -1
  4. package/dist/cloud/auth/rbac.js +2 -2
  5. package/dist/cloud/auth/rbac.js.map +1 -1
  6. package/dist/cloud/billing/stripe-client.d.ts.map +1 -1
  7. package/dist/cloud/billing/stripe-client.js +6 -1
  8. package/dist/cloud/billing/stripe-client.js.map +1 -1
  9. package/dist/cloud/ingestion/gateway.d.ts.map +1 -1
  10. package/dist/cloud/ingestion/gateway.js +0 -1
  11. package/dist/cloud/ingestion/gateway.js.map +1 -1
  12. package/dist/cloud/middleware/validate-org-access.d.ts +14 -0
  13. package/dist/cloud/middleware/validate-org-access.d.ts.map +1 -0
  14. package/dist/cloud/middleware/validate-org-access.js +38 -0
  15. package/dist/cloud/middleware/validate-org-access.js.map +1 -0
  16. package/dist/cloud/routes/index.d.ts +13 -0
  17. package/dist/cloud/routes/index.d.ts.map +1 -0
  18. package/dist/cloud/routes/index.js +98 -0
  19. package/dist/cloud/routes/index.js.map +1 -0
  20. package/dist/config.d.ts +33 -1
  21. package/dist/config.d.ts.map +1 -1
  22. package/dist/config.js +71 -1
  23. package/dist/config.js.map +1 -1
  24. package/dist/db/api-key-lookup.d.ts +25 -0
  25. package/dist/db/api-key-lookup.d.ts.map +1 -0
  26. package/dist/db/api-key-lookup.js +38 -0
  27. package/dist/db/api-key-lookup.js.map +1 -0
  28. package/dist/db/connection.postgres.d.ts +44 -0
  29. package/dist/db/connection.postgres.d.ts.map +1 -0
  30. package/dist/db/connection.postgres.js +79 -0
  31. package/dist/db/connection.postgres.js.map +1 -0
  32. package/dist/db/cost-budget-store.d.ts +30 -0
  33. package/dist/db/cost-budget-store.d.ts.map +1 -0
  34. package/dist/db/cost-budget-store.js +201 -0
  35. package/dist/db/cost-budget-store.js.map +1 -0
  36. package/dist/db/drizzle/0000_initial.sql +336 -0
  37. package/dist/db/drizzle/0001_indexes.sql +20 -0
  38. package/dist/db/drizzle/0002_pgvector.sql +19 -0
  39. package/dist/db/drizzle/drizzle/0000_initial.sql +336 -0
  40. package/dist/db/drizzle/drizzle/0001_indexes.sql +20 -0
  41. package/dist/db/drizzle/drizzle/0002_pgvector.sql +19 -0
  42. package/dist/db/drizzle/drizzle/meta/0000_snapshot.json +2593 -0
  43. package/dist/db/drizzle/drizzle/meta/_journal.json +27 -0
  44. package/dist/db/drizzle/meta/0000_snapshot.json +2593 -0
  45. package/dist/db/drizzle/meta/_journal.json +27 -0
  46. package/dist/db/embedding-store.d.ts +2 -1
  47. package/dist/db/embedding-store.d.ts.map +1 -1
  48. package/dist/db/embedding-store.interface.d.ts +19 -0
  49. package/dist/db/embedding-store.interface.d.ts.map +1 -0
  50. package/dist/db/embedding-store.interface.js +7 -0
  51. package/dist/db/embedding-store.interface.js.map +1 -0
  52. package/dist/db/embedding-store.js +3 -1
  53. package/dist/db/embedding-store.js.map +1 -1
  54. package/dist/db/eval-store.d.ts +88 -0
  55. package/dist/db/eval-store.d.ts.map +1 -0
  56. package/dist/db/eval-store.js +408 -0
  57. package/dist/db/eval-store.js.map +1 -0
  58. package/dist/db/guardrail-store.d.ts +9 -0
  59. package/dist/db/guardrail-store.d.ts.map +1 -1
  60. package/dist/db/guardrail-store.js +57 -3
  61. package/dist/db/guardrail-store.js.map +1 -1
  62. package/dist/db/index.d.ts +7 -0
  63. package/dist/db/index.d.ts.map +1 -1
  64. package/dist/db/index.js +4 -12
  65. package/dist/db/index.js.map +1 -1
  66. package/dist/db/migrate.d.ts +5 -22
  67. package/dist/db/migrate.d.ts.map +1 -1
  68. package/dist/db/migrate.js +7 -637
  69. package/dist/db/migrate.js.map +1 -1
  70. package/dist/db/migrate.postgres.d.ts +16 -0
  71. package/dist/db/migrate.postgres.d.ts.map +1 -0
  72. package/dist/db/migrate.postgres.js +23 -0
  73. package/dist/db/migrate.postgres.js.map +1 -0
  74. package/dist/db/migrate.sqlite.d.ts +26 -0
  75. package/dist/db/migrate.sqlite.d.ts.map +1 -0
  76. package/dist/db/migrate.sqlite.js +920 -0
  77. package/dist/db/migrate.sqlite.js.map +1 -0
  78. package/dist/db/postgres-embedding-store.d.ts +23 -0
  79. package/dist/db/postgres-embedding-store.d.ts.map +1 -0
  80. package/dist/db/postgres-embedding-store.js +218 -0
  81. package/dist/db/postgres-embedding-store.js.map +1 -0
  82. package/dist/db/postgres-store.d.ts +80 -0
  83. package/dist/db/postgres-store.d.ts.map +1 -0
  84. package/dist/db/postgres-store.js +910 -0
  85. package/dist/db/postgres-store.js.map +1 -0
  86. package/dist/db/prompt-store.d.ts +57 -0
  87. package/dist/db/prompt-store.d.ts.map +1 -0
  88. package/dist/db/prompt-store.js +300 -0
  89. package/dist/db/prompt-store.js.map +1 -0
  90. package/dist/db/repositories/agent-repository.d.ts +21 -0
  91. package/dist/db/repositories/agent-repository.d.ts.map +1 -0
  92. package/dist/db/repositories/agent-repository.js +142 -0
  93. package/dist/db/repositories/agent-repository.js.map +1 -0
  94. package/dist/db/repositories/alert-repository.d.ts +27 -0
  95. package/dist/db/repositories/alert-repository.d.ts.map +1 -0
  96. package/dist/db/repositories/alert-repository.js +164 -0
  97. package/dist/db/repositories/alert-repository.js.map +1 -0
  98. package/dist/db/repositories/analytics-repository.d.ts +24 -0
  99. package/dist/db/repositories/analytics-repository.d.ts.map +1 -0
  100. package/dist/db/repositories/analytics-repository.js +147 -0
  101. package/dist/db/repositories/analytics-repository.js.map +1 -0
  102. package/dist/db/repositories/event-repository.d.ts +81 -0
  103. package/dist/db/repositories/event-repository.d.ts.map +1 -0
  104. package/dist/db/repositories/event-repository.js +331 -0
  105. package/dist/db/repositories/event-repository.js.map +1 -0
  106. package/dist/db/repositories/notification-channel-repository.d.ts +28 -0
  107. package/dist/db/repositories/notification-channel-repository.d.ts.map +1 -0
  108. package/dist/db/repositories/notification-channel-repository.js +151 -0
  109. package/dist/db/repositories/notification-channel-repository.js.map +1 -0
  110. package/dist/db/repositories/session-repository.d.ts +26 -0
  111. package/dist/db/repositories/session-repository.d.ts.map +1 -0
  112. package/dist/db/repositories/session-repository.js +240 -0
  113. package/dist/db/repositories/session-repository.js.map +1 -0
  114. package/dist/db/schema.postgres.d.ts +4681 -0
  115. package/dist/db/schema.postgres.d.ts.map +1 -0
  116. package/dist/db/schema.postgres.js +458 -0
  117. package/dist/db/schema.postgres.js.map +1 -0
  118. package/dist/db/schema.sqlite.d.ts +2221 -671
  119. package/dist/db/schema.sqlite.d.ts.map +1 -1
  120. package/dist/db/schema.sqlite.js +137 -2
  121. package/dist/db/schema.sqlite.js.map +1 -1
  122. package/dist/db/services/retention-service.d.ts +13 -0
  123. package/dist/db/services/retention-service.d.ts.map +1 -0
  124. package/dist/db/services/retention-service.js +48 -0
  125. package/dist/db/services/retention-service.js.map +1 -0
  126. package/dist/db/shared/query-helpers.d.ts +32 -0
  127. package/dist/db/shared/query-helpers.d.ts.map +1 -0
  128. package/dist/db/shared/query-helpers.js +180 -0
  129. package/dist/db/shared/query-helpers.js.map +1 -0
  130. package/dist/db/sqlite-store.d.ts +48 -55
  131. package/dist/db/sqlite-store.d.ts.map +1 -1
  132. package/dist/db/sqlite-store.js +78 -945
  133. package/dist/db/sqlite-store.js.map +1 -1
  134. package/dist/db/tenant-scoped-store.d.ts +18 -1
  135. package/dist/db/tenant-scoped-store.d.ts.map +1 -1
  136. package/dist/db/tenant-scoped-store.js +6 -0
  137. package/dist/db/tenant-scoped-store.js.map +1 -1
  138. package/dist/index.d.ts +28 -14
  139. package/dist/index.d.ts.map +1 -1
  140. package/dist/index.js +432 -97
  141. package/dist/index.js.map +1 -1
  142. package/dist/lib/alert-engine.d.ts +10 -0
  143. package/dist/lib/alert-engine.d.ts.map +1 -1
  144. package/dist/lib/alert-engine.js +73 -20
  145. package/dist/lib/alert-engine.js.map +1 -1
  146. package/dist/lib/audit-verify.d.ts +40 -0
  147. package/dist/lib/audit-verify.d.ts.map +1 -0
  148. package/dist/lib/audit-verify.js +128 -0
  149. package/dist/lib/audit-verify.js.map +1 -0
  150. package/dist/lib/audit.d.ts +37 -0
  151. package/dist/lib/audit.d.ts.map +1 -0
  152. package/dist/lib/audit.js +59 -0
  153. package/dist/lib/audit.js.map +1 -0
  154. package/dist/lib/budget-engine.d.ts +26 -0
  155. package/dist/lib/budget-engine.d.ts.map +1 -0
  156. package/dist/lib/budget-engine.js +201 -0
  157. package/dist/lib/budget-engine.js.map +1 -0
  158. package/dist/lib/compliance-export.d.ts +41 -0
  159. package/dist/lib/compliance-export.d.ts.map +1 -0
  160. package/dist/lib/compliance-export.js +124 -0
  161. package/dist/lib/compliance-export.js.map +1 -0
  162. package/dist/lib/compliance-report.d.ts +87 -0
  163. package/dist/lib/compliance-report.d.ts.map +1 -0
  164. package/dist/lib/compliance-report.js +148 -0
  165. package/dist/lib/compliance-report.js.map +1 -0
  166. package/dist/lib/context/retrieval.d.ts +5 -3
  167. package/dist/lib/context/retrieval.d.ts.map +1 -1
  168. package/dist/lib/context/retrieval.js +5 -2
  169. package/dist/lib/context/retrieval.js.map +1 -1
  170. package/dist/lib/cost-anomaly-detector.d.ts +23 -0
  171. package/dist/lib/cost-anomaly-detector.d.ts.map +1 -0
  172. package/dist/lib/cost-anomaly-detector.js +108 -0
  173. package/dist/lib/cost-anomaly-detector.js.map +1 -0
  174. package/dist/lib/db-resilience.d.ts +15 -0
  175. package/dist/lib/db-resilience.d.ts.map +1 -0
  176. package/dist/lib/db-resilience.js +49 -0
  177. package/dist/lib/db-resilience.js.map +1 -0
  178. package/dist/lib/diagnostics/cache.d.ts +29 -0
  179. package/dist/lib/diagnostics/cache.d.ts.map +1 -0
  180. package/dist/lib/diagnostics/cache.js +88 -0
  181. package/dist/lib/diagnostics/cache.js.map +1 -0
  182. package/dist/lib/diagnostics/context-builder.d.ts +41 -0
  183. package/dist/lib/diagnostics/context-builder.d.ts.map +1 -0
  184. package/dist/lib/diagnostics/context-builder.js +135 -0
  185. package/dist/lib/diagnostics/context-builder.js.map +1 -0
  186. package/dist/lib/diagnostics/index.d.ts +34 -0
  187. package/dist/lib/diagnostics/index.d.ts.map +1 -0
  188. package/dist/lib/diagnostics/index.js +223 -0
  189. package/dist/lib/diagnostics/index.js.map +1 -0
  190. package/dist/lib/diagnostics/llm-client.d.ts +24 -0
  191. package/dist/lib/diagnostics/llm-client.d.ts.map +1 -0
  192. package/dist/lib/diagnostics/llm-client.js +42 -0
  193. package/dist/lib/diagnostics/llm-client.js.map +1 -0
  194. package/dist/lib/diagnostics/prompt-templates.d.ts +18 -0
  195. package/dist/lib/diagnostics/prompt-templates.d.ts.map +1 -0
  196. package/dist/lib/diagnostics/prompt-templates.js +144 -0
  197. package/dist/lib/diagnostics/prompt-templates.js.map +1 -0
  198. package/dist/lib/diagnostics/providers/anthropic.d.ts +8 -0
  199. package/dist/lib/diagnostics/providers/anthropic.d.ts.map +1 -0
  200. package/dist/lib/diagnostics/providers/anthropic.js +79 -0
  201. package/dist/lib/diagnostics/providers/anthropic.js.map +1 -0
  202. package/dist/lib/diagnostics/providers/openai.d.ts +8 -0
  203. package/dist/lib/diagnostics/providers/openai.d.ts.map +1 -0
  204. package/dist/lib/diagnostics/providers/openai.js +70 -0
  205. package/dist/lib/diagnostics/providers/openai.js.map +1 -0
  206. package/dist/lib/diagnostics/providers/types.d.ts +23 -0
  207. package/dist/lib/diagnostics/providers/types.d.ts.map +1 -0
  208. package/dist/lib/diagnostics/providers/types.js +5 -0
  209. package/dist/lib/diagnostics/providers/types.js.map +1 -0
  210. package/dist/lib/diagnostics/response-parser.d.ts +60 -0
  211. package/dist/lib/diagnostics/response-parser.d.ts.map +1 -0
  212. package/dist/lib/diagnostics/response-parser.js +55 -0
  213. package/dist/lib/diagnostics/response-parser.js.map +1 -0
  214. package/dist/lib/diagnostics/types.d.ts +60 -0
  215. package/dist/lib/diagnostics/types.d.ts.map +1 -0
  216. package/dist/lib/diagnostics/types.js +7 -0
  217. package/dist/lib/diagnostics/types.js.map +1 -0
  218. package/dist/lib/embeddings/index.d.ts +6 -3
  219. package/dist/lib/embeddings/index.d.ts.map +1 -1
  220. package/dist/lib/embeddings/index.js +7 -15
  221. package/dist/lib/embeddings/index.js.map +1 -1
  222. package/dist/lib/embeddings/worker.d.ts +2 -2
  223. package/dist/lib/embeddings/worker.d.ts.map +1 -1
  224. package/dist/lib/embeddings/worker.js +3 -1
  225. package/dist/lib/embeddings/worker.js.map +1 -1
  226. package/dist/lib/error-sanitizer.d.ts +28 -0
  227. package/dist/lib/error-sanitizer.d.ts.map +1 -0
  228. package/dist/lib/error-sanitizer.js +106 -0
  229. package/dist/lib/error-sanitizer.js.map +1 -0
  230. package/dist/lib/eval/index.d.ts +15 -0
  231. package/dist/lib/eval/index.d.ts.map +1 -0
  232. package/dist/lib/eval/index.js +24 -0
  233. package/dist/lib/eval/index.js.map +1 -0
  234. package/dist/lib/eval/runner.d.ts +28 -0
  235. package/dist/lib/eval/runner.d.ts.map +1 -0
  236. package/dist/lib/eval/runner.js +260 -0
  237. package/dist/lib/eval/runner.js.map +1 -0
  238. package/dist/lib/eval/scorers/contains.d.ts +10 -0
  239. package/dist/lib/eval/scorers/contains.d.ts.map +1 -0
  240. package/dist/lib/eval/scorers/contains.js +33 -0
  241. package/dist/lib/eval/scorers/contains.js.map +1 -0
  242. package/dist/lib/eval/scorers/exact-match.d.ts +10 -0
  243. package/dist/lib/eval/scorers/exact-match.d.ts.map +1 -0
  244. package/dist/lib/eval/scorers/exact-match.js +33 -0
  245. package/dist/lib/eval/scorers/exact-match.js.map +1 -0
  246. package/dist/lib/eval/scorers/index.d.ts +20 -0
  247. package/dist/lib/eval/scorers/index.d.ts.map +1 -0
  248. package/dist/lib/eval/scorers/index.js +19 -0
  249. package/dist/lib/eval/scorers/index.js.map +1 -0
  250. package/dist/lib/eval/scorers/llm-judge.d.ts +22 -0
  251. package/dist/lib/eval/scorers/llm-judge.d.ts.map +1 -0
  252. package/dist/lib/eval/scorers/llm-judge.js +79 -0
  253. package/dist/lib/eval/scorers/llm-judge.js.map +1 -0
  254. package/dist/lib/eval/scorers/regex.d.ts +10 -0
  255. package/dist/lib/eval/scorers/regex.d.ts.map +1 -0
  256. package/dist/lib/eval/scorers/regex.js +36 -0
  257. package/dist/lib/eval/scorers/regex.js.map +1 -0
  258. package/dist/lib/guardrails/actions.d.ts +6 -0
  259. package/dist/lib/guardrails/actions.d.ts.map +1 -1
  260. package/dist/lib/guardrails/actions.js +82 -0
  261. package/dist/lib/guardrails/actions.js.map +1 -1
  262. package/dist/lib/guardrails/conditions.d.ts +47 -0
  263. package/dist/lib/guardrails/conditions.d.ts.map +1 -1
  264. package/dist/lib/guardrails/conditions.js +55 -10
  265. package/dist/lib/guardrails/conditions.js.map +1 -1
  266. package/dist/lib/guardrails/content-engine.d.ts +19 -0
  267. package/dist/lib/guardrails/content-engine.d.ts.map +1 -0
  268. package/dist/lib/guardrails/content-engine.js +154 -0
  269. package/dist/lib/guardrails/content-engine.js.map +1 -0
  270. package/dist/lib/guardrails/engine.d.ts +33 -0
  271. package/dist/lib/guardrails/engine.d.ts.map +1 -1
  272. package/dist/lib/guardrails/engine.js +37 -2
  273. package/dist/lib/guardrails/engine.js.map +1 -1
  274. package/dist/lib/guardrails/scanners/base-scanner.d.ts +23 -0
  275. package/dist/lib/guardrails/scanners/base-scanner.d.ts.map +1 -0
  276. package/dist/lib/guardrails/scanners/base-scanner.js +7 -0
  277. package/dist/lib/guardrails/scanners/base-scanner.js.map +1 -0
  278. package/dist/lib/guardrails/scanners/patterns/pii-patterns.d.ts +13 -0
  279. package/dist/lib/guardrails/scanners/patterns/pii-patterns.d.ts.map +1 -0
  280. package/dist/lib/guardrails/scanners/patterns/pii-patterns.js +49 -0
  281. package/dist/lib/guardrails/scanners/patterns/pii-patterns.js.map +1 -0
  282. package/dist/lib/guardrails/scanners/patterns/secret-patterns.d.ts +6 -0
  283. package/dist/lib/guardrails/scanners/patterns/secret-patterns.d.ts.map +1 -0
  284. package/dist/lib/guardrails/scanners/patterns/secret-patterns.js +69 -0
  285. package/dist/lib/guardrails/scanners/patterns/secret-patterns.js.map +1 -0
  286. package/dist/lib/guardrails/scanners/pii-scanner.d.ts +10 -0
  287. package/dist/lib/guardrails/scanners/pii-scanner.d.ts.map +1 -0
  288. package/dist/lib/guardrails/scanners/pii-scanner.js +57 -0
  289. package/dist/lib/guardrails/scanners/pii-scanner.js.map +1 -0
  290. package/dist/lib/guardrails/scanners/scanner-registry.d.ts +14 -0
  291. package/dist/lib/guardrails/scanners/scanner-registry.d.ts.map +1 -0
  292. package/dist/lib/guardrails/scanners/scanner-registry.js +51 -0
  293. package/dist/lib/guardrails/scanners/scanner-registry.js.map +1 -0
  294. package/dist/lib/guardrails/scanners/secrets-scanner.d.ts +9 -0
  295. package/dist/lib/guardrails/scanners/secrets-scanner.d.ts.map +1 -0
  296. package/dist/lib/guardrails/scanners/secrets-scanner.js +47 -0
  297. package/dist/lib/guardrails/scanners/secrets-scanner.js.map +1 -0
  298. package/dist/lib/logger.d.ts +8 -0
  299. package/dist/lib/logger.d.ts.map +1 -0
  300. package/dist/lib/logger.js +31 -0
  301. package/dist/lib/logger.js.map +1 -0
  302. package/dist/lib/lore-client.d.ts +128 -0
  303. package/dist/lib/lore-client.d.ts.map +1 -0
  304. package/dist/lib/lore-client.js +188 -0
  305. package/dist/lib/lore-client.js.map +1 -0
  306. package/dist/lib/mesh-client.d.ts +31 -0
  307. package/dist/lib/mesh-client.d.ts.map +1 -0
  308. package/dist/lib/mesh-client.js +72 -0
  309. package/dist/lib/mesh-client.js.map +1 -0
  310. package/dist/lib/notifications/grouping-buffer.d.ts +25 -0
  311. package/dist/lib/notifications/grouping-buffer.d.ts.map +1 -0
  312. package/dist/lib/notifications/grouping-buffer.js +73 -0
  313. package/dist/lib/notifications/grouping-buffer.js.map +1 -0
  314. package/dist/lib/notifications/provider.d.ts +10 -0
  315. package/dist/lib/notifications/provider.d.ts.map +1 -0
  316. package/dist/lib/notifications/provider.js +5 -0
  317. package/dist/lib/notifications/provider.js.map +1 -0
  318. package/dist/lib/notifications/providers/email.d.ts +14 -0
  319. package/dist/lib/notifications/providers/email.d.ts.map +1 -0
  320. package/dist/lib/notifications/providers/email.js +88 -0
  321. package/dist/lib/notifications/providers/email.js.map +1 -0
  322. package/dist/lib/notifications/providers/pagerduty.d.ts +16 -0
  323. package/dist/lib/notifications/providers/pagerduty.d.ts.map +1 -0
  324. package/dist/lib/notifications/providers/pagerduty.js +94 -0
  325. package/dist/lib/notifications/providers/pagerduty.js.map +1 -0
  326. package/dist/lib/notifications/providers/slack.d.ts +14 -0
  327. package/dist/lib/notifications/providers/slack.d.ts.map +1 -0
  328. package/dist/lib/notifications/providers/slack.js +106 -0
  329. package/dist/lib/notifications/providers/slack.js.map +1 -0
  330. package/dist/lib/notifications/providers/webhook.d.ts +16 -0
  331. package/dist/lib/notifications/providers/webhook.d.ts.map +1 -0
  332. package/dist/lib/notifications/providers/webhook.js +78 -0
  333. package/dist/lib/notifications/providers/webhook.js.map +1 -0
  334. package/dist/lib/notifications/router.d.ts +30 -0
  335. package/dist/lib/notifications/router.d.ts.map +1 -0
  336. package/dist/lib/notifications/router.js +137 -0
  337. package/dist/lib/notifications/router.js.map +1 -0
  338. package/dist/lib/notifications/ssrf.d.ts +13 -0
  339. package/dist/lib/notifications/ssrf.d.ts.map +1 -0
  340. package/dist/lib/notifications/ssrf.js +37 -0
  341. package/dist/lib/notifications/ssrf.js.map +1 -0
  342. package/dist/lib/optimization/analyzers/model-downgrade.d.ts +15 -0
  343. package/dist/lib/optimization/analyzers/model-downgrade.d.ts.map +1 -0
  344. package/dist/lib/optimization/analyzers/model-downgrade.js +58 -0
  345. package/dist/lib/optimization/analyzers/model-downgrade.js.map +1 -0
  346. package/dist/lib/optimization/analyzers/prompt-optimization.d.ts +17 -0
  347. package/dist/lib/optimization/analyzers/prompt-optimization.d.ts.map +1 -0
  348. package/dist/lib/optimization/analyzers/prompt-optimization.js +160 -0
  349. package/dist/lib/optimization/analyzers/prompt-optimization.js.map +1 -0
  350. package/dist/lib/optimization/analyzers/types.d.ts +23 -0
  351. package/dist/lib/optimization/analyzers/types.d.ts.map +1 -0
  352. package/dist/lib/optimization/analyzers/types.js +5 -0
  353. package/dist/lib/optimization/analyzers/types.js.map +1 -0
  354. package/dist/lib/optimization/classifier.d.ts +4 -3
  355. package/dist/lib/optimization/classifier.d.ts.map +1 -1
  356. package/dist/lib/optimization/classifier.js +15 -9
  357. package/dist/lib/optimization/classifier.js.map +1 -1
  358. package/dist/lib/optimization/cost-optimizer.d.ts +21 -0
  359. package/dist/lib/optimization/cost-optimizer.d.ts.map +1 -0
  360. package/dist/lib/optimization/cost-optimizer.js +114 -0
  361. package/dist/lib/optimization/cost-optimizer.js.map +1 -0
  362. package/dist/lib/optimization/engine.d.ts.map +1 -1
  363. package/dist/lib/optimization/engine.js +45 -6
  364. package/dist/lib/optimization/engine.js.map +1 -1
  365. package/dist/lib/optimization/forecast.d.ts +39 -0
  366. package/dist/lib/optimization/forecast.d.ts.map +1 -0
  367. package/dist/lib/optimization/forecast.js +128 -0
  368. package/dist/lib/optimization/forecast.js.map +1 -0
  369. package/dist/lib/secrets.d.ts +30 -0
  370. package/dist/lib/secrets.d.ts.map +1 -0
  371. package/dist/lib/secrets.js +103 -0
  372. package/dist/lib/secrets.js.map +1 -0
  373. package/dist/lib/threshold-monitor.d.ts +53 -0
  374. package/dist/lib/threshold-monitor.d.ts.map +1 -0
  375. package/dist/lib/threshold-monitor.js +112 -0
  376. package/dist/lib/threshold-monitor.js.map +1 -0
  377. package/dist/middleware/audit.d.ts +16 -0
  378. package/dist/middleware/audit.d.ts.map +1 -0
  379. package/dist/middleware/audit.js +16 -0
  380. package/dist/middleware/audit.js.map +1 -0
  381. package/dist/middleware/auth-errors.d.ts +67 -0
  382. package/dist/middleware/auth-errors.d.ts.map +1 -0
  383. package/dist/middleware/auth-errors.js +84 -0
  384. package/dist/middleware/auth-errors.js.map +1 -0
  385. package/dist/middleware/auth.d.ts +5 -2
  386. package/dist/middleware/auth.d.ts.map +1 -1
  387. package/dist/middleware/auth.js +44 -17
  388. package/dist/middleware/auth.js.map +1 -1
  389. package/dist/middleware/body-limit.d.ts +9 -0
  390. package/dist/middleware/body-limit.d.ts.map +1 -0
  391. package/dist/middleware/body-limit.js +15 -0
  392. package/dist/middleware/body-limit.js.map +1 -0
  393. package/dist/middleware/cors-config.d.ts +30 -0
  394. package/dist/middleware/cors-config.d.ts.map +1 -0
  395. package/dist/middleware/cors-config.js +55 -0
  396. package/dist/middleware/cors-config.js.map +1 -0
  397. package/dist/middleware/rate-limit.d.ts +9 -0
  398. package/dist/middleware/rate-limit.d.ts.map +1 -0
  399. package/dist/middleware/rate-limit.js +56 -0
  400. package/dist/middleware/rate-limit.js.map +1 -0
  401. package/dist/middleware/rbac.d.ts +30 -0
  402. package/dist/middleware/rbac.d.ts.map +1 -0
  403. package/dist/middleware/rbac.js +87 -0
  404. package/dist/middleware/rbac.js.map +1 -0
  405. package/dist/middleware/security-headers.d.ts +12 -0
  406. package/dist/middleware/security-headers.d.ts.map +1 -0
  407. package/dist/middleware/security-headers.js +57 -0
  408. package/dist/middleware/security-headers.js.map +1 -0
  409. package/dist/middleware/unified-auth.d.ts +49 -0
  410. package/dist/middleware/unified-auth.d.ts.map +1 -0
  411. package/dist/middleware/unified-auth.js +246 -0
  412. package/dist/middleware/unified-auth.js.map +1 -0
  413. package/dist/middleware/validation.d.ts +31 -0
  414. package/dist/middleware/validation.d.ts.map +1 -0
  415. package/dist/middleware/validation.js +45 -0
  416. package/dist/middleware/validation.js.map +1 -0
  417. package/dist/routes/alerts.d.ts.map +1 -1
  418. package/dist/routes/alerts.js +4 -3
  419. package/dist/routes/alerts.js.map +1 -1
  420. package/dist/routes/analytics.d.ts +2 -1
  421. package/dist/routes/analytics.d.ts.map +1 -1
  422. package/dist/routes/analytics.js +175 -95
  423. package/dist/routes/analytics.js.map +1 -1
  424. package/dist/routes/api-keys.d.ts +5 -0
  425. package/dist/routes/api-keys.d.ts.map +1 -1
  426. package/dist/routes/api-keys.js +89 -8
  427. package/dist/routes/api-keys.js.map +1 -1
  428. package/dist/routes/audit-verify.d.ts +12 -0
  429. package/dist/routes/audit-verify.d.ts.map +1 -0
  430. package/dist/routes/audit-verify.js +73 -0
  431. package/dist/routes/audit-verify.js.map +1 -0
  432. package/dist/routes/audit.d.ts +4 -6
  433. package/dist/routes/audit.d.ts.map +1 -1
  434. package/dist/routes/audit.js +54 -157
  435. package/dist/routes/audit.js.map +1 -1
  436. package/dist/routes/auth.d.ts +21 -0
  437. package/dist/routes/auth.d.ts.map +1 -0
  438. package/dist/routes/auth.js +235 -0
  439. package/dist/routes/auth.js.map +1 -0
  440. package/dist/routes/benchmarks.d.ts.map +1 -1
  441. package/dist/routes/benchmarks.js +63 -11
  442. package/dist/routes/benchmarks.js.map +1 -1
  443. package/dist/routes/capabilities-top.d.ts.map +1 -1
  444. package/dist/routes/capabilities-top.js +1 -4
  445. package/dist/routes/capabilities-top.js.map +1 -1
  446. package/dist/routes/capabilities.d.ts.map +1 -1
  447. package/dist/routes/capabilities.js +1 -7
  448. package/dist/routes/capabilities.js.map +1 -1
  449. package/dist/routes/compliance.d.ts +17 -0
  450. package/dist/routes/compliance.d.ts.map +1 -0
  451. package/dist/routes/compliance.js +151 -0
  452. package/dist/routes/compliance.js.map +1 -0
  453. package/dist/routes/config.d.ts +1 -13
  454. package/dist/routes/config.d.ts.map +1 -1
  455. package/dist/routes/context.d.ts.map +1 -1
  456. package/dist/routes/context.js +6 -5
  457. package/dist/routes/context.js.map +1 -1
  458. package/dist/routes/cost-budgets.d.ts +20 -0
  459. package/dist/routes/cost-budgets.d.ts.map +1 -0
  460. package/dist/routes/cost-budgets.js +194 -0
  461. package/dist/routes/cost-budgets.js.map +1 -0
  462. package/dist/routes/delegation.d.ts.map +1 -1
  463. package/dist/routes/delegation.js +67 -41
  464. package/dist/routes/delegation.js.map +1 -1
  465. package/dist/routes/delegations-top.d.ts.map +1 -1
  466. package/dist/routes/delegations-top.js +1 -3
  467. package/dist/routes/delegations-top.js.map +1 -1
  468. package/dist/routes/diagnose.d.ts +16 -0
  469. package/dist/routes/diagnose.d.ts.map +1 -0
  470. package/dist/routes/diagnose.js +82 -0
  471. package/dist/routes/diagnose.js.map +1 -0
  472. package/dist/routes/discovery.d.ts.map +1 -1
  473. package/dist/routes/discovery.js +50 -38
  474. package/dist/routes/discovery.js.map +1 -1
  475. package/dist/routes/eval.d.ts +24 -0
  476. package/dist/routes/eval.d.ts.map +1 -0
  477. package/dist/routes/eval.js +281 -0
  478. package/dist/routes/eval.js.map +1 -0
  479. package/dist/routes/events.d.ts.map +1 -1
  480. package/dist/routes/events.js +11 -6
  481. package/dist/routes/events.js.map +1 -1
  482. package/dist/routes/guardrails.d.ts +2 -1
  483. package/dist/routes/guardrails.d.ts.map +1 -1
  484. package/dist/routes/guardrails.js +85 -14
  485. package/dist/routes/guardrails.js.map +1 -1
  486. package/dist/routes/health.d.ts +14 -11
  487. package/dist/routes/health.d.ts.map +1 -1
  488. package/dist/routes/health.js +181 -61
  489. package/dist/routes/health.js.map +1 -1
  490. package/dist/routes/lore-proxy.d.ts +13 -0
  491. package/dist/routes/lore-proxy.d.ts.map +1 -0
  492. package/dist/routes/lore-proxy.js +229 -0
  493. package/dist/routes/lore-proxy.js.map +1 -0
  494. package/dist/routes/mesh-proxy.d.ts +7 -0
  495. package/dist/routes/mesh-proxy.d.ts.map +1 -0
  496. package/dist/routes/mesh-proxy.js +94 -0
  497. package/dist/routes/mesh-proxy.js.map +1 -0
  498. package/dist/routes/notifications.d.ts +19 -0
  499. package/dist/routes/notifications.d.ts.map +1 -0
  500. package/dist/routes/notifications.js +129 -0
  501. package/dist/routes/notifications.js.map +1 -0
  502. package/dist/routes/optimize.d.ts.map +1 -1
  503. package/dist/routes/optimize.js +44 -0
  504. package/dist/routes/optimize.js.map +1 -1
  505. package/dist/routes/otlp.d.ts +17 -0
  506. package/dist/routes/otlp.d.ts.map +1 -0
  507. package/dist/routes/otlp.js +544 -0
  508. package/dist/routes/otlp.js.map +1 -0
  509. package/dist/routes/prompts.d.ts +21 -0
  510. package/dist/routes/prompts.d.ts.map +1 -0
  511. package/dist/routes/prompts.js +173 -0
  512. package/dist/routes/prompts.js.map +1 -0
  513. package/dist/routes/recall.d.ts.map +1 -1
  514. package/dist/routes/recall.js +6 -4
  515. package/dist/routes/recall.js.map +1 -1
  516. package/dist/routes/replay.d.ts.map +1 -1
  517. package/dist/routes/replay.js +2 -1
  518. package/dist/routes/replay.js.map +1 -1
  519. package/dist/routes/server-info.d.ts +9 -0
  520. package/dist/routes/server-info.d.ts.map +1 -0
  521. package/dist/routes/server-info.js +18 -0
  522. package/dist/routes/server-info.js.map +1 -0
  523. package/dist/routes/sessions.d.ts +7 -7
  524. package/dist/routes/sessions.d.ts.map +1 -1
  525. package/dist/routes/sessions.js +112 -35
  526. package/dist/routes/sessions.js.map +1 -1
  527. package/dist/routes/stats.d.ts.map +1 -1
  528. package/dist/routes/stats.js +40 -0
  529. package/dist/routes/stats.js.map +1 -1
  530. package/dist/routes/stream.d.ts +2 -2
  531. package/dist/routes/stream.d.ts.map +1 -1
  532. package/dist/routes/stream.js +7 -11
  533. package/dist/routes/stream.js.map +1 -1
  534. package/dist/routes/tenant-helper.d.ts +15 -10
  535. package/dist/routes/tenant-helper.d.ts.map +1 -1
  536. package/dist/routes/tenant-helper.js +36 -22
  537. package/dist/routes/tenant-helper.js.map +1 -1
  538. package/dist/routes/trust.d.ts.map +1 -1
  539. package/dist/routes/trust.js +1 -3
  540. package/dist/routes/trust.js.map +1 -1
  541. package/dist/schemas/api-keys.d.ts +11 -0
  542. package/dist/schemas/api-keys.d.ts.map +1 -0
  543. package/dist/schemas/api-keys.js +10 -0
  544. package/dist/schemas/api-keys.js.map +1 -0
  545. package/dist/schemas/common.d.ts +34 -0
  546. package/dist/schemas/common.d.ts.map +1 -0
  547. package/dist/schemas/common.js +43 -0
  548. package/dist/schemas/common.js.map +1 -0
  549. package/dist/schemas/delegation.d.ts +23 -0
  550. package/dist/schemas/delegation.d.ts.map +1 -0
  551. package/dist/schemas/delegation.js +22 -0
  552. package/dist/schemas/delegation.js.map +1 -0
  553. package/dist/schemas/discovery.d.ts +17 -0
  554. package/dist/schemas/discovery.d.ts.map +1 -0
  555. package/dist/schemas/discovery.js +15 -0
  556. package/dist/schemas/discovery.js.map +1 -0
  557. package/dist/schemas/health.d.ts +75 -0
  558. package/dist/schemas/health.d.ts.map +1 -0
  559. package/dist/schemas/health.js +55 -0
  560. package/dist/schemas/health.js.map +1 -0
  561. package/dist/schemas/index.d.ts +6 -0
  562. package/dist/schemas/index.d.ts.map +1 -0
  563. package/dist/schemas/index.js +6 -0
  564. package/dist/schemas/index.js.map +1 -0
  565. package/dist/schemas/sessions.d.ts +67 -0
  566. package/dist/schemas/sessions.d.ts.map +1 -0
  567. package/dist/schemas/sessions.js +58 -0
  568. package/dist/schemas/sessions.js.map +1 -0
  569. package/dist/services/delegation-service.d.ts +1 -4
  570. package/dist/services/delegation-service.d.ts.map +1 -1
  571. package/dist/services/delegation-service.js +5 -31
  572. package/dist/services/delegation-service.js.map +1 -1
  573. package/package.json +29 -19
  574. package/dist/db/lesson-store.d.ts +0 -57
  575. package/dist/db/lesson-store.d.ts.map +0 -1
  576. package/dist/db/lesson-store.js +0 -217
  577. package/dist/db/lesson-store.js.map +0 -1
  578. package/dist/lib/embeddings/local.d.ts +0 -15
  579. package/dist/lib/embeddings/local.d.ts.map +0 -1
  580. package/dist/lib/embeddings/local.js +0 -65
  581. package/dist/lib/embeddings/local.js.map +0 -1
  582. package/dist/lib/redaction/human-review-layer.d.ts +0 -37
  583. package/dist/lib/redaction/human-review-layer.d.ts.map +0 -1
  584. package/dist/lib/redaction/human-review-layer.js +0 -62
  585. package/dist/lib/redaction/human-review-layer.js.map +0 -1
  586. package/dist/lib/redaction/index.d.ts +0 -12
  587. package/dist/lib/redaction/index.d.ts.map +0 -1
  588. package/dist/lib/redaction/index.js +0 -12
  589. package/dist/lib/redaction/index.js.map +0 -1
  590. package/dist/lib/redaction/pii-detection-layer.d.ts +0 -30
  591. package/dist/lib/redaction/pii-detection-layer.d.ts.map +0 -1
  592. package/dist/lib/redaction/pii-detection-layer.js +0 -183
  593. package/dist/lib/redaction/pii-detection-layer.js.map +0 -1
  594. package/dist/lib/redaction/pipeline.d.ts +0 -26
  595. package/dist/lib/redaction/pipeline.d.ts.map +0 -1
  596. package/dist/lib/redaction/pipeline.js +0 -91
  597. package/dist/lib/redaction/pipeline.js.map +0 -1
  598. package/dist/lib/redaction/secret-detection-layer.d.ts +0 -10
  599. package/dist/lib/redaction/secret-detection-layer.d.ts.map +0 -1
  600. package/dist/lib/redaction/secret-detection-layer.js +0 -79
  601. package/dist/lib/redaction/secret-detection-layer.js.map +0 -1
  602. package/dist/lib/redaction/secret-patterns.d.ts +0 -29
  603. package/dist/lib/redaction/secret-patterns.d.ts.map +0 -1
  604. package/dist/lib/redaction/secret-patterns.js +0 -133
  605. package/dist/lib/redaction/secret-patterns.js.map +0 -1
  606. package/dist/lib/redaction/semantic-denylist-layer.d.ts +0 -10
  607. package/dist/lib/redaction/semantic-denylist-layer.d.ts.map +0 -1
  608. package/dist/lib/redaction/semantic-denylist-layer.js +0 -64
  609. package/dist/lib/redaction/semantic-denylist-layer.js.map +0 -1
  610. package/dist/lib/redaction/tenant-deidentification-layer.d.ts +0 -10
  611. package/dist/lib/redaction/tenant-deidentification-layer.d.ts.map +0 -1
  612. package/dist/lib/redaction/tenant-deidentification-layer.js +0 -64
  613. package/dist/lib/redaction/tenant-deidentification-layer.js.map +0 -1
  614. package/dist/lib/redaction/url-path-scrubbing-layer.d.ts +0 -14
  615. package/dist/lib/redaction/url-path-scrubbing-layer.d.ts.map +0 -1
  616. package/dist/lib/redaction/url-path-scrubbing-layer.js +0 -156
  617. package/dist/lib/redaction/url-path-scrubbing-layer.js.map +0 -1
  618. package/dist/routes/community.d.ts +0 -24
  619. package/dist/routes/community.d.ts.map +0 -1
  620. package/dist/routes/community.js +0 -272
  621. package/dist/routes/community.js.map +0 -1
  622. package/dist/routes/lessons.d.ts +0 -19
  623. package/dist/routes/lessons.d.ts.map +0 -1
  624. package/dist/routes/lessons.js +0 -164
  625. package/dist/routes/lessons.js.map +0 -1
  626. package/dist/routes/redaction-test.d.ts +0 -14
  627. package/dist/routes/redaction-test.d.ts.map +0 -1
  628. package/dist/routes/redaction-test.js +0 -33
  629. package/dist/routes/redaction-test.js.map +0 -1
  630. package/dist/services/community-service.d.ts +0 -283
  631. package/dist/services/community-service.d.ts.map +0 -1
  632. package/dist/services/community-service.js +0 -816
  633. package/dist/services/community-service.js.map +0 -1
@@ -1,992 +1,125 @@
1
1
  /**
2
- * SQLite implementation of IEventStore.
2
+ * SQLite implementation of IEventStore — thin facade.
3
3
  *
4
- * Write operations (Story 3.4):
5
- * - insertEvents()batch insert in single transaction
6
- * - Auto-create/update session records on event insert
7
- * - Auto-create agent records on first event
8
- * - Session status management
9
- *
10
- * Read operations (Story 3.5):
11
- * - queryEvents(), getEvent(), getSessionTimeline(), countEvents()
12
- * - querySessions(), getSession()
13
- * - listAgents(), getAgent()
14
- * - getAnalytics(), getStats()
15
- */
16
- import { eq, and, gte, lte, inArray, desc, asc, sql, count as drizzleCount } from 'drizzle-orm';
17
- import { computeEventHash } from '@agentlensai/core';
18
- import { events, sessions, agents, alertRules, alertHistory } from './schema.sqlite.js';
19
- import { HashChainError, NotFoundError } from './errors.js';
20
- // ─── Helpers ───────────────────────────────────────────────
21
- /**
22
- * Safe JSON.parse that returns a fallback on any error instead of throwing.
4
+ * Delegates to focused repository classes (Story S-7.5):
5
+ * - EventRepositoryevent CRUD
6
+ * - SessionRepository session CRUD
7
+ * - AgentRepository agent CRUD
8
+ * - AlertRepository alert rules + history
9
+ * - AnalyticsRepository — analytics and stats
10
+ * - RetentionService data retention/cleanup
23
11
  */
24
- export function safeJsonParse(raw, fallback) {
25
- try {
26
- return JSON.parse(raw);
27
- }
28
- catch {
29
- return fallback;
30
- }
31
- }
12
+ import { EventRepository } from './repositories/event-repository.js';
13
+ import { SessionRepository } from './repositories/session-repository.js';
14
+ import { AgentRepository } from './repositories/agent-repository.js';
15
+ import { AlertRepository } from './repositories/alert-repository.js';
16
+ import { AnalyticsRepository } from './repositories/analytics-repository.js';
17
+ import { RetentionService } from './services/retention-service.js';
18
+ // Re-export for backward compatibility
19
+ export { safeJsonParse } from './shared/query-helpers.js';
32
20
  export class SqliteEventStore {
33
21
  db;
22
+ eventRepo;
23
+ sessionRepo;
24
+ agentRepo;
25
+ alertRepo;
26
+ analyticsRepo;
27
+ retentionService;
34
28
  constructor(db) {
35
29
  this.db = db;
36
- }
37
- /**
38
- * Defense-in-depth: warn when a query method is called without tenantId.
39
- * This helps catch missing tenant scoping in call chains.
40
- */
41
- warnIfNoTenant(method, tenantId) {
42
- if (tenantId === undefined) {
43
- console.warn(`[SqliteEventStore] ${method}() called without tenantId — query is unscoped. ` +
44
- `Ensure tenant isolation is applied upstream (via TenantScopedStore).`);
45
- }
46
- }
47
- // ─── Events — Write ────────────────────────────────────────
30
+ this.eventRepo = new EventRepository(db);
31
+ this.sessionRepo = new SessionRepository(db);
32
+ this.agentRepo = new AgentRepository(db);
33
+ this.alertRepo = new AlertRepository(db);
34
+ this.analyticsRepo = new AnalyticsRepository(db);
35
+ this.retentionService = new RetentionService(db);
36
+ }
37
+ // ─── Events ────────────────────────────────────────────────
48
38
  async insertEvents(eventList) {
49
- if (eventList.length === 0)
50
- return;
51
- // Batch insert in a single transaction for atomicity and performance
52
- this.db.transaction((tx) => {
53
- // CRITICAL 3: Validate hash chain before inserting
54
- const firstEvent = eventList[0];
55
- const tenantId = firstEvent.tenantId ?? 'default';
56
- // Check if the first event already exists (idempotent re-insert)
57
- const existingFirst = tx
58
- .select({ id: events.id })
59
- .from(events)
60
- .where(eq(events.id, firstEvent.id))
61
- .get();
62
- if (!existingFirst) {
63
- // Fresh insert — validate chain continuity against stored events
64
- const lastStoredEvent = tx
65
- .select({ hash: events.hash })
66
- .from(events)
67
- .where(and(eq(events.sessionId, firstEvent.sessionId), eq(events.tenantId, tenantId)))
68
- .orderBy(desc(events.timestamp), desc(events.id))
69
- .limit(1)
70
- .get();
71
- const lastStoredHash = lastStoredEvent?.hash ?? null;
72
- // Validate that the first event's prevHash matches the latest stored hash
73
- if (firstEvent.prevHash !== lastStoredHash) {
74
- throw new HashChainError(`Chain continuity broken: event ${firstEvent.id} has prevHash=${firstEvent.prevHash} but last stored hash is ${lastStoredHash}`);
75
- }
76
- }
77
- // Validate each event's hash and intra-batch chain links
78
- for (let i = 0; i < eventList.length; i++) {
79
- const event = eventList[i];
80
- // Verify intra-batch chain continuity (for events after the first)
81
- if (i > 0) {
82
- const prevEvent = eventList[i - 1];
83
- if (event.prevHash !== prevEvent.hash) {
84
- throw new HashChainError(`Chain continuity broken within batch: event ${event.id} has prevHash=${event.prevHash} but previous event hash is ${prevEvent.hash}`);
85
- }
86
- }
87
- // Recompute hash server-side and verify
88
- const recomputedHash = computeEventHash({
89
- id: event.id,
90
- timestamp: event.timestamp,
91
- sessionId: event.sessionId,
92
- agentId: event.agentId,
93
- eventType: event.eventType,
94
- severity: event.severity,
95
- payload: event.payload,
96
- metadata: event.metadata,
97
- prevHash: event.prevHash,
98
- });
99
- if (event.hash !== recomputedHash) {
100
- throw new HashChainError(`Hash mismatch for event ${event.id}: supplied=${event.hash}, computed=${recomputedHash}`);
101
- }
102
- }
103
- for (const event of eventList) {
104
- // CRITICAL 4: Idempotent event insertion — ON CONFLICT DO NOTHING
105
- tx.insert(events)
106
- .values({
107
- id: event.id,
108
- timestamp: event.timestamp,
109
- sessionId: event.sessionId,
110
- agentId: event.agentId,
111
- eventType: event.eventType,
112
- severity: event.severity,
113
- payload: JSON.stringify(event.payload),
114
- metadata: JSON.stringify(event.metadata),
115
- prevHash: event.prevHash,
116
- hash: event.hash,
117
- tenantId,
118
- })
119
- .onConflictDoNothing({ target: events.id })
120
- .run();
121
- // Handle session management
122
- this._handleSessionUpdate(tx, event, tenantId);
123
- // Handle agent auto-creation
124
- this._handleAgentUpsert(tx, event, tenantId);
125
- }
126
- });
127
- }
128
- _handleSessionUpdate(tx, event, tenantId) {
129
- if (event.eventType === 'session_started') {
130
- // Create new session
131
- const payload = event.payload;
132
- const tags = payload.tags ?? [];
133
- const agentName = payload.agentName ?? undefined;
134
- // CRITICAL 4: Use INSERT ... ON CONFLICT DO UPDATE for sessions
135
- tx.insert(sessions)
136
- .values({
137
- id: event.sessionId,
138
- agentId: event.agentId,
139
- agentName: agentName,
140
- startedAt: event.timestamp,
141
- status: 'active',
142
- eventCount: 1,
143
- toolCallCount: 0,
144
- errorCount: 0,
145
- totalCostUsd: 0,
146
- tags: JSON.stringify(tags),
147
- tenantId,
148
- })
149
- .onConflictDoUpdate({
150
- target: [sessions.id, sessions.tenantId],
151
- set: {
152
- agentName: agentName ?? sql `coalesce(${sessions.agentName}, NULL)`,
153
- status: 'active',
154
- eventCount: sql `${sessions.eventCount} + 1`,
155
- tags: tags.length > 0 ? JSON.stringify(tags) : sql `${sessions.tags}`,
156
- },
157
- })
158
- .run();
159
- return;
160
- }
161
- // For non-session_started events, ensure a session exists first (upsert)
162
- tx.insert(sessions)
163
- .values({
164
- id: event.sessionId,
165
- agentId: event.agentId,
166
- startedAt: event.timestamp,
167
- status: 'active',
168
- eventCount: 0,
169
- toolCallCount: 0,
170
- errorCount: 0,
171
- totalCostUsd: 0,
172
- tags: '[]',
173
- tenantId,
174
- })
175
- .onConflictDoNothing({ target: [sessions.id, sessions.tenantId] })
176
- .run();
177
- // Build incremental updates
178
- const isToolCall = event.eventType === 'tool_call';
179
- const isError = event.severity === 'error' ||
180
- event.severity === 'critical' ||
181
- event.eventType === 'tool_error';
182
- const isCost = event.eventType === 'cost_tracked';
183
- const isLlmResponse = event.eventType === 'llm_response';
184
- const costPayload = event.payload;
185
- const costUsd = isCost ? (Number(costPayload.costUsd) || 0) : 0;
186
- const llmCostUsd = isLlmResponse ? (Number(costPayload.costUsd) || 0) : 0;
187
- const llmUsage = isLlmResponse ? costPayload.usage : undefined;
188
- const llmInputTokens = llmUsage ? (Number(llmUsage.inputTokens) || 0) : 0;
189
- const llmOutputTokens = llmUsage ? (Number(llmUsage.outputTokens) || 0) : 0;
190
- if (event.eventType === 'session_ended') {
191
- const payload = event.payload;
192
- const reason = payload.reason;
193
- const status = reason === 'error' ? 'error' : 'completed';
194
- tx.update(sessions)
195
- .set({
196
- endedAt: event.timestamp,
197
- status: status,
198
- eventCount: sql `${sessions.eventCount} + 1`,
199
- errorCount: isError
200
- ? sql `${sessions.errorCount} + 1`
201
- : sessions.errorCount,
202
- })
203
- .where(and(eq(sessions.id, event.sessionId), eq(sessions.tenantId, tenantId)))
204
- .run();
205
- return;
206
- }
207
- // Regular event — increment counters
208
- tx.update(sessions)
209
- .set({
210
- eventCount: sql `${sessions.eventCount} + 1`,
211
- toolCallCount: isToolCall
212
- ? sql `${sessions.toolCallCount} + 1`
213
- : sessions.toolCallCount,
214
- errorCount: isError
215
- ? sql `${sessions.errorCount} + 1`
216
- : sessions.errorCount,
217
- totalCostUsd: isCost
218
- ? sql `${sessions.totalCostUsd} + ${costUsd}`
219
- : isLlmResponse
220
- ? sql `${sessions.totalCostUsd} + ${llmCostUsd}`
221
- : sessions.totalCostUsd,
222
- llmCallCount: isLlmResponse
223
- ? sql `${sessions.llmCallCount} + 1`
224
- : sessions.llmCallCount,
225
- totalInputTokens: isLlmResponse
226
- ? sql `${sessions.totalInputTokens} + ${llmInputTokens}`
227
- : sessions.totalInputTokens,
228
- totalOutputTokens: isLlmResponse
229
- ? sql `${sessions.totalOutputTokens} + ${llmOutputTokens}`
230
- : sessions.totalOutputTokens,
231
- })
232
- .where(and(eq(sessions.id, event.sessionId), eq(sessions.tenantId, tenantId)))
233
- .run();
234
- }
235
- _handleAgentUpsert(tx, event, tenantId) {
236
- // CRITICAL 4: Use INSERT ... ON CONFLICT DO UPDATE for agents
237
- // Agents are scoped per tenant — use composite key (id + tenant_id)
238
- const payload = event.payload;
239
- const agentName = payload.agentName ?? event.agentId;
240
- tx.insert(agents)
241
- .values({
242
- id: event.agentId,
243
- name: agentName,
244
- firstSeenAt: event.timestamp,
245
- lastSeenAt: event.timestamp,
246
- sessionCount: event.eventType === 'session_started' ? 1 : 0,
247
- tenantId,
248
- })
249
- .onConflictDoUpdate({
250
- target: [agents.id, agents.tenantId],
251
- set: {
252
- lastSeenAt: event.timestamp,
253
- sessionCount: event.eventType === 'session_started'
254
- ? sql `${agents.sessionCount} + 1`
255
- : agents.sessionCount,
256
- },
257
- })
258
- .run();
259
- }
260
- // ─── Sessions — Write ──────────────────────────────────────
261
- async upsertSession(session) {
262
- const tenantId = session.tenantId ?? 'default';
263
- const existing = this.db
264
- .select()
265
- .from(sessions)
266
- .where(and(eq(sessions.id, session.id), eq(sessions.tenantId, tenantId)))
267
- .get();
268
- if (existing) {
269
- const updates = {};
270
- if (session.agentId !== undefined)
271
- updates.agentId = session.agentId;
272
- if (session.agentName !== undefined)
273
- updates.agentName = session.agentName;
274
- if (session.startedAt !== undefined)
275
- updates.startedAt = session.startedAt;
276
- if (session.endedAt !== undefined)
277
- updates.endedAt = session.endedAt;
278
- if (session.status !== undefined)
279
- updates.status = session.status;
280
- if (session.eventCount !== undefined)
281
- updates.eventCount = session.eventCount;
282
- if (session.toolCallCount !== undefined)
283
- updates.toolCallCount = session.toolCallCount;
284
- if (session.errorCount !== undefined)
285
- updates.errorCount = session.errorCount;
286
- if (session.totalCostUsd !== undefined)
287
- updates.totalCostUsd = session.totalCostUsd;
288
- if (session.llmCallCount !== undefined)
289
- updates.llmCallCount = session.llmCallCount;
290
- if (session.totalInputTokens !== undefined)
291
- updates.totalInputTokens = session.totalInputTokens;
292
- if (session.totalOutputTokens !== undefined)
293
- updates.totalOutputTokens = session.totalOutputTokens;
294
- if (session.tags !== undefined)
295
- updates.tags = JSON.stringify(session.tags);
296
- if (Object.keys(updates).length > 0) {
297
- this.db
298
- .update(sessions)
299
- .set(updates)
300
- .where(and(eq(sessions.id, session.id), eq(sessions.tenantId, tenantId)))
301
- .run();
302
- }
303
- }
304
- else {
305
- this.db
306
- .insert(sessions)
307
- .values({
308
- id: session.id,
309
- agentId: session.agentId ?? '',
310
- startedAt: session.startedAt ?? new Date().toISOString(),
311
- status: session.status ?? 'active',
312
- agentName: session.agentName,
313
- endedAt: session.endedAt,
314
- eventCount: session.eventCount ?? 0,
315
- toolCallCount: session.toolCallCount ?? 0,
316
- errorCount: session.errorCount ?? 0,
317
- totalCostUsd: session.totalCostUsd ?? 0,
318
- llmCallCount: session.llmCallCount ?? 0,
319
- totalInputTokens: session.totalInputTokens ?? 0,
320
- totalOutputTokens: session.totalOutputTokens ?? 0,
321
- tags: JSON.stringify(session.tags ?? []),
322
- tenantId,
323
- })
324
- .run();
325
- }
326
- }
327
- // ─── Agents — Write ────────────────────────────────────────
328
- async upsertAgent(agent) {
329
- const tenantId = agent.tenantId ?? 'default';
330
- const existing = this.db
331
- .select()
332
- .from(agents)
333
- .where(and(eq(agents.id, agent.id), eq(agents.tenantId, tenantId)))
334
- .get();
335
- if (existing) {
336
- const updates = {};
337
- if (agent.name !== undefined)
338
- updates.name = agent.name;
339
- if (agent.description !== undefined)
340
- updates.description = agent.description;
341
- if (agent.lastSeenAt !== undefined)
342
- updates.lastSeenAt = agent.lastSeenAt;
343
- if (agent.sessionCount !== undefined)
344
- updates.sessionCount = agent.sessionCount;
345
- if (Object.keys(updates).length > 0) {
346
- this.db
347
- .update(agents)
348
- .set(updates)
349
- .where(and(eq(agents.id, agent.id), eq(agents.tenantId, tenantId)))
350
- .run();
351
- }
352
- }
353
- else {
354
- const now = new Date().toISOString();
355
- this.db
356
- .insert(agents)
357
- .values({
358
- id: agent.id,
359
- name: agent.name ?? agent.id,
360
- description: agent.description,
361
- firstSeenAt: agent.firstSeenAt ?? now,
362
- lastSeenAt: agent.lastSeenAt ?? now,
363
- sessionCount: agent.sessionCount ?? 0,
364
- tenantId,
365
- })
366
- .run();
367
- }
39
+ this.eventRepo.insertEvents(eventList, (tx, event, tenantId) => this.sessionRepo.handleSessionUpdate(tx, event, tenantId), (tx, event, tenantId) => this.agentRepo.handleAgentUpsert(tx, event, tenantId));
368
40
  }
369
- // ─── Agents — Pause/Override (B1 — Story 1.2) ──────────────
370
- /**
371
- * Pause an agent: set paused_at and pause_reason.
372
- */
373
- async pauseAgent(tenantId, agentId, reason) {
374
- const result = this.db
375
- .update(agents)
376
- .set({
377
- pausedAt: new Date().toISOString(),
378
- pauseReason: reason,
379
- })
380
- .where(and(eq(agents.id, agentId), eq(agents.tenantId, tenantId)))
381
- .run();
382
- return result.changes > 0;
383
- }
384
- /**
385
- * Unpause an agent: clear paused_at, pause_reason, and optionally model_override.
386
- */
387
- async unpauseAgent(tenantId, agentId, clearModelOverride) {
388
- const updates = {
389
- pausedAt: null,
390
- pauseReason: null,
391
- };
392
- if (clearModelOverride) {
393
- updates.modelOverride = null;
394
- }
395
- const result = this.db
396
- .update(agents)
397
- .set(updates)
398
- .where(and(eq(agents.id, agentId), eq(agents.tenantId, tenantId)))
399
- .run();
400
- return result.changes > 0;
401
- }
402
- /**
403
- * Set model override on an agent.
404
- */
405
- async setModelOverride(tenantId, agentId, model) {
406
- const result = this.db
407
- .update(agents)
408
- .set({ modelOverride: model })
409
- .where(and(eq(agents.id, agentId), eq(agents.tenantId, tenantId)))
410
- .run();
411
- return result.changes > 0;
412
- }
413
- // ─── Events — Read (Story 3.5 stubs, implemented later) ────
414
41
  async queryEvents(query) {
415
- const limit = Math.min(query.limit ?? 50, 500);
416
- const offset = query.offset ?? 0;
417
- const orderDir = query.order === 'asc' ? asc : desc;
418
- const conditions = this._buildEventConditions(query);
419
- const rows = this.db
420
- .select()
421
- .from(events)
422
- .where(conditions.length > 0 ? and(...conditions) : undefined)
423
- .orderBy(orderDir(events.timestamp))
424
- .limit(limit)
425
- .offset(offset)
426
- .all();
427
- const total = await this.countEvents(query);
428
- return {
429
- events: rows.map(this._mapEventRow),
430
- total,
431
- hasMore: offset + rows.length < total,
432
- };
42
+ return this.eventRepo.queryEvents(query);
433
43
  }
434
44
  async getEvent(id, tenantId) {
435
- this.warnIfNoTenant('getEvent', tenantId);
436
- const conditions = [eq(events.id, id)];
437
- if (tenantId)
438
- conditions.push(eq(events.tenantId, tenantId));
439
- const row = this.db
440
- .select()
441
- .from(events)
442
- .where(and(...conditions))
443
- .get();
444
- return row ? this._mapEventRow(row) : null;
45
+ return this.eventRepo.getEvent(id, tenantId);
445
46
  }
446
47
  async getSessionTimeline(sessionId, tenantId) {
447
- const conditions = [eq(events.sessionId, sessionId)];
448
- if (tenantId)
449
- conditions.push(eq(events.tenantId, tenantId));
450
- const rows = this.db
451
- .select()
452
- .from(events)
453
- .where(and(...conditions))
454
- .orderBy(asc(events.timestamp))
455
- .all();
456
- return rows.map(this._mapEventRow);
48
+ return this.eventRepo.getSessionTimeline(sessionId, tenantId);
457
49
  }
458
50
  async getLastEventHash(sessionId, tenantId) {
459
- const conditions = [eq(events.sessionId, sessionId)];
460
- if (tenantId)
461
- conditions.push(eq(events.tenantId, tenantId));
462
- const row = this.db
463
- .select({ hash: events.hash })
464
- .from(events)
465
- .where(and(...conditions))
466
- .orderBy(desc(events.timestamp), desc(events.id))
467
- .limit(1)
468
- .get();
469
- return row?.hash ?? null;
51
+ return this.eventRepo.getLastEventHash(sessionId, tenantId);
470
52
  }
471
53
  async countEvents(query) {
472
- const conditions = this._buildEventConditions(query);
473
- const result = this.db
474
- .select({ count: drizzleCount() })
475
- .from(events)
476
- .where(conditions.length > 0 ? and(...conditions) : undefined)
477
- .get();
478
- return result?.count ?? 0;
54
+ return this.eventRepo.countEvents(query);
55
+ }
56
+ async countEventsBatch(query) {
57
+ return this.eventRepo.countEventsBatch(query);
58
+ }
59
+ // ─── Sessions ──────────────────────────────────────────────
60
+ async upsertSession(session) {
61
+ return this.sessionRepo.upsertSession(session);
479
62
  }
480
- // ─── Sessions — Read ───────────────────────────────────────
481
63
  async querySessions(query) {
482
- this.warnIfNoTenant('querySessions', query.tenantId);
483
- const limit = Math.min(query.limit ?? 50, 500);
484
- const offset = query.offset ?? 0;
485
- const conditions = this._buildSessionConditions(query);
486
- const rows = this.db
487
- .select()
488
- .from(sessions)
489
- .where(conditions.length > 0 ? and(...conditions) : undefined)
490
- .orderBy(desc(sessions.startedAt))
491
- .limit(limit)
492
- .offset(offset)
493
- .all();
494
- const totalResult = this.db
495
- .select({ count: drizzleCount() })
496
- .from(sessions)
497
- .where(conditions.length > 0 ? and(...conditions) : undefined)
498
- .get();
499
- return {
500
- sessions: rows.map(this._mapSessionRow),
501
- total: totalResult?.count ?? 0,
502
- };
64
+ return this.sessionRepo.querySessions(query);
503
65
  }
504
66
  async getSession(id, tenantId) {
505
- const conditions = [eq(sessions.id, id)];
506
- if (tenantId)
507
- conditions.push(eq(sessions.tenantId, tenantId));
508
- const row = this.db
509
- .select()
510
- .from(sessions)
511
- .where(and(...conditions))
512
- .get();
513
- return row ? this._mapSessionRow(row) : null;
67
+ return this.sessionRepo.getSession(id, tenantId);
68
+ }
69
+ async sumSessionCost(query) {
70
+ return this.sessionRepo.sumSessionCost(query);
71
+ }
72
+ // ─── Agents ────────────────────────────────────────────────
73
+ async upsertAgent(agent) {
74
+ return this.agentRepo.upsertAgent(agent);
75
+ }
76
+ async pauseAgent(tenantId, agentId, reason) {
77
+ return this.agentRepo.pauseAgent(tenantId, agentId, reason);
78
+ }
79
+ async unpauseAgent(tenantId, agentId, clearModelOverride) {
80
+ return this.agentRepo.unpauseAgent(tenantId, agentId, clearModelOverride);
81
+ }
82
+ async setModelOverride(tenantId, agentId, model) {
83
+ return this.agentRepo.setModelOverride(tenantId, agentId, model);
514
84
  }
515
- // ─── Agents — Read ─────────────────────────────────────────
516
85
  async listAgents(tenantId) {
517
- this.warnIfNoTenant('listAgents', tenantId);
518
- const conditions = tenantId ? [eq(agents.tenantId, tenantId)] : [];
519
- const rows = this.db
520
- .select()
521
- .from(agents)
522
- .where(conditions.length > 0 ? and(...conditions) : undefined)
523
- .orderBy(desc(agents.lastSeenAt))
524
- .all();
525
- return rows.map(this._mapAgentRow);
86
+ return this.agentRepo.listAgents(tenantId);
526
87
  }
527
88
  async getAgent(id, tenantId) {
528
- const conditions = [eq(agents.id, id)];
529
- if (tenantId)
530
- conditions.push(eq(agents.tenantId, tenantId));
531
- const row = this.db
532
- .select()
533
- .from(agents)
534
- .where(and(...conditions))
535
- .get();
536
- return row ? this._mapAgentRow(row) : null;
537
- }
538
- // ─── Analytics ─────────────────────────────────────────────
539
- async getAnalytics(params) {
540
- this.warnIfNoTenant('getAnalytics', params.tenantId);
541
- // HIGH 5: Build the time-bucket format string for SQLite strftime
542
- const formatStr = params.granularity === 'hour'
543
- ? '%Y-%m-%dT%H:00:00Z'
544
- : params.granularity === 'day'
545
- ? '%Y-%m-%dT00:00:00Z'
546
- : '%Y-%W'; // week — true ISO week bucketing
547
- const conditions = [
548
- gte(events.timestamp, params.from),
549
- lte(events.timestamp, params.to),
550
- ];
551
- if (params.agentId) {
552
- conditions.push(eq(events.agentId, params.agentId));
553
- }
554
- // HIGH 6: Compute avgLatencyMs and totalCostUsd from payload JSON
555
- // Bucketed query
556
- const bucketRows = this.db
557
- .all(sql `
558
- SELECT
559
- strftime(${formatStr}, timestamp) as bucket,
560
- COUNT(*) as eventCount,
561
- SUM(CASE WHEN event_type = 'tool_call' THEN 1 ELSE 0 END) as toolCallCount,
562
- SUM(CASE WHEN severity IN ('error', 'critical') OR event_type = 'tool_error' THEN 1 ELSE 0 END) as errorCount,
563
- COUNT(DISTINCT session_id) as uniqueSessions,
564
- COALESCE(AVG(CASE WHEN event_type = 'tool_response' THEN json_extract(payload, '$.durationMs') ELSE NULL END), 0) as avgLatencyMs,
565
- COALESCE(SUM(CASE WHEN event_type = 'cost_tracked' THEN json_extract(payload, '$.costUsd') ELSE 0 END), 0) as totalCostUsd
566
- FROM events
567
- WHERE timestamp >= ${params.from}
568
- AND timestamp <= ${params.to}
569
- ${params.agentId ? sql `AND agent_id = ${params.agentId}` : sql ``}
570
- ${params.tenantId ? sql `AND tenant_id = ${params.tenantId}` : sql ``}
571
- GROUP BY bucket
572
- ORDER BY bucket ASC
573
- `);
574
- // Totals query
575
- const totalsRow = this.db.get(sql `
576
- SELECT
577
- COUNT(*) as eventCount,
578
- SUM(CASE WHEN event_type = 'tool_call' THEN 1 ELSE 0 END) as toolCallCount,
579
- SUM(CASE WHEN severity IN ('error', 'critical') OR event_type = 'tool_error' THEN 1 ELSE 0 END) as errorCount,
580
- COUNT(DISTINCT session_id) as uniqueSessions,
581
- COUNT(DISTINCT agent_id) as uniqueAgents,
582
- COALESCE(AVG(CASE WHEN event_type = 'tool_response' THEN json_extract(payload, '$.durationMs') ELSE NULL END), 0) as avgLatencyMs,
583
- COALESCE(SUM(CASE WHEN event_type = 'cost_tracked' THEN json_extract(payload, '$.costUsd') ELSE 0 END), 0) as totalCostUsd
584
- FROM events
585
- WHERE timestamp >= ${params.from}
586
- AND timestamp <= ${params.to}
587
- ${params.agentId ? sql `AND agent_id = ${params.agentId}` : sql ``}
588
- ${params.tenantId ? sql `AND tenant_id = ${params.tenantId}` : sql ``}
589
- `);
590
- return {
591
- buckets: bucketRows.map((row) => ({
592
- timestamp: row.bucket,
593
- eventCount: Number(row.eventCount),
594
- toolCallCount: Number(row.toolCallCount),
595
- errorCount: Number(row.errorCount),
596
- avgLatencyMs: Number(row.avgLatencyMs),
597
- totalCostUsd: Number(row.totalCostUsd),
598
- uniqueSessions: Number(row.uniqueSessions),
599
- })),
600
- totals: {
601
- eventCount: Number(totalsRow?.eventCount ?? 0),
602
- toolCallCount: Number(totalsRow?.toolCallCount ?? 0),
603
- errorCount: Number(totalsRow?.errorCount ?? 0),
604
- avgLatencyMs: Number(totalsRow?.avgLatencyMs ?? 0),
605
- totalCostUsd: Number(totalsRow?.totalCostUsd ?? 0),
606
- uniqueSessions: Number(totalsRow?.uniqueSessions ?? 0),
607
- uniqueAgents: Number(totalsRow?.uniqueAgents ?? 0),
608
- },
609
- };
89
+ return this.agentRepo.getAgent(id, tenantId);
610
90
  }
611
- // ─── Alert Rules ───────────────────────────────────────────
91
+ // ─── Alerts ────────────────────────────────────────────────
612
92
  async createAlertRule(rule) {
613
- this.db
614
- .insert(alertRules)
615
- .values({
616
- id: rule.id,
617
- name: rule.name,
618
- enabled: rule.enabled,
619
- condition: rule.condition,
620
- threshold: rule.threshold,
621
- windowMinutes: rule.windowMinutes,
622
- scope: JSON.stringify(rule.scope),
623
- notifyChannels: JSON.stringify(rule.notifyChannels),
624
- createdAt: rule.createdAt,
625
- updatedAt: rule.updatedAt,
626
- tenantId: rule.tenantId ?? 'default',
627
- })
628
- .run();
93
+ return this.alertRepo.createAlertRule(rule);
629
94
  }
630
- // HIGH 8: Check affected row count and throw NotFoundError when zero
631
95
  async updateAlertRule(id, updates, tenantId) {
632
- const setValues = {};
633
- if (updates.name !== undefined)
634
- setValues.name = updates.name;
635
- if (updates.enabled !== undefined)
636
- setValues.enabled = updates.enabled;
637
- if (updates.condition !== undefined)
638
- setValues.condition = updates.condition;
639
- if (updates.threshold !== undefined)
640
- setValues.threshold = updates.threshold;
641
- if (updates.windowMinutes !== undefined)
642
- setValues.windowMinutes = updates.windowMinutes;
643
- if (updates.scope !== undefined)
644
- setValues.scope = JSON.stringify(updates.scope);
645
- if (updates.notifyChannels !== undefined)
646
- setValues.notifyChannels = JSON.stringify(updates.notifyChannels);
647
- if (updates.updatedAt !== undefined)
648
- setValues.updatedAt = updates.updatedAt;
649
- const whereConditions = [eq(alertRules.id, id)];
650
- if (tenantId)
651
- whereConditions.push(eq(alertRules.tenantId, tenantId));
652
- if (Object.keys(setValues).length === 0) {
653
- // Even with no actual updates, verify the rule exists
654
- const existing = this.db
655
- .select({ id: alertRules.id })
656
- .from(alertRules)
657
- .where(and(...whereConditions))
658
- .get();
659
- if (!existing) {
660
- throw new NotFoundError(`Alert rule not found: ${id}`);
661
- }
662
- return;
663
- }
664
- const result = this.db
665
- .update(alertRules)
666
- .set(setValues)
667
- .where(and(...whereConditions))
668
- .run();
669
- if (result.changes === 0) {
670
- throw new NotFoundError(`Alert rule not found: ${id}`);
671
- }
96
+ return this.alertRepo.updateAlertRule(id, updates, tenantId);
672
97
  }
673
98
  async deleteAlertRule(id, tenantId) {
674
- const whereConditions = [eq(alertRules.id, id)];
675
- if (tenantId)
676
- whereConditions.push(eq(alertRules.tenantId, tenantId));
677
- const result = this.db.delete(alertRules).where(and(...whereConditions)).run();
678
- if (result.changes === 0) {
679
- throw new NotFoundError(`Alert rule not found: ${id}`);
680
- }
99
+ return this.alertRepo.deleteAlertRule(id, tenantId);
681
100
  }
682
101
  async listAlertRules(tenantId) {
683
- this.warnIfNoTenant('listAlertRules', tenantId);
684
- const conditions = tenantId ? [eq(alertRules.tenantId, tenantId)] : [];
685
- const rows = this.db
686
- .select()
687
- .from(alertRules)
688
- .where(conditions.length > 0 ? and(...conditions) : undefined)
689
- .all();
690
- return rows.map(this._mapAlertRuleRow);
102
+ return this.alertRepo.listAlertRules(tenantId);
691
103
  }
692
104
  async getAlertRule(id, tenantId) {
693
- const conditions = [eq(alertRules.id, id)];
694
- if (tenantId)
695
- conditions.push(eq(alertRules.tenantId, tenantId));
696
- const row = this.db
697
- .select()
698
- .from(alertRules)
699
- .where(and(...conditions))
700
- .get();
701
- return row ? this._mapAlertRuleRow(row) : null;
105
+ return this.alertRepo.getAlertRule(id, tenantId);
702
106
  }
703
- // ─── Alert History ─────────────────────────────────────────
704
107
  async insertAlertHistory(entry) {
705
- this.db
706
- .insert(alertHistory)
707
- .values({
708
- id: entry.id,
709
- ruleId: entry.ruleId,
710
- triggeredAt: entry.triggeredAt,
711
- resolvedAt: entry.resolvedAt ?? null,
712
- currentValue: entry.currentValue,
713
- threshold: entry.threshold,
714
- message: entry.message,
715
- tenantId: entry.tenantId ?? 'default',
716
- })
717
- .run();
108
+ return this.alertRepo.insertAlertHistory(entry);
718
109
  }
719
110
  async listAlertHistory(opts) {
720
- const limit = Math.min(opts?.limit ?? 50, 500);
721
- const offset = opts?.offset ?? 0;
722
- const conditions = [];
723
- if (opts?.ruleId) {
724
- conditions.push(eq(alertHistory.ruleId, opts.ruleId));
725
- }
726
- if (opts?.tenantId) {
727
- conditions.push(eq(alertHistory.tenantId, opts.tenantId));
728
- }
729
- const rows = this.db
730
- .select()
731
- .from(alertHistory)
732
- .where(conditions.length > 0 ? and(...conditions) : undefined)
733
- .orderBy(desc(alertHistory.triggeredAt))
734
- .limit(limit)
735
- .offset(offset)
736
- .all();
737
- const totalResult = this.db
738
- .select({ count: drizzleCount() })
739
- .from(alertHistory)
740
- .where(conditions.length > 0 ? and(...conditions) : undefined)
741
- .get();
742
- return {
743
- entries: rows.map((row) => ({
744
- id: row.id,
745
- ruleId: row.ruleId,
746
- triggeredAt: row.triggeredAt,
747
- resolvedAt: row.resolvedAt ?? undefined,
748
- currentValue: row.currentValue,
749
- threshold: row.threshold,
750
- message: row.message,
751
- tenantId: row.tenantId,
752
- })),
753
- total: totalResult?.count ?? 0,
754
- };
111
+ return this.alertRepo.listAlertHistory(opts);
755
112
  }
756
- // ─── Maintenance ───────────────────────────────────────────
757
- async applyRetention(olderThan, tenantId) {
758
- // Build conditions — always filter by timestamp, optionally by tenant
759
- const countConditions = [lte(events.timestamp, olderThan)];
760
- if (tenantId)
761
- countConditions.push(eq(events.tenantId, tenantId));
762
- // Count events to be deleted
763
- const countResult = this.db
764
- .select({ count: drizzleCount() })
765
- .from(events)
766
- .where(and(...countConditions))
767
- .get();
768
- const deletedCount = countResult?.count ?? 0;
769
- if (deletedCount === 0)
770
- return { deletedCount: 0 };
771
- this.db.transaction((tx) => {
772
- if (tenantId) {
773
- // Tenant-scoped retention: only delete this tenant's old events
774
- tx.delete(events)
775
- .where(and(lte(events.timestamp, olderThan), eq(events.tenantId, tenantId)))
776
- .run();
777
- // Clean up this tenant's sessions that have no remaining events
778
- tx.run(sql `
779
- DELETE FROM sessions
780
- WHERE tenant_id = ${tenantId}
781
- AND id NOT IN (
782
- SELECT DISTINCT session_id FROM events WHERE tenant_id = ${tenantId}
783
- )
784
- `);
785
- }
786
- else {
787
- // Global retention (system-level, not exposed through TenantScopedStore)
788
- tx.delete(events).where(lte(events.timestamp, olderThan)).run();
789
- tx.run(sql `
790
- DELETE FROM sessions
791
- WHERE id NOT IN (SELECT DISTINCT session_id FROM events)
792
- `);
793
- }
794
- });
795
- return { deletedCount };
113
+ // ─── Analytics & Stats ─────────────────────────────────────
114
+ async getAnalytics(params) {
115
+ return this.analyticsRepo.getAnalytics(params);
796
116
  }
797
117
  async getStats(tenantId) {
798
- const eventConditions = tenantId ? [eq(events.tenantId, tenantId)] : [];
799
- const sessionConditions = tenantId ? [eq(sessions.tenantId, tenantId)] : [];
800
- const agentConditions = tenantId ? [eq(agents.tenantId, tenantId)] : [];
801
- const eventCount = this.db
802
- .select({ count: drizzleCount() })
803
- .from(events)
804
- .where(eventConditions.length > 0 ? and(...eventConditions) : undefined)
805
- .get()?.count ?? 0;
806
- const sessionCount = this.db
807
- .select({ count: drizzleCount() })
808
- .from(sessions)
809
- .where(sessionConditions.length > 0 ? and(...sessionConditions) : undefined)
810
- .get()?.count ?? 0;
811
- const agentCount = this.db
812
- .select({ count: drizzleCount() })
813
- .from(agents)
814
- .where(agentConditions.length > 0 ? and(...agentConditions) : undefined)
815
- .get()?.count ?? 0;
816
- const oldest = this.db
817
- .select({ timestamp: events.timestamp })
818
- .from(events)
819
- .where(eventConditions.length > 0 ? and(...eventConditions) : undefined)
820
- .orderBy(asc(events.timestamp))
821
- .limit(1)
822
- .get();
823
- const newest = this.db
824
- .select({ timestamp: events.timestamp })
825
- .from(events)
826
- .where(eventConditions.length > 0 ? and(...eventConditions) : undefined)
827
- .orderBy(desc(events.timestamp))
828
- .limit(1)
829
- .get();
830
- // SQLite page_count * page_size for storage size
831
- const pageCount = this.db.get(sql `PRAGMA page_count`)
832
- ?.page_count ?? 0;
833
- const pageSize = this.db.get(sql `PRAGMA page_size`)
834
- ?.page_size ?? 0;
835
- return {
836
- totalEvents: eventCount,
837
- totalSessions: sessionCount,
838
- totalAgents: agentCount,
839
- oldestEvent: oldest?.timestamp,
840
- newestEvent: newest?.timestamp,
841
- storageSizeBytes: pageCount * pageSize,
842
- };
843
- }
844
- // ─── Private Helpers ───────────────────────────────────────
845
- _buildEventConditions(query) {
846
- const conditions = [];
847
- if (query.tenantId) {
848
- conditions.push(eq(events.tenantId, query.tenantId));
849
- }
850
- if (query.sessionId) {
851
- conditions.push(eq(events.sessionId, query.sessionId));
852
- }
853
- if (query.agentId) {
854
- conditions.push(eq(events.agentId, query.agentId));
855
- }
856
- if (query.eventType) {
857
- if (Array.isArray(query.eventType)) {
858
- conditions.push(inArray(events.eventType, query.eventType));
859
- }
860
- else {
861
- conditions.push(eq(events.eventType, query.eventType));
862
- }
863
- }
864
- if (query.severity) {
865
- if (Array.isArray(query.severity)) {
866
- conditions.push(inArray(events.severity, query.severity));
867
- }
868
- else {
869
- conditions.push(eq(events.severity, query.severity));
870
- }
871
- }
872
- if (query.from) {
873
- conditions.push(gte(events.timestamp, query.from));
874
- }
875
- if (query.to) {
876
- conditions.push(lte(events.timestamp, query.to));
877
- }
878
- if (query.search) {
879
- // H1 fix: Escape LIKE wildcards to prevent wildcard abuse
880
- const escaped = query.search
881
- .replace(/\\/g, '\\\\')
882
- .replace(/%/g, '\\%')
883
- .replace(/_/g, '\\_');
884
- conditions.push(sql `${events.payload} LIKE ${'%' + escaped + '%'} ESCAPE '\\'`);
885
- }
886
- return conditions;
887
- }
888
- // HIGH 4: Use json_each() for exact tag matching with OR semantics
889
- _buildSessionConditions(query) {
890
- const conditions = [];
891
- if (query.tenantId) {
892
- conditions.push(eq(sessions.tenantId, query.tenantId));
893
- }
894
- if (query.agentId) {
895
- conditions.push(eq(sessions.agentId, query.agentId));
896
- }
897
- if (query.status) {
898
- if (Array.isArray(query.status)) {
899
- if (query.status.length === 1) {
900
- conditions.push(eq(sessions.status, query.status[0]));
901
- }
902
- else if (query.status.length > 1) {
903
- conditions.push(inArray(sessions.status, query.status));
904
- }
905
- }
906
- else {
907
- conditions.push(eq(sessions.status, query.status));
908
- }
909
- }
910
- if (query.from) {
911
- conditions.push(gte(sessions.startedAt, query.from));
912
- }
913
- if (query.to) {
914
- conditions.push(lte(sessions.startedAt, query.to));
915
- }
916
- if (query.tags && query.tags.length > 0) {
917
- // Use json_each for exact tag matching with OR semantics
918
- // A session matches if it contains ANY of the specified tags
919
- const tagPlaceholders = query.tags.map((tag) => sql `${tag}`);
920
- conditions.push(sql `EXISTS (
921
- SELECT 1 FROM json_each(${sessions.tags}) AS je
922
- WHERE je.value IN (${sql.join(tagPlaceholders, sql `, `)})
923
- )`);
924
- }
925
- return conditions;
118
+ return this.analyticsRepo.getStats(tenantId);
926
119
  }
927
- // HIGH 7: Use safeJsonParse everywhere
928
- _mapEventRow(row) {
929
- return {
930
- id: row.id,
931
- timestamp: row.timestamp,
932
- sessionId: row.sessionId,
933
- agentId: row.agentId,
934
- eventType: row.eventType,
935
- severity: row.severity,
936
- payload: safeJsonParse(row.payload, {}),
937
- metadata: safeJsonParse(row.metadata, {}),
938
- prevHash: row.prevHash,
939
- hash: row.hash,
940
- tenantId: row.tenantId,
941
- };
942
- }
943
- _mapSessionRow(row) {
944
- return {
945
- id: row.id,
946
- agentId: row.agentId,
947
- agentName: row.agentName ?? undefined,
948
- startedAt: row.startedAt,
949
- endedAt: row.endedAt ?? undefined,
950
- status: row.status,
951
- eventCount: row.eventCount,
952
- toolCallCount: row.toolCallCount,
953
- errorCount: row.errorCount,
954
- totalCostUsd: row.totalCostUsd,
955
- llmCallCount: row.llmCallCount,
956
- totalInputTokens: row.totalInputTokens,
957
- totalOutputTokens: row.totalOutputTokens,
958
- tags: safeJsonParse(row.tags, []),
959
- tenantId: row.tenantId,
960
- };
961
- }
962
- _mapAgentRow(row) {
963
- return {
964
- id: row.id,
965
- name: row.name,
966
- description: row.description ?? undefined,
967
- firstSeenAt: row.firstSeenAt,
968
- lastSeenAt: row.lastSeenAt,
969
- sessionCount: row.sessionCount,
970
- tenantId: row.tenantId,
971
- modelOverride: row.modelOverride ?? undefined,
972
- pausedAt: row.pausedAt ?? undefined,
973
- pauseReason: row.pauseReason ?? undefined,
974
- };
975
- }
976
- _mapAlertRuleRow(row) {
977
- return {
978
- id: row.id,
979
- name: row.name,
980
- enabled: row.enabled,
981
- condition: row.condition,
982
- threshold: row.threshold,
983
- windowMinutes: row.windowMinutes,
984
- scope: safeJsonParse(row.scope, {}),
985
- notifyChannels: safeJsonParse(row.notifyChannels, []),
986
- createdAt: row.createdAt,
987
- updatedAt: row.updatedAt,
988
- tenantId: row.tenantId,
989
- };
120
+ // ─── Maintenance ───────────────────────────────────────────
121
+ async applyRetention(olderThan, tenantId) {
122
+ return this.retentionService.applyRetention(olderThan, tenantId);
990
123
  }
991
124
  }
992
125
  //# sourceMappingURL=sqlite-store.js.map