hermes-wasm 1.8.28 → 1.8.30

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 ADDED
@@ -0,0 +1,266 @@
1
+ # hermes-wasm
2
+
3
+ WebAssembly bindings for the [Hermes](https://github.com/SpaceFrontiers/hermes) search engine. Run a full-text search engine entirely in the browser — including indexing, BM25 ranking, and document storage.
4
+
5
+ ## Features
6
+
7
+ - **Local indexing** — create indexes, add documents, commit, and search entirely in WASM
8
+ - **Pluggable persistence** — bring your own storage (IDB, encrypted, OPFS) via simple JS interface
9
+ - **Remote search** — load pre-built indexes over HTTP with slice caching
10
+ - **IPFS support** — load indexes from IPFS via JavaScript fetch callbacks
11
+ - **15+ language stemmers** — English, German, French, Spanish, Russian, Arabic, and more
12
+ - **Query language** — `field:term`, `AND`, `OR`, `NOT`, grouping with parentheses
13
+ - **~3 MB** WASM binary (gzipped ~1.2 MB)
14
+
15
+ ## Quick Start
16
+
17
+ ```bash
18
+ npm install hermes-wasm
19
+ ```
20
+
21
+ ### In-Memory Index
22
+
23
+ ```js
24
+ import init, { LocalIndex } from "hermes-wasm";
25
+
26
+ await init();
27
+
28
+ // Define schema using SDL
29
+ const index = await LocalIndex.create(`
30
+ index articles {
31
+ field title: text<en_stem> [indexed, stored]
32
+ field body: text<en_stem> [indexed, stored]
33
+ field views: u64 [indexed, stored]
34
+ }
35
+ `);
36
+
37
+ // Add documents
38
+ await index.addDocuments([
39
+ {
40
+ title: "Rust Programming",
41
+ body: "Rust is a systems language.",
42
+ views: 1500,
43
+ },
44
+ { title: "Search Engines", body: "BM25 is a ranking function.", views: 800 },
45
+ ]);
46
+
47
+ // Commit (builds the segment)
48
+ await index.commit();
49
+
50
+ // Search
51
+ const results = await index.search("rust", 10);
52
+ // { hits: [{ address: { segment_id, doc_id }, score }], total_hits: 1 }
53
+
54
+ // Get document
55
+ const doc = await index.getDocument(
56
+ results.hits[0].address.segment_id,
57
+ results.hits[0].address.doc_id,
58
+ );
59
+ // { title: "Rust Programming", body: "Rust is a systems language.", views: 1500 }
60
+ ```
61
+
62
+ ### Persistent Index (Custom Storage)
63
+
64
+ Bring your own storage backend — IndexedDB, encrypted storage, OPFS, or anything async:
65
+
66
+ ```ts
67
+ // Your storage must implement this interface:
68
+ interface IFilesStorage {
69
+ write(name: string, buffer: ArrayBuffer): Promise<void>;
70
+ get(name: string): Promise<ArrayBuffer | null>;
71
+ delete(names: string[]): Promise<void>;
72
+ list(): Promise<string[]>;
73
+ }
74
+ ```
75
+
76
+ ```js
77
+ // Create with custom storage — auto-saves changed files on each commit
78
+ const index = await LocalIndex.withStorage(myStorage, schema);
79
+ await index.addDocuments(docs);
80
+ await index.commit(); // only new segment files written to storage
81
+
82
+ // Later (page reload) — same call reopens if storage has files
83
+ const index = await LocalIndex.withStorage(myStorage, schema);
84
+ const results = await index.search("rust", 10); // works immediately
85
+ ```
86
+
87
+ A simple IndexedDB implementation:
88
+
89
+ ```js
90
+ class IdbStorage {
91
+ constructor(name) {
92
+ this.prefix = `idx:${name}:`;
93
+ }
94
+ async write(name, buffer) {
95
+ /* idb put this.prefix + name → buffer */
96
+ }
97
+ async get(name) {
98
+ /* idb get this.prefix + name */
99
+ }
100
+ async delete(names) {
101
+ /* idb delete each this.prefix + name */
102
+ }
103
+ async list() {
104
+ /* idb getAllKeys matching this.prefix, strip prefix */
105
+ }
106
+ }
107
+
108
+ const index = await LocalIndex.withStorage(new IdbStorage("articles"), schema);
109
+ ```
110
+
111
+ ### Remote Index (HTTP)
112
+
113
+ ```js
114
+ import init, { RemoteIndex } from "hermes-wasm";
115
+
116
+ await init();
117
+
118
+ const index = new RemoteIndex("https://example.com/my-index/");
119
+ await index.load_with_idb_cache(); // loads with IndexedDB cache for fast reload
120
+
121
+ const results = await index.search("query", 10);
122
+
123
+ // Fetch a document
124
+ const doc = await index.get_document(
125
+ results.hits[0].address.segment_id,
126
+ results.hits[0].address.doc_id,
127
+ );
128
+ ```
129
+
130
+ ## API Reference
131
+
132
+ ### `LocalIndex`
133
+
134
+ | Method | Description |
135
+ | ------------------------------------------ | -------------------------------------------------- |
136
+ | `LocalIndex.create(sdl)` | Create in-memory index from SDL schema |
137
+ | `LocalIndex.withStorage(storage, sdl)` | Create or open index with pluggable storage |
138
+ | `index.addDocument(json)` | Add a single document |
139
+ | `index.addDocuments(jsonArray)` | Add multiple documents, returns count |
140
+ | `index.commit()` | Commit pending docs, sync to storage if configured |
141
+ | `index.search(query, limit)` | Search with BM25 ranking |
142
+ | `index.searchOffset(query, limit, offset)` | Search with pagination |
143
+ | `index.getDocument(segmentId, docId)` | Retrieve stored document |
144
+ | `index.numDocs()` | Count of committed documents |
145
+ | `index.pendingDocs()` | Count of uncommitted documents |
146
+ | `index.fieldNames()` | List of field names |
147
+
148
+ ### `RemoteIndex`
149
+
150
+ | Method | Description |
151
+ | ------------------------------------------- | ----------------------------------- |
152
+ | `new RemoteIndex(url)` | Create remote index pointing to URL |
153
+ | `RemoteIndex.with_cache_size(url, bytes)` | Create with custom cache size |
154
+ | `index.load()` | Load index metadata and segments |
155
+ | `index.load_with_idb_cache()` | Load with IndexedDB cache pre-fill |
156
+ | `index.search(query, limit)` | Search |
157
+ | `index.search_offset(query, limit, offset)` | Search with pagination |
158
+ | `index.get_document(segmentId, docId)` | Retrieve document |
159
+ | `index.num_docs()` | Document count |
160
+ | `index.num_segments()` | Segment count |
161
+ | `index.field_names()` | Field names |
162
+ | `index.default_fields()` | Default search fields |
163
+ | `index.export_cache()` | Export slice cache as `Uint8Array` |
164
+ | `index.import_cache(data)` | Import previously exported cache |
165
+ | `index.save_cache_to_idb()` | Persist slice cache to IndexedDB |
166
+ | `index.load_cache_from_idb()` | Restore cache from IndexedDB |
167
+ | `index.clear_idb_cache()` | Remove persisted cache |
168
+ | `index.cache_stats()` | Cache utilization info |
169
+ | `index.network_stats()` | HTTP request statistics |
170
+ | `index.reset_network_stats()` | Clear network statistics |
171
+
172
+ ### `IpfsIndex`
173
+
174
+ Same API as `RemoteIndex` but loaded via JavaScript callbacks instead of HTTP:
175
+
176
+ | Method | Description |
177
+ | -------------------------------------------- | ---------------------------------------- |
178
+ | `new IpfsIndex(basePath)` | Create with IPFS path (e.g. `/ipfs/Qm…`) |
179
+ | `IpfsIndex.with_cache_size(path, bytes)` | Create with custom cache size |
180
+ | `index.load(fetchFn, sizeFn)` | Load using JS callbacks |
181
+ | `index.load_with_idb_cache(fetchFn, sizeFn)` | Load with IDB cache + JS callbacks |
182
+
183
+ `fetchFn`: `(path: string, rangeStart?: number, rangeEnd?: number) => Promise<Uint8Array>`
184
+ `sizeFn`: `(path: string) => Promise<number>`
185
+
186
+ All other methods (`search`, `get_document`, `cache_stats`, etc.) are identical to `RemoteIndex`.
187
+
188
+ ### `IndexRegistry`
189
+
190
+ Manages multiple named remote indexes:
191
+
192
+ | Method | Description |
193
+ | ------------------------------------- | ------------------------------ |
194
+ | `new IndexRegistry()` | Create empty registry |
195
+ | `registry.add_remote(name, url)` | Load and register remote index |
196
+ | `registry.remove(name)` | Remove index |
197
+ | `registry.list()` | List index names |
198
+ | `registry.search(name, query, limit)` | Search a specific index |
199
+
200
+ ### Schema Definition Language (SDL)
201
+
202
+ ```
203
+ index <name> {
204
+ field <name>: <type> [attributes]
205
+ }
206
+ ```
207
+
208
+ **Types:** `text`, `u64`, `i64`, `f64`, `bytes`
209
+
210
+ **Tokenizers:** `text<en_stem>`, `text<de_stem>`, `text<fr_stem>`, `text<es_stem>`, `text<it_stem>`, `text<pt_stem>`, `text<ru_stem>`, `text<ar_stem>`, `text<simple>`, etc.
211
+
212
+ **Attributes:** `indexed` (searchable), `stored` (retrievable), `fast` (columnar access)
213
+
214
+ ### Query Language
215
+
216
+ | Syntax | Example | Description |
217
+ | ------ | ---------------------- | --------------------------- |
218
+ | Term | `rust` | Match across default fields |
219
+ | Field | `title:rust` | Match in specific field |
220
+ | AND | `rust AND web` | Both terms required |
221
+ | OR | `rust OR python` | Either term |
222
+ | NOT | `rust NOT unsafe` | Exclude term |
223
+ | Group | `(rust OR go) AND web` | Grouping |
224
+ | Phrase | `"search engine"` | Exact phrase |
225
+
226
+ ## Building
227
+
228
+ ```bash
229
+ cd hermes-wasm
230
+ bash build.sh # requires Homebrew LLVM on macOS
231
+ ```
232
+
233
+ The build script sets `CC` and `AR` to Homebrew LLVM binaries for zstd cross-compilation to `wasm32-unknown-unknown`.
234
+
235
+ ## Example
236
+
237
+ Open `examples/index.html` in a browser (needs to be served, not opened as file):
238
+
239
+ ```bash
240
+ cd hermes-wasm
241
+ bash build.sh
242
+ cp pkg/hermes_wasm.js pkg/hermes_wasm_bg.wasm examples/
243
+ cd examples && python3 -m http.server 8080
244
+ # Open http://localhost:8080
245
+ ```
246
+
247
+ ## Architecture
248
+
249
+ ```
250
+ Browser JS
251
+
252
+ ├── LocalIndex (create/index/search in WASM)
253
+ │ └── WasmIndexWriter → SegmentBuilder → RamDirectory
254
+ │ │
255
+ │ [pluggable IFilesStorage]
256
+ │ (IDB, encrypted, OPFS, ...)
257
+
258
+ ├── RemoteIndex (HTTP range requests)
259
+ │ └── Searcher → SliceCachingDirectory → HttpDirectory
260
+
261
+ ├── IpfsIndex (JS fetch callbacks)
262
+ │ └── Searcher → SliceCachingDirectory → JsFetchDirectory
263
+
264
+ └── IndexRegistry (multi-index management)
265
+ └── Map<name, RemoteIndex>
266
+ ```
package/hermes_wasm.d.ts CHANGED
@@ -113,6 +113,9 @@ export class IpfsIndex {
113
113
  save_cache_to_idb(): Promise<void>;
114
114
  /**
115
115
  * Search the index
116
+ *
117
+ * Returns `{ hits: [{ address: { segment_id: string, doc_id: number }, score: number }], total_hits: number }`.
118
+ * Use `get_document(hit.address.segment_id, hit.address.doc_id)` to fetch document content.
116
119
  */
117
120
  search(query_str: string, limit: number): Promise<any>;
118
121
  /**
@@ -125,6 +128,86 @@ export class IpfsIndex {
125
128
  static with_cache_size(base_path: string, cache_size: number): IpfsIndex;
126
129
  }
127
130
 
131
+ /**
132
+ * In-browser local index — create, index documents, search, all in WASM.
133
+ *
134
+ * ```js
135
+ * // In-memory (ephemeral)
136
+ * const index = await LocalIndex.create("index articles { ... }");
137
+ *
138
+ * // With pluggable storage (IDB, encrypted, remote, etc.)
139
+ * const index = await LocalIndex.withStorage(myStorage, "index articles { ... }");
140
+ * ```
141
+ */
142
+ export class LocalIndex {
143
+ private constructor();
144
+ free(): void;
145
+ [Symbol.dispose](): void;
146
+ /**
147
+ * Add a single document (JSON object with field names matching the schema).
148
+ */
149
+ addDocument(doc_json: any): Promise<void>;
150
+ /**
151
+ * Add multiple documents at once (array of JSON objects).
152
+ */
153
+ addDocuments(docs_json: any): Promise<number>;
154
+ /**
155
+ * Commit pending documents — builds segments and updates metadata.
156
+ *
157
+ * For persistent indexes, only writes new/changed files to storage.
158
+ */
159
+ commit(): Promise<boolean>;
160
+ /**
161
+ * Create a new in-memory index from an SDL schema string.
162
+ *
163
+ * Data is lost on page refresh. Use `withStorage()` for persistence.
164
+ */
165
+ static create(schema_sdl: string): Promise<LocalIndex>;
166
+ /**
167
+ * Get field names from the schema.
168
+ */
169
+ fieldNames(): any;
170
+ /**
171
+ * Get a document by its address.
172
+ */
173
+ getDocument(segment_id: string, doc_id: number): Promise<any>;
174
+ /**
175
+ * Number of indexed documents (across all committed segments).
176
+ */
177
+ numDocs(): number;
178
+ /**
179
+ * Number of documents pending (not yet committed).
180
+ */
181
+ pendingDocs(): number;
182
+ /**
183
+ * Search the index.
184
+ *
185
+ * Returns `{ hits: [{ address: { segment_id, doc_id }, score }], total_hits }`.
186
+ */
187
+ search(query_str: string, limit: number): Promise<any>;
188
+ /**
189
+ * Search with offset for pagination.
190
+ */
191
+ searchOffset(query_str: string, limit: number, offset: number): Promise<any>;
192
+ /**
193
+ * Create or open an index with a pluggable storage backend.
194
+ *
195
+ * If the storage already contains index files, the index is reopened.
196
+ * Otherwise a new index is created from the SDL schema.
197
+ *
198
+ * The storage object must implement:
199
+ * ```ts
200
+ * interface IFilesStorage {
201
+ * write(name: string, buffer: ArrayBuffer): Promise<void>;
202
+ * get(name: string): Promise<ArrayBuffer | null>;
203
+ * delete(names: string[]): Promise<void>;
204
+ * list(): Promise<string[]>;
205
+ * }
206
+ * ```
207
+ */
208
+ static withStorage(storage: any, schema_sdl: string): Promise<LocalIndex>;
209
+ }
210
+
128
211
  /**
129
212
  * Remote index that loads data via HTTP with slice caching
130
213
  */
@@ -219,7 +302,9 @@ export class RemoteIndex {
219
302
  *
220
303
  * Accepts both query language syntax (field:term, AND, OR, NOT, grouping)
221
304
  * and simple text (tokenized and searched across default fields).
222
- * Returns document addresses (segment_id + doc_id) without document content.
305
+ *
306
+ * Returns `{ hits: [{ address: { segment_id: string, doc_id: number }, score: number }], total_hits: number }`.
307
+ * Use `get_document(hit.address.segment_id, hit.address.doc_id)` to fetch document content.
223
308
  */
224
309
  search(query_str: string, limit: number): Promise<any>;
225
310
  /**
@@ -246,30 +331,9 @@ export type InitInput = RequestInfo | URL | Response | BufferSource | WebAssembl
246
331
 
247
332
  export interface InitOutput {
248
333
  readonly memory: WebAssembly.Memory;
249
- readonly __wbg_remoteindex_free: (a: number, b: number) => void;
250
- readonly remoteindex_cache_stats: (a: number) => any;
251
- readonly remoteindex_clear_idb_cache: (a: number) => any;
252
- readonly remoteindex_default_fields: (a: number) => any;
253
- readonly remoteindex_export_cache: (a: number) => [number, number];
254
- readonly remoteindex_field_names: (a: number) => any;
255
- readonly remoteindex_get_document: (a: number, b: number, c: number, d: number) => any;
256
- readonly remoteindex_import_cache: (a: number, b: number, c: number) => [number, number];
257
- readonly remoteindex_load: (a: number) => any;
258
- readonly remoteindex_load_cache_from_idb: (a: number) => any;
259
- readonly remoteindex_load_with_idb_cache: (a: number) => any;
260
- readonly remoteindex_network_stats: (a: number) => any;
261
- readonly remoteindex_new: (a: number, b: number) => number;
262
- readonly remoteindex_num_docs: (a: number) => number;
263
- readonly remoteindex_num_segments: (a: number) => number;
264
- readonly remoteindex_reset_network_stats: (a: number) => void;
265
- readonly remoteindex_save_cache_to_idb: (a: number) => any;
266
- readonly remoteindex_search: (a: number, b: number, c: number, d: number) => any;
267
- readonly remoteindex_search_offset: (a: number, b: number, c: number, d: number, e: number) => any;
268
- readonly remoteindex_with_cache_size: (a: number, b: number, c: number) => number;
269
- readonly init: () => void;
270
- readonly setup_logging: () => void;
271
334
  readonly __wbg_indexregistry_free: (a: number, b: number) => void;
272
335
  readonly __wbg_ipfsindex_free: (a: number, b: number) => void;
336
+ readonly __wbg_remoteindex_free: (a: number, b: number) => void;
273
337
  readonly indexregistry_add_remote: (a: number, b: number, c: number, d: number, e: number) => any;
274
338
  readonly indexregistry_list: (a: number) => any;
275
339
  readonly indexregistry_new: () => number;
@@ -294,6 +358,39 @@ export interface InitOutput {
294
358
  readonly ipfsindex_search: (a: number, b: number, c: number, d: number) => any;
295
359
  readonly ipfsindex_search_offset: (a: number, b: number, c: number, d: number, e: number) => any;
296
360
  readonly ipfsindex_with_cache_size: (a: number, b: number, c: number) => number;
361
+ readonly remoteindex_cache_stats: (a: number) => any;
362
+ readonly remoteindex_clear_idb_cache: (a: number) => any;
363
+ readonly remoteindex_default_fields: (a: number) => any;
364
+ readonly remoteindex_export_cache: (a: number) => [number, number];
365
+ readonly remoteindex_field_names: (a: number) => any;
366
+ readonly remoteindex_get_document: (a: number, b: number, c: number, d: number) => any;
367
+ readonly remoteindex_import_cache: (a: number, b: number, c: number) => [number, number];
368
+ readonly remoteindex_load: (a: number) => any;
369
+ readonly remoteindex_load_cache_from_idb: (a: number) => any;
370
+ readonly remoteindex_load_with_idb_cache: (a: number) => any;
371
+ readonly remoteindex_network_stats: (a: number) => any;
372
+ readonly remoteindex_new: (a: number, b: number) => number;
373
+ readonly remoteindex_reset_network_stats: (a: number) => void;
374
+ readonly remoteindex_save_cache_to_idb: (a: number) => any;
375
+ readonly remoteindex_search: (a: number, b: number, c: number, d: number) => any;
376
+ readonly remoteindex_search_offset: (a: number, b: number, c: number, d: number, e: number) => any;
377
+ readonly remoteindex_with_cache_size: (a: number, b: number, c: number) => number;
378
+ readonly remoteindex_num_docs: (a: number) => number;
379
+ readonly remoteindex_num_segments: (a: number) => number;
380
+ readonly __wbg_localindex_free: (a: number, b: number) => void;
381
+ readonly localindex_addDocument: (a: number, b: any) => any;
382
+ readonly localindex_addDocuments: (a: number, b: any) => any;
383
+ readonly localindex_commit: (a: number) => any;
384
+ readonly localindex_create: (a: number, b: number) => any;
385
+ readonly localindex_fieldNames: (a: number) => any;
386
+ readonly localindex_getDocument: (a: number, b: number, c: number, d: number) => any;
387
+ readonly localindex_numDocs: (a: number) => number;
388
+ readonly localindex_pendingDocs: (a: number) => number;
389
+ readonly localindex_search: (a: number, b: number, c: number, d: number) => any;
390
+ readonly localindex_searchOffset: (a: number, b: number, c: number, d: number, e: number) => any;
391
+ readonly localindex_withStorage: (a: any, b: number, c: number) => any;
392
+ readonly init: () => void;
393
+ readonly setup_logging: () => void;
297
394
  readonly rust_zstd_wasm_shim_calloc: (a: number, b: number) => number;
298
395
  readonly rust_zstd_wasm_shim_free: (a: number) => void;
299
396
  readonly rust_zstd_wasm_shim_malloc: (a: number) => number;
package/hermes_wasm.js CHANGED
@@ -254,6 +254,9 @@ export class IpfsIndex {
254
254
  }
255
255
  /**
256
256
  * Search the index
257
+ *
258
+ * Returns `{ hits: [{ address: { segment_id: string, doc_id: number }, score: number }], total_hits: number }`.
259
+ * Use `get_document(hit.address.segment_id, hit.address.doc_id)` to fetch document content.
257
260
  * @param {string} query_str
258
261
  * @param {number} limit
259
262
  * @returns {Promise<any>}
@@ -292,6 +295,167 @@ export class IpfsIndex {
292
295
  }
293
296
  if (Symbol.dispose) IpfsIndex.prototype[Symbol.dispose] = IpfsIndex.prototype.free;
294
297
 
298
+ /**
299
+ * In-browser local index — create, index documents, search, all in WASM.
300
+ *
301
+ * ```js
302
+ * // In-memory (ephemeral)
303
+ * const index = await LocalIndex.create("index articles { ... }");
304
+ *
305
+ * // With pluggable storage (IDB, encrypted, remote, etc.)
306
+ * const index = await LocalIndex.withStorage(myStorage, "index articles { ... }");
307
+ * ```
308
+ */
309
+ export class LocalIndex {
310
+ static __wrap(ptr) {
311
+ ptr = ptr >>> 0;
312
+ const obj = Object.create(LocalIndex.prototype);
313
+ obj.__wbg_ptr = ptr;
314
+ LocalIndexFinalization.register(obj, obj.__wbg_ptr, obj);
315
+ return obj;
316
+ }
317
+ __destroy_into_raw() {
318
+ const ptr = this.__wbg_ptr;
319
+ this.__wbg_ptr = 0;
320
+ LocalIndexFinalization.unregister(this);
321
+ return ptr;
322
+ }
323
+ free() {
324
+ const ptr = this.__destroy_into_raw();
325
+ wasm.__wbg_localindex_free(ptr, 0);
326
+ }
327
+ /**
328
+ * Add a single document (JSON object with field names matching the schema).
329
+ * @param {any} doc_json
330
+ * @returns {Promise<void>}
331
+ */
332
+ addDocument(doc_json) {
333
+ const ret = wasm.localindex_addDocument(this.__wbg_ptr, doc_json);
334
+ return ret;
335
+ }
336
+ /**
337
+ * Add multiple documents at once (array of JSON objects).
338
+ * @param {any} docs_json
339
+ * @returns {Promise<number>}
340
+ */
341
+ addDocuments(docs_json) {
342
+ const ret = wasm.localindex_addDocuments(this.__wbg_ptr, docs_json);
343
+ return ret;
344
+ }
345
+ /**
346
+ * Commit pending documents — builds segments and updates metadata.
347
+ *
348
+ * For persistent indexes, only writes new/changed files to storage.
349
+ * @returns {Promise<boolean>}
350
+ */
351
+ commit() {
352
+ const ret = wasm.localindex_commit(this.__wbg_ptr);
353
+ return ret;
354
+ }
355
+ /**
356
+ * Create a new in-memory index from an SDL schema string.
357
+ *
358
+ * Data is lost on page refresh. Use `withStorage()` for persistence.
359
+ * @param {string} schema_sdl
360
+ * @returns {Promise<LocalIndex>}
361
+ */
362
+ static create(schema_sdl) {
363
+ const ptr0 = passStringToWasm0(schema_sdl, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
364
+ const len0 = WASM_VECTOR_LEN;
365
+ const ret = wasm.localindex_create(ptr0, len0);
366
+ return ret;
367
+ }
368
+ /**
369
+ * Get field names from the schema.
370
+ * @returns {any}
371
+ */
372
+ fieldNames() {
373
+ const ret = wasm.localindex_fieldNames(this.__wbg_ptr);
374
+ return ret;
375
+ }
376
+ /**
377
+ * Get a document by its address.
378
+ * @param {string} segment_id
379
+ * @param {number} doc_id
380
+ * @returns {Promise<any>}
381
+ */
382
+ getDocument(segment_id, doc_id) {
383
+ const ptr0 = passStringToWasm0(segment_id, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
384
+ const len0 = WASM_VECTOR_LEN;
385
+ const ret = wasm.localindex_getDocument(this.__wbg_ptr, ptr0, len0, doc_id);
386
+ return ret;
387
+ }
388
+ /**
389
+ * Number of indexed documents (across all committed segments).
390
+ * @returns {number}
391
+ */
392
+ numDocs() {
393
+ const ret = wasm.localindex_numDocs(this.__wbg_ptr);
394
+ return ret >>> 0;
395
+ }
396
+ /**
397
+ * Number of documents pending (not yet committed).
398
+ * @returns {number}
399
+ */
400
+ pendingDocs() {
401
+ const ret = wasm.localindex_pendingDocs(this.__wbg_ptr);
402
+ return ret >>> 0;
403
+ }
404
+ /**
405
+ * Search the index.
406
+ *
407
+ * Returns `{ hits: [{ address: { segment_id, doc_id }, score }], total_hits }`.
408
+ * @param {string} query_str
409
+ * @param {number} limit
410
+ * @returns {Promise<any>}
411
+ */
412
+ search(query_str, limit) {
413
+ const ptr0 = passStringToWasm0(query_str, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
414
+ const len0 = WASM_VECTOR_LEN;
415
+ const ret = wasm.localindex_search(this.__wbg_ptr, ptr0, len0, limit);
416
+ return ret;
417
+ }
418
+ /**
419
+ * Search with offset for pagination.
420
+ * @param {string} query_str
421
+ * @param {number} limit
422
+ * @param {number} offset
423
+ * @returns {Promise<any>}
424
+ */
425
+ searchOffset(query_str, limit, offset) {
426
+ const ptr0 = passStringToWasm0(query_str, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
427
+ const len0 = WASM_VECTOR_LEN;
428
+ const ret = wasm.localindex_searchOffset(this.__wbg_ptr, ptr0, len0, limit, offset);
429
+ return ret;
430
+ }
431
+ /**
432
+ * Create or open an index with a pluggable storage backend.
433
+ *
434
+ * If the storage already contains index files, the index is reopened.
435
+ * Otherwise a new index is created from the SDL schema.
436
+ *
437
+ * The storage object must implement:
438
+ * ```ts
439
+ * interface IFilesStorage {
440
+ * write(name: string, buffer: ArrayBuffer): Promise<void>;
441
+ * get(name: string): Promise<ArrayBuffer | null>;
442
+ * delete(names: string[]): Promise<void>;
443
+ * list(): Promise<string[]>;
444
+ * }
445
+ * ```
446
+ * @param {any} storage
447
+ * @param {string} schema_sdl
448
+ * @returns {Promise<LocalIndex>}
449
+ */
450
+ static withStorage(storage, schema_sdl) {
451
+ const ptr0 = passStringToWasm0(schema_sdl, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
452
+ const len0 = WASM_VECTOR_LEN;
453
+ const ret = wasm.localindex_withStorage(storage, ptr0, len0);
454
+ return ret;
455
+ }
456
+ }
457
+ if (Symbol.dispose) LocalIndex.prototype[Symbol.dispose] = LocalIndex.prototype.free;
458
+
295
459
  /**
296
460
  * Remote index that loads data via HTTP with slice caching
297
461
  */
@@ -480,7 +644,9 @@ export class RemoteIndex {
480
644
  *
481
645
  * Accepts both query language syntax (field:term, AND, OR, NOT, grouping)
482
646
  * and simple text (tokenized and searched across default fields).
483
- * Returns document addresses (segment_id + doc_id) without document content.
647
+ *
648
+ * Returns `{ hits: [{ address: { segment_id: string, doc_id: number }, score: number }], total_hits: number }`.
649
+ * Use `get_document(hit.address.segment_id, hit.address.doc_id)` to fetch document content.
484
650
  * @param {string} query_str
485
651
  * @param {number} limit
486
652
  * @returns {Promise<any>}
@@ -547,6 +713,17 @@ function __wbg_get_imports() {
547
713
  getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
548
714
  getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
549
715
  },
716
+ __wbg___wbindgen_bigint_get_as_i64_447a76b5c6ef7bda: function(arg0, arg1) {
717
+ const v = arg1;
718
+ const ret = typeof(v) === 'bigint' ? v : undefined;
719
+ getDataViewMemory0().setBigInt64(arg0 + 8 * 1, isLikeNone(ret) ? BigInt(0) : ret, true);
720
+ getDataViewMemory0().setInt32(arg0 + 4 * 0, !isLikeNone(ret), true);
721
+ },
722
+ __wbg___wbindgen_boolean_get_c0f3f60bac5a78d1: function(arg0) {
723
+ const v = arg0;
724
+ const ret = typeof(v) === 'boolean' ? v : undefined;
725
+ return isLikeNone(ret) ? 0xFFFFFF : ret ? 1 : 0;
726
+ },
550
727
  __wbg___wbindgen_debug_string_5398f5bb970e0daa: function(arg0, arg1) {
551
728
  const ret = debugString(arg1);
552
729
  const ptr1 = passStringToWasm0(ret, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
@@ -554,6 +731,14 @@ function __wbg_get_imports() {
554
731
  getDataViewMemory0().setInt32(arg0 + 4 * 1, len1, true);
555
732
  getDataViewMemory0().setInt32(arg0 + 4 * 0, ptr1, true);
556
733
  },
734
+ __wbg___wbindgen_in_41dbb8413020e076: function(arg0, arg1) {
735
+ const ret = arg0 in arg1;
736
+ return ret;
737
+ },
738
+ __wbg___wbindgen_is_bigint_e2141d4f045b7eda: function(arg0) {
739
+ const ret = typeof(arg0) === 'bigint';
740
+ return ret;
741
+ },
557
742
  __wbg___wbindgen_is_function_3c846841762788c1: function(arg0) {
558
743
  const ret = typeof(arg0) === 'function';
559
744
  return ret;
@@ -562,6 +747,11 @@ function __wbg_get_imports() {
562
747
  const ret = arg0 === null;
563
748
  return ret;
564
749
  },
750
+ __wbg___wbindgen_is_object_781bc9f159099513: function(arg0) {
751
+ const val = arg0;
752
+ const ret = typeof(val) === 'object' && val !== null;
753
+ return ret;
754
+ },
565
755
  __wbg___wbindgen_is_string_7ef6b97b02428fae: function(arg0) {
566
756
  const ret = typeof(arg0) === 'string';
567
757
  return ret;
@@ -570,6 +760,14 @@ function __wbg_get_imports() {
570
760
  const ret = arg0 === undefined;
571
761
  return ret;
572
762
  },
763
+ __wbg___wbindgen_jsval_eq_ee31bfad3e536463: function(arg0, arg1) {
764
+ const ret = arg0 === arg1;
765
+ return ret;
766
+ },
767
+ __wbg___wbindgen_jsval_loose_eq_5bcc3bed3c69e72b: function(arg0, arg1) {
768
+ const ret = arg0 == arg1;
769
+ return ret;
770
+ },
573
771
  __wbg___wbindgen_number_get_34bb9d9dcfa21373: function(arg0, arg1) {
574
772
  const obj = arg1;
575
773
  const ret = typeof(obj) === 'number' ? obj : undefined;
@@ -603,10 +801,22 @@ function __wbg_get_imports() {
603
801
  const ret = arg0.arrayBuffer();
604
802
  return ret;
605
803
  }, arguments); },
804
+ __wbg_buffer_60b8043cd926067d: function(arg0) {
805
+ const ret = arg0.buffer;
806
+ return ret;
807
+ },
606
808
  __wbg_call_2d781c1f4d5c0ef8: function() { return handleError(function (arg0, arg1, arg2) {
607
809
  const ret = arg0.call(arg1, arg2);
608
810
  return ret;
609
811
  }, arguments); },
812
+ __wbg_call_dcc2662fa17a72cf: function() { return handleError(function (arg0, arg1, arg2, arg3) {
813
+ const ret = arg0.call(arg1, arg2, arg3);
814
+ return ret;
815
+ }, arguments); },
816
+ __wbg_call_e133b57c9155d22c: function() { return handleError(function (arg0, arg1) {
817
+ const ret = arg0.call(arg1);
818
+ return ret;
819
+ }, arguments); },
610
820
  __wbg_call_f858478a02f9600f: function() { return handleError(function (arg0, arg1, arg2, arg3, arg4) {
611
821
  const ret = arg0.call(arg1, arg2, arg3, arg4);
612
822
  return ret;
@@ -638,6 +848,10 @@ function __wbg_get_imports() {
638
848
  const ret = arg0.entries();
639
849
  return ret;
640
850
  },
851
+ __wbg_entries_e8a20ff8c9757101: function(arg0) {
852
+ const ret = Object.entries(arg0);
853
+ return ret;
854
+ },
641
855
  __wbg_error_8d9a8e04cd1d3588: function(arg0) {
642
856
  console.error(arg0);
643
857
  },
@@ -664,6 +878,13 @@ function __wbg_get_imports() {
664
878
  const ret = arg0.fetch(arg1);
665
879
  return ret;
666
880
  },
881
+ __wbg_getRandomValues_3f44b700395062e5: function() { return handleError(function (arg0, arg1) {
882
+ globalThis.crypto.getRandomValues(getArrayU8FromWasm0(arg0, arg1));
883
+ }, arguments); },
884
+ __wbg_get_326e41e095fb2575: function() { return handleError(function (arg0, arg1) {
885
+ const ret = Reflect.get(arg0, arg1);
886
+ return ret;
887
+ }, arguments); },
667
888
  __wbg_get_3ef1eba1850ade27: function() { return handleError(function (arg0, arg1) {
668
889
  const ret = Reflect.get(arg0, arg1);
669
890
  return ret;
@@ -676,6 +897,10 @@ function __wbg_get_imports() {
676
897
  const ret = arg0[arg1 >>> 0];
677
898
  return ret;
678
899
  },
900
+ __wbg_get_unchecked_329cfe50afab7352: function(arg0, arg1) {
901
+ const ret = arg0[arg1 >>> 0];
902
+ return ret;
903
+ },
679
904
  __wbg_has_926ef2ff40b308cf: function() { return handleError(function (arg0, arg1) {
680
905
  const ret = Reflect.has(arg0, arg1);
681
906
  return ret;
@@ -691,6 +916,16 @@ function __wbg_get_imports() {
691
916
  __wbg_info_7d4e223bb1a7e671: function(arg0) {
692
917
  console.info(arg0);
693
918
  },
919
+ __wbg_instanceof_ArrayBuffer_101e2bf31071a9f6: function(arg0) {
920
+ let result;
921
+ try {
922
+ result = arg0 instanceof ArrayBuffer;
923
+ } catch (_) {
924
+ result = false;
925
+ }
926
+ const ret = result;
927
+ return ret;
928
+ },
694
929
  __wbg_instanceof_IdbDatabase_5f436cc89cc07f14: function(arg0) {
695
930
  let result;
696
931
  try {
@@ -721,6 +956,16 @@ function __wbg_get_imports() {
721
956
  const ret = result;
722
957
  return ret;
723
958
  },
959
+ __wbg_instanceof_Map_f194b366846aca0c: function(arg0) {
960
+ let result;
961
+ try {
962
+ result = arg0 instanceof Map;
963
+ } catch (_) {
964
+ result = false;
965
+ }
966
+ const ret = result;
967
+ return ret;
968
+ },
724
969
  __wbg_instanceof_Response_9b4d9fd451e051b1: function(arg0) {
725
970
  let result;
726
971
  try {
@@ -755,10 +1000,26 @@ function __wbg_get_imports() {
755
1000
  const ret = Array.isArray(arg0);
756
1001
  return ret;
757
1002
  },
1003
+ __wbg_isSafeInteger_ecd6a7f9c3e053cd: function(arg0) {
1004
+ const ret = Number.isSafeInteger(arg0);
1005
+ return ret;
1006
+ },
1007
+ __wbg_iterator_d8f549ec8fb061b1: function() {
1008
+ const ret = Symbol.iterator;
1009
+ return ret;
1010
+ },
1011
+ __wbg_length_b3416cf66a5452c8: function(arg0) {
1012
+ const ret = arg0.length;
1013
+ return ret;
1014
+ },
758
1015
  __wbg_length_ea16607d7b61445b: function(arg0) {
759
1016
  const ret = arg0.length;
760
1017
  return ret;
761
1018
  },
1019
+ __wbg_localindex_new: function(arg0) {
1020
+ const ret = LocalIndex.__wrap(arg0);
1021
+ return ret;
1022
+ },
762
1023
  __wbg_log_524eedafa26daa59: function(arg0) {
763
1024
  console.log(arg0);
764
1025
  },
@@ -820,6 +1081,10 @@ function __wbg_get_imports() {
820
1081
  const ret = arg0.next();
821
1082
  return ret;
822
1083
  }, arguments); },
1084
+ __wbg_next_e01a967809d1aa68: function(arg0) {
1085
+ const ret = arg0.next;
1086
+ return ret;
1087
+ },
823
1088
  __wbg_now_c6d7a7d35f74f6f1: function(arg0) {
824
1089
  const ret = arg0.now();
825
1090
  return ret;
@@ -843,6 +1108,10 @@ function __wbg_get_imports() {
843
1108
  __wbg_prototypesetcall_d62e5099504357e6: function(arg0, arg1, arg2) {
844
1109
  Uint8Array.prototype.set.call(getArrayU8FromWasm0(arg0, arg1), arg2);
845
1110
  },
1111
+ __wbg_push_e87b0e732085a946: function(arg0, arg1) {
1112
+ const ret = arg0.push(arg1);
1113
+ return ret;
1114
+ },
846
1115
  __wbg_put_f1673d719f93ce22: function() { return handleError(function (arg0, arg1, arg2) {
847
1116
  const ret = arg0.put(arg1, arg2);
848
1117
  return ret;
@@ -975,22 +1244,22 @@ function __wbg_get_imports() {
975
1244
  console.warn(arg0);
976
1245
  },
977
1246
  __wbindgen_cast_0000000000000001: function(arg0, arg1) {
978
- // Cast intrinsic for `Closure(Closure { dtor_idx: 205, function: Function { arguments: [NamedExternref("Event")], shim_idx: 206, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
1247
+ // Cast intrinsic for `Closure(Closure { dtor_idx: 243, function: Function { arguments: [NamedExternref("Event")], shim_idx: 244, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
979
1248
  const ret = makeMutClosure(arg0, arg1, wasm.wasm_bindgen_efede8c867e8014b___closure__destroy___dyn_core_5858575f5ab61d4b___ops__function__FnMut__web_sys_108d82c43c7519e2___features__gen_IdbVersionChangeEvent__IdbVersionChangeEvent____Output_______, wasm_bindgen_efede8c867e8014b___convert__closures_____invoke___web_sys_108d82c43c7519e2___features__gen_IdbVersionChangeEvent__IdbVersionChangeEvent______true_);
980
1249
  return ret;
981
1250
  },
982
1251
  __wbindgen_cast_0000000000000002: function(arg0, arg1) {
983
- // Cast intrinsic for `Closure(Closure { dtor_idx: 205, function: Function { arguments: [NamedExternref("IDBVersionChangeEvent")], shim_idx: 206, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
1252
+ // Cast intrinsic for `Closure(Closure { dtor_idx: 243, function: Function { arguments: [NamedExternref("IDBVersionChangeEvent")], shim_idx: 244, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
984
1253
  const ret = makeMutClosure(arg0, arg1, wasm.wasm_bindgen_efede8c867e8014b___closure__destroy___dyn_core_5858575f5ab61d4b___ops__function__FnMut__web_sys_108d82c43c7519e2___features__gen_IdbVersionChangeEvent__IdbVersionChangeEvent____Output_______, wasm_bindgen_efede8c867e8014b___convert__closures_____invoke___web_sys_108d82c43c7519e2___features__gen_IdbVersionChangeEvent__IdbVersionChangeEvent______true__1);
985
1254
  return ret;
986
1255
  },
987
1256
  __wbindgen_cast_0000000000000003: function(arg0, arg1) {
988
- // Cast intrinsic for `Closure(Closure { dtor_idx: 602, function: Function { arguments: [], shim_idx: 603, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
1257
+ // Cast intrinsic for `Closure(Closure { dtor_idx: 741, function: Function { arguments: [], shim_idx: 742, ret: Unit, inner_ret: Some(Unit) }, mutable: true }) -> Externref`.
989
1258
  const ret = makeMutClosure(arg0, arg1, wasm.wasm_bindgen_efede8c867e8014b___closure__destroy___dyn_core_5858575f5ab61d4b___ops__function__FnMut_____Output_______, wasm_bindgen_efede8c867e8014b___convert__closures_____invoke_______true_);
990
1259
  return ret;
991
1260
  },
992
1261
  __wbindgen_cast_0000000000000004: function(arg0, arg1) {
993
- // Cast intrinsic for `Closure(Closure { dtor_idx: 632, function: Function { arguments: [Externref], shim_idx: 633, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
1262
+ // Cast intrinsic for `Closure(Closure { dtor_idx: 771, function: Function { arguments: [Externref], shim_idx: 772, ret: Result(Unit), inner_ret: Some(Result(Unit)) }, mutable: true }) -> Externref`.
994
1263
  const ret = makeMutClosure(arg0, arg1, wasm.wasm_bindgen_efede8c867e8014b___closure__destroy___dyn_core_5858575f5ab61d4b___ops__function__FnMut__wasm_bindgen_efede8c867e8014b___JsValue____Output___core_5858575f5ab61d4b___result__Result_____wasm_bindgen_efede8c867e8014b___JsError___, wasm_bindgen_efede8c867e8014b___convert__closures_____invoke___wasm_bindgen_efede8c867e8014b___JsValue__core_5858575f5ab61d4b___result__Result_____wasm_bindgen_efede8c867e8014b___JsError___true_);
995
1264
  return ret;
996
1265
  },
@@ -1070,6 +1339,9 @@ const IndexRegistryFinalization = (typeof FinalizationRegistry === 'undefined')
1070
1339
  const IpfsIndexFinalization = (typeof FinalizationRegistry === 'undefined')
1071
1340
  ? { register: () => {}, unregister: () => {} }
1072
1341
  : new FinalizationRegistry(ptr => wasm.__wbg_ipfsindex_free(ptr >>> 0, 1));
1342
+ const LocalIndexFinalization = (typeof FinalizationRegistry === 'undefined')
1343
+ ? { register: () => {}, unregister: () => {} }
1344
+ : new FinalizationRegistry(ptr => wasm.__wbg_localindex_free(ptr >>> 0, 1));
1073
1345
  const RemoteIndexFinalization = (typeof FinalizationRegistry === 'undefined')
1074
1346
  ? { register: () => {}, unregister: () => {} }
1075
1347
  : new FinalizationRegistry(ptr => wasm.__wbg_remoteindex_free(ptr >>> 0, 1));
Binary file
package/package.json CHANGED
@@ -5,7 +5,7 @@
5
5
  "izihawa"
6
6
  ],
7
7
  "description": "WASM bindings for Hermes search engine",
8
- "version": "1.8.28",
8
+ "version": "1.8.30",
9
9
  "license": "MIT",
10
10
  "repository": {
11
11
  "type": "git",