albex 0.3.0 → 0.6.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 (41) hide show
  1. package/CHANGELOG.md +275 -0
  2. package/README.md +4 -2
  3. package/dist/albex-worker.js +1 -1
  4. package/dist/albex.d.ts +157 -17
  5. package/dist/albex.d.ts.map +1 -1
  6. package/dist/albex.js +405 -232
  7. package/dist/albex.js.map +1 -1
  8. package/dist/errors.d.ts +16 -2
  9. package/dist/errors.d.ts.map +1 -1
  10. package/dist/errors.js +6 -3
  11. package/dist/errors.js.map +1 -1
  12. package/dist/persistence.js +1 -1
  13. package/dist/profile.d.ts +11 -6
  14. package/dist/profile.d.ts.map +1 -1
  15. package/dist/profile.js +6 -13
  16. package/dist/profile.js.map +1 -1
  17. package/dist/resource-manager.js +1 -1
  18. package/dist/tiered-store.js +1 -1
  19. package/dist/wasm-bindings.d.ts +46 -5
  20. package/dist/wasm-bindings.d.ts.map +1 -1
  21. package/dist/wasm-bindings.js +102 -7
  22. package/dist/wasm-bindings.js.map +1 -1
  23. package/dist/worker-protocol.js +1 -1
  24. package/dist/worker-runtime.js +12 -3
  25. package/dist/worker-runtime.js.map +1 -1
  26. package/package.json +13 -9
  27. package/src/albex.ts +478 -246
  28. package/src/errors.ts +18 -2
  29. package/src/profile.ts +11 -10
  30. package/src/wasm-bindings.ts +157 -8
  31. package/src/worker-runtime.ts +12 -2
  32. package/wasm/pkg/albex_pdf.wasm +0 -0
  33. package/wasm/pkg/albex_wasm.wasm +0 -0
  34. package/wasm/pkg/albex_wasm_bg.wasm +0 -0
  35. package/wasm/pkg/albex_wasm_simd.wasm +0 -0
  36. package/wasm/pkg/albex_wasm_mini.wasm +0 -0
  37. package/wasm/pkg/albex_wasm_mini_simd.wasm +0 -0
  38. package/wasm/pkg/albex_wasm_pro.wasm +0 -0
  39. package/wasm/pkg/albex_wasm_pro_simd.wasm +0 -0
  40. package/wasm/pkg/albex_wasm_std.wasm +0 -0
  41. package/wasm/pkg/albex_wasm_std_simd.wasm +0 -0
package/CHANGELOG.md CHANGED
@@ -5,6 +5,281 @@ All notable changes to Albex are documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and Albex follows [Semantic Versioning](https://semver.org/).
7
7
 
8
+ ## [0.6.0] — 2026-05-31
9
+
10
+ Release de auditoría algorítmica + robustez. Cierra los hallazgos #1–#8 de
11
+ la revisión externa en profundidad: sube la selectividad del pre-filtro de
12
+ forma drástica, elimina dos clases de corrupción/pérdida silenciosa de
13
+ datos, y de paso corrige una falta de _soundness_ del filtro Bloom bajo
14
+ matching difuso que existía desde el principio. El binario crece ~2 KB
15
+ (33 KB baseline · 37 KB SIMD) por el código del pre-filtro de trigramas.
16
+
17
+ ### Breaking changes
18
+
19
+ - **ABI WASM v2 → v3** (hallazgo #7). El binario principal exporta ahora
20
+ `getLastIndexOverflow` y el host fija el rango ABI aceptado a `[3, 3]`
21
+ (antes `[1, 2]`, con un mínimo inalcanzable que la lista de exports
22
+ requeridos ya hacía imposible). Un `.wasm` cacheado de 0.5.x falla con
23
+ `AlbexAbiMismatchError` claro en `init()` en vez de petar más tarde.
24
+
25
+ ### Added
26
+
27
+ - **Pre-filtro de trigramas q-gram** (hallazgo #1). El Bloom de 64 bits
28
+ (un bit por `c & 0x3F`) está saturado en chunks de prosa de 512 bytes —
29
+ cada chunk contiene casi todo el alfabeto, así que no poda y el Bitap
30
+ acababa ejecutándose sobre todo el corpus. Se añade una firma de 256
31
+ bits de los **trigramas** de cada chunk (`CHUNK_SIG`, BSS, no infla el
32
+ `.wasm`) como segundo pre-filtro mucho más selectivo. Es **sound bajo
33
+ matching difuso**: una ocurrencia con `e` errores conserva ≥ `N − 3e`
34
+ de los trigramas exactos del token (lema q-gram), y la firma no tiene
35
+ falsos negativos, así que nunca descarta un match real — solo poda
36
+ chunks que demostrablemente no pueden contenerlo. El Bitap confirma
37
+ cada superviviente: la corrección no cambia, solo se encoge el conjunto
38
+ candidato.
39
+ - **`AlbexCapacityError` con campo `limit`** (`'chunks' | 'text' | 'docs'
40
+ | 'names'`). El nuevo export `getLastIndexOverflow()` señaliza qué pool
41
+ se llenó durante el último `begin..endDocument`.
42
+
43
+ ### Fixed
44
+
45
+ - **Pérdida silenciosa de datos al agotar capacidad** (hallazgo #3). Los
46
+ pools del WASM se llenaban en silencio y `indexFile` devolvía un
47
+ documento a medio indexar indistinguible de uno completo (`getStats()`
48
+ mentía). Ahora `indexFile` lee el overflow y lanza `AlbexCapacityError`.
49
+ El documento que desborda se **revierte atómicamente** en el WASM
50
+ (`endDocument` restaura `chunk_count`/`text_used`/`name_used` al inicio
51
+ del doc): indexación all-or-nothing por fichero, sin chunks huérfanos
52
+ sin nombre.
53
+ - **Re-entrancy en el path async** (hallazgo #2). Una única instancia WASM
54
+ con estado global y ops async que ceden al scheduler entre slices: dos
55
+ operaciones solapadas se corrompían (un `searchBegin` nuevo reseteaba el
56
+ cursor de una búsqueda cooperativa en vuelo). Las ops async se serializan
57
+ ahora con una cola interna; los mutadores/búsquedas síncronos rechazan
58
+ ejecutarse a media operación (`AlbexError` kind `'busy'`) en vez de
59
+ corromper. El worker-runtime procesa mensajes estrictamente en orden.
60
+ - **Bloom no-sound bajo fuzzy** (corolario del #1). El filtro Bloom de
61
+ caracteres rechazaba un match aproximado cuando el carácter sustituido
62
+ no estaba en el chunk (bug latente pre-0.6.0). Ahora el Bloom solo se
63
+ aplica a tokens exactos (`eff_errors == 0`); los tokens difusos se
64
+ filtran solo con el conteo de trigramas, que sí es sound.
65
+ - **Frase + `windowed`** (hallazgo #7). El post-filtro de frase corría
66
+ contra el snippet recortado, así que `{ windowed: true }` podía descartar
67
+ un match válido cuyo segundo término caía fuera de la ventana. Ahora la
68
+ comprobación de adyacencia corre contra el **texto completo** del chunk;
69
+ el windowing solo afecta a la visualización.
70
+ - **GPU + OR**: el hash del pre-filtro GPU usaba siempre el patrón de la
71
+ rama 0, generando una máscara de candidatos errónea para las ramas i≠0 de
72
+ una query OR y descartando sus hits en silencio (hallazgo #6).
73
+ - **Corte de chunk a mitad de codepoint UTF-8** (hallazgo #7): el corte duro
74
+ a 512 bytes podía partir una secuencia multibyte; ahora retrocede a la
75
+ frontera de codepoint y el snippet del borde no renderiza `�`.
76
+ - **`replaceDocument` sin reclamar espacio** (hallazgo #7): repetidos
77
+ replaces dejaban tombstones en el text pool; ahora se compacta de forma
78
+ oportunista bajo presión.
79
+
80
+ ### Performance
81
+
82
+ - `prepareQuery` ya no hace un `memset` de 64 KB en pila por query (hallazgo
83
+ #4). La query de trabajo se acota a `MAX_QUERY_BYTES` (1 KB).
84
+
85
+ ### Tooling
86
+
87
+ - `npm run relaunch`: limpia artefactos, recompila WASM (baseline + SIMD) +
88
+ PDF + TS + OCR, corre los tests, empaqueta la librería (`npm pack`) y
89
+ levanta el demo en `http://localhost:5173/demo/`. Scripts auxiliares
90
+ `clean` / `clean:all` / `build:ocr`.
91
+ - Cobertura: +16 tests (110 en total) — selectividad del trigram, soundness
92
+ fuzzy, supervivencia de firmas tras compact/restore, error de capacidad,
93
+ guard de concurrencia, frase+windowed.
94
+
95
+ ## [0.5.0] — 2026-05-30
96
+
97
+ Release de endurecimiento — cierra las cinco clases de bugs accionables
98
+ de la auditoría externa de código. Sin nuevas features que pidan datos
99
+ reales para ser correctas. El binario crece ~2 KB respecto a 0.4.0 por
100
+ la lógica de query parsing en Rust + ABI version.
101
+
102
+ ### Breaking changes
103
+
104
+ - **`@albex/ocr` ahora requiere `engine.attachOcr()`** (audit 3.8). El
105
+ patrón anterior de mutar `engine.ocrImage = ...` y
106
+ `engine.ocrConfig = ...` directamente queda eliminado. Para
107
+ integradores que usaban `@albex/ocr`, **el cambio es transparente** —
108
+ `enableOcr(engine)` sigue siendo la misma llamada. Para quien tuviera
109
+ un adaptador manual: usar `engine.attachOcr({ recognize, options })`.
110
+ - **Tiers eliminados** (audit 4.1). Mini/std/pro × baseline/SIMD (6
111
+ binarios) consolidados a **baseline + SIMD** (2 binarios). El
112
+ parámetro `tier` de `AlbexOptions` queda como noop deprecado. El alias
113
+ `albex_wasm_bg.wasm` se mantiene para compatibilidad con `0.4.x`.
114
+ - `pickTier(profile)` siempre devuelve `'std'` ahora. La función queda
115
+ exportada para compatibilidad de código fuente, no de comportamiento.
116
+
117
+ ### Fixed
118
+
119
+ - **Validación runtime de la ABI WASM** (audit 3.2). `asAlbexExports` y
120
+ `asAlbexPdfExports` ya no son `as unknown as` ceremoniales — verifican
121
+ que `memory` sea una `WebAssembly.Memory`, que cada export requerido
122
+ exista, y que `abiVersion()` esté en el rango soportado. Lanzan
123
+ `AlbexAbiMismatchError` con la lista de exports faltantes cuando algo
124
+ no encaja. Antes, un binario incompatible instanciaba en silencio y
125
+ petaba en el primer call site que tocaba la función ausente.
126
+ - **`makePdfWasmImports` falla rápido** ante imports desconocidos
127
+ (compatibilidad con el cambio anterior de 0.3.1; ya estaba pero ahora
128
+ alineado con la ABI version del módulo).
129
+
130
+ ### Added
131
+
132
+ - **Canal de diagnósticos estructurado** (audit 3.6). Los `console.warn`
133
+ diseminados por el path de indexación desaparecen — los reemplaza un
134
+ buffer interno de `AlbexDiagnostic[]` consultable con
135
+ `engine.takeDiagnostics()`. Cada entrada es `{kind, stage, message, file?,
136
+ page?}` con `kind` en `'recovered' | 'skipped' | 'fallback' | 'info'`.
137
+ Cubre: fallback PDF→OCR, OCR fail por imagen, GPU caída a CPU, descarga
138
+ PDF WASM en red restringida. Capped a 256 entradas para no explotar en
139
+ corpus muy corruptos. La API de "best-effort" se mantiene, pero el
140
+ caller ahora puede inspeccionar qué se perdió.
141
+ - **`engine.attachOcr(adapter)`** — extension point formal. Devuelve un
142
+ `OcrHandle` con `dispose()`. El motor valida el contrato y rechaza
143
+ un segundo `attachOcr` mientras haya uno activo. La propiedad pública
144
+ `engine.ocrImage` se mantiene como getter de feature-detect pero no es
145
+ asignable — para evitar el patrón anti-encapsulación del audit.
146
+ - **`abiVersion()` exportada por ambos módulos WASM**. Main = v2 (incluye
147
+ query parser nuevo); PDF = v3 (incluye image extraction). El validador
148
+ TS rechaza binarios fuera de rango.
149
+
150
+ ### Architecture — query parsing moves to WASM (audit "two truths")
151
+
152
+ Pre-0.5.0 el TypeScript dueño de `parseQuery`, `tokenize`,
153
+ `tokensToWasmQuery`, mientras Rust tokenizaba al indexar. Dos verdades
154
+ sobre qué era un "token".
155
+
156
+ - Nuevos exports WASM: `prepareQuery`, `getQueryKind`,
157
+ `getQueryBranchCount`, `getQueryBranchPattern`, `selectQueryBranch`.
158
+ - Hasta **8 branches OR** soportadas, **4 tokens por branch**, **256
159
+ bytes por pattern compilado** — todo en static BSS, sin alocación.
160
+ - `containsPhrase` queda en TS porque opera sobre snippets (output del
161
+ WASM), no sobre la query — no es divergencia de tokenizer.
162
+ - `parseQuery`, `tokenize`, `tokensToWasmQuery` eliminados del TS.
163
+ - Un único algoritmo de "qué es un token" entre indexación y querying.
164
+
165
+ ### Build & maintenance
166
+
167
+ - **`prepublishOnly` rebuildea WASM + corre tests** desde 0.3.1, ya
168
+ garantizado en 0.5.0.
169
+ - Build pipeline simplificada: `scripts/build-wasm.mjs` produce solo
170
+ dos binarios. `npm pack --dry-run` muestra 4 archivos `.wasm` en lugar
171
+ de 8.
172
+ - `wasm/Cargo.toml` añade `wee_alloc` (~1 KB) para el staging Vec del
173
+ restore atómico de 0.4.0.
174
+
175
+ ### Tests
176
+
177
+ - 94 vitest cases verdes (era 88 en 0.4.0). Cinco tests del tier matrix
178
+ eliminados (mini/std/pro ya no existen). Tests nuevos:
179
+ - `tests/abi-validation.test.ts` (5): valida que `AlbexAbiMismatchError`
180
+ se lanza ante exports faltantes, abiVersion fuera de rango, memory
181
+ inválida.
182
+ - `tests/diagnostics.test.ts` (4): valida `takeDiagnostics()` drena,
183
+ cap a 256, reset limpia.
184
+
185
+ ### Postponed con razón
186
+
187
+ Cosas del audit que NO se cierran en 0.5.0 porque cerrarlas sin datos
188
+ reales sería adivinar:
189
+
190
+ - **3.5 OCR paralelización**: optimización sin profiling no es ingeniería.
191
+ - **3.9 Adaptive runtime con métricas reales**: requiere corpus y uso
192
+ reales para validar decisiones.
193
+ - **4.3 GPU equivalence test**: requiere corpus >20k chunks que aún no
194
+ está checked in.
195
+ - **7 parsers lite a WASM**: ~3 semanas serias. Separable. No es bug
196
+ fix, es mejora arquitectural más limpia con tiempo dedicado.
197
+
198
+ ## [0.4.0] — 2026-05-30
199
+
200
+ Cierre de dos clases enteras de bugs identificadas por la auditoría externa
201
+ de código. Sin cambios cosméticos — el binario crece ~4 KB por la lógica
202
+ de atomicidad y el allocator necesario para el staging buffer.
203
+
204
+ ### Fixed — atomic snapshot restore (audit 3.4)
205
+
206
+ - **Snapshot v3 con formato por campos**. Reemplaza la copia byte a byte
207
+ de los structs internos `Chunk`/`DocEntry` (`from_raw_parts`) por un
208
+ encoding explícito little-endian. El formato deja de depender del
209
+ layout en memoria de Rust, del target, del padding o de cambios en
210
+ los tipos. Lo que va al disco es un contrato.
211
+ - **`restoreCommit()` — protocolo de 3 fases atómico**. El antiguo
212
+ `restoreBegin` reseteaba el estado y escribía los counters antes de
213
+ recibir un solo byte del payload. Si `restoreFeed` fallaba a mitad,
214
+ el corpus previo quedaba destruido. v3 acumula todo el payload en un
215
+ staging buffer y solo aplica al estado vivo cuando `restoreCommit`
216
+ valida que el tamaño completo coincide con el header. Un commit
217
+ fallido deja el motor con el corpus previo intacto.
218
+ - **Compatibilidad backwards**. v1 y v2 siguen cargando — para ellos
219
+ `restoreBegin` mantiene la semántica vieja (no-atómica) y
220
+ `restoreCommit` es no-op que devuelve 1. El primer `save()` tras
221
+ cargar un snapshot viejo lo reescribe como v3.
222
+ - Binarios crecen ~4 KB por la lógica nueva y por `wee_alloc` (única
223
+ fuente de alocación en el módulo, usada por el staging Vec).
224
+
225
+ ### Fixed — single source of truth for content hash (audit "two truths")
226
+
227
+ - **FNV-1a 64-bit ahora vive en Rust**. La implementación TypeScript que
228
+ duplicaba el algoritmo desaparece. Tres nuevos exports
229
+ (`hashBegin`/`hashFeed`/`hashFinish`) implementan el hash en streaming
230
+ para archivos mayores que el scratchpad. El método privado del engine
231
+ `_contentHash` produce exactamente el mismo string hex de 16
232
+ caracteres que devolvía la versión TS — ningún caller cambia.
233
+
234
+ ### Added — tests
235
+
236
+ - `tests/load-restores-docs.test.ts`: nuevo test "a v3 restore that
237
+ never commits leaves the previous index intact". Verifica
238
+ explícitamente la atomicidad: trunca el payload de un snapshot al
239
+ 75 %, intenta cargarlo, verifica que `load()` devuelve `false` y que
240
+ el corpus previo sigue indexado y consultable.
241
+ - `tests/hash.test.ts`: reescrito para validar el hash WASM contra el
242
+ engine real (la versión vieja era una re-implementación TS standalone
243
+ comparándose consigo misma). Cubre shape, determinismo, sensibilidad
244
+ a un byte, FNV offset basis, streaming sobre 96 KB (> scratchpad).
245
+ - 88 tests verdes (era 85 en 0.3.1).
246
+
247
+ ### Postponed
248
+
249
+ - Mover el tokenizador y query parser a WASM (audit "wrapper TS hace
250
+ demasiado") se traslada a 0.5.0. Es mejora arquitectural, no cierre
251
+ de bug — y tiene suficientes trade-offs de diseño (semánticas de OR,
252
+ post-filter de phrase) como para no publicar una API a medio cocer.
253
+
254
+ ## [0.3.1] — 2026-05-30
255
+
256
+ Hardening pass after an external code audit. No new features; three
257
+ specific issues addressed.
258
+
259
+ ### Fixed
260
+
261
+ - **Debug logs removed from the indexing hot path.** Three `console.log`
262
+ statements added during the OCR-worker-abort diagnostic session were
263
+ firing on every PDF (hybrid OCR decision) and every embedded image
264
+ (kind / len / magic-byte trace). They are gone; the legitimate
265
+ `console.warn` messages for actual failures stay.
266
+
267
+ - **`makePdfWasmImports` now fails fast on unknown imports.** Previously
268
+ any unrecognised import was satisfied with a `console.warn` stub,
269
+ which let the module instantiate and defer the real failure to an
270
+ arbitrary call inside `extractPdf`. The loader now throws
271
+ `AlbexInitError` at boot with a clear "rebuild your binary" message.
272
+ An unknown import means the wasm-bindgen / lopdf / getrandom graph
273
+ drifted from what this loader was written for; better to surface that
274
+ immediately than to hang or crash mid-extraction.
275
+
276
+ - **`prepublishOnly` now rebuilds every WASM artifact and runs the
277
+ entire test suite.** It was running only `tsc + banner.mjs`, which
278
+ meant the WASM binaries published to npm could be out of sync with
279
+ the current Rust source. The script is now `npm run build:all && npm
280
+ test`. Publishing takes longer, but the package is guaranteed to
281
+ contain binaries reproducible from the source it ships.
282
+
8
283
  ## [0.3.0] — 2026-05-30
9
284
 
10
285
  ### Hybrid PDF OCR (opt-in)
package/README.md CHANGED
@@ -69,7 +69,7 @@ That's the entire onboarding. Read on for what else the engine can do.
69
69
  - **Bundler-friendly default** — `new AlbexEngine()` works without extra
70
70
  configuration in bundlers that recognise the `new URL(..., import.meta.url)`
71
71
  asset pattern (see the "Install" section for the tested matrix).
72
- - **Fuzzy matching** — finds `"contrato"` even if you type `"conttrato"` (Bitap with adaptive edit distance).
72
+ - **Fuzzy matching** — finds `"contrato"` even if you type `"conttrato"` (Bitap with adaptive edit distance). Sound under a two-stage pre-filter (character Bloom for exact tokens, a 256-bit **trigram q-gram signature** for everything) that prunes the candidate set ~10× on prose without ever dropping a real approximate match.
73
73
  - **Accent-insensitive** — `"accion"` matches `"acción"`, `"espana"` matches `"España"`, plus Latin Extended (Polish, Czech, Slovak, Turkish…).
74
74
  - **11 formats with varying depth** — DOCX · XLSX · PDF · HTML · MD · JSON · CSV · EML · RTF · TXT · XML. See the support table below; several formats are deliberately "lite" (CSV is RFC-4180-lite, EML is MIME-lite, RTF is regex-stripped, etc.).
75
75
  - **Phrase + OR queries** — `"contrato marco"` and `contrato | acuerdo` work out of the box.
@@ -81,8 +81,10 @@ That's the entire onboarding. Read on for what else the engine can do.
81
81
  - **WebGPU pre-filter** — experimental, opt-in (`gpu: 'auto'`). Implemented for corpora over 20 k chunks; no reproducible speedup number yet — the bench in this repo runs on a 200-document synthetic corpus only.
82
82
  - **SIMD opportunistic** — picks a SIMD-accelerated variant when the host supports v128.
83
83
  - **Tiered storage** — `TieredStore` keeps recent docs hot, evicts cold ones to OPFS, promotes on demand.
84
+ - **Capacity-safe** — when a pool fills (`docs`/`chunks`/`text`/`names`), `indexFile` throws `AlbexCapacityError` with a `limit` field instead of silently truncating the corpus.
85
+ - **Re-entrancy-safe** — async operations on one engine serialize; sync `search`/`compact`/`reset` refuse to run mid-operation (`AlbexError` kind `busy`) rather than corrupting the shared WASM state. Use `searchCooperative` for overlapping search-as-you-type.
84
86
  - **Typed errors** — `AlbexParseError`, `AlbexUnsupportedFormatError`, `AlbexCapacityError`, `AlbexInitError`. All extend `AlbexError`.
85
- - **Tiny core** — main WASM 24 KB (27 KB SIMD). PDF module (~1.2 MB) loads on demand. The OCR companion (`@albex/ocr`) is a separate package and pulls Tesseract.js (~3.5 MB) only when you call `enableOcr()`.
87
+ - **Tiny core** — main WASM 33 KB (37 KB SIMD). PDF module (~1.2 MB) loads on demand. The OCR companion (`@albex/ocr`) is a separate package and pulls Tesseract.js (~3.5 MB) only when you call `enableOcr()`.
86
88
 
87
89
  ---
88
90
 
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * albex v0.3.0
2
+ * albex v0.6.0
3
3
  * Zero-config local full-text search for documents — runs entirely in the browser, no server, no upload.
4
4
  * (c) 2026 RafaCalRob
5
5
  * @license MIT
package/dist/albex.d.ts CHANGED
@@ -45,6 +45,8 @@ export interface AlbexOptions {
45
45
  * Override the tier auto-detection. Pass `'auto'` (default), or an
46
46
  * explicit tier when you know the constraints of your target environment.
47
47
  */
48
+ /** @deprecated Removed in 0.5.0. Albex no longer has capacity tiers;
49
+ * pass `'auto'` or omit. Other values are accepted and ignored. */
48
50
  tier?: 'auto' | 'mini' | 'std' | 'pro';
49
51
  /**
50
52
  * SIMD selection. When `'auto'` (default), Albex probes for v128 support
@@ -143,6 +145,25 @@ export interface SearchStats {
143
145
  bloomPassed: number;
144
146
  bitapMatched: number;
145
147
  }
148
+ /**
149
+ * One structured warning recorded by the engine during indexFile or
150
+ * load. Replaces the pre-0.5.0 pattern of scattered `console.warn`
151
+ * calls. Inspect via `engine.takeDiagnostics()` after the operation.
152
+ */
153
+ export interface AlbexDiagnostic {
154
+ /** Coarse kind. `'recovered'` means the engine handled the issue and
155
+ * kept going; `'skipped'` means content was dropped; `'fallback'` means
156
+ * an alternate code path was used (e.g. lopdf after pdf-extract trap). */
157
+ kind: 'recovered' | 'skipped' | 'fallback' | 'info';
158
+ /** Where in the pipeline this happened. Free-form short tag. */
159
+ stage: 'pdf' | 'ocr' | 'gpu' | 'persistence' | 'network';
160
+ /** Human-readable message safe to surface in a UI. */
161
+ message: string;
162
+ /** Optional file the issue belongs to. */
163
+ file?: string;
164
+ /** Optional page number (1-based for PDFs). */
165
+ page?: number;
166
+ }
146
167
  /**
147
168
  * Result shape returned by an attached OCR module. Kept structural here so
148
169
  * the main package has no runtime dependency on `@albex/ocr` — the optional
@@ -157,6 +178,36 @@ export interface OcrAttachedOptions {
157
178
  lang?: string;
158
179
  hint?: string;
159
180
  }
181
+ /**
182
+ * Contract the engine accepts from an OCR plugin. `@albex/ocr` is the
183
+ * canonical implementation, but any module that satisfies this interface
184
+ * can be attached via `engine.attachOcr(adapter)`.
185
+ */
186
+ export interface OcrAdapter {
187
+ /** Invoked by the engine to OCR a single image. Receives whatever the
188
+ * caller passes (Blob, ArrayBuffer, etc.); the adapter is responsible
189
+ * for accepting that input. Must return text + confidence. */
190
+ recognize(image: unknown, opts?: OcrAttachedOptions): Promise<OcrAttachedResult>;
191
+ /** Engine-side switches the adapter wants honoured. The only one
192
+ * defined today is `alwaysExtractEmbeddedImages`, which turns on the
193
+ * hybrid PDF OCR pass. New flags can be added without breaking the
194
+ * adapter interface. */
195
+ options?: {
196
+ /** When true, every PDF (native or scanned) is walked for embedded
197
+ * images and each qualifying image is sent to `recognize`. Off by
198
+ * default to keep performance predictable on native PDFs. */
199
+ alwaysExtractEmbeddedImages?: boolean;
200
+ };
201
+ }
202
+ /** Returned by `attachOcr`. Holds the lifecycle handles for the plugin.
203
+ * Calling `dispose()` removes the adapter from the engine; subsequent
204
+ * `engine.ocrImage` access returns `undefined` again. */
205
+ export interface OcrHandle {
206
+ /** Detach the plugin and tear down any resources it holds. After this,
207
+ * the engine reverts to "no OCR" — scanned PDFs go back to registering
208
+ * with zero chunks. */
209
+ dispose(): Promise<void>;
210
+ }
160
211
  export declare class AlbexEngine {
161
212
  private _wasm;
162
213
  private _mem;
@@ -166,28 +217,26 @@ export declare class AlbexEngine {
166
217
  * runtime dependency on OCR — this is a structural slot that the optional
167
218
  * companion package fills.
168
219
  */
169
- ocrImage?: (image: unknown, opts?: OcrAttachedOptions) => Promise<OcrAttachedResult>;
170
220
  /**
171
- * Optional OCR-side configuration set by `@albex/ocr::enableOcr`. Read
172
- * by the engine to decide whether to invoke OCR on top of the text it
173
- * already extracted from a PDF (hybrid PDFs: native text + images that
174
- * also contain text, like stamps, scanned annexes, or diagrams with
175
- * labels).
176
- *
177
- * When `alwaysExtractEmbeddedImages` is true, every page of every PDF
178
- * passes through `extractPageImages` after the normal text extraction;
179
- * any image that meets the size filter (200×200 in Rust) is fed to
180
- * `ocrImage`. Performance cost: 1–3 s per qualifying image.
181
- *
182
- * Off by default — set this opt-in via the OCR module's options.
221
+ * Public OCR entry point. Forwards to the attached OCR adapter installed
222
+ * via `attachOcr()`. Reading this property is a feature-detect for
223
+ * integrators: `if (engine.ocrImage) { ... OCR available ... }`. Writing
224
+ * to it directly is no longer supported in 0.5.0+ — use `attachOcr`.
183
225
  */
184
- ocrConfig?: {
185
- alwaysExtractEmbeddedImages?: boolean;
186
- };
226
+ get ocrImage(): ((image: unknown, opts?: OcrAttachedOptions) => Promise<OcrAttachedResult>) | undefined;
227
+ /** Private adapter slot. Holds the OCR plugin contract installed by
228
+ * `attachOcr()`. The engine reads `recognize` and `options` here; the
229
+ * caller never gets a reference to this object directly. */
230
+ private _ocrAdapter;
187
231
  private _pdfWasm;
188
232
  private _pdfMem;
189
233
  private _docs;
190
234
  private _lastSearch;
235
+ /** Structured diagnostics collected during the most recent operation.
236
+ * Drained by `takeDiagnostics()`. Capped at 256 entries to avoid
237
+ * unbounded memory growth in pathological cases (very corrupted
238
+ * corpora producing thousands of recovery warnings). */
239
+ private _diagnostics;
191
240
  private _tier;
192
241
  private _simd;
193
242
  private _profile;
@@ -196,7 +245,17 @@ export declare class AlbexEngine {
196
245
  private _gpuChunkCountUploaded;
197
246
  private _unsubscribeResources;
198
247
  private readonly _opts;
248
+ private _opChain;
249
+ private _busy;
199
250
  constructor(opts: AlbexOptions);
251
+ /** Serialize an async engine operation behind any in-flight one. */
252
+ private _exclusive;
253
+ /** Guard a synchronous mutator/search: refuse to run mid-async-operation
254
+ * rather than silently corrupt the shared WASM state. */
255
+ private _assertIdle;
256
+ /** Compact opportunistically when tombstones pile up under text pressure,
257
+ * so repeated removeDocument/replaceDocument don't exhaust the pool. */
258
+ private _autoCompactIfNeeded;
200
259
  /** Load and initialise the main WASM module. Must be called before any other method. */
201
260
  init(): Promise<void>;
202
261
  /**
@@ -250,6 +309,15 @@ export declare class AlbexEngine {
250
309
  private _writeStr;
251
310
  private _readPad;
252
311
  private _feedText;
312
+ /**
313
+ * Compute the FNV-1a 64-bit content hash of `bytes` via the WASM
314
+ * streaming API. Returns a 16-character hex string identical in shape
315
+ * to what the TS implementation in 0.3.x returned, so all callers
316
+ * stay unchanged. Single source of truth — same hash whether we use
317
+ * it for indexFile dedup, for snapshot v2 persistence, or anywhere
318
+ * else. Large inputs are chunked at FEED_SIZE just like _feedText.
319
+ */
320
+ private _contentHash;
253
321
  private _feedXmlBytes;
254
322
  private _ensurePdfWasm;
255
323
  private _indexDocx;
@@ -340,6 +408,7 @@ export declare class AlbexEngine {
340
408
  * Throws for unsupported formats or parse errors.
341
409
  */
342
410
  indexFile(file: File): Promise<IndexedDocument>;
411
+ private _indexFileInner;
343
412
  /**
344
413
  * Mark a previously indexed document as removed. Searches no longer return
345
414
  * its chunks. Storage is reclaimed only after `compact()`.
@@ -348,6 +417,7 @@ export declare class AlbexEngine {
348
417
  * Returns `true` if a matching document was found and tombstoned.
349
418
  */
350
419
  removeDocument(id: string): boolean;
420
+ private _removeDocumentInner;
351
421
  /**
352
422
  * Replace a previously indexed document with new content. Equivalent to
353
423
  * `removeDocument(name)` + `indexFile(newFile)` but does not trigger the
@@ -372,6 +442,10 @@ export declare class AlbexEngine {
372
442
  * markers instead of full chunk text. Defaults: 60 bytes before, 120 after.
373
443
  */
374
444
  search(query: string, opts?: SearchOptions): SearchResult[];
445
+ /** Read the WASM-compiled tokens of branch `i` for phrase post-filter.
446
+ * The bytes returned are exactly what the WASM tokenizer produced —
447
+ * no TS re-tokenization. */
448
+ private _branchTokens;
375
449
  /**
376
450
  * Cooperative search. Processes the corpus in slices, yielding to the
377
451
  * event loop between them so the host UI thread keeps a chance to paint
@@ -387,6 +461,9 @@ export declare class AlbexEngine {
387
461
  * Pass `opts.frameBudgetMs` to control the slice size (default 8 ms).
388
462
  */
389
463
  searchCooperative(query: string, opts?: SearchOptions): AsyncIterable<SearchResult>;
464
+ /** Materialise a cooperative search to a sorted result array. Runs inside
465
+ * the exclusivity lock. Frame-budget yielding lives in _runSearchBudgeted. */
466
+ private _searchCooperativeCollect;
390
467
  /**
391
468
  * @deprecated Renamed to `searchCooperative` in 0.3.0. The original name
392
469
  * was misleading — this method does not stream incremental results, it
@@ -404,9 +481,19 @@ export declare class AlbexEngine {
404
481
  * may eat the entire budget, which is also fine.
405
482
  */
406
483
  private _runSearchBudgeted;
407
- /** Materialise results [0..count) into the public SearchResult shape. */
484
+ /** Materialise results [0..count) into the public SearchResult shape.
485
+ * When `phraseTokens` is given, each result is kept only if those tokens
486
+ * appear adjacently in the FULL chunk text — independent of any display
487
+ * windowing — so phrase queries stay correct under `{ windowed: true }`. */
408
488
  private _collectResults;
489
+ /** Run all OR branches and merge dedup-by-(doc, location, match). The
490
+ * branches are already compiled inside the WASM (by prepareQuery); we
491
+ * iterate them with selectQueryBranch. The "rawQuery" param is kept
492
+ * only for the lastSearch.query field. */
409
493
  private _searchOr;
494
+ /** Execute a single search using whichever query branch is currently
495
+ * active (set via selectQueryBranch). Returns the materialised
496
+ * SearchResult[]. Caller is responsible for activating a branch first. */
410
497
  private _runSearch;
411
498
  /** Returns current engine statistics. */
412
499
  getStats(): EngineStats;
@@ -433,6 +520,57 @@ export declare class AlbexEngine {
433
520
  setLanguage(lang: 'off' | 'es'): void;
434
521
  /** Full reset — clears all indexed documents and chunks. */
435
522
  reset(): void;
523
+ private _resetInner;
524
+ /**
525
+ * Drain and return the diagnostics collected since the last call (or
526
+ * since the engine was created). Use this to surface recoverable
527
+ * issues to the caller after `indexFile`, `load`, or any other
528
+ * operation that may run into a "best-effort" path.
529
+ *
530
+ * Example diagnostics:
531
+ * - `{kind:'fallback', stage:'pdf', message:'pdf-extract crashed,
532
+ * attempting OCR-only fallback', file:'invoice.pdf'}`
533
+ * - `{kind:'skipped', stage:'ocr', message:'Tesseract abort on page
534
+ * 3 image 1; remaining images on this page skipped', file:'...',
535
+ * page:3}`
536
+ * - `{kind:'fallback', stage:'gpu', message:'GPU pre-filter failed,
537
+ * using CPU'}`
538
+ *
539
+ * The buffer is cleared on each call; callers should consume the
540
+ * returned array immediately (e.g. log to their telemetry, surface
541
+ * a UI banner). After `reset()` the buffer is also cleared.
542
+ */
543
+ takeDiagnostics(): AlbexDiagnostic[];
544
+ /** Internal: record a diagnostic. Capped at 256 to bound memory. */
545
+ private _diag;
546
+ /**
547
+ * Install an OCR adapter. Returns a handle whose `dispose()` removes the
548
+ * adapter from the engine.
549
+ *
550
+ * The contract: the adapter must provide `recognize(image, opts)` that
551
+ * returns `Promise<OcrAttachedResult>`. The engine validates the
552
+ * contract at attach time and refuses adapters that don't expose a
553
+ * recognise function. Only one adapter can be attached at a time; a
554
+ * second call to `attachOcr` while one is active throws — the caller
555
+ * must dispose the previous one first.
556
+ *
557
+ * @example
558
+ * ```ts
559
+ * import { enableOcr } from '@albex/ocr';
560
+ * const handle = enableOcr(engine); // internally calls attachOcr
561
+ * // ... later ...
562
+ * await handle.dispose();
563
+ * ```
564
+ *
565
+ * Direct use without the companion package:
566
+ * ```ts
567
+ * const handle = engine.attachOcr({
568
+ * recognize: async (blob) => myCustomOcr(blob),
569
+ * options: { alwaysExtractEmbeddedImages: false },
570
+ * });
571
+ * ```
572
+ */
573
+ attachOcr(adapter: OcrAdapter): OcrHandle;
436
574
  /**
437
575
  * Persist the current index to OPFS (or IndexedDB as fallback) under `name`.
438
576
  *
@@ -441,12 +579,14 @@ export declare class AlbexEngine {
441
579
  * state in roughly O(total bytes), bypassing re-parsing.
442
580
  */
443
581
  save(name: string): Promise<void>;
582
+ private _saveInner;
444
583
  /**
445
584
  * Restore an index previously saved with `save(name)`. Returns `true` on
446
585
  * success, `false` if the snapshot is missing or has an incompatible
447
586
  * header (wrong magic, version, or struct sizes).
448
587
  */
449
588
  load(name: string): Promise<boolean>;
589
+ private _loadInner;
450
590
  /**
451
591
  * Convenience: load if the snapshot exists, otherwise leave the engine
452
592
  * empty. Returns whether a load actually happened.
@@ -1 +1 @@
1
- {"version":3,"file":"albex.d.ts","sourceRoot":"","sources":["../src/albex.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"albex.d.ts","sourceRoot":"","sources":["../src/albex.ts"],"names":[],"mappings":"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"}