lucivy-wasm 3.0.7 → 3.0.8

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
@@ -1,4 +1,4 @@
1
- # lucivy-wasm 3.0.7
1
+ # lucivy-wasm 3.0.8
2
2
 
3
3
  Fast BM25 full-text search for browsers — WASM build with **threading** (emscripten pthreads), OPFS persistence, and snapshot/delta sync support. Runs in a Web Worker.
4
4
 
@@ -586,6 +586,62 @@ self.onmessage = async (e) => {
586
586
  break;
587
587
  }
588
588
 
589
+ // ── Incremental sync (LUCIDS) ───────────────────────────────
590
+ // The three entry points below were compiled into the wasm and
591
+ // listed in EXPORTED_FUNCTIONS from the start, but nothing above
592
+ // them called into them, so a browser client could only ever take
593
+ // a whole snapshot. Syncing a growing server index to a browser is
594
+ // the case this exists for, and a full snapshot each time is what
595
+ // makes it impractical.
596
+
597
+ case 'shardVersions': {
598
+ // What this client already holds, per shard — hand it to the
599
+ // server so it can send back only what moved.
600
+ const ctx = getCtx(args.path);
601
+ const json = await callStr('lucivy_shard_versions', ctx);
602
+ const parsed = json ? JSON.parse(json) : [];
603
+ // The C side reports failure as {"error": "..."}, which is a
604
+ // perfectly valid parse — returning it as data would hand the
605
+ // caller an object where it expects a list.
606
+ if (!Array.isArray(parsed)) throw new Error(parsed.error || 'shard_versions failed');
607
+ result = parsed;
608
+ break;
609
+ }
610
+
611
+ case 'exportShardedDelta': {
612
+ const ctx = getCtx(args.path);
613
+ const versions = JSON.stringify(args.clientVersions || []);
614
+ const lenPtr = Module._malloc(4);
615
+ const dataPtr = await Module.ccall('lucivy_export_sharded_delta', 'number',
616
+ ['number', 'string', 'number'], [ctx, versions, lenPtr], { async: true });
617
+ if (!dataPtr) {
618
+ Module._free(lenPtr);
619
+ throw new Error('export_sharded_delta failed — check the client versions shape');
620
+ }
621
+ const len = Module.getValue(lenPtr, 'i32');
622
+ Module._free(lenPtr);
623
+ // slice(), not subarray(): the wasm heap moves when it grows,
624
+ // and a view into it would silently point elsewhere afterwards.
625
+ result = Module.HEAPU8.slice(dataPtr, dataPtr + len);
626
+ break;
627
+ }
628
+
629
+ case 'applyShardedDelta': {
630
+ const ctx = getCtx(args.path);
631
+ const data = args.data instanceof Uint8Array ? args.data : new Uint8Array(args.data);
632
+ const ptr = Module._malloc(data.length);
633
+ Module.HEAPU8.set(data, ptr);
634
+ let res;
635
+ try {
636
+ res = await callStr('lucivy_apply_sharded_delta', ctx, ptr, data.length);
637
+ } finally {
638
+ Module._free(ptr);
639
+ }
640
+ checkResult(res);
641
+ result = true;
642
+ break;
643
+ }
644
+
589
645
  case 'numDocs': {
590
646
  const ctx = getCtx(args.path);
591
647
  result = await Module.ccall('lucivy_num_docs', 'number', ['number'], [ctx], { async: true });
package/js/lucivy.d.ts CHANGED
@@ -374,6 +374,20 @@ export class LucivyIndex {
374
374
  numDocs(): Promise<number>;
375
375
  schema(): Promise<IndexConfig>;
376
376
  exportSnapshot(): Promise<Uint8Array>;
377
+ /** What this index holds per shard — hand it to whoever exports the delta. */
378
+ shardVersions(): Promise<ShardVersion[]>;
379
+ /** A LUCIDS delta holding only the shards that moved since `clientVersions`. */
380
+ exportShardedDelta(clientVersions?: ShardVersion[]): Promise<Uint8Array>;
381
+ /** Apply a LUCIDS delta onto this index, in place. */
382
+ applyShardedDelta(data: Uint8Array | ArrayBuffer): Promise<boolean>;
377
383
  close(): Promise<void>;
378
384
  destroy(): Promise<void>;
379
385
  }
386
+
387
+ /** One shard's identity and the version of it a client holds. */
388
+ export interface ShardVersion {
389
+ shard_id: number;
390
+ version: string;
391
+ /** The segments that version is made of — what the exporter diffs against. */
392
+ segment_ids: string[];
393
+ }
package/js/lucivy.js CHANGED
@@ -229,6 +229,44 @@ export class LucivyIndex {
229
229
  return this._lucivy._call('exportSnapshot', { path: this.path });
230
230
  }
231
231
 
232
+ /**
233
+ * What this index already holds, one entry per shard.
234
+ *
235
+ * Send it to whoever exports the delta: it is what lets them return only
236
+ * the shards that moved instead of the whole index.
237
+ *
238
+ * @returns {Promise<Array<{shard: number, version: string}>>}
239
+ */
240
+ shardVersions() {
241
+ return this._lucivy._call('shardVersions', { path: this.path });
242
+ }
243
+
244
+ /**
245
+ * A LUCIDS delta holding only what changed since `clientVersions`.
246
+ *
247
+ * @param {Array} clientVersions what the other side holds, from its own
248
+ * `shardVersions()`. An empty array asks for everything.
249
+ * @returns {Promise<Uint8Array>}
250
+ */
251
+ exportShardedDelta(clientVersions = []) {
252
+ return this._lucivy._call('exportShardedDelta', { path: this.path, clientVersions });
253
+ }
254
+
255
+ /**
256
+ * Apply a LUCIDS delta onto this index, in place.
257
+ *
258
+ * The counterpart of `exportShardedDelta`: after it resolves, this index
259
+ * holds what the exporting side held when it produced the delta. Applying
260
+ * a delta built against different versions than this index actually has is
261
+ * rejected rather than half-applied.
262
+ *
263
+ * @param {Uint8Array|ArrayBuffer} data the delta blob
264
+ * @returns {Promise<boolean>}
265
+ */
266
+ applyShardedDelta(data) {
267
+ return this._lucivy._call('applyShardedDelta', { path: this.path, data });
268
+ }
269
+
232
270
  close() {
233
271
  return this._lucivy._call('close', { path: this.path });
234
272
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lucivy-wasm",
3
- "version": "3.0.7",
3
+ "version": "3.0.8",
4
4
  "type": "module",
5
5
  "description": "Fast BM25 full-text search for browsers — WASM build of Lucivy with threading, OPFS persistence, and LUCE snapshot support",
6
6
  "license": "MIT",
package/pkg/lucivy.wasm CHANGED
Binary file