hippo-memory 1.71.0 → 2.0.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 (625) hide show
  1. package/README.md +7 -5
  2. package/dist/agent-memories/apply.d.ts +0 -11
  3. package/dist/agent-memories/apply.js +11 -26
  4. package/dist/agent-memories/claude-code.js +1 -1
  5. package/dist/agent-memories/codex.js +1 -1
  6. package/dist/agent-memories/copilot.d.ts +1 -3
  7. package/dist/agent-memories/copilot.js +1 -17
  8. package/dist/agent-memories/project-folds.d.ts +10 -0
  9. package/dist/agent-memories/project-folds.js +34 -0
  10. package/dist/agent-memories/sync.js +8 -6
  11. package/dist/api/assemble.js +3 -2
  12. package/dist/api/audit.d.ts +30 -2
  13. package/dist/api/audit.js +48 -7
  14. package/dist/api/auth.d.ts +11 -9
  15. package/dist/api/auth.js +39 -40
  16. package/dist/api/auto-sleep.d.ts +5 -2
  17. package/dist/api/auto-sleep.js +7 -3
  18. package/dist/api/availability.js +2 -3
  19. package/dist/api/cards.d.ts +42 -0
  20. package/dist/api/cards.js +52 -0
  21. package/dist/api/conflicts.d.ts +28 -0
  22. package/dist/api/conflicts.js +61 -0
  23. package/dist/api/context-auto.js +4 -2
  24. package/dist/api/context-render.js +4 -3
  25. package/dist/api/context-select.js +15 -29
  26. package/dist/api/context.js +29 -18
  27. package/dist/api/continuity.d.ts +47 -0
  28. package/dist/api/continuity.js +66 -0
  29. package/dist/api/dormant.js +4 -2
  30. package/dist/api/drill-down.js +3 -2
  31. package/dist/api/embeddings.d.ts +17 -0
  32. package/dist/api/embeddings.js +28 -0
  33. package/dist/api/error-reply.d.ts +8 -0
  34. package/dist/api/error-reply.js +21 -0
  35. package/dist/api/forget.d.ts +7 -3
  36. package/dist/api/forget.js +24 -14
  37. package/dist/api/goals.d.ts +1 -1
  38. package/dist/api/goals.js +5 -9
  39. package/dist/api/graph.js +2 -1
  40. package/dist/api/index.d.ts +4 -2
  41. package/dist/api/index.js +4 -2
  42. package/dist/api/instruction-detect.js +5 -1
  43. package/dist/api/learn.d.ts +5 -1
  44. package/dist/api/learn.js +71 -44
  45. package/dist/api/ledger-db.d.ts +2 -6
  46. package/dist/api/ledger-db.js +4 -36
  47. package/dist/api/memories.d.ts +21 -1
  48. package/dist/api/memories.js +51 -1
  49. package/dist/api/objects.d.ts +1 -1
  50. package/dist/api/objects.js +2 -1
  51. package/dist/api/outcome.d.ts +5 -5
  52. package/dist/api/outcome.js +17 -16
  53. package/dist/api/pilot-arm.d.ts +1 -11
  54. package/dist/api/pilot-arm.js +5 -45
  55. package/dist/api/predictions.d.ts +3 -1
  56. package/dist/api/predictions.js +8 -1
  57. package/dist/api/projects.d.ts +21 -0
  58. package/dist/api/projects.js +24 -0
  59. package/dist/api/promote.d.ts +3 -3
  60. package/dist/api/promote.js +26 -28
  61. package/dist/api/prompt-hook.d.ts +17 -2
  62. package/dist/api/prompt-hook.js +45 -4
  63. package/dist/api/quarantine.js +2 -1
  64. package/dist/api/recall-cli.d.ts +3 -0
  65. package/dist/api/recall-cli.js +13 -4
  66. package/dist/api/recall-core.js +10 -5
  67. package/dist/api/recall-pipeline.js +23 -24
  68. package/dist/api/recall-request.js +1 -1
  69. package/dist/api/recall-types.d.ts +3 -1
  70. package/dist/api/recall.d.ts +0 -3
  71. package/dist/api/recall.js +51 -73
  72. package/dist/api/remember-local.d.ts +5 -2
  73. package/dist/api/remember-local.js +15 -7
  74. package/dist/api/remember.d.ts +7 -3
  75. package/dist/api/remember.js +19 -16
  76. package/dist/api/session-end.d.ts +46 -0
  77. package/dist/api/session-end.js +131 -0
  78. package/dist/api/sleep-run.d.ts +1 -1
  79. package/dist/api/sleep-run.js +16 -11
  80. package/dist/api/sleep.js +4 -3
  81. package/dist/api/status.d.ts +24 -0
  82. package/dist/api/status.js +40 -0
  83. package/dist/api/store-init.d.ts +4 -0
  84. package/dist/api/store-init.js +9 -0
  85. package/dist/api/tokens.js +2 -2
  86. package/dist/api/types.d.ts +3 -7
  87. package/dist/api/types.js +6 -1
  88. package/dist/capture/caller-session.d.ts +0 -3
  89. package/dist/capture/caller-session.js +1 -12
  90. package/dist/capture/capture-error.d.ts +2 -2
  91. package/dist/capture/capture-error.js +23 -18
  92. package/dist/capture/codex-patch.js +3 -1
  93. package/dist/capture/command.js +36 -95
  94. package/dist/capture/compact.js +10 -5
  95. package/dist/capture/compaction-items-caller.js +11 -20
  96. package/dist/capture/compaction-record.d.ts +7 -93
  97. package/dist/capture/compaction-record.js +29 -426
  98. package/dist/capture/compaction-spool.d.ts +7 -7
  99. package/dist/capture/compaction-spool.js +60 -51
  100. package/dist/capture/copilot-transcript.d.ts +2 -1
  101. package/dist/capture/copilot-transcript.js +2 -1
  102. package/dist/capture/extract.d.ts +5 -2
  103. package/dist/capture/extract.js +4 -3
  104. package/dist/capture/failure-caller.d.ts +1 -1
  105. package/dist/capture/failure-caller.js +21 -16
  106. package/dist/capture/failure-reading.d.ts +2 -1
  107. package/dist/capture/failure-reading.js +7 -9
  108. package/dist/capture/pre-compact-caller.js +5 -4
  109. package/dist/capture/session-digest.js +4 -3
  110. package/dist/capture/session-end-caller.js +3 -2
  111. package/dist/capture/session-worker.js +22 -10
  112. package/dist/capture/transcript.d.ts +2 -1
  113. package/dist/capture/transcript.js +6 -3
  114. package/dist/capture/working-state.d.ts +4 -2
  115. package/dist/capture/working-state.js +4 -2
  116. package/dist/cli/audit-prune.d.ts +0 -25
  117. package/dist/cli/audit-prune.js +1 -27
  118. package/dist/cli/audit.js +20 -20
  119. package/dist/cli/auth.d.ts +1 -1
  120. package/dist/cli/auth.js +16 -17
  121. package/dist/cli/briefs.d.ts +1 -4
  122. package/dist/cli/briefs.js +37 -292
  123. package/dist/cli/card.js +41 -33
  124. package/dist/cli/client.d.ts +6 -2
  125. package/dist/cli/client.js +37 -21
  126. package/dist/cli/compact-resume-payload.js +1 -1
  127. package/dist/cli/context.d.ts +1 -1
  128. package/dist/cli/context.js +13 -13
  129. package/dist/cli/continuity.d.ts +1 -1
  130. package/dist/cli/continuity.js +36 -39
  131. package/dist/cli/curate.d.ts +2 -2
  132. package/dist/cli/curate.js +32 -36
  133. package/dist/cli/dag.d.ts +1 -1
  134. package/dist/cli/dag.js +23 -8
  135. package/dist/cli/decisions.d.ts +0 -2
  136. package/dist/cli/decisions.js +7 -285
  137. package/dist/cli/eval.d.ts +1 -1
  138. package/dist/cli/eval.js +12 -13
  139. package/dist/cli/explain.d.ts +1 -1
  140. package/dist/cli/explain.js +21 -25
  141. package/dist/cli/flag-values.js +16 -6
  142. package/dist/cli/flags.d.ts +0 -289
  143. package/dist/cli/flags.js +3 -138
  144. package/dist/cli/graph.d.ts +3 -0
  145. package/dist/cli/graph.js +83 -0
  146. package/dist/cli/hook-runtime.d.ts +6 -6
  147. package/dist/cli/hook-runtime.js +9 -36
  148. package/dist/cli/incidents.d.ts +3 -0
  149. package/dist/cli/incidents.js +112 -0
  150. package/dist/cli/init.d.ts +1 -1
  151. package/dist/cli/init.js +28 -19
  152. package/dist/cli/install-steps.d.ts +2 -1
  153. package/dist/cli/install-steps.js +11 -3
  154. package/dist/cli/last-sleep.js +1 -1
  155. package/dist/cli/maintenance.d.ts +3 -3
  156. package/dist/cli/maintenance.js +29 -30
  157. package/dist/cli/notes.d.ts +2 -0
  158. package/dist/cli/notes.js +41 -0
  159. package/dist/cli/object-verbs.d.ts +2 -2
  160. package/dist/cli/object-verbs.js +4 -4
  161. package/dist/cli/open-browser.d.ts +14 -0
  162. package/dist/cli/open-browser.js +26 -0
  163. package/dist/cli/playbooks.d.ts +3 -4
  164. package/dist/cli/playbooks.js +126 -290
  165. package/dist/cli/predictions.d.ts +3 -0
  166. package/dist/cli/predictions.js +174 -0
  167. package/dist/cli/print.js +2 -1
  168. package/dist/cli/projects.js +30 -22
  169. package/dist/cli/quality-repair-once.d.ts +1 -1
  170. package/dist/cli/quality-repair-once.js +6 -5
  171. package/dist/cli/recall.js +13 -7
  172. package/dist/cli/refine-llm.js +18 -17
  173. package/dist/cli/remember.js +17 -17
  174. package/dist/cli/scheduler.js +2 -1
  175. package/dist/cli/serve.js +11 -6
  176. package/dist/cli/session-hooks.d.ts +1 -5
  177. package/dist/cli/session-hooks.js +89 -168
  178. package/dist/cli/setup.d.ts +1 -1
  179. package/dist/cli/setup.js +17 -10
  180. package/dist/cli/shared.d.ts +2 -6
  181. package/dist/cli/shared.js +9 -29
  182. package/dist/cli/sleep-render.js +6 -3
  183. package/dist/cli/sleep.js +6 -37
  184. package/dist/cli/status.d.ts +3 -3
  185. package/dist/cli/status.js +32 -35
  186. package/dist/cli/transfer.d.ts +3 -3
  187. package/dist/cli/transfer.js +64 -43
  188. package/dist/cli/usage.d.ts +1 -80
  189. package/dist/cli/usage.js +2 -696
  190. package/dist/cli/verb-row.d.ts +34 -0
  191. package/dist/cli/verb-row.js +6 -0
  192. package/dist/cli/verbs/health.d.ts +27 -0
  193. package/dist/cli/verbs/health.js +234 -0
  194. package/dist/cli/verbs/memory.d.ts +16 -0
  195. package/dist/cli/verbs/memory.js +236 -0
  196. package/dist/cli/verbs/objects.d.ts +20 -0
  197. package/dist/cli/verbs/objects.js +257 -0
  198. package/dist/cli/verbs/sessions.d.ts +31 -0
  199. package/dist/cli/verbs/sessions.js +314 -0
  200. package/dist/cli/verbs.d.ts +81 -0
  201. package/dist/cli/verbs.js +7 -0
  202. package/dist/cli/versioned-verbs.d.ts +51 -0
  203. package/dist/cli/versioned-verbs.js +79 -0
  204. package/dist/cli.d.ts +1 -272
  205. package/dist/cli.js +24 -315
  206. package/dist/connectors/dlq.d.ts +39 -3
  207. package/dist/connectors/dlq.js +39 -4
  208. package/dist/connectors/github/backfill.js +12 -3
  209. package/dist/connectors/github/deletion.js +2 -1
  210. package/dist/connectors/github/dlq.js +31 -73
  211. package/dist/connectors/github/ingest.d.ts +2 -6
  212. package/dist/connectors/github/ingest.js +5 -29
  213. package/dist/connectors/github/tenant-routing.js +2 -1
  214. package/dist/connectors/github/webhook.d.ts +2 -1
  215. package/dist/connectors/github/webhook.js +35 -2
  216. package/dist/connectors/ingest.d.ts +10 -0
  217. package/dist/connectors/ingest.js +29 -0
  218. package/dist/connectors/slack/deletion.js +2 -1
  219. package/dist/connectors/slack/dlq.js +49 -71
  220. package/dist/connectors/slack/ingest.d.ts +2 -6
  221. package/dist/connectors/slack/ingest.js +4 -28
  222. package/dist/connectors/slack/tenant-routing.js +2 -1
  223. package/dist/connectors/slack/webhook.d.ts +2 -1
  224. package/dist/connectors/slack/webhook.js +2 -1
  225. package/dist/consolidate/conflicts.js +2 -2
  226. package/dist/consolidate/dag.js +29 -18
  227. package/dist/consolidate/dedupe.d.ts +7 -0
  228. package/dist/consolidate/dedupe.js +6 -4
  229. package/dist/consolidate/llm-passes.js +45 -19
  230. package/dist/consolidate/memory-value.js +3 -2
  231. package/dist/consolidate/merge.js +8 -8
  232. package/dist/consolidate/physics-pass.d.ts +6 -1
  233. package/dist/consolidate/physics-pass.js +26 -6
  234. package/dist/consolidate/replay.js +11 -4
  235. package/dist/consolidate/sleep.js +9 -6
  236. package/dist/consolidate/traces.js +5 -5
  237. package/dist/core/ablation.d.ts +10 -0
  238. package/dist/core/ablation.js +12 -0
  239. package/dist/{sharing/scope.d.ts → core/active-scope.d.ts} +1 -1
  240. package/dist/{sharing/scope.js → core/active-scope.js} +1 -1
  241. package/dist/core/ambient.d.ts +4 -0
  242. package/dist/core/ambient.js +39 -18
  243. package/dist/core/api-errors.d.ts +16 -0
  244. package/dist/core/api-errors.js +20 -0
  245. package/dist/core/card.js +3 -1
  246. package/dist/core/compaction-timing.d.ts +7 -0
  247. package/dist/core/compaction-timing.js +9 -0
  248. package/dist/core/config.d.ts +1 -1
  249. package/dist/core/config.js +22 -18
  250. package/dist/core/cosine.d.ts +3 -0
  251. package/dist/core/cosine.js +19 -0
  252. package/dist/{store → core}/markdown.d.ts +1 -1
  253. package/dist/{store → core}/markdown.js +4 -4
  254. package/dist/core/memory-audit.d.ts +17 -0
  255. package/dist/core/memory-audit.js +54 -0
  256. package/dist/core/memory.d.ts +14 -8
  257. package/dist/core/memory.js +35 -23
  258. package/dist/{consolidate → core}/merged-row.d.ts +1 -1
  259. package/dist/{consolidate → core}/merged-row.js +1 -1
  260. package/dist/core/physics.d.ts +3 -1
  261. package/dist/core/physics.js +23 -18
  262. package/dist/core/prediction.d.ts +3 -0
  263. package/dist/core/prediction.js +6 -0
  264. package/dist/core/project-identity.d.ts +3 -0
  265. package/dist/core/project-identity.js +12 -2
  266. package/dist/{store → core}/recall-scope.d.ts +1 -10
  267. package/dist/{store → core}/recall-scope.js +2 -19
  268. package/dist/core/search-types.d.ts +1 -1
  269. package/dist/dashboard/dashboard-actions.d.ts +2 -2
  270. package/dist/dashboard/dashboard-actions.js +5 -5
  271. package/dist/dashboard/dashboard-queries.js +2 -7
  272. package/dist/dashboard/dashboard-snapshot.js +1 -3
  273. package/dist/dashboard/dashboard.js +16 -5
  274. package/dist/db/busy.d.ts +2 -7
  275. package/dist/db/busy.js +21 -26
  276. package/dist/db/connect.d.ts +2 -2
  277. package/dist/db/connect.js +7 -7
  278. package/dist/db/index.d.ts +3 -3
  279. package/dist/db/index.js +3 -3
  280. package/dist/db/migrate.js +14 -7
  281. package/dist/db/migrations/index.d.ts +1 -1
  282. package/dist/db/migrations/index.js +3 -1
  283. package/dist/db/migrations/v11.js +1 -0
  284. package/dist/db/migrations/v14.js +1 -0
  285. package/dist/db/migrations/v55.d.ts +3 -0
  286. package/dist/db/migrations/v55.js +17 -0
  287. package/dist/db/open.d.ts +0 -2
  288. package/dist/db/open.js +6 -10
  289. package/dist/db/physics-state.d.ts +0 -4
  290. package/dist/db/physics-state.js +7 -33
  291. package/dist/db/request-stores.d.ts +1 -0
  292. package/dist/db/request-stores.js +2 -1
  293. package/dist/db/tables.d.ts +2 -0
  294. package/dist/db/tables.js +6 -2
  295. package/dist/db/vector-store.js +19 -5
  296. package/dist/db/wal-checkpointer.js +2 -1
  297. package/dist/doctor.d.ts +3 -0
  298. package/dist/doctor.js +18 -15
  299. package/dist/embeddings/local.d.ts +62 -0
  300. package/dist/embeddings/local.js +146 -0
  301. package/dist/{store/embeddings → embeddings}/provider.d.ts +5 -2
  302. package/dist/{store/embeddings → embeddings}/provider.js +19 -25
  303. package/dist/embeddings/transformers.d.ts +26 -0
  304. package/dist/embeddings/transformers.js +89 -0
  305. package/dist/entry/session-text.d.ts +1 -1
  306. package/dist/entry/session-text.js +1 -1
  307. package/dist/entry/store-kit.d.ts +37 -0
  308. package/dist/entry/store-kit.js +25 -0
  309. package/dist/entry/testing.d.ts +6 -0
  310. package/dist/entry/testing.js +7 -0
  311. package/dist/eval/eval-suite.js +17 -11
  312. package/dist/eval/eval.js +1 -1
  313. package/dist/eval/judgment.js +12 -5
  314. package/dist/graph/extract.js +3 -3
  315. package/dist/graph/recall.js +1 -1
  316. package/dist/graph/view.js +13 -5
  317. package/dist/graph/write.d.ts +1 -1
  318. package/dist/graph/write.js +9 -9
  319. package/dist/hooks/codex-session.js +3 -2
  320. package/dist/hooks/codex-wrapper.js +2 -1
  321. package/dist/hooks/json-hooks.js +10 -4
  322. package/dist/hooks/opencode.js +8 -5
  323. package/dist/hooks/shared.d.ts +0 -6
  324. package/dist/hooks/shared.js +4 -15
  325. package/dist/importers/core.js +4 -4
  326. package/dist/importers/sources.js +5 -4
  327. package/dist/importers/vault.d.ts +1 -1
  328. package/dist/importers/vault.js +25 -23
  329. package/dist/index.d.ts +5 -4
  330. package/dist/index.js +4 -3
  331. package/dist/learn/autolearn.d.ts +15 -3
  332. package/dist/learn/autolearn.js +38 -16
  333. package/dist/learn/churn-git.js +13 -4
  334. package/dist/learn/extract.d.ts +3 -2
  335. package/dist/learn/extract.js +7 -5
  336. package/dist/learn/forward-claim-detector.js +4 -2
  337. package/dist/learn/invalidation.d.ts +2 -1
  338. package/dist/learn/invalidation.js +18 -9
  339. package/dist/mcp/admin-tools.d.ts +2 -2
  340. package/dist/mcp/admin-tools.js +27 -48
  341. package/dist/mcp/format.js +3 -2
  342. package/dist/mcp/framing.d.ts +1 -0
  343. package/dist/mcp/framing.js +1 -1
  344. package/dist/mcp/memory-tools.d.ts +1 -1
  345. package/dist/mcp/memory-tools.js +8 -9
  346. package/dist/mcp/protocol.d.ts +11 -7
  347. package/dist/mcp/protocol.js +25 -12
  348. package/dist/mcp/recall-tools.js +12 -9
  349. package/dist/mcp/request.js +22 -20
  350. package/dist/mcp/stdio.js +37 -16
  351. package/dist/mcp/tool-args.js +2 -1
  352. package/dist/mcp/tools.js +44 -21
  353. package/dist/objects/customer-notes.d.ts +2 -2
  354. package/dist/objects/decisions.d.ts +2 -2
  355. package/dist/objects/descriptor.d.ts +1 -1
  356. package/dist/objects/incidents.d.ts +2 -2
  357. package/dist/objects/lifecycle.d.ts +1 -1
  358. package/dist/objects/lifecycle.js +2 -1
  359. package/dist/objects/policies.d.ts +2 -2
  360. package/dist/objects/policies.js +2 -1
  361. package/dist/objects/processes.d.ts +2 -2
  362. package/dist/objects/project-briefs.d.ts +2 -2
  363. package/dist/objects/project-briefs.js +2 -3
  364. package/dist/objects/skills.d.ts +2 -2
  365. package/dist/postinstall.js +1 -1
  366. package/dist/rerankers/clef.js +3 -6
  367. package/dist/rerankers/cross-encoder.d.ts +31 -2
  368. package/dist/rerankers/cross-encoder.js +71 -98
  369. package/dist/rerankers/index.js +5 -4
  370. package/dist/rerankers/jev.js +2 -4
  371. package/dist/rerankers/outage-warning.d.ts +3 -1
  372. package/dist/rerankers/outage-warning.js +5 -3
  373. package/dist/search/bm25-search.js +1 -1
  374. package/dist/search/boosts.js +1 -1
  375. package/dist/search/embed-memories.d.ts +12 -0
  376. package/dist/search/embed-memories.js +389 -0
  377. package/dist/search/engine.d.ts +8 -0
  378. package/dist/search/engine.js +10 -0
  379. package/dist/search/goal-boost.d.ts +1 -1
  380. package/dist/search/goal-boost.js +6 -3
  381. package/dist/search/hybrid.d.ts +9 -2
  382. package/dist/search/hybrid.js +9 -4
  383. package/dist/search/physics-search.d.ts +6 -3
  384. package/dist/search/physics-search.js +22 -15
  385. package/dist/search/rerank.js +1 -1
  386. package/dist/search/vector.d.ts +8 -6
  387. package/dist/search/vector.js +14 -17
  388. package/dist/server/auth.d.ts +3 -1
  389. package/dist/server/auth.js +24 -15
  390. package/dist/server/boot.d.ts +2 -1
  391. package/dist/server/boot.js +34 -84
  392. package/dist/server/client-ip.d.ts +9 -6
  393. package/dist/server/client-ip.js +36 -17
  394. package/dist/server/deadline.d.ts +0 -2
  395. package/dist/server/deadline.js +1 -7
  396. package/dist/server/defaults.d.ts +1 -0
  397. package/dist/server/defaults.js +1 -0
  398. package/dist/server/mcp-http.js +16 -11
  399. package/dist/server/request.js +7 -2
  400. package/dist/server/route-checks.d.ts +7 -0
  401. package/dist/server/route-checks.js +42 -0
  402. package/dist/server/route-table.d.ts +9 -8
  403. package/dist/server/route-table.js +127 -133
  404. package/dist/server/routes/admin.d.ts +8 -8
  405. package/dist/server/routes/admin.js +13 -21
  406. package/dist/server/routes/customer-notes.d.ts +6 -6
  407. package/dist/server/routes/customer-notes.js +1 -2
  408. package/dist/server/routes/decisions.d.ts +6 -6
  409. package/dist/server/routes/decisions.js +2 -4
  410. package/dist/server/routes/incidents.d.ts +6 -6
  411. package/dist/server/routes/incidents.js +2 -5
  412. package/dist/server/routes/memories.d.ts +9 -9
  413. package/dist/server/routes/memories.js +19 -40
  414. package/dist/server/routes/object-routes.d.ts +6 -6
  415. package/dist/server/routes/object-routes.js +4 -7
  416. package/dist/server/routes/policies.d.ts +7 -7
  417. package/dist/server/routes/policies.js +2 -4
  418. package/dist/server/routes/predictions.d.ts +6 -6
  419. package/dist/server/routes/predictions.js +9 -13
  420. package/dist/server/routes/processes.d.ts +6 -6
  421. package/dist/server/routes/processes.js +1 -2
  422. package/dist/server/routes/project-briefs.d.ts +7 -7
  423. package/dist/server/routes/project-briefs.js +2 -4
  424. package/dist/server/routes/recall.d.ts +5 -5
  425. package/dist/server/routes/recall.js +6 -10
  426. package/dist/server/routes/skills.d.ts +7 -7
  427. package/dist/server/routes/skills.js +2 -4
  428. package/dist/server/server-detect.d.ts +7 -1
  429. package/dist/server/server-detect.js +36 -11
  430. package/dist/server/sleep-child.js +26 -7
  431. package/dist/server/sleep-offload.d.ts +11 -5
  432. package/dist/server/sleep-offload.js +17 -11
  433. package/dist/server/tls.d.ts +7 -2
  434. package/dist/server/tls.js +17 -5
  435. package/dist/server/types.d.ts +29 -12
  436. package/dist/server/validation.d.ts +1 -2
  437. package/dist/server/validation.js +6 -11
  438. package/dist/server.d.ts +4 -40
  439. package/dist/server.js +3 -29
  440. package/dist/sharing/global-store.d.ts +4 -5
  441. package/dist/sharing/global-store.js +8 -13
  442. package/dist/sharing/global-sync.js +38 -45
  443. package/dist/sharing/project-merge.d.ts +7 -14
  444. package/dist/sharing/project-merge.js +57 -121
  445. package/dist/sharing/search-both.js +10 -3
  446. package/dist/sharing/share.d.ts +2 -0
  447. package/dist/sharing/share.js +39 -38
  448. package/dist/store/ambient.js +7 -7
  449. package/dist/store/audit-event.d.ts +1 -1
  450. package/dist/store/audit.d.ts +0 -16
  451. package/dist/store/audit.js +4 -55
  452. package/dist/store/auth.d.ts +4 -2
  453. package/dist/store/auth.js +7 -3
  454. package/dist/store/candidates.d.ts +3 -2
  455. package/dist/store/candidates.js +59 -30
  456. package/dist/store/capture-write.d.ts +17 -0
  457. package/dist/store/capture-write.js +35 -0
  458. package/dist/store/cards.js +6 -5
  459. package/dist/store/compaction-caller.d.ts +18 -0
  460. package/dist/store/compaction-caller.js +29 -0
  461. package/dist/store/compactions-record.d.ts +115 -0
  462. package/dist/store/compactions-record.js +418 -0
  463. package/dist/store/compactions.js +6 -4
  464. package/dist/store/conflicts.d.ts +7 -1
  465. package/dist/store/conflicts.js +13 -9
  466. package/dist/store/connectors/dlq.d.ts +10 -0
  467. package/dist/store/connectors/dlq.js +33 -0
  468. package/dist/store/connectors/event-log.d.ts +13 -0
  469. package/dist/store/connectors/event-log.js +24 -0
  470. package/dist/store/connectors/github.d.ts +7 -9
  471. package/dist/store/connectors/github.js +35 -60
  472. package/dist/store/connectors/slack.d.ts +2 -11
  473. package/dist/store/connectors/slack.js +24 -57
  474. package/dist/store/dashboard-reads.js +8 -6
  475. package/dist/store/delete-and-batch.d.ts +6 -0
  476. package/dist/store/delete-and-batch.js +40 -6
  477. package/dist/store/delivery-recorder.d.ts +12 -5
  478. package/dist/store/delivery-recorder.js +13 -11
  479. package/dist/store/descendant-page.js +8 -4
  480. package/dist/store/dormant.d.ts +1 -1
  481. package/dist/store/dormant.js +10 -4
  482. package/dist/store/embeddings/index.d.ts +2 -12
  483. package/dist/store/embeddings/index.js +5 -374
  484. package/dist/store/entry-reads.d.ts +35 -4
  485. package/dist/store/entry-reads.js +86 -19
  486. package/dist/store/entry-row.js +9 -2
  487. package/dist/store/entry-writes.d.ts +15 -12
  488. package/dist/store/entry-writes.js +54 -22
  489. package/dist/store/failure-log-at.d.ts +8 -0
  490. package/dist/store/failure-log-at.js +16 -0
  491. package/dist/store/failure-log.d.ts +2 -2
  492. package/dist/store/failure-log.js +5 -3
  493. package/dist/{trust → store}/gated-write.d.ts +3 -1
  494. package/dist/{trust → store}/gated-write.js +7 -5
  495. package/dist/store/goals.js +22 -19
  496. package/dist/store/graph-reads.js +9 -6
  497. package/dist/store/graph-view-rows.js +2 -1
  498. package/dist/store/graph-writes.d.ts +6 -6
  499. package/dist/store/graph-writes.js +48 -71
  500. package/dist/store/half-life.js +2 -2
  501. package/dist/store/handoffs.d.ts +10 -4
  502. package/dist/store/handoffs.js +10 -9
  503. package/dist/store/index-and-stats.js +2 -2
  504. package/dist/store/index.d.ts +2 -2
  505. package/dist/store/index.js +1 -1
  506. package/dist/store/key-writes.js +1 -1
  507. package/dist/store/ledger-turn.d.ts +9 -0
  508. package/dist/store/ledger-turn.js +38 -0
  509. package/dist/store/mirrors.js +19 -10
  510. package/dist/store/open.d.ts +2 -5
  511. package/dist/store/open.js +42 -54
  512. package/dist/store/pilot-arm.d.ts +12 -0
  513. package/dist/store/pilot-arm.js +42 -0
  514. package/dist/store/port.d.ts +68 -6
  515. package/dist/store/port.js +8 -0
  516. package/dist/store/predictions.d.ts +1 -2
  517. package/dist/store/predictions.js +3 -6
  518. package/dist/store/project-tags.d.ts +62 -0
  519. package/dist/store/project-tags.js +67 -0
  520. package/dist/store/quality-repair.js +1 -1
  521. package/dist/store/quarantine.js +2 -1
  522. package/dist/store/recall-trace.d.ts +2 -0
  523. package/dist/store/recall-trace.js +20 -3
  524. package/dist/store/rejected-values.js +16 -10
  525. package/dist/store/rejection-probe.d.ts +4 -0
  526. package/dist/store/rejection-probe.js +19 -0
  527. package/dist/store/rejection.d.ts +0 -17
  528. package/dist/store/rejection.js +1 -21
  529. package/dist/store/rows.js +2 -2
  530. package/dist/store/rule-sql.d.ts +11 -0
  531. package/dist/store/rule-sql.js +31 -6
  532. package/dist/store/search-rows.d.ts +5 -5
  533. package/dist/store/search-rows.js +18 -16
  534. package/dist/store/sessions.js +4 -2
  535. package/dist/store/set-aside.d.ts +14 -0
  536. package/dist/store/set-aside.js +23 -0
  537. package/dist/store/sqlite/busy.d.ts +3 -0
  538. package/dist/store/sqlite/busy.js +8 -0
  539. package/dist/store/sqlite/connector-events-group.js +4 -7
  540. package/dist/store/sqlite/connector-writes-group.js +6 -4
  541. package/dist/store/sqlite/entry-writes-group.d.ts +3 -3
  542. package/dist/store/sqlite/entry-writes-group.js +3 -3
  543. package/dist/store/sqlite/error-codec.js +4 -3
  544. package/dist/store/sqlite/executor.js +10 -4
  545. package/dist/store/sqlite/graph-reads-group.js +1 -1
  546. package/dist/store/sqlite/held-connection.d.ts +11 -0
  547. package/dist/store/sqlite/held-connection.js +41 -0
  548. package/dist/store/sqlite/last-recall-group.d.ts +13 -0
  549. package/dist/store/sqlite/last-recall-group.js +57 -0
  550. package/dist/store/sqlite/local.d.ts +0 -17
  551. package/dist/store/sqlite/local.js +0 -31
  552. package/dist/store/sqlite/maintenance-groups.d.ts +6 -0
  553. package/dist/store/sqlite/maintenance-groups.js +60 -0
  554. package/dist/store/sqlite/object-rows.d.ts +1 -1
  555. package/dist/store/sqlite/objects-group.d.ts +1 -1
  556. package/dist/store/sqlite/objects-group.js +15 -7
  557. package/dist/store/sqlite/store.d.ts +1 -8
  558. package/dist/store/sqlite/store.js +13 -22
  559. package/dist/store/summaries.d.ts +10 -3
  560. package/dist/store/summaries.js +54 -11
  561. package/dist/store/token-ledger-rows.js +3 -2
  562. package/dist/store/token-ledger.d.ts +0 -7
  563. package/dist/store/token-ledger.js +0 -35
  564. package/dist/store/vector-index.js +8 -4
  565. package/dist/support-bundle.js +2 -3
  566. package/dist/trust/reject-flow.js +2 -2
  567. package/dist/util/agent-homes.d.ts +15 -0
  568. package/dist/util/agent-homes.js +34 -0
  569. package/dist/util/anthropic-messages.d.ts +6 -1
  570. package/dist/util/anthropic-messages.js +26 -7
  571. package/dist/util/atomic-write.d.ts +5 -2
  572. package/dist/util/atomic-write.js +12 -8
  573. package/dist/util/chunked.d.ts +3 -0
  574. package/dist/util/chunked.js +10 -0
  575. package/dist/util/ellipsize.d.ts +3 -0
  576. package/dist/util/ellipsize.js +5 -0
  577. package/dist/util/env.d.ts +12 -2
  578. package/dist/util/env.js +12 -2
  579. package/dist/util/format.d.ts +5 -0
  580. package/dist/util/format.js +10 -0
  581. package/dist/util/hook-payload.d.ts +8 -0
  582. package/dist/util/hook-payload.js +37 -0
  583. package/dist/util/http-retry.d.ts +6 -0
  584. package/dist/util/http-retry.js +43 -5
  585. package/dist/util/http-util.d.ts +0 -8
  586. package/dist/util/http-util.js +10 -21
  587. package/dist/util/limits.d.ts +7 -0
  588. package/dist/util/limits.js +14 -0
  589. package/dist/util/log.d.ts +4 -0
  590. package/dist/util/log.js +9 -0
  591. package/dist/util/request-scope.d.ts +9 -3
  592. package/dist/util/request-scope.js +18 -9
  593. package/dist/util/secret-detect.js +6 -1
  594. package/dist/util/spawn-argv.d.ts +9 -0
  595. package/dist/util/spawn-argv.js +57 -0
  596. package/dist/util/sql.d.ts +3 -0
  597. package/dist/util/sql.js +6 -0
  598. package/dist/util/sqlite-blocked.d.ts +2 -0
  599. package/dist/util/sqlite-blocked.js +5 -0
  600. package/dist/util/stream-tee.d.ts +3 -0
  601. package/dist/util/stream-tee.js +35 -0
  602. package/dist/util/time.d.ts +4 -0
  603. package/dist/util/time.js +4 -0
  604. package/dist/util/vector-codec.d.ts +4 -0
  605. package/dist/util/vector-codec.js +15 -0
  606. package/dist/util/version.d.ts +1 -1
  607. package/dist/util/version.js +1 -1
  608. package/extensions/openclaw-plugin/openclaw.plugin.json +1 -1
  609. package/extensions/openclaw-plugin/package.json +1 -1
  610. package/openclaw.plugin.json +1 -1
  611. package/package.json +4 -2
  612. package/dist/api/on-store.d.ts +0 -16
  613. package/dist/api/on-store.js +0 -38
  614. package/dist/store/embeddings/local.d.ts +0 -15
  615. package/dist/store/embeddings/local.js +0 -175
  616. /package/dist/{cli → api}/correction-latency.d.ts +0 -0
  617. /package/dist/{cli → api}/correction-latency.js +0 -0
  618. /package/dist/{cli → api}/provenance-coverage.d.ts +0 -0
  619. /package/dist/{cli → api}/provenance-coverage.js +0 -0
  620. /package/dist/{store → core}/object-types.d.ts +0 -0
  621. /package/dist/{store → core}/object-types.js +0 -0
  622. /package/dist/{capture → util}/compaction-items.d.ts +0 -0
  623. /package/dist/{capture → util}/compaction-items.js +0 -0
  624. /package/dist/{store → util}/yaml.d.ts +0 -0
  625. /package/dist/{store → util}/yaml.js +0 -0
@@ -1,50 +1,55 @@
1
1
  import { calculateStrength } from '../core/memory.js';
2
2
  import { estimateTokens } from '../util/token-text.js';
3
- import { evalNow, isRecallBoostAblated } from '../core/ablation.js';
3
+ import { evalNow, isRecallBoostAblated, strengthAblation } from '../core/ablation.js';
4
4
  import { indexNeedsRebuild } from '../store/embeddings/index.js';
5
5
  import { indexedModel } from '../store/vector-index.js';
6
- import { resolveEmbeddingProvider } from '../store/embeddings/provider.js';
6
+ import { resolveEmbeddingProvider } from '../embeddings/provider.js';
7
7
  import { physicsScore as computePhysicsScores, computeMass } from '../core/physics.js';
8
8
  import { DEFAULT_PHYSICS_CONFIG } from '../core/physics-config.js';
9
- import { rethrowIfSqliteBlocked } from '../db/index.js';
9
+ import { rethrowIfSqliteBlocked } from '../util/sqlite-blocked.js';
10
10
  import { compareScoredResults } from '../core/compare.js';
11
11
  import { errorMessage, log } from '../util/log.js';
12
- import { sqliteStore } from '../store/index.js';
13
12
  import { churnStaleFactor, summaryMultipliers, summaryScoring } from './boosts.js';
14
13
  import { addDagFields, ageInDays } from './breakdown.js';
15
14
  import { fitBudget } from './finalize.js';
16
- import { hybridSearch } from './hybrid.js';
15
+ import { hybridSearch, vectorSourceOf } from './hybrid.js';
17
16
  import { currentEntries } from './as-of.js';
18
- import { embedQueryBy, requireVectorReads, startQueryEmbedDeadline, vectorCandidatesOutside } from './vector.js';
17
+ import { embedQueryBy, requireVectorReads, startQueryEmbedDeadline, vectorCandidatesOutside, } from './vector.js';
19
18
  import { DEFAULT_RECALL_BUDGET } from '../core/search-types.js';
20
- /** Scores memories by gravity, momentum and cluster amplification; rows without physics state rank through hybridSearch. */
19
+ /** Scores memories by gravity, momentum and cluster amplification; rows without physics state rank through hybridSearch.
20
+ * Reads hippo.db under `hippoRoot` when no store is passed. */
21
21
  export async function physicsSearch(query, entries, options = {}) {
22
+ const source = entries.length > 0 ? vectorSourceOf(options) : undefined;
23
+ return source ? physicsSearchIn(source, query, entries, options) : [];
24
+ }
25
+ /** physicsSearch on the store the caller names, so a caller holding its request's store never falls back to hippo.db. */
26
+ export async function physicsSearchIn(source, query, entries, options = {}) {
22
27
  const now = options.now ?? evalNow(); // honors HIPPO_FAKE_NOW (eval-only; see ablation.ts)
23
28
  const explain = options.explain ?? false;
24
29
  const scoring = { now, explain, summary: summaryScoring(options) };
25
- if (entries.length === 0 || !options.hippoRoot)
30
+ if (entries.length === 0)
26
31
  return [];
32
+ const { root, store } = source;
33
+ const hybrid = { ...options, hippoRoot: root, store };
27
34
  // memory_physics keeps only current positions and masses, so a past-dated query must rank without them.
28
35
  if (options.asOf)
29
- return hybridSearch(query, entries, options);
30
- const root = options.hippoRoot;
31
- const store = options.store ?? sqliteStore(root);
36
+ return hybridSearch(query, entries, hybrid);
32
37
  // Shared with every hybrid ranking below, so a provider that stalls here is not waited on a second time.
33
38
  const queryEmbedDeadline = startQueryEmbedDeadline();
34
39
  const queryVector = await physicsQueryVector(query, root, store, queryEmbedDeadline, options.queryEmbedding);
35
40
  if (!queryVector)
36
- return hybridSearch(query, entries, { ...options, queryEmbedDeadline });
41
+ return hybridSearch(query, entries, { ...hybrid, queryEmbedDeadline });
37
42
  // Checked here too, since a caller's own query vector skips the check inside physicsQueryVector.
38
43
  const reads = requireVectorReads(store);
39
44
  const pool = currentEntries(await withVectorCandidates(reads, entries, queryVector, options.vectorCandidates), options);
40
45
  const physicsMap = await loadCandidateParticles(reads, pool);
41
46
  if (!physicsMap)
42
- return hybridSearch(query, pool, { ...options, queryEmbedDeadline });
47
+ return hybridSearch(query, pool, { ...hybrid, queryEmbedDeadline });
43
48
  const pools = splitByParticle(pool, physicsMap, queryVector, now);
44
49
  const config = options.physicsConfig ?? DEFAULT_PHYSICS_CONFIG;
45
50
  const physicsResults = scorePhysicsPool(pools, queryVector, config, scoring);
46
51
  const classicResults = pools.classic.length > 0
47
- ? await hybridSearch(query, pools.classic, { ...options, queryEmbedDeadline, vectorCandidates: undefined, budget: Infinity, explain })
52
+ ? await hybridSearch(query, pools.classic, { ...hybrid, queryEmbedDeadline, vectorCandidates: undefined, budget: Infinity, explain })
48
53
  : [];
49
54
  const merged = mergeScorePools(physicsResults, classicResults);
50
55
  merged.sort(compareScoredResults);
@@ -107,7 +112,9 @@ function splitByParticle(pool, physicsMap, queryVector, now) {
107
112
  }
108
113
  pools.entries.push(entry);
109
114
  // EVAL-ONLY ablation (see ablation.ts): persisted masses bake in recall history twice, so the flag recomputes mass live.
110
- pools.particles.push(isRecallBoostAblated() ? { ...particle, mass: computeMass(calculateStrength(entry, now), entry.retrieval_count) } : particle);
115
+ pools.particles.push(isRecallBoostAblated()
116
+ ? { ...particle, mass: computeMass(calculateStrength(entry, now, { ablation: strengthAblation() }), entry.retrieval_count) }
117
+ : particle);
111
118
  }
112
119
  return pools;
113
120
  }
@@ -1,4 +1,4 @@
1
- import { cosineOf } from '../store/embeddings/index.js';
1
+ import { cosineOf } from '../core/cosine.js';
2
2
  const DEFAULT_RERANK_TOP_K = 50;
3
3
  // MMR is O(K^2) cosine ops; candidates below this window never survive budget filtering anyway.
4
4
  const MMR_CANDIDATE_CAP = 100;
@@ -1,6 +1,6 @@
1
1
  import type { MemoryEntry } from '../core/memory.js';
2
2
  import type { VectorCandidateSpec } from '../store/search-rows.js';
3
- import { type EmbeddingProvider } from '../store/embeddings/provider.js';
3
+ import { type EmbeddingProvider } from '../embeddings/provider.js';
4
4
  import { type HippoStore, type VectorReads } from '../store/index.js';
5
5
  import { type CurrentnessOptions } from './as-of.js';
6
6
  /** hybridSearch's vector arm: which rows it may add, plus the caller's JS admission rules (exact private regex, entry filters). */
@@ -15,24 +15,26 @@ export interface VectorArm {
15
15
  embeddingIndex: Record<string, ArrayLike<number>>;
16
16
  queryVector: number[];
17
17
  }
18
+ /** Where the vector arm reads: the embedding provider configured under `root`, and the vectors `store` holds. */
19
+ export interface VectorSource {
20
+ readonly root: string;
21
+ readonly store: HippoStore;
22
+ }
18
23
  export interface VectorArmOptions extends CurrentnessOptions {
19
- hippoRoot?: string;
20
24
  vectorCandidates?: HybridVectorCandidates;
21
- /** Where vectors are read; hippo.db under `hippoRoot` when unset. */
22
- store?: HippoStore;
23
25
  /** The deadline a caller already started for this recall's query embedding; a fresh budget when unset. */
24
26
  queryEmbedDeadline?: AbortSignal;
25
27
  }
26
28
  /** One deadline for every query embedding a recall makes, so two stores or a physics fallback share the budget. */
27
29
  export declare function startQueryEmbedDeadline(): AbortSignal;
28
- /** The query's vector, or null when an API provider outlasts `deadline`; any other provider failure throws as before. */
30
+ /** The query's vector, or null when the provider outlasts `deadline`: an API call, or a local model still downloading. Any other failure throws. */
29
31
  export declare function embedQueryBy(deadline: AbortSignal, provider: EmbeddingProvider, query: string): Promise<number[] | null>;
30
32
  /** The store's vector reads; a store without them answers 501, as any unported path does. */
31
33
  export declare function requireVectorReads(store: HippoStore): VectorReads;
32
34
  /** The nearest admitted rows not already in `entries`. */
33
35
  export declare function vectorCandidatesOutside(reads: VectorReads, entries: readonly MemoryEntry[], queryVector: readonly number[], spec: HybridVectorCandidates): Promise<MemoryEntry[]>;
34
36
  /** Embeds the query and loads stored vectors; any failure leaves BM25 to rank alone. */
35
- export declare function resolveVectorArm(query: string, entries: MemoryEntry[], options: VectorArmOptions): Promise<VectorArm>;
37
+ export declare function resolveVectorArm(query: string, entries: MemoryEntry[], source: VectorSource | undefined, options: VectorArmOptions): Promise<VectorArm>;
36
38
  export interface DenseScores {
37
39
  cosine: number[];
38
40
  /** Whether each entry had a cached doc vector to compare against. */
@@ -1,10 +1,11 @@
1
- import { cosineOf, indexNeedsRebuild } from '../store/embeddings/index.js';
1
+ import { cosineOf } from '../core/cosine.js';
2
+ import { indexNeedsRebuild } from '../store/embeddings/index.js';
2
3
  import { indexedModel } from '../store/vector-index.js';
3
- import { resolveEmbeddingProvider } from '../store/embeddings/provider.js';
4
- import { rethrowIfSqliteBlocked } from '../db/index.js';
4
+ import { resolveEmbeddingProvider } from '../embeddings/provider.js';
5
+ import { rethrowIfSqliteBlocked } from '../util/sqlite-blocked.js';
5
6
  import { errorMessage, log } from '../util/log.js';
6
7
  import { envQueryEmbedTimeoutMs } from '../util/env.js';
7
- import { requireGroup, sqliteStore } from '../store/index.js';
8
+ import { hasGroup, requireGroup } from '../store/index.js';
8
9
  import { redactSecretsStrict } from '../util/secret-detect.js';
9
10
  import { currentEntries } from './as-of.js';
10
11
  // Jev's default budget (rerankers/jev.ts): each is one off-box call that a recall waits on.
@@ -17,11 +18,8 @@ function queryEmbedBudgetMs() {
17
18
  export function startQueryEmbedDeadline() {
18
19
  return AbortSignal.timeout(queryEmbedBudgetMs());
19
20
  }
20
- /** The query's vector, or null when an API provider outlasts `deadline`; any other provider failure throws as before. */
21
+ /** The query's vector, or null when the provider outlasts `deadline`: an API call, or a local model still downloading. Any other failure throws. */
21
22
  export async function embedQueryBy(deadline, provider, query) {
22
- // No signal stops an in-process model, so the local provider is not held to the deadline.
23
- if (provider.kind === 'local')
24
- return (await provider.embed([query], 'query'))[0] ?? [];
25
23
  try {
26
24
  return (await provider.embed([query], 'query', { signal: deadline }))[0] ?? [];
27
25
  }
@@ -35,12 +33,12 @@ export async function embedQueryBy(deadline, provider, query) {
35
33
  function warnBm25Fallback(reason, detail) {
36
34
  log.once(`search.bm25-fallback.${reason}`, 'warn', `hybrid search fell back to BM25 only: ${redactSecretsStrict(detail)}`);
37
35
  }
38
- function reindexHint(storeKind) {
36
+ function reindexHint(store) {
39
37
  const why = 'the embedding index was built by another model or is being rebuilt';
40
38
  // `hippo embed` writes only hippo.db, so another store gets its vectors by a rebuild from it.
41
- return storeKind === 'sqlite'
39
+ return hasGroup(store, 'localFiles')
42
40
  ? `${why}; run 'hippo embed'`
43
- : `${why}; run 'hippo embed' on the SQLite store, then rebuild the '${storeKind}' database from it`;
41
+ : `${why}; run 'hippo embed' on the SQLite store, then rebuild the '${store.kind}' database from it`;
44
42
  }
45
43
  /** The store's vector reads; a store without them answers 501, as any unported path does. */
46
44
  export function requireVectorReads(store) {
@@ -54,12 +52,12 @@ export async function vectorCandidatesOutside(reads, entries, queryVector, spec)
54
52
  return (await reads.nearestEntries(queryVector, stored)).filter((e) => !inPool.has(e.id) && (admit?.(e) ?? true));
55
53
  }
56
54
  /** Embeds the query and loads stored vectors; any failure leaves BM25 to rank alone. */
57
- export async function resolveVectorArm(query, entries, options) {
55
+ export async function resolveVectorArm(query, entries, source, options) {
58
56
  const arm = { entries, addedRows: false, useEmbeddings: false, embeddingIndex: {}, queryVector: [] };
59
- if (!options.hippoRoot)
57
+ if (!source)
60
58
  return arm;
61
59
  try {
62
- await fillVectorArm(arm, query, options.hippoRoot, options);
60
+ await fillVectorArm(arm, query, source, options);
63
61
  }
64
62
  catch (err) {
65
63
  rethrowIfSqliteBlocked(err);
@@ -71,15 +69,14 @@ export async function resolveVectorArm(query, entries, options) {
71
69
  async function storedVectorsOf(store, reads, ids) {
72
70
  return store.vectorViews ? store.vectorViews.storedVectorViews(ids) : reads.storedVectors(ids);
73
71
  }
74
- async function fillVectorArm(arm, query, root, options) {
72
+ async function fillVectorArm(arm, query, { root, store }, options) {
75
73
  const provider = resolveEmbeddingProvider(root);
76
74
  if (!provider.isAvailable())
77
75
  return;
78
- const store = options.store ?? sqliteStore(root);
79
76
  const reads = requireVectorReads(store);
80
77
  const index = await reads.embeddingIndexState();
81
78
  if (indexNeedsRebuild(indexedModel(index), provider.id)) {
82
- warnBm25Fallback('reindex', reindexHint(store.kind));
79
+ warnBm25Fallback('reindex', reindexHint(store));
83
80
  return;
84
81
  }
85
82
  const spec = options.vectorCandidates;
@@ -16,7 +16,7 @@ type AuthHeader = {
16
16
  token: string;
17
17
  };
18
18
  export declare function readAuthHeader(req: IncomingMessage): AuthHeader;
19
- type AuthOpts = Pick<ResolvedServeOpts, 'hippoRoot' | 'authResolver' | 'authResolverTimeoutMs' | 'store' | 'callerLimiter'> & Partial<Pick<ResolvedServeOpts, 'failedAuthLimiter'>>;
19
+ type AuthOpts = Pick<ResolvedServeOpts, 'hippoRoot' | 'authResolver' | 'authResolverTimeoutMs' | 'store' | 'callerLimiter'> & Partial<Pick<ResolvedServeOpts, 'failedAuthLimiter' | 'keylessLocalRole'>>;
20
20
  /** Add-ons call this to refuse a subject that would collide with a built-in actor. */
21
21
  export declare function isReservedActor(subject: string): boolean;
22
22
  /** Key cap for every serve() bucket, shared by the warn map so it never tracks more callers than the buckets do. */
@@ -24,6 +24,8 @@ export declare const LIMITER_MAX_KEYS = 10000;
24
24
  /** Builds a per-request Context from the Authorization header and remote address; throws HttpError(401) for invalid or missing credentials.
25
25
  * Reads the store only for an API-key-shaped Bearer (or any Bearer when no auth resolver is registered), so keyless local requests stay cheap. */
26
26
  export declare function buildContextWithAuth(req: IncomingMessage, opts: AuthOpts): Promise<Context>;
27
+ /** The auth check again, uncharged, for a handler that authenticated with requireAuth before a slow body read and must re-check right before it acts. */
28
+ export declare function recheckContextWithAuth(req: IncomingMessage, opts: AuthOpts): Promise<Context>;
27
29
  /** Auth check for routes that need no tenant Context (e.g. the MCP transport, which resolves its own root): throws HttpError 401 like buildContextWithAuth.
28
30
  * A keyless local request passes only under HIPPO_ALLOW_KEYLESS_LOCAL=1. */
29
31
  export declare function requireAuth(req: IncomingMessage, opts: AuthOpts): Promise<void>;
@@ -1,10 +1,11 @@
1
1
  // Bearer and loopback auth for the HTTP server.
2
- import { envAllowKeylessLocal, envRequireAuth } from '../util/env.js';
2
+ import { envAllowKeylessLocal, envKeylessLocalRole, envRequireAuth } from '../util/env.js';
3
3
  import { resolveTenantId } from '../store/tenant.js';
4
- import { log } from '../util/log.js';
4
+ import { errorFields, errorMessage, log } from '../util/log.js';
5
5
  import { API_KEY_PREFIX, verifyApiKeyCached } from '../store/auth.js';
6
6
  import { ownerOrSubject } from '../api/index.js';
7
- import { HttpError, isCrossSite, isHeaderString, LOOPBACK_HOST_HEADER, MAX_ID_LEN } from '../util/http-util.js';
7
+ import { HttpError, isCrossSite, isHeaderString, LOOPBACK_HOST_HEADER } from '../util/http-util.js';
8
+ import { MAX_ID_LEN } from '../util/limits.js';
8
9
  import { clientLimitKey } from './client-ip.js';
9
10
  import { keyCheckBounds } from './key-check-bounds.js';
10
11
  import { isJsonString } from '../util/json.js';
@@ -243,18 +244,24 @@ function chargeCaller(tenantId, actor, opts) {
243
244
  * Reads the store only for an API-key-shaped Bearer (or any Bearer when no auth resolver is registered), so keyless local requests stay cheap. */
244
245
  export async function buildContextWithAuth(req, opts) {
245
246
  const id = await checkAuth(req, opts);
246
- if (id !== null) {
247
- const actor = bearerActor(id);
248
- chargeCaller(id.tenantId, actor, opts);
249
- return { hippoRoot: opts.hippoRoot, tenantId: id.tenantId, actor, store: opts.store };
250
- }
251
- // The keyless local fallback (HIPPO_ALLOW_KEYLESS_LOCAL=1) is this machine's own user, so it is host admin.
252
- return {
253
- hippoRoot: opts.hippoRoot,
254
- tenantId: resolveTenantId({}),
255
- actor: { subject: 'localhost:cli', role: 'admin', hostAdmin: true },
256
- store: opts.store,
257
- };
247
+ const ctx = contextFor(id, opts);
248
+ if (id !== null)
249
+ chargeCaller(id.tenantId, ctx.actor, opts);
250
+ return ctx;
251
+ }
252
+ /** The auth check again, uncharged, for a handler that authenticated with requireAuth before a slow body read and must re-check right before it acts. */
253
+ export async function recheckContextWithAuth(req, opts) {
254
+ return contextFor(await checkAuth(req, opts), opts);
255
+ }
256
+ /** The keyless local caller: any process on this machine can reach loopback, so it is a member unless the operator names admin. */
257
+ function keylessLocalActor(opts) {
258
+ const role = opts.keylessLocalRole ?? envKeylessLocalRole();
259
+ return role === 'admin' ? { subject: 'localhost:cli', role: 'admin', hostAdmin: true } : { subject: 'localhost:cli', role: 'member' };
260
+ }
261
+ function contextFor(id, opts) {
262
+ if (id !== null)
263
+ return { hippoRoot: opts.hippoRoot, tenantId: id.tenantId, actor: bearerActor(id), store: opts.store };
264
+ return { hippoRoot: opts.hippoRoot, tenantId: resolveTenantId({}), actor: keylessLocalActor(opts), store: opts.store };
258
265
  }
259
266
  /** Auth check for routes that need no tenant Context (e.g. the MCP transport, which resolves its own root): throws HttpError 401 like buildContextWithAuth.
260
267
  * A keyless local request passes only under HIPPO_ALLOW_KEYLESS_LOCAL=1. */
@@ -270,6 +277,8 @@ export async function heartbeatVerdict(req, opts) {
270
277
  return 'ok';
271
278
  }
272
279
  catch (err) {
280
+ if (!(err instanceof HttpError))
281
+ log.error(`heartbeat auth check failed: ${errorMessage(err)}`, errorFields(err));
273
282
  return err instanceof HttpError && err.status < 500 && err.status !== 429 ? 'revoked' : 'unavailable';
274
283
  }
275
284
  }
@@ -1,5 +1,6 @@
1
1
  import type { ServeOpts, ServerHandle } from './types.js';
2
- /** Boots the HTTP daemon on host:port and writes the pidfile under hippoRoot; refuses non-loopback hosts unless HIPPO_REQUIRE_AUTH=1.
2
+ /** Boots the HTTP daemon on host:port and writes the pidfile under hippoRoot; refuses a non-loopback host unless HIPPO_REQUIRE_AUTH=1 and
3
+ * either `tls` or allowCleartext is given, and refuses HIPPO_CLIENT_IP_HEADER without HIPPO_TRUSTED_PROXIES.
3
4
  * Use port: 0 in tests for an ephemeral port. See docs/ARCHITECTURE.md#srcserverbootts. */
4
5
  export declare function serve(opts: ServeOpts): Promise<ServerHandle>;
5
6
  //# sourceMappingURL=boot.d.ts.map
@@ -1,9 +1,9 @@
1
- import { envPort, envRequireAuth, envV1Rps } from '../util/env.js';
2
- import { existsSync } from 'node:fs';
1
+ import { envAllowCleartext, envCallerRps, envPort, envRequireAuth, envV1Rps } from '../util/env.js';
3
2
  import { detectServer, removePidfileIfOwned, writePidfile } from './server-detect.js';
4
- import { closeHippoDb, getHippoDbPath, isStoreBusy, openHippoDb, outsideRequestStores, outsideSqliteOffLoop, runWithRequestStores, SERVER_DB_WAIT_MS, withSqliteBlocked } from '../db/index.js';
5
- import { startWalCheckpointer } from '../db/wal-checkpointer.js';
6
- import { requireGroup } from '../store/index.js';
3
+ import { outsideSqliteOffLoop, runWithRequestStores, SERVER_DB_WAIT_MS, withSqliteBlocked } from '../db/index.js';
4
+ import { hasGroup } from '../store/index.js';
5
+ import { isStoreBusy } from '../store/sqlite/busy.js';
6
+ import { holdSqliteConnection } from '../store/sqlite/held-connection.js';
7
7
  import { workerSqliteStore } from '../store/sqlite/worker-store.js';
8
8
  import { markSharedStore } from '../core/config.js';
9
9
  import { auditWriteFailureCount } from '../store/audit.js';
@@ -12,12 +12,10 @@ import { errorFields, errorMessage, log } from '../util/log.js';
12
12
  import { runWithRequestId } from '../util/request-scope.js';
13
13
  import { createRateLimiter } from './rate-limit.js';
14
14
  import { RecallContractError } from '../api/index.js';
15
- import { handleSlackEventsWebhook } from '../connectors/slack/webhook.js';
16
- import { handleGitHubEventsWebhook } from '../connectors/github/webhook.js';
17
15
  import { BodyTimeoutError, BodyTooLargeError, closeAfterReply, DeadlineExceededError, HttpError, JSON_HEADERS, sendJson } from '../util/http-util.js';
18
16
  import { workerCounts } from '../store/sqlite/executor-counts.js';
19
17
  import { isLocalCaller, LIMITER_MAX_KEYS } from './auth.js';
20
- import { enforceRateLimit, warnIfClientIpHeaderUnpinned } from './client-ip.js';
18
+ import { assertClientIpHeaderPinned, enforceRateLimit } from './client-ip.js';
21
19
  import { answerAtDeadline, handlerDeadlineCount, isAbandoned, requestDeadlineFor } from './deadline.js';
22
20
  import { DEFAULT_SHUTDOWN_DRAIN_MS, drainAndClose, setKeepAliveTimeouts, shutdownBoundMs } from './lifecycle.js';
23
21
  import { readyProbeFor } from './ready.js';
@@ -26,8 +24,9 @@ import { installCrashHandlers, installSignalHandlers } from '../util/crash-handl
26
24
  import { handleMcpPost, handleMcpStream } from './mcp-http.js';
27
25
  import { MCP_PROJECT_SCOPED_HEADER } from '../core/project-identity.js';
28
26
  import { accessRouteOf, logRequestFailure, noteAccess, openRequest, parseRequest, rejectEncodedSlash, replyFor, sendError } from './request.js';
29
- import { createListener, warnIfCleartext } from './tls.js';
30
- import { assertAddonRoutes, assertPublicJson, dispatchAddonRoute, dispatchPublicJson, dispatchV1Route, isPublicRoute } from './route-table.js';
27
+ import { assertTlsOrCleartextAllowed, createListener } from './tls.js';
28
+ import { assertAddonRoutes, assertPublicJson } from './route-checks.js';
29
+ import { dispatchAddonRoute, dispatchPublicJson, dispatchV1Route } from './route-table.js';
31
30
  // server.address() returns AddressInfo once a TCP socket is bound; null before
32
31
  // listening, a string only for pipe/unix-socket listeners (never used here).
33
32
  function isAddressInfo(a) {
@@ -70,13 +69,7 @@ async function handleRequest(req, res, opts, options) {
70
69
  res.writeHead(404, JSON_HEADERS);
71
70
  res.end(JSON.stringify({ error: 'not found' }));
72
71
  }
73
- const WEBHOOK_GROUPS = ['entryWrites', 'connectorWrites', 'connectorEvents'];
74
- /** A store missing a group a delivery writes through refuses the webhook up front, so no delivery is acknowledged and then half stored. */
75
- function requireWebhookGroups(store) {
76
- for (const group of WEBHOOK_GROUPS)
77
- requireGroup(store, group);
78
- }
79
- /** Every route that runs inside a request scope, so it opens each store once: the /v1 table, public JSON, add-on routes, the webhooks and POST /mcp. */
72
+ /** Every route that runs inside a request scope, so it opens each store once: the /v1 table with the webhooks, public JSON, add-on routes and POST /mcp. */
80
73
  async function dispatchScopedRoute(r, method, path) {
81
74
  if (await dispatchV1Route(r, method, path))
82
75
  return true;
@@ -85,26 +78,6 @@ async function dispatchScopedRoute(r, method, path) {
85
78
  if (await dispatchAddonRoute(r, method, path))
86
79
  return true;
87
80
  const { req, res, opts } = r;
88
- if (method === 'POST' && path === '/v1/connectors/slack/events') {
89
- noteAccess(req, { route: path });
90
- // Bearer auth deliberately skipped: this route is in PUBLIC_ROUTES and authenticates via the Slack HMAC signature.
91
- if (!isPublicRoute(method, path)) {
92
- // Defensive: PUBLIC_ROUTES drift would land here. Fail closed.
93
- throw new HttpError(401, 'auth required');
94
- }
95
- requireWebhookGroups(opts.store);
96
- await handleSlackEventsWebhook({ req, res, opts }, opts.store);
97
- return true;
98
- }
99
- if (method === 'POST' && path === '/v1/connectors/github/events') {
100
- noteAccess(req, { route: path });
101
- if (!isPublicRoute(method, path)) {
102
- throw new HttpError(401, 'auth required');
103
- }
104
- requireWebhookGroups(opts.store);
105
- await handleGitHubEventsWebhook({ req, res, opts }, opts.store);
106
- return true;
107
- }
108
81
  // Store-ready: under another store the MCP layer lists and runs only the tools ported to the port.
109
82
  if (method === 'POST' && path === '/mcp') {
110
83
  noteAccess(req, { route: path });
@@ -184,58 +157,37 @@ function assertRateLimitSpec(name, { ratePerSec, burst }) {
184
157
  if (!Number.isFinite(burst) || burst < 1)
185
158
  throw new Error(`rateLimits.${name}.burst must be a finite number of at least 1`);
186
159
  }
160
+ const DEFAULT_CALLER_RPS = 20;
161
+ /** The per-caller spec when serve() names none: HIPPO_CALLER_RPS (0 is off), else 20 per second with a burst of twice that. */
162
+ function defaultCallerSpec() {
163
+ const raw = envCallerRps();
164
+ const rps = raw === undefined ? DEFAULT_CALLER_RPS : Number(raw);
165
+ // A typo must not switch the limit off, so only an explicit 0 does.
166
+ if (!Number.isFinite(rps) || rps < 0)
167
+ throw new Error(`HIPPO_CALLER_RPS must be a number of at least 0 (0 turns the per-caller limit off), not '${raw}'`);
168
+ return rps === 0 ? 'off' : { ratePerSec: rps, burst: Math.max(1, rps * 2) };
169
+ }
187
170
  /** Refuses a bad spec at boot, since a NaN or zero rate would otherwise turn a bucket off or refuse every request. */
188
171
  function bootLimiters(rateLimits) {
189
- const { perCaller, perAddress, failedAuthPerAddress = DEFAULT_FAILED_AUTH } = rateLimits ?? {};
190
- if (perCaller !== undefined)
172
+ const { perCaller = defaultCallerSpec(), perAddress, failedAuthPerAddress = DEFAULT_FAILED_AUTH } = rateLimits ?? {};
173
+ if (perCaller !== 'off')
191
174
  assertRateLimitSpec('perCaller', perCaller);
192
175
  if (perAddress !== undefined && perAddress !== 'off')
193
176
  assertRateLimitSpec('perAddress', perAddress);
194
177
  assertRateLimitSpec('failedAuthPerAddress', failedAuthPerAddress);
195
- warnIfClientIpHeaderUnpinned();
178
+ assertClientIpHeaderPinned();
196
179
  return {
197
180
  perAddress: bootRateLimiter(perAddress),
198
- callerLimiter: perCaller === undefined ? undefined : limiterFor(perCaller),
181
+ callerLimiter: perCaller === 'off' ? undefined : limiterFor(perCaller),
199
182
  failedAuthLimiter: limiterFor(failedAuthPerAddress),
200
183
  };
201
184
  }
202
185
  function createStoreHolder(hippoRoot, store) {
203
- if (store.kind !== 'sqlite') {
204
- log.info(`serve: the '${store.kind}' store serves ${hippoRoot}, so no hippo.db connection is held`);
205
- return { hold: () => { }, afterResponse: () => { }, release: async () => { } };
206
- }
207
- // Handlers open and close their own connections; while this one is held, none of those closes is SQLite's last,
208
- // which checkpoints and deletes the WAL. It opens only once the store exists, so serving never creates one.
209
- let heldDb;
210
- let checkpointer;
211
- let stopHolding = false;
212
- const hold = () => {
213
- if (heldDb || stopHolding || !existsSync(getHippoDbPath(hippoRoot)))
214
- return;
215
- try {
216
- // The 'finish' listener can fire inside a request scope (closing this connection with the request) and inside a `loop: 'off'` block (refusing the open).
217
- // The server's lock wait: this open runs on the event loop, where SQLite's 5 s default and the 30 s journal-mode retry would stall every request.
218
- heldDb = outsideSqliteOffLoop(() => outsideRequestStores(() => openHippoDb(hippoRoot, { busyWaitMs: SERVER_DB_WAIT_MS })));
219
- checkpointer = startWalCheckpointer(getHippoDbPath(hippoRoot));
220
- }
221
- catch (err) {
222
- stopHolding = true;
223
- log.warn(`serve: could not hold a store connection; requests still work, only slower: ${errorMessage(err)}`);
224
- }
225
- };
226
- const afterResponse = () => {
227
- hold();
228
- checkpointer?.noteResponse();
229
- };
230
- const release = async () => {
231
- stopHolding = true;
232
- // The worker's connection closes first, so the held one is SQLite's last and its close checkpoints and deletes the WAL.
233
- await checkpointer?.stop();
234
- if (heldDb)
235
- closeHippoDb(heldDb);
236
- heldDb = undefined;
237
- };
238
- return { hold, afterResponse, release };
186
+ if (hasGroup(store, 'localFiles'))
187
+ return holdSqliteConnection(hippoRoot);
188
+ log.info(`serve: the '${store.kind}' store serves ${hippoRoot}, so no hippo.db connection is held`);
189
+ // A missed port under another store would otherwise create and write a hippo.db that store never reads.
190
+ return { hold: () => { }, afterResponse: () => { }, release: async () => { }, runRequest: (run) => withSqliteBlocked(store.kind, run) };
239
191
  }
240
192
  // A plugin's resolver may read hippo.db through this package's synchronous functions, so it runs outside the block of a `loop: 'off'` route.
241
193
  function outsideRouteBlock(resolver) {
@@ -346,7 +298,8 @@ function exitOnSignalOrCrash(stop, drainMs) {
346
298
  installSignalHandlers('serve', shutdown);
347
299
  installCrashHandlers('serve', shutdown);
348
300
  }
349
- /** Boots the HTTP daemon on host:port and writes the pidfile under hippoRoot; refuses non-loopback hosts unless HIPPO_REQUIRE_AUTH=1.
301
+ /** Boots the HTTP daemon on host:port and writes the pidfile under hippoRoot; refuses a non-loopback host unless HIPPO_REQUIRE_AUTH=1 and
302
+ * either `tls` or allowCleartext is given, and refuses HIPPO_CLIENT_IP_HEADER without HIPPO_TRUSTED_PROXIES.
350
303
  * Use port: 0 in tests for an ephemeral port. See docs/ARCHITECTURE.md#srcserverbootts. */
351
304
  export async function serve(opts) {
352
305
  const host = opts.host ?? DEFAULT_SERVER_HOST;
@@ -355,6 +308,7 @@ export async function serve(opts) {
355
308
  const publicJsonBodies = assertPublicJson(opts.publicJson ?? {});
356
309
  const limiters = bootLimiters(opts.rateLimits);
357
310
  assertBindable(host);
311
+ assertTlsOrCleartextAllowed(host, opts.tls, LOOPBACK_HOSTS, opts.allowCleartext ?? envAllowCleartext());
358
312
  await assertNoLiveServer(opts.hippoRoot);
359
313
  // Single source of truth for the start time: returned by GET /health and written into the pidfile, so detectServer can prove a pid-reusing impostor is not
360
314
  // this server.
@@ -363,7 +317,7 @@ export async function serve(opts) {
363
317
  const streamSlots = new Map();
364
318
  const served = servedOptsFor(opts, routes, publicJsonBodies, limiters);
365
319
  // A store other than hippo.db is a team's central server, so its folder's config.json must not decide shared-ness.
366
- if (served.store.kind !== 'sqlite')
320
+ if (!hasGroup(served.store, 'localFiles'))
367
321
  markSharedStore(opts.hippoRoot);
368
322
  const holder = createStoreHolder(opts.hippoRoot, served.store);
369
323
  const inflight = new Set();
@@ -402,14 +356,11 @@ function servedOptsFor(opts, routes, publicJsonBodies, { callerLimiter, failedAu
402
356
  };
403
357
  }
404
358
  function acceptingServer(served, holder, inflight, options) {
405
- const { kind } = served.store;
406
359
  return createListener(served.tls, (req, res) => {
407
360
  res.once('finish', holder.afterResponse);
408
361
  inflight.add(res);
409
362
  res.once('close', () => inflight.delete(res));
410
- const run = () => handleRequest(req, res, served, options);
411
- // A missed port under another store would otherwise create and write a hippo.db that store never reads.
412
- answerRequest(req, res, () => (kind === 'sqlite' ? run() : withSqliteBlocked(kind, run)), served.slowRequestWarnMs);
363
+ answerRequest(req, res, () => holder.runRequest(() => handleRequest(req, res, served, options)), served.slowRequestWarnMs);
413
364
  });
414
365
  }
415
366
  async function listenAndDescribe(server, port, host, tls) {
@@ -421,7 +372,6 @@ async function listenAndDescribe(server, port, host, tls) {
421
372
  const addressInfo = address;
422
373
  const actualPort = addressInfo.port;
423
374
  const url = `${tls ? 'https' : 'http'}://${host.includes(':') ? `[${host}]` : host}:${actualPort}`;
424
- warnIfCleartext(host, tls, LOOPBACK_HOSTS);
425
375
  return { port: actualPort, url };
426
376
  }
427
377
  async function stopListening(opts, server, inflight, startedAt) {
@@ -2,13 +2,16 @@ import type { IncomingMessage } from 'node:http';
2
2
  import type { RateLimiter } from './rate-limit.js';
3
3
  /**
4
4
  * Rate-limit key: the socket's remote address, which behind a TLS proxy collapses into one bucket unauthenticated traffic can drain.
5
- * Set HIPPO_CLIENT_IP_HEADER (fly-client-ip on Fly) only when a trusted proxy fronts EVERY request, or clients could mint a fresh bucket per request.
6
- * HIPPO_TRUSTED_PROXIES (IPs or CIDRs) pins which peers count as that proxy; in a comma-joined chain the key is the rightmost hop no trusted proxy added. */
5
+ * HIPPO_CLIENT_IP_HEADER (fly-client-ip on Fly) is read only from a peer in HIPPO_TRUSTED_PROXIES (IPs or CIDRs, or `*` for any peer),
6
+ * so a caller that reaches the port past the proxy cannot pick its own bucket. In a comma-joined chain the key is the rightmost hop no trusted proxy added. */
7
7
  export declare function clientIpForRateLimit(req: IncomingMessage): string;
8
- /** Said once at boot: with no proxy list, a caller that reaches the port without the proxy picks its own bucket by sending the header. */
9
- export declare function warnIfClientIpHeaderUnpinned(): void;
10
- /** The key for one subscriber: an IPv6 address's /64, since one host may hold the whole /64; any other key as is. */
11
- export declare function subscriberKey(ip: string): string;
8
+ /** serve() refused HIPPO_CLIENT_IP_HEADER with no HIPPO_TRUSTED_PROXIES: the header would be read from no one, so the setting is a mistake. */
9
+ export declare class UntrustedClientIpHeaderError extends Error {
10
+ readonly header: string;
11
+ constructor(header: string);
12
+ }
13
+ /** Checked at boot: a client-IP header needs a trusted-proxy list, and `*` is said once, since it believes any peer. */
14
+ export declare function assertClientIpHeaderPinned(): void;
12
15
  /** The one key every per-address limit and slot count uses, so rotating inside a /64 never buys a fresh bucket. */
13
16
  export declare function clientLimitKey(req: IncomingMessage): string;
14
17
  export declare function enforceRateLimit(req: IncomingMessage, path: string, limiter?: RateLimiter): void;