hippo-memory 1.70.0 → 1.72.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 +2 -2
- package/dist/agent-memories/apply.d.ts +0 -11
- package/dist/agent-memories/apply.js +6 -21
- package/dist/agent-memories/claude-code.d.ts +4 -2
- package/dist/agent-memories/claude-code.js +15 -6
- 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/files.js +23 -12
- package/dist/agent-memories/markdown.d.ts +1 -3
- package/dist/agent-memories/markdown.js +1 -3
- package/dist/agent-memories/project-folds.d.ts +10 -0
- package/dist/agent-memories/project-folds.js +34 -0
- package/dist/agent-memories/report.js +2 -1
- package/dist/agent-memories/sync.d.ts +4 -2
- package/dist/agent-memories/sync.js +18 -11
- package/dist/api/assemble.d.ts +7 -44
- package/dist/api/assemble.js +3 -23
- package/dist/api/audit.d.ts +33 -1
- package/dist/api/audit.js +48 -1
- package/dist/api/auth.d.ts +20 -26
- package/dist/api/auth.js +43 -29
- package/dist/api/auto-sleep.d.ts +5 -2
- package/dist/api/auto-sleep.js +9 -5
- package/dist/api/availability.d.ts +2 -15
- package/dist/api/availability.js +4 -18
- 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-render.js +4 -3
- package/dist/api/context-select.js +12 -15
- package/dist/api/context-types.d.ts +10 -35
- package/dist/api/context.d.ts +5 -22
- package/dist/api/context.js +38 -46
- package/dist/api/continuity.d.ts +47 -0
- package/dist/api/continuity.js +66 -0
- package/dist/{cli → api}/correction-latency.d.ts +2 -14
- package/dist/{cli → api}/correction-latency.js +2 -14
- package/dist/api/dormant.d.ts +5 -21
- package/dist/api/dormant.js +11 -28
- package/dist/api/drill-down.d.ts +7 -46
- package/dist/api/drill-down.js +6 -27
- 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 +11 -26
- package/dist/api/forget.js +23 -35
- package/dist/api/goals.d.ts +1 -1
- package/dist/api/goals.js +5 -9
- package/dist/api/graph.d.ts +8 -0
- package/dist/api/graph.js +7 -0
- package/dist/api/index.d.ts +6 -2
- package/dist/api/index.js +6 -2
- package/dist/api/instruction-detect.js +21 -6
- package/dist/api/learn.d.ts +4 -0
- package/dist/api/learn.js +53 -27
- package/dist/api/ledger-db.d.ts +2 -5
- package/dist/api/ledger-db.js +5 -35
- package/dist/api/memories.d.ts +23 -0
- package/dist/api/memories.js +46 -0
- package/dist/api/objects.d.ts +9 -0
- package/dist/api/objects.js +11 -0
- package/dist/api/on-store.js +5 -3
- package/dist/api/outcome.js +1 -1
- package/dist/api/pilot-arm.d.ts +1 -11
- package/dist/api/pilot-arm.js +5 -45
- package/dist/api/predictions.d.ts +11 -0
- package/dist/api/predictions.js +24 -0
- package/dist/api/projects.d.ts +21 -0
- package/dist/api/projects.js +24 -0
- package/dist/api/promote.d.ts +13 -17
- package/dist/api/promote.js +12 -20
- package/dist/api/prompt-hook.d.ts +19 -6
- package/dist/api/prompt-hook.js +54 -13
- package/dist/api/provenance-coverage.d.ts +14 -0
- package/dist/{cli → api}/provenance-coverage.js +2 -6
- package/dist/api/recall-cli.d.ts +58 -0
- package/dist/api/recall-cli.js +103 -0
- package/dist/api/recall-core.js +17 -9
- package/dist/api/recall-finish.d.ts +53 -0
- package/dist/api/recall-finish.js +30 -0
- package/dist/api/recall-history.d.ts +17 -84
- package/dist/api/recall-history.js +15 -88
- package/dist/api/recall-pipeline.d.ts +2 -3
- package/dist/api/recall-pipeline.js +21 -15
- package/dist/api/recall-request.js +1 -1
- package/dist/api/recall-types.d.ts +64 -304
- package/dist/api/recall.d.ts +3 -34
- package/dist/api/recall.js +63 -89
- package/dist/api/refine.d.ts +7 -0
- package/dist/api/refine.js +10 -0
- package/dist/api/remember-local.d.ts +57 -0
- package/dist/api/remember-local.js +90 -0
- package/dist/api/remember.d.ts +20 -2
- package/dist/api/remember.js +16 -3
- package/dist/api/session-end.d.ts +22 -0
- package/dist/api/session-end.js +101 -0
- package/dist/api/sleep-run.d.ts +2 -4
- package/dist/api/sleep-run.js +28 -28
- package/dist/api/sleep.d.ts +9 -28
- 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.d.ts +3 -10
- package/dist/api/tokens.js +4 -11
- package/dist/api/types.d.ts +8 -29
- package/dist/api/types.js +10 -23
- 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.d.ts +4 -12
- package/dist/capture/command.js +39 -114
- package/dist/capture/compact.d.ts +4 -15
- package/dist/capture/compact.js +26 -30
- package/dist/capture/compaction-items-caller.js +11 -20
- package/dist/capture/compaction-record.d.ts +7 -93
- package/dist/capture/compaction-record.js +34 -399
- package/dist/capture/compaction-spool.d.ts +5 -3
- package/dist/capture/compaction-spool.js +21 -7
- 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.d.ts +1 -1
- package/dist/capture/session-digest.js +17 -10
- package/dist/capture/session-end-caller.js +2 -1
- package/dist/capture/session-worker.js +3 -4
- package/dist/capture/transcript.d.ts +4 -11
- package/dist/capture/transcript.js +10 -21
- package/dist/capture/working-state.d.ts +4 -2
- package/dist/capture/working-state.js +4 -2
- package/dist/cli/api-context.d.ts +3 -0
- package/dist/cli/api-context.js +6 -0
- package/dist/cli/audit-prune.d.ts +1 -59
- package/dist/cli/audit-prune.js +2 -61
- package/dist/cli/audit.d.ts +1 -1
- package/dist/cli/audit.js +42 -43
- package/dist/cli/auth.d.ts +2 -2
- package/dist/cli/auth.js +61 -44
- package/dist/cli/briefs.d.ts +1 -4
- package/dist/cli/briefs.js +42 -301
- package/dist/cli/card.d.ts +2 -2
- package/dist/cli/card.js +63 -56
- package/dist/cli/client.d.ts +12 -27
- package/dist/cli/client.js +41 -44
- package/dist/cli/compact-resume-payload.js +4 -3
- package/dist/cli/context.d.ts +2 -3
- package/dist/cli/context.js +22 -18
- package/dist/cli/continuity.d.ts +6 -6
- package/dist/cli/continuity.js +81 -86
- package/dist/cli/curate.d.ts +13 -17
- package/dist/cli/curate.js +88 -116
- package/dist/cli/dag.d.ts +4 -4
- package/dist/cli/dag.js +55 -34
- package/dist/cli/decisions.d.ts +2 -4
- package/dist/cli/decisions.js +18 -309
- package/dist/cli/eval.d.ts +1 -1
- package/dist/cli/eval.js +27 -26
- package/dist/cli/exit.d.ts +6 -0
- package/dist/cli/exit.js +11 -0
- package/dist/cli/explain.d.ts +2 -3
- package/dist/cli/explain.js +25 -27
- package/dist/cli/flag-values.d.ts +6 -1
- package/dist/cli/flag-values.js +42 -15
- package/dist/cli/flags.d.ts +0 -288
- package/dist/cli/flags.js +3 -138
- package/dist/cli/github.d.ts +14 -0
- package/dist/{connectors/github/cli-impl.js → cli/github.js} +43 -71
- package/dist/cli/goals.d.ts +2 -2
- package/dist/cli/goals.js +46 -50
- package/dist/cli/graph.d.ts +3 -0
- package/dist/cli/graph.js +83 -0
- package/dist/cli/hook-runtime.d.ts +12 -32
- package/dist/cli/hook-runtime.js +21 -64
- package/dist/cli/incidents.d.ts +3 -0
- package/dist/cli/incidents.js +112 -0
- package/dist/cli/init.d.ts +2 -2
- package/dist/cli/init.js +33 -30
- package/dist/cli/install-steps.d.ts +2 -1
- package/dist/cli/install-steps.js +13 -14
- package/dist/cli/last-sleep.d.ts +2 -1
- package/dist/cli/last-sleep.js +4 -1
- package/dist/cli/lenient-id.d.ts +2 -0
- package/dist/cli/lenient-id.js +13 -0
- package/dist/cli/maintenance.d.ts +5 -5
- package/dist/cli/maintenance.js +37 -43
- package/dist/cli/notes.d.ts +2 -0
- package/dist/cli/notes.js +41 -0
- package/dist/cli/object-verbs.js +4 -3
- package/dist/cli/open-browser.d.ts +14 -0
- package/dist/cli/open-browser.js +26 -0
- package/dist/cli/owner-validation.d.ts +5 -28
- package/dist/cli/owner-validation.js +5 -28
- package/dist/cli/playbooks.d.ts +3 -4
- package/dist/cli/playbooks.js +131 -300
- package/dist/cli/predictions.d.ts +3 -0
- package/dist/cli/predictions.js +175 -0
- package/dist/cli/print.d.ts +2 -5
- package/dist/cli/print.js +3 -5
- package/dist/cli/projects.d.ts +2 -2
- package/dist/cli/projects.js +31 -25
- package/dist/cli/quality-repair-once.d.ts +1 -1
- package/dist/cli/quality-repair-once.js +7 -6
- package/dist/cli/recall.d.ts +2 -4
- package/dist/cli/recall.js +67 -137
- package/dist/cli/refine-llm.d.ts +5 -31
- package/dist/cli/refine-llm.js +23 -50
- package/dist/cli/remember.d.ts +3 -3
- package/dist/cli/remember.js +134 -192
- package/dist/cli/scheduler.d.ts +2 -17
- package/dist/cli/scheduler.js +14 -19
- package/dist/cli/serve.js +23 -14
- package/dist/cli/session-hooks.d.ts +11 -19
- package/dist/cli/session-hooks.js +143 -214
- package/dist/cli/setup.d.ts +4 -4
- package/dist/cli/setup.js +35 -30
- package/dist/cli/shared.d.ts +7 -25
- package/dist/cli/shared.js +17 -60
- package/dist/cli/slack.d.ts +2 -2
- package/dist/cli/slack.js +19 -23
- package/dist/cli/sleep-render.js +6 -3
- package/dist/cli/sleep.d.ts +3 -2
- package/dist/cli/sleep.js +17 -49
- package/dist/cli/status.d.ts +11 -14
- package/dist/cli/status.js +74 -120
- package/dist/cli/stdin.d.ts +4 -6
- package/dist/cli/stdin.js +2 -3
- package/dist/cli/transfer.d.ts +9 -9
- package/dist/cli/transfer.js +87 -108
- package/dist/cli/usage.d.ts +0 -79
- package/dist/cli/usage.js +1 -689
- package/dist/cli/verb-row.d.ts +32 -0
- package/dist/cli/verb-row.js +6 -0
- package/dist/cli/verbs/health.d.ts +27 -0
- package/dist/cli/verbs/health.js +232 -0
- package/dist/cli/verbs/memory.d.ts +16 -0
- package/dist/cli/verbs/memory.js +244 -0
- package/dist/cli/verbs/objects.d.ts +20 -0
- package/dist/cli/verbs/objects.js +254 -0
- package/dist/cli/verbs/sessions.d.ts +31 -0
- package/dist/cli/verbs/sessions.js +312 -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 -654
- package/dist/cli.js +44 -510
- package/dist/connectors/dlq.d.ts +39 -3
- package/dist/connectors/dlq.js +37 -3
- package/dist/connectors/github/backfill.d.ts +5 -25
- package/dist/connectors/github/backfill.js +26 -52
- package/dist/connectors/github/deletion.d.ts +4 -18
- package/dist/connectors/github/deletion.js +2 -15
- package/dist/connectors/github/dlq.d.ts +8 -33
- package/dist/connectors/github/dlq.js +34 -93
- package/dist/connectors/github/ingest.d.ts +4 -12
- package/dist/connectors/github/ingest.js +5 -36
- package/dist/connectors/github/octokit-client.d.ts +4 -16
- package/dist/connectors/github/octokit-client.js +27 -24
- package/dist/connectors/github/ratelimit.d.ts +3 -14
- package/dist/connectors/github/ratelimit.js +3 -14
- package/dist/connectors/github/scope.d.ts +3 -5
- package/dist/connectors/github/scope.js +3 -5
- package/dist/connectors/github/signature.d.ts +4 -26
- package/dist/connectors/github/signature.js +4 -26
- package/dist/connectors/github/tenant-routing.d.ts +2 -24
- package/dist/connectors/github/tenant-routing.js +4 -26
- package/dist/connectors/github/transform.js +2 -16
- package/dist/connectors/github/types.d.ts +3 -15
- package/dist/connectors/github/types.js +2 -9
- package/dist/connectors/github/webhook.d.ts +3 -16
- package/dist/connectors/github/webhook.js +38 -23
- package/dist/connectors/ingest.d.ts +10 -0
- package/dist/connectors/ingest.js +28 -0
- package/dist/connectors/slack/backfill.d.ts +4 -17
- package/dist/connectors/slack/backfill.js +4 -13
- package/dist/connectors/slack/dlq.d.ts +2 -19
- package/dist/connectors/slack/dlq.js +51 -90
- package/dist/connectors/slack/ingest.d.ts +4 -9
- package/dist/connectors/slack/ingest.js +4 -30
- package/dist/connectors/slack/scope.d.ts +2 -8
- package/dist/connectors/slack/scope.js +2 -8
- package/dist/connectors/slack/signature.d.ts +1 -6
- package/dist/connectors/slack/tenant-routing.d.ts +2 -19
- package/dist/connectors/slack/tenant-routing.js +2 -21
- package/dist/connectors/slack/transform.d.ts +2 -18
- package/dist/connectors/slack/transform.js +2 -18
- package/dist/connectors/slack/types.d.ts +3 -9
- package/dist/connectors/slack/types.js +2 -4
- package/dist/connectors/slack/web-client.js +33 -27
- package/dist/connectors/slack/webhook.d.ts +3 -19
- package/dist/connectors/slack/webhook.js +6 -26
- package/dist/connectors/slack/workspaces.d.ts +4 -24
- package/dist/connectors/slack/workspaces.js +4 -24
- package/dist/consolidate/conflicts.js +7 -15
- package/dist/consolidate/dag-summary.d.ts +8 -0
- package/dist/consolidate/dag-summary.js +41 -0
- package/dist/consolidate/dag.d.ts +5 -28
- package/dist/consolidate/dag.js +29 -84
- package/dist/consolidate/decay.js +7 -19
- package/dist/consolidate/dedupe.d.ts +13 -52
- package/dist/consolidate/dedupe.js +18 -74
- package/dist/consolidate/flush-units.d.ts +3 -4
- package/dist/consolidate/flush-units.js +3 -3
- package/dist/consolidate/half-life-migration.d.ts +3 -26
- package/dist/consolidate/half-life-migration.js +11 -28
- package/dist/consolidate/llm-passes.js +49 -40
- package/dist/consolidate/memory-value-weights.d.ts +2 -13
- package/dist/consolidate/memory-value-weights.js +2 -13
- package/dist/consolidate/memory-value.d.ts +11 -84
- package/dist/consolidate/memory-value.js +18 -105
- package/dist/consolidate/merge.js +12 -33
- package/dist/consolidate/physics-pass.d.ts +6 -1
- package/dist/consolidate/physics-pass.js +27 -9
- package/dist/consolidate/replay.d.ts +6 -38
- package/dist/consolidate/replay.js +25 -56
- package/dist/consolidate/run.js +1 -1
- package/dist/consolidate/sleep.d.ts +1 -8
- package/dist/consolidate/sleep.js +13 -22
- package/dist/consolidate/trace.d.ts +3 -18
- package/dist/consolidate/trace.js +3 -18
- package/dist/consolidate/traces.js +9 -25
- package/dist/core/ablation.d.ts +14 -91
- package/dist/core/ablation.js +16 -91
- package/dist/core/active-scope.d.ts +7 -0
- package/dist/{sharing/scope.js → core/active-scope.js} +5 -12
- package/dist/core/ambient.d.ts +5 -8
- package/dist/core/ambient.js +40 -26
- package/dist/core/api-errors.d.ts +16 -0
- package/dist/core/api-errors.js +20 -0
- package/dist/core/capture-contract.d.ts +4 -2
- package/dist/core/capture-contract.js +4 -2
- package/dist/core/card.d.ts +4 -1
- package/dist/core/card.js +11 -1
- package/dist/core/compaction-timing.d.ts +7 -0
- package/dist/core/compaction-timing.js +9 -0
- package/dist/core/compare.d.ts +11 -67
- package/dist/core/compare.js +9 -63
- package/dist/core/config.d.ts +10 -24
- package/dist/core/config.js +20 -16
- package/dist/core/cosine.d.ts +3 -0
- package/dist/core/cosine.js +19 -0
- package/dist/core/handoff.d.ts +1 -7
- package/dist/core/handoff.js +1 -7
- package/dist/core/markdown.d.ts +6 -0
- package/dist/{store → core}/markdown.js +23 -22
- package/dist/core/memory-audit.d.ts +17 -0
- package/dist/core/memory-audit.js +54 -0
- package/dist/core/memory-quality.js +1 -1
- package/dist/core/memory.d.ts +51 -168
- package/dist/core/memory.js +76 -239
- package/dist/{consolidate → core}/merged-row.d.ts +1 -1
- package/dist/{consolidate → core}/merged-row.js +3 -2
- package/dist/core/package-root.d.ts +3 -0
- package/dist/core/package-root.js +5 -0
- package/dist/core/physics-config.d.ts +1 -4
- package/dist/core/physics-config.js +3 -8
- package/dist/core/physics.d.ts +15 -61
- package/dist/core/physics.js +65 -138
- package/dist/core/prediction.d.ts +3 -0
- package/dist/core/prediction.js +6 -0
- package/dist/core/project-identity.d.ts +20 -58
- package/dist/core/project-identity.js +27 -39
- package/dist/core/project-remote.js +13 -2
- package/dist/core/raw-append-only.d.ts +5 -0
- package/dist/core/raw-append-only.js +7 -0
- package/dist/core/recall-scope.d.ts +69 -0
- package/dist/core/recall-scope.js +138 -0
- package/dist/core/salience.d.ts +1 -7
- package/dist/core/salience.js +1 -7
- package/dist/dashboard/dashboard-actions.js +2 -2
- package/dist/dashboard/dashboard-snapshot.d.ts +2 -1
- package/dist/dashboard/dashboard-snapshot.js +11 -2
- package/dist/dashboard/dashboard-types.d.ts +2 -1
- package/dist/dashboard/dashboard.d.ts +1 -0
- package/dist/dashboard/dashboard.js +50 -4
- package/dist/db/busy.d.ts +3 -8
- package/dist/db/busy.js +37 -33
- package/dist/db/connect.js +7 -8
- package/dist/db/index.d.ts +3 -3
- package/dist/db/index.js +3 -3
- package/dist/db/migrate.js +3 -3
- 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 -5
- package/dist/db/migrations/v14.js +2 -3
- package/dist/db/migrations/v15.js +2 -8
- package/dist/db/migrations/v16.js +2 -3
- package/dist/db/migrations/v17.js +2 -3
- package/dist/db/migrations/v19.js +2 -5
- package/dist/db/migrations/v20.js +2 -7
- package/dist/db/migrations/v22.js +4 -17
- package/dist/db/migrations/v23.js +3 -14
- package/dist/db/migrations/v24.js +2 -4
- package/dist/db/migrations/v25.js +3 -8
- package/dist/db/migrations/v26.js +2 -13
- package/dist/db/migrations/v27.js +3 -11
- package/dist/db/migrations/v28.js +2 -14
- package/dist/db/migrations/v29.js +4 -18
- package/dist/db/migrations/v30.js +4 -16
- package/dist/db/migrations/v31.js +2 -15
- package/dist/db/migrations/v32.js +4 -22
- package/dist/db/migrations/v33.js +2 -15
- package/dist/db/migrations/v34.js +2 -11
- package/dist/db/migrations/v35.js +2 -11
- package/dist/db/migrations/v36.js +2 -11
- package/dist/db/migrations/v37.js +8 -33
- package/dist/db/migrations/v38.js +5 -38
- package/dist/db/migrations/v39.js +9 -20
- package/dist/db/migrations/v40.js +2 -9
- package/dist/db/migrations/v41.js +2 -24
- package/dist/db/migrations/v43.js +1 -1
- package/dist/db/migrations/v44.js +2 -8
- package/dist/db/migrations/v45.js +2 -7
- package/dist/db/migrations/v47.js +2 -3
- package/dist/db/migrations/v51.js +1 -1
- package/dist/db/migrations/v55.d.ts +3 -0
- package/dist/db/migrations/v55.js +17 -0
- package/dist/db/open.d.ts +2 -2
- package/dist/db/open.js +21 -9
- package/dist/db/physics-state.d.ts +6 -22
- package/dist/db/physics-state.js +28 -39
- package/dist/db/raw-archive-mirror-cleanup.d.ts +2 -17
- package/dist/db/raw-archive-mirror-cleanup.js +2 -17
- package/dist/db/tables.d.ts +2 -0
- package/dist/db/tables.js +6 -2
- package/dist/db/vector-store.d.ts +2 -0
- package/dist/db/vector-store.js +25 -5
- package/dist/db/wal-checkpointer.js +2 -1
- package/dist/doctor.js +85 -27
- package/dist/embeddings/local.d.ts +62 -0
- package/dist/embeddings/local.js +146 -0
- package/dist/embeddings/provider.d.ts +43 -0
- package/dist/{store/embeddings → embeddings}/provider.js +58 -83
- 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 +3 -2
- package/dist/eval/eval-stats.d.ts +15 -53
- package/dist/eval/eval-stats.js +12 -42
- package/dist/eval/eval-suite.d.ts +2 -13
- package/dist/eval/eval-suite.js +91 -45
- package/dist/eval/eval.d.ts +6 -24
- package/dist/eval/eval.js +8 -35
- package/dist/eval/judgment.d.ts +0 -3
- package/dist/eval/judgment.js +30 -15
- package/dist/extensions/openclaw-plugin/index.js +1 -1
- package/dist/graph/extract.d.ts +5 -27
- package/dist/graph/extract.js +10 -36
- package/dist/graph/recall.d.ts +7 -20
- package/dist/graph/recall.js +15 -77
- package/dist/graph/stream.d.ts +7 -39
- package/dist/graph/stream.js +11 -34
- package/dist/graph/view.d.ts +9 -35
- package/dist/graph/view.js +24 -44
- 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 +4 -3
- package/dist/hooks/copilot.js +2 -1
- package/dist/hooks/hook-blocks.d.ts +6 -2
- package/dist/hooks/hook-blocks.js +37 -124
- package/dist/hooks/json-hooks.d.ts +4 -36
- package/dist/hooks/json-hooks.js +22 -59
- package/dist/hooks/opencode.d.ts +0 -38
- package/dist/hooks/opencode.js +17 -81
- package/dist/hooks/shared.d.ts +6 -21
- package/dist/hooks/shared.js +31 -33
- package/dist/importers/core.d.ts +12 -37
- package/dist/importers/core.js +10 -28
- package/dist/importers/markdown-parse.d.ts +8 -22
- package/dist/importers/markdown-parse.js +8 -25
- package/dist/importers/markdown.js +3 -12
- package/dist/importers/sources.js +12 -39
- package/dist/importers/vault.d.ts +2 -8
- package/dist/importers/vault.js +31 -85
- package/dist/index.d.ts +8 -3
- package/dist/index.js +8 -3
- package/dist/learn/autolearn.d.ts +23 -42
- package/dist/learn/autolearn.js +45 -52
- package/dist/learn/churn-git.js +13 -4
- package/dist/learn/extract.d.ts +3 -2
- package/dist/learn/extract.js +8 -8
- package/dist/learn/forward-claim-detector.d.ts +6 -30
- package/dist/learn/forward-claim-detector.js +18 -68
- package/dist/learn/invalidation.d.ts +6 -18
- package/dist/learn/invalidation.js +18 -31
- package/dist/mcp/admin-tools.d.ts +2 -2
- package/dist/mcp/admin-tools.js +30 -53
- 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.js +7 -10
- package/dist/mcp/protocol.d.ts +15 -29
- package/dist/mcp/protocol.js +26 -16
- package/dist/mcp/recall-tools.js +14 -11
- package/dist/mcp/request.d.ts +3 -11
- package/dist/mcp/request.js +12 -27
- package/dist/mcp/server.d.ts +3 -9
- package/dist/mcp/server.js +5 -16
- package/dist/mcp/session-state.d.ts +1 -1
- package/dist/mcp/session-state.js +5 -11
- package/dist/mcp/stdio.d.ts +2 -6
- package/dist/mcp/stdio.js +68 -16
- package/dist/mcp/tool-args.js +2 -1
- package/dist/mcp/tools.js +47 -22
- package/dist/objects/customer-notes.d.ts +9 -44
- package/dist/objects/customer-notes.js +7 -48
- package/dist/objects/decisions.d.ts +14 -52
- package/dist/objects/decisions.js +15 -53
- package/dist/objects/descriptor.d.ts +1 -1
- package/dist/objects/incidents.d.ts +9 -40
- package/dist/objects/incidents.js +7 -41
- package/dist/objects/lifecycle.d.ts +1 -1
- package/dist/objects/lifecycle.js +2 -1
- package/dist/objects/policies.d.ts +13 -91
- package/dist/objects/policies.js +13 -99
- package/dist/objects/processes.d.ts +9 -54
- package/dist/objects/processes.js +7 -61
- package/dist/objects/project-briefs.d.ts +13 -57
- package/dist/objects/project-briefs.js +16 -78
- package/dist/objects/skills.d.ts +9 -44
- package/dist/objects/skills.js +8 -54
- package/dist/postinstall.js +7 -20
- package/dist/predictions/planning-fallacy.d.ts +11 -34
- package/dist/rerankers/clef.js +6 -37
- package/dist/rerankers/cross-encoder.d.ts +31 -2
- package/dist/rerankers/cross-encoder.js +65 -101
- package/dist/rerankers/index.js +5 -4
- package/dist/rerankers/jev.js +11 -10
- package/dist/rerankers/llm.d.ts +2 -11
- package/dist/rerankers/llm.js +14 -14
- package/dist/rerankers/outage-warning.d.ts +5 -2
- package/dist/rerankers/outage-warning.js +7 -4
- package/dist/rerankers/remote.d.ts +1 -0
- package/dist/rerankers/remote.js +2 -0
- package/dist/rerankers/types.d.ts +2 -14
- package/dist/search/bm25-search.js +1 -1
- package/dist/search/boosts.d.ts +0 -2
- package/dist/search/boosts.js +3 -3
- package/dist/search/embed-memories.d.ts +9 -0
- package/dist/search/embed-memories.js +377 -0
- package/dist/search/goal-boost.d.ts +23 -0
- package/dist/search/goal-boost.js +93 -0
- package/dist/search/hybrid.d.ts +11 -2
- package/dist/search/hybrid.js +9 -4
- package/dist/search/multihop.js +2 -3
- package/dist/search/path-context.d.ts +5 -18
- package/dist/search/path-context.js +5 -18
- package/dist/search/physics-search.d.ts +6 -3
- package/dist/search/physics-search.js +29 -19
- package/dist/search/rerank.js +1 -1
- package/dist/search/rrf.d.ts +7 -35
- package/dist/search/rrf.js +5 -30
- package/dist/search/vector.d.ts +13 -4
- package/dist/search/vector.js +40 -13
- package/dist/server/auth.d.ts +11 -28
- package/dist/server/auth.js +49 -32
- package/dist/server/boot.d.ts +2 -21
- package/dist/server/boot.js +69 -161
- package/dist/server/client-ip.d.ts +3 -21
- package/dist/server/client-ip.js +8 -30
- package/dist/server/deadline.d.ts +0 -2
- package/dist/server/deadline.js +1 -7
- package/dist/server/defaults.d.ts +4 -0
- package/dist/server/defaults.js +5 -0
- package/dist/server/key-check-bounds.d.ts +2 -1
- package/dist/server/lifecycle.d.ts +5 -4
- package/dist/server/lifecycle.js +19 -4
- package/dist/server/mcp-http.js +24 -53
- package/dist/server/rate-limit.d.ts +5 -18
- package/dist/server/rate-limit.js +4 -13
- package/dist/server/request.d.ts +4 -8
- package/dist/server/request.js +16 -19
- 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 -139
- package/dist/server/routes/admin.d.ts +8 -8
- package/dist/server/routes/admin.js +35 -49
- package/dist/server/routes/customer-notes.d.ts +6 -6
- package/dist/server/routes/customer-notes.js +8 -14
- package/dist/server/routes/decisions.d.ts +6 -6
- package/dist/server/routes/decisions.js +12 -21
- package/dist/server/routes/incidents.d.ts +6 -6
- package/dist/server/routes/incidents.js +14 -25
- package/dist/server/routes/memories.d.ts +9 -9
- package/dist/server/routes/memories.js +20 -63
- package/dist/server/routes/object-routes.d.ts +6 -11
- package/dist/server/routes/object-routes.js +11 -22
- package/dist/server/routes/policies.d.ts +7 -7
- package/dist/server/routes/policies.js +12 -22
- package/dist/server/routes/predictions.d.ts +6 -6
- package/dist/server/routes/predictions.js +22 -38
- package/dist/server/routes/processes.d.ts +6 -6
- package/dist/server/routes/processes.js +17 -28
- package/dist/server/routes/project-briefs.d.ts +7 -7
- package/dist/server/routes/project-briefs.js +11 -20
- package/dist/server/routes/recall.d.ts +5 -5
- package/dist/server/routes/recall.js +16 -45
- package/dist/server/routes/skills.d.ts +7 -7
- package/dist/server/routes/skills.js +10 -22
- package/dist/server/server-detect.d.ts +15 -53
- package/dist/server/server-detect.js +55 -96
- package/dist/server/sleep-child.js +26 -7
- package/dist/server/sleep-offload.d.ts +11 -5
- package/dist/server/sleep-offload.js +21 -12
- package/dist/server/types.d.ts +32 -18
- package/dist/server/validation.d.ts +3 -2
- package/dist/server/validation.js +15 -33
- package/dist/server.d.ts +7 -6
- package/dist/server.js +8 -6
- package/dist/sharing/global-store.d.ts +19 -0
- package/dist/sharing/global-store.js +75 -0
- package/dist/sharing/global-sync.d.ts +6 -0
- package/dist/sharing/global-sync.js +73 -0
- package/dist/sharing/project-merge.d.ts +11 -19
- package/dist/sharing/project-merge.js +63 -125
- package/dist/sharing/search-both.d.ts +60 -0
- package/dist/sharing/search-both.js +138 -0
- package/dist/sharing/share.d.ts +40 -0
- package/dist/sharing/share.js +229 -0
- package/dist/store/ambient.js +9 -15
- package/dist/store/audit-event.d.ts +5 -13
- package/dist/store/audit-event.js +4 -12
- package/dist/store/audit.d.ts +2 -21
- package/dist/store/audit.js +8 -67
- package/dist/store/auth.d.ts +10 -8
- package/dist/store/auth.js +17 -12
- package/dist/store/candidates.d.ts +23 -5
- package/dist/store/candidates.js +119 -71
- package/dist/store/capture-write.d.ts +17 -0
- package/dist/store/capture-write.js +35 -0
- package/dist/store/card-detail.d.ts +2 -1
- package/dist/store/card-detail.js +2 -1
- package/dist/store/cards.d.ts +14 -9
- package/dist/store/cards.js +72 -126
- 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 +417 -0
- package/dist/store/compactions.js +6 -4
- package/dist/store/conflicts.d.ts +4 -21
- package/dist/store/conflicts.js +76 -152
- package/dist/store/connectors/dlq.d.ts +10 -0
- package/dist/store/connectors/dlq.js +32 -0
- package/dist/store/connectors/github.d.ts +14 -16
- package/dist/store/connectors/github.js +34 -57
- package/dist/store/connectors/slack.d.ts +2 -11
- package/dist/store/connectors/slack.js +18 -47
- package/dist/store/dashboard-reads.js +11 -14
- package/dist/store/delete-and-batch.d.ts +17 -31
- package/dist/store/delete-and-batch.js +84 -67
- package/dist/store/delivery-recorder.d.ts +15 -4
- package/dist/store/delivery-recorder.js +34 -17
- package/dist/store/descendant-page.js +6 -3
- package/dist/store/diagnostics.js +6 -13
- package/dist/store/dormant.d.ts +8 -30
- package/dist/store/dormant.js +18 -57
- package/dist/store/embeddings/index.d.ts +11 -90
- package/dist/store/embeddings/index.js +18 -523
- package/dist/store/entry-reads.d.ts +34 -61
- package/dist/store/entry-reads.js +111 -136
- package/dist/store/entry-row.d.ts +6 -35
- package/dist/store/entry-row.js +9 -37
- package/dist/store/entry-writes.d.ts +12 -18
- package/dist/store/entry-writes.js +46 -44
- 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.d.ts +3 -40
- package/dist/store/goals.js +41 -178
- package/dist/store/graph-queue.d.ts +6 -22
- package/dist/store/graph-queue.js +14 -45
- package/dist/store/graph-reads.d.ts +11 -35
- package/dist/store/graph-reads.js +24 -60
- package/dist/store/graph-rows.d.ts +3 -6
- package/dist/store/graph-rows.js +6 -9
- package/dist/store/graph-view-rows.d.ts +2 -1
- package/dist/store/graph-view-rows.js +2 -1
- package/dist/store/graph-writes.d.ts +10 -35
- package/dist/store/graph-writes.js +59 -106
- package/dist/store/half-life.d.ts +2 -1
- package/dist/store/half-life.js +14 -16
- package/dist/store/handoffs.d.ts +6 -12
- package/dist/store/handoffs.js +22 -40
- package/dist/store/index-and-stats.d.ts +6 -19
- package/dist/store/index-and-stats.js +36 -84
- 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.d.ts +2 -6
- package/dist/store/mirrors.js +24 -29
- package/dist/store/open.d.ts +0 -4
- package/dist/store/open.js +42 -62
- package/dist/store/pilot-arm.d.ts +12 -0
- package/dist/store/pilot-arm.js +42 -0
- package/dist/store/planning-fallacy-evidence.d.ts +2 -30
- package/dist/store/planning-fallacy-evidence.js +8 -37
- package/dist/store/port.d.ts +91 -82
- package/dist/store/port.js +8 -0
- package/dist/store/predictions.d.ts +12 -53
- package/dist/store/predictions.js +41 -125
- package/dist/store/project-tags.d.ts +62 -0
- package/dist/store/project-tags.js +67 -0
- package/dist/{cli → store}/quality-repair.js +15 -31
- package/dist/store/quarantine.js +2 -1
- package/dist/store/raw-archive.d.ts +4 -16
- package/dist/store/raw-archive.js +14 -29
- package/dist/store/recall-trace.d.ts +12 -77
- package/dist/store/recall-trace.js +37 -97
- package/dist/store/rejected-values.js +9 -20
- package/dist/store/rejection-probe.d.ts +4 -0
- package/dist/store/rejection-probe.js +19 -0
- package/dist/store/rejection.d.ts +10 -73
- package/dist/store/rejection.js +12 -84
- package/dist/store/report-reads.d.ts +6 -0
- package/dist/store/report-reads.js +29 -0
- package/dist/store/rows.d.ts +9 -19
- package/dist/store/rows.js +36 -34
- package/dist/store/rule-sql.d.ts +14 -0
- package/dist/store/rule-sql.js +56 -0
- package/dist/store/search-rows.d.ts +7 -38
- package/dist/store/search-rows.js +23 -54
- package/dist/store/sessions.d.ts +10 -47
- package/dist/store/sessions.js +21 -75
- 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 +5 -8
- package/dist/store/sqlite/connector-writes-group.js +3 -3
- package/dist/store/sqlite/entry-writes-group.js +4 -4
- package/dist/store/sqlite/error-codec.js +8 -5
- package/dist/store/sqlite/executor.d.ts +2 -1
- package/dist/store/sqlite/executor.js +12 -5
- package/dist/store/sqlite/graph-reads-group.js +1 -1
- package/dist/store/sqlite/held-connection.d.ts +9 -0
- package/dist/store/sqlite/held-connection.js +41 -0
- package/dist/store/sqlite/local.d.ts +3 -3
- package/dist/store/sqlite/local.js +1 -0
- package/dist/store/sqlite/object-rows.d.ts +1 -1
- package/dist/store/sqlite/object-rows.js +6 -3
- package/dist/store/sqlite/objects-group.d.ts +1 -1
- package/dist/store/sqlite/objects-group.js +5 -3
- package/dist/store/sqlite/quarantine-group.js +2 -2
- package/dist/store/sqlite/store.d.ts +1 -4
- package/dist/store/sqlite/store.js +16 -15
- package/dist/store/sqlite/vector-reads-group.js +2 -2
- package/dist/store/sqlite/worker-jobs.js +1 -1
- package/dist/store/sqlite/worker-ops.d.ts +13 -2
- package/dist/store/sqlite/worker-ops.js +13 -2
- package/dist/store/sqlite/worker-store.js +5 -2
- package/dist/store/summaries.d.ts +11 -63
- package/dist/store/summaries.js +37 -148
- package/dist/store/summary-dirty.js +1 -1
- package/dist/store/tenant-lookup.d.ts +6 -1
- package/dist/store/tenant-lookup.js +7 -0
- package/dist/store/tenant.d.ts +2 -16
- package/dist/store/tenant.js +4 -19
- package/dist/store/token-ledger.d.ts +13 -50
- package/dist/store/token-ledger.js +19 -85
- package/dist/store/usage-reports.js +5 -13
- package/dist/store/vector-index.d.ts +46 -0
- package/dist/store/vector-index.js +171 -0
- package/dist/store/working-memory.d.ts +6 -25
- package/dist/store/working-memory.js +18 -52
- package/dist/support-bundle.js +9 -8
- package/dist/trust/reject-flow.js +3 -5
- package/dist/util/agent-homes.d.ts +15 -0
- package/dist/util/agent-homes.js +34 -0
- package/dist/util/anthropic-messages.d.ts +3 -0
- package/dist/util/anthropic-messages.js +35 -6
- package/dist/util/atomic-write.d.ts +2 -1
- package/dist/util/atomic-write.js +35 -4
- package/dist/util/capped-json.d.ts +6 -0
- package/dist/util/capped-json.js +46 -0
- package/dist/util/chunked.d.ts +3 -0
- package/dist/util/chunked.js +10 -0
- package/dist/util/crash-handlers.d.ts +8 -1
- package/dist/util/crash-handlers.js +52 -10
- package/dist/util/ellipsize.d.ts +3 -0
- package/dist/util/ellipsize.js +5 -0
- package/dist/util/env.d.ts +14 -6
- package/dist/util/env.js +15 -7
- package/dist/util/format.d.ts +3 -0
- package/dist/util/format.js +6 -0
- package/dist/util/home-path.d.ts +2 -1
- package/dist/util/home-path.js +4 -2
- package/dist/util/hook-payload.d.ts +8 -0
- package/dist/util/hook-payload.js +37 -0
- package/dist/util/http-retry.d.ts +9 -1
- package/dist/util/http-retry.js +67 -8
- 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 +7 -2
- package/dist/util/log.js +34 -9
- package/dist/util/request-scope.d.ts +5 -2
- package/dist/util/request-scope.js +13 -7
- package/dist/util/secret-detect.d.ts +5 -30
- package/dist/util/secret-detect.js +19 -40
- package/dist/util/sqlite-blocked.d.ts +2 -0
- package/dist/util/sqlite-blocked.js +5 -0
- package/dist/util/stored-json.d.ts +1 -1
- package/dist/util/stored-json.js +1 -1
- 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/token-text.d.ts +1 -4
- package/dist/util/token-text.js +1 -4
- package/dist/util/transcript-tail.d.ts +2 -0
- package/dist/util/transcript-tail.js +24 -23
- package/dist/util/version.d.ts +5 -20
- package/dist/util/version.js +5 -20
- package/dist/{store → util}/yaml.d.ts +1 -5
- package/dist/{store → util}/yaml.js +2 -6
- package/extensions/openclaw-plugin/index.ts +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 +2 -2
- package/dist/cli/provenance-coverage.d.ts +0 -18
- package/dist/connectors/github/cli-impl.d.ts +0 -25
- package/dist/sharing/scope.d.ts +0 -14
- package/dist/sharing/shared.d.ts +0 -187
- package/dist/sharing/shared.js +0 -563
- package/dist/store/embeddings/local.d.ts +0 -15
- package/dist/store/embeddings/local.js +0 -192
- package/dist/store/embeddings/provider.d.ts +0 -77
- package/dist/store/markdown.d.ts +0 -10
- package/dist/store/recall-scope.d.ts +0 -138
- package/dist/store/recall-scope.js +0 -216
- package/dist/store/vector-writes.d.ts +0 -13
- package/dist/store/vector-writes.js +0 -89
- /package/dist/{store → core}/object-types.d.ts +0 -0
- /package/dist/{store → core}/object-types.js +0 -0
- /package/dist/{cli → store}/quality-repair.d.ts +0 -0
- /package/dist/{capture → util}/compaction-items.d.ts +0 -0
- /package/dist/{capture → util}/compaction-items.js +0 -0
package/dist/server/client-ip.js
CHANGED
|
@@ -5,25 +5,9 @@ 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
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
* carries the proxy's address, so per-IP buckets collapse into one global
|
|
12
|
-
* bucket that unauthenticated traffic can drain before auth runs. Set
|
|
13
|
-
* HIPPO_CLIENT_IP_HEADER to the header the proxy stamps with the real
|
|
14
|
-
* client address (fly-client-ip on Fly, which the edge always overwrites)
|
|
15
|
-
* to key buckets per client instead.
|
|
16
|
-
*
|
|
17
|
-
* Only set this when a trusted proxy fronts EVERY request: a directly
|
|
18
|
-
* reachable server honoring the header would let clients mint a fresh
|
|
19
|
-
* bucket per request and bypass the limiter entirely.
|
|
20
|
-
*
|
|
21
|
-
* HIPPO_TRUSTED_PROXIES (comma-separated IPs or CIDRs) pins which peers count
|
|
22
|
-
* as that proxy: the header is read only when the socket peer is listed, and
|
|
23
|
-
* listed hops are skipped. In a comma-joined chain (X-Forwarded-For) the key is
|
|
24
|
-
* the rightmost hop no trusted proxy added; entries to its left are whatever
|
|
25
|
-
* the client sent, so they never pick the bucket.
|
|
26
|
-
*/
|
|
8
|
+
* Rate-limit key: the socket's remote address, which behind a TLS proxy collapses into one bucket unauthenticated traffic can drain.
|
|
9
|
+
* Set HIPPO_CLIENT_IP_HEADER (fly-client-ip on Fly) only when a trusted proxy fronts EVERY request, or clients could mint a fresh bucket per request.
|
|
10
|
+
* HIPPO_TRUSTED_PROXIES (IPs or CIDRs) pins which peers count as that proxy; in a comma-joined chain the key is the rightmost hop no trusted proxy added. */
|
|
27
11
|
export function clientIpForRateLimit(req) {
|
|
28
12
|
const socketIp = req.socket.remoteAddress ?? 'unknown';
|
|
29
13
|
const header = envClientIpHeader();
|
|
@@ -73,11 +57,12 @@ export function warnIfClientIpHeaderUnpinned() {
|
|
|
73
57
|
const header = envClientIpHeader();
|
|
74
58
|
if (!header || trustedProxyList(envTrustedProxies()))
|
|
75
59
|
return;
|
|
76
|
-
log.warn(`serve: HIPPO_CLIENT_IP_HEADER is ${header} and HIPPO_TRUSTED_PROXIES is unset, so any caller that reaches this port
|
|
60
|
+
log.warn(`serve: HIPPO_CLIENT_IP_HEADER is ${header} and HIPPO_TRUSTED_PROXIES is unset, so any caller that reaches this port ` +
|
|
61
|
+
`without passing the proxy can send that header and pick its own rate-limit bucket. ` +
|
|
77
62
|
"Set HIPPO_TRUSTED_PROXIES to the proxy's addresses or CIDRs, so the header is read from the proxy alone.");
|
|
78
63
|
}
|
|
79
64
|
/** The key for one subscriber: an IPv6 address's /64, since one host may hold the whole /64; any other key as is. */
|
|
80
|
-
|
|
65
|
+
function subscriberKey(ip) {
|
|
81
66
|
const bare = ip.split('%')[0];
|
|
82
67
|
if (bare.toLowerCase().startsWith('::ffff:') && isIP(bare.slice(7)) === 4)
|
|
83
68
|
return bare.slice(7);
|
|
@@ -101,15 +86,8 @@ function isTrustedProxy(list, ip) {
|
|
|
101
86
|
return family !== 0 && list.check(bare, family === 6 ? 'ipv6' : 'ipv4');
|
|
102
87
|
}
|
|
103
88
|
export function enforceRateLimit(req, path, limiter) {
|
|
104
|
-
// Per-IP rate limit on /v1/* and /mcp* to bound api-key-id enumeration
|
|
105
|
-
// (
|
|
106
|
-
// here lands in the createServer catch like any other HttpError.
|
|
107
|
-
//
|
|
108
|
-
// Keyed on the socket's remote address by default. Behind a TLS-terminating
|
|
109
|
-
// proxy every socket carries the proxy's address, collapsing the per-IP
|
|
110
|
-
// buckets into one global bucket that pre-auth traffic can drain; set
|
|
111
|
-
// HIPPO_CLIENT_IP_HEADER there so each real client gets its own bucket
|
|
112
|
-
// (see clientIpForRateLimit).
|
|
89
|
+
// Per-IP rate limit on /v1/* and /mcp* to bound api-key-id enumeration; /health and other paths are never throttled, and a 429 lands in the createServer
|
|
90
|
+
// catch. Keyed per clientIpForRateLimit (set HIPPO_CLIENT_IP_HEADER behind a TLS-terminating proxy, or all clients share one bucket).
|
|
113
91
|
if (limiter && (path.startsWith('/v1/') || path === '/mcp' || path === '/mcp/stream')) {
|
|
114
92
|
if (!limiter.check(clientLimitKey(req))) {
|
|
115
93
|
throw new HttpError(429, 'rate limit exceeded', limiter.retryAfterSec);
|
|
@@ -4,8 +4,6 @@ import { RequestDeadline } from '../util/request-scope.js';
|
|
|
4
4
|
export declare function handlerDeadlineCount(): number;
|
|
5
5
|
/** Whether `res` was answered at its deadline, so whatever its handler does later has no caller. */
|
|
6
6
|
export declare function isAbandoned(res: ServerResponse): boolean;
|
|
7
|
-
/** How long a request may run: 120 s, or HIPPO_REQUEST_DEADLINE_MS, where 0 turns the deadline off. */
|
|
8
|
-
export declare function requestDeadlineMs(): number;
|
|
9
7
|
/** The deadline of `req`, for every /v1 and /mcp route but the two exempt ones. */
|
|
10
8
|
export declare function requestDeadlineFor(req: IncomingMessage): RequestDeadline | undefined;
|
|
11
9
|
/** Calls `reply` when `res` has sent nothing by `deadline`. A store call still in flight answers first, since only the store knows what became of a write. */
|
package/dist/server/deadline.js
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { RequestDeadline } from '../util/request-scope.js';
|
|
3
|
-
const DEFAULT_REQUEST_DEADLINE_MS = 120_000;
|
|
1
|
+
import { RequestDeadline, requestDeadlineMs } from '../util/request-scope.js';
|
|
4
2
|
// Each has a deadline of its own kind: sleep stops its child process, and the stream is meant to stay open.
|
|
5
3
|
const EXEMPT = new Set(['POST /v1/sleep', 'GET /mcp/stream']);
|
|
6
4
|
const abandoned = new WeakSet();
|
|
@@ -13,10 +11,6 @@ export function handlerDeadlineCount() {
|
|
|
13
11
|
export function isAbandoned(res) {
|
|
14
12
|
return abandoned.has(res);
|
|
15
13
|
}
|
|
16
|
-
/** How long a request may run: 120 s, or HIPPO_REQUEST_DEADLINE_MS, where 0 turns the deadline off. */
|
|
17
|
-
export function requestDeadlineMs() {
|
|
18
|
-
return envRequestDeadlineMs() ?? DEFAULT_REQUEST_DEADLINE_MS;
|
|
19
|
-
}
|
|
20
14
|
/** The deadline of `req`, for every /v1 and /mcp route but the two exempt ones. */
|
|
21
15
|
export function requestDeadlineFor(req) {
|
|
22
16
|
const ms = requestDeadlineMs();
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
// `hippo serve` reads these without loading the server, so the CLI and serve() cannot disagree on a default.
|
|
2
|
+
export const DEFAULT_SERVER_PORT = 6789;
|
|
3
|
+
export const DEFAULT_SERVER_HOST = '127.0.0.1';
|
|
4
|
+
export const DEFAULT_DASHBOARD_PORT = 3333;
|
|
5
|
+
//# sourceMappingURL=defaults.js.map
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export interface KeyCheckBounds {
|
|
2
|
-
/** Throws the 429 a refused key check answers, before any derivation: no room left to
|
|
2
|
+
/** Throws the 429 a refused key check answers, before any derivation: no room left to
|
|
3
|
+
* wait (Retry-After 1), or `address` has spent its tries on `keyId` (Retry-After 12). */
|
|
3
4
|
admit(keyId: string, address: string): void;
|
|
4
5
|
/** Runs `derive` now or once a slot frees; `admit` in the same tick keeps the queue within its cap. */
|
|
5
6
|
run<T>(derive: () => Promise<T>): Promise<T>;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import type { Server, ServerResponse } from 'node:http';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
2
|
+
export declare function setKeepAliveTimeouts(server: Server): void;
|
|
3
|
+
export declare const DEFAULT_SHUTDOWN_DRAIN_MS = 5000;
|
|
4
|
+
/** How long a signal or crash shutdown may run before the process is ended without it. */
|
|
5
|
+
export declare function shutdownBoundMs(drainMs: number): number;
|
|
6
|
+
/** Stops accepting, ends streams at once (they never finish on their own), gives other in-flight requests up to `drainMs`, then closes what is left. */
|
|
6
7
|
export declare function drainAndClose(server: Server, inflight: ReadonlySet<ServerResponse>, drainMs: number): Promise<void>;
|
|
7
8
|
//# sourceMappingURL=lifecycle.d.ts.map
|
package/dist/server/lifecycle.js
CHANGED
|
@@ -1,8 +1,23 @@
|
|
|
1
|
+
import { bodyDeadlineMs } from '../util/http-util.js';
|
|
1
2
|
import { log } from '../util/log.js';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
// Node's own default, named so the three socket deadlines read together. It times the request arriving, never the handler, so a 10 minute sleep is not cut.
|
|
4
|
+
const REQUEST_RECEIVE_TIMEOUT_MS = 300_000;
|
|
5
|
+
export function setKeepAliveTimeouts(server) {
|
|
6
|
+
// The default 5s keepAliveTimeout closes idle sockets just as clients reuse them (ECONNRESET).
|
|
7
|
+
// headersTimeout must stay ABOVE keepAliveTimeout + keepAliveTimeoutBuffer (1s), or it closes idle reused sockets itself.
|
|
8
|
+
server.keepAliveTimeout = 65_000;
|
|
9
|
+
server.headersTimeout = 70_000;
|
|
10
|
+
// Never below what a raised body deadline allows, or Node's bare 408 would come before the route's own.
|
|
11
|
+
server.requestTimeout = Math.max(REQUEST_RECEIVE_TIMEOUT_MS, server.headersTimeout + bodyDeadlineMs());
|
|
12
|
+
}
|
|
13
|
+
export const DEFAULT_SHUTDOWN_DRAIN_MS = 5000;
|
|
14
|
+
// Past the request drain, a stop only waits for each store thread to end its statement and close: seconds at most, so longer means a thread that will not end.
|
|
15
|
+
const STORE_CLOSE_GRACE_MS = 10_000;
|
|
16
|
+
/** How long a signal or crash shutdown may run before the process is ended without it. */
|
|
17
|
+
export function shutdownBoundMs(drainMs) {
|
|
18
|
+
return drainMs + STORE_CLOSE_GRACE_MS;
|
|
19
|
+
}
|
|
20
|
+
/** Stops accepting, ends streams at once (they never finish on their own), gives other in-flight requests up to `drainMs`, then closes what is left. */
|
|
6
21
|
export async function drainAndClose(server, inflight, drainMs) {
|
|
7
22
|
const closed = new Promise((resolve, reject) => {
|
|
8
23
|
server.close((err) => (err ? reject(err) : resolve()));
|
package/dist/server/mcp-http.js
CHANGED
|
@@ -1,54 +1,30 @@
|
|
|
1
1
|
// MCP over HTTP: POST /mcp and the GET /mcp/stream SSE keepalive.
|
|
2
2
|
import { envMcpSseHeartbeatMs, envMcpSseMaxAgeSec, envMcpSseMaxStreams } from '../util/env.js';
|
|
3
|
-
import { createHash } from 'node:crypto';
|
|
4
3
|
import { isSharedStore } from '../core/config.js';
|
|
5
4
|
import { handleMcpRequest, mcpErrorResponse } from '../mcp/server.js';
|
|
6
5
|
import { HttpError, readBody, sendJson } from '../util/http-util.js';
|
|
6
|
+
import { log } from '../util/log.js';
|
|
7
7
|
import { assertCallerProject } from '../core/project-identity.js';
|
|
8
8
|
import { buildContextWithAuth, heartbeatVerdict, readAuthHeader, requireAuth } from './auth.js';
|
|
9
|
-
import { clientLimitKey
|
|
9
|
+
import { clientLimitKey } from './client-ip.js';
|
|
10
10
|
import { noteAccess } from './request.js';
|
|
11
11
|
import { isJsonString, isJsonObject } from '../util/json.js';
|
|
12
|
-
import {
|
|
13
|
-
|
|
12
|
+
import { blockHash } from '../util/token-text.js';
|
|
13
|
+
import { consolidateInChild } from './sleep-offload.js';
|
|
14
|
+
const DEFAULT_SSE_HEARTBEAT_MS = 60_000;
|
|
14
15
|
const DEFAULT_SSE_MAX_AGE_SEC = 3600;
|
|
15
|
-
/**
|
|
16
|
-
*
|
|
17
|
-
* mcp/server.ts to scope `lastRecalledIds` to the calling client so two
|
|
18
|
-
* clients on the same tenant cannot poison each other's outcome feedback.
|
|
19
|
-
*
|
|
20
|
-
* Token is hashed (sha256, 16-hex-char prefix) so we never log or persist
|
|
21
|
-
* the raw bearer. Combined with remoteAddress so two clients sharing a key
|
|
22
|
-
* (e.g. on a shared Postman environment) are still separable in the common
|
|
23
|
-
* case. 'noauth' covers loopback no-auth and is acceptable because that
|
|
24
|
-
* path is single-host single-user.
|
|
25
|
-
*/
|
|
16
|
+
/** Per-client key for MCP state isolation under HTTP-MCP (scopes `lastRecalledIds`): sha256 of the token (16 hex chars, so the raw bearer is never logged)
|
|
17
|
+
* plus the client address the rate limiter keys on, so clients sharing a key stay separable behind a trusted proxy too; 'noauth' covers loopback no-auth. */
|
|
26
18
|
function buildMcpClientKey(req) {
|
|
27
19
|
const auth = readAuthHeader(req);
|
|
28
20
|
const tokenHash = auth.kind === 'bearer'
|
|
29
|
-
?
|
|
21
|
+
? blockHash(auth.token)
|
|
30
22
|
: 'noauth';
|
|
31
|
-
|
|
32
|
-
return `http:${tokenHash}:${addr}`;
|
|
23
|
+
return `http:${tokenHash}:${clientLimitKey(req)}`;
|
|
33
24
|
}
|
|
34
|
-
//
|
|
35
|
-
//
|
|
36
|
-
//
|
|
37
|
-
// dispatch to the same `handleMcpRequest` as the stdio loop in src/mcp/server.ts.
|
|
38
|
-
//
|
|
39
|
-
// POST /mcp — Send a JSON-RPC request, get a JSON-RPC response synchronously
|
|
40
|
-
// in the body. Content-type: application/json both ways.
|
|
41
|
-
// GET /mcp/stream — Open an SSE stream for server-initiated messages.
|
|
42
|
-
// v1 simplification: this stream is keepalive-only. Clients
|
|
43
|
-
// that need server-pushed notifications/progress will see
|
|
44
|
-
// only `: ping` comments every 30s. All real responses come
|
|
45
|
-
// back synchronously on POST /mcp. This matches the
|
|
46
|
-
// "synchronous JSON in body" leg of the MCP HTTP spec and
|
|
47
|
-
// is enough for `tools/list` / `tools/call` round-trips.
|
|
48
|
-
// Server-initiated SSE messages will be wired in a later task.
|
|
49
|
-
//
|
|
50
|
-
// Auth: same as /v1/* — Bearer token validated via `requireAuth`, with the
|
|
51
|
-
// loopback no-auth fallback. SSE check runs once at stream-open.
|
|
25
|
+
// MCP-over-HTTP/SSE: POST /mcp answers a JSON-RPC request synchronously; GET /mcp/stream is a keepalive-only SSE stream
|
|
26
|
+
// (`: ping` every DEFAULT_SSE_HEARTBEAT_MS, 60 s) in v1.
|
|
27
|
+
// Both dispatch to handleMcpRequest as stdio does. Auth matches /v1/* (Bearer via `requireAuth`, loopback fallback); SSE is checked once at stream-open.
|
|
52
28
|
// Percent-encoded by the client, so any lowercase Unicode name fits a Latin-1 header.
|
|
53
29
|
const HEADER_PIECE = /^[A-Za-z0-9\-_.!~*'()%]+$/;
|
|
54
30
|
function decodeHeaderPiece(raw, header) {
|
|
@@ -95,17 +71,15 @@ function mcpContextFor(ctx, clientKey, autoSleep, project) {
|
|
|
95
71
|
clientKey,
|
|
96
72
|
store: ctx.store,
|
|
97
73
|
autoSleep,
|
|
74
|
+
autoSleepRunner: consolidateInChild,
|
|
98
75
|
};
|
|
99
76
|
if (project !== undefined)
|
|
100
77
|
mcpCtx.project = project;
|
|
101
78
|
return mcpCtx;
|
|
102
79
|
}
|
|
103
80
|
export async function handleMcpPost(req, res, opts) {
|
|
104
|
-
//
|
|
105
|
-
//
|
|
106
|
-
// Without this, executeTool would walk from cwd via findHippoRoot() and
|
|
107
|
-
// pull tenant from HIPPO_TENANT, dropping a valid Bearer for tenant B
|
|
108
|
-
// back to whatever the env says.
|
|
81
|
+
// Same Context the /v1/* routes use, so MCP tool calls inherit the bound hippoRoot and the auth-resolved tenantId/actor; otherwise executeTool would walk
|
|
82
|
+
// from cwd and read HIPPO_TENANT, dropping a valid Bearer for tenant B to the env's tenant.
|
|
109
83
|
const ctx = await buildContextWithAuth(req, opts);
|
|
110
84
|
noteAccess(req, { tenant: ctx.tenantId });
|
|
111
85
|
const project = callerProjectFromHeaders(req, ctx.hippoRoot);
|
|
@@ -120,16 +94,16 @@ export async function handleMcpPost(req, res, opts) {
|
|
|
120
94
|
if (!isJsonObject(mcpReq) || !isJsonString(mcpReq.method)) {
|
|
121
95
|
throw new HttpError(400, 'JSON-RPC body must include a method string');
|
|
122
96
|
}
|
|
123
|
-
// SAFETY: validated above as a plain JSON object
|
|
124
|
-
//
|
|
125
|
-
// safely defaulted inside handleMcpRequest's JSON-RPC dispatch.
|
|
97
|
+
// SAFETY: validated above as a plain JSON object with a string method; the other McpRequest wire fields (jsonrpc, id, params) are checked or defaulted in
|
|
98
|
+
// handleMcpRequest.
|
|
126
99
|
const rpcReq = mcpReq;
|
|
127
100
|
let mcpRes;
|
|
128
101
|
try {
|
|
129
102
|
mcpRes = await handleMcpRequest(rpcReq, mcpContextFor(ctx, buildMcpClientKey(req), opts.autoSleep, project));
|
|
130
103
|
}
|
|
131
104
|
catch (err) {
|
|
132
|
-
|
|
105
|
+
const tool = rpcReq.params?.name;
|
|
106
|
+
mcpRes = mcpErrorResponse(rpcReq.id, err, undefined, isJsonString(tool) ? `${rpcReq.method} ${tool.slice(0, 128)}` : rpcReq.method);
|
|
133
107
|
}
|
|
134
108
|
if (mcpRes === null) {
|
|
135
109
|
// Notification — no body, 202 Accepted.
|
|
@@ -145,7 +119,7 @@ const DEFAULT_MAX_STREAMS_PER_CLIENT = 8;
|
|
|
145
119
|
function streamSlotKey(req) {
|
|
146
120
|
const auth = readAuthHeader(req);
|
|
147
121
|
if (auth.kind === 'bearer')
|
|
148
|
-
return `key:${
|
|
122
|
+
return `key:${blockHash(auth.token)}`;
|
|
149
123
|
return `ip:${clientLimitKey(req)}`;
|
|
150
124
|
}
|
|
151
125
|
/** Takes a stream slot or throws 429; the slot is released once, when the response closes. */
|
|
@@ -178,13 +152,8 @@ export async function handleMcpStream(req, res, opts, streamSlots) {
|
|
|
178
152
|
// Initial ping so smoke tests can confirm the stream is live without
|
|
179
153
|
// waiting for the first keepalive interval.
|
|
180
154
|
res.write(': ping\n\n');
|
|
181
|
-
// SSE hardening:
|
|
182
|
-
//
|
|
183
|
-
// revoked or rotated, close the stream with reason='auth_revoked'.
|
|
184
|
-
// - MCP_SSE_MAX_AGE_SEC (default 3600) caps stream lifetime; close
|
|
185
|
-
// with reason='max_age_exceeded' when reached.
|
|
186
|
-
// - MCP_SSE_HEARTBEAT_MS (default 60000) lets tests run with a short
|
|
187
|
-
// interval without waiting a full minute.
|
|
155
|
+
// SSE hardening: the heartbeat re-validates the bearer (MCP_SSE_HEARTBEAT_MS, default 60000) and closes with 'auth_revoked' if the key was revoked or
|
|
156
|
+
// rotated; MCP_SSE_MAX_AGE_SEC (default 3600) caps stream lifetime and closes with 'max_age_exceeded'.
|
|
188
157
|
keepStreamAlive(req, res, opts);
|
|
189
158
|
}
|
|
190
159
|
function keepStreamAlive(req, res, opts) {
|
|
@@ -214,6 +183,8 @@ function keepStreamAlive(req, res, opts) {
|
|
|
214
183
|
checking = true;
|
|
215
184
|
void heartbeatVerdict(req, opts).then((verdict) => {
|
|
216
185
|
checking = false;
|
|
186
|
+
if (!closed && verdict === 'unavailable')
|
|
187
|
+
log.warn('heartbeat tick skipped: auth check unavailable');
|
|
217
188
|
if (closed || verdict === 'unavailable')
|
|
218
189
|
return;
|
|
219
190
|
if (verdict === 'revoked') {
|
|
@@ -1,16 +1,7 @@
|
|
|
1
|
-
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
* Bounds api-key-id enumeration: a
|
|
5
|
-
* client that drains its bucket is denied until it refills. Dependency-free
|
|
6
|
-
* and unit-testable in isolation via the injectable `now`.
|
|
7
|
-
*/
|
|
1
|
+
/** Per-key token-bucket rate limiter for inbound /v1/* requests, bounding api-key-id enumeration. Dependency-free; the injectable `now` makes it
|
|
2
|
+
* unit-testable. */
|
|
8
3
|
export interface RateLimiter {
|
|
9
|
-
/**
|
|
10
|
-
* Consume one token for `key`. Returns true if the request is allowed,
|
|
11
|
-
* false if the key's bucket is exhausted. `now` (epoch ms) is injectable
|
|
12
|
-
* for deterministic tests.
|
|
13
|
-
*/
|
|
4
|
+
/** Consume one token for `key`: true if allowed, false if the bucket is exhausted; `now` (epoch ms) is injectable for deterministic tests. */
|
|
14
5
|
check(key: string, now?: number): boolean;
|
|
15
6
|
readonly retryAfterSec: number;
|
|
16
7
|
}
|
|
@@ -24,11 +15,7 @@ export interface RateLimiterOpts {
|
|
|
24
15
|
/** Hard cap on tracked keys; the least-recently-used key is evicted on overflow. */
|
|
25
16
|
maxKeys: number;
|
|
26
17
|
}
|
|
27
|
-
/**
|
|
28
|
-
*
|
|
29
|
-
* to once per `idleEvictMs`) drops idle buckets, and a hard `maxKeys` cap evicts
|
|
30
|
-
* the least-recently-used key, so a client rotating source addresses cannot
|
|
31
|
-
* grow the map without bound between sweeps.
|
|
32
|
-
*/
|
|
18
|
+
/** Token-bucket limiter with bounded memory: a sweep (at most once per `idleEvictMs`) drops idle buckets and a `maxKeys` cap evicts the least-recently-used
|
|
19
|
+
* key, so a client rotating source addresses cannot grow the map without bound. */
|
|
33
20
|
export declare function createRateLimiter(opts: RateLimiterOpts): RateLimiter;
|
|
34
21
|
//# sourceMappingURL=rate-limit.d.ts.map
|
|
@@ -1,16 +1,7 @@
|
|
|
1
|
-
/**
|
|
2
|
-
*
|
|
3
|
-
|
|
4
|
-
*
|
|
5
|
-
* client that drains its bucket is denied until it refills. Dependency-free
|
|
6
|
-
* and unit-testable in isolation via the injectable `now`.
|
|
7
|
-
*/
|
|
8
|
-
/**
|
|
9
|
-
* Build a token-bucket limiter. Memory is bounded two ways: a sweep (throttled
|
|
10
|
-
* to once per `idleEvictMs`) drops idle buckets, and a hard `maxKeys` cap evicts
|
|
11
|
-
* the least-recently-used key, so a client rotating source addresses cannot
|
|
12
|
-
* grow the map without bound between sweeps.
|
|
13
|
-
*/
|
|
1
|
+
/** Per-key token-bucket rate limiter for inbound /v1/* requests, bounding api-key-id enumeration. Dependency-free; the injectable `now` makes it
|
|
2
|
+
* unit-testable. */
|
|
3
|
+
/** Token-bucket limiter with bounded memory: a sweep (at most once per `idleEvictMs`) drops idle buckets and a `maxKeys` cap evicts the least-recently-used
|
|
4
|
+
* key, so a client rotating source addresses cannot grow the map without bound. */
|
|
14
5
|
export function createRateLimiter(opts) {
|
|
15
6
|
const { ratePerSec, burst, idleEvictMs, maxKeys } = opts;
|
|
16
7
|
const buckets = new Map();
|
package/dist/server/request.d.ts
CHANGED
|
@@ -13,6 +13,8 @@ interface AccessNote {
|
|
|
13
13
|
}
|
|
14
14
|
/** Names the matched route (the table's pattern, never the path sent) or the caller's tenant for the request's access line. */
|
|
15
15
|
export declare function noteAccess(req: IncomingMessage, note: AccessNote): void;
|
|
16
|
+
/** The route name the request's access line carries, for a line about the same request logged after its reply. */
|
|
17
|
+
export declare function accessRouteOf(req: IncomingMessage): string;
|
|
16
18
|
/** The request's id, after stamping the headers every reply carries and starting the slow-request watchdog and the access line. */
|
|
17
19
|
export declare function openRequest(req: IncomingMessage, res: ServerResponse, slowWarnMs?: number): string;
|
|
18
20
|
export declare function sendError(res: ServerResponse, status: number, message: string): void;
|
|
@@ -23,14 +25,8 @@ interface ParsedRoute {
|
|
|
23
25
|
}
|
|
24
26
|
export declare function parseRequest(req: IncomingMessage): ParsedRoute;
|
|
25
27
|
export declare function matchPath(pattern: string, path: string): Record<string, string> | null;
|
|
26
|
-
/**
|
|
27
|
-
*
|
|
28
|
-
* them — otherwise `%2F` becomes `/`, path-split runs, and the route either
|
|
29
|
-
* silently 404s or matches the wrong template.
|
|
30
|
-
*
|
|
31
|
-
* Only the PATHNAME is scanned (split on the first `?`), so recall queries
|
|
32
|
-
* containing URLs like `?q=https%3A%2F%2Fexample.com` are not rejected.
|
|
33
|
-
*/
|
|
28
|
+
/** Rejects URL-encoded slashes in path segments BEFORE the URL parser decodes them (`%2F` would become `/` and 404 or match the wrong template).
|
|
29
|
+
* Only the PATHNAME is scanned, so recall queries like `?q=https%3A%2F%2Fexample.com` are not rejected. */
|
|
34
30
|
export declare function rejectEncodedSlash(rawUrl: string): void;
|
|
35
31
|
export {};
|
|
36
32
|
//# sourceMappingURL=request.d.ts.map
|
package/dist/server/request.js
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { randomUUID } from 'node:crypto';
|
|
2
|
-
import {
|
|
2
|
+
import { STORE_BUSY_MESSAGE } from '../store/port.js';
|
|
3
|
+
import { isStoreBusy } from '../store/sqlite/busy.js';
|
|
3
4
|
import { errorFields, errorMessage, log } from '../util/log.js';
|
|
4
|
-
import {
|
|
5
|
+
import { mapApiError } from '../api/error-reply.js';
|
|
6
|
+
import { HttpError, sendJson } from '../util/http-util.js';
|
|
5
7
|
// The caller's id lands in a response header and in logs, so only a short plain token is echoed back.
|
|
6
8
|
const REQUEST_ID_RE = /^[A-Za-z0-9._:-]{1,128}$/;
|
|
7
9
|
/** The caller's `X-Request-Id` when it is a short plain token, else a fresh UUID. */
|
|
@@ -18,6 +20,9 @@ export function logRequestFailure(req, err, status) {
|
|
|
18
20
|
log.warn(line, { status });
|
|
19
21
|
else if (status >= 500 && status !== 501)
|
|
20
22
|
log.error(line, { status, ...errorFields(err) });
|
|
23
|
+
// A failed login is the one 4xx an operator needs by default; the id (never the credential) is stamped from the request scope.
|
|
24
|
+
else if (status === 401 || status === 403)
|
|
25
|
+
log.warn(line, { status });
|
|
21
26
|
else
|
|
22
27
|
log.info(line, { status });
|
|
23
28
|
}
|
|
@@ -27,7 +32,8 @@ export function replyFor(err) {
|
|
|
27
32
|
}
|
|
28
33
|
// Above the 30 s body deadline and the 5 s resolver deadline, so a request those govern is answered before it is called slow.
|
|
29
34
|
const SLOW_REQUEST_WARN_MS = 60_000;
|
|
30
|
-
/** Logs one warn when `res` has sent nothing after `afterMs`. It never ends the request
|
|
35
|
+
/** Logs one warn when `res` has sent nothing after `afterMs`. It never ends the request
|
|
36
|
+
* or touches the reply; the timer goes when the reply finishes or the socket closes. */
|
|
31
37
|
function watchSlowRequest(req, res, requestId, afterMs = SLOW_REQUEST_WARN_MS) {
|
|
32
38
|
const startedAt = Date.now();
|
|
33
39
|
const timer = setTimeout(() => {
|
|
@@ -51,6 +57,10 @@ export function noteAccess(req, note) {
|
|
|
51
57
|
if (held)
|
|
52
58
|
Object.assign(held, note);
|
|
53
59
|
}
|
|
60
|
+
/** The route name the request's access line carries, for a line about the same request logged after its reply. */
|
|
61
|
+
export function accessRouteOf(req) {
|
|
62
|
+
return accessNotes.get(req)?.route ?? UNMATCHED_ROUTE;
|
|
63
|
+
}
|
|
54
64
|
/** One info line per finished request. A path id and a query string can both hold caller data, so the line carries neither. */
|
|
55
65
|
function logAccessWhenFinished(req, res, requestId) {
|
|
56
66
|
const note = {};
|
|
@@ -97,14 +107,7 @@ export function parseRequest(req) {
|
|
|
97
107
|
query: url.searchParams,
|
|
98
108
|
};
|
|
99
109
|
}
|
|
100
|
-
/**
|
|
101
|
-
* Lightweight pattern matcher for /v1/memories/:id/<action>. Avoids pulling
|
|
102
|
-
* in a router dependency for the half-dozen patterns we actually use.
|
|
103
|
-
*
|
|
104
|
-
* Returns null if `path` does not match `pattern`. Otherwise returns an object
|
|
105
|
-
* mapping each :param name to its value. Path segments are exact-matched
|
|
106
|
-
* except for parameter slots.
|
|
107
|
-
*/
|
|
110
|
+
/** Pattern matcher for /v1/memories/:id/<action> (no router dependency); null if `path` does not match, else each :param name mapped to its value. */
|
|
108
111
|
function decodePathSegment(segment) {
|
|
109
112
|
try {
|
|
110
113
|
return decodeURIComponent(segment);
|
|
@@ -135,14 +138,8 @@ export function matchPath(pattern, path) {
|
|
|
135
138
|
}
|
|
136
139
|
return params;
|
|
137
140
|
}
|
|
138
|
-
/**
|
|
139
|
-
*
|
|
140
|
-
* them — otherwise `%2F` becomes `/`, path-split runs, and the route either
|
|
141
|
-
* silently 404s or matches the wrong template.
|
|
142
|
-
*
|
|
143
|
-
* Only the PATHNAME is scanned (split on the first `?`), so recall queries
|
|
144
|
-
* containing URLs like `?q=https%3A%2F%2Fexample.com` are not rejected.
|
|
145
|
-
*/
|
|
141
|
+
/** Rejects URL-encoded slashes in path segments BEFORE the URL parser decodes them (`%2F` would become `/` and 404 or match the wrong template).
|
|
142
|
+
* Only the PATHNAME is scanned, so recall queries like `?q=https%3A%2F%2Fexample.com` are not rejected. */
|
|
146
143
|
export function rejectEncodedSlash(rawUrl) {
|
|
147
144
|
const queryIdx = rawUrl.indexOf('?');
|
|
148
145
|
const pathname = queryIdx === -1 ? rawUrl : rawUrl.slice(0, queryIdx);
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { JsonValue } from '../util/json.js';
|
|
2
|
+
import type { AddonRoute } from './types.js';
|
|
3
|
+
/** Boot-time check: an add-on path must be plain, unique and not one core serves, so no add-on shadows a core route or hides from dispatch. */
|
|
4
|
+
export declare function assertAddonRoutes(routes: readonly AddonRoute[]): void;
|
|
5
|
+
/** Boot-time check and serialization: a public path that a core GET route serves would open that route to anyone. */
|
|
6
|
+
export declare function assertPublicJson(publicJson: Readonly<Record<string, JsonValue>>): ReadonlyMap<string, string>;
|
|
7
|
+
//# sourceMappingURL=route-checks.d.ts.map
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { V1_ROUTES, routeMatches } from './route-table.js';
|
|
2
|
+
const PLAIN_SEGMENT_RE = /^[A-Za-z0-9._~-]+$/;
|
|
3
|
+
function isPlainV1Path(path) {
|
|
4
|
+
return path.startsWith('/v1/') && new URL(path, 'http://h').pathname === path
|
|
5
|
+
&& path.slice('/v1/'.length).split('/').every((segment) => PLAIN_SEGMENT_RE.test(segment));
|
|
6
|
+
}
|
|
7
|
+
// A plain path never holds a `%`, so matchPath cannot throw here.
|
|
8
|
+
function isCorePath(method, path) {
|
|
9
|
+
return V1_ROUTES.some((route) => routeMatches(route, method, path) !== null);
|
|
10
|
+
}
|
|
11
|
+
/** Boot-time check: an add-on path must be plain, unique and not one core serves, so no add-on shadows a core route or hides from dispatch. */
|
|
12
|
+
export function assertAddonRoutes(routes) {
|
|
13
|
+
const seen = new Set();
|
|
14
|
+
for (const { path } of routes) {
|
|
15
|
+
if (!isPlainV1Path(path))
|
|
16
|
+
throw new Error(`add-on route '${path}' is not a plain /v1/ path (segments use A-Z a-z 0-9 . _ ~ -)`);
|
|
17
|
+
if (seen.has(path))
|
|
18
|
+
throw new Error(`add-on route '${path}' is registered twice`);
|
|
19
|
+
if (isCorePath('POST', path))
|
|
20
|
+
throw new Error(`add-on route '${path}' is already served by core`);
|
|
21
|
+
seen.add(path);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
const PUBLIC_JSON_MAX_BYTES = 64 * 1024;
|
|
25
|
+
/** Boot-time check and serialization: a public path that a core GET route serves would open that route to anyone. */
|
|
26
|
+
export function assertPublicJson(publicJson) {
|
|
27
|
+
const bodies = new Map();
|
|
28
|
+
for (const [path, value] of Object.entries(publicJson)) {
|
|
29
|
+
if (!isPlainV1Path(path))
|
|
30
|
+
throw new Error(`public JSON path '${path}' is not a plain /v1/ path (segments use A-Z a-z 0-9 . _ ~ -)`);
|
|
31
|
+
if (isCorePath('GET', path))
|
|
32
|
+
throw new Error(`public JSON path '${path}' is already served by core`);
|
|
33
|
+
const text = JSON.stringify(value);
|
|
34
|
+
if (text === undefined)
|
|
35
|
+
throw new Error(`public JSON at '${path}' is not JSON`);
|
|
36
|
+
if (Buffer.byteLength(text) > PUBLIC_JSON_MAX_BYTES)
|
|
37
|
+
throw new Error(`public JSON at '${path}' is over 64 KiB`);
|
|
38
|
+
bodies.set(path, text);
|
|
39
|
+
}
|
|
40
|
+
return bodies;
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=route-checks.js.map
|
|
@@ -1,15 +1,16 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
3
|
-
|
|
1
|
+
import type { Route, RouteRequest } from './types.js';
|
|
2
|
+
/** The /v1 routes in dispatch order; the first entry whose method and path match handles the request. Each row's `auth` is what the
|
|
3
|
+
* dispatch gate proves before its handler runs, so a handler never checks the caller itself. */
|
|
4
|
+
export declare const V1_ROUTES: readonly Route[];
|
|
5
|
+
/** The route's run for this request, gate first, or null when method or path differ. The matcher runs before the method check,
|
|
6
|
+
* as the inline route blocks did, so a malformed `%` escape still throws from matchPath on any method. */
|
|
7
|
+
export declare function routeMatches(route: Route, method: string, path: string): ((r: RouteRequest) => Promise<void>) | null;
|
|
8
|
+
/** The route as the access line names it; a regex route reads as its pattern would, so no line carries a caller's id. */
|
|
9
|
+
export declare function routeLabel(route: Route): string;
|
|
4
10
|
/** Run the first /v1 route whose method and path match. */
|
|
5
11
|
export declare function dispatchV1Route(r: RouteRequest, method: string, path: string): Promise<boolean>;
|
|
6
|
-
/** Boot-time check: an add-on path must be plain, unique and not one core serves, so no add-on shadows a core route or hides from dispatch. */
|
|
7
|
-
export declare function assertAddonRoutes(routes: readonly AddonRoute[]): void;
|
|
8
|
-
/** Boot-time check and serialization: a public path that a core GET route serves would open that route to anyone. */
|
|
9
|
-
export declare function assertPublicJson(publicJson: Readonly<Record<string, JsonValue>>): ReadonlyMap<string, string>;
|
|
10
12
|
/** Core authenticates and parses before the handler runs, so an add-on route gets the same 401, 400 and 501 as a core one. */
|
|
11
13
|
export declare function dispatchAddonRoute({ req, res, opts }: RouteRequest, method: string, path: string): Promise<boolean>;
|
|
12
14
|
/** No auth, body read or store access, so a caller with no key gets it under any store. */
|
|
13
15
|
export declare function dispatchPublicJson({ req, res, opts }: RouteRequest, method: string, path: string): boolean;
|
|
14
|
-
export declare function assertSqliteStore(opts: ResolvedServeOpts): void;
|
|
15
16
|
//# sourceMappingURL=route-table.d.ts.map
|