hermes-wasm 1.8.29 → 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 CHANGED
@@ -5,7 +5,7 @@ WebAssembly bindings for the [Hermes](https://github.com/SpaceFrontiers/hermes)
5
5
  ## Features
6
6
 
7
7
  - **Local indexing** — create indexes, add documents, commit, and search entirely in WASM
8
- - **IndexedDB persistence** — indexes survive page refreshes via per-file IDB records
8
+ - **Pluggable persistence** — bring your own storage (IDB, encrypted, OPFS) via simple JS interface
9
9
  - **Remote search** — load pre-built indexes over HTTP with slice caching
10
10
  - **IPFS support** — load indexes from IPFS via JavaScript fetch callbacks
11
11
  - **15+ language stemmers** — English, German, French, Spanish, Russian, Arabic, and more
@@ -59,21 +59,53 @@ const doc = await index.getDocument(
59
59
  // { title: "Rust Programming", body: "Rust is a systems language.", views: 1500 }
60
60
  ```
61
61
 
62
- ### Persistent Index (IndexedDB)
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
+ ```
63
75
 
64
76
  ```js
65
- // Create — auto-saves changed files to IDB on each commit
66
- const index = await LocalIndex.createPersistent("my-index", schema);
77
+ // Create with custom storage — auto-saves changed files on each commit
78
+ const index = await LocalIndex.withStorage(myStorage, schema);
67
79
  await index.addDocuments(docs);
68
- await index.commit(); // only new segment files written to IDB
80
+ await index.commit(); // only new segment files written to storage
69
81
 
70
- // Later, on page reload:
71
- const index = await LocalIndex.open("my-index");
82
+ // Later (page reload) — same call reopens if storage has files
83
+ const index = await LocalIndex.withStorage(myStorage, schema);
72
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
+ }
73
107
 
74
- // Management
75
- await LocalIndex.exists("my-index"); // true
76
- await LocalIndex.deleteIndex("my-index");
108
+ const index = await LocalIndex.withStorage(new IdbStorage("articles"), schema);
77
109
  ```
78
110
 
79
111
  ### Remote Index (HTTP)
@@ -99,22 +131,19 @@ const doc = await index.get_document(
99
131
 
100
132
  ### `LocalIndex`
101
133
 
102
- | Method | Description |
103
- | ------------------------------------------ | --------------------------------------- |
104
- | `LocalIndex.create(sdl)` | Create in-memory index from SDL schema |
105
- | `LocalIndex.createPersistent(name, sdl)` | Create IndexedDB-backed index |
106
- | `LocalIndex.open(name)` | Open existing persistent index from IDB |
107
- | `LocalIndex.deleteIndex(name)` | Delete persistent index from IDB |
108
- | `LocalIndex.exists(name)` | Check if persistent index exists in IDB |
109
- | `index.addDocument(json)` | Add a single document |
110
- | `index.addDocuments(jsonArray)` | Add multiple documents, returns count |
111
- | `index.commit()` | Commit pending docs (builds segments) |
112
- | `index.search(query, limit)` | Search with BM25 ranking |
113
- | `index.searchOffset(query, limit, offset)` | Search with pagination |
114
- | `index.getDocument(segmentId, docId)` | Retrieve stored document |
115
- | `index.numDocs()` | Count of committed documents |
116
- | `index.pendingDocs()` | Count of uncommitted documents |
117
- | `index.fieldNames()` | List of field names |
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 |
118
147
 
119
148
  ### `RemoteIndex`
120
149
 
@@ -223,7 +252,8 @@ Browser JS
223
252
  ├── LocalIndex (create/index/search in WASM)
224
253
  │ └── WasmIndexWriter → SegmentBuilder → RamDirectory
225
254
  │ │
226
- │ [per-file IndexedDB records]
255
+ │ [pluggable IFilesStorage]
256
+ │ (IDB, encrypted, OPFS, ...)
227
257
 
228
258
  ├── RemoteIndex (HTTP range requests)
229
259
  │ └── Searcher → SliceCachingDirectory → HttpDirectory
package/hermes_wasm.d.ts CHANGED
@@ -133,12 +133,10 @@ export class IpfsIndex {
133
133
  *
134
134
  * ```js
135
135
  * // In-memory (ephemeral)
136
- * const index = await LocalIndex.create("index articles { field title: text<en_stem> [indexed, stored] }");
136
+ * const index = await LocalIndex.create("index articles { ... }");
137
137
  *
138
- * // Persistent (IndexedDB-backed)
139
- * const index = await LocalIndex.createPersistent("my-index", "index articles { ... }");
140
- * // ... later, on page reload:
141
- * const index = await LocalIndex.open("my-index");
138
+ * // With pluggable storage (IDB, encrypted, remote, etc.)
139
+ * const index = await LocalIndex.withStorage(myStorage, "index articles { ... }");
142
140
  * ```
143
141
  */
144
142
  export class LocalIndex {
@@ -156,31 +154,15 @@ export class LocalIndex {
156
154
  /**
157
155
  * Commit pending documents — builds segments and updates metadata.
158
156
  *
159
- * For persistent indexes, only writes new/changed files to IndexedDB.
157
+ * For persistent indexes, only writes new/changed files to storage.
160
158
  */
161
159
  commit(): Promise<boolean>;
162
160
  /**
163
161
  * Create a new in-memory index from an SDL schema string.
164
162
  *
165
- * Data is lost on page refresh. Use `createPersistent()` for IndexedDB-backed storage.
163
+ * Data is lost on page refresh. Use `withStorage()` for persistence.
166
164
  */
167
165
  static create(schema_sdl: string): Promise<LocalIndex>;
168
- /**
169
- * Create a new persistent index backed by IndexedDB.
170
- *
171
- * Each file in the index gets its own IDB record — commits only write
172
- * new/changed files, not the entire index.
173
- * Use `LocalIndex.open(name)` to reopen it after page refresh.
174
- */
175
- static createPersistent(name: string, schema_sdl: string): Promise<LocalIndex>;
176
- /**
177
- * Delete a persistent index from IndexedDB.
178
- */
179
- static deleteIndex(name: string): Promise<void>;
180
- /**
181
- * Check if a persistent index exists in IndexedDB.
182
- */
183
- static exists(name: string): Promise<boolean>;
184
166
  /**
185
167
  * Get field names from the schema.
186
168
  */
@@ -193,12 +175,6 @@ export class LocalIndex {
193
175
  * Number of indexed documents (across all committed segments).
194
176
  */
195
177
  numDocs(): number;
196
- /**
197
- * Open an existing persistent index from IndexedDB.
198
- *
199
- * Loads the file manifest and all index files into a RamDirectory.
200
- */
201
- static open(name: string): Promise<LocalIndex>;
202
178
  /**
203
179
  * Number of documents pending (not yet committed).
204
180
  */
@@ -213,6 +189,23 @@ export class LocalIndex {
213
189
  * Search with offset for pagination.
214
190
  */
215
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>;
216
209
  }
217
210
 
218
211
  /**
@@ -382,8 +375,6 @@ export interface InitOutput {
382
375
  readonly remoteindex_search: (a: number, b: number, c: number, d: number) => any;
383
376
  readonly remoteindex_search_offset: (a: number, b: number, c: number, d: number, e: number) => any;
384
377
  readonly remoteindex_with_cache_size: (a: number, b: number, c: number) => number;
385
- readonly init: () => void;
386
- readonly setup_logging: () => void;
387
378
  readonly remoteindex_num_docs: (a: number) => number;
388
379
  readonly remoteindex_num_segments: (a: number) => number;
389
380
  readonly __wbg_localindex_free: (a: number, b: number) => void;
@@ -391,16 +382,15 @@ export interface InitOutput {
391
382
  readonly localindex_addDocuments: (a: number, b: any) => any;
392
383
  readonly localindex_commit: (a: number) => any;
393
384
  readonly localindex_create: (a: number, b: number) => any;
394
- readonly localindex_createPersistent: (a: number, b: number, c: number, d: number) => any;
395
- readonly localindex_deleteIndex: (a: number, b: number) => any;
396
- readonly localindex_exists: (a: number, b: number) => any;
397
385
  readonly localindex_fieldNames: (a: number) => any;
398
386
  readonly localindex_getDocument: (a: number, b: number, c: number, d: number) => any;
399
387
  readonly localindex_numDocs: (a: number) => number;
400
- readonly localindex_open: (a: number, b: number) => any;
401
388
  readonly localindex_pendingDocs: (a: number) => number;
402
389
  readonly localindex_search: (a: number, b: number, c: number, d: number) => any;
403
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;
404
394
  readonly rust_zstd_wasm_shim_calloc: (a: number, b: number) => number;
405
395
  readonly rust_zstd_wasm_shim_free: (a: number) => void;
406
396
  readonly rust_zstd_wasm_shim_malloc: (a: number) => number;
package/hermes_wasm.js CHANGED
@@ -300,12 +300,10 @@ if (Symbol.dispose) IpfsIndex.prototype[Symbol.dispose] = IpfsIndex.prototype.fr
300
300
  *
301
301
  * ```js
302
302
  * // In-memory (ephemeral)
303
- * const index = await LocalIndex.create("index articles { field title: text<en_stem> [indexed, stored] }");
303
+ * const index = await LocalIndex.create("index articles { ... }");
304
304
  *
305
- * // Persistent (IndexedDB-backed)
306
- * const index = await LocalIndex.createPersistent("my-index", "index articles { ... }");
307
- * // ... later, on page reload:
308
- * const index = await LocalIndex.open("my-index");
305
+ * // With pluggable storage (IDB, encrypted, remote, etc.)
306
+ * const index = await LocalIndex.withStorage(myStorage, "index articles { ... }");
309
307
  * ```
310
308
  */
311
309
  export class LocalIndex {
@@ -347,7 +345,7 @@ export class LocalIndex {
347
345
  /**
348
346
  * Commit pending documents — builds segments and updates metadata.
349
347
  *
350
- * For persistent indexes, only writes new/changed files to IndexedDB.
348
+ * For persistent indexes, only writes new/changed files to storage.
351
349
  * @returns {Promise<boolean>}
352
350
  */
353
351
  commit() {
@@ -357,7 +355,7 @@ export class LocalIndex {
357
355
  /**
358
356
  * Create a new in-memory index from an SDL schema string.
359
357
  *
360
- * Data is lost on page refresh. Use `createPersistent()` for IndexedDB-backed storage.
358
+ * Data is lost on page refresh. Use `withStorage()` for persistence.
361
359
  * @param {string} schema_sdl
362
360
  * @returns {Promise<LocalIndex>}
363
361
  */
@@ -367,46 +365,6 @@ export class LocalIndex {
367
365
  const ret = wasm.localindex_create(ptr0, len0);
368
366
  return ret;
369
367
  }
370
- /**
371
- * Create a new persistent index backed by IndexedDB.
372
- *
373
- * Each file in the index gets its own IDB record — commits only write
374
- * new/changed files, not the entire index.
375
- * Use `LocalIndex.open(name)` to reopen it after page refresh.
376
- * @param {string} name
377
- * @param {string} schema_sdl
378
- * @returns {Promise<LocalIndex>}
379
- */
380
- static createPersistent(name, schema_sdl) {
381
- const ptr0 = passStringToWasm0(name, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
382
- const len0 = WASM_VECTOR_LEN;
383
- const ptr1 = passStringToWasm0(schema_sdl, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
384
- const len1 = WASM_VECTOR_LEN;
385
- const ret = wasm.localindex_createPersistent(ptr0, len0, ptr1, len1);
386
- return ret;
387
- }
388
- /**
389
- * Delete a persistent index from IndexedDB.
390
- * @param {string} name
391
- * @returns {Promise<void>}
392
- */
393
- static deleteIndex(name) {
394
- const ptr0 = passStringToWasm0(name, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
395
- const len0 = WASM_VECTOR_LEN;
396
- const ret = wasm.localindex_deleteIndex(ptr0, len0);
397
- return ret;
398
- }
399
- /**
400
- * Check if a persistent index exists in IndexedDB.
401
- * @param {string} name
402
- * @returns {Promise<boolean>}
403
- */
404
- static exists(name) {
405
- const ptr0 = passStringToWasm0(name, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
406
- const len0 = WASM_VECTOR_LEN;
407
- const ret = wasm.localindex_exists(ptr0, len0);
408
- return ret;
409
- }
410
368
  /**
411
369
  * Get field names from the schema.
412
370
  * @returns {any}
@@ -435,19 +393,6 @@ export class LocalIndex {
435
393
  const ret = wasm.localindex_numDocs(this.__wbg_ptr);
436
394
  return ret >>> 0;
437
395
  }
438
- /**
439
- * Open an existing persistent index from IndexedDB.
440
- *
441
- * Loads the file manifest and all index files into a RamDirectory.
442
- * @param {string} name
443
- * @returns {Promise<LocalIndex>}
444
- */
445
- static open(name) {
446
- const ptr0 = passStringToWasm0(name, wasm.__wbindgen_malloc, wasm.__wbindgen_realloc);
447
- const len0 = WASM_VECTOR_LEN;
448
- const ret = wasm.localindex_open(ptr0, len0);
449
- return ret;
450
- }
451
396
  /**
452
397
  * Number of documents pending (not yet committed).
453
398
  * @returns {number}
@@ -483,6 +428,31 @@ export class LocalIndex {
483
428
  const ret = wasm.localindex_searchOffset(this.__wbg_ptr, ptr0, len0, limit, offset);
484
429
  return ret;
485
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
+ }
486
456
  }
487
457
  if (Symbol.dispose) LocalIndex.prototype[Symbol.dispose] = LocalIndex.prototype.free;
488
458
 
@@ -831,10 +801,18 @@ function __wbg_get_imports() {
831
801
  const ret = arg0.arrayBuffer();
832
802
  return ret;
833
803
  }, arguments); },
804
+ __wbg_buffer_60b8043cd926067d: function(arg0) {
805
+ const ret = arg0.buffer;
806
+ return ret;
807
+ },
834
808
  __wbg_call_2d781c1f4d5c0ef8: function() { return handleError(function (arg0, arg1, arg2) {
835
809
  const ret = arg0.call(arg1, arg2);
836
810
  return ret;
837
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); },
838
816
  __wbg_call_e133b57c9155d22c: function() { return handleError(function (arg0, arg1) {
839
817
  const ret = arg0.call(arg1);
840
818
  return ret;
@@ -1130,6 +1108,10 @@ function __wbg_get_imports() {
1130
1108
  __wbg_prototypesetcall_d62e5099504357e6: function(arg0, arg1, arg2) {
1131
1109
  Uint8Array.prototype.set.call(getArrayU8FromWasm0(arg0, arg1), arg2);
1132
1110
  },
1111
+ __wbg_push_e87b0e732085a946: function(arg0, arg1) {
1112
+ const ret = arg0.push(arg1);
1113
+ return ret;
1114
+ },
1133
1115
  __wbg_put_f1673d719f93ce22: function() { return handleError(function (arg0, arg1, arg2) {
1134
1116
  const ret = arg0.put(arg1, arg2);
1135
1117
  return ret;
@@ -1262,22 +1244,22 @@ function __wbg_get_imports() {
1262
1244
  console.warn(arg0);
1263
1245
  },
1264
1246
  __wbindgen_cast_0000000000000001: function(arg0, arg1) {
1265
- // Cast intrinsic for `Closure(Closure { dtor_idx: 289, function: Function { arguments: [NamedExternref("Event")], shim_idx: 290, 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`.
1266
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_);
1267
1249
  return ret;
1268
1250
  },
1269
1251
  __wbindgen_cast_0000000000000002: function(arg0, arg1) {
1270
- // Cast intrinsic for `Closure(Closure { dtor_idx: 289, function: Function { arguments: [NamedExternref("IDBVersionChangeEvent")], shim_idx: 290, 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`.
1271
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);
1272
1254
  return ret;
1273
1255
  },
1274
1256
  __wbindgen_cast_0000000000000003: function(arg0, arg1) {
1275
- // Cast intrinsic for `Closure(Closure { dtor_idx: 762, function: Function { arguments: [], shim_idx: 763, 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`.
1276
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_);
1277
1259
  return ret;
1278
1260
  },
1279
1261
  __wbindgen_cast_0000000000000004: function(arg0, arg1) {
1280
- // Cast intrinsic for `Closure(Closure { dtor_idx: 792, function: Function { arguments: [Externref], shim_idx: 793, 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`.
1281
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_);
1282
1264
  return ret;
1283
1265
  },
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.29",
8
+ "version": "1.8.30",
9
9
  "license": "MIT",
10
10
  "repository": {
11
11
  "type": "git",