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.
- package/CHANGELOG.md +275 -0
- package/README.md +4 -2
- package/dist/albex-worker.js +1 -1
- package/dist/albex.d.ts +157 -17
- package/dist/albex.d.ts.map +1 -1
- package/dist/albex.js +405 -232
- package/dist/albex.js.map +1 -1
- package/dist/errors.d.ts +16 -2
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +6 -3
- package/dist/errors.js.map +1 -1
- package/dist/persistence.js +1 -1
- package/dist/profile.d.ts +11 -6
- package/dist/profile.d.ts.map +1 -1
- package/dist/profile.js +6 -13
- package/dist/profile.js.map +1 -1
- package/dist/resource-manager.js +1 -1
- package/dist/tiered-store.js +1 -1
- package/dist/wasm-bindings.d.ts +46 -5
- package/dist/wasm-bindings.d.ts.map +1 -1
- package/dist/wasm-bindings.js +102 -7
- package/dist/wasm-bindings.js.map +1 -1
- package/dist/worker-protocol.js +1 -1
- package/dist/worker-runtime.js +12 -3
- package/dist/worker-runtime.js.map +1 -1
- package/package.json +13 -9
- package/src/albex.ts +478 -246
- package/src/errors.ts +18 -2
- package/src/profile.ts +11 -10
- package/src/wasm-bindings.ts +157 -8
- package/src/worker-runtime.ts +12 -2
- package/wasm/pkg/albex_pdf.wasm +0 -0
- package/wasm/pkg/albex_wasm.wasm +0 -0
- package/wasm/pkg/albex_wasm_bg.wasm +0 -0
- package/wasm/pkg/albex_wasm_simd.wasm +0 -0
- package/wasm/pkg/albex_wasm_mini.wasm +0 -0
- package/wasm/pkg/albex_wasm_mini_simd.wasm +0 -0
- package/wasm/pkg/albex_wasm_pro.wasm +0 -0
- package/wasm/pkg/albex_wasm_pro_simd.wasm +0 -0
- package/wasm/pkg/albex_wasm_std.wasm +0 -0
- 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
|
|
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
|
|
package/dist/albex-worker.js
CHANGED
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
|
-
*
|
|
172
|
-
*
|
|
173
|
-
*
|
|
174
|
-
*
|
|
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
|
-
|
|
185
|
-
|
|
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.
|
package/dist/albex.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"albex.d.ts","sourceRoot":"","sources":["../src/albex.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;
|
|
1
|
+
{"version":3,"file":"albex.d.ts","sourceRoot":"","sources":["../src/albex.ts"],"names":[],"mappings":"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"}
|