hippo-memory 2.0.0 → 2.1.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/dist/agent-memories/apply.d.ts +7 -5
- package/dist/agent-memories/apply.js +66 -39
- package/dist/agent-memories/claude-code.d.ts +8 -2
- package/dist/agent-memories/claude-code.js +26 -7
- package/dist/agent-memories/copilot.js +2 -1
- package/dist/agent-memories/files.js +2 -1
- package/dist/agent-memories/legacy.d.ts +6 -3
- package/dist/agent-memories/legacy.js +35 -14
- package/dist/agent-memories/markdown.d.ts +3 -1
- package/dist/agent-memories/markdown.js +3 -1
- package/dist/agent-memories/openclaw.js +5 -2
- package/dist/agent-memories/plan.js +11 -1
- package/dist/agent-memories/project-folds.js +2 -1
- package/dist/agent-memories/report.d.ts +4 -1
- package/dist/agent-memories/report.js +43 -9
- package/dist/agent-memories/source.d.ts +8 -2
- package/dist/agent-memories/source.js +11 -3
- package/dist/agent-memories/sync.d.ts +7 -2
- package/dist/agent-memories/sync.js +141 -101
- package/dist/api/assemble.d.ts +6 -4
- package/dist/api/assemble.js +11 -6
- package/dist/api/{audit.d.ts → auth/audit.d.ts} +18 -16
- package/dist/api/{audit.js → auth/audit.js} +11 -11
- package/dist/api/{auth.d.ts → auth/auth.d.ts} +19 -15
- package/dist/api/{auth.js → auth/auth.js} +46 -29
- package/dist/api/{quarantine.d.ts → auth/quarantine.d.ts} +8 -7
- package/dist/api/{quarantine.js → auth/quarantine.js} +8 -8
- package/dist/api/auth/session-owners.d.ts +10 -0
- package/dist/api/auth/session-owners.js +35 -0
- package/dist/api/availability.d.ts +3 -1
- package/dist/api/availability.js +3 -1
- package/dist/api/busy.d.ts +2 -0
- package/dist/api/busy.js +2 -0
- package/dist/api/cli-surface.d.ts +6 -0
- package/dist/api/cli-surface.js +6 -0
- package/dist/api/config-of.d.ts +5 -0
- package/dist/api/config-of.js +6 -0
- package/dist/api/context-auto.d.ts +4 -1
- package/dist/api/context-auto.js +10 -2
- package/dist/api/context-render.js +14 -7
- package/dist/api/context-select.d.ts +4 -1
- package/dist/api/context-select.js +23 -14
- package/dist/api/context-types.d.ts +38 -12
- package/dist/api/context.d.ts +8 -5
- package/dist/api/context.js +112 -57
- package/dist/api/continuity.d.ts +24 -21
- package/dist/api/continuity.js +18 -20
- package/dist/api/correction-latency.d.ts +3 -1
- package/dist/api/correction-latency.js +3 -1
- package/dist/api/error-reply.d.ts +4 -1
- package/dist/api/error-reply.js +12 -3
- package/dist/api/index.d.ts +39 -23
- package/dist/api/index.js +21 -23
- package/dist/api/instruction-detect.d.ts +4 -1
- package/dist/api/instruction-detect.js +75 -20
- package/dist/api/ledger-db.d.ts +15 -11
- package/dist/api/ledger-db.js +21 -23
- package/dist/api/memories/conflicts.d.ts +33 -0
- package/dist/api/memories/conflicts.js +67 -0
- package/dist/api/{forget.d.ts → memories/forget.d.ts} +11 -9
- package/dist/api/{forget.js → memories/forget.js} +22 -15
- package/dist/api/memories/memories.d.ts +27 -0
- package/dist/api/{memories.js → memories/memories.js} +16 -21
- package/dist/api/memories/outcome.d.ts +22 -0
- package/dist/api/{outcome.js → memories/outcome.js} +14 -8
- package/dist/api/memories/promote.d.ts +40 -0
- package/dist/api/{promote.js → memories/promote.js} +35 -22
- package/dist/api/memories/refine.d.ts +10 -0
- package/dist/api/memories/refine.js +12 -0
- package/dist/api/{remember-local.d.ts → memories/remember-local.d.ts} +16 -11
- package/dist/api/{remember-local.js → memories/remember-local.js} +34 -20
- package/dist/api/{remember.d.ts → memories/remember.d.ts} +19 -13
- package/dist/api/{remember.js → memories/remember.js} +42 -26
- package/dist/api/objects/cards.d.ts +39 -0
- package/dist/api/{cards.js → objects/cards.js} +12 -14
- package/dist/api/{drill-down.d.ts → objects/drill-down.d.ts} +12 -10
- package/dist/api/{drill-down.js → objects/drill-down.js} +7 -8
- package/dist/api/objects/goals.d.ts +18 -0
- package/dist/api/{goals.js → objects/goals.js} +12 -12
- package/dist/api/objects/graph.d.ts +11 -0
- package/dist/api/objects/graph.js +16 -0
- package/dist/api/objects/objects.d.ts +9 -0
- package/dist/api/{objects.js → objects/objects.js} +2 -4
- package/dist/api/objects/predictions.d.ts +11 -0
- package/dist/api/{predictions.js → objects/predictions.js} +7 -6
- package/dist/api/{projects.d.ts → objects/projects.d.ts} +8 -5
- package/dist/api/{projects.js → objects/projects.js} +8 -4
- package/dist/api/pilot-arm.d.ts +8 -4
- package/dist/api/pilot-arm.js +5 -4
- package/dist/api/prompt-hook.d.ts +32 -19
- package/dist/api/prompt-hook.js +65 -44
- package/dist/api/provenance-coverage.d.ts +3 -1
- package/dist/api/provenance-coverage.js +3 -1
- package/dist/api/recall/finish.d.ts +185 -0
- package/dist/api/recall/finish.js +301 -0
- package/dist/api/{recall-pipeline.d.ts → recall/pipeline.d.ts} +12 -8
- package/dist/api/{recall-pipeline.js → recall/pipeline.js} +176 -92
- package/dist/api/recall/recall.d.ts +6 -0
- package/dist/api/{recall.js → recall/recall.js} +101 -60
- package/dist/api/recall/render.d.ts +39 -0
- package/dist/api/recall/render.js +60 -0
- package/dist/api/{recall-request.d.ts → recall/request.d.ts} +7 -5
- package/dist/api/recall/request.js +261 -0
- package/dist/api/{recall-cli.d.ts → recall/rows.d.ts} +18 -12
- package/dist/api/{recall-cli.js → recall/rows.js} +28 -27
- package/dist/api/{recall-types.d.ts → recall/types.d.ts} +95 -70
- package/dist/api/{recall-types.js → recall/types.js} +1 -1
- package/dist/api/session-end.d.ts +16 -12
- package/dist/api/session-end.js +46 -30
- package/dist/api/{auto-sleep.d.ts → sleep/auto-sleep.d.ts} +9 -5
- package/dist/api/{auto-sleep.js → sleep/auto-sleep.js} +7 -12
- package/dist/api/sleep/dormant.d.ts +25 -0
- package/dist/api/sleep/dormant.js +64 -0
- package/dist/api/{learn.d.ts → sleep/learn.d.ts} +5 -4
- package/dist/api/sleep/learn.js +138 -0
- package/dist/api/sleep/sleep-run.d.ts +38 -0
- package/dist/api/{sleep-run.js → sleep/sleep-run.js} +51 -43
- package/dist/api/{sleep.d.ts → sleep/sleep.d.ts} +17 -11
- package/dist/api/sleep/sleep.js +9 -0
- package/dist/api/status.d.ts +3 -1
- package/dist/api/status.js +3 -1
- package/dist/api/store-init.d.ts +4 -1
- package/dist/api/store-init.js +4 -1
- package/dist/api/tokens.d.ts +10 -9
- package/dist/api/tokens.js +9 -10
- package/dist/api/types.d.ts +28 -7
- package/dist/api/types.js +13 -4
- package/dist/capture/caller-session.d.ts +8 -2
- package/dist/capture/caller-session.js +16 -6
- package/dist/capture/capture-error.d.ts +3 -1
- package/dist/capture/capture-error.js +3 -1
- package/dist/capture/codex-patch.js +7 -2
- package/dist/capture/command.d.ts +4 -2
- package/dist/capture/command.js +33 -14
- package/dist/capture/compact-resume-caller.js +15 -8
- package/dist/capture/compact.d.ts +8 -5
- package/dist/capture/compact.js +34 -23
- package/dist/capture/compaction-items-caller.js +9 -3
- package/dist/capture/compaction-record.d.ts +4 -3
- package/dist/capture/compaction-record.js +20 -12
- package/dist/capture/compaction-spool.d.ts +15 -4
- package/dist/capture/compaction-spool.js +64 -17
- package/dist/capture/copilot-transcript.d.ts +11 -3
- package/dist/capture/copilot-transcript.js +16 -6
- package/dist/capture/extract.js +20 -8
- package/dist/capture/failure-caller.js +23 -12
- package/dist/capture/failure-reading.d.ts +10 -3
- package/dist/capture/failure-reading.js +24 -7
- package/dist/capture/pre-compact-caller.js +11 -4
- package/dist/capture/session-digest.d.ts +15 -4
- package/dist/capture/session-digest.js +39 -13
- package/dist/capture/session-end-caller.d.ts +4 -1
- package/dist/capture/session-end-caller.js +20 -8
- package/dist/capture/session-texts.d.ts +6 -2
- package/dist/capture/session-texts.js +22 -7
- package/dist/capture/session-worker.d.ts +4 -2
- package/dist/capture/session-worker.js +45 -17
- package/dist/capture/transcript.d.ts +13 -4
- package/dist/capture/transcript.js +32 -10
- package/dist/capture/working-state.d.ts +13 -4
- package/dist/capture/working-state.js +50 -56
- package/dist/cli/api-context.d.ts +14 -2
- package/dist/cli/api-context.js +45 -2
- package/dist/cli/audit.js +23 -23
- package/dist/cli/auth.js +19 -27
- package/dist/cli/briefs.d.ts +1 -1
- package/dist/cli/briefs.js +20 -15
- package/dist/cli/card.d.ts +1 -1
- package/dist/cli/card.js +56 -73
- package/dist/cli/client.d.ts +12 -4
- package/dist/cli/client.js +43 -13
- package/dist/cli/compact-resume-payload.d.ts +4 -1
- package/dist/cli/compact-resume-payload.js +12 -5
- package/dist/cli/context.js +42 -17
- package/dist/cli/continuity.d.ts +5 -5
- package/dist/cli/continuity.js +90 -107
- package/dist/cli/curate.d.ts +4 -3
- package/dist/cli/curate.js +46 -68
- package/dist/cli/dag.d.ts +1 -1
- package/dist/cli/dag.js +14 -17
- package/dist/cli/decisions.js +27 -26
- package/dist/cli/eval.js +16 -21
- package/dist/cli/exit.d.ts +4 -1
- package/dist/cli/exit.js +10 -2
- package/dist/cli/explain.js +12 -11
- package/dist/cli/flag-values.d.ts +1 -1
- package/dist/cli/flag-values.js +9 -18
- package/dist/cli/github.d.ts +6 -0
- package/dist/cli/github.js +25 -13
- package/dist/cli/goals.d.ts +1 -1
- package/dist/cli/goals.js +39 -56
- package/dist/cli/graph.d.ts +1 -1
- package/dist/cli/graph.js +15 -11
- package/dist/cli/hook-runtime.d.ts +31 -9
- package/dist/cli/hook-runtime.js +40 -15
- package/dist/cli/incidents.d.ts +1 -1
- package/dist/cli/incidents.js +25 -25
- package/dist/cli/init.js +26 -11
- package/dist/cli/install-steps.d.ts +12 -3
- package/dist/cli/install-steps.js +42 -18
- package/dist/cli/last-sleep.d.ts +4 -1
- package/dist/cli/last-sleep.js +9 -4
- package/dist/cli/maintenance.d.ts +1 -1
- package/dist/cli/maintenance.js +11 -12
- package/dist/cli/notes.d.ts +1 -1
- package/dist/cli/notes.js +8 -5
- package/dist/cli/object-verbs.d.ts +4 -4
- package/dist/cli/object-verbs.js +10 -13
- package/dist/cli/open-browser.js +11 -2
- package/dist/cli/playbooks.d.ts +3 -3
- package/dist/cli/playbooks.js +40 -32
- package/dist/cli/predictions.js +15 -19
- package/dist/cli/print.js +4 -2
- package/dist/cli/projects.js +21 -11
- package/dist/cli/quality-repair-once.js +5 -4
- package/dist/cli/recall.js +129 -93
- package/dist/cli/refine-llm.d.ts +15 -4
- package/dist/cli/refine-llm.js +16 -7
- package/dist/cli/remember.js +46 -50
- package/dist/cli/scheduler.d.ts +4 -1
- package/dist/cli/scheduler.js +9 -5
- package/dist/cli/serve.js +22 -17
- package/dist/cli/session-hooks.d.ts +2 -2
- package/dist/cli/session-hooks.js +87 -50
- package/dist/cli/setup.js +54 -32
- package/dist/cli/shared.d.ts +3 -1
- package/dist/cli/shared.js +24 -9
- package/dist/cli/slack.js +15 -24
- package/dist/cli/sleep-render.d.ts +3 -1
- package/dist/cli/sleep-render.js +8 -5
- package/dist/cli/sleep.js +14 -6
- package/dist/cli/status.d.ts +4 -4
- package/dist/cli/status.js +32 -27
- package/dist/cli/stdin.d.ts +10 -3
- package/dist/cli/stdin.js +10 -3
- package/dist/cli/transfer.d.ts +1 -1
- package/dist/cli/transfer.js +71 -75
- package/dist/cli/verbs/memory.js +8 -6
- package/dist/cli/verbs/objects.js +10 -4
- package/dist/cli/versioned-verbs.d.ts +8 -7
- package/dist/cli/versioned-verbs.js +31 -21
- package/dist/cli.js +13 -16
- package/dist/connectors/dlq.d.ts +6 -6
- package/dist/connectors/dlq.js +12 -8
- package/dist/connectors/github/backfill.d.ts +4 -4
- package/dist/connectors/github/backfill.js +6 -4
- package/dist/connectors/github/deletion.d.ts +6 -4
- package/dist/connectors/github/deletion.js +5 -5
- package/dist/connectors/github/dlq.d.ts +8 -6
- package/dist/connectors/github/dlq.js +11 -5
- package/dist/connectors/github/ingest.d.ts +2 -2
- package/dist/connectors/github/ingest.js +9 -6
- package/dist/connectors/github/octokit-client.d.ts +3 -1
- package/dist/connectors/github/octokit-client.js +7 -2
- package/dist/connectors/github/ratelimit.d.ts +6 -2
- package/dist/connectors/github/ratelimit.js +6 -2
- package/dist/connectors/github/signature.d.ts +14 -3
- package/dist/connectors/github/signature.js +17 -3
- package/dist/connectors/github/tenant-routing.d.ts +6 -4
- package/dist/connectors/github/tenant-routing.js +6 -6
- package/dist/connectors/github/transform.js +50 -67
- package/dist/connectors/github/types.d.ts +10 -3
- package/dist/connectors/github/types.js +6 -2
- package/dist/connectors/github/webhook.d.ts +5 -5
- package/dist/connectors/github/webhook.js +34 -23
- package/dist/connectors/ingest.d.ts +5 -3
- package/dist/connectors/ingest.js +3 -4
- package/dist/connectors/slack/backfill.d.ts +5 -5
- package/dist/connectors/slack/backfill.js +3 -3
- package/dist/connectors/slack/deletion.d.ts +4 -4
- package/dist/connectors/slack/deletion.js +6 -6
- package/dist/connectors/slack/dlq.d.ts +4 -4
- package/dist/connectors/slack/dlq.js +6 -6
- package/dist/connectors/slack/ingest.d.ts +6 -4
- package/dist/connectors/slack/ingest.js +5 -5
- package/dist/connectors/slack/signature.d.ts +4 -1
- package/dist/connectors/slack/tenant-routing.d.ts +6 -4
- package/dist/connectors/slack/tenant-routing.js +6 -6
- package/dist/connectors/slack/transform.d.ts +6 -2
- package/dist/connectors/slack/transform.js +6 -2
- package/dist/connectors/slack/types.d.ts +3 -1
- package/dist/connectors/slack/web-client.js +8 -3
- package/dist/connectors/slack/webhook.d.ts +5 -5
- package/dist/connectors/slack/webhook.js +19 -11
- package/dist/connectors/slack/workspaces.d.ts +7 -3
- package/dist/connectors/slack/workspaces.js +7 -3
- package/dist/connectors/store.d.ts +8 -0
- package/dist/connectors/store.js +2 -0
- package/dist/consolidate/conflicts.js +23 -9
- package/dist/consolidate/dag-summary.js +2 -1
- package/dist/consolidate/dag.d.ts +10 -5
- package/dist/consolidate/dag.js +37 -36
- package/dist/consolidate/decay.js +19 -6
- package/dist/consolidate/dedupe.d.ts +14 -5
- package/dist/consolidate/dedupe.js +27 -16
- package/dist/consolidate/flush-units.d.ts +4 -1
- package/dist/consolidate/flush-units.js +4 -1
- package/dist/consolidate/half-life-migration.d.ts +18 -8
- package/dist/consolidate/half-life-migration.js +48 -18
- package/dist/consolidate/llm-passes.js +27 -11
- package/dist/consolidate/memory-value-weights.d.ts +6 -2
- package/dist/consolidate/memory-value-weights.js +6 -2
- package/dist/consolidate/memory-value.d.ts +30 -10
- package/dist/consolidate/memory-value.js +36 -13
- package/dist/consolidate/merge.d.ts +4 -1
- package/dist/consolidate/merge.js +42 -32
- package/dist/consolidate/overlap-index.d.ts +8 -2
- package/dist/consolidate/overlap-index.js +11 -4
- package/dist/consolidate/physics-pass.d.ts +3 -1
- package/dist/consolidate/physics-pass.js +10 -7
- package/dist/consolidate/replay.d.ts +11 -4
- package/dist/consolidate/replay.js +19 -7
- package/dist/consolidate/run.d.ts +13 -5
- package/dist/consolidate/run.js +4 -4
- package/dist/consolidate/sleep.d.ts +14 -6
- package/dist/consolidate/sleep.js +41 -38
- package/dist/consolidate/trace.d.ts +7 -2
- package/dist/consolidate/trace.js +7 -2
- package/dist/consolidate/traces.js +26 -29
- package/dist/core/ablation.d.ts +9 -3
- package/dist/core/ablation.js +14 -4
- package/dist/core/active-scope.d.ts +3 -1
- package/dist/core/active-scope.js +3 -1
- package/dist/core/agent-memory-tools.d.ts +2 -0
- package/dist/core/agent-memory-tools.js +2 -0
- package/dist/core/ambient.d.ts +4 -3
- package/dist/core/ambient.js +8 -6
- package/dist/core/api-errors.d.ts +9 -3
- package/dist/core/api-errors.js +9 -3
- package/dist/core/capture-contract.d.ts +4 -1
- package/dist/core/capture-contract.js +27 -8
- package/dist/core/compare.d.ts +24 -8
- package/dist/core/compare.js +24 -8
- package/dist/core/config.d.ts +18 -9
- package/dist/core/config.js +24 -14
- package/dist/core/cosine.d.ts +4 -1
- package/dist/core/cosine.js +4 -1
- package/dist/core/handoff.d.ts +7 -2
- package/dist/core/handoff.js +4 -1
- package/dist/core/markdown.js +21 -16
- package/dist/core/memory-audit.js +14 -3
- package/dist/core/memory-quality.d.ts +12 -3
- package/dist/core/memory-quality.js +57 -21
- package/dist/core/memory.d.ts +84 -27
- package/dist/core/memory.js +73 -29
- package/dist/core/merged-row.d.ts +8 -2
- package/dist/core/merged-row.js +10 -3
- package/dist/core/package-root.d.ts +3 -1
- package/dist/core/package-root.js +3 -1
- package/dist/core/particle-refresh.d.ts +8 -0
- package/dist/core/particle-refresh.js +22 -0
- package/dist/core/physics-config.d.ts +4 -1
- package/dist/core/physics-config.js +6 -2
- package/dist/core/physics.d.ts +37 -11
- package/dist/core/physics.js +55 -20
- package/dist/core/project-identity.d.ts +34 -17
- package/dist/core/project-identity.js +33 -17
- package/dist/core/project-remote.d.ts +8 -4
- package/dist/core/project-remote.js +31 -14
- package/dist/core/recall-scope.d.ts +33 -11
- package/dist/core/recall-scope.js +42 -15
- package/dist/core/rejection-digest.d.ts +7 -0
- package/dist/core/rejection-digest.js +13 -0
- package/dist/core/salience.d.ts +3 -1
- package/dist/core/salience.js +10 -4
- package/dist/core/search-types.d.ts +15 -2
- package/dist/core/search-types.js +11 -0
- package/dist/dashboard/dashboard-actions.js +13 -2
- package/dist/dashboard/dashboard-snapshot.d.ts +2 -2
- package/dist/dashboard/dashboard-snapshot.js +4 -4
- package/dist/dashboard/dashboard.js +6 -3
- package/dist/db/backup.js +2 -2
- package/dist/db/busy.d.ts +10 -3
- package/dist/db/busy.js +27 -5
- package/dist/db/connect.d.ts +10 -3
- package/dist/db/connect.js +8 -3
- package/dist/db/continuity.d.ts +1 -1
- package/dist/db/continuity.js +27 -11
- package/dist/db/meta.d.ts +4 -1
- package/dist/db/meta.js +4 -1
- package/dist/db/migrate.d.ts +10 -5
- package/dist/db/migrate.js +26 -13
- package/dist/db/migrations/index.d.ts +1 -1
- package/dist/db/migrations/index.js +3 -1
- package/dist/db/migrations/types.d.ts +2 -1
- package/dist/db/migrations/v12.js +2 -1
- package/dist/db/migrations/v14.js +2 -1
- package/dist/db/migrations/v15.js +4 -2
- package/dist/db/migrations/v16.js +6 -3
- package/dist/db/migrations/v17.js +2 -1
- package/dist/db/migrations/v19.js +4 -2
- package/dist/db/migrations/v20.js +2 -1
- package/dist/db/migrations/v22.js +12 -6
- package/dist/db/migrations/v23.js +6 -3
- package/dist/db/migrations/v24.js +6 -3
- package/dist/db/migrations/v25.js +4 -2
- package/dist/db/migrations/v26.js +4 -2
- package/dist/db/migrations/v27.js +6 -3
- package/dist/db/migrations/v28.js +4 -2
- package/dist/db/migrations/v29.js +4 -2
- package/dist/db/migrations/v30.js +6 -3
- package/dist/db/migrations/v31.js +4 -2
- package/dist/db/migrations/v32.js +6 -3
- package/dist/db/migrations/v33.js +4 -2
- package/dist/db/migrations/v34.js +2 -1
- package/dist/db/migrations/v35.js +2 -1
- package/dist/db/migrations/v36.js +2 -1
- package/dist/db/migrations/v37.js +10 -5
- package/dist/db/migrations/v38.js +10 -5
- package/dist/db/migrations/v39.js +14 -6
- package/dist/db/migrations/v40.js +4 -2
- package/dist/db/migrations/v41.js +4 -2
- package/dist/db/migrations/v42.js +2 -1
- package/dist/db/migrations/v44.js +4 -2
- package/dist/db/migrations/v45.js +4 -2
- package/dist/db/migrations/v49.js +2 -1
- package/dist/db/migrations/v50.js +4 -2
- package/dist/db/migrations/v51.js +4 -2
- package/dist/db/migrations/v52.js +2 -1
- package/dist/db/migrations/v53.js +8 -4
- package/dist/db/migrations/v54.js +2 -1
- package/dist/db/migrations/v55.js +4 -2
- package/dist/db/migrations/v56.d.ts +3 -0
- package/dist/db/migrations/v56.js +28 -0
- package/dist/db/open.d.ts +24 -12
- package/dist/db/open.js +25 -13
- package/dist/db/physics-state.d.ts +8 -4
- package/dist/db/physics-state.js +13 -20
- package/dist/db/raw-archive-mirror-cleanup.d.ts +4 -2
- package/dist/db/raw-archive-mirror-cleanup.js +6 -4
- package/dist/db/request-stores.d.ts +19 -5
- package/dist/db/request-stores.js +14 -5
- package/dist/db/tables.d.ts +2 -1
- package/dist/db/tables.js +12 -4
- package/dist/db/vector-store.d.ts +13 -4
- package/dist/db/vector-store.js +34 -14
- package/dist/db/wal-checkpointer.d.ts +2 -1
- package/dist/db/wal-checkpointer.js +19 -7
- package/dist/doctor.d.ts +4 -1
- package/dist/doctor.js +121 -39
- package/dist/embeddings/local.d.ts +8 -4
- package/dist/embeddings/local.js +9 -5
- package/dist/embeddings/provider.d.ts +19 -10
- package/dist/embeddings/provider.js +31 -17
- package/dist/embeddings/transformers.d.ts +16 -4
- package/dist/embeddings/transformers.js +32 -15
- package/dist/entry/json-hooks.d.ts +1 -1
- package/dist/entry/json-hooks.js +1 -1
- package/dist/entry/project-identity.js +2 -1
- package/dist/entry/session-text.d.ts +1 -1
- package/dist/entry/session-text.js +1 -1
- package/dist/entry/sqlite-handles.d.ts +10 -0
- package/dist/entry/sqlite-handles.js +9 -0
- package/dist/entry/store-kit.d.ts +19 -6
- package/dist/entry/store-kit.js +6 -4
- package/dist/eval/eval-stats.d.ts +27 -8
- package/dist/eval/eval-stats.js +17 -5
- package/dist/eval/eval-suite.d.ts +3 -1
- package/dist/eval/eval-suite.js +409 -187
- package/dist/eval/eval.d.ts +8 -2
- package/dist/eval/eval.js +8 -2
- package/dist/eval/judgment.js +16 -6
- package/dist/graph/delta.d.ts +9 -42
- package/dist/graph/delta.js +17 -11
- package/dist/graph/extract.d.ts +10 -7
- package/dist/graph/extract.js +57 -25
- package/dist/graph/recall.d.ts +12 -4
- package/dist/graph/recall.js +30 -13
- package/dist/graph/stream.d.ts +18 -6
- package/dist/graph/stream.js +32 -10
- package/dist/graph/view.d.ts +19 -6
- package/dist/graph/view.js +42 -17
- package/dist/hooks/codex-session.js +2 -2
- package/dist/hooks/codex-wrapper.d.ts +3 -1
- package/dist/hooks/codex-wrapper.js +9 -4
- package/dist/hooks/copilot.d.ts +19 -5
- package/dist/hooks/copilot.js +54 -15
- package/dist/hooks/hook-blocks.d.ts +4 -1
- package/dist/hooks/hook-blocks.js +8 -3
- package/dist/hooks/json-hooks.d.ts +9 -5
- package/dist/hooks/json-hooks.js +69 -34
- package/dist/hooks/opencode.js +15 -5
- package/dist/hooks/shared.d.ts +27 -8
- package/dist/hooks/shared.js +57 -16
- package/dist/importers/core.d.ts +12 -4
- package/dist/importers/core.js +8 -7
- package/dist/importers/markdown-parse.d.ts +15 -5
- package/dist/importers/markdown-parse.js +16 -7
- package/dist/importers/markdown.js +6 -9
- package/dist/importers/sources.js +10 -23
- package/dist/importers/vault.d.ts +2 -2
- package/dist/importers/vault.js +43 -27
- package/dist/index.d.ts +32 -6
- package/dist/index.js +25 -7
- package/dist/learn/autolearn.d.ts +17 -6
- package/dist/learn/autolearn.js +53 -24
- package/dist/learn/churn-git.d.ts +4 -1
- package/dist/learn/churn-git.js +29 -5
- package/dist/learn/extract.d.ts +4 -1
- package/dist/learn/extract.js +16 -9
- package/dist/learn/forward-claim-detector.d.ts +17 -5
- package/dist/learn/forward-claim-detector.js +34 -15
- package/dist/learn/invalidation.d.ts +12 -7
- package/dist/learn/invalidation.js +56 -27
- package/dist/learn/roots.d.ts +3 -0
- package/dist/learn/roots.js +5 -0
- package/dist/mcp/admin-tools.d.ts +5 -5
- package/dist/mcp/admin-tools.js +28 -23
- package/dist/mcp/format.d.ts +1 -1
- package/dist/mcp/format.js +4 -2
- package/dist/mcp/framing.d.ts +3 -1
- package/dist/mcp/framing.js +20 -8
- package/dist/mcp/memory-tools.d.ts +3 -3
- package/dist/mcp/memory-tools.js +18 -14
- package/dist/mcp/protocol.d.ts +32 -16
- package/dist/mcp/protocol.js +12 -9
- package/dist/mcp/recall-tools.d.ts +3 -3
- package/dist/mcp/recall-tools.js +62 -74
- package/dist/mcp/request.d.ts +7 -5
- package/dist/mcp/request.js +57 -74
- package/dist/mcp/server.d.ts +3 -1
- package/dist/mcp/server.js +8 -3
- package/dist/mcp/session-state.d.ts +1 -1
- package/dist/mcp/session-state.js +4 -3
- package/dist/mcp/shared-gate.d.ts +3 -2
- package/dist/mcp/shared-gate.js +3 -2
- package/dist/mcp/stdio.d.ts +6 -3
- package/dist/mcp/stdio.js +52 -21
- package/dist/mcp/tool-args.d.ts +4 -1
- package/dist/mcp/tool-args.js +8 -3
- package/dist/mcp/tools.js +76 -32
- package/dist/objects/customer-notes.d.ts +12 -10
- package/dist/objects/customer-notes.js +21 -15
- package/dist/objects/decisions.d.ts +18 -10
- package/dist/objects/decisions.js +23 -17
- package/dist/objects/descriptor.js +2 -1
- package/dist/objects/fields.d.ts +4 -1
- package/dist/objects/fields.js +6 -2
- package/dist/objects/incidents.d.ts +14 -16
- package/dist/objects/incidents.js +29 -30
- package/dist/objects/lifecycle.d.ts +0 -4
- package/dist/objects/lifecycle.js +21 -24
- package/dist/objects/policies.d.ts +12 -16
- package/dist/objects/policies.js +17 -21
- package/dist/objects/processes.d.ts +16 -10
- package/dist/objects/processes.js +20 -15
- package/dist/objects/project-briefs.d.ts +13 -14
- package/dist/objects/project-briefs.js +33 -39
- package/dist/objects/skills.d.ts +10 -12
- package/dist/objects/skills.js +17 -22
- package/dist/postinstall.js +15 -7
- package/dist/predictions/planning-fallacy.d.ts +19 -6
- package/dist/predictions/planning-fallacy.js +4 -2
- package/dist/rerankers/clef.d.ts +8 -2
- package/dist/rerankers/clef.js +14 -9
- package/dist/rerankers/cross-encoder.d.ts +2 -1
- package/dist/rerankers/cross-encoder.js +9 -6
- package/dist/rerankers/index.js +2 -1
- package/dist/rerankers/jev.js +2 -1
- package/dist/rerankers/llm.d.ts +6 -2
- package/dist/rerankers/llm.js +8 -3
- package/dist/rerankers/remote.d.ts +3 -1
- package/dist/rerankers/remote.js +5 -2
- package/dist/rerankers/types.d.ts +6 -2
- package/dist/search/bm25-search.d.ts +3 -1
- package/dist/search/bm25-search.js +15 -2
- package/dist/search/boosts.js +4 -3
- package/dist/search/embed-memories.d.ts +10 -5
- package/dist/search/embed-memories.js +62 -36
- package/dist/search/engine.d.ts +4 -1
- package/dist/search/engine.js +6 -2
- package/dist/search/goal-boost.d.ts +10 -3
- package/dist/search/goal-boost.js +13 -6
- package/dist/search/hybrid-score.d.ts +4 -1
- package/dist/search/hybrid-score.js +4 -1
- package/dist/search/hybrid.d.ts +23 -8
- package/dist/search/hybrid.js +12 -7
- package/dist/search/multihop.js +14 -13
- package/dist/search/path-context.d.ts +10 -3
- package/dist/search/path-context.js +10 -3
- package/dist/search/physics-search.d.ts +9 -4
- package/dist/search/physics-search.js +38 -14
- package/dist/search/rerank.d.ts +2 -1
- package/dist/search/rerank.js +2 -1
- package/dist/search/rrf.d.ts +14 -5
- package/dist/search/rrf.js +11 -4
- package/dist/search/vector.d.ts +8 -2
- package/dist/search/vector.js +9 -3
- package/dist/server/auth.d.ts +18 -14
- package/dist/server/auth.js +69 -38
- package/dist/server/boot.d.ts +3 -1
- package/dist/server/boot.js +95 -56
- package/dist/server/client-ip.d.ts +11 -4
- package/dist/server/client-ip.js +27 -10
- package/dist/server/cursor.d.ts +10 -3
- package/dist/server/cursor.js +10 -3
- package/dist/server/deadline.d.ts +5 -2
- package/dist/server/deadline.js +10 -3
- package/dist/server/key-check-bounds.js +12 -4
- package/dist/server/lifecycle.d.ts +4 -1
- package/dist/server/lifecycle.js +10 -4
- package/dist/server/mcp-http.d.ts +2 -1
- package/dist/server/mcp-http.js +37 -22
- package/dist/server/rate-limit.d.ts +17 -5
- package/dist/server/rate-limit.js +55 -26
- package/dist/server/ready.js +7 -4
- package/dist/server/request.d.ts +15 -4
- package/dist/server/request.js +42 -15
- package/dist/server/route-checks.d.ts +4 -1
- package/dist/server/route-checks.js +8 -3
- package/dist/server/route-table.d.ts +8 -6
- package/dist/server/route-table.js +547 -93
- package/dist/server/routes/admin.d.ts +7 -7
- package/dist/server/routes/admin.js +36 -15
- package/dist/server/routes/customer-notes.d.ts +5 -5
- package/dist/server/routes/customer-notes.js +5 -4
- package/dist/server/routes/decisions.d.ts +5 -5
- package/dist/server/routes/decisions.js +12 -6
- package/dist/server/routes/incidents.d.ts +5 -5
- package/dist/server/routes/incidents.js +10 -4
- package/dist/server/routes/memories.d.ts +8 -8
- package/dist/server/routes/memories.js +12 -19
- package/dist/server/routes/object-routes.d.ts +8 -5
- package/dist/server/routes/object-routes.js +4 -2
- package/dist/server/routes/policies.d.ts +6 -6
- package/dist/server/routes/policies.js +11 -4
- package/dist/server/routes/predictions.d.ts +5 -5
- package/dist/server/routes/predictions.js +9 -4
- package/dist/server/routes/processes.d.ts +5 -5
- package/dist/server/routes/processes.js +15 -6
- package/dist/server/routes/project-briefs.d.ts +6 -6
- package/dist/server/routes/project-briefs.js +3 -2
- package/dist/server/routes/recall.d.ts +3 -3
- package/dist/server/routes/recall.js +21 -10
- package/dist/server/routes/skills.d.ts +6 -6
- package/dist/server/routes/skills.js +12 -4
- package/dist/server/server-detect.d.ts +24 -8
- package/dist/server/server-detect.js +57 -22
- package/dist/server/sleep-child.js +16 -10
- package/dist/server/sleep-offload.d.ts +8 -5
- package/dist/server/sleep-offload.js +41 -19
- package/dist/server/tls.d.ts +4 -1
- package/dist/server/tls.js +13 -5
- package/dist/server/types.d.ts +38 -26
- package/dist/server/validation.d.ts +4 -1
- package/dist/server/validation.js +22 -9
- package/dist/server.d.ts +15 -10
- package/dist/server.js +32 -12
- package/dist/sharing/global-store.d.ts +5 -10
- package/dist/sharing/global-store.js +8 -43
- package/dist/sharing/global-sync.d.ts +3 -1
- package/dist/sharing/global-sync.js +16 -6
- package/dist/sharing/project-merge.d.ts +25 -7
- package/dist/sharing/project-merge.js +49 -17
- package/dist/sharing/search-both.d.ts +8 -4
- package/dist/sharing/search-both.js +19 -12
- package/dist/sharing/share.d.ts +8 -4
- package/dist/sharing/share.js +39 -15
- package/dist/store/ambient.js +9 -5
- package/dist/store/audit-event.d.ts +2 -2
- package/dist/store/audit-event.js +8 -3
- package/dist/store/audit.d.ts +6 -3
- package/dist/store/audit.js +16 -6
- package/dist/store/auth.d.ts +4 -2
- package/dist/store/auth.js +63 -20
- package/dist/store/busy.d.ts +9 -0
- package/dist/store/busy.js +16 -0
- package/dist/store/candidates.d.ts +12 -5
- package/dist/store/candidates.js +75 -36
- package/dist/store/capture-write.d.ts +2 -1
- package/dist/store/capture-write.js +2 -1
- package/dist/store/card-detail.d.ts +4 -4
- package/dist/store/card-detail.js +15 -8
- package/dist/store/cards.d.ts +24 -10
- package/dist/store/cards.js +93 -60
- package/dist/store/compaction-caller.d.ts +2 -1
- package/dist/store/compaction-caller.js +2 -1
- package/dist/store/compactions-record.d.ts +14 -8
- package/dist/store/compactions-record.js +95 -32
- package/dist/store/compactions.js +35 -15
- package/dist/store/conflicts.d.ts +9 -4
- package/dist/store/conflicts.js +100 -45
- package/dist/store/connectors/dlq.d.ts +17 -5
- package/dist/store/connectors/dlq.js +56 -5
- package/dist/store/connectors/event-log.d.ts +111 -2
- package/dist/store/connectors/event-log.js +2 -1
- package/dist/store/connectors/github.d.ts +6 -3
- package/dist/store/connectors/github.js +24 -40
- package/dist/store/connectors/slack.d.ts +2 -1
- package/dist/store/connectors/slack.js +25 -37
- package/dist/store/dashboard-reads.d.ts +7 -3
- package/dist/store/dashboard-reads.js +32 -11
- package/dist/store/delete-and-batch.d.ts +17 -11
- package/dist/store/delete-and-batch.js +67 -26
- package/dist/store/delivery-recorder.d.ts +8 -5
- package/dist/store/delivery-recorder.js +70 -32
- package/dist/store/descendant-page.d.ts +2 -1
- package/dist/store/descendant-page.js +24 -9
- package/dist/store/diagnostics.d.ts +2 -1
- package/dist/store/diagnostics.js +2 -1
- package/dist/store/doctor-reads.d.ts +2 -1
- package/dist/store/doctor-reads.js +13 -5
- package/dist/store/dormant.d.ts +19 -11
- package/dist/store/dormant.js +40 -18
- package/dist/store/embeddings/index.d.ts +13 -9
- package/dist/store/embeddings/index.js +19 -12
- package/dist/store/entry-reads.d.ts +49 -20
- package/dist/store/entry-reads.js +181 -66
- package/dist/store/entry-row.d.ts +10 -6
- package/dist/store/entry-row.js +17 -12
- package/dist/store/entry-writes.d.ts +22 -10
- package/dist/store/entry-writes.js +41 -14
- package/dist/store/failure-log-at.js +1 -1
- package/dist/store/failure-log.d.ts +4 -2
- package/dist/store/failure-log.js +13 -6
- package/dist/store/gated-write.d.ts +3 -3
- package/dist/store/gated-write.js +3 -3
- package/dist/store/goals.d.ts +5 -4
- package/dist/store/goals.js +8 -10
- package/dist/store/graph-apply.d.ts +21 -0
- package/dist/{graph/write.js → store/graph-apply.js} +31 -11
- package/dist/store/graph-queue.d.ts +9 -6
- package/dist/store/graph-queue.js +15 -10
- package/dist/store/graph-reads.d.ts +16 -11
- package/dist/store/graph-reads.js +24 -15
- package/dist/store/graph-rows.d.ts +41 -3
- package/dist/store/graph-rows.js +10 -7
- package/dist/store/graph-view-rows.js +14 -7
- package/dist/store/graph-writes.d.ts +16 -10
- package/dist/store/graph-writes.js +59 -36
- package/dist/store/handoffs.d.ts +4 -4
- package/dist/store/handoffs.js +40 -19
- package/dist/store/index-and-stats.d.ts +2 -2
- package/dist/store/index-and-stats.js +6 -5
- package/dist/store/index.d.ts +3 -1
- package/dist/store/index.js +1 -0
- package/dist/store/key-audit.d.ts +2 -1
- package/dist/store/key-audit.js +2 -1
- package/dist/store/key-writes.d.ts +2 -1
- package/dist/store/key-writes.js +9 -2
- package/dist/store/ledger-turn.d.ts +4 -1
- package/dist/store/ledger-turn.js +7 -2
- package/dist/store/mirrors.d.ts +11 -4
- package/dist/store/mirrors.js +88 -16
- package/dist/store/narrow.d.ts +6 -0
- package/dist/store/narrow.js +11 -0
- package/dist/store/open.d.ts +4 -2
- package/dist/store/open.js +18 -9
- package/dist/store/pilot-arm.d.ts +2 -1
- package/dist/store/pilot-arm.js +18 -6
- package/dist/store/planning-fallacy-evidence.d.ts +2 -2
- package/dist/store/planning-fallacy-evidence.js +8 -5
- package/dist/store/port/agent-import.d.ts +62 -0
- package/dist/store/port/agent-import.js +2 -0
- package/dist/store/port/consolidation.d.ts +129 -0
- package/dist/store/port/consolidation.js +2 -0
- package/dist/store/port/learning.d.ts +19 -0
- package/dist/store/port/learning.js +2 -0
- package/dist/store/port/local-files.d.ts +18 -0
- package/dist/store/port/local-files.js +2 -0
- package/dist/store/port/promotion.d.ts +20 -0
- package/dist/store/port/promotion.js +3 -0
- package/dist/store/port-groups.d.ts +160 -0
- package/dist/store/port-groups.js +2 -0
- package/dist/store/port.d.ts +215 -229
- package/dist/store/port.js +3 -9
- package/dist/store/predictions.d.ts +14 -10
- package/dist/store/predictions.js +37 -17
- package/dist/store/project-tags.d.ts +4 -1
- package/dist/store/project-tags.js +16 -5
- package/dist/store/quality-repair.d.ts +8 -4
- package/dist/store/quality-repair.js +53 -20
- package/dist/store/quarantine.d.ts +1 -0
- package/dist/store/quarantine.js +23 -9
- package/dist/store/raw-archive.d.ts +5 -4
- package/dist/store/raw-archive.js +11 -10
- package/dist/store/recall-trace.d.ts +22 -17
- package/dist/store/recall-trace.js +126 -63
- package/dist/store/rejected-values.d.ts +15 -10
- package/dist/store/rejected-values.js +33 -12
- package/dist/store/rejection.d.ts +12 -11
- package/dist/store/rejection.js +18 -19
- package/dist/store/report-reads.d.ts +2 -1
- package/dist/store/report-reads.js +2 -1
- package/dist/store/rows.d.ts +7 -5
- package/dist/store/rows.js +18 -11
- package/dist/store/rule-sql.d.ts +6 -4
- package/dist/store/rule-sql.js +16 -9
- package/dist/store/search-rows.d.ts +14 -9
- package/dist/store/search-rows.js +48 -23
- package/dist/store/sessions.d.ts +12 -10
- package/dist/store/sessions.js +40 -21
- package/dist/store/set-aside.d.ts +2 -2
- package/dist/store/set-aside.js +18 -5
- package/dist/store/sqlite/agent-import.d.ts +3 -0
- package/dist/store/sqlite/agent-import.js +77 -0
- package/dist/store/sqlite/cards-group.d.ts +6 -0
- package/dist/store/sqlite/cards-group.js +37 -0
- package/dist/store/sqlite/conflicts-group.d.ts +6 -0
- package/dist/store/sqlite/conflicts-group.js +18 -0
- package/dist/store/sqlite/connector-events-group.d.ts +2 -1
- package/dist/store/sqlite/connector-events-group.js +17 -6
- package/dist/store/sqlite/connector-writes-group.d.ts +2 -1
- package/dist/store/sqlite/connector-writes-group.js +9 -4
- package/dist/store/sqlite/consolidation-group.d.ts +4 -0
- package/dist/store/sqlite/consolidation-group.js +64 -0
- package/dist/store/sqlite/dag-reads-group.js +1 -1
- package/dist/store/sqlite/dormant-group.d.ts +6 -0
- package/dist/store/sqlite/dormant-group.js +29 -0
- package/dist/store/sqlite/entry-writes-group.d.ts +6 -3
- package/dist/store/sqlite/entry-writes-group.js +37 -14
- package/dist/store/sqlite/error-codec.d.ts +4 -2
- package/dist/store/sqlite/error-codec.js +32 -10
- package/dist/store/sqlite/executor-counts.js +2 -1
- package/dist/store/sqlite/executor.d.ts +8 -3
- package/dist/store/sqlite/executor.js +56 -18
- package/dist/store/sqlite/global-promote.d.ts +5 -0
- package/dist/store/sqlite/global-promote.js +48 -0
- package/dist/store/sqlite/goals-group.d.ts +6 -0
- package/dist/store/sqlite/goals-group.js +23 -0
- package/dist/store/sqlite/graph-reads-group.d.ts +2 -1
- package/dist/store/sqlite/graph-reads-group.js +2 -1
- package/dist/store/sqlite/held-connection.d.ts +7 -1
- package/dist/store/sqlite/held-connection.js +34 -7
- package/dist/store/sqlite/last-recall-group.d.ts +4 -2
- package/dist/store/sqlite/last-recall-group.js +9 -4
- package/dist/store/sqlite/learning-group.d.ts +4 -0
- package/dist/store/sqlite/learning-group.js +17 -0
- package/dist/store/sqlite/maintenance-groups.js +2 -1
- package/dist/store/sqlite/object-rows.d.ts +6 -3
- package/dist/store/sqlite/object-rows.js +34 -5
- package/dist/store/sqlite/objects-group.d.ts +5 -4
- package/dist/store/sqlite/objects-group.js +84 -33
- package/dist/store/sqlite/predictions-group.d.ts +2 -1
- package/dist/store/sqlite/predictions-group.js +4 -2
- package/dist/store/sqlite/promotion-group.d.ts +3 -0
- package/dist/store/sqlite/promotion-group.js +10 -0
- package/dist/store/sqlite/quarantine-group.d.ts +2 -1
- package/dist/store/sqlite/quarantine-group.js +4 -2
- package/dist/store/sqlite/reports-group.d.ts +6 -0
- package/dist/store/sqlite/reports-group.js +33 -0
- package/dist/store/sqlite/request-scope.d.ts +6 -0
- package/dist/store/sqlite/request-scope.js +18 -0
- package/dist/store/sqlite/sessions-group.d.ts +6 -0
- package/dist/store/sqlite/sessions-group.js +46 -0
- package/dist/store/sqlite/store.d.ts +22 -11
- package/dist/store/sqlite/store.js +84 -11
- package/dist/store/sqlite/vector-pack.js +2 -1
- package/dist/store/sqlite/vector-reads-group.js +2 -1
- package/dist/store/sqlite/worker-jobs.d.ts +2 -1
- package/dist/store/sqlite/worker-jobs.js +19 -7
- package/dist/store/sqlite/worker-ops.d.ts +10 -5
- package/dist/store/sqlite/worker-ops.js +6 -3
- package/dist/store/sqlite/worker-store.d.ts +4 -3
- package/dist/store/sqlite/worker-store.js +24 -14
- package/dist/store/summaries.d.ts +19 -12
- package/dist/store/summaries.js +36 -21
- package/dist/store/summary-dirty.d.ts +2 -1
- package/dist/store/summary-dirty.js +2 -1
- package/dist/store/tenant.d.ts +3 -2
- package/dist/store/tenant.js +5 -4
- package/dist/store/token-ledger-rows.js +6 -3
- package/dist/store/token-ledger.d.ts +19 -13
- package/dist/store/token-ledger.js +27 -14
- package/dist/store/tombstone-checks.d.ts +4 -1
- package/dist/store/tombstone-checks.js +10 -1
- package/dist/store/usage-reports.js +2 -1
- package/dist/store/vector-index.d.ts +8 -5
- package/dist/store/vector-index.js +24 -10
- package/dist/store/working-memory.d.ts +6 -4
- package/dist/store/working-memory.js +14 -9
- package/dist/support-bundle.js +10 -5
- package/dist/trust/quarantine.d.ts +1 -2
- package/dist/trust/quarantine.js +1 -5
- package/dist/trust/reject-flow.d.ts +12 -3
- package/dist/trust/reject-flow.js +12 -4
- package/dist/util/anthropic-messages.d.ts +4 -1
- package/dist/util/anthropic-messages.js +14 -5
- package/dist/util/atomic-write.d.ts +4 -2
- package/dist/util/atomic-write.js +25 -14
- package/dist/util/compaction-items.d.ts +4 -1
- package/dist/util/compaction-items.js +8 -2
- package/dist/util/crash-handlers.d.ts +7 -2
- package/dist/util/crash-handlers.js +13 -4
- package/dist/util/env.d.ts +16 -4
- package/dist/util/env.js +78 -25
- package/dist/util/home-path.js +12 -6
- package/dist/util/hook-payload.d.ts +3 -1
- package/dist/util/hook-payload.js +3 -1
- package/dist/util/http-retry.d.ts +12 -6
- package/dist/util/http-retry.js +16 -6
- package/dist/util/http-util.d.ts +20 -5
- package/dist/util/http-util.js +28 -9
- package/dist/util/json.d.ts +4 -1
- package/dist/util/json.js +4 -1
- package/dist/util/keyset.js +2 -1
- package/dist/util/limits.js +4 -2
- package/dist/util/log.d.ts +13 -5
- package/dist/util/log.js +29 -6
- package/dist/util/net.d.ts +5 -0
- package/dist/util/net.js +19 -0
- package/dist/util/real-path.d.ts +2 -1
- package/dist/util/real-path.js +4 -3
- package/dist/util/request-scope.d.ts +11 -3
- package/dist/util/request-scope.js +13 -4
- package/dist/util/same-text.d.ts +10 -3
- package/dist/util/same-text.js +10 -3
- package/dist/util/secret-detect.d.ts +24 -7
- package/dist/util/secret-detect.js +49 -14
- package/dist/util/spawn-argv.d.ts +3 -1
- package/dist/util/spawn-argv.js +13 -4
- package/dist/util/sqlite-blocked.d.ts +15 -4
- package/dist/util/sqlite-blocked.js +19 -6
- package/dist/util/stored-json.d.ts +4 -1
- package/dist/util/stored-json.js +6 -2
- package/dist/util/stream-tee.d.ts +2 -1
- package/dist/util/stream-tee.js +8 -5
- package/dist/util/transcript-tail.d.ts +4 -1
- package/dist/util/transcript-tail.js +4 -1
- package/dist/util/version.d.ts +8 -3
- package/dist/util/version.js +8 -3
- package/dist/util/write-budget.d.ts +7 -2
- package/dist/util/write-budget.js +5 -2
- package/dist/util/yaml.d.ts +4 -1
- package/dist/util/yaml.js +4 -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 +2 -1
- package/scripts/postinstall.cjs +3 -1
- package/dist/api/cards.d.ts +0 -42
- package/dist/api/conflicts.d.ts +0 -28
- package/dist/api/conflicts.js +0 -61
- package/dist/api/dormant.d.ts +0 -14
- package/dist/api/dormant.js +0 -58
- package/dist/api/goals.d.ts +0 -18
- package/dist/api/graph.d.ts +0 -8
- package/dist/api/graph.js +0 -8
- package/dist/api/learn.js +0 -125
- package/dist/api/memories.d.ts +0 -25
- package/dist/api/objects.d.ts +0 -9
- package/dist/api/outcome.d.ts +0 -19
- package/dist/api/predictions.d.ts +0 -11
- package/dist/api/promote.d.ts +0 -36
- package/dist/api/recall-core.d.ts +0 -4
- package/dist/api/recall-core.js +0 -125
- package/dist/api/recall-finish.d.ts +0 -53
- package/dist/api/recall-finish.js +0 -30
- package/dist/api/recall-history.d.ts +0 -64
- package/dist/api/recall-history.js +0 -159
- package/dist/api/recall-record.d.ts +0 -43
- package/dist/api/recall-record.js +0 -78
- package/dist/api/recall-request.js +0 -121
- package/dist/api/recall.d.ts +0 -6
- package/dist/api/refine.d.ts +0 -7
- package/dist/api/refine.js +0 -10
- package/dist/api/session-owners.d.ts +0 -4
- package/dist/api/session-owners.js +0 -17
- package/dist/api/sleep-run.d.ts +0 -26
- package/dist/api/sleep.js +0 -11
- package/dist/graph/write.d.ts +0 -14
- package/dist/store/sqlite/busy.d.ts +0 -3
- package/dist/store/sqlite/busy.js +0 -8
- package/dist/store/sqlite/local.d.ts +0 -4
- package/dist/store/sqlite/local.js +0 -8
package/dist/server/auth.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
// Bearer and loopback auth for the HTTP server.
|
|
2
2
|
import { envAllowKeylessLocal, envKeylessLocalRole, envRequireAuth } from '../util/env.js';
|
|
3
|
+
import { loadConfig } from '../core/config.js';
|
|
3
4
|
import { resolveTenantId } from '../store/tenant.js';
|
|
5
|
+
import { sqliteReach } from '../store/sqlite/store.js';
|
|
4
6
|
import { errorFields, errorMessage, log } from '../util/log.js';
|
|
5
7
|
import { API_KEY_PREFIX, verifyApiKeyCached } from '../store/auth.js';
|
|
6
8
|
import { ownerOrSubject } from '../api/index.js';
|
|
@@ -9,38 +11,40 @@ import { MAX_ID_LEN } from '../util/limits.js';
|
|
|
9
11
|
import { clientLimitKey } from './client-ip.js';
|
|
10
12
|
import { keyCheckBounds } from './key-check-bounds.js';
|
|
11
13
|
import { isJsonString } from '../util/json.js';
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
if (remoteAddress === '::1')
|
|
19
|
-
return true;
|
|
20
|
-
if (remoteAddress === '::ffff:127.0.0.1')
|
|
21
|
-
return true;
|
|
22
|
-
return false;
|
|
23
|
-
}
|
|
24
|
-
// A proxy on this host (nginx, Caddy, cloudflared) connects from loopback, so these headers mean the caller is not local.
|
|
14
|
+
import { MINUTE_MS } from '../util/time.js';
|
|
15
|
+
import { isLoopbackAddress } from '../util/net.js';
|
|
16
|
+
/** Kept under its old name because src/server.ts publishes it. */
|
|
17
|
+
export const isLoopback = isLoopbackAddress;
|
|
18
|
+
// A proxy on this host (nginx, Caddy, cloudflared) connects
|
|
19
|
+
// from loopback, so these headers mean the caller is not local.
|
|
25
20
|
const PROXY_HEADERS = [
|
|
26
|
-
'forwarded',
|
|
21
|
+
'forwarded',
|
|
22
|
+
'x-forwarded-for',
|
|
23
|
+
'x-forwarded-host',
|
|
24
|
+
'x-forwarded-proto',
|
|
25
|
+
'x-real-ip',
|
|
26
|
+
'cf-connecting-ip',
|
|
27
|
+
'true-client-ip',
|
|
27
28
|
'fly-client-ip',
|
|
28
29
|
];
|
|
29
30
|
function proxyHeaderOf(req) {
|
|
30
31
|
return PROXY_HEADERS.find((name) => req.headers[name] !== undefined);
|
|
31
32
|
}
|
|
32
|
-
/** A page in a browser on this machine: another site's request,
|
|
33
|
+
/** A page in a browser on this machine: another site's request,
|
|
34
|
+
* or a hostile name resolved to loopback (DNS rebinding). */
|
|
33
35
|
function isForeignPage(req) {
|
|
34
36
|
const host = req.headers.host;
|
|
35
37
|
return (host !== undefined && !LOOPBACK_HOST_HEADER.test(host)) || isCrossSite(req);
|
|
36
38
|
}
|
|
37
|
-
/** True only for a request made on this machine by its own user: a proxy and a browser page are loopback too, so the
|
|
39
|
+
/** True only for a request made on this machine by its own user: a proxy and a browser page are loopback too, so the
|
|
40
|
+
* socket alone proves nothing. */
|
|
38
41
|
export function isLocalCaller(req) {
|
|
39
|
-
return
|
|
42
|
+
return isLoopbackAddress(req.socket.remoteAddress) && proxyHeaderOf(req) === undefined && !isForeignPage(req);
|
|
40
43
|
}
|
|
41
|
-
// The throwing twin of isLocalCaller, for the no-key fallback:
|
|
44
|
+
// The throwing twin of isLocalCaller, for the no-key fallback:
|
|
45
|
+
// each refusal has its own status, and a proxied one is logged.
|
|
42
46
|
function assertLocalCaller(req) {
|
|
43
|
-
if (!
|
|
47
|
+
if (!isLoopbackAddress(req.socket.remoteAddress))
|
|
44
48
|
throw new HttpError(401, 'auth required');
|
|
45
49
|
const proxyHeader = proxyHeaderOf(req);
|
|
46
50
|
if (proxyHeader !== undefined) {
|
|
@@ -52,10 +56,11 @@ function assertLocalCaller(req) {
|
|
|
52
56
|
throw new HttpError(403, 'cross-site or non-local request refused; send an API key');
|
|
53
57
|
}
|
|
54
58
|
}
|
|
55
|
-
/** The 401 a keyless request from this machine gets by default; it names both fixes, since an upgrade is where most
|
|
59
|
+
/** The 401 a keyless request from this machine gets by default; it names both fixes, since an upgrade is where most
|
|
60
|
+
* people meet it. */
|
|
56
61
|
const KEY_REQUIRED_MESSAGE = 'auth required: this server takes no request without an API key. Mint one with `hippo auth create` and send it as ' +
|
|
57
|
-
'"Authorization: Bearer <key>" (the hippo CLI reads HIPPO_API_KEY), or start the server with
|
|
58
|
-
'to let requests from this machine in without a key.';
|
|
62
|
+
'"Authorization: Bearer <key>" (the hippo CLI reads HIPPO_API_KEY), or start the server with ' +
|
|
63
|
+
'HIPPO_ALLOW_KEYLESS_LOCAL=1 to let requests from this machine in without a key.';
|
|
59
64
|
export function readAuthHeader(req) {
|
|
60
65
|
const raw = req.headers['authorization'];
|
|
61
66
|
if (raw === undefined)
|
|
@@ -149,7 +154,8 @@ async function askResolver(resolver, token, deadlineMs) {
|
|
|
149
154
|
return clean;
|
|
150
155
|
}
|
|
151
156
|
const DEFAULT_RESOLVER_DEADLINE_MS = 5000;
|
|
152
|
-
/** Runs only before scrypt, so junk, unknown, revoked and expired
|
|
157
|
+
/** Runs only before scrypt, so junk, unknown, revoked and expired
|
|
158
|
+
* tokens and a proven key's re-check never spend a colleague's budget. */
|
|
153
159
|
function chargeScryptRun(req, opts) {
|
|
154
160
|
const limiter = opts.failedAuthLimiter;
|
|
155
161
|
// Reserving rather than peeking bounds scrypt runs exactly, even when concurrent misses await a slow store.
|
|
@@ -164,17 +170,24 @@ async function resolveBearer(req, token, opts) {
|
|
|
164
170
|
const t = opts.authResolverTimeoutMs;
|
|
165
171
|
const deadlineMs = t !== undefined && Number.isFinite(t) && t > 0 ? t : DEFAULT_RESOLVER_DEADLINE_MS;
|
|
166
172
|
const clean = await askResolver(opts.authResolver, token, deadlineMs);
|
|
167
|
-
|
|
173
|
+
// A resolver vouches for a person, never names one.
|
|
174
|
+
return { ...clean, viaAuthResolver: true, owner: clean.subject };
|
|
168
175
|
}
|
|
169
176
|
const key = await verifyApiKeyCached(token, opts.store, (keyId, derive) => {
|
|
170
|
-
// The key's own bucket first, so a flood on one key id ends at its five tries and leaves the address's budget to
|
|
177
|
+
// The key's own bucket first, so a flood on one key id ends at its five tries and leaves the address's budget to
|
|
178
|
+
// the callers who share it.
|
|
171
179
|
keyChecks.admit(keyId, clientLimitKey(req));
|
|
172
180
|
chargeScryptRun(req, opts);
|
|
173
181
|
return keyChecks.run(derive);
|
|
174
182
|
});
|
|
175
183
|
if (!key)
|
|
176
184
|
throw new HttpError(401, 'invalid api key');
|
|
177
|
-
const id = {
|
|
185
|
+
const id = {
|
|
186
|
+
tenantId: key.tenantId,
|
|
187
|
+
subject: `api_key:${key.keyId}`,
|
|
188
|
+
role: key.role,
|
|
189
|
+
scopes: key.scopes,
|
|
190
|
+
};
|
|
178
191
|
if (key.ownerSubject)
|
|
179
192
|
id.owner = key.ownerSubject;
|
|
180
193
|
return id;
|
|
@@ -213,7 +226,7 @@ function bearerActor(id) {
|
|
|
213
226
|
export const LIMITER_MAX_KEYS = 10_000;
|
|
214
227
|
// One for the process, as the thread pool its derivations run on is.
|
|
215
228
|
const keyChecks = keyCheckBounds(LIMITER_MAX_KEYS);
|
|
216
|
-
const CALLER_WARN_EVERY_MS =
|
|
229
|
+
const CALLER_WARN_EVERY_MS = MINUTE_MS;
|
|
217
230
|
const callerWarnedAt = new Map();
|
|
218
231
|
function warnCallerLimited(key, tenantId, person) {
|
|
219
232
|
const now = Date.now();
|
|
@@ -240,8 +253,8 @@ function chargeCaller(tenantId, actor, opts) {
|
|
|
240
253
|
warnCallerLimited(key, tenantId, person);
|
|
241
254
|
throw new HttpError(429, 'rate limit exceeded for this caller', limiter.retryAfterSec);
|
|
242
255
|
}
|
|
243
|
-
/** Builds a per-request Context from the Authorization header and remote address; throws HttpError(401)
|
|
244
|
-
* Reads the store only for an API-key-shaped Bearer (or any Bearer
|
|
256
|
+
/** Builds a per-request Context from the Authorization header and remote address; throws HttpError(401) on bad ones.
|
|
257
|
+
* Reads the store only for an API-key-shaped Bearer (or any Bearer with no resolver), so keyless calls stay cheap. */
|
|
245
258
|
export async function buildContextWithAuth(req, opts) {
|
|
246
259
|
const id = await checkAuth(req, opts);
|
|
247
260
|
const ctx = contextFor(id, opts);
|
|
@@ -249,28 +262,46 @@ export async function buildContextWithAuth(req, opts) {
|
|
|
249
262
|
chargeCaller(id.tenantId, ctx.actor, opts);
|
|
250
263
|
return ctx;
|
|
251
264
|
}
|
|
252
|
-
/** The auth check again, uncharged, for a handler that authenticated with requireAuth before a slow body read and
|
|
265
|
+
/** The auth check again, uncharged, for a handler that authenticated with requireAuth before a slow body read and
|
|
266
|
+
* must re-check right before it acts. */
|
|
253
267
|
export async function recheckContextWithAuth(req, opts) {
|
|
254
268
|
return contextFor(await checkAuth(req, opts), opts);
|
|
255
269
|
}
|
|
256
|
-
/** The keyless local caller: any process on this machine can reach
|
|
270
|
+
/** The keyless local caller: any process on this machine can reach
|
|
271
|
+
* loopback, so it is a member unless the operator names admin. */
|
|
257
272
|
function keylessLocalActor(opts) {
|
|
258
273
|
const role = opts.keylessLocalRole ?? envKeylessLocalRole();
|
|
259
|
-
return role === 'admin'
|
|
274
|
+
return role === 'admin'
|
|
275
|
+
? { subject: 'localhost:cli', role: 'admin', hostAdmin: true }
|
|
276
|
+
: { subject: 'localhost:cli', role: 'member' };
|
|
260
277
|
}
|
|
261
278
|
function contextFor(id, opts) {
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
279
|
+
// Per request, never cached at serve: the global store can be created while the server runs.
|
|
280
|
+
const reach = sqliteReach(opts.hippoRoot, opts.store);
|
|
281
|
+
// loadConfig caches by file mtime, so each request still sees an edit made while the server runs.
|
|
282
|
+
const config = loadConfig(opts.hippoRoot);
|
|
283
|
+
if (id !== null) {
|
|
284
|
+
const actor = bearerActor(id);
|
|
285
|
+
return { hippoRoot: opts.hippoRoot, tenantId: id.tenantId, actor, store: opts.store, reach, config };
|
|
286
|
+
}
|
|
287
|
+
return {
|
|
288
|
+
hippoRoot: opts.hippoRoot,
|
|
289
|
+
tenantId: resolveTenantId({}),
|
|
290
|
+
actor: keylessLocalActor(opts),
|
|
291
|
+
store: opts.store,
|
|
292
|
+
reach,
|
|
293
|
+
config,
|
|
294
|
+
};
|
|
265
295
|
}
|
|
266
|
-
/** Auth check for routes that need no tenant Context (e.g. the MCP transport, which resolves its own root): throws
|
|
267
|
-
* A keyless local request passes only under HIPPO_ALLOW_KEYLESS_LOCAL=1. */
|
|
296
|
+
/** Auth check for routes that need no tenant Context (e.g. the MCP transport, which resolves its own root): throws
|
|
297
|
+
* HttpError 401 like buildContextWithAuth. A keyless local request passes only under HIPPO_ALLOW_KEYLESS_LOCAL=1. */
|
|
268
298
|
export async function requireAuth(req, opts) {
|
|
269
299
|
const id = await checkAuth(req, opts);
|
|
270
300
|
if (id !== null)
|
|
271
301
|
chargeCaller(id.tenantId, bearerActor(id), opts);
|
|
272
302
|
}
|
|
273
|
-
/** Never rejects or charges a caller bucket: an outage (5xx) or a throttle (429) skips one tick; only a definite 4xx
|
|
303
|
+
/** Never rejects or charges a caller bucket: an outage (5xx) or a throttle (429) skips one tick; only a definite 4xx
|
|
304
|
+
* denial closes the stream. */
|
|
274
305
|
export async function heartbeatVerdict(req, opts) {
|
|
275
306
|
try {
|
|
276
307
|
await checkAuth(req, opts);
|
package/dist/server/boot.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type { ServeOpts, ServerHandle } from './types.js';
|
|
2
|
-
/**
|
|
2
|
+
/**
|
|
3
|
+
* Boots the HTTP daemon on host:port and writes the pidfile under hippoRoot; refuses a non-loopback host unless
|
|
4
|
+
* HIPPO_REQUIRE_AUTH=1 and
|
|
3
5
|
* either `tls` or allowCleartext is given, and refuses HIPPO_CLIENT_IP_HEADER without HIPPO_TRUSTED_PROXIES.
|
|
4
6
|
* Use port: 0 in tests for an ephemeral port. See docs/ARCHITECTURE.md#srcserverbootts. */
|
|
5
7
|
export declare function serve(opts: ServeOpts): Promise<ServerHandle>;
|
package/dist/server/boot.js
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
import { envAllowCleartext, envCallerRps, envPort, envRequireAuth, envV1Rps } from '../util/env.js';
|
|
2
2
|
import { detectServer, removePidfileIfOwned, writePidfile } from './server-detect.js';
|
|
3
|
-
import { outsideSqliteOffLoop, runWithRequestStores, SERVER_DB_WAIT_MS, withSqliteBlocked } from '../db/index.js';
|
|
4
3
|
import { hasGroup } from '../store/index.js';
|
|
5
|
-
import { isStoreBusy } from '../
|
|
6
|
-
import {
|
|
4
|
+
import { isStoreBusy } from '../api/busy.js';
|
|
5
|
+
import { createStoreHolder, offLoopFor, outsideRouteBlock, } from '../store/sqlite/held-connection.js';
|
|
7
6
|
import { workerSqliteStore } from '../store/sqlite/worker-store.js';
|
|
8
7
|
import { markSharedStore } from '../core/config.js';
|
|
9
8
|
import { auditWriteFailureCount } from '../store/audit.js';
|
|
10
9
|
import { PACKAGE_VERSION } from '../util/version.js';
|
|
10
|
+
import { MINUTE_MS } from '../util/time.js';
|
|
11
11
|
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 { BodyTimeoutError, BodyTooLargeError, closeAfterReply, DeadlineExceededError, HttpError, JSON_HEADERS, sendJson } from '../util/http-util.js';
|
|
15
|
+
import { BodyTimeoutError, BodyTooLargeError, closeAfterReply, DeadlineExceededError, HttpError, JSON_HEADERS, sendJson, } from '../util/http-util.js';
|
|
16
16
|
import { workerCounts } from '../store/sqlite/executor-counts.js';
|
|
17
17
|
import { isLocalCaller, LIMITER_MAX_KEYS } from './auth.js';
|
|
18
18
|
import { assertClientIpHeaderPinned, enforceRateLimit } from './client-ip.js';
|
|
@@ -23,7 +23,7 @@ import { DEFAULT_SERVER_HOST, DEFAULT_SERVER_PORT } from './defaults.js';
|
|
|
23
23
|
import { installCrashHandlers, installSignalHandlers } from '../util/crash-handlers.js';
|
|
24
24
|
import { handleMcpPost, handleMcpStream } from './mcp-http.js';
|
|
25
25
|
import { MCP_PROJECT_SCOPED_HEADER } from '../core/project-identity.js';
|
|
26
|
-
import { accessRouteOf, logRequestFailure, noteAccess, openRequest, parseRequest, rejectEncodedSlash, replyFor, sendError } from './request.js';
|
|
26
|
+
import { accessRouteOf, logRequestFailure, noteAccess, openRequest, parseRequest, rejectEncodedSlash, replyFor, sendError, } from './request.js';
|
|
27
27
|
import { assertTlsOrCleartextAllowed, createListener } from './tls.js';
|
|
28
28
|
import { assertAddonRoutes, assertPublicJson } from './route-checks.js';
|
|
29
29
|
import { dispatchAddonRoute, dispatchPublicJson, dispatchV1Route } from './route-table.js';
|
|
@@ -32,7 +32,8 @@ import { dispatchAddonRoute, dispatchPublicJson, dispatchV1Route } from './route
|
|
|
32
32
|
function isAddressInfo(a) {
|
|
33
33
|
return a !== null && typeof a !== 'string';
|
|
34
34
|
}
|
|
35
|
-
// Pinned at module load, bumped with package.json on releases; reading package.json synchronously here would couple the
|
|
35
|
+
// Pinned at module load, bumped with package.json on releases; reading package.json synchronously here would couple the
|
|
36
|
+
// daemon to its install path,
|
|
36
37
|
// which tests that mkdtemp a hippoRoot avoid.
|
|
37
38
|
const VERSION = PACKAGE_VERSION;
|
|
38
39
|
const LOOPBACK_HOSTS = new Set(['127.0.0.1', '::1', 'localhost']);
|
|
@@ -42,7 +43,8 @@ async function handleRequest(req, res, opts, options) {
|
|
|
42
43
|
// Node's URL parser collapses them and they slip past the route table.
|
|
43
44
|
rejectEncodedSlash(req.url ?? '/');
|
|
44
45
|
const { method, path, query } = parseRequest(req);
|
|
45
|
-
// An older core ignores X-Hippo-Project, so every /mcp reply, a 429 or 401 too, tells the client this one filters by
|
|
46
|
+
// An older core ignores X-Hippo-Project, so every /mcp reply, a 429 or 401 too, tells the client this one filters by
|
|
47
|
+
// it.
|
|
46
48
|
if (path === '/mcp')
|
|
47
49
|
res.setHeader(MCP_PROJECT_SCOPED_HEADER, '1');
|
|
48
50
|
if (method === 'GET' && path === '/health') {
|
|
@@ -57,19 +59,22 @@ async function handleRequest(req, res, opts, options) {
|
|
|
57
59
|
}
|
|
58
60
|
enforceRateLimit(req, path, limiter);
|
|
59
61
|
const routeRequest = { req, res, opts, query };
|
|
60
|
-
if (await
|
|
62
|
+
if (await dispatchScopedRoute(routeRequest, method, path))
|
|
61
63
|
return;
|
|
62
|
-
//
|
|
63
|
-
// heartbeat wait
|
|
64
|
+
// The request scope (the server's lock wait) is kept by the heartbeat timer after it closes, so the key check and
|
|
65
|
+
// every heartbeat wait that long. Store-ready: the stream only authenticates, through the port.
|
|
64
66
|
if (method === 'GET' && path === '/mcp/stream') {
|
|
65
67
|
noteAccess(req, { route: path });
|
|
66
|
-
await
|
|
68
|
+
await handleMcpStream(req, res, opts, streamSlots);
|
|
67
69
|
return;
|
|
68
70
|
}
|
|
69
71
|
res.writeHead(404, JSON_HEADERS);
|
|
70
72
|
res.end(JSON.stringify({ error: 'not found' }));
|
|
71
73
|
}
|
|
72
|
-
/**
|
|
74
|
+
/**
|
|
75
|
+
* Every route that runs inside a request scope, so it opens each store once: the /v1 table with the webhooks, public
|
|
76
|
+
* JSON, add-on routes and POST /mcp.
|
|
77
|
+
*/
|
|
73
78
|
async function dispatchScopedRoute(r, method, path) {
|
|
74
79
|
if (await dispatchV1Route(r, method, path))
|
|
75
80
|
return true;
|
|
@@ -87,8 +92,10 @@ async function dispatchScopedRoute(r, method, path) {
|
|
|
87
92
|
return false;
|
|
88
93
|
}
|
|
89
94
|
function sendHealth(req, res, startedAt) {
|
|
90
|
-
// A caller on this machine (detectServer's probe reads version and pid) gets the full body; anyone else, even a
|
|
91
|
-
//
|
|
95
|
+
// A caller on this machine (detectServer's probe reads version and pid) gets the full body; anyone else, even a
|
|
96
|
+
// proxied caller or a browser page on loopback,
|
|
97
|
+
// gets liveness only: the version would fingerprint the build and the pid is noise. Platform health checks only need
|
|
98
|
+
// the 200.
|
|
92
99
|
if (isLocalCaller(req)) {
|
|
93
100
|
sendJson(res, 200, {
|
|
94
101
|
ok: true,
|
|
@@ -128,7 +135,8 @@ function assertBindable(host) {
|
|
|
128
135
|
}
|
|
129
136
|
}
|
|
130
137
|
async function assertNoLiveServer(hippoRoot) {
|
|
131
|
-
// Refuse to start if a live hippo server already serves this hippoRoot (detectServer probes the recorded /health and
|
|
138
|
+
// Refuse to start if a live hippo server already serves this hippoRoot (detectServer probes the recorded /health and
|
|
139
|
+
// unlinks a stale pidfile):
|
|
132
140
|
// a concurrent `hippo serve` would race for the port and clobber the pidfile.
|
|
133
141
|
const existing = await detectServer(hippoRoot);
|
|
134
142
|
if (existing) {
|
|
@@ -136,35 +144,47 @@ async function assertNoLiveServer(hippoRoot) {
|
|
|
136
144
|
`Stop that server before starting another on the same hippoRoot.`);
|
|
137
145
|
}
|
|
138
146
|
}
|
|
139
|
-
// SHORTCUT: buckets live in this process and reset on restart or LRU eviction; move them to the store if serve ever
|
|
147
|
+
// SHORTCUT: buckets live in this process and reset on restart or LRU eviction; move them to the store if serve ever
|
|
148
|
+
// runs as several processes.
|
|
140
149
|
function limiterFor({ ratePerSec, burst }) {
|
|
141
|
-
return createRateLimiter({ ratePerSec, burst, idleEvictMs:
|
|
150
|
+
return createRateLimiter({ ratePerSec, burst, idleEvictMs: MINUTE_MS, maxKeys: LIMITER_MAX_KEYS });
|
|
142
151
|
}
|
|
143
152
|
function bootRateLimiter(perAddress) {
|
|
144
153
|
if (perAddress === 'off')
|
|
145
154
|
return undefined;
|
|
146
155
|
if (perAddress !== undefined)
|
|
147
156
|
return limiterFor(perAddress);
|
|
148
|
-
// Per-IP rate limiter for /v1/* and /mcp*, built here (not at module scope) so HIPPO_V1_RPS is read at boot and a
|
|
149
|
-
//
|
|
150
|
-
|
|
151
|
-
|
|
157
|
+
// Per-IP rate limiter for /v1/* and /mcp*, built here (not at module scope) so HIPPO_V1_RPS is read at boot and a
|
|
158
|
+
// test can set it before serve().
|
|
159
|
+
// A typo must not switch the limit off, so only an explicit 0 does.
|
|
160
|
+
const raw = envV1Rps();
|
|
161
|
+
const v1Rps = raw === undefined ? 20 : Number(raw);
|
|
162
|
+
if (!Number.isFinite(v1Rps) || v1Rps < 0) {
|
|
163
|
+
throw new Error(`HIPPO_V1_RPS must be a number of at least 0 (0 turns the per-address limit off), not '${raw}'`);
|
|
164
|
+
}
|
|
165
|
+
return v1Rps > 0 ? limiterFor({ ratePerSec: v1Rps, burst: v1Rps * 2 }) : undefined;
|
|
152
166
|
}
|
|
153
167
|
const DEFAULT_FAILED_AUTH = { ratePerSec: 20, burst: 40 };
|
|
154
168
|
function assertRateLimitSpec(name, { ratePerSec, burst }) {
|
|
155
|
-
if (!Number.isFinite(ratePerSec) || ratePerSec <= 0)
|
|
169
|
+
if (!Number.isFinite(ratePerSec) || ratePerSec <= 0) {
|
|
156
170
|
throw new Error(`rateLimits.${name}.ratePerSec must be a finite number above 0`);
|
|
157
|
-
|
|
171
|
+
}
|
|
172
|
+
if (!Number.isFinite(burst) || burst < 1) {
|
|
158
173
|
throw new Error(`rateLimits.${name}.burst must be a finite number of at least 1`);
|
|
174
|
+
}
|
|
159
175
|
}
|
|
160
176
|
const DEFAULT_CALLER_RPS = 20;
|
|
161
|
-
/**
|
|
177
|
+
/**
|
|
178
|
+
* The per-caller spec when serve() names none: HIPPO_CALLER_RPS (0 is off), else 20 per second with a burst of twice
|
|
179
|
+
* that.
|
|
180
|
+
*/
|
|
162
181
|
function defaultCallerSpec() {
|
|
163
182
|
const raw = envCallerRps();
|
|
164
183
|
const rps = raw === undefined ? DEFAULT_CALLER_RPS : Number(raw);
|
|
165
184
|
// A typo must not switch the limit off, so only an explicit 0 does.
|
|
166
|
-
if (!Number.isFinite(rps) || rps < 0)
|
|
185
|
+
if (!Number.isFinite(rps) || rps < 0) {
|
|
167
186
|
throw new Error(`HIPPO_CALLER_RPS must be a number of at least 0 (0 turns the per-caller limit off), not '${raw}'`);
|
|
187
|
+
}
|
|
168
188
|
return rps === 0 ? 'off' : { ratePerSec: rps, burst: Math.max(1, rps * 2) };
|
|
169
189
|
}
|
|
170
190
|
/** Refuses a bad spec at boot, since a NaN or zero rate would otherwise turn a bucket off or refuse every request. */
|
|
@@ -182,17 +202,6 @@ function bootLimiters(rateLimits) {
|
|
|
182
202
|
failedAuthLimiter: limiterFor(failedAuthPerAddress),
|
|
183
203
|
};
|
|
184
204
|
}
|
|
185
|
-
function createStoreHolder(hippoRoot, store) {
|
|
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) };
|
|
191
|
-
}
|
|
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.
|
|
193
|
-
function outsideRouteBlock(resolver) {
|
|
194
|
-
return resolver && ((token) => outsideSqliteOffLoop(() => resolver(token)));
|
|
195
|
-
}
|
|
196
205
|
function replyWithFailure(req, res, err, requestId) {
|
|
197
206
|
const mapped = replyFor(err);
|
|
198
207
|
logRequestFailure(req, err, mapped.status);
|
|
@@ -203,10 +212,12 @@ function replyWithFailure(req, res, err, requestId) {
|
|
|
203
212
|
catch { /* socket already gone */ }
|
|
204
213
|
return;
|
|
205
214
|
}
|
|
206
|
-
if (isStoreBusy(err))
|
|
215
|
+
if (isStoreBusy(err)) {
|
|
207
216
|
res.setHeader('Retry-After', '1');
|
|
208
|
-
|
|
217
|
+
}
|
|
218
|
+
else if (err instanceof HttpError && err.retryAfterSec !== undefined) {
|
|
209
219
|
res.setHeader('Retry-After', String(err.retryAfterSec));
|
|
220
|
+
}
|
|
210
221
|
if (mapped.status === 500) {
|
|
211
222
|
// The id lets an operator find the logged cause without the client seeing internal text.
|
|
212
223
|
sendJson(res, 500, { error: mapped.message, requestId });
|
|
@@ -221,29 +232,43 @@ function replyWithFailure(req, res, err, requestId) {
|
|
|
221
232
|
sendJson(res, 504, { error: err.message, code: err.code, requestId });
|
|
222
233
|
return;
|
|
223
234
|
}
|
|
224
|
-
// readBody hit its cap or deadline, so close once the 413 or 408 is out rather than drain what the client keeps
|
|
225
|
-
|
|
235
|
+
// readBody hit its cap or deadline, so close once the 413 or 408 is out rather than drain what the client keeps
|
|
236
|
+
// sending.
|
|
237
|
+
if (err instanceof BodyTooLargeError || err instanceof BodyTimeoutError) {
|
|
226
238
|
res.once('finish', () => closeAfterReply(req));
|
|
239
|
+
}
|
|
227
240
|
sendError(res, mapped.status, mapped.message);
|
|
228
241
|
}
|
|
229
242
|
const HANDLER_LATE = 'the request did not finish by its deadline and was abandoned; a write it started may or may not be saved';
|
|
230
|
-
// The caller already has its 504, so this line is the only trace of the failure. The path and the error text can hold
|
|
243
|
+
// The caller already has its 504, so this line is the only trace of the failure. The path and the error text can hold
|
|
244
|
+
// caller data, so it carries neither.
|
|
231
245
|
function logLateFailure(req, err, requestId) {
|
|
232
|
-
const fields = {
|
|
246
|
+
const fields = {
|
|
247
|
+
requestId,
|
|
248
|
+
method: req.method ?? 'GET',
|
|
249
|
+
route: accessRouteOf(req),
|
|
250
|
+
failureStatus: replyFor(err).status,
|
|
251
|
+
};
|
|
233
252
|
log.warn('request failed after its deadline reply', { ...fields, errorClass: errorFields(err).errorClass });
|
|
234
253
|
}
|
|
235
|
-
// A handler that ends after the 504 finds the response finished, so sending its own reply throws this: its work ran to
|
|
254
|
+
// A handler that ends after the 504 finds the response finished, so sending its own reply throws this: its work ran to
|
|
255
|
+
// the end.
|
|
236
256
|
function isDroppedLateReply(err) {
|
|
237
257
|
return err instanceof Error && 'code' in err && err.code === 'ERR_HTTP_HEADERS_SENT';
|
|
238
258
|
}
|
|
239
259
|
/** A GET only reads; every other method this server routes can write. */
|
|
240
260
|
const isRead = (method) => method === 'GET';
|
|
241
|
-
// A read that ends late changed nothing. A write that ends late ran to its end after its caller was told it may not
|
|
261
|
+
// A read that ends late changed nothing. A write that ends late ran to its end after its caller was told it may not
|
|
262
|
+
// have been saved.
|
|
242
263
|
function logLateFinish(req, requestId) {
|
|
243
264
|
const method = req.method ?? 'GET';
|
|
244
265
|
if (isRead(method))
|
|
245
266
|
return;
|
|
246
|
-
log.info('request finished after its deadline reply; its own reply was dropped', {
|
|
267
|
+
log.info('request finished after its deadline reply; its own reply was dropped', {
|
|
268
|
+
requestId,
|
|
269
|
+
method,
|
|
270
|
+
route: accessRouteOf(req),
|
|
271
|
+
});
|
|
247
272
|
}
|
|
248
273
|
function replyOrClose(req, res, err, requestId) {
|
|
249
274
|
try {
|
|
@@ -255,14 +280,19 @@ function replyOrClose(req, res, err, requestId) {
|
|
|
255
280
|
res.destroy();
|
|
256
281
|
}
|
|
257
282
|
}
|
|
258
|
-
/**
|
|
283
|
+
/**
|
|
284
|
+
* Runs `handle` under the request's id and deadline; a failure becomes the reply, unless the deadline has already
|
|
285
|
+
* answered.
|
|
286
|
+
*/
|
|
259
287
|
function answerRequest(req, res, handle, slowWarnMs) {
|
|
260
288
|
const requestId = openRequest(req, res, slowWarnMs);
|
|
261
289
|
const deadline = requestDeadlineFor(req);
|
|
290
|
+
const abort = deadline ? new AbortController() : undefined;
|
|
262
291
|
// Inside the scope, so the failure reply's log line carries the id too.
|
|
263
292
|
runWithRequestId(requestId, () => {
|
|
264
|
-
if (deadline)
|
|
265
|
-
answerAtDeadline(res, deadline, () => replyOrClose(req, res, new DeadlineExceededError(HANDLER_LATE), requestId));
|
|
293
|
+
if (deadline) {
|
|
294
|
+
answerAtDeadline(res, deadline, () => replyOrClose(req, res, new DeadlineExceededError(HANDLER_LATE), requestId), () => abort?.abort(new DeadlineExceededError(HANDLER_LATE)));
|
|
295
|
+
}
|
|
266
296
|
handle().then(() => {
|
|
267
297
|
if (isAbandoned(res))
|
|
268
298
|
logLateFinish(req, requestId);
|
|
@@ -274,7 +304,7 @@ function answerRequest(req, res, handle, slowWarnMs) {
|
|
|
274
304
|
else
|
|
275
305
|
logLateFailure(req, err, requestId);
|
|
276
306
|
});
|
|
277
|
-
}, deadline);
|
|
307
|
+
}, deadline, abort?.signal);
|
|
278
308
|
}
|
|
279
309
|
function listenOn(server, port, host) {
|
|
280
310
|
return new Promise((resolve, reject) => {
|
|
@@ -298,7 +328,9 @@ function exitOnSignalOrCrash(stop, drainMs) {
|
|
|
298
328
|
installSignalHandlers('serve', shutdown);
|
|
299
329
|
installCrashHandlers('serve', shutdown);
|
|
300
330
|
}
|
|
301
|
-
/**
|
|
331
|
+
/**
|
|
332
|
+
* Boots the HTTP daemon on host:port and writes the pidfile under hippoRoot; refuses a non-loopback host unless
|
|
333
|
+
* HIPPO_REQUIRE_AUTH=1 and
|
|
302
334
|
* either `tls` or allowCleartext is given, and refuses HIPPO_CLIENT_IP_HEADER without HIPPO_TRUSTED_PROXIES.
|
|
303
335
|
* Use port: 0 in tests for an ephemeral port. See docs/ARCHITECTURE.md#srcserverbootts. */
|
|
304
336
|
export async function serve(opts) {
|
|
@@ -310,7 +342,8 @@ export async function serve(opts) {
|
|
|
310
342
|
assertBindable(host);
|
|
311
343
|
assertTlsOrCleartextAllowed(host, opts.tls, LOOPBACK_HOSTS, opts.allowCleartext ?? envAllowCleartext());
|
|
312
344
|
await assertNoLiveServer(opts.hippoRoot);
|
|
313
|
-
// Single source of truth for the start time: returned by GET /health and written into the pidfile, so detectServer
|
|
345
|
+
// Single source of truth for the start time: returned by GET /health and written into the pidfile, so detectServer
|
|
346
|
+
// can prove a pid-reusing impostor is not
|
|
314
347
|
// this server.
|
|
315
348
|
const startedAt = new Date().toISOString();
|
|
316
349
|
// Open /mcp/stream count per client key, so the cap is per server rather than per process.
|
|
@@ -343,15 +376,20 @@ export async function serve(opts) {
|
|
|
343
376
|
}
|
|
344
377
|
function frozenAddonRoutes(addonRoutes) {
|
|
345
378
|
// A frozen copy, so a route the caller adds or renames after boot never skips the check below.
|
|
346
|
-
const routes = Object.freeze((addonRoutes ?? []).map(({ path, handler, storeReady }) => Object.freeze(storeReady === undefined
|
|
347
|
-
? { path, handler }
|
|
348
|
-
: { path, handler, storeReady })));
|
|
379
|
+
const routes = Object.freeze((addonRoutes ?? []).map(({ path, handler, storeReady }) => Object.freeze(storeReady === undefined ? { path, handler } : { path, handler, storeReady })));
|
|
349
380
|
assertAddonRoutes(routes);
|
|
350
381
|
return routes;
|
|
351
382
|
}
|
|
352
383
|
function servedOptsFor(opts, routes, publicJsonBodies, { callerLimiter, failedAuthLimiter }) {
|
|
384
|
+
const store = opts.store ?? workerSqliteStore(opts.hippoRoot);
|
|
353
385
|
return {
|
|
354
|
-
...opts,
|
|
386
|
+
...opts,
|
|
387
|
+
routes,
|
|
388
|
+
publicJsonBodies,
|
|
389
|
+
store,
|
|
390
|
+
offLoop: offLoopFor(store),
|
|
391
|
+
callerLimiter,
|
|
392
|
+
failedAuthLimiter,
|
|
355
393
|
authResolver: outsideRouteBlock(opts.authResolver),
|
|
356
394
|
};
|
|
357
395
|
}
|
|
@@ -375,7 +413,8 @@ async function listenAndDescribe(server, port, host, tls) {
|
|
|
375
413
|
return { port: actualPort, url };
|
|
376
414
|
}
|
|
377
415
|
async function stopListening(opts, server, inflight, startedAt) {
|
|
378
|
-
// Remove the pidfile only if it still names this server: a newer server may have rewritten it, and an unconditional
|
|
416
|
+
// Remove the pidfile only if it still names this server: a newer server may have rewritten it, and an unconditional
|
|
417
|
+
// unlink would orphan it.
|
|
379
418
|
removePidfileIfOwned(opts.hippoRoot, { pid: process.pid, startedAt });
|
|
380
419
|
await drainAndClose(server, inflight, opts.shutdownDrainMs ?? DEFAULT_SHUTDOWN_DRAIN_MS);
|
|
381
420
|
}
|
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
import type { IncomingMessage } from 'node:http';
|
|
2
2
|
import type { RateLimiter } from './rate-limit.js';
|
|
3
3
|
/**
|
|
4
|
-
* Rate-limit key: the socket's remote address, which behind a TLS proxy collapses into one bucket unauthenticated
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* Rate-limit key: the socket's remote address, which behind a TLS proxy collapses into one bucket unauthenticated
|
|
5
|
+
* traffic can drain.
|
|
6
|
+
* HIPPO_CLIENT_IP_HEADER (fly-client-ip on Fly) is read only from a peer in HIPPO_TRUSTED_PROXIES (IPs or CIDRs, or `*`
|
|
7
|
+
* for any peer),
|
|
8
|
+
* so a caller that reaches the port past the proxy cannot pick its own bucket. In a comma-joined chain the key is the
|
|
9
|
+
* rightmost hop no trusted proxy added.
|
|
10
|
+
*/
|
|
7
11
|
export declare function clientIpForRateLimit(req: IncomingMessage): string;
|
|
8
|
-
/**
|
|
12
|
+
/**
|
|
13
|
+
* serve() refused HIPPO_CLIENT_IP_HEADER with no HIPPO_TRUSTED_PROXIES: the header would be read from no one, so the
|
|
14
|
+
* setting is a mistake.
|
|
15
|
+
*/
|
|
9
16
|
export declare class UntrustedClientIpHeaderError extends Error {
|
|
10
17
|
readonly header: string;
|
|
11
18
|
constructor(header: string);
|
package/dist/server/client-ip.js
CHANGED
|
@@ -5,9 +5,13 @@ import { log } from '../util/log.js';
|
|
|
5
5
|
import { HttpError } from '../util/http-util.js';
|
|
6
6
|
const IPV6_PREFIX_GROUPS = 4;
|
|
7
7
|
/**
|
|
8
|
-
* Rate-limit key: the socket's remote address, which behind a TLS proxy collapses into one bucket unauthenticated
|
|
9
|
-
*
|
|
10
|
-
*
|
|
8
|
+
* Rate-limit key: the socket's remote address, which behind a TLS proxy collapses into one bucket unauthenticated
|
|
9
|
+
* traffic can drain.
|
|
10
|
+
* HIPPO_CLIENT_IP_HEADER (fly-client-ip on Fly) is read only from a peer in HIPPO_TRUSTED_PROXIES (IPs or CIDRs, or `*`
|
|
11
|
+
* for any peer),
|
|
12
|
+
* so a caller that reaches the port past the proxy cannot pick its own bucket. In a comma-joined chain the key is the
|
|
13
|
+
* rightmost hop no trusted proxy added.
|
|
14
|
+
*/
|
|
11
15
|
export function clientIpForRateLimit(req) {
|
|
12
16
|
const socketIp = req.socket.remoteAddress ?? 'unknown';
|
|
13
17
|
const header = envClientIpHeader();
|
|
@@ -57,12 +61,17 @@ function proxyTrust(raw) {
|
|
|
57
61
|
trustedProxyCache = { raw: value, list };
|
|
58
62
|
return list;
|
|
59
63
|
}
|
|
60
|
-
/**
|
|
64
|
+
/**
|
|
65
|
+
* serve() refused HIPPO_CLIENT_IP_HEADER with no HIPPO_TRUSTED_PROXIES: the header would be read from no one, so the
|
|
66
|
+
* setting is a mistake.
|
|
67
|
+
*/
|
|
61
68
|
export class UntrustedClientIpHeaderError extends Error {
|
|
62
69
|
header;
|
|
63
70
|
constructor(header) {
|
|
64
|
-
super(`hippo serve: HIPPO_CLIENT_IP_HEADER is ${header} but HIPPO_TRUSTED_PROXIES is unset, so no peer may set that
|
|
65
|
-
|
|
71
|
+
super(`hippo serve: HIPPO_CLIENT_IP_HEADER is ${header} but HIPPO_TRUSTED_PROXIES is unset, so no peer may set that ` +
|
|
72
|
+
`header. ` +
|
|
73
|
+
"Set HIPPO_TRUSTED_PROXIES to the proxy's addresses or CIDRs, or to * when the proxy is the only peer that " +
|
|
74
|
+
"can reach this port.");
|
|
66
75
|
this.header = header;
|
|
67
76
|
this.name = 'UntrustedClientIpHeaderError';
|
|
68
77
|
}
|
|
@@ -76,7 +85,10 @@ export function assertClientIpHeaderPinned() {
|
|
|
76
85
|
if (trust === undefined)
|
|
77
86
|
throw new UntrustedClientIpHeaderError(header);
|
|
78
87
|
if (trust === ANY_PEER) {
|
|
79
|
-
log.warn(`serve: HIPPO_TRUSTED_PROXIES is *, so ${header} is read from any peer
|
|
88
|
+
log.warn(`serve: HIPPO_TRUSTED_PROXIES is *, so ${header} is read from any peer: a client that reaches this port ` +
|
|
89
|
+
`without the proxy can put any address ` +
|
|
90
|
+
`in ${header} and so escape every per-address limit. Keep the proxy the only route to this port, or list the ` +
|
|
91
|
+
`proxy's addresses instead of *.`);
|
|
80
92
|
}
|
|
81
93
|
}
|
|
82
94
|
/** The key for one subscriber: an IPv6 address's /64, since one host may hold the whole /64; any other key as is. */
|
|
@@ -92,7 +104,10 @@ function subscriberKey(ip) {
|
|
|
92
104
|
// A trailing dotted quad holds two groups; isIP has already checked the shape.
|
|
93
105
|
const rightGroups = right.length + (right.at(-1)?.includes('.') ? 1 : 0);
|
|
94
106
|
const groups = tail === undefined ? left : [...left, ...Array(8 - left.length - rightGroups).fill('0'), ...right];
|
|
95
|
-
return `${groups
|
|
107
|
+
return `${groups
|
|
108
|
+
.slice(0, IPV6_PREFIX_GROUPS)
|
|
109
|
+
.map((g) => parseInt(g, 16).toString(16))
|
|
110
|
+
.join(':')}::/64`;
|
|
96
111
|
}
|
|
97
112
|
/** The one key every per-address limit and slot count uses, so rotating inside a /64 never buys a fresh bucket. */
|
|
98
113
|
export function clientLimitKey(req) {
|
|
@@ -104,8 +119,10 @@ function isTrustedProxy(list, ip) {
|
|
|
104
119
|
return family !== 0 && list.check(bare, family === 6 ? 'ipv6' : 'ipv4');
|
|
105
120
|
}
|
|
106
121
|
export function enforceRateLimit(req, path, limiter) {
|
|
107
|
-
// Per-IP rate limit on /v1/* and /mcp* to bound api-key-id enumeration; /health and other paths are never throttled,
|
|
108
|
-
//
|
|
122
|
+
// Per-IP rate limit on /v1/* and /mcp* to bound api-key-id enumeration; /health and other paths are never throttled,
|
|
123
|
+
// and a 429 lands in the createServer
|
|
124
|
+
// catch. Keyed per clientIpForRateLimit (set HIPPO_CLIENT_IP_HEADER behind a TLS-terminating proxy, or all clients
|
|
125
|
+
// share one bucket).
|
|
109
126
|
if (limiter && (path.startsWith('/v1/') || path === '/mcp' || path === '/mcp/stream')) {
|
|
110
127
|
if (!limiter.check(clientLimitKey(req))) {
|
|
111
128
|
throw new HttpError(429, 'rate limit exceeded', limiter.retryAfterSec);
|