@atomicmemory/core 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +27 -0
- package/LICENSE +201 -0
- package/README.md +314 -0
- package/dist/app/bind-ephemeral.d.ts +18 -0
- package/dist/app/bind-ephemeral.js +22 -0
- package/dist/app/cors-headers.d.ts +12 -0
- package/dist/app/cors-headers.js +18 -0
- package/dist/app/create-app.d.ts +25 -0
- package/dist/app/create-app.js +156 -0
- package/dist/app/runtime-config-route-snapshot.d.ts +27 -0
- package/dist/app/runtime-config-route-snapshot.js +27 -0
- package/dist/app/runtime-container.d.ts +281 -0
- package/dist/app/runtime-container.js +297 -0
- package/dist/app/startup-checks.d.ts +28 -0
- package/dist/app/startup-checks.js +45 -0
- package/dist/bin.d.ts +17 -0
- package/dist/bin.js +128 -0
- package/dist/config.d.ts +680 -0
- package/dist/config.js +808 -0
- package/dist/db/agent-trust-repository.d.ts +49 -0
- package/dist/db/agent-trust-repository.js +66 -0
- package/dist/db/belief-edges-repository.d.ts +68 -0
- package/dist/db/belief-edges-repository.js +124 -0
- package/dist/db/claim-repository.d.ts +6 -0
- package/dist/db/claim-repository.js +4 -0
- package/dist/db/contradictions-repository.d.ts +56 -0
- package/dist/db/contradictions-repository.js +88 -0
- package/dist/db/document-chunk-repository.d.ts +48 -0
- package/dist/db/document-chunk-repository.js +145 -0
- package/dist/db/document-chunk-types.d.ts +35 -0
- package/dist/db/document-chunk-types.js +9 -0
- package/dist/db/document-list-cursor.d.ts +45 -0
- package/dist/db/document-list-cursor.js +111 -0
- package/dist/db/document-list-repository.d.ts +103 -0
- package/dist/db/document-list-repository.js +204 -0
- package/dist/db/entity-cards-repository.d.ts +37 -0
- package/dist/db/entity-cards-repository.js +46 -0
- package/dist/db/entity-values-repository.d.ts +26 -0
- package/dist/db/entity-values-repository.js +57 -0
- package/dist/db/link-repository.d.ts +30 -0
- package/dist/db/link-repository.js +54 -0
- package/dist/db/memory-repository.d.ts +163 -0
- package/dist/db/memory-repository.js +232 -0
- package/dist/db/migrate.d.ts +6 -0
- package/dist/db/migrate.js +36 -0
- package/dist/db/mmr.d.ts +14 -0
- package/dist/db/mmr.js +57 -0
- package/dist/db/passport-feed-repository.d.ts +91 -0
- package/dist/db/passport-feed-repository.js +198 -0
- package/dist/db/pg-episode-store.d.ts +19 -0
- package/dist/db/pg-episode-store.js +17 -0
- package/dist/db/pg-link-store.d.ts +17 -0
- package/dist/db/pg-link-store.js +14 -0
- package/dist/db/pg-memory-store.d.ts +68 -0
- package/dist/db/pg-memory-store.js +53 -0
- package/dist/db/pg-recap-store.d.ts +13 -0
- package/dist/db/pg-recap-store.js +19 -0
- package/dist/db/pg-representation-store.d.ts +17 -0
- package/dist/db/pg-representation-store.js +17 -0
- package/dist/db/pg-search-store.d.ts +29 -0
- package/dist/db/pg-search-store.js +47 -0
- package/dist/db/pool.d.ts +5 -0
- package/dist/db/pool.js +21 -0
- package/dist/db/ppr.d.ts +56 -0
- package/dist/db/ppr.js +178 -0
- package/dist/db/query-helpers.d.ts +44 -0
- package/dist/db/query-helpers.js +60 -0
- package/dist/db/raw-doc-artifact-sync.d.ts +128 -0
- package/dist/db/raw-doc-artifact-sync.js +259 -0
- package/dist/db/raw-document-blob-repository.d.ts +148 -0
- package/dist/db/raw-document-blob-repository.js +300 -0
- package/dist/db/raw-document-repository.d.ts +104 -0
- package/dist/db/raw-document-repository.js +410 -0
- package/dist/db/raw-document-status-repository.d.ts +122 -0
- package/dist/db/raw-document-status-repository.js +183 -0
- package/dist/db/raw-document-types.d.ts +236 -0
- package/dist/db/raw-document-types.js +10 -0
- package/dist/db/raw-storage-reconciliation-repository.d.ts +110 -0
- package/dist/db/raw-storage-reconciliation-repository.js +200 -0
- package/dist/db/reflection-jobs-repository.d.ts +33 -0
- package/dist/db/reflection-jobs-repository.js +48 -0
- package/dist/db/reflections-repository.d.ts +41 -0
- package/dist/db/reflections-repository.js +83 -0
- package/dist/db/repository-claims.d.ts +141 -0
- package/dist/db/repository-claims.js +376 -0
- package/dist/db/repository-deferred-audn.d.ts +33 -0
- package/dist/db/repository-deferred-audn.js +69 -0
- package/dist/db/repository-document-delete.d.ts +53 -0
- package/dist/db/repository-document-delete.js +156 -0
- package/dist/db/repository-entities.d.ts +114 -0
- package/dist/db/repository-entities.js +317 -0
- package/dist/db/repository-entity-attributes.d.ts +41 -0
- package/dist/db/repository-entity-attributes.js +65 -0
- package/dist/db/repository-entity-graph.d.ts +32 -0
- package/dist/db/repository-entity-graph.js +87 -0
- package/dist/db/repository-first-mentions.d.ts +41 -0
- package/dist/db/repository-first-mentions.js +79 -0
- package/dist/db/repository-lessons.d.ts +51 -0
- package/dist/db/repository-lessons.js +90 -0
- package/dist/db/repository-links.d.ts +26 -0
- package/dist/db/repository-links.js +105 -0
- package/dist/db/repository-observation.d.ts +26 -0
- package/dist/db/repository-observation.js +51 -0
- package/dist/db/repository-read.d.ts +56 -0
- package/dist/db/repository-read.js +271 -0
- package/dist/db/repository-recaps.d.ts +59 -0
- package/dist/db/repository-recaps.js +158 -0
- package/dist/db/repository-representations.d.ts +48 -0
- package/dist/db/repository-representations.js +162 -0
- package/dist/db/repository-temporal-state.d.ts +35 -0
- package/dist/db/repository-temporal-state.js +46 -0
- package/dist/db/repository-tll.d.ts +88 -0
- package/dist/db/repository-tll.js +179 -0
- package/dist/db/repository-types.d.ts +313 -0
- package/dist/db/repository-types.js +142 -0
- package/dist/db/repository-user-profiles.d.ts +17 -0
- package/dist/db/repository-user-profiles.js +28 -0
- package/dist/db/repository-vector-search.d.ts +33 -0
- package/dist/db/repository-vector-search.js +373 -0
- package/dist/db/repository-wipe.d.ts +34 -0
- package/dist/db/repository-wipe.js +94 -0
- package/dist/db/repository-write.d.ts +61 -0
- package/dist/db/repository-write.js +279 -0
- package/dist/db/schema.sql +1355 -0
- package/dist/db/storage-artifact-delete-tx.d.ts +56 -0
- package/dist/db/storage-artifact-delete-tx.js +123 -0
- package/dist/db/storage-artifact-providers.d.ts +21 -0
- package/dist/db/storage-artifact-providers.js +21 -0
- package/dist/db/storage-artifact-recovery-repository.d.ts +66 -0
- package/dist/db/storage-artifact-recovery-repository.js +58 -0
- package/dist/db/storage-artifact-repository.d.ts +329 -0
- package/dist/db/storage-artifact-repository.js +497 -0
- package/dist/db/stores.d.ts +220 -0
- package/dist/db/stores.js +12 -0
- package/dist/db/summaries-repository.d.ts +74 -0
- package/dist/db/summaries-repository.js +125 -0
- package/dist/eval/beam-10m-loader.d.ts +98 -0
- package/dist/eval/beam-10m-loader.js +128 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.js +17 -0
- package/dist/middleware/require-bearer.d.ts +27 -0
- package/dist/middleware/require-bearer.js +60 -0
- package/dist/middleware/validate-response.d.ts +33 -0
- package/dist/middleware/validate-response.js +55 -0
- package/dist/middleware/validate.d.ts +43 -0
- package/dist/middleware/validate.js +85 -0
- package/dist/routes/agents.d.ts +13 -0
- package/dist/routes/agents.js +89 -0
- package/dist/routes/document-response-formatters.d.ts +98 -0
- package/dist/routes/document-response-formatters.js +243 -0
- package/dist/routes/documents.d.ts +74 -0
- package/dist/routes/documents.js +425 -0
- package/dist/routes/memories.d.ts +29 -0
- package/dist/routes/memories.js +725 -0
- package/dist/routes/memory-response-formatters.d.ts +179 -0
- package/dist/routes/memory-response-formatters.js +210 -0
- package/dist/routes/public-raw-storage-metadata.d.ts +54 -0
- package/dist/routes/public-raw-storage-metadata.js +56 -0
- package/dist/routes/reflect.d.ts +14 -0
- package/dist/routes/reflect.js +19 -0
- package/dist/routes/response-schema-map.d.ts +14 -0
- package/dist/routes/response-schema-map.js +69 -0
- package/dist/routes/route-errors.d.ts +12 -0
- package/dist/routes/route-errors.js +30 -0
- package/dist/routes/storage-error-handlers.d.ts +34 -0
- package/dist/routes/storage-error-handlers.js +185 -0
- package/dist/routes/storage-response-formatters.d.ts +44 -0
- package/dist/routes/storage-response-formatters.js +155 -0
- package/dist/routes/storage.d.ts +38 -0
- package/dist/routes/storage.js +369 -0
- package/dist/routes/upstream-provider-errors.d.ts +19 -0
- package/dist/routes/upstream-provider-errors.js +95 -0
- package/dist/schemas/agents.d.ts +79 -0
- package/dist/schemas/agents.js +126 -0
- package/dist/schemas/common.d.ts +110 -0
- package/dist/schemas/common.js +190 -0
- package/dist/schemas/document-list-responses.d.ts +102 -0
- package/dist/schemas/document-list-responses.js +87 -0
- package/dist/schemas/document-list-schemas.d.ts +123 -0
- package/dist/schemas/document-list-schemas.js +174 -0
- package/dist/schemas/document-response-schemas.d.ts +610 -0
- package/dist/schemas/document-response-schemas.js +264 -0
- package/dist/schemas/document-status-envelope.d.ts +48 -0
- package/dist/schemas/document-status-envelope.js +54 -0
- package/dist/schemas/documents.d.ts +292 -0
- package/dist/schemas/documents.js +449 -0
- package/dist/schemas/errors.d.ts +75 -0
- package/dist/schemas/errors.js +105 -0
- package/dist/schemas/memories.d.ts +378 -0
- package/dist/schemas/memories.js +542 -0
- package/dist/schemas/openapi.d.ts +24 -0
- package/dist/schemas/openapi.js +1038 -0
- package/dist/schemas/response-scalars.d.ts +10 -0
- package/dist/schemas/response-scalars.js +10 -0
- package/dist/schemas/responses.d.ts +536 -0
- package/dist/schemas/responses.js +350 -0
- package/dist/schemas/search-response-parts.d.ts +97 -0
- package/dist/schemas/search-response-parts.js +103 -0
- package/dist/schemas/storage-schemas.d.ts +175 -0
- package/dist/schemas/storage-schemas.js +277 -0
- package/dist/schemas/zod-setup.d.ts +15 -0
- package/dist/schemas/zod-setup.js +17 -0
- package/dist/server.d.ts +13 -0
- package/dist/server.js +57 -0
- package/dist/services/abstract-query-policy.d.ts +13 -0
- package/dist/services/abstract-query-policy.js +50 -0
- package/dist/services/affinity-clustering.d.ts +66 -0
- package/dist/services/affinity-clustering.js +125 -0
- package/dist/services/agentic-retrieval.d.ts +38 -0
- package/dist/services/agentic-retrieval.js +126 -0
- package/dist/services/answer-format.d.ts +56 -0
- package/dist/services/answer-format.js +118 -0
- package/dist/services/answer-rescue.d.ts +72 -0
- package/dist/services/answer-rescue.js +177 -0
- package/dist/services/answer-verifier.d.ts +24 -0
- package/dist/services/answer-verifier.js +73 -0
- package/dist/services/api-retry.d.ts +6 -0
- package/dist/services/api-retry.js +41 -0
- package/dist/services/assistant-turn-filter.d.ts +20 -0
- package/dist/services/assistant-turn-filter.js +69 -0
- package/dist/services/atomicmem-uri.d.ts +33 -0
- package/dist/services/atomicmem-uri.js +86 -0
- package/dist/services/audit-events.d.ts +54 -0
- package/dist/services/audit-events.js +56 -0
- package/dist/services/chunked-extraction.d.ts +21 -0
- package/dist/services/chunked-extraction.js +108 -0
- package/dist/services/claim-slotting.d.ts +27 -0
- package/dist/services/claim-slotting.js +38 -0
- package/dist/services/claude-code-llm.d.ts +19 -0
- package/dist/services/claude-code-llm.js +96 -0
- package/dist/services/composite-dedup.d.ts +50 -0
- package/dist/services/composite-dedup.js +153 -0
- package/dist/services/composite-grouping.d.ts +41 -0
- package/dist/services/composite-grouping.js +111 -0
- package/dist/services/composite-staleness.d.ts +20 -0
- package/dist/services/composite-staleness.js +50 -0
- package/dist/services/conciseness-preference.d.ts +14 -0
- package/dist/services/conciseness-preference.js +42 -0
- package/dist/services/conflict-policy.d.ts +20 -0
- package/dist/services/conflict-policy.js +335 -0
- package/dist/services/consensus-extraction.d.ts +39 -0
- package/dist/services/consensus-extraction.js +147 -0
- package/dist/services/consensus-validation.d.ts +52 -0
- package/dist/services/consensus-validation.js +206 -0
- package/dist/services/consolidation-service.d.ts +60 -0
- package/dist/services/consolidation-service.js +171 -0
- package/dist/services/content-detection.d.ts +18 -0
- package/dist/services/content-detection.js +25 -0
- package/dist/services/contradiction-surfacing.d.ts +62 -0
- package/dist/services/contradiction-surfacing.js +111 -0
- package/dist/services/cost-telemetry.d.ts +39 -0
- package/dist/services/cost-telemetry.js +58 -0
- package/dist/services/counter-evidence.d.ts +34 -0
- package/dist/services/counter-evidence.js +92 -0
- package/dist/services/current-state-ranking.d.ts +21 -0
- package/dist/services/current-state-ranking.js +152 -0
- package/dist/services/deferred-audn.d.ts +47 -0
- package/dist/services/deferred-audn.js +162 -0
- package/dist/services/document-chunker.d.ts +50 -0
- package/dist/services/document-chunker.js +153 -0
- package/dist/services/document-failure-markers.d.ts +91 -0
- package/dist/services/document-failure-markers.js +305 -0
- package/dist/services/document-indexer.d.ts +122 -0
- package/dist/services/document-indexer.js +405 -0
- package/dist/services/document-service.d.ts +245 -0
- package/dist/services/document-service.js +325 -0
- package/dist/services/document-upload-artifact-sync.d.ts +80 -0
- package/dist/services/document-upload-artifact-sync.js +162 -0
- package/dist/services/document-upload-beta2-recovery.d.ts +72 -0
- package/dist/services/document-upload-beta2-recovery.js +94 -0
- package/dist/services/document-upload.d.ts +44 -0
- package/dist/services/document-upload.js +353 -0
- package/dist/services/embedding.d.ts +57 -0
- package/dist/services/embedding.js +416 -0
- package/dist/services/entity-attribute-extractor.d.ts +34 -0
- package/dist/services/entity-attribute-extractor.js +117 -0
- package/dist/services/entity-card-synthesis.d.ts +54 -0
- package/dist/services/entity-card-synthesis.js +92 -0
- package/dist/services/entity-dedup.d.ts +9 -0
- package/dist/services/entity-dedup.js +14 -0
- package/dist/services/entity-graph.d.ts +17 -0
- package/dist/services/entity-graph.js +135 -0
- package/dist/services/entropy-gate.d.ts +52 -0
- package/dist/services/entropy-gate.js +56 -0
- package/dist/services/episode-fetcher.d.ts +47 -0
- package/dist/services/episode-fetcher.js +128 -0
- package/dist/services/event-anchor-facts.d.ts +8 -0
- package/dist/services/event-anchor-facts.js +205 -0
- package/dist/services/event-chain-detector.d.ts +52 -0
- package/dist/services/event-chain-detector.js +83 -0
- package/dist/services/extraction-cache.d.ts +9 -0
- package/dist/services/extraction-cache.js +54 -0
- package/dist/services/extraction-enrichment.d.ts +9 -0
- package/dist/services/extraction-enrichment.js +223 -0
- package/dist/services/extraction.d.ts +69 -0
- package/dist/services/extraction.js +596 -0
- package/dist/services/fact-normalization.d.ts +12 -0
- package/dist/services/fact-normalization.js +248 -0
- package/dist/services/filecoin-observability.d.ts +127 -0
- package/dist/services/filecoin-observability.js +200 -0
- package/dist/services/first-mention-service.d.ts +76 -0
- package/dist/services/first-mention-service.js +186 -0
- package/dist/services/hierarchical-retrieval.d.ts +49 -0
- package/dist/services/hierarchical-retrieval.js +50 -0
- package/dist/services/ingest-fact-pipeline.d.ts +32 -0
- package/dist/services/ingest-fact-pipeline.js +212 -0
- package/dist/services/ingest-post-write.d.ts +50 -0
- package/dist/services/ingest-post-write.js +117 -0
- package/dist/services/ingest-trace.d.ts +32 -0
- package/dist/services/ingest-trace.js +60 -0
- package/dist/services/input-sanitizer.d.ts +41 -0
- package/dist/services/input-sanitizer.js +135 -0
- package/dist/services/iterative-retrieval.d.ts +26 -0
- package/dist/services/iterative-retrieval.js +139 -0
- package/dist/services/keyword-expansion.d.ts +10 -0
- package/dist/services/keyword-expansion.js +26 -0
- package/dist/services/lesson-service.d.ts +68 -0
- package/dist/services/lesson-service.js +178 -0
- package/dist/services/literal-extractor.d.ts +16 -0
- package/dist/services/literal-extractor.js +74 -0
- package/dist/services/literal-list-protection.d.ts +17 -0
- package/dist/services/literal-list-protection.js +134 -0
- package/dist/services/literal-query-expansion.d.ts +20 -0
- package/dist/services/literal-query-expansion.js +181 -0
- package/dist/services/llm.d.ts +61 -0
- package/dist/services/llm.js +265 -0
- package/dist/services/memcell-projection.d.ts +17 -0
- package/dist/services/memcell-projection.js +41 -0
- package/dist/services/memory-audn.d.ts +43 -0
- package/dist/services/memory-audn.js +419 -0
- package/dist/services/memory-crud.d.ts +93 -0
- package/dist/services/memory-crud.js +255 -0
- package/dist/services/memory-ingest.d.ts +21 -0
- package/dist/services/memory-ingest.js +249 -0
- package/dist/services/memory-lifecycle.d.ts +75 -0
- package/dist/services/memory-lifecycle.js +108 -0
- package/dist/services/memory-lineage.d.ts +181 -0
- package/dist/services/memory-lineage.js +232 -0
- package/dist/services/memory-network.d.ts +40 -0
- package/dist/services/memory-network.js +75 -0
- package/dist/services/memory-search-types.d.ts +25 -0
- package/dist/services/memory-search-types.js +10 -0
- package/dist/services/memory-search.d.ts +48 -0
- package/dist/services/memory-search.js +505 -0
- package/dist/services/memory-service-types.d.ts +371 -0
- package/dist/services/memory-service-types.js +8 -0
- package/dist/services/memory-service.d.ts +152 -0
- package/dist/services/memory-service.js +225 -0
- package/dist/services/memory-storage.d.ts +33 -0
- package/dist/services/memory-storage.js +328 -0
- package/dist/services/msr-aggregator.d.ts +38 -0
- package/dist/services/msr-aggregator.js +97 -0
- package/dist/services/msr-detector.d.ts +35 -0
- package/dist/services/msr-detector.js +65 -0
- package/dist/services/namespace-retrieval.d.ts +60 -0
- package/dist/services/namespace-retrieval.js +180 -0
- package/dist/services/observation-date-extraction.d.ts +12 -0
- package/dist/services/observation-date-extraction.js +50 -0
- package/dist/services/observation-service.d.ts +27 -0
- package/dist/services/observation-service.js +84 -0
- package/dist/services/packaging-observability.d.ts +29 -0
- package/dist/services/packaging-observability.js +146 -0
- package/dist/services/query-expansion.d.ts +83 -0
- package/dist/services/query-expansion.js +242 -0
- package/dist/services/query-keyword-matches.d.ts +6 -0
- package/dist/services/query-keyword-matches.js +56 -0
- package/dist/services/query-term-visibility.d.ts +28 -0
- package/dist/services/query-term-visibility.js +100 -0
- package/dist/services/quick-extraction.d.ts +25 -0
- package/dist/services/quick-extraction.js +431 -0
- package/dist/services/quoted-entity-extraction.d.ts +10 -0
- package/dist/services/quoted-entity-extraction.js +161 -0
- package/dist/services/raw-storage-reconciler-backoff.d.ts +8 -0
- package/dist/services/raw-storage-reconciler-backoff.js +14 -0
- package/dist/services/raw-storage-reconciler-scheduler.d.ts +29 -0
- package/dist/services/raw-storage-reconciler-scheduler.js +43 -0
- package/dist/services/raw-storage-reconciler.d.ts +71 -0
- package/dist/services/raw-storage-reconciler.js +278 -0
- package/dist/services/recap-builder.d.ts +49 -0
- package/dist/services/recap-builder.js +157 -0
- package/dist/services/reflect-jobs.d.ts +23 -0
- package/dist/services/reflect-jobs.js +36 -0
- package/dist/services/reflect-prompts.d.ts +71 -0
- package/dist/services/reflect-prompts.js +99 -0
- package/dist/services/reflect-retrieval.d.ts +33 -0
- package/dist/services/reflect-retrieval.js +30 -0
- package/dist/services/reflect.d.ts +49 -0
- package/dist/services/reflect.js +84 -0
- package/dist/services/relative-temporal.d.ts +14 -0
- package/dist/services/relative-temporal.js +163 -0
- package/dist/services/relevance-policy.d.ts +37 -0
- package/dist/services/relevance-policy.js +109 -0
- package/dist/services/rerank.d.ts +32 -0
- package/dist/services/rerank.js +118 -0
- package/dist/services/reranker.d.ts +20 -0
- package/dist/services/reranker.js +99 -0
- package/dist/services/retrieval-channel-rules.d.ts +34 -0
- package/dist/services/retrieval-channel-rules.js +41 -0
- package/dist/services/retrieval-config-overlay.d.ts +36 -0
- package/dist/services/retrieval-config-overlay.js +44 -0
- package/dist/services/retrieval-format.d.ts +119 -0
- package/dist/services/retrieval-format.js +559 -0
- package/dist/services/retrieval-policy.d.ts +69 -0
- package/dist/services/retrieval-policy.js +275 -0
- package/dist/services/retrieval-profiles.d.ts +37 -0
- package/dist/services/retrieval-profiles.js +90 -0
- package/dist/services/retrieval-side-effects.d.ts +14 -0
- package/dist/services/retrieval-side-effects.js +26 -0
- package/dist/services/retrieval-trace.d.ts +108 -0
- package/dist/services/retrieval-trace.js +147 -0
- package/dist/services/rrf-fusion.d.ts +18 -0
- package/dist/services/rrf-fusion.js +34 -0
- package/dist/services/search-pipeline.d.ts +71 -0
- package/dist/services/search-pipeline.js +788 -0
- package/dist/services/session-date.d.ts +20 -0
- package/dist/services/session-date.js +61 -0
- package/dist/services/session-packaging.d.ts +53 -0
- package/dist/services/session-packaging.js +182 -0
- package/dist/services/session-summary-generator.d.ts +53 -0
- package/dist/services/session-summary-generator.js +134 -0
- package/dist/services/specialists/cr-specialist.d.ts +52 -0
- package/dist/services/specialists/cr-specialist.js +121 -0
- package/dist/services/specialists/dispatch.d.ts +53 -0
- package/dist/services/specialists/dispatch.js +102 -0
- package/dist/services/specialists/ie-ku-specialist.d.ts +37 -0
- package/dist/services/specialists/ie-ku-specialist.js +63 -0
- package/dist/services/specialists/msr-specialist.d.ts +61 -0
- package/dist/services/specialists/msr-specialist.js +162 -0
- package/dist/services/specialists/tr-specialist.d.ts +37 -0
- package/dist/services/specialists/tr-specialist.js +146 -0
- package/dist/services/storage-key-prefix.d.ts +42 -0
- package/dist/services/storage-key-prefix.js +45 -0
- package/dist/services/storage-put-recovery.d.ts +71 -0
- package/dist/services/storage-put-recovery.js +269 -0
- package/dist/services/storage-service-errors.d.ts +124 -0
- package/dist/services/storage-service-errors.js +189 -0
- package/dist/services/storage-service.d.ts +176 -0
- package/dist/services/storage-service.js +423 -0
- package/dist/services/subject-aware-ranking.d.ts +19 -0
- package/dist/services/subject-aware-ranking.js +161 -0
- package/dist/services/supplemental-extraction.d.ts +7 -0
- package/dist/services/supplemental-extraction.js +116 -0
- package/dist/services/tbc-execution.d.ts +49 -0
- package/dist/services/tbc-execution.js +284 -0
- package/dist/services/temporal-classifier.d.ts +56 -0
- package/dist/services/temporal-classifier.js +94 -0
- package/dist/services/temporal-endpoint-evidence.d.ts +12 -0
- package/dist/services/temporal-endpoint-evidence.js +313 -0
- package/dist/services/temporal-fingerprint.d.ts +6 -0
- package/dist/services/temporal-fingerprint.js +12 -0
- package/dist/services/temporal-format.d.ts +9 -0
- package/dist/services/temporal-format.js +21 -0
- package/dist/services/temporal-intent.d.ts +39 -0
- package/dist/services/temporal-intent.js +78 -0
- package/dist/services/temporal-query-constraints.d.ts +16 -0
- package/dist/services/temporal-query-constraints.js +107 -0
- package/dist/services/temporal-query-expansion.d.ts +14 -0
- package/dist/services/temporal-query-expansion.js +131 -0
- package/dist/services/temporal-rerank.d.ts +22 -0
- package/dist/services/temporal-rerank.js +47 -0
- package/dist/services/temporal-result-protection.d.ts +7 -0
- package/dist/services/temporal-result-protection.js +60 -0
- package/dist/services/temporal-state-write.d.ts +57 -0
- package/dist/services/temporal-state-write.js +45 -0
- package/dist/services/tiered-context.d.ts +87 -0
- package/dist/services/tiered-context.js +214 -0
- package/dist/services/tiered-loading.d.ts +88 -0
- package/dist/services/tiered-loading.js +263 -0
- package/dist/services/timeline-pack.d.ts +36 -0
- package/dist/services/timeline-pack.js +50 -0
- package/dist/services/timing.d.ts +13 -0
- package/dist/services/timing.js +72 -0
- package/dist/services/tll-augmentation.d.ts +20 -0
- package/dist/services/tll-augmentation.js +125 -0
- package/dist/services/tll-retrieval.d.ts +55 -0
- package/dist/services/tll-retrieval.js +101 -0
- package/dist/services/topic-abstraction.d.ts +36 -0
- package/dist/services/topic-abstraction.js +105 -0
- package/dist/services/trust-scoring.d.ts +43 -0
- package/dist/services/trust-scoring.js +89 -0
- package/dist/services/typed-belief-calculus.d.ts +126 -0
- package/dist/services/typed-belief-calculus.js +204 -0
- package/dist/services/upload-config.d.ts +34 -0
- package/dist/services/upload-config.js +23 -0
- package/dist/services/upload-decision.d.ts +65 -0
- package/dist/services/upload-decision.js +98 -0
- package/dist/services/upload-helpers.d.ts +107 -0
- package/dist/services/upload-helpers.js +148 -0
- package/dist/services/user-profile-builder.d.ts +22 -0
- package/dist/services/user-profile-builder.js +109 -0
- package/dist/services/voyage-embedding.d.ts +22 -0
- package/dist/services/voyage-embedding.js +77 -0
- package/dist/services/write-security.d.ts +31 -0
- package/dist/services/write-security.js +64 -0
- package/dist/storage/artifact-public-redaction.d.ts +34 -0
- package/dist/storage/artifact-public-redaction.js +83 -0
- package/dist/storage/cleanup.d.ts +103 -0
- package/dist/storage/cleanup.js +138 -0
- package/dist/storage/codec-factory.d.ts +17 -0
- package/dist/storage/codec-factory.js +33 -0
- package/dist/storage/codecs/aes-gcm-codec.d.ts +44 -0
- package/dist/storage/codecs/aes-gcm-codec.js +108 -0
- package/dist/storage/codecs/noop-codec.d.ts +16 -0
- package/dist/storage/codecs/noop-codec.js +23 -0
- package/dist/storage/factory.d.ts +44 -0
- package/dist/storage/factory.js +99 -0
- package/dist/storage/filecoin-cid-validation.d.ts +82 -0
- package/dist/storage/filecoin-cid-validation.js +122 -0
- package/dist/storage/filecoin-public-metadata.d.ts +73 -0
- package/dist/storage/filecoin-public-metadata.js +110 -0
- package/dist/storage/local-fs-store.d.ts +39 -0
- package/dist/storage/local-fs-store.js +145 -0
- package/dist/storage/pointer-uri-allowlist.d.ts +38 -0
- package/dist/storage/pointer-uri-allowlist.js +70 -0
- package/dist/storage/provider-metadata-projection.d.ts +27 -0
- package/dist/storage/provider-metadata-projection.js +68 -0
- package/dist/storage/providers/filecoin/backend.d.ts +42 -0
- package/dist/storage/providers/filecoin/backend.js +250 -0
- package/dist/storage/providers/filecoin/config.d.ts +70 -0
- package/dist/storage/providers/filecoin/config.js +275 -0
- package/dist/storage/providers/filecoin/errors.d.ts +45 -0
- package/dist/storage/providers/filecoin/errors.js +56 -0
- package/dist/storage/providers/filecoin/filecoin-pin-car.d.ts +78 -0
- package/dist/storage/providers/filecoin/filecoin-pin-car.js +155 -0
- package/dist/storage/providers/filecoin/filecoin-pin-client.d.ts +92 -0
- package/dist/storage/providers/filecoin/filecoin-pin-client.js +199 -0
- package/dist/storage/providers/filecoin/filecoin-pin-mapping.d.ts +58 -0
- package/dist/storage/providers/filecoin/filecoin-pin-mapping.js +103 -0
- package/dist/storage/providers/filecoin/filecoin-pin-timeout.d.ts +30 -0
- package/dist/storage/providers/filecoin/filecoin-pin-timeout.js +53 -0
- package/dist/storage/providers/filecoin/filecoin-pin-vendor.d.ts +111 -0
- package/dist/storage/providers/filecoin/filecoin-pin-vendor.js +87 -0
- package/dist/storage/providers/filecoin/hints.d.ts +71 -0
- package/dist/storage/providers/filecoin/hints.js +123 -0
- package/dist/storage/providers/filecoin/index.d.ts +51 -0
- package/dist/storage/providers/filecoin/index.js +103 -0
- package/dist/storage/providers/filecoin/ipfs-cid.d.ts +50 -0
- package/dist/storage/providers/filecoin/ipfs-cid.js +64 -0
- package/dist/storage/providers/filecoin/metadata.d.ts +72 -0
- package/dist/storage/providers/filecoin/metadata.js +137 -0
- package/dist/storage/providers/filecoin/piece-cid.d.ts +48 -0
- package/dist/storage/providers/filecoin/piece-cid.js +57 -0
- package/dist/storage/providers/filecoin/provider-client.d.ts +234 -0
- package/dist/storage/providers/filecoin/provider-client.js +27 -0
- package/dist/storage/providers/filecoin/readiness.d.ts +62 -0
- package/dist/storage/providers/filecoin/readiness.js +85 -0
- package/dist/storage/providers/filecoin/retriever.d.ts +82 -0
- package/dist/storage/providers/filecoin/retriever.js +63 -0
- package/dist/storage/providers/filecoin/skeleton-client.d.ts +36 -0
- package/dist/storage/providers/filecoin/skeleton-client.js +55 -0
- package/dist/storage/providers/filecoin/synapse-client.d.ts +169 -0
- package/dist/storage/providers/filecoin/synapse-client.js +343 -0
- package/dist/storage/providers/filecoin/synapse-construction.d.ts +26 -0
- package/dist/storage/providers/filecoin/synapse-construction.js +47 -0
- package/dist/storage/providers/filecoin/synapse-error-mapping.d.ts +23 -0
- package/dist/storage/providers/filecoin/synapse-error-mapping.js +49 -0
- package/dist/storage/providers/filecoin/synapse-readiness.d.ts +37 -0
- package/dist/storage/providers/filecoin/synapse-readiness.js +231 -0
- package/dist/storage/providers/filecoin/uri.d.ts +49 -0
- package/dist/storage/providers/filecoin/uri.js +84 -0
- package/dist/storage/providers/filecoin/verified-fetch-lifecycle.d.ts +77 -0
- package/dist/storage/providers/filecoin/verified-fetch-lifecycle.js +196 -0
- package/dist/storage/providers/filecoin/verified-fetch-retriever.d.ts +54 -0
- package/dist/storage/providers/filecoin/verified-fetch-retriever.js +81 -0
- package/dist/storage/providers/filecoin/verified-fetch-vendor.d.ts +71 -0
- package/dist/storage/providers/filecoin/verified-fetch-vendor.js +94 -0
- package/dist/storage/raw-content-codec.d.ts +89 -0
- package/dist/storage/raw-content-codec.js +47 -0
- package/dist/storage/raw-content-store-backend-adapter.d.ts +28 -0
- package/dist/storage/raw-content-store-backend-adapter.js +67 -0
- package/dist/storage/raw-content-store.d.ts +228 -0
- package/dist/storage/raw-content-store.js +27 -0
- package/dist/storage/s3-store.d.ts +42 -0
- package/dist/storage/s3-store.js +181 -0
- package/dist/storage/storage-backend-registry.d.ts +58 -0
- package/dist/storage/storage-backend-registry.js +56 -0
- package/dist/storage/storage-backend.d.ts +82 -0
- package/dist/storage/storage-backend.js +14 -0
- package/dist/storage/storage-capabilities.d.ts +56 -0
- package/dist/storage/storage-capabilities.js +170 -0
- package/dist/storage/store-registry.d.ts +67 -0
- package/dist/storage/store-registry.js +77 -0
- package/dist/vector-math.d.ts +15 -0
- package/dist/vector-math.js +31 -0
- package/dist/xml-escape.d.ts +5 -0
- package/dist/xml-escape.js +7 -0
- package/openapi.json +15395 -0
- package/openapi.yaml +10794 -0
- package/package.json +119 -0
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Row + input types for the document_chunks table (Phase 2).
|
|
3
|
+
*
|
|
4
|
+
* Mirrors the columns in `schema.sql`. The `embedding` field stays on
|
|
5
|
+
* the row (vs being held only in `memories.embedding`) so the chunk
|
|
6
|
+
* store supports raw chunk-level lookups for re-index and audit
|
|
7
|
+
* without round-tripping through the memory layer.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Fields shared by the persisted row and the insert input. Extracted
|
|
11
|
+
* so the two shapes don't drift independently.
|
|
12
|
+
*/
|
|
13
|
+
interface DocumentChunkBody {
|
|
14
|
+
userId: string;
|
|
15
|
+
rawDocumentId: string;
|
|
16
|
+
chunkIndex: number;
|
|
17
|
+
content: string;
|
|
18
|
+
contentHash: string;
|
|
19
|
+
charStart: number;
|
|
20
|
+
charEnd: number;
|
|
21
|
+
tokenCount: number;
|
|
22
|
+
embedding: number[];
|
|
23
|
+
parserVersion: string;
|
|
24
|
+
chunkerVersion: string;
|
|
25
|
+
}
|
|
26
|
+
export interface DocumentChunkRow extends DocumentChunkBody {
|
|
27
|
+
id: string;
|
|
28
|
+
metadata: Record<string, unknown>;
|
|
29
|
+
createdAt: Date;
|
|
30
|
+
deletedAt: Date | null;
|
|
31
|
+
}
|
|
32
|
+
export interface InsertDocumentChunkInput extends DocumentChunkBody {
|
|
33
|
+
metadata?: Record<string, unknown>;
|
|
34
|
+
}
|
|
35
|
+
export {};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Row + input types for the document_chunks table (Phase 2).
|
|
3
|
+
*
|
|
4
|
+
* Mirrors the columns in `schema.sql`. The `embedding` field stays on
|
|
5
|
+
* the row (vs being held only in `memories.embedding`) so the chunk
|
|
6
|
+
* store supports raw chunk-level lookups for re-index and audit
|
|
7
|
+
* without round-tripping through the memory layer.
|
|
8
|
+
*/
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Phase D — opaque base64 cursor helpers for the document list /
|
|
3
|
+
* recovery / passport-feed endpoints.
|
|
4
|
+
*
|
|
5
|
+
* Cursor encodes `{ sortAt, sortId }`: a tuple that is strictly
|
|
6
|
+
* less-than-comparable in the underlying SQL using `(sortAt, sortId) <
|
|
7
|
+
* ($cursor.sortAt, $cursor.sortId)`. Callers pick which column drives
|
|
8
|
+
* the sort (`raw_documents.created_at` for the standalone-list and
|
|
9
|
+
* recovery feeds; the grouped passport-feed uses
|
|
10
|
+
* `MAX(memories.created_at)` for memory-backed rows and
|
|
11
|
+
* `raw_documents.created_at` for synthetic ones).
|
|
12
|
+
*
|
|
13
|
+
* The cursor is base64-url-encoded JSON so it round-trips through
|
|
14
|
+
* query strings cleanly. Callers must validate `decodeListCursor`'s
|
|
15
|
+
* `null` return as "malformed cursor" and 400 — the helper does NOT
|
|
16
|
+
* throw on bad input so route handlers can map invalid cursors to a
|
|
17
|
+
* 400 instead of a 500. ISO date strings on the wire keep the cursor
|
|
18
|
+
* human-readable in logs.
|
|
19
|
+
*
|
|
20
|
+
* Phase D review-fix: structural validation extends past "is a
|
|
21
|
+
* non-empty string" — `sortAt` MUST be a parseable ISO 8601 timestamp
|
|
22
|
+
* and `sortId` MUST be a UUID. Without that, a structurally valid
|
|
23
|
+
* base64url cursor like
|
|
24
|
+
* `{"sortAt":"not-a-date","sortId":"not-a-uuid"}` would slip past
|
|
25
|
+
* the cursor decoder and hit the underlying SQL cast (`$N::timestamptz`
|
|
26
|
+
* / `$N::uuid`), producing a 500 from Postgres instead of the
|
|
27
|
+
* intended 400 invalid_cursor.
|
|
28
|
+
*/
|
|
29
|
+
export interface DocumentListCursor {
|
|
30
|
+
sortAt: string;
|
|
31
|
+
sortId: string;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Encode a `(sortAt, sortId)` tuple to an opaque cursor string.
|
|
35
|
+
* `sortAt` should already be ISO 8601; the helper does not coerce
|
|
36
|
+
* Date instances on purpose, so callers see the formatting bug at
|
|
37
|
+
* source if they forget to `.toISOString()`.
|
|
38
|
+
*/
|
|
39
|
+
export declare function encodeListCursor(cursor: DocumentListCursor): string;
|
|
40
|
+
/**
|
|
41
|
+
* Decode an opaque cursor string. Returns null on missing input,
|
|
42
|
+
* malformed base64, malformed JSON, or a payload that doesn't carry
|
|
43
|
+
* both fields with the right types.
|
|
44
|
+
*/
|
|
45
|
+
export declare function decodeListCursor(raw: string | undefined | null): DocumentListCursor | null;
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Phase D — opaque base64 cursor helpers for the document list /
|
|
3
|
+
* recovery / passport-feed endpoints.
|
|
4
|
+
*
|
|
5
|
+
* Cursor encodes `{ sortAt, sortId }`: a tuple that is strictly
|
|
6
|
+
* less-than-comparable in the underlying SQL using `(sortAt, sortId) <
|
|
7
|
+
* ($cursor.sortAt, $cursor.sortId)`. Callers pick which column drives
|
|
8
|
+
* the sort (`raw_documents.created_at` for the standalone-list and
|
|
9
|
+
* recovery feeds; the grouped passport-feed uses
|
|
10
|
+
* `MAX(memories.created_at)` for memory-backed rows and
|
|
11
|
+
* `raw_documents.created_at` for synthetic ones).
|
|
12
|
+
*
|
|
13
|
+
* The cursor is base64-url-encoded JSON so it round-trips through
|
|
14
|
+
* query strings cleanly. Callers must validate `decodeListCursor`'s
|
|
15
|
+
* `null` return as "malformed cursor" and 400 — the helper does NOT
|
|
16
|
+
* throw on bad input so route handlers can map invalid cursors to a
|
|
17
|
+
* 400 instead of a 500. ISO date strings on the wire keep the cursor
|
|
18
|
+
* human-readable in logs.
|
|
19
|
+
*
|
|
20
|
+
* Phase D review-fix: structural validation extends past "is a
|
|
21
|
+
* non-empty string" — `sortAt` MUST be a parseable ISO 8601 timestamp
|
|
22
|
+
* and `sortId` MUST be a UUID. Without that, a structurally valid
|
|
23
|
+
* base64url cursor like
|
|
24
|
+
* `{"sortAt":"not-a-date","sortId":"not-a-uuid"}` would slip past
|
|
25
|
+
* the cursor decoder and hit the underlying SQL cast (`$N::timestamptz`
|
|
26
|
+
* / `$N::uuid`), producing a 500 from Postgres instead of the
|
|
27
|
+
* intended 400 invalid_cursor.
|
|
28
|
+
*/
|
|
29
|
+
const CURSOR_UUID_REGEX = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
30
|
+
/**
|
|
31
|
+
* Server-emitted cursor `sortAt` is always `Date#toISOString()`, which
|
|
32
|
+
* produces ISO-8601 UTC with millisecond precision and a trailing `Z`
|
|
33
|
+
* (`YYYY-MM-DDTHH:mm:ss.sssZ`). Tightening the validator to this
|
|
34
|
+
* exact shape (plus a `Date` round-trip below) rejects parseable-but-
|
|
35
|
+
* non-server formats like `"2026-05-10"` or `"May 10 2026"` that
|
|
36
|
+
* `Date.parse` would otherwise admit. This stops a caller (or
|
|
37
|
+
* attacker) from crafting a cursor whose `sortAt` parses to a real
|
|
38
|
+
* timestamp but does not correspond to a value the cursor encoder
|
|
39
|
+
* could ever have emitted.
|
|
40
|
+
*/
|
|
41
|
+
const CURSOR_SORT_AT_REGEX = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}\.\d{3}Z$/;
|
|
42
|
+
/** Base64url encode a UTF-8 string (RFC 4648 §5; no padding). */
|
|
43
|
+
function base64urlEncode(input) {
|
|
44
|
+
return Buffer.from(input, 'utf8')
|
|
45
|
+
.toString('base64')
|
|
46
|
+
.replace(/\+/g, '-')
|
|
47
|
+
.replace(/\//g, '_')
|
|
48
|
+
.replace(/=+$/, '');
|
|
49
|
+
}
|
|
50
|
+
/** Inverse of {@link base64urlEncode}. Returns null on malformed input. */
|
|
51
|
+
function base64urlDecode(input) {
|
|
52
|
+
try {
|
|
53
|
+
const padded = input.replace(/-/g, '+').replace(/_/g, '/');
|
|
54
|
+
return Buffer.from(padded, 'base64').toString('utf8');
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Encode a `(sortAt, sortId)` tuple to an opaque cursor string.
|
|
62
|
+
* `sortAt` should already be ISO 8601; the helper does not coerce
|
|
63
|
+
* Date instances on purpose, so callers see the formatting bug at
|
|
64
|
+
* source if they forget to `.toISOString()`.
|
|
65
|
+
*/
|
|
66
|
+
export function encodeListCursor(cursor) {
|
|
67
|
+
return base64urlEncode(JSON.stringify(cursor));
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Decode an opaque cursor string. Returns null on missing input,
|
|
71
|
+
* malformed base64, malformed JSON, or a payload that doesn't carry
|
|
72
|
+
* both fields with the right types.
|
|
73
|
+
*/
|
|
74
|
+
export function decodeListCursor(raw) {
|
|
75
|
+
if (raw === undefined || raw === null || raw.length === 0)
|
|
76
|
+
return null;
|
|
77
|
+
const decoded = base64urlDecode(raw);
|
|
78
|
+
if (decoded === null)
|
|
79
|
+
return null;
|
|
80
|
+
let parsed;
|
|
81
|
+
try {
|
|
82
|
+
parsed = JSON.parse(decoded);
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
return null;
|
|
86
|
+
}
|
|
87
|
+
if (typeof parsed !== 'object' || parsed === null)
|
|
88
|
+
return null;
|
|
89
|
+
const obj = parsed;
|
|
90
|
+
if (typeof obj.sortAt !== 'string' || typeof obj.sortId !== 'string')
|
|
91
|
+
return null;
|
|
92
|
+
if (obj.sortAt.length === 0 || obj.sortId.length === 0)
|
|
93
|
+
return null;
|
|
94
|
+
// Validate sortAt against the exact server-emitted ISO UTC
|
|
95
|
+
// millisecond shape AND a Date round-trip. The regex covers the
|
|
96
|
+
// syntactic shape; the round-trip catches values like
|
|
97
|
+
// `"2026-13-99T..."` that match the regex but don't represent
|
|
98
|
+
// real dates. Together this rejects every cursor that could not
|
|
99
|
+
// have come from this server's `Date#toISOString()`.
|
|
100
|
+
if (!CURSOR_SORT_AT_REGEX.test(obj.sortAt))
|
|
101
|
+
return null;
|
|
102
|
+
const sortAtDate = new Date(obj.sortAt);
|
|
103
|
+
if (Number.isNaN(sortAtDate.getTime()))
|
|
104
|
+
return null;
|
|
105
|
+
if (sortAtDate.toISOString() !== obj.sortAt)
|
|
106
|
+
return null;
|
|
107
|
+
// Validate sortId is a UUID the SQL `::uuid` cast will accept.
|
|
108
|
+
if (!CURSOR_UUID_REGEX.test(obj.sortId))
|
|
109
|
+
return null;
|
|
110
|
+
return { sortAt: obj.sortAt, sortId: obj.sortId };
|
|
111
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Phase D — focused module for the cursor-paginated user-scoped
|
|
3
|
+
* document list helpers (`GET /v1/documents`,
|
|
4
|
+
* `GET /v1/documents/without-memories`).
|
|
5
|
+
*
|
|
6
|
+
* Split out from `raw-document-repository.ts` to keep that file
|
|
7
|
+
* under the 400 non-comment LOC workspace rule. The legacy
|
|
8
|
+
* offset/limit + source_site `listRawDocuments` helper still lives
|
|
9
|
+
* in `raw-document-repository.ts`; only the Phase D cursor-based
|
|
10
|
+
* surfaces are here.
|
|
11
|
+
*
|
|
12
|
+
* Imports `RAW_DOCUMENT_COLUMNS` + `rowToRawDocument` from the
|
|
13
|
+
* sibling repo so the canonical column set + projection stays in
|
|
14
|
+
* one place.
|
|
15
|
+
*/
|
|
16
|
+
import type pg from 'pg';
|
|
17
|
+
import { type DocumentListCursor } from './document-list-cursor.js';
|
|
18
|
+
import type { RawDocumentRow } from './raw-document-types.js';
|
|
19
|
+
/**
|
|
20
|
+
* Phase D — coarse status-bucket filter for the standalone
|
|
21
|
+
* `GET /v1/documents` list endpoint. The buckets pivot on the new
|
|
22
|
+
* Phase B per-layer status columns; `'all'` returns every active
|
|
23
|
+
* row. The recovery-relevant buckets serve the UI's
|
|
24
|
+
* "what is broken / what needs attention" surfaces; the
|
|
25
|
+
* `'unsupported'` bucket lights up `.parquet` and similar
|
|
26
|
+
* stored-but-not-indexed files.
|
|
27
|
+
*/
|
|
28
|
+
export type DocumentListStatusFilter = 'failed' | 'unsupported' | 'pending' | 'all';
|
|
29
|
+
export interface ListDocumentsForUserInput {
|
|
30
|
+
userId: string;
|
|
31
|
+
limit?: number;
|
|
32
|
+
cursor?: DocumentListCursor | null;
|
|
33
|
+
statusFilter?: DocumentListStatusFilter;
|
|
34
|
+
}
|
|
35
|
+
export interface ListDocumentsForUserResult {
|
|
36
|
+
documents: RawDocumentRow[];
|
|
37
|
+
nextCursor: string | null;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Phase D — cursor-paginated user-scoped document list with optional
|
|
41
|
+
* recovery-status bucket filter. Distinct from `listRawDocuments`
|
|
42
|
+
* (offset/limit + source_site filter) which backs the legacy
|
|
43
|
+
* `GET /v1/documents/list` route.
|
|
44
|
+
*
|
|
45
|
+
* Cursor semantics: stable ordering on `(created_at DESC, id DESC)`.
|
|
46
|
+
* Standard `+1 over-fetch` pattern; `nextCursor` only when more
|
|
47
|
+
* rows exist beyond the current page.
|
|
48
|
+
*
|
|
49
|
+
* Status filter expressions:
|
|
50
|
+
* - 'failed' — any layer is failed (extraction OR semantic_index OR
|
|
51
|
+
* raw_storage)
|
|
52
|
+
* - 'unsupported' — extraction_status = 'unsupported' (the
|
|
53
|
+
* deliberately-not-indexed bucket)
|
|
54
|
+
* - 'pending' — extraction or semantic_index is pending/running.
|
|
55
|
+
* Forward-compatible with the future async-worker PR; in this
|
|
56
|
+
* PR's synchronous flow `running` matches only manually seeded
|
|
57
|
+
* rows (the Phase B indexer never commits 'running').
|
|
58
|
+
* - 'all' — no status filter.
|
|
59
|
+
*/
|
|
60
|
+
export declare function listDocumentsForUser(pool: pg.Pool, input: ListDocumentsForUserInput): Promise<ListDocumentsForUserResult>;
|
|
61
|
+
/**
|
|
62
|
+
* Phase D — layer-aware recovery filter consumed by
|
|
63
|
+
* {@link listDocumentsWithoutMemoriesForUser}. Each layer's array (when
|
|
64
|
+
* supplied) narrows that layer to one of the values; rows match when
|
|
65
|
+
* ANY layer's value is in its array. An empty array on a layer means
|
|
66
|
+
* "do not match this layer at all" (deliberate — the layer can be
|
|
67
|
+
* scoped out by passing `[]` rather than omitting the key).
|
|
68
|
+
*/
|
|
69
|
+
export interface DocumentRecoveryStatusFilter {
|
|
70
|
+
extraction?: Array<'pending' | 'running' | 'failed' | 'unsupported'>;
|
|
71
|
+
semantic_index?: Array<'pending' | 'running' | 'failed' | 'stale'>;
|
|
72
|
+
/**
|
|
73
|
+
* Filecoin lifecycle refactor (Slice 2): includes `blob_pending`
|
|
74
|
+
* (eventual provider still propagating) and `blob_archival_failed`
|
|
75
|
+
* (Phase 3 reconciler's permanent-failure terminal) so a row stuck
|
|
76
|
+
* in either state surfaces to `/without-memories`. `blob_available`
|
|
77
|
+
* and `blob_tombstoned` are terminal-OK / no-longer-managed and
|
|
78
|
+
* deliberately NOT recovery targets.
|
|
79
|
+
*/
|
|
80
|
+
raw_storage?: Array<'raw_storage_failed' | 'pointer_recorded' | 'blob_pending' | 'blob_archival_failed'>;
|
|
81
|
+
}
|
|
82
|
+
export interface ListDocumentsWithoutMemoriesInput {
|
|
83
|
+
userId: string;
|
|
84
|
+
limit?: number;
|
|
85
|
+
cursor?: DocumentListCursor | null;
|
|
86
|
+
statusFilter?: DocumentRecoveryStatusFilter;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Phase D — list active documents with ZERO non-deleted memories AND
|
|
90
|
+
* matching the layer-aware recovery filter. Backs
|
|
91
|
+
* `GET /v1/documents/without-memories` and the document-only stream
|
|
92
|
+
* of the passport server-side merge.
|
|
93
|
+
*
|
|
94
|
+
* Visibility: a row appears when it is the user's, not soft-deleted,
|
|
95
|
+
* has no memories pointing to it (strict `NOT EXISTS` over
|
|
96
|
+
* `memories.raw_document_id`), and at least one layer status sits in
|
|
97
|
+
* its filter array. Default filter is recovery-relevant — failed,
|
|
98
|
+
* pending, or unsupported across the three layers — so happy-path
|
|
99
|
+
* pointer-only documents that simply have no chunks (e.g., future
|
|
100
|
+
* Drive listings) do NOT surface in the passport synthetic-row
|
|
101
|
+
* stream.
|
|
102
|
+
*/
|
|
103
|
+
export declare function listDocumentsWithoutMemoriesForUser(pool: pg.Pool, input: ListDocumentsWithoutMemoriesInput): Promise<ListDocumentsForUserResult>;
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Phase D — focused module for the cursor-paginated user-scoped
|
|
3
|
+
* document list helpers (`GET /v1/documents`,
|
|
4
|
+
* `GET /v1/documents/without-memories`).
|
|
5
|
+
*
|
|
6
|
+
* Split out from `raw-document-repository.ts` to keep that file
|
|
7
|
+
* under the 400 non-comment LOC workspace rule. The legacy
|
|
8
|
+
* offset/limit + source_site `listRawDocuments` helper still lives
|
|
9
|
+
* in `raw-document-repository.ts`; only the Phase D cursor-based
|
|
10
|
+
* surfaces are here.
|
|
11
|
+
*
|
|
12
|
+
* Imports `RAW_DOCUMENT_COLUMNS` + `rowToRawDocument` from the
|
|
13
|
+
* sibling repo so the canonical column set + projection stays in
|
|
14
|
+
* one place.
|
|
15
|
+
*/
|
|
16
|
+
import { encodeListCursor, } from './document-list-cursor.js';
|
|
17
|
+
import { RAW_DOCUMENT_COLUMNS, rowToRawDocument, } from './raw-document-repository.js';
|
|
18
|
+
const LIST_DEFAULT_LIMIT = 50;
|
|
19
|
+
const LIST_MAX_LIMIT = 100;
|
|
20
|
+
/**
|
|
21
|
+
* Phase D — cursor-paginated user-scoped document list with optional
|
|
22
|
+
* recovery-status bucket filter. Distinct from `listRawDocuments`
|
|
23
|
+
* (offset/limit + source_site filter) which backs the legacy
|
|
24
|
+
* `GET /v1/documents/list` route.
|
|
25
|
+
*
|
|
26
|
+
* Cursor semantics: stable ordering on `(created_at DESC, id DESC)`.
|
|
27
|
+
* Standard `+1 over-fetch` pattern; `nextCursor` only when more
|
|
28
|
+
* rows exist beyond the current page.
|
|
29
|
+
*
|
|
30
|
+
* Status filter expressions:
|
|
31
|
+
* - 'failed' — any layer is failed (extraction OR semantic_index OR
|
|
32
|
+
* raw_storage)
|
|
33
|
+
* - 'unsupported' — extraction_status = 'unsupported' (the
|
|
34
|
+
* deliberately-not-indexed bucket)
|
|
35
|
+
* - 'pending' — extraction or semantic_index is pending/running.
|
|
36
|
+
* Forward-compatible with the future async-worker PR; in this
|
|
37
|
+
* PR's synchronous flow `running` matches only manually seeded
|
|
38
|
+
* rows (the Phase B indexer never commits 'running').
|
|
39
|
+
* - 'all' — no status filter.
|
|
40
|
+
*/
|
|
41
|
+
export async function listDocumentsForUser(pool, input) {
|
|
42
|
+
const limit = clampListLimit(input.limit);
|
|
43
|
+
const overFetch = limit + 1;
|
|
44
|
+
const params = [input.userId, overFetch];
|
|
45
|
+
const wheres = ['user_id = $1', 'deleted_at IS NULL'];
|
|
46
|
+
const statusClause = buildStatusFilterSql(input.statusFilter ?? 'all', params);
|
|
47
|
+
if (statusClause !== null)
|
|
48
|
+
wheres.push(statusClause);
|
|
49
|
+
if (input.cursor) {
|
|
50
|
+
params.push(input.cursor.sortAt, input.cursor.sortId);
|
|
51
|
+
wheres.push(`(created_at, id) < ($${params.length - 1}::timestamptz, $${params.length}::uuid)`);
|
|
52
|
+
}
|
|
53
|
+
const sql = `SELECT ${RAW_DOCUMENT_COLUMNS}
|
|
54
|
+
FROM raw_documents
|
|
55
|
+
WHERE ${wheres.join(' AND ')}
|
|
56
|
+
ORDER BY created_at DESC, id DESC
|
|
57
|
+
LIMIT $2`;
|
|
58
|
+
const result = await pool.query(sql, params);
|
|
59
|
+
return slicePageWithCursor(result.rows.map(rowToRawDocument), limit);
|
|
60
|
+
}
|
|
61
|
+
function clampListLimit(raw) {
|
|
62
|
+
if (raw === undefined)
|
|
63
|
+
return LIST_DEFAULT_LIMIT;
|
|
64
|
+
if (!Number.isFinite(raw))
|
|
65
|
+
return LIST_DEFAULT_LIMIT;
|
|
66
|
+
return Math.max(1, Math.min(LIST_MAX_LIMIT, Math.floor(raw)));
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Append the parameterised SQL that narrows the document list to one
|
|
70
|
+
* recovery-status bucket. Returns the WHERE fragment (without leading
|
|
71
|
+
* AND), or null when the filter is `'all'`.
|
|
72
|
+
*
|
|
73
|
+
* Mutates `params` to push the literal status values; this keeps each
|
|
74
|
+
* value explicitly bound rather than embedded in the SQL string, so
|
|
75
|
+
* the query is fully prepared-statement friendly.
|
|
76
|
+
*
|
|
77
|
+
* Lifecycle awareness (Filecoin refactor):
|
|
78
|
+
* - `failed` matches `extraction_status='failed'` OR
|
|
79
|
+
* `semantic_index_status='failed'` OR `raw_storage_status` in
|
|
80
|
+
* `{raw_storage_failed, blob_archival_failed}`. The two raw-storage
|
|
81
|
+
* failure terminals are equivalent surfaces for "the bytes never
|
|
82
|
+
* made it" — immediate-provider catch path vs Phase 3
|
|
83
|
+
* reconciler's permanent-failure terminal — and both belong in
|
|
84
|
+
* the same recovery bucket.
|
|
85
|
+
* - `pending` matches extraction/semantic_index pending/running OR
|
|
86
|
+
* `raw_storage_status='blob_pending'`. The eventual-provider
|
|
87
|
+
* in-flight state belongs in the pending bucket alongside the
|
|
88
|
+
* extraction/index pending/running rows.
|
|
89
|
+
* - `unsupported` is raw-storage-agnostic.
|
|
90
|
+
*/
|
|
91
|
+
function buildStatusFilterSql(filter, params) {
|
|
92
|
+
if (filter === 'all')
|
|
93
|
+
return null;
|
|
94
|
+
if (filter === 'failed') {
|
|
95
|
+
params.push('failed', 'failed', 'raw_storage_failed', 'blob_archival_failed');
|
|
96
|
+
return `(extraction_status = $${params.length - 3}
|
|
97
|
+
OR semantic_index_status = $${params.length - 2}
|
|
98
|
+
OR raw_storage_status IN ($${params.length - 1}, $${params.length}))`;
|
|
99
|
+
}
|
|
100
|
+
if (filter === 'unsupported') {
|
|
101
|
+
params.push('unsupported');
|
|
102
|
+
return `extraction_status = $${params.length}`;
|
|
103
|
+
}
|
|
104
|
+
// 'pending' — extraction OR semantic_index OR raw_storage is in a
|
|
105
|
+
// pre-completion state. `running` is included for forward
|
|
106
|
+
// compatibility with the future async-worker PR; `blob_pending`
|
|
107
|
+
// is the Filecoin/eventual-provider in-flight state.
|
|
108
|
+
params.push('pending', 'running', 'pending', 'running', 'blob_pending');
|
|
109
|
+
return `(extraction_status IN ($${params.length - 4}, $${params.length - 3})
|
|
110
|
+
OR semantic_index_status IN ($${params.length - 2}, $${params.length - 1})
|
|
111
|
+
OR raw_storage_status = $${params.length})`;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Cursor-aware page slicer. The repository over-fetches by one row;
|
|
115
|
+
* if we got the full `limit + 1`, the last consumed row's
|
|
116
|
+
* `(created_at, id)` becomes the next cursor. Otherwise the page
|
|
117
|
+
* exhausts the stream and `nextCursor === null`.
|
|
118
|
+
*/
|
|
119
|
+
function slicePageWithCursor(candidates, limit) {
|
|
120
|
+
if (candidates.length <= limit) {
|
|
121
|
+
return { documents: candidates, nextCursor: null };
|
|
122
|
+
}
|
|
123
|
+
const documents = candidates.slice(0, limit);
|
|
124
|
+
const last = documents[documents.length - 1];
|
|
125
|
+
const sortAt = last.createdAt instanceof Date
|
|
126
|
+
? last.createdAt.toISOString()
|
|
127
|
+
: String(last.createdAt);
|
|
128
|
+
return {
|
|
129
|
+
documents,
|
|
130
|
+
nextCursor: encodeListCursor({ sortAt, sortId: last.id }),
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
const DEFAULT_RECOVERY_STATUS_FILTER = {
|
|
134
|
+
extraction: ['pending', 'failed', 'unsupported'],
|
|
135
|
+
semantic_index: ['pending', 'failed'],
|
|
136
|
+
// `blob_pending` and `blob_archival_failed` join the default so a
|
|
137
|
+
// freshly-uploaded eventual-provider doc surfaces in the recovery
|
|
138
|
+
// feed until the Phase 3 reconciler promotes it (or marks it
|
|
139
|
+
// failed). `raw_storage_failed` stays for the existing upload-
|
|
140
|
+
// failure path. `pointer_recorded` is NOT in the default — its
|
|
141
|
+
// mere presence isn't a recovery signal — but the schema allows
|
|
142
|
+
// callers to request it explicitly.
|
|
143
|
+
raw_storage: ['raw_storage_failed', 'blob_pending', 'blob_archival_failed'],
|
|
144
|
+
};
|
|
145
|
+
/**
|
|
146
|
+
* Phase D — list active documents with ZERO non-deleted memories AND
|
|
147
|
+
* matching the layer-aware recovery filter. Backs
|
|
148
|
+
* `GET /v1/documents/without-memories` and the document-only stream
|
|
149
|
+
* of the passport server-side merge.
|
|
150
|
+
*
|
|
151
|
+
* Visibility: a row appears when it is the user's, not soft-deleted,
|
|
152
|
+
* has no memories pointing to it (strict `NOT EXISTS` over
|
|
153
|
+
* `memories.raw_document_id`), and at least one layer status sits in
|
|
154
|
+
* its filter array. Default filter is recovery-relevant — failed,
|
|
155
|
+
* pending, or unsupported across the three layers — so happy-path
|
|
156
|
+
* pointer-only documents that simply have no chunks (e.g., future
|
|
157
|
+
* Drive listings) do NOT surface in the passport synthetic-row
|
|
158
|
+
* stream.
|
|
159
|
+
*/
|
|
160
|
+
export async function listDocumentsWithoutMemoriesForUser(pool, input) {
|
|
161
|
+
const limit = clampListLimit(input.limit);
|
|
162
|
+
const overFetch = limit + 1;
|
|
163
|
+
const filter = mergeRecoveryFilter(input.statusFilter);
|
|
164
|
+
const params = [
|
|
165
|
+
input.userId,
|
|
166
|
+
overFetch,
|
|
167
|
+
filter.extraction,
|
|
168
|
+
filter.semantic_index,
|
|
169
|
+
filter.raw_storage,
|
|
170
|
+
];
|
|
171
|
+
const wheres = [
|
|
172
|
+
'rd.user_id = $1',
|
|
173
|
+
'rd.deleted_at IS NULL',
|
|
174
|
+
'NOT EXISTS (SELECT 1 FROM memories m WHERE m.raw_document_id = rd.id AND m.deleted_at IS NULL)',
|
|
175
|
+
`(rd.extraction_status = ANY($3::text[])
|
|
176
|
+
OR rd.semantic_index_status = ANY($4::text[])
|
|
177
|
+
OR rd.raw_storage_status = ANY($5::text[]))`,
|
|
178
|
+
];
|
|
179
|
+
if (input.cursor) {
|
|
180
|
+
params.push(input.cursor.sortAt, input.cursor.sortId);
|
|
181
|
+
wheres.push(`(rd.created_at, rd.id) < ($${params.length - 1}::timestamptz, $${params.length}::uuid)`);
|
|
182
|
+
}
|
|
183
|
+
const sql = `SELECT ${RAW_DOCUMENT_COLUMNS.split(', ').map((c) => `rd.${c}`).join(', ')}
|
|
184
|
+
FROM raw_documents rd
|
|
185
|
+
WHERE ${wheres.join(' AND ')}
|
|
186
|
+
ORDER BY rd.created_at DESC, rd.id DESC
|
|
187
|
+
LIMIT $2`;
|
|
188
|
+
const result = await pool.query(sql, params);
|
|
189
|
+
return slicePageWithCursor(result.rows.map(rowToRawDocument), limit);
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Apply the recovery-status default to any layer the caller omitted.
|
|
193
|
+
* Empty arrays passed by the caller are kept verbatim so callers can
|
|
194
|
+
* scope a layer out by passing `[]`.
|
|
195
|
+
*/
|
|
196
|
+
function mergeRecoveryFilter(override) {
|
|
197
|
+
if (!override)
|
|
198
|
+
return DEFAULT_RECOVERY_STATUS_FILTER;
|
|
199
|
+
return {
|
|
200
|
+
extraction: override.extraction ?? DEFAULT_RECOVERY_STATUS_FILTER.extraction,
|
|
201
|
+
semantic_index: override.semantic_index ?? DEFAULT_RECOVERY_STATUS_FILTER.semantic_index,
|
|
202
|
+
raw_storage: override.raw_storage ?? DEFAULT_RECOVERY_STATUS_FILTER.raw_storage,
|
|
203
|
+
};
|
|
204
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EntityCardsRepository — upsert + read for the always-on ENTITY_CARD channel.
|
|
3
|
+
*
|
|
4
|
+
* One row per (user_id, conversation_id, entity_name) holds a durable LLM-
|
|
5
|
+
* synthesized summary card for that entity. The Reflect worker re-synthesizes
|
|
6
|
+
* the card from new observations + prior card text on every run; the search
|
|
7
|
+
* pipeline injects all cards for the active conversation under `## ENTITY_STATE`.
|
|
8
|
+
*
|
|
9
|
+
* Pure SQL via pg.Pool. Mutations fail closed — errors propagate to the caller.
|
|
10
|
+
*/
|
|
11
|
+
import type pg from 'pg';
|
|
12
|
+
export interface EntityCard {
|
|
13
|
+
id: string;
|
|
14
|
+
userId: string;
|
|
15
|
+
conversationId: string;
|
|
16
|
+
entityName: string;
|
|
17
|
+
cardText: string;
|
|
18
|
+
sourceObservationIds: string[];
|
|
19
|
+
version: number;
|
|
20
|
+
updatedAt: Date;
|
|
21
|
+
}
|
|
22
|
+
export interface UpsertEntityCardInput {
|
|
23
|
+
userId: string;
|
|
24
|
+
conversationId: string;
|
|
25
|
+
entityName: string;
|
|
26
|
+
cardText: string;
|
|
27
|
+
sourceObservationIds: string[];
|
|
28
|
+
version: number;
|
|
29
|
+
}
|
|
30
|
+
export declare class EntityCardsRepository {
|
|
31
|
+
private readonly pool;
|
|
32
|
+
constructor(pool: pg.Pool);
|
|
33
|
+
/** Upsert a card by (userId, conversationId, entityName). Increments version on update. */
|
|
34
|
+
upsert(input: UpsertEntityCardInput): Promise<void>;
|
|
35
|
+
/** Find cards for a (userId, conversationId), most recently updated first. */
|
|
36
|
+
findByConversation(userId: string, conversationId: string, limit: number): Promise<EntityCard[]>;
|
|
37
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
export class EntityCardsRepository {
|
|
2
|
+
pool;
|
|
3
|
+
constructor(pool) {
|
|
4
|
+
this.pool = pool;
|
|
5
|
+
}
|
|
6
|
+
/** Upsert a card by (userId, conversationId, entityName). Increments version on update. */
|
|
7
|
+
async upsert(input) {
|
|
8
|
+
await this.pool.query(`INSERT INTO entity_cards
|
|
9
|
+
(user_id, conversation_id, entity_name, card_text, source_observation_ids, version, updated_at)
|
|
10
|
+
VALUES ($1, $2, $3, $4, $5, $6, now())
|
|
11
|
+
ON CONFLICT (user_id, conversation_id, entity_name) DO UPDATE
|
|
12
|
+
SET card_text = EXCLUDED.card_text,
|
|
13
|
+
source_observation_ids = EXCLUDED.source_observation_ids,
|
|
14
|
+
version = entity_cards.version + 1,
|
|
15
|
+
updated_at = now()`, [
|
|
16
|
+
input.userId,
|
|
17
|
+
input.conversationId,
|
|
18
|
+
input.entityName,
|
|
19
|
+
input.cardText,
|
|
20
|
+
input.sourceObservationIds,
|
|
21
|
+
input.version,
|
|
22
|
+
]);
|
|
23
|
+
}
|
|
24
|
+
/** Find cards for a (userId, conversationId), most recently updated first. */
|
|
25
|
+
async findByConversation(userId, conversationId, limit) {
|
|
26
|
+
const { rows } = await this.pool.query(`SELECT id, user_id, conversation_id, entity_name, card_text,
|
|
27
|
+
source_observation_ids, version, updated_at
|
|
28
|
+
FROM entity_cards
|
|
29
|
+
WHERE user_id = $1 AND conversation_id = $2
|
|
30
|
+
ORDER BY updated_at DESC
|
|
31
|
+
LIMIT $3`, [userId, conversationId, limit]);
|
|
32
|
+
return rows.map(mapRow);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
function mapRow(r) {
|
|
36
|
+
return {
|
|
37
|
+
id: r.id,
|
|
38
|
+
userId: r.user_id,
|
|
39
|
+
conversationId: r.conversation_id,
|
|
40
|
+
entityName: r.entity_name,
|
|
41
|
+
cardText: r.card_text,
|
|
42
|
+
sourceObservationIds: r.source_observation_ids,
|
|
43
|
+
version: r.version,
|
|
44
|
+
updatedAt: r.updated_at,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* EntityValuesRepository — CRUD for the entity_values table populated at
|
|
3
|
+
* ingest. Used by the IE/KU literal-value specialist at retrieval.
|
|
4
|
+
*/
|
|
5
|
+
import pg from 'pg';
|
|
6
|
+
export type ValueType = 'date' | 'number' | 'string' | 'duration' | 'list';
|
|
7
|
+
export interface NewEntityValue {
|
|
8
|
+
userId: string;
|
|
9
|
+
entity: string;
|
|
10
|
+
attribute: string;
|
|
11
|
+
value: string;
|
|
12
|
+
valueType: ValueType;
|
|
13
|
+
observedAt: Date;
|
|
14
|
+
factId: string;
|
|
15
|
+
}
|
|
16
|
+
export interface EntityValue extends NewEntityValue {
|
|
17
|
+
id: string;
|
|
18
|
+
createdAt: Date;
|
|
19
|
+
}
|
|
20
|
+
export declare class EntityValuesRepository {
|
|
21
|
+
private readonly pool;
|
|
22
|
+
constructor(pool: pg.Pool);
|
|
23
|
+
insertMany(rows: readonly NewEntityValue[]): Promise<void>;
|
|
24
|
+
/** Fuzzy lookup: case-insensitive match on (entity, attribute), most recent first. */
|
|
25
|
+
findLatest(userId: string, entity: string, attribute: string): Promise<EntityValue | null>;
|
|
26
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
export class EntityValuesRepository {
|
|
2
|
+
pool;
|
|
3
|
+
constructor(pool) {
|
|
4
|
+
this.pool = pool;
|
|
5
|
+
}
|
|
6
|
+
async insertMany(rows) {
|
|
7
|
+
if (rows.length === 0)
|
|
8
|
+
return;
|
|
9
|
+
const sql = `
|
|
10
|
+
INSERT INTO entity_values
|
|
11
|
+
(user_id, entity, attribute, value, value_type, observed_at, fact_id)
|
|
12
|
+
VALUES ($1, $2, $3, $4, $5, $6, $7)
|
|
13
|
+
`;
|
|
14
|
+
const client = await this.pool.connect();
|
|
15
|
+
try {
|
|
16
|
+
await client.query('BEGIN');
|
|
17
|
+
for (const r of rows) {
|
|
18
|
+
await client.query(sql, [
|
|
19
|
+
r.userId, r.entity, r.attribute, r.value, r.valueType,
|
|
20
|
+
r.observedAt, r.factId,
|
|
21
|
+
]);
|
|
22
|
+
}
|
|
23
|
+
await client.query('COMMIT');
|
|
24
|
+
}
|
|
25
|
+
catch (e) {
|
|
26
|
+
await client.query('ROLLBACK');
|
|
27
|
+
throw e;
|
|
28
|
+
}
|
|
29
|
+
finally {
|
|
30
|
+
client.release();
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
/** Fuzzy lookup: case-insensitive match on (entity, attribute), most recent first. */
|
|
34
|
+
async findLatest(userId, entity, attribute) {
|
|
35
|
+
const { rows } = await this.pool.query(`SELECT id, user_id, entity, attribute, value, value_type, observed_at, fact_id, created_at
|
|
36
|
+
FROM entity_values
|
|
37
|
+
WHERE user_id = $1
|
|
38
|
+
AND lower(entity) = lower($2)
|
|
39
|
+
AND lower(attribute) = lower($3)
|
|
40
|
+
ORDER BY observed_at DESC
|
|
41
|
+
LIMIT 1`, [userId, entity, attribute]);
|
|
42
|
+
return rows[0] ? mapRow(rows[0]) : null;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
function mapRow(r) {
|
|
46
|
+
return {
|
|
47
|
+
id: r.id,
|
|
48
|
+
userId: r.user_id,
|
|
49
|
+
entity: r.entity,
|
|
50
|
+
attribute: r.attribute,
|
|
51
|
+
value: r.value,
|
|
52
|
+
valueType: r.value_type,
|
|
53
|
+
observedAt: r.observed_at,
|
|
54
|
+
factId: r.fact_id,
|
|
55
|
+
createdAt: r.created_at,
|
|
56
|
+
};
|
|
57
|
+
}
|