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.
- package/README.md +7 -5
- package/dist/agent-memories/apply.d.ts +0 -11
- package/dist/agent-memories/apply.js +11 -26
- package/dist/agent-memories/claude-code.js +1 -1
- package/dist/agent-memories/codex.js +1 -1
- package/dist/agent-memories/copilot.d.ts +1 -3
- package/dist/agent-memories/copilot.js +1 -17
- package/dist/agent-memories/project-folds.d.ts +10 -0
- package/dist/agent-memories/project-folds.js +34 -0
- package/dist/agent-memories/sync.js +8 -6
- package/dist/api/assemble.js +3 -2
- package/dist/api/audit.d.ts +30 -2
- package/dist/api/audit.js +48 -7
- package/dist/api/auth.d.ts +11 -9
- package/dist/api/auth.js +39 -40
- package/dist/api/auto-sleep.d.ts +5 -2
- package/dist/api/auto-sleep.js +7 -3
- package/dist/api/availability.js +2 -3
- package/dist/api/cards.d.ts +42 -0
- package/dist/api/cards.js +52 -0
- package/dist/api/conflicts.d.ts +28 -0
- package/dist/api/conflicts.js +61 -0
- package/dist/api/context-auto.js +4 -2
- package/dist/api/context-render.js +4 -3
- package/dist/api/context-select.js +15 -29
- package/dist/api/context.js +29 -18
- package/dist/api/continuity.d.ts +47 -0
- package/dist/api/continuity.js +66 -0
- package/dist/api/dormant.js +4 -2
- package/dist/api/drill-down.js +3 -2
- package/dist/api/embeddings.d.ts +17 -0
- package/dist/api/embeddings.js +28 -0
- package/dist/api/error-reply.d.ts +8 -0
- package/dist/api/error-reply.js +21 -0
- package/dist/api/forget.d.ts +7 -3
- package/dist/api/forget.js +24 -14
- package/dist/api/goals.d.ts +1 -1
- package/dist/api/goals.js +5 -9
- package/dist/api/graph.js +2 -1
- package/dist/api/index.d.ts +4 -2
- package/dist/api/index.js +4 -2
- package/dist/api/instruction-detect.js +5 -1
- package/dist/api/learn.d.ts +5 -1
- package/dist/api/learn.js +71 -44
- package/dist/api/ledger-db.d.ts +2 -6
- package/dist/api/ledger-db.js +4 -36
- package/dist/api/memories.d.ts +21 -1
- package/dist/api/memories.js +51 -1
- package/dist/api/objects.d.ts +1 -1
- package/dist/api/objects.js +2 -1
- package/dist/api/outcome.d.ts +5 -5
- package/dist/api/outcome.js +17 -16
- package/dist/api/pilot-arm.d.ts +1 -11
- package/dist/api/pilot-arm.js +5 -45
- package/dist/api/predictions.d.ts +3 -1
- package/dist/api/predictions.js +8 -1
- package/dist/api/projects.d.ts +21 -0
- package/dist/api/projects.js +24 -0
- package/dist/api/promote.d.ts +3 -3
- package/dist/api/promote.js +26 -28
- package/dist/api/prompt-hook.d.ts +17 -2
- package/dist/api/prompt-hook.js +45 -4
- package/dist/api/quarantine.js +2 -1
- package/dist/api/recall-cli.d.ts +3 -0
- package/dist/api/recall-cli.js +13 -4
- package/dist/api/recall-core.js +10 -5
- package/dist/api/recall-pipeline.js +23 -24
- package/dist/api/recall-request.js +1 -1
- package/dist/api/recall-types.d.ts +3 -1
- package/dist/api/recall.d.ts +0 -3
- package/dist/api/recall.js +51 -73
- package/dist/api/remember-local.d.ts +5 -2
- package/dist/api/remember-local.js +15 -7
- package/dist/api/remember.d.ts +7 -3
- package/dist/api/remember.js +19 -16
- package/dist/api/session-end.d.ts +46 -0
- package/dist/api/session-end.js +131 -0
- package/dist/api/sleep-run.d.ts +1 -1
- package/dist/api/sleep-run.js +16 -11
- package/dist/api/sleep.js +4 -3
- package/dist/api/status.d.ts +24 -0
- package/dist/api/status.js +40 -0
- package/dist/api/store-init.d.ts +4 -0
- package/dist/api/store-init.js +9 -0
- package/dist/api/tokens.js +2 -2
- package/dist/api/types.d.ts +3 -7
- package/dist/api/types.js +6 -1
- package/dist/capture/caller-session.d.ts +0 -3
- package/dist/capture/caller-session.js +1 -12
- package/dist/capture/capture-error.d.ts +2 -2
- package/dist/capture/capture-error.js +23 -18
- package/dist/capture/codex-patch.js +3 -1
- package/dist/capture/command.js +36 -95
- package/dist/capture/compact.js +10 -5
- package/dist/capture/compaction-items-caller.js +11 -20
- package/dist/capture/compaction-record.d.ts +7 -93
- package/dist/capture/compaction-record.js +29 -426
- package/dist/capture/compaction-spool.d.ts +7 -7
- package/dist/capture/compaction-spool.js +60 -51
- package/dist/capture/copilot-transcript.d.ts +2 -1
- package/dist/capture/copilot-transcript.js +2 -1
- package/dist/capture/extract.d.ts +5 -2
- package/dist/capture/extract.js +4 -3
- package/dist/capture/failure-caller.d.ts +1 -1
- package/dist/capture/failure-caller.js +21 -16
- package/dist/capture/failure-reading.d.ts +2 -1
- package/dist/capture/failure-reading.js +7 -9
- package/dist/capture/pre-compact-caller.js +5 -4
- package/dist/capture/session-digest.js +4 -3
- package/dist/capture/session-end-caller.js +3 -2
- package/dist/capture/session-worker.js +22 -10
- package/dist/capture/transcript.d.ts +2 -1
- package/dist/capture/transcript.js +6 -3
- package/dist/capture/working-state.d.ts +4 -2
- package/dist/capture/working-state.js +4 -2
- package/dist/cli/audit-prune.d.ts +0 -25
- package/dist/cli/audit-prune.js +1 -27
- package/dist/cli/audit.js +20 -20
- package/dist/cli/auth.d.ts +1 -1
- package/dist/cli/auth.js +16 -17
- package/dist/cli/briefs.d.ts +1 -4
- package/dist/cli/briefs.js +37 -292
- package/dist/cli/card.js +41 -33
- package/dist/cli/client.d.ts +6 -2
- package/dist/cli/client.js +37 -21
- package/dist/cli/compact-resume-payload.js +1 -1
- package/dist/cli/context.d.ts +1 -1
- package/dist/cli/context.js +13 -13
- package/dist/cli/continuity.d.ts +1 -1
- package/dist/cli/continuity.js +36 -39
- package/dist/cli/curate.d.ts +2 -2
- package/dist/cli/curate.js +32 -36
- package/dist/cli/dag.d.ts +1 -1
- package/dist/cli/dag.js +23 -8
- package/dist/cli/decisions.d.ts +0 -2
- package/dist/cli/decisions.js +7 -285
- package/dist/cli/eval.d.ts +1 -1
- package/dist/cli/eval.js +12 -13
- package/dist/cli/explain.d.ts +1 -1
- package/dist/cli/explain.js +21 -25
- package/dist/cli/flag-values.js +16 -6
- package/dist/cli/flags.d.ts +0 -289
- package/dist/cli/flags.js +3 -138
- package/dist/cli/graph.d.ts +3 -0
- package/dist/cli/graph.js +83 -0
- package/dist/cli/hook-runtime.d.ts +6 -6
- package/dist/cli/hook-runtime.js +9 -36
- package/dist/cli/incidents.d.ts +3 -0
- package/dist/cli/incidents.js +112 -0
- package/dist/cli/init.d.ts +1 -1
- package/dist/cli/init.js +28 -19
- package/dist/cli/install-steps.d.ts +2 -1
- package/dist/cli/install-steps.js +11 -3
- package/dist/cli/last-sleep.js +1 -1
- package/dist/cli/maintenance.d.ts +3 -3
- package/dist/cli/maintenance.js +29 -30
- package/dist/cli/notes.d.ts +2 -0
- package/dist/cli/notes.js +41 -0
- package/dist/cli/object-verbs.d.ts +2 -2
- package/dist/cli/object-verbs.js +4 -4
- package/dist/cli/open-browser.d.ts +14 -0
- package/dist/cli/open-browser.js +26 -0
- package/dist/cli/playbooks.d.ts +3 -4
- package/dist/cli/playbooks.js +126 -290
- package/dist/cli/predictions.d.ts +3 -0
- package/dist/cli/predictions.js +174 -0
- package/dist/cli/print.js +2 -1
- package/dist/cli/projects.js +30 -22
- package/dist/cli/quality-repair-once.d.ts +1 -1
- package/dist/cli/quality-repair-once.js +6 -5
- package/dist/cli/recall.js +13 -7
- package/dist/cli/refine-llm.js +18 -17
- package/dist/cli/remember.js +17 -17
- package/dist/cli/scheduler.js +2 -1
- package/dist/cli/serve.js +11 -6
- package/dist/cli/session-hooks.d.ts +1 -5
- package/dist/cli/session-hooks.js +89 -168
- package/dist/cli/setup.d.ts +1 -1
- package/dist/cli/setup.js +17 -10
- package/dist/cli/shared.d.ts +2 -6
- package/dist/cli/shared.js +9 -29
- package/dist/cli/sleep-render.js +6 -3
- package/dist/cli/sleep.js +6 -37
- package/dist/cli/status.d.ts +3 -3
- package/dist/cli/status.js +32 -35
- package/dist/cli/transfer.d.ts +3 -3
- package/dist/cli/transfer.js +64 -43
- package/dist/cli/usage.d.ts +1 -80
- package/dist/cli/usage.js +2 -696
- package/dist/cli/verb-row.d.ts +34 -0
- package/dist/cli/verb-row.js +6 -0
- package/dist/cli/verbs/health.d.ts +27 -0
- package/dist/cli/verbs/health.js +234 -0
- package/dist/cli/verbs/memory.d.ts +16 -0
- package/dist/cli/verbs/memory.js +236 -0
- package/dist/cli/verbs/objects.d.ts +20 -0
- package/dist/cli/verbs/objects.js +257 -0
- package/dist/cli/verbs/sessions.d.ts +31 -0
- package/dist/cli/verbs/sessions.js +314 -0
- package/dist/cli/verbs.d.ts +81 -0
- package/dist/cli/verbs.js +7 -0
- package/dist/cli/versioned-verbs.d.ts +51 -0
- package/dist/cli/versioned-verbs.js +79 -0
- package/dist/cli.d.ts +1 -272
- package/dist/cli.js +24 -315
- package/dist/connectors/dlq.d.ts +39 -3
- package/dist/connectors/dlq.js +39 -4
- package/dist/connectors/github/backfill.js +12 -3
- package/dist/connectors/github/deletion.js +2 -1
- package/dist/connectors/github/dlq.js +31 -73
- package/dist/connectors/github/ingest.d.ts +2 -6
- package/dist/connectors/github/ingest.js +5 -29
- package/dist/connectors/github/tenant-routing.js +2 -1
- package/dist/connectors/github/webhook.d.ts +2 -1
- package/dist/connectors/github/webhook.js +35 -2
- package/dist/connectors/ingest.d.ts +10 -0
- package/dist/connectors/ingest.js +29 -0
- package/dist/connectors/slack/deletion.js +2 -1
- package/dist/connectors/slack/dlq.js +49 -71
- package/dist/connectors/slack/ingest.d.ts +2 -6
- package/dist/connectors/slack/ingest.js +4 -28
- package/dist/connectors/slack/tenant-routing.js +2 -1
- package/dist/connectors/slack/webhook.d.ts +2 -1
- package/dist/connectors/slack/webhook.js +2 -1
- package/dist/consolidate/conflicts.js +2 -2
- package/dist/consolidate/dag.js +29 -18
- package/dist/consolidate/dedupe.d.ts +7 -0
- package/dist/consolidate/dedupe.js +6 -4
- package/dist/consolidate/llm-passes.js +45 -19
- package/dist/consolidate/memory-value.js +3 -2
- package/dist/consolidate/merge.js +8 -8
- package/dist/consolidate/physics-pass.d.ts +6 -1
- package/dist/consolidate/physics-pass.js +26 -6
- package/dist/consolidate/replay.js +11 -4
- package/dist/consolidate/sleep.js +9 -6
- package/dist/consolidate/traces.js +5 -5
- package/dist/core/ablation.d.ts +10 -0
- package/dist/core/ablation.js +12 -0
- package/dist/{sharing/scope.d.ts → core/active-scope.d.ts} +1 -1
- package/dist/{sharing/scope.js → core/active-scope.js} +1 -1
- package/dist/core/ambient.d.ts +4 -0
- package/dist/core/ambient.js +39 -18
- package/dist/core/api-errors.d.ts +16 -0
- package/dist/core/api-errors.js +20 -0
- package/dist/core/card.js +3 -1
- package/dist/core/compaction-timing.d.ts +7 -0
- package/dist/core/compaction-timing.js +9 -0
- package/dist/core/config.d.ts +1 -1
- package/dist/core/config.js +22 -18
- package/dist/core/cosine.d.ts +3 -0
- package/dist/core/cosine.js +19 -0
- package/dist/{store → core}/markdown.d.ts +1 -1
- package/dist/{store → core}/markdown.js +4 -4
- package/dist/core/memory-audit.d.ts +17 -0
- package/dist/core/memory-audit.js +54 -0
- package/dist/core/memory.d.ts +14 -8
- package/dist/core/memory.js +35 -23
- package/dist/{consolidate → core}/merged-row.d.ts +1 -1
- package/dist/{consolidate → core}/merged-row.js +1 -1
- package/dist/core/physics.d.ts +3 -1
- package/dist/core/physics.js +23 -18
- package/dist/core/prediction.d.ts +3 -0
- package/dist/core/prediction.js +6 -0
- package/dist/core/project-identity.d.ts +3 -0
- package/dist/core/project-identity.js +12 -2
- package/dist/{store → core}/recall-scope.d.ts +1 -10
- package/dist/{store → core}/recall-scope.js +2 -19
- package/dist/core/search-types.d.ts +1 -1
- package/dist/dashboard/dashboard-actions.d.ts +2 -2
- package/dist/dashboard/dashboard-actions.js +5 -5
- package/dist/dashboard/dashboard-queries.js +2 -7
- package/dist/dashboard/dashboard-snapshot.js +1 -3
- package/dist/dashboard/dashboard.js +16 -5
- package/dist/db/busy.d.ts +2 -7
- package/dist/db/busy.js +21 -26
- package/dist/db/connect.d.ts +2 -2
- package/dist/db/connect.js +7 -7
- package/dist/db/index.d.ts +3 -3
- package/dist/db/index.js +3 -3
- package/dist/db/migrate.js +14 -7
- package/dist/db/migrations/index.d.ts +1 -1
- package/dist/db/migrations/index.js +3 -1
- package/dist/db/migrations/v11.js +1 -0
- package/dist/db/migrations/v14.js +1 -0
- package/dist/db/migrations/v55.d.ts +3 -0
- package/dist/db/migrations/v55.js +17 -0
- package/dist/db/open.d.ts +0 -2
- package/dist/db/open.js +6 -10
- package/dist/db/physics-state.d.ts +0 -4
- package/dist/db/physics-state.js +7 -33
- package/dist/db/request-stores.d.ts +1 -0
- package/dist/db/request-stores.js +2 -1
- package/dist/db/tables.d.ts +2 -0
- package/dist/db/tables.js +6 -2
- package/dist/db/vector-store.js +19 -5
- package/dist/db/wal-checkpointer.js +2 -1
- package/dist/doctor.d.ts +3 -0
- package/dist/doctor.js +18 -15
- package/dist/embeddings/local.d.ts +62 -0
- package/dist/embeddings/local.js +146 -0
- package/dist/{store/embeddings → embeddings}/provider.d.ts +5 -2
- package/dist/{store/embeddings → embeddings}/provider.js +19 -25
- package/dist/embeddings/transformers.d.ts +26 -0
- package/dist/embeddings/transformers.js +89 -0
- package/dist/entry/session-text.d.ts +1 -1
- package/dist/entry/session-text.js +1 -1
- package/dist/entry/store-kit.d.ts +37 -0
- package/dist/entry/store-kit.js +25 -0
- package/dist/entry/testing.d.ts +6 -0
- package/dist/entry/testing.js +7 -0
- package/dist/eval/eval-suite.js +17 -11
- package/dist/eval/eval.js +1 -1
- package/dist/eval/judgment.js +12 -5
- package/dist/graph/extract.js +3 -3
- package/dist/graph/recall.js +1 -1
- package/dist/graph/view.js +13 -5
- package/dist/graph/write.d.ts +1 -1
- package/dist/graph/write.js +9 -9
- package/dist/hooks/codex-session.js +3 -2
- package/dist/hooks/codex-wrapper.js +2 -1
- package/dist/hooks/json-hooks.js +10 -4
- package/dist/hooks/opencode.js +8 -5
- package/dist/hooks/shared.d.ts +0 -6
- package/dist/hooks/shared.js +4 -15
- package/dist/importers/core.js +4 -4
- package/dist/importers/sources.js +5 -4
- package/dist/importers/vault.d.ts +1 -1
- package/dist/importers/vault.js +25 -23
- package/dist/index.d.ts +5 -4
- package/dist/index.js +4 -3
- package/dist/learn/autolearn.d.ts +15 -3
- package/dist/learn/autolearn.js +38 -16
- package/dist/learn/churn-git.js +13 -4
- package/dist/learn/extract.d.ts +3 -2
- package/dist/learn/extract.js +7 -5
- package/dist/learn/forward-claim-detector.js +4 -2
- package/dist/learn/invalidation.d.ts +2 -1
- package/dist/learn/invalidation.js +18 -9
- package/dist/mcp/admin-tools.d.ts +2 -2
- package/dist/mcp/admin-tools.js +27 -48
- package/dist/mcp/format.js +3 -2
- package/dist/mcp/framing.d.ts +1 -0
- package/dist/mcp/framing.js +1 -1
- package/dist/mcp/memory-tools.d.ts +1 -1
- package/dist/mcp/memory-tools.js +8 -9
- package/dist/mcp/protocol.d.ts +11 -7
- package/dist/mcp/protocol.js +25 -12
- package/dist/mcp/recall-tools.js +12 -9
- package/dist/mcp/request.js +22 -20
- package/dist/mcp/stdio.js +37 -16
- package/dist/mcp/tool-args.js +2 -1
- package/dist/mcp/tools.js +44 -21
- package/dist/objects/customer-notes.d.ts +2 -2
- package/dist/objects/decisions.d.ts +2 -2
- package/dist/objects/descriptor.d.ts +1 -1
- package/dist/objects/incidents.d.ts +2 -2
- package/dist/objects/lifecycle.d.ts +1 -1
- package/dist/objects/lifecycle.js +2 -1
- package/dist/objects/policies.d.ts +2 -2
- package/dist/objects/policies.js +2 -1
- package/dist/objects/processes.d.ts +2 -2
- package/dist/objects/project-briefs.d.ts +2 -2
- package/dist/objects/project-briefs.js +2 -3
- package/dist/objects/skills.d.ts +2 -2
- package/dist/postinstall.js +1 -1
- package/dist/rerankers/clef.js +3 -6
- package/dist/rerankers/cross-encoder.d.ts +31 -2
- package/dist/rerankers/cross-encoder.js +71 -98
- package/dist/rerankers/index.js +5 -4
- package/dist/rerankers/jev.js +2 -4
- package/dist/rerankers/outage-warning.d.ts +3 -1
- package/dist/rerankers/outage-warning.js +5 -3
- package/dist/search/bm25-search.js +1 -1
- package/dist/search/boosts.js +1 -1
- package/dist/search/embed-memories.d.ts +12 -0
- package/dist/search/embed-memories.js +389 -0
- package/dist/search/engine.d.ts +8 -0
- package/dist/search/engine.js +10 -0
- package/dist/search/goal-boost.d.ts +1 -1
- package/dist/search/goal-boost.js +6 -3
- package/dist/search/hybrid.d.ts +9 -2
- package/dist/search/hybrid.js +9 -4
- package/dist/search/physics-search.d.ts +6 -3
- package/dist/search/physics-search.js +22 -15
- package/dist/search/rerank.js +1 -1
- package/dist/search/vector.d.ts +8 -6
- package/dist/search/vector.js +14 -17
- package/dist/server/auth.d.ts +3 -1
- package/dist/server/auth.js +24 -15
- package/dist/server/boot.d.ts +2 -1
- package/dist/server/boot.js +34 -84
- package/dist/server/client-ip.d.ts +9 -6
- package/dist/server/client-ip.js +36 -17
- package/dist/server/deadline.d.ts +0 -2
- package/dist/server/deadline.js +1 -7
- package/dist/server/defaults.d.ts +1 -0
- package/dist/server/defaults.js +1 -0
- package/dist/server/mcp-http.js +16 -11
- package/dist/server/request.js +7 -2
- package/dist/server/route-checks.d.ts +7 -0
- package/dist/server/route-checks.js +42 -0
- package/dist/server/route-table.d.ts +9 -8
- package/dist/server/route-table.js +127 -133
- package/dist/server/routes/admin.d.ts +8 -8
- package/dist/server/routes/admin.js +13 -21
- package/dist/server/routes/customer-notes.d.ts +6 -6
- package/dist/server/routes/customer-notes.js +1 -2
- package/dist/server/routes/decisions.d.ts +6 -6
- package/dist/server/routes/decisions.js +2 -4
- package/dist/server/routes/incidents.d.ts +6 -6
- package/dist/server/routes/incidents.js +2 -5
- package/dist/server/routes/memories.d.ts +9 -9
- package/dist/server/routes/memories.js +19 -40
- package/dist/server/routes/object-routes.d.ts +6 -6
- package/dist/server/routes/object-routes.js +4 -7
- package/dist/server/routes/policies.d.ts +7 -7
- package/dist/server/routes/policies.js +2 -4
- package/dist/server/routes/predictions.d.ts +6 -6
- package/dist/server/routes/predictions.js +9 -13
- package/dist/server/routes/processes.d.ts +6 -6
- package/dist/server/routes/processes.js +1 -2
- package/dist/server/routes/project-briefs.d.ts +7 -7
- package/dist/server/routes/project-briefs.js +2 -4
- package/dist/server/routes/recall.d.ts +5 -5
- package/dist/server/routes/recall.js +6 -10
- package/dist/server/routes/skills.d.ts +7 -7
- package/dist/server/routes/skills.js +2 -4
- package/dist/server/server-detect.d.ts +7 -1
- package/dist/server/server-detect.js +36 -11
- package/dist/server/sleep-child.js +26 -7
- package/dist/server/sleep-offload.d.ts +11 -5
- package/dist/server/sleep-offload.js +17 -11
- package/dist/server/tls.d.ts +7 -2
- package/dist/server/tls.js +17 -5
- package/dist/server/types.d.ts +29 -12
- package/dist/server/validation.d.ts +1 -2
- package/dist/server/validation.js +6 -11
- package/dist/server.d.ts +4 -40
- package/dist/server.js +3 -29
- package/dist/sharing/global-store.d.ts +4 -5
- package/dist/sharing/global-store.js +8 -13
- package/dist/sharing/global-sync.js +38 -45
- package/dist/sharing/project-merge.d.ts +7 -14
- package/dist/sharing/project-merge.js +57 -121
- package/dist/sharing/search-both.js +10 -3
- package/dist/sharing/share.d.ts +2 -0
- package/dist/sharing/share.js +39 -38
- package/dist/store/ambient.js +7 -7
- package/dist/store/audit-event.d.ts +1 -1
- package/dist/store/audit.d.ts +0 -16
- package/dist/store/audit.js +4 -55
- package/dist/store/auth.d.ts +4 -2
- package/dist/store/auth.js +7 -3
- package/dist/store/candidates.d.ts +3 -2
- package/dist/store/candidates.js +59 -30
- package/dist/store/capture-write.d.ts +17 -0
- package/dist/store/capture-write.js +35 -0
- package/dist/store/cards.js +6 -5
- package/dist/store/compaction-caller.d.ts +18 -0
- package/dist/store/compaction-caller.js +29 -0
- package/dist/store/compactions-record.d.ts +115 -0
- package/dist/store/compactions-record.js +418 -0
- package/dist/store/compactions.js +6 -4
- package/dist/store/conflicts.d.ts +7 -1
- package/dist/store/conflicts.js +13 -9
- package/dist/store/connectors/dlq.d.ts +10 -0
- package/dist/store/connectors/dlq.js +33 -0
- package/dist/store/connectors/event-log.d.ts +13 -0
- package/dist/store/connectors/event-log.js +24 -0
- package/dist/store/connectors/github.d.ts +7 -9
- package/dist/store/connectors/github.js +35 -60
- package/dist/store/connectors/slack.d.ts +2 -11
- package/dist/store/connectors/slack.js +24 -57
- package/dist/store/dashboard-reads.js +8 -6
- package/dist/store/delete-and-batch.d.ts +6 -0
- package/dist/store/delete-and-batch.js +40 -6
- package/dist/store/delivery-recorder.d.ts +12 -5
- package/dist/store/delivery-recorder.js +13 -11
- package/dist/store/descendant-page.js +8 -4
- package/dist/store/dormant.d.ts +1 -1
- package/dist/store/dormant.js +10 -4
- package/dist/store/embeddings/index.d.ts +2 -12
- package/dist/store/embeddings/index.js +5 -374
- package/dist/store/entry-reads.d.ts +35 -4
- package/dist/store/entry-reads.js +86 -19
- package/dist/store/entry-row.js +9 -2
- package/dist/store/entry-writes.d.ts +15 -12
- package/dist/store/entry-writes.js +54 -22
- package/dist/store/failure-log-at.d.ts +8 -0
- package/dist/store/failure-log-at.js +16 -0
- package/dist/store/failure-log.d.ts +2 -2
- package/dist/store/failure-log.js +5 -3
- package/dist/{trust → store}/gated-write.d.ts +3 -1
- package/dist/{trust → store}/gated-write.js +7 -5
- package/dist/store/goals.js +22 -19
- package/dist/store/graph-reads.js +9 -6
- package/dist/store/graph-view-rows.js +2 -1
- package/dist/store/graph-writes.d.ts +6 -6
- package/dist/store/graph-writes.js +48 -71
- package/dist/store/half-life.js +2 -2
- package/dist/store/handoffs.d.ts +10 -4
- package/dist/store/handoffs.js +10 -9
- package/dist/store/index-and-stats.js +2 -2
- package/dist/store/index.d.ts +2 -2
- package/dist/store/index.js +1 -1
- package/dist/store/key-writes.js +1 -1
- package/dist/store/ledger-turn.d.ts +9 -0
- package/dist/store/ledger-turn.js +38 -0
- package/dist/store/mirrors.js +19 -10
- package/dist/store/open.d.ts +2 -5
- package/dist/store/open.js +42 -54
- package/dist/store/pilot-arm.d.ts +12 -0
- package/dist/store/pilot-arm.js +42 -0
- package/dist/store/port.d.ts +68 -6
- package/dist/store/port.js +8 -0
- package/dist/store/predictions.d.ts +1 -2
- package/dist/store/predictions.js +3 -6
- package/dist/store/project-tags.d.ts +62 -0
- package/dist/store/project-tags.js +67 -0
- package/dist/store/quality-repair.js +1 -1
- package/dist/store/quarantine.js +2 -1
- package/dist/store/recall-trace.d.ts +2 -0
- package/dist/store/recall-trace.js +20 -3
- package/dist/store/rejected-values.js +16 -10
- package/dist/store/rejection-probe.d.ts +4 -0
- package/dist/store/rejection-probe.js +19 -0
- package/dist/store/rejection.d.ts +0 -17
- package/dist/store/rejection.js +1 -21
- package/dist/store/rows.js +2 -2
- package/dist/store/rule-sql.d.ts +11 -0
- package/dist/store/rule-sql.js +31 -6
- package/dist/store/search-rows.d.ts +5 -5
- package/dist/store/search-rows.js +18 -16
- package/dist/store/sessions.js +4 -2
- package/dist/store/set-aside.d.ts +14 -0
- package/dist/store/set-aside.js +23 -0
- package/dist/store/sqlite/busy.d.ts +3 -0
- package/dist/store/sqlite/busy.js +8 -0
- package/dist/store/sqlite/connector-events-group.js +4 -7
- package/dist/store/sqlite/connector-writes-group.js +6 -4
- package/dist/store/sqlite/entry-writes-group.d.ts +3 -3
- package/dist/store/sqlite/entry-writes-group.js +3 -3
- package/dist/store/sqlite/error-codec.js +4 -3
- package/dist/store/sqlite/executor.js +10 -4
- package/dist/store/sqlite/graph-reads-group.js +1 -1
- package/dist/store/sqlite/held-connection.d.ts +11 -0
- package/dist/store/sqlite/held-connection.js +41 -0
- package/dist/store/sqlite/last-recall-group.d.ts +13 -0
- package/dist/store/sqlite/last-recall-group.js +57 -0
- package/dist/store/sqlite/local.d.ts +0 -17
- package/dist/store/sqlite/local.js +0 -31
- package/dist/store/sqlite/maintenance-groups.d.ts +6 -0
- package/dist/store/sqlite/maintenance-groups.js +60 -0
- package/dist/store/sqlite/object-rows.d.ts +1 -1
- package/dist/store/sqlite/objects-group.d.ts +1 -1
- package/dist/store/sqlite/objects-group.js +15 -7
- package/dist/store/sqlite/store.d.ts +1 -8
- package/dist/store/sqlite/store.js +13 -22
- package/dist/store/summaries.d.ts +10 -3
- package/dist/store/summaries.js +54 -11
- package/dist/store/token-ledger-rows.js +3 -2
- package/dist/store/token-ledger.d.ts +0 -7
- package/dist/store/token-ledger.js +0 -35
- package/dist/store/vector-index.js +8 -4
- package/dist/support-bundle.js +2 -3
- package/dist/trust/reject-flow.js +2 -2
- package/dist/util/agent-homes.d.ts +15 -0
- package/dist/util/agent-homes.js +34 -0
- package/dist/util/anthropic-messages.d.ts +6 -1
- package/dist/util/anthropic-messages.js +26 -7
- package/dist/util/atomic-write.d.ts +5 -2
- package/dist/util/atomic-write.js +12 -8
- package/dist/util/chunked.d.ts +3 -0
- package/dist/util/chunked.js +10 -0
- package/dist/util/ellipsize.d.ts +3 -0
- package/dist/util/ellipsize.js +5 -0
- package/dist/util/env.d.ts +12 -2
- package/dist/util/env.js +12 -2
- package/dist/util/format.d.ts +5 -0
- package/dist/util/format.js +10 -0
- package/dist/util/hook-payload.d.ts +8 -0
- package/dist/util/hook-payload.js +37 -0
- package/dist/util/http-retry.d.ts +6 -0
- package/dist/util/http-retry.js +43 -5
- package/dist/util/http-util.d.ts +0 -8
- package/dist/util/http-util.js +10 -21
- package/dist/util/limits.d.ts +7 -0
- package/dist/util/limits.js +14 -0
- package/dist/util/log.d.ts +4 -0
- package/dist/util/log.js +9 -0
- package/dist/util/request-scope.d.ts +9 -3
- package/dist/util/request-scope.js +18 -9
- package/dist/util/secret-detect.js +6 -1
- package/dist/util/spawn-argv.d.ts +9 -0
- package/dist/util/spawn-argv.js +57 -0
- package/dist/util/sql.d.ts +3 -0
- package/dist/util/sql.js +6 -0
- package/dist/util/sqlite-blocked.d.ts +2 -0
- package/dist/util/sqlite-blocked.js +5 -0
- package/dist/util/stream-tee.d.ts +3 -0
- package/dist/util/stream-tee.js +35 -0
- package/dist/util/time.d.ts +4 -0
- package/dist/util/time.js +4 -0
- package/dist/util/vector-codec.d.ts +4 -0
- package/dist/util/vector-codec.js +15 -0
- package/dist/util/version.d.ts +1 -1
- package/dist/util/version.js +1 -1
- package/extensions/openclaw-plugin/openclaw.plugin.json +1 -1
- package/extensions/openclaw-plugin/package.json +1 -1
- package/openclaw.plugin.json +1 -1
- package/package.json +4 -2
- package/dist/api/on-store.d.ts +0 -16
- package/dist/api/on-store.js +0 -38
- package/dist/store/embeddings/local.d.ts +0 -15
- package/dist/store/embeddings/local.js +0 -175
- /package/dist/{cli → api}/correction-latency.d.ts +0 -0
- /package/dist/{cli → api}/correction-latency.js +0 -0
- /package/dist/{cli → api}/provenance-coverage.d.ts +0 -0
- /package/dist/{cli → api}/provenance-coverage.js +0 -0
- /package/dist/{store → core}/object-types.d.ts +0 -0
- /package/dist/{store → core}/object-types.js +0 -0
- /package/dist/{capture → util}/compaction-items.d.ts +0 -0
- /package/dist/{capture → util}/compaction-items.js +0 -0
- /package/dist/{store → util}/yaml.d.ts +0 -0
- /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 '../
|
|
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 '../
|
|
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
|
|
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,
|
|
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, { ...
|
|
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, { ...
|
|
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, { ...
|
|
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()
|
|
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
|
}
|
package/dist/search/rerank.js
CHANGED
package/dist/search/vector.d.ts
CHANGED
|
@@ -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 '../
|
|
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
|
|
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. */
|
package/dist/search/vector.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import { cosineOf
|
|
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 '../
|
|
4
|
-
import { rethrowIfSqliteBlocked } from '../
|
|
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 {
|
|
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
|
|
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(
|
|
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
|
|
39
|
+
return hasGroup(store, 'localFiles')
|
|
42
40
|
? `${why}; run 'hippo embed'`
|
|
43
|
-
: `${why}; run 'hippo embed' on the SQLite store, then rebuild the '${
|
|
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 (!
|
|
57
|
+
if (!source)
|
|
60
58
|
return arm;
|
|
61
59
|
try {
|
|
62
|
-
await fillVectorArm(arm, query,
|
|
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
|
|
79
|
+
warnBm25Fallback('reindex', reindexHint(store));
|
|
83
80
|
return;
|
|
84
81
|
}
|
|
85
82
|
const spec = options.vectorCandidates;
|
package/dist/server/auth.d.ts
CHANGED
|
@@ -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>;
|
package/dist/server/auth.js
CHANGED
|
@@ -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
|
|
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
|
-
|
|
247
|
-
|
|
248
|
-
chargeCaller(id.tenantId, actor, opts);
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
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
|
}
|
package/dist/server/boot.d.ts
CHANGED
|
@@ -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
|
|
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
|
package/dist/server/boot.js
CHANGED
|
@@ -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 {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
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 {
|
|
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 {
|
|
30
|
-
import { assertAddonRoutes, assertPublicJson
|
|
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
|
-
|
|
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 !==
|
|
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
|
-
|
|
178
|
+
assertClientIpHeaderPinned();
|
|
196
179
|
return {
|
|
197
180
|
perAddress: bootRateLimiter(perAddress),
|
|
198
|
-
callerLimiter: 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
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
*
|
|
6
|
-
*
|
|
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
|
-
/**
|
|
9
|
-
export declare
|
|
10
|
-
|
|
11
|
-
|
|
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;
|