albex 0.1.0 → 0.3.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.
Files changed (76) hide show
  1. package/CHANGELOG.md +141 -0
  2. package/README.md +242 -112
  3. package/dist/albex-worker.d.ts +70 -0
  4. package/dist/albex-worker.d.ts.map +1 -0
  5. package/dist/albex-worker.js +153 -0
  6. package/dist/albex-worker.js.map +1 -0
  7. package/dist/albex.d.ts +368 -6
  8. package/dist/albex.d.ts.map +1 -1
  9. package/dist/albex.js +1692 -95
  10. package/dist/albex.js.map +1 -1
  11. package/dist/errors.d.ts +38 -0
  12. package/dist/errors.d.ts.map +1 -0
  13. package/dist/errors.js +63 -0
  14. package/dist/errors.js.map +1 -0
  15. package/dist/gpu/bloom-runtime.d.ts +60 -0
  16. package/dist/gpu/bloom-runtime.d.ts.map +1 -0
  17. package/dist/gpu/bloom-runtime.js +176 -0
  18. package/dist/gpu/bloom-runtime.js.map +1 -0
  19. package/dist/gpu/bloom-shader.wgsl.d.ts +19 -0
  20. package/dist/gpu/bloom-shader.wgsl.d.ts.map +1 -0
  21. package/dist/gpu/bloom-shader.wgsl.js +49 -0
  22. package/dist/gpu/bloom-shader.wgsl.js.map +1 -0
  23. package/dist/persistence.d.ts +21 -0
  24. package/dist/persistence.d.ts.map +1 -0
  25. package/dist/persistence.js +174 -0
  26. package/dist/persistence.js.map +1 -0
  27. package/dist/pool/coordinator.d.ts +98 -0
  28. package/dist/pool/coordinator.d.ts.map +1 -0
  29. package/dist/pool/coordinator.js +247 -0
  30. package/dist/pool/coordinator.js.map +1 -0
  31. package/dist/profile.d.ts +95 -0
  32. package/dist/profile.d.ts.map +1 -0
  33. package/dist/profile.js +207 -0
  34. package/dist/profile.js.map +1 -0
  35. package/dist/resource-manager.d.ts +56 -0
  36. package/dist/resource-manager.d.ts.map +1 -0
  37. package/dist/resource-manager.js +138 -0
  38. package/dist/resource-manager.js.map +1 -0
  39. package/dist/tiered-store.d.ts +98 -0
  40. package/dist/tiered-store.d.ts.map +1 -0
  41. package/dist/tiered-store.js +238 -0
  42. package/dist/tiered-store.js.map +1 -0
  43. package/dist/wasm-bindings.d.ts +139 -0
  44. package/dist/wasm-bindings.d.ts.map +1 -0
  45. package/dist/wasm-bindings.js +33 -0
  46. package/dist/wasm-bindings.js.map +1 -0
  47. package/dist/worker-protocol.d.ts +86 -0
  48. package/dist/worker-protocol.d.ts.map +1 -0
  49. package/dist/worker-protocol.js +20 -0
  50. package/dist/worker-protocol.js.map +1 -0
  51. package/dist/worker-runtime.d.ts +14 -0
  52. package/dist/worker-runtime.d.ts.map +1 -0
  53. package/dist/worker-runtime.js +100 -0
  54. package/dist/worker-runtime.js.map +1 -0
  55. package/package.json +56 -13
  56. package/src/albex-worker.ts +187 -0
  57. package/src/albex.ts +1845 -130
  58. package/src/errors.ts +60 -0
  59. package/src/gpu/bloom-runtime.ts +229 -0
  60. package/src/gpu/bloom-shader.wgsl.ts +48 -0
  61. package/src/persistence.ts +175 -0
  62. package/src/pool/coordinator.ts +324 -0
  63. package/src/profile.ts +279 -0
  64. package/src/resource-manager.ts +167 -0
  65. package/src/tiered-store.ts +259 -0
  66. package/src/wasm-bindings.ts +200 -0
  67. package/src/worker-protocol.ts +48 -0
  68. package/src/worker-runtime.ts +96 -0
  69. package/wasm/pkg/albex_pdf.wasm +0 -0
  70. package/wasm/pkg/albex_wasm_bg.wasm +0 -0
  71. package/wasm/pkg/albex_wasm_mini.wasm +0 -0
  72. package/wasm/pkg/albex_wasm_mini_simd.wasm +0 -0
  73. package/wasm/pkg/albex_wasm_pro.wasm +0 -0
  74. package/wasm/pkg/albex_wasm_pro_simd.wasm +0 -0
  75. package/wasm/pkg/albex_wasm_std.wasm +0 -0
  76. package/wasm/pkg/albex_wasm_std_simd.wasm +0 -0
@@ -0,0 +1,238 @@
1
+ /*!
2
+ * albex v0.3.0
3
+ * Zero-config local full-text search for documents — runs entirely in the browser, no server, no upload.
4
+ * (c) 2026 RafaCalRob
5
+ * @license MIT
6
+ * https://github.com/RafaCalRob/Albex#readme
7
+ */
8
+ /**
9
+ * Tiered storage layer for Albex.
10
+ *
11
+ * The base engine keeps every indexed document in memory inside the BSS
12
+ * arrays. That works beautifully up to the tier's capacity (4 MB to 128 MB
13
+ * of indexed text) but breaks when the user wants to search across more.
14
+ *
15
+ * `TieredStore` adds two memory tiers behind the engine:
16
+ *
17
+ * HOT — already-indexed documents living in the WASM arrays.
18
+ * WARM — original file blobs serialised in OPFS, NOT in the engine.
19
+ *
20
+ * Eviction happens when text capacity climbs above a configurable
21
+ * threshold (default 85 %). The least-recently-accessed HOT document is
22
+ * removed from the engine; its blob stays in OPFS so we can promote it
23
+ * back later without asking the user to re-pick the file.
24
+ *
25
+ * Promotion happens explicitly: callers tell the store "I want these
26
+ * names searchable again" and we re-feed them through `engine.indexFile`.
27
+ *
28
+ * **Trade-off vs storing the internal representation in OPFS:** promoting
29
+ * a doc means re-parsing it (DOCX XML decode, etc.). For typical document
30
+ * sizes this is 20-200 ms — negligible for an explicit "search across the
31
+ * archive" action. The win is huge: the persistence format is just the
32
+ * source files, so it survives engine version bumps without any migration.
33
+ */
34
+ const OPFS_DIR = 'albex-tiered';
35
+ export class TieredStore {
36
+ _engine;
37
+ _entries = new Map();
38
+ _dir = null;
39
+ _opts;
40
+ constructor(engine, opts = {}) {
41
+ this._engine = engine;
42
+ this._opts = {
43
+ evictThreshold: opts.evictThreshold ?? 0.85,
44
+ hotFloor: opts.hotFloor ?? 1,
45
+ };
46
+ }
47
+ /** Ensure the OPFS directory exists. Idempotent. Tolerated when OPFS is unavailable. */
48
+ async init() {
49
+ try {
50
+ const root = await navigator.storage.getDirectory();
51
+ this._dir = await root.getDirectoryHandle(OPFS_DIR, { create: true });
52
+ }
53
+ catch {
54
+ // No OPFS — warm tier disabled; everything stays hot.
55
+ this._dir = null;
56
+ }
57
+ await this._rehydrateIndex();
58
+ }
59
+ /**
60
+ * Index a file AND register it in the warm tier so it survives across
61
+ * sessions. Equivalent to `engine.indexFile(file)` but with the extra
62
+ * persistence guarantee.
63
+ */
64
+ async indexFile(file) {
65
+ const doc = await this._engine.indexFile(file);
66
+ // Persist the original blob in OPFS so we can promote it back later
67
+ // without asking the user to re-pick the file.
68
+ await this._writeBlob(file);
69
+ this._entries.set(doc.name, {
70
+ name: doc.name,
71
+ ext: doc.ext,
72
+ lastAccessedMs: Date.now(),
73
+ hot: true,
74
+ byteSize: file.size,
75
+ });
76
+ await this._enforceCapacity();
77
+ return doc;
78
+ }
79
+ /** Touch an entry to mark it recently used (for LRU). */
80
+ touch(name) {
81
+ const e = this._entries.get(name);
82
+ if (e)
83
+ e.lastAccessedMs = Date.now();
84
+ }
85
+ /**
86
+ * Evict the least-recently-used HOT documents until `textUsed` falls
87
+ * below the configured threshold. Respects `hotFloor` (never evicts
88
+ * the last N docs).
89
+ */
90
+ async _enforceCapacity() {
91
+ const stats = this._engine.getStats();
92
+ const threshold = stats.textCapacity * this._opts.evictThreshold;
93
+ if (stats.textUsed <= threshold)
94
+ return;
95
+ const hot = [...this._entries.values()]
96
+ .filter(e => e.hot)
97
+ .sort((a, b) => a.lastAccessedMs - b.lastAccessedMs);
98
+ while (hot.length > this._opts.hotFloor) {
99
+ const victim = hot.shift();
100
+ this._engine.removeDocument(victim.name);
101
+ victim.hot = false;
102
+ // Reclaim storage now so subsequent index calls see real headroom.
103
+ this._engine.compact();
104
+ const after = this._engine.getStats();
105
+ if (after.textUsed <= threshold)
106
+ break;
107
+ }
108
+ }
109
+ /**
110
+ * Bring a warm document back into the engine. No-op if already hot.
111
+ * Returns the resulting `IndexedDocument` or `null` if the doc isn't known.
112
+ */
113
+ async promote(name) {
114
+ const e = this._entries.get(name);
115
+ if (!e)
116
+ return null;
117
+ if (e.hot) {
118
+ this.touch(name);
119
+ const stats = this._engine.getStats();
120
+ void stats;
121
+ return this._engine.documents.find(d => d.name === name) ?? null;
122
+ }
123
+ const blob = await this._readBlob(name);
124
+ if (!blob)
125
+ return null;
126
+ // Re-create the File so `engine.indexFile` sees the original metadata.
127
+ const file = new File([blob], name);
128
+ const doc = await this._engine.indexFile(file);
129
+ e.hot = true;
130
+ e.lastAccessedMs = Date.now();
131
+ return doc;
132
+ }
133
+ /**
134
+ * Forget a document entirely: remove from engine and delete its OPFS blob.
135
+ * Returns whether the entry existed.
136
+ */
137
+ async forget(name) {
138
+ const had = this._entries.has(name);
139
+ if (this._entries.get(name)?.hot)
140
+ this._engine.removeDocument(name);
141
+ this._entries.delete(name);
142
+ await this._deleteBlob(name);
143
+ return had;
144
+ }
145
+ /** Names of all known documents, hot or warm. */
146
+ list() {
147
+ return [...this._entries.values()].map(e => ({
148
+ name: e.name, hot: e.hot, byteSize: e.byteSize,
149
+ }));
150
+ }
151
+ /** Aggregate storage stats. */
152
+ getTierStats() {
153
+ let hot = 0, warm = 0, totalBytes = 0;
154
+ for (const e of this._entries.values()) {
155
+ if (e.hot)
156
+ hot++;
157
+ else
158
+ warm++;
159
+ totalBytes += e.byteSize;
160
+ }
161
+ return { hot, warm, totalBytes };
162
+ }
163
+ // ── OPFS plumbing ─────────────────────────────────────────────────────
164
+ _safeName(name) {
165
+ // Strip path separators just in case; OPFS requires plain file names.
166
+ return name.replace(/[/\\]/g, '_');
167
+ }
168
+ async _writeBlob(file) {
169
+ if (!this._dir)
170
+ return;
171
+ try {
172
+ const handle = await this._dir.getFileHandle(this._safeName(file.name), { create: true });
173
+ const w = await handle.createWritable();
174
+ const bytes = new Uint8Array(await file.arrayBuffer());
175
+ const plain = new Uint8Array(bytes.byteLength);
176
+ plain.set(bytes);
177
+ await w.write(plain);
178
+ await w.close();
179
+ }
180
+ catch (e) {
181
+ console.warn(`[albex] failed to persist blob for ${file.name}:`, e);
182
+ }
183
+ }
184
+ async _readBlob(name) {
185
+ if (!this._dir)
186
+ return null;
187
+ try {
188
+ const handle = await this._dir.getFileHandle(this._safeName(name));
189
+ return await handle.getFile();
190
+ }
191
+ catch {
192
+ return null;
193
+ }
194
+ }
195
+ async _deleteBlob(name) {
196
+ if (!this._dir)
197
+ return;
198
+ try {
199
+ await this._dir.removeEntry(this._safeName(name));
200
+ }
201
+ catch { /* not found */ }
202
+ }
203
+ /**
204
+ * TC39 explicit-resource-management hook. Drops the in-memory index and
205
+ * the OPFS directory handle. The underlying OPFS blobs are NOT deleted —
206
+ * disposal only frees JS-side state. Use `forget()` per-doc or
207
+ * `deleteOpfsAll()` if you want to wipe persisted data.
208
+ */
209
+ [Symbol.dispose]() {
210
+ this._entries.clear();
211
+ this._dir = null;
212
+ }
213
+ async _rehydrateIndex() {
214
+ if (!this._dir)
215
+ return;
216
+ try {
217
+ // @ts-expect-error async-iterable on FileSystemDirectoryHandle
218
+ for await (const [name, handle] of this._dir.entries()) {
219
+ if (handle.kind !== 'file')
220
+ continue;
221
+ const file = await handle.getFile();
222
+ if (this._entries.has(name))
223
+ continue;
224
+ this._entries.set(name, {
225
+ name,
226
+ ext: (name.split('.').pop() ?? '').toLowerCase(),
227
+ lastAccessedMs: 0, // never accessed in this session yet
228
+ hot: false,
229
+ byteSize: file.size,
230
+ });
231
+ }
232
+ }
233
+ catch (e) {
234
+ console.warn('[albex] could not rehydrate tiered index:', e);
235
+ }
236
+ }
237
+ }
238
+ //# sourceMappingURL=tiered-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tiered-store.js","sourceRoot":"","sources":["../src/tiered-store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,139 @@
1
+ /**
2
+ * Typed interfaces for the two WASM modules Albex ships with.
3
+ *
4
+ * These types replace ad-hoc `as Function` casts and give us:
5
+ * - argument/return type checking at call sites,
6
+ * - autocompletion in IDEs,
7
+ * - safe refactors when an export name or signature changes.
8
+ *
9
+ * The interfaces mirror the `#[no_mangle] pub extern "C" fn` exports
10
+ * in `wasm/src/lib.rs` and `pdf-wasm/src/lib.rs`.
11
+ */
12
+ export interface AlbexWasmExports {
13
+ readonly memory: WebAssembly.Memory;
14
+ getBuffer(size: number): number;
15
+ init(): void;
16
+ setDocumentName(len: number): void;
17
+ beginDocument(): number;
18
+ feedXmlBytes(len: number): void;
19
+ endDocument(): number;
20
+ beginXlsx(): number;
21
+ feedXlsxBytes(len: number): void;
22
+ feedText(len: number): void;
23
+ flushParagraph(): void;
24
+ setMaxErrors(errors: number): void;
25
+ setThreshold(threshold: number): void;
26
+ setMaxResults(max: number): void;
27
+ setPattern(len: number): number;
28
+ search(): number;
29
+ searchBegin(): number;
30
+ searchSlice(maxChunks: number): number;
31
+ getSearchCursor(): number;
32
+ getSearchTotal(): number;
33
+ getResultCount(): number;
34
+ getResultDocId(i: number): number;
35
+ getResultLocation(i: number): number;
36
+ getResultScore(i: number): number;
37
+ getResultStart(i: number): number;
38
+ getResultEnd(i: number): number;
39
+ getResultChunkIdx(i: number): number;
40
+ getResultDocName(i: number): number;
41
+ getResultMatchCount(i: number): number;
42
+ getResultMatchStartAt(i: number, k: number): number;
43
+ getResultMatchEndAt(i: number, k: number): number;
44
+ getSnippet(i: number): number;
45
+ getSnippetWindow(i: number, before: number, after: number): number;
46
+ getSnippetWindowOffset(): number;
47
+ getStatBloomTested(): number;
48
+ getStatBloomPassed(): number;
49
+ getStatBitapMatched(): number;
50
+ getChunkCount(): number;
51
+ getDocCount(): number;
52
+ getTextUsed(): number;
53
+ getTextCapacity(): number;
54
+ snapshotSize(): number;
55
+ snapshotChunk(offset: number, maxLen: number): number;
56
+ restoreBegin(): number;
57
+ restoreFeed(len: number): number;
58
+ getDocId(index: number): number;
59
+ getDocChunkCount(index: number): number;
60
+ getDocName(index: number): number;
61
+ isDocDeleted(index: number): number;
62
+ removeDocument(docId: number): number;
63
+ compact(): void;
64
+ /**
65
+ * Per-document content hash (snapshot v2). Returns a pointer to 8 bytes
66
+ * holding the FNV-1a 64-bit hash of the original file bytes, or 0 if the
67
+ * doc index is out of range. All-zero bytes mean "hash not available"
68
+ * — either the host never called setDocumentContentHash for this doc
69
+ * (legacy code path) or it was restored from a v1 snapshot.
70
+ */
71
+ getDocContentHashPtr(index: number): number;
72
+ /** Always returns 8. Useful as a runtime feature-detect: older binaries
73
+ * without snapshot v2 will not export this function at all. */
74
+ getDocContentHashLen(): number;
75
+ /** Copy a content hash (up to 8 bytes from the scratchpad) into the
76
+ * pending slot. endDocument() then writes it into doc_hashes[]. */
77
+ setDocumentContentHash(len: number): void;
78
+ setLanguage(lang: number): void;
79
+ getTier(): number;
80
+ getMaxChunks(): number;
81
+ getMaxDocs(): number;
82
+ getNameCapacity(): number;
83
+ getChunksPtr(): number;
84
+ getChunkStructSize(): number;
85
+ setCandidateMask(byteLen: number): void;
86
+ clearCandidateMask(): void;
87
+ }
88
+ export interface AlbexPdfExports {
89
+ readonly memory: WebAssembly.Memory;
90
+ /** Reserve `len` bytes inside the PDF module and return a pointer. */
91
+ allocInput(len: number): number;
92
+ /**
93
+ * Parse the PDF. Returns:
94
+ * N ≥ 0 — page count,
95
+ * -1 — parse error (read with getErrorPtr/getErrorLen),
96
+ * -2 — image-only / no extractable text.
97
+ *
98
+ * When `-2` is returned, the host can fall through to the scanned-PDF
99
+ * path via `getPageCount` + `extractPageImages`.
100
+ */
101
+ extractPdf(len: number): number;
102
+ getPageLen(page: number): number;
103
+ getPagePtr(page: number): number;
104
+ getErrorLen(): number;
105
+ getErrorPtr(): number;
106
+ /** Total page count of the loaded PDF; 0 if the input cannot be parsed. */
107
+ getPageCount(): number;
108
+ /**
109
+ * Extract every supported image XObject on page `page` (0-based) into the
110
+ * module's internal buffer.
111
+ *
112
+ * Returns:
113
+ * N ≥ 0 — number of images extracted on this page,
114
+ * -1 — parse error or page index out of range.
115
+ *
116
+ * Each extracted image is one of:
117
+ * * JPEG (kind = 1, from a `/DCTDecode` filter), or
118
+ * * JPEG2000 (kind = 2, from a `/JPXDecode` filter).
119
+ *
120
+ * Filters that require Rust-side reconstruction (`FlateDecode`,
121
+ * `CCITTFaxDecode`, `JBIG2Decode`) are intentionally skipped — they
122
+ * would roughly double the binary size for ~5 % more coverage.
123
+ */
124
+ extractPageImages(page: number): number;
125
+ /** Byte length of extracted image `i` (from the last `extractPageImages`). */
126
+ getPageImageLen(i: number): number;
127
+ /** Pointer to extracted image `i`'s raw bytes. */
128
+ getPageImagePtr(i: number): number;
129
+ /** Format tag for extracted image `i`: 1 = JPEG, 2 = JPEG2000, 0 = none. */
130
+ getPageImageKind(i: number): number;
131
+ }
132
+ /**
133
+ * Cast `WebAssembly.Exports` to the typed Albex main interface.
134
+ * Runtime check is intentionally minimal — if the .wasm doesn't match,
135
+ * the first call site that touches a missing function throws naturally.
136
+ */
137
+ export declare function asAlbexExports(exports: WebAssembly.Exports): AlbexWasmExports;
138
+ export declare function asAlbexPdfExports(exports: WebAssembly.Exports): AlbexPdfExports;
139
+ //# sourceMappingURL=wasm-bindings.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wasm-bindings.d.ts","sourceRoot":"","sources":["../src/wasm-bindings.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAMH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC,MAAM,CAAC;IAGpC,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IAChC,IAAI,IAAI,IAAI,CAAC;IAGb,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,aAAa,IAAI,MAAM,CAAC;IACxB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,WAAW,IAAI,MAAM,CAAC;IAGtB,SAAS,IAAI,MAAM,CAAC;IACpB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IAGjC,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,cAAc,IAAI,IAAI,CAAC;IAGvB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,YAAY,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACtC,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IAGjC,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;IAChC,MAAM,IAAI,MAAM,CAAC;IAEjB,WAAW,IAAI,MAAM,CAAC;IACtB,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAAC;IACvC,eAAe,IAAI,MAAM,CAAC;IAC1B,cAAc,IAAI,MAAM,CAAC;IAGzB,cAAc,IAAI,MAAM,CAAC;IACzB,cAAc,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAClC,iBAAiB,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACrC,cAAc,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAClC,cAAc,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAClC,YAAY,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAChC,iBAAiB,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACrC,gBAAgB,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACpC,mBAAmB,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACvC,qBAAqB,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IACpD,mBAAmB,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAClD,UAAU,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC9B,gBAAgB,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;IACnE,sBAAsB,IAAI,MAAM,CAAC;IAGjC,kBAAkB,IAAI,MAAM,CAAC;IAC7B,kBAAkB,IAAI,MAAM,CAAC;IAC7B,mBAAmB,IAAI,MAAM,CAAC;IAC9B,aAAa,IAAI,MAAM,CAAC;IACxB,WAAW,IAAI,MAAM,CAAC;IACtB,WAAW,IAAI,MAAM,CAAC;IACtB,eAAe,IAAI,MAAM,CAAC;IAG1B,YAAY,IAAI,MAAM,CAAC;IACvB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC;IACtD,YAAY,IAAI,MAAM,CAAC;IACvB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;IAGjC,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;IAChC,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;IACxC,UAAU,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;IAClC,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;IACpC,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;IACtC,OAAO,IAAI,IAAI,CAAC;IAEhB;;;;;;OAMG;IACH,oBAAoB,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;IAC5C;mEAC+D;IAC/D,oBAAoB,IAAI,MAAM,CAAC;IAC/B;uEACmE;IACnE,sBAAsB,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IAG1C,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAGhC,OAAO,IAAI,MAAM,CAAC;IAClB,YAAY,IAAI,MAAM,CAAC;IACvB,UAAU,IAAI,MAAM,CAAC;IACrB,eAAe,IAAI,MAAM,CAAC;IAG1B,YAAY,IAAI,MAAM,CAAC;IACvB,kBAAkB,IAAI,MAAM,CAAC;IAC7B,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACxC,kBAAkB,IAAI,IAAI,CAAC;CAC5B;AAMD,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC,MAAM,CAAC;IAEpC,sEAAsE;IACtE,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;IAEhC;;;;;;;;OAQG;IACH,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAAC;IAEhC,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IACjC,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IACjC,WAAW,IAAI,MAAM,CAAC;IACtB,WAAW,IAAI,MAAM,CAAC;IAQtB,2EAA2E;IAC3E,YAAY,IAAI,MAAM,CAAC;IAEvB;;;;;;;;;;;;;;;OAeG;IACH,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAC;IAExC,8EAA8E;IAC9E,eAAe,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAEnC,kDAAkD;IAClD,eAAe,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAEnC,4EAA4E;IAC5E,gBAAgB,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;CACrC;AAMD;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,WAAW,CAAC,OAAO,GAAG,gBAAgB,CAE7E;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,WAAW,CAAC,OAAO,GAAG,eAAe,CAE/E"}
@@ -0,0 +1,33 @@
1
+ /*!
2
+ * albex v0.3.0
3
+ * Zero-config local full-text search for documents — runs entirely in the browser, no server, no upload.
4
+ * (c) 2026 RafaCalRob
5
+ * @license MIT
6
+ * https://github.com/RafaCalRob/Albex#readme
7
+ */
8
+ /**
9
+ * Typed interfaces for the two WASM modules Albex ships with.
10
+ *
11
+ * These types replace ad-hoc `as Function` casts and give us:
12
+ * - argument/return type checking at call sites,
13
+ * - autocompletion in IDEs,
14
+ * - safe refactors when an export name or signature changes.
15
+ *
16
+ * The interfaces mirror the `#[no_mangle] pub extern "C" fn` exports
17
+ * in `wasm/src/lib.rs` and `pdf-wasm/src/lib.rs`.
18
+ */
19
+ // ─────────────────────────────────────────────────────────────────────────────
20
+ // Narrowing helpers for instantiation results
21
+ // ─────────────────────────────────────────────────────────────────────────────
22
+ /**
23
+ * Cast `WebAssembly.Exports` to the typed Albex main interface.
24
+ * Runtime check is intentionally minimal — if the .wasm doesn't match,
25
+ * the first call site that touches a missing function throws naturally.
26
+ */
27
+ export function asAlbexExports(exports) {
28
+ return exports;
29
+ }
30
+ export function asAlbexPdfExports(exports) {
31
+ return exports;
32
+ }
33
+ //# sourceMappingURL=wasm-bindings.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wasm-bindings.js","sourceRoot":"","sources":["../src/wasm-bindings.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AA8KH,gFAAgF;AAChF,8CAA8C;AAC9C,gFAAgF;AAEhF;;;;GAIG;AACH,MAAM,UAAU,cAAc,CAAC,OAA4B;IACzD,OAAO,OAAsC,CAAC;AAChD,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,OAA4B;IAC5D,OAAO,OAAqC,CAAC;AAC/C,CAAC"}
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Wire protocol between the main thread and the AlbexEngineWorker runtime.
3
+ *
4
+ * One request/response pair per call, identified by `id`. The runtime is
5
+ * single-threaded so we serialise requests on the main side (one in-flight
6
+ * call at a time per worker) — keeps the protocol trivial and matches the
7
+ * actual constraint of `static mut` WASM state.
8
+ *
9
+ * `Transferable` is opt-in per op; we use it for `indexFile` to avoid
10
+ * copying the file bytes into the worker.
11
+ */
12
+ import type { AlbexOptions, IndexedDocument, SearchOptions, SearchResult, EngineStats, SearchStats } from './albex.js';
13
+ export type WorkerOp = {
14
+ kind: 'init';
15
+ opts: AlbexOptions;
16
+ } | {
17
+ kind: 'indexFile';
18
+ name: string;
19
+ buffer: ArrayBuffer;
20
+ } | {
21
+ kind: 'search';
22
+ query: string;
23
+ options: SearchOptions;
24
+ } | {
25
+ kind: 'removeDocument';
26
+ id: string;
27
+ } | {
28
+ kind: 'compact';
29
+ } | {
30
+ kind: 'reset';
31
+ } | {
32
+ kind: 'getStats';
33
+ } | {
34
+ kind: 'getLastSearchStats';
35
+ } | {
36
+ kind: 'getDocuments';
37
+ } | {
38
+ kind: 'setMaxErrors';
39
+ n: 0 | 1 | 2 | 3;
40
+ } | {
41
+ kind: 'setThreshold';
42
+ n: number;
43
+ } | {
44
+ kind: 'setMaxResults';
45
+ n: number;
46
+ } | {
47
+ kind: 'setLanguage';
48
+ lang: 'off' | 'es';
49
+ } | {
50
+ kind: 'save';
51
+ name: string;
52
+ } | {
53
+ kind: 'load';
54
+ name: string;
55
+ } | {
56
+ kind: 'loadOrInit';
57
+ name: string;
58
+ } | {
59
+ kind: 'deleteSnapshot';
60
+ name: string;
61
+ } | {
62
+ kind: 'listSnapshots';
63
+ };
64
+ export interface WorkerRequest {
65
+ id: number;
66
+ op: WorkerOp;
67
+ }
68
+ export type WorkerResponse = {
69
+ id: number;
70
+ ok: true;
71
+ result: unknown;
72
+ } | {
73
+ id: number;
74
+ ok: false;
75
+ error: {
76
+ name: string;
77
+ kind?: string;
78
+ message: string;
79
+ };
80
+ };
81
+ export type IndexFileResult = IndexedDocument;
82
+ export type SearchResultArr = SearchResult[];
83
+ export type StatsResult = EngineStats;
84
+ export type SearchStatsRes = SearchStats | null;
85
+ export type DocsResult = readonly IndexedDocument[];
86
+ //# sourceMappingURL=worker-protocol.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worker-protocol.d.ts","sourceRoot":"","sources":["../src/worker-protocol.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,eAAe,EAAE,aAAa,EAAE,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEvH,MAAM,MAAM,QAAQ,GAChB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAY,IAAI,EAAE,YAAY,CAAA;CAAE,GAC/C;IAAE,IAAI,EAAE,WAAW,CAAC;IAAQ,IAAI,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,WAAW,CAAA;CAAE,GAC/D;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAW,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,aAAa,CAAA;CAAE,GACnE;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAG,EAAE,EAAE,MAAM,CAAA;CAAE,GACxC;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,GACnB;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,GACjB;IAAE,IAAI,EAAE,UAAU,CAAA;CAAE,GACpB;IAAE,IAAI,EAAE,oBAAoB,CAAA;CAAE,GAC9B;IAAE,IAAI,EAAE,cAAc,CAAA;CAAE,GACxB;IAAE,IAAI,EAAE,cAAc,CAAC;IAAK,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;CAAE,GAC9C;IAAE,IAAI,EAAE,cAAc,CAAC;IAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GACvC;IAAE,IAAI,EAAE,eAAe,CAAC;IAAI,CAAC,EAAE,MAAM,CAAA;CAAE,GACvC;IAAE,IAAI,EAAE,aAAa,CAAC;IAAM,IAAI,EAAE,KAAK,GAAG,IAAI,CAAA;CAAE,GAChD;IAAE,IAAI,EAAE,MAAM,CAAC;IAAa,IAAI,EAAE,MAAM,CAAA;CAAE,GAC1C;IAAE,IAAI,EAAE,MAAM,CAAC;IAAa,IAAI,EAAE,MAAM,CAAA;CAAE,GAC1C;IAAE,IAAI,EAAE,YAAY,CAAC;IAAO,IAAI,EAAE,MAAM,CAAA;CAAE,GAC1C;IAAE,IAAI,EAAE,gBAAgB,CAAC;IAAG,IAAI,EAAE,MAAM,CAAA;CAAE,GAC1C;IAAE,IAAI,EAAE,eAAe,CAAA;CAAE,CAAC;AAE9B,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,EAAE,EAAE,QAAQ,CAAC;CACd;AAED,MAAM,MAAM,cAAc,GACtB;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,IAAI,CAAC;IAAE,MAAM,EAAE,OAAO,CAAA;CAAE,GAC1C;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAA;CAAE,CAAC;AAEvF,MAAM,MAAM,eAAe,GAAG,eAAe,CAAC;AAC9C,MAAM,MAAM,eAAe,GAAG,YAAY,EAAE,CAAC;AAC7C,MAAM,MAAM,WAAW,GAAO,WAAW,CAAC;AAC1C,MAAM,MAAM,cAAc,GAAI,WAAW,GAAG,IAAI,CAAC;AACjD,MAAM,MAAM,UAAU,GAAQ,SAAS,eAAe,EAAE,CAAC"}
@@ -0,0 +1,20 @@
1
+ /*!
2
+ * albex v0.3.0
3
+ * Zero-config local full-text search for documents — runs entirely in the browser, no server, no upload.
4
+ * (c) 2026 RafaCalRob
5
+ * @license MIT
6
+ * https://github.com/RafaCalRob/Albex#readme
7
+ */
8
+ /**
9
+ * Wire protocol between the main thread and the AlbexEngineWorker runtime.
10
+ *
11
+ * One request/response pair per call, identified by `id`. The runtime is
12
+ * single-threaded so we serialise requests on the main side (one in-flight
13
+ * call at a time per worker) — keeps the protocol trivial and matches the
14
+ * actual constraint of `static mut` WASM state.
15
+ *
16
+ * `Transferable` is opt-in per op; we use it for `indexFile` to avoid
17
+ * copying the file bytes into the worker.
18
+ */
19
+ export {};
20
+ //# sourceMappingURL=worker-protocol.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worker-protocol.js","sourceRoot":"","sources":["../src/worker-protocol.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Albex worker runtime.
3
+ *
4
+ * Loads inside a Web Worker, instantiates an `AlbexEngine`, and serves the
5
+ * wire protocol from `worker-protocol.ts`. Designed to be referenced as:
6
+ *
7
+ * new Worker(new URL('./worker-runtime.js', import.meta.url),
8
+ * { type: 'module' });
9
+ *
10
+ * The runtime is intentionally side-effectful (registers `onmessage` at
11
+ * import time). It is not meant to be imported from the main thread.
12
+ */
13
+ export {};
14
+ //# sourceMappingURL=worker-runtime.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worker-runtime.d.ts","sourceRoot":"","sources":["../src/worker-runtime.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG"}
@@ -0,0 +1,100 @@
1
+ /*!
2
+ * albex v0.3.0
3
+ * Zero-config local full-text search for documents — runs entirely in the browser, no server, no upload.
4
+ * (c) 2026 RafaCalRob
5
+ * @license MIT
6
+ * https://github.com/RafaCalRob/Albex#readme
7
+ */
8
+ /**
9
+ * Albex worker runtime.
10
+ *
11
+ * Loads inside a Web Worker, instantiates an `AlbexEngine`, and serves the
12
+ * wire protocol from `worker-protocol.ts`. Designed to be referenced as:
13
+ *
14
+ * new Worker(new URL('./worker-runtime.js', import.meta.url),
15
+ * { type: 'module' });
16
+ *
17
+ * The runtime is intentionally side-effectful (registers `onmessage` at
18
+ * import time). It is not meant to be imported from the main thread.
19
+ */
20
+ import { AlbexEngine, AlbexError } from './albex.js';
21
+ let engine = null;
22
+ function ensureEngine() {
23
+ if (!engine)
24
+ throw new Error('Worker runtime: init() not called yet');
25
+ return engine;
26
+ }
27
+ async function dispatch(op) {
28
+ switch (op.kind) {
29
+ case 'init': {
30
+ engine = new AlbexEngine(op.opts);
31
+ await engine.init();
32
+ return undefined;
33
+ }
34
+ case 'indexFile': {
35
+ // Wrap the transferred buffer in a File-like object so existing
36
+ // indexers work unchanged.
37
+ const file = new File([op.buffer], op.name);
38
+ return ensureEngine().indexFile(file);
39
+ }
40
+ case 'search':
41
+ return ensureEngine().search(op.query, op.options);
42
+ case 'removeDocument':
43
+ return ensureEngine().removeDocument(op.id);
44
+ case 'compact':
45
+ ensureEngine().compact();
46
+ return undefined;
47
+ case 'reset':
48
+ ensureEngine().reset();
49
+ return undefined;
50
+ case 'getStats':
51
+ return ensureEngine().getStats();
52
+ case 'getLastSearchStats':
53
+ return ensureEngine().getLastSearchStats();
54
+ case 'getDocuments':
55
+ return ensureEngine().documents.slice();
56
+ case 'setMaxErrors':
57
+ ensureEngine().setMaxErrors(op.n);
58
+ return undefined;
59
+ case 'setThreshold':
60
+ ensureEngine().setThreshold(op.n);
61
+ return undefined;
62
+ case 'setMaxResults':
63
+ ensureEngine().setMaxResults(op.n);
64
+ return undefined;
65
+ case 'setLanguage':
66
+ ensureEngine().setLanguage(op.lang);
67
+ return undefined;
68
+ case 'save':
69
+ return ensureEngine().save(op.name);
70
+ case 'load':
71
+ return ensureEngine().load(op.name);
72
+ case 'loadOrInit':
73
+ return ensureEngine().loadOrInit(op.name);
74
+ case 'deleteSnapshot':
75
+ return ensureEngine().deleteSnapshot(op.name);
76
+ case 'listSnapshots':
77
+ return ensureEngine().listSnapshots();
78
+ }
79
+ }
80
+ self.onmessage = async (ev) => {
81
+ const { id, op } = ev.data;
82
+ try {
83
+ const result = await dispatch(op);
84
+ const res = { id, ok: true, result };
85
+ self.postMessage(res);
86
+ }
87
+ catch (err) {
88
+ const e = err;
89
+ const res = {
90
+ id, ok: false,
91
+ error: {
92
+ name: e.name ?? 'Error',
93
+ kind: err instanceof AlbexError ? err.kind : undefined,
94
+ message: e.message ?? String(err),
95
+ },
96
+ };
97
+ self.postMessage(res);
98
+ }
99
+ };
100
+ //# sourceMappingURL=worker-runtime.js.map