@forwardimpact/libindex
Advanced tools
+3
-2
| { | ||
| "name": "@forwardimpact/libindex", | ||
| "version": "0.1.41", | ||
| "version": "0.1.42", | ||
| "description": "JSONL-backed indexes with filtering and buffered writes — fast context lookup without an external search engine.", | ||
@@ -46,3 +46,4 @@ "keywords": [ | ||
| "devDependencies": { | ||
| "@forwardimpact/libmock": "^0.1.0" | ||
| "@forwardimpact/libmock": "^0.1.0", | ||
| "@forwardimpact/libstorage": "^0.1.0" | ||
| }, | ||
@@ -49,0 +50,0 @@ "engines": { |
+15
-0
@@ -216,2 +216,17 @@ import { resource } from "@forwardimpact/libtype"; | ||
| /** | ||
| * Replaces the persisted index file with a JSONL serialisation of the | ||
| * current in-memory live set. Closes the append-only-vs-deletion gap: a | ||
| * caller that removes an entry from the in-memory `index` Map and then | ||
| * calls `compact()` ends with that entry absent from both memory and disk. | ||
| * Uses `storage.put` (atomic file-replace) so a process restart cannot | ||
| * observe a half-written index. | ||
| * @returns {Promise<void>} | ||
| */ | ||
| async compact() { | ||
| if (!this.#loaded) await this.loadData(); | ||
| const records = [...this.#index.values()]; | ||
| await this.#storage.put(this.#indexKey, records); | ||
| } | ||
| /** | ||
| * Queries items from the index using basic filtering | ||
@@ -218,0 +233,0 @@ * Provides a default implementation that applies shared filters to all items |
+17
-10
| import { IndexBase } from "./base.js"; | ||
| import { createDefaultRuntime } from "@forwardimpact/libutil/runtime"; | ||
@@ -23,15 +22,12 @@ /** | ||
| * @param {number} [config.max_buffer_size] - Max items before forced flush (default: 1000) | ||
| * @param {object} [deps] - Injected collaborators | ||
| * @param {import("@forwardimpact/libutil/runtime").Runtime} [deps.runtime] | ||
| * @param {object} deps - Injected collaborators | ||
| * @param {import("@forwardimpact/libutil/runtime").Runtime["clock"]} deps.clock - | ||
| * Injected clock collaborator (the only runtime surface BufferedIndex uses). | ||
| */ | ||
| constructor( | ||
| storage, | ||
| indexKey, | ||
| config = {}, | ||
| { runtime = createDefaultRuntime() } = {}, | ||
| ) { | ||
| constructor(storage, indexKey, config = {}, { clock } = {}) { | ||
| super(storage, indexKey); | ||
| if (!clock) throw new Error("clock is required"); | ||
| this.#flushInterval = config.flush_interval || 5000; | ||
| this.#maxBufferSize = config.max_buffer_size || 1000; | ||
| this.#clock = runtime.clock; | ||
| this.#clock = clock; | ||
| } | ||
@@ -90,2 +86,13 @@ | ||
| /** | ||
| * Compaction on a buffered index drains the in-memory write buffer to | ||
| * storage first (so any post-buffer state is observable on disk) and | ||
| * then replaces the persisted file with the live in-memory set. | ||
| * @returns {Promise<void>} | ||
| */ | ||
| async compact() { | ||
| await this.flush(); | ||
| await super.compact(); | ||
| } | ||
| /** | ||
| * Shuts down the index by flushing remaining buffer and clearing timer | ||
@@ -92,0 +99,0 @@ * @returns {Promise<void>} |
24369
4.32%315
6.78%2
100%