@kreuzberg/wasm 4.0.0-rc.21 → 4.0.0-rc.23

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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../typescript/ocr/registry.ts"],"sourcesContent":["/**\n * OCR Backend Registry\n *\n * Provides a registry for OCR backends in the WASM environment.\n * This enables auto-registration and management of OCR backends.\n *\n * Note: The WASM package provides a lightweight registry in the browser.\n * For more advanced features like Rust integration, use @kreuzberg/node or @kreuzberg/deno.\n *\n * @example\n * ```typescript\n * import { TesseractWasmBackend } from '@kreuzberg/wasm/ocr/tesseract-wasm-backend';\n * import { enableOcr } from '@kreuzberg/wasm';\n *\n * // Simple auto-registration\n * await enableOcr();\n * ```\n */\n\nimport type { OcrBackendProtocol } from \"../types.js\";\n\n/** Global registry of OCR backends */\nconst ocrBackendRegistry = new Map<string, OcrBackendProtocol>();\n\n/**\n * Register an OCR backend\n *\n * Registers an OCR backend with the WASM extraction pipeline.\n * If a backend with the same name is already registered, it will be replaced.\n *\n * @param backend - OCR backend implementing OcrBackendProtocol\n * @throws {Error} If backend validation fails\n *\n * @example\n * ```typescript\n * import { TesseractWasmBackend } from '@kreuzberg/wasm/ocr/tesseract-wasm-backend';\n * import { registerOcrBackend } from '@kreuzberg/wasm/ocr/registry';\n *\n * const backend = new TesseractWasmBackend();\n * await backend.initialize();\n * registerOcrBackend(backend);\n * ```\n */\nexport function registerOcrBackend(backend: OcrBackendProtocol): void {\n\t// Validate backend\n\tif (!backend) {\n\t\tthrow new Error(\"Backend cannot be null or undefined\");\n\t}\n\n\tif (typeof backend.name !== \"function\") {\n\t\tthrow new Error(\"Backend must implement name() method\");\n\t}\n\n\tif (typeof backend.supportedLanguages !== \"function\") {\n\t\tthrow new Error(\"Backend must implement supportedLanguages() method\");\n\t}\n\n\tif (typeof backend.processImage !== \"function\") {\n\t\tthrow new Error(\"Backend must implement processImage() method\");\n\t}\n\n\tconst backendName = backend.name();\n\n\tif (!backendName || typeof backendName !== \"string\") {\n\t\tthrow new Error(\"Backend name must be a non-empty string\");\n\t}\n\n\t// Check for duplicate registration (allow overwriting with warning)\n\tif (ocrBackendRegistry.has(backendName)) {\n\t\tconsole.warn(`OCR backend \"${backendName}\" is already registered and will be replaced`);\n\t}\n\n\t// Register the backend\n\tocrBackendRegistry.set(backendName, backend);\n}\n\n/**\n * Get a registered OCR backend by name\n *\n * @param name - Backend name\n * @returns The OCR backend or undefined if not found\n *\n * @example\n * ```typescript\n * import { getOcrBackend } from '@kreuzberg/wasm/ocr/registry';\n *\n * const backend = getOcrBackend('tesseract-wasm');\n * if (backend) {\n * console.log('Available languages:', backend.supportedLanguages());\n * }\n * ```\n */\nexport function getOcrBackend(name: string): OcrBackendProtocol | undefined {\n\treturn ocrBackendRegistry.get(name);\n}\n\n/**\n * List all registered OCR backends\n *\n * @returns Array of registered backend names\n *\n * @example\n * ```typescript\n * import { listOcrBackends } from '@kreuzberg/wasm/ocr/registry';\n *\n * const backends = listOcrBackends();\n * console.log('Available OCR backends:', backends);\n * ```\n */\nexport function listOcrBackends(): string[] {\n\treturn Array.from(ocrBackendRegistry.keys());\n}\n\n/**\n * Unregister an OCR backend\n *\n * @param name - Backend name to unregister\n * @throws {Error} If backend is not found\n *\n * @example\n * ```typescript\n * import { unregisterOcrBackend } from '@kreuzberg/wasm/ocr/registry';\n *\n * unregisterOcrBackend('tesseract-wasm');\n * ```\n */\nexport async function unregisterOcrBackend(name: string): Promise<void> {\n\tconst backend = ocrBackendRegistry.get(name);\n\n\tif (!backend) {\n\t\tthrow new Error(\n\t\t\t`OCR backend \"${name}\" is not registered. Available backends: ${Array.from(ocrBackendRegistry.keys()).join(\", \")}`,\n\t\t);\n\t}\n\n\t// Call shutdown if available\n\tif (typeof backend.shutdown === \"function\") {\n\t\ttry {\n\t\t\tawait backend.shutdown();\n\t\t} catch (error) {\n\t\t\tconsole.warn(\n\t\t\t\t`Error shutting down OCR backend \"${name}\": ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t);\n\t\t}\n\t}\n\n\tocrBackendRegistry.delete(name);\n}\n\n/**\n * Clear all registered OCR backends\n *\n * Unregisters all OCR backends and calls their shutdown methods.\n *\n * @example\n * ```typescript\n * import { clearOcrBackends } from '@kreuzberg/wasm/ocr/registry';\n *\n * // Clean up all backends when shutting down\n * await clearOcrBackends();\n * ```\n */\nexport async function clearOcrBackends(): Promise<void> {\n\tconst backends = Array.from(ocrBackendRegistry.entries());\n\n\tfor (const [name, backend] of backends) {\n\t\tif (typeof backend.shutdown === \"function\") {\n\t\t\ttry {\n\t\t\t\tawait backend.shutdown();\n\t\t\t} catch (error) {\n\t\t\t\tconsole.warn(\n\t\t\t\t\t`Error shutting down OCR backend \"${name}\": ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\tocrBackendRegistry.clear();\n}\n"],"mappings":";AAsBA,IAAM,qBAAqB,oBAAI,IAAgC;AAqBxD,SAAS,mBAAmB,SAAmC;AAErE,MAAI,CAAC,SAAS;AACb,UAAM,IAAI,MAAM,qCAAqC;AAAA,EACtD;AAEA,MAAI,OAAO,QAAQ,SAAS,YAAY;AACvC,UAAM,IAAI,MAAM,sCAAsC;AAAA,EACvD;AAEA,MAAI,OAAO,QAAQ,uBAAuB,YAAY;AACrD,UAAM,IAAI,MAAM,oDAAoD;AAAA,EACrE;AAEA,MAAI,OAAO,QAAQ,iBAAiB,YAAY;AAC/C,UAAM,IAAI,MAAM,8CAA8C;AAAA,EAC/D;AAEA,QAAM,cAAc,QAAQ,KAAK;AAEjC,MAAI,CAAC,eAAe,OAAO,gBAAgB,UAAU;AACpD,UAAM,IAAI,MAAM,yCAAyC;AAAA,EAC1D;AAGA,MAAI,mBAAmB,IAAI,WAAW,GAAG;AACxC,YAAQ,KAAK,gBAAgB,WAAW,8CAA8C;AAAA,EACvF;AAGA,qBAAmB,IAAI,aAAa,OAAO;AAC5C;AAkBO,SAAS,cAAc,MAA8C;AAC3E,SAAO,mBAAmB,IAAI,IAAI;AACnC;AAeO,SAAS,kBAA4B;AAC3C,SAAO,MAAM,KAAK,mBAAmB,KAAK,CAAC;AAC5C;AAeA,eAAsB,qBAAqB,MAA6B;AACvE,QAAM,UAAU,mBAAmB,IAAI,IAAI;AAE3C,MAAI,CAAC,SAAS;AACb,UAAM,IAAI;AAAA,MACT,gBAAgB,IAAI,4CAA4C,MAAM,KAAK,mBAAmB,KAAK,CAAC,EAAE,KAAK,IAAI,CAAC;AAAA,IACjH;AAAA,EACD;AAGA,MAAI,OAAO,QAAQ,aAAa,YAAY;AAC3C,QAAI;AACH,YAAM,QAAQ,SAAS;AAAA,IACxB,SAAS,OAAO;AACf,cAAQ;AAAA,QACP,oCAAoC,IAAI,MAAM,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AAAA,MACrG;AAAA,IACD;AAAA,EACD;AAEA,qBAAmB,OAAO,IAAI;AAC/B;AAeA,eAAsB,mBAAkC;AACvD,QAAM,WAAW,MAAM,KAAK,mBAAmB,QAAQ,CAAC;AAExD,aAAW,CAAC,MAAM,OAAO,KAAK,UAAU;AACvC,QAAI,OAAO,QAAQ,aAAa,YAAY;AAC3C,UAAI;AACH,cAAM,QAAQ,SAAS;AAAA,MACxB,SAAS,OAAO;AACf,gBAAQ;AAAA,UACP,oCAAoC,IAAI,MAAM,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AAAA,QACrG;AAAA,MACD;AAAA,IACD;AAAA,EACD;AAEA,qBAAmB,MAAM;AAC1B;","names":[]}
1
+ {"version":3,"sources":["../../typescript/ocr/registry.ts"],"sourcesContent":["/**\n * OCR Backend Registry\n *\n * Provides a registry for OCR backends in the WASM environment.\n * This enables auto-registration and management of OCR backends.\n *\n * Note: The WASM package provides a lightweight registry in the browser.\n * For more advanced features like Rust integration, use @kreuzberg/node or @kreuzberg/deno.\n *\n * @example\n * ```typescript\n * import { TesseractWasmBackend } from '@kreuzberg/wasm/ocr/tesseract-wasm-backend';\n * import { enableOcr } from '@kreuzberg/wasm';\n *\n * // Simple auto-registration\n * await enableOcr();\n * ```\n */\n\nimport type { OcrBackendProtocol } from \"../types.js\";\n\n/** Global registry of OCR backends */\nconst ocrBackendRegistry = new Map<string, OcrBackendProtocol>();\n\n/**\n * Register an OCR backend\n *\n * Registers an OCR backend with the WASM extraction pipeline.\n * If a backend with the same name is already registered, it will be replaced.\n *\n * @param backend - OCR backend implementing OcrBackendProtocol\n * @throws {Error} If backend validation fails\n *\n * @example\n * ```typescript\n * import { TesseractWasmBackend } from '@kreuzberg/wasm/ocr/tesseract-wasm-backend';\n * import { registerOcrBackend } from '@kreuzberg/wasm/ocr/registry';\n *\n * const backend = new TesseractWasmBackend();\n * await backend.initialize();\n * registerOcrBackend(backend);\n * ```\n */\nexport function registerOcrBackend(backend: OcrBackendProtocol): void {\n\tif (!backend) {\n\t\tthrow new Error(\"Backend cannot be null or undefined\");\n\t}\n\n\tif (typeof backend.name !== \"function\") {\n\t\tthrow new Error(\"Backend must implement name() method\");\n\t}\n\n\tif (typeof backend.supportedLanguages !== \"function\") {\n\t\tthrow new Error(\"Backend must implement supportedLanguages() method\");\n\t}\n\n\tif (typeof backend.processImage !== \"function\") {\n\t\tthrow new Error(\"Backend must implement processImage() method\");\n\t}\n\n\tconst backendName = backend.name();\n\n\tif (!backendName || typeof backendName !== \"string\") {\n\t\tthrow new Error(\"Backend name must be a non-empty string\");\n\t}\n\n\tif (ocrBackendRegistry.has(backendName)) {\n\t\tconsole.warn(`OCR backend \"${backendName}\" is already registered and will be replaced`);\n\t}\n\n\tocrBackendRegistry.set(backendName, backend);\n}\n\n/**\n * Get a registered OCR backend by name\n *\n * @param name - Backend name\n * @returns The OCR backend or undefined if not found\n *\n * @example\n * ```typescript\n * import { getOcrBackend } from '@kreuzberg/wasm/ocr/registry';\n *\n * const backend = getOcrBackend('tesseract-wasm');\n * if (backend) {\n * console.log('Available languages:', backend.supportedLanguages());\n * }\n * ```\n */\nexport function getOcrBackend(name: string): OcrBackendProtocol | undefined {\n\treturn ocrBackendRegistry.get(name);\n}\n\n/**\n * List all registered OCR backends\n *\n * @returns Array of registered backend names\n *\n * @example\n * ```typescript\n * import { listOcrBackends } from '@kreuzberg/wasm/ocr/registry';\n *\n * const backends = listOcrBackends();\n * console.log('Available OCR backends:', backends);\n * ```\n */\nexport function listOcrBackends(): string[] {\n\treturn Array.from(ocrBackendRegistry.keys());\n}\n\n/**\n * Unregister an OCR backend\n *\n * @param name - Backend name to unregister\n * @throws {Error} If backend is not found\n *\n * @example\n * ```typescript\n * import { unregisterOcrBackend } from '@kreuzberg/wasm/ocr/registry';\n *\n * unregisterOcrBackend('tesseract-wasm');\n * ```\n */\nexport async function unregisterOcrBackend(name: string): Promise<void> {\n\tconst backend = ocrBackendRegistry.get(name);\n\n\tif (!backend) {\n\t\tthrow new Error(\n\t\t\t`OCR backend \"${name}\" is not registered. Available backends: ${Array.from(ocrBackendRegistry.keys()).join(\", \")}`,\n\t\t);\n\t}\n\n\tif (typeof backend.shutdown === \"function\") {\n\t\ttry {\n\t\t\tawait backend.shutdown();\n\t\t} catch (error) {\n\t\t\tconsole.warn(\n\t\t\t\t`Error shutting down OCR backend \"${name}\": ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t);\n\t\t}\n\t}\n\n\tocrBackendRegistry.delete(name);\n}\n\n/**\n * Clear all registered OCR backends\n *\n * Unregisters all OCR backends and calls their shutdown methods.\n *\n * @example\n * ```typescript\n * import { clearOcrBackends } from '@kreuzberg/wasm/ocr/registry';\n *\n * // Clean up all backends when shutting down\n * await clearOcrBackends();\n * ```\n */\nexport async function clearOcrBackends(): Promise<void> {\n\tconst backends = Array.from(ocrBackendRegistry.entries());\n\n\tfor (const [name, backend] of backends) {\n\t\tif (typeof backend.shutdown === \"function\") {\n\t\t\ttry {\n\t\t\t\tawait backend.shutdown();\n\t\t\t} catch (error) {\n\t\t\t\tconsole.warn(\n\t\t\t\t\t`Error shutting down OCR backend \"${name}\": ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\n\tocrBackendRegistry.clear();\n}\n"],"mappings":";AAsBA,IAAM,qBAAqB,oBAAI,IAAgC;AAqBxD,SAAS,mBAAmB,SAAmC;AACrE,MAAI,CAAC,SAAS;AACb,UAAM,IAAI,MAAM,qCAAqC;AAAA,EACtD;AAEA,MAAI,OAAO,QAAQ,SAAS,YAAY;AACvC,UAAM,IAAI,MAAM,sCAAsC;AAAA,EACvD;AAEA,MAAI,OAAO,QAAQ,uBAAuB,YAAY;AACrD,UAAM,IAAI,MAAM,oDAAoD;AAAA,EACrE;AAEA,MAAI,OAAO,QAAQ,iBAAiB,YAAY;AAC/C,UAAM,IAAI,MAAM,8CAA8C;AAAA,EAC/D;AAEA,QAAM,cAAc,QAAQ,KAAK;AAEjC,MAAI,CAAC,eAAe,OAAO,gBAAgB,UAAU;AACpD,UAAM,IAAI,MAAM,yCAAyC;AAAA,EAC1D;AAEA,MAAI,mBAAmB,IAAI,WAAW,GAAG;AACxC,YAAQ,KAAK,gBAAgB,WAAW,8CAA8C;AAAA,EACvF;AAEA,qBAAmB,IAAI,aAAa,OAAO;AAC5C;AAkBO,SAAS,cAAc,MAA8C;AAC3E,SAAO,mBAAmB,IAAI,IAAI;AACnC;AAeO,SAAS,kBAA4B;AAC3C,SAAO,MAAM,KAAK,mBAAmB,KAAK,CAAC;AAC5C;AAeA,eAAsB,qBAAqB,MAA6B;AACvE,QAAM,UAAU,mBAAmB,IAAI,IAAI;AAE3C,MAAI,CAAC,SAAS;AACb,UAAM,IAAI;AAAA,MACT,gBAAgB,IAAI,4CAA4C,MAAM,KAAK,mBAAmB,KAAK,CAAC,EAAE,KAAK,IAAI,CAAC;AAAA,IACjH;AAAA,EACD;AAEA,MAAI,OAAO,QAAQ,aAAa,YAAY;AAC3C,QAAI;AACH,YAAM,QAAQ,SAAS;AAAA,IACxB,SAAS,OAAO;AACf,cAAQ;AAAA,QACP,oCAAoC,IAAI,MAAM,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AAAA,MACrG;AAAA,IACD;AAAA,EACD;AAEA,qBAAmB,OAAO,IAAI;AAC/B;AAeA,eAAsB,mBAAkC;AACvD,QAAM,WAAW,MAAM,KAAK,mBAAmB,QAAQ,CAAC;AAExD,aAAW,CAAC,MAAM,OAAO,KAAK,UAAU;AACvC,QAAI,OAAO,QAAQ,aAAa,YAAY;AAC3C,UAAI;AACH,cAAM,QAAQ,SAAS;AAAA,MACxB,SAAS,OAAO;AACf,gBAAQ;AAAA,UACP,oCAAoC,IAAI,MAAM,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AAAA,QACrG;AAAA,MACD;AAAA,IACD;AAAA,EACD;AAEA,qBAAmB,MAAM;AAC1B;","names":[]}
@@ -65,93 +65,48 @@ var TesseractWasmBackend = class {
65
65
  return this.supportedLangsCache;
66
66
  }
67
67
  this.supportedLangsCache = [
68
- // Major languages
69
68
  "eng",
70
- // English
71
69
  "deu",
72
- // German
73
70
  "fra",
74
- // French
75
71
  "spa",
76
- // Spanish
77
72
  "ita",
78
- // Italian
79
73
  "por",
80
- // Portuguese
81
74
  "nld",
82
- // Dutch
83
75
  "rus",
84
- // Russian
85
76
  "jpn",
86
- // Japanese
87
77
  "kor",
88
- // Korean
89
78
  "chi_sim",
90
- // Chinese (Simplified)
91
79
  "chi_tra",
92
- // Chinese (Traditional)
93
- // Additional European languages
94
80
  "pol",
95
- // Polish
96
81
  "tur",
97
- // Turkish
98
82
  "swe",
99
- // Swedish
100
83
  "dan",
101
- // Danish
102
84
  "fin",
103
- // Finnish
104
85
  "nor",
105
- // Norwegian
106
86
  "ces",
107
- // Czech
108
87
  "slk",
109
- // Slovak
110
88
  "ron",
111
- // Romanian
112
89
  "hun",
113
- // Hungarian
114
90
  "hrv",
115
- // Croatian
116
91
  "srp",
117
- // Serbian
118
92
  "bul",
119
- // Bulgarian
120
93
  "ukr",
121
- // Ukrainian
122
94
  "ell",
123
- // Greek
124
- // Asian languages
125
95
  "ara",
126
- // Arabic
127
96
  "heb",
128
- // Hebrew
129
97
  "hin",
130
- // Hindi
131
98
  "tha",
132
- // Thai
133
99
  "vie",
134
- // Vietnamese
135
100
  "mkd",
136
- // Macedonian
137
101
  "ben",
138
- // Bengali
139
102
  "tam",
140
- // Tamil
141
103
  "tel",
142
- // Telugu
143
104
  "kan",
144
- // Kannada
145
105
  "mal",
146
- // Malayalam
147
106
  "mya",
148
- // Burmese
149
107
  "khm",
150
- // Khmer
151
108
  "lao",
152
- // Lao
153
109
  "sin"
154
- // Sinhala
155
110
  ];
156
111
  return this.supportedLangsCache;
157
112
  }
@@ -253,7 +208,6 @@ var TesseractWasmBackend = class {
253
208
  ...pageMetadata
254
209
  },
255
210
  tables: []
256
- // Tesseract-wasm doesn't provide structured table detection
257
211
  };
258
212
  } catch (error) {
259
213
  const message = error instanceof Error ? error.message : String(error);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../typescript/ocr/tesseract-wasm-backend.ts"],"sourcesContent":["/**\n * Tesseract WASM OCR Backend\n *\n * Provides OCR capabilities using tesseract-wasm library for browser environments.\n * Loads training data on-demand from jsDelivr CDN and implements the OcrBackendProtocol.\n *\n * ## Browser-Only Requirement\n *\n * This backend requires browser APIs like createImageBitmap and Web Workers.\n * It will NOT work in Node.js environments without additional canvas polyfills.\n *\n * ## Supported Languages\n *\n * Common ISO 639-1 and ISO 639-2 codes:\n * - English: \"eng\"\n * - German: \"deu\"\n * - French: \"fra\"\n * - Spanish: \"spa\"\n * - Italian: \"ita\"\n * - Portuguese: \"por\"\n * - Dutch: \"nld\"\n * - Russian: \"rus\"\n * - Chinese (Simplified): \"chi_sim\"\n * - Chinese (Traditional): \"chi_tra\"\n * - Japanese: \"jpn\"\n * - Korean: \"kor\"\n * - Arabic: \"ara\"\n * - Hindi: \"hin\"\n *\n * For complete language list, see: https://github.com/naptha/tesseract.js\n *\n * @example Basic Usage\n * ```typescript\n * import { TesseractWasmBackend } from '@kreuzberg/wasm/ocr/tesseract-wasm-backend';\n * import { registerOcrBackend, extractBytes, initWasm } from '@kreuzberg/wasm';\n *\n * // Initialize\n * await initWasm();\n * const backend = new TesseractWasmBackend();\n * await backend.initialize();\n * registerOcrBackend(backend);\n *\n * // Use in extraction\n * const imageBytes = new Uint8Array(buffer);\n * const result = await extractBytes(imageBytes, 'image/png', {\n * ocr: { backend: 'tesseract-wasm', language: 'eng' }\n * });\n * console.log(result.content); // Extracted text\n * ```\n *\n * @example With Language Auto-Detection\n * ```typescript\n * const backend = new TesseractWasmBackend();\n * await backend.initialize();\n * registerOcrBackend(backend);\n *\n * // Extract without specifying language - backend will auto-detect\n * const result = await extractBytes(imageBytes, 'image/png', {\n * ocr: { backend: 'tesseract-wasm' } // language will auto-detect\n * });\n * ```\n */\n\nimport type { OcrBackendProtocol } from \"../types.js\";\n\n/**\n * Tesseract WASM Client interface\n * Type definition for tesseract-wasm's OCRClient class\n */\ninterface TesseractClient {\n\tloadModel(modelPath: string): Promise<void>;\n\tloadImage(image: ImageBitmap | Blob): Promise<void>;\n\tgetText(): Promise<string>;\n\tgetConfidence(): Promise<number>;\n\tgetPageMetadata(): Promise<Record<string, unknown>>;\n\tdestroy(): void;\n\tterminate(): void;\n}\n\n/**\n * TesseractWasmBackend - OCR backend using tesseract-wasm library\n *\n * Implements the OcrBackendProtocol for Kreuzberg document extraction pipeline.\n * Provides comprehensive OCR support with model caching, error handling, and progress reporting.\n */\nexport class TesseractWasmBackend implements OcrBackendProtocol {\n\t/** Tesseract WASM client instance */\n\tprivate client: TesseractClient | null = null;\n\n\t/** Track which models are currently loaded to avoid redundant loads */\n\tprivate loadedLanguages: Set<string> = new Set();\n\n\t/** Cache for language availability validation */\n\tprivate supportedLangsCache: string[] | null = null;\n\n\t/** Progress callback for UI updates */\n\tprivate progressCallback: ((progress: number) => void) | null = null;\n\n\t/** Base URL for training data CDN */\n\tprivate readonly CDN_BASE_URL = \"https://cdn.jsdelivr.net/npm/tesseract-wasm@0.11.0/dist\";\n\n\t/**\n\t * Return the unique name of this OCR backend\n\t *\n\t * @returns Backend identifier \"tesseract-wasm\"\n\t */\n\tname(): string {\n\t\treturn \"tesseract-wasm\";\n\t}\n\n\t/**\n\t * Return list of supported language codes\n\t *\n\t * Returns a curated list of commonly available Tesseract language models.\n\t * Tesseract supports many more languages through custom models.\n\t *\n\t * @returns Array of ISO 639-1/2/3 language codes\n\t */\n\tsupportedLanguages(): string[] {\n\t\t// Return cached list if already computed\n\t\tif (this.supportedLangsCache) {\n\t\t\treturn this.supportedLangsCache;\n\t\t}\n\n\t\t// Comprehensive list of languages supported by tesseract-wasm\n\t\t// Includes both 3-letter (ISO 639-2) and 2-letter (ISO 639-1) codes where applicable\n\t\tthis.supportedLangsCache = [\n\t\t\t// Major languages\n\t\t\t\"eng\", // English\n\t\t\t\"deu\", // German\n\t\t\t\"fra\", // French\n\t\t\t\"spa\", // Spanish\n\t\t\t\"ita\", // Italian\n\t\t\t\"por\", // Portuguese\n\t\t\t\"nld\", // Dutch\n\t\t\t\"rus\", // Russian\n\t\t\t\"jpn\", // Japanese\n\t\t\t\"kor\", // Korean\n\t\t\t\"chi_sim\", // Chinese (Simplified)\n\t\t\t\"chi_tra\", // Chinese (Traditional)\n\n\t\t\t// Additional European languages\n\t\t\t\"pol\", // Polish\n\t\t\t\"tur\", // Turkish\n\t\t\t\"swe\", // Swedish\n\t\t\t\"dan\", // Danish\n\t\t\t\"fin\", // Finnish\n\t\t\t\"nor\", // Norwegian\n\t\t\t\"ces\", // Czech\n\t\t\t\"slk\", // Slovak\n\t\t\t\"ron\", // Romanian\n\t\t\t\"hun\", // Hungarian\n\t\t\t\"hrv\", // Croatian\n\t\t\t\"srp\", // Serbian\n\t\t\t\"bul\", // Bulgarian\n\t\t\t\"ukr\", // Ukrainian\n\t\t\t\"ell\", // Greek\n\n\t\t\t// Asian languages\n\t\t\t\"ara\", // Arabic\n\t\t\t\"heb\", // Hebrew\n\t\t\t\"hin\", // Hindi\n\t\t\t\"tha\", // Thai\n\t\t\t\"vie\", // Vietnamese\n\t\t\t\"mkd\", // Macedonian\n\t\t\t\"ben\", // Bengali\n\t\t\t\"tam\", // Tamil\n\t\t\t\"tel\", // Telugu\n\t\t\t\"kan\", // Kannada\n\t\t\t\"mal\", // Malayalam\n\t\t\t\"mya\", // Burmese\n\t\t\t\"khm\", // Khmer\n\t\t\t\"lao\", // Lao\n\t\t\t\"sin\", // Sinhala\n\t\t];\n\n\t\treturn this.supportedLangsCache;\n\t}\n\n\t/**\n\t * Initialize the OCR backend\n\t *\n\t * Creates the Tesseract WASM client instance. This is called once when\n\t * the backend is registered with the extraction pipeline.\n\t *\n\t * The actual model loading happens in processImage() on-demand to avoid\n\t * loading all models upfront.\n\t *\n\t * @throws {Error} If tesseract-wasm is not available or initialization fails\n\t *\n\t * @example\n\t * ```typescript\n\t * const backend = new TesseractWasmBackend();\n\t * try {\n\t * await backend.initialize();\n\t * } catch (error) {\n\t * console.error('Failed to initialize OCR:', error);\n\t * }\n\t * ```\n\t */\n\tasync initialize(): Promise<void> {\n\t\tif (this.client) {\n\t\t\treturn; // Already initialized\n\t\t}\n\n\t\ttry {\n\t\t\t// Dynamically import tesseract-wasm\n\t\t\tconst tesseractModule = await this.loadTesseractWasm();\n\n\t\t\t// @ts-expect-error - tesseract-wasm types are not fully typed\n\t\t\tif (!tesseractModule || typeof tesseractModule.OCRClient !== \"function\") {\n\t\t\t\tthrow new Error(\"tesseract-wasm OCRClient not found. Ensure tesseract-wasm is installed and available.\");\n\t\t\t}\n\n\t\t\t// Create client instance\n\t\t\t// @ts-expect-error - tesseract-wasm types are not fully typed\n\t\t\tthis.client = new tesseractModule.OCRClient();\n\n\t\t\t// Initialize tracking\n\t\t\tthis.loadedLanguages.clear();\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tthrow new Error(`Failed to initialize TesseractWasmBackend: ${message}`);\n\t\t}\n\t}\n\n\t/**\n\t * Process image bytes and extract text via OCR\n\t *\n\t * Handles image loading, model loading, OCR processing, and result formatting.\n\t * Automatically loads the language model on first use and caches it for subsequent calls.\n\t *\n\t * @param imageBytes - Raw image data (Uint8Array) or Base64-encoded string\n\t * @param language - ISO 639-2/3 language code (e.g., \"eng\", \"deu\")\n\t * @returns Promise resolving to OCR result with content and metadata\n\t * @throws {Error} If image processing fails, model loading fails, or language is unsupported\n\t *\n\t * @example\n\t * ```typescript\n\t * const backend = new TesseractWasmBackend();\n\t * await backend.initialize();\n\t *\n\t * const imageBuffer = fs.readFileSync('scanned.png');\n\t * const result = await backend.processImage(\n\t * new Uint8Array(imageBuffer),\n\t * 'eng'\n\t * );\n\t *\n\t * console.log(result.content); // Extracted text\n\t * console.log(result.metadata.confidence); // OCR confidence score\n\t * ```\n\t */\n\tasync processImage(\n\t\timageBytes: Uint8Array | string,\n\t\tlanguage: string,\n\t): Promise<{\n\t\tcontent: string;\n\t\tmime_type: string;\n\t\tmetadata: Record<string, unknown>;\n\t\ttables: unknown[];\n\t}> {\n\t\tif (!this.client) {\n\t\t\tthrow new Error(\"TesseractWasmBackend not initialized. Call initialize() first.\");\n\t\t}\n\n\t\t// Validate language support\n\t\tconst supported = this.supportedLanguages();\n\t\t// Normalize language code for comparison\n\t\tconst normalizedLang = language.toLowerCase();\n\t\tconst isSupported = supported.some((lang) => lang.toLowerCase() === normalizedLang);\n\n\t\tif (!isSupported) {\n\t\t\tthrow new Error(`Language \"${language}\" is not supported. Supported languages: ${supported.join(\", \")}`);\n\t\t}\n\n\t\ttry {\n\t\t\t// Load language model if not already loaded\n\t\t\tif (!this.loadedLanguages.has(normalizedLang)) {\n\t\t\t\tthis.reportProgress(10); // Progress: loading model\n\t\t\t\tawait this.loadLanguageModel(normalizedLang);\n\t\t\t\tthis.loadedLanguages.add(normalizedLang);\n\t\t\t\tthis.reportProgress(30); // Progress: model loaded\n\t\t\t}\n\n\t\t\t// Convert image bytes to ImageBitmap\n\t\t\tthis.reportProgress(40); // Progress: processing image\n\t\t\tconst imageBitmap = await this.convertToImageBitmap(imageBytes);\n\n\t\t\t// Load image into Tesseract\n\t\t\tthis.reportProgress(50); // Progress: loading image\n\t\t\tawait this.client.loadImage(imageBitmap);\n\n\t\t\t// Perform OCR\n\t\t\tthis.reportProgress(70); // Progress: performing OCR\n\t\t\tconst text = await this.client.getText();\n\n\t\t\t// Get confidence and metadata\n\t\t\tconst confidence = await this.getConfidenceScore();\n\t\t\tconst pageMetadata = await this.getPageMetadata();\n\n\t\t\tthis.reportProgress(90); // Progress: nearly complete\n\n\t\t\t// Return result in Kreuzberg format\n\t\t\treturn {\n\t\t\t\tcontent: text,\n\t\t\t\tmime_type: \"text/plain\",\n\t\t\t\tmetadata: {\n\t\t\t\t\tlanguage: normalizedLang,\n\t\t\t\t\tconfidence,\n\t\t\t\t\t...pageMetadata,\n\t\t\t\t},\n\t\t\t\ttables: [], // Tesseract-wasm doesn't provide structured table detection\n\t\t\t};\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tthrow new Error(`OCR processing failed for language \"${language}\": ${message}`);\n\t\t} finally {\n\t\t\tthis.reportProgress(100); // Progress: complete\n\t\t}\n\t}\n\n\t/**\n\t * Shutdown the OCR backend and release resources\n\t *\n\t * Properly cleans up the Tesseract WASM client, freeing memory and Web Workers.\n\t * Called when the backend is unregistered or the application shuts down.\n\t *\n\t * @throws {Error} If cleanup fails (errors are logged but not critical)\n\t *\n\t * @example\n\t * ```typescript\n\t * const backend = new TesseractWasmBackend();\n\t * await backend.initialize();\n\t * // ... use backend ...\n\t * await backend.shutdown(); // Clean up resources\n\t * ```\n\t */\n\tasync shutdown(): Promise<void> {\n\t\ttry {\n\t\t\tif (this.client) {\n\t\t\t\t// Try both destroy and terminate for compatibility\n\t\t\t\tif (typeof this.client.destroy === \"function\") {\n\t\t\t\t\tthis.client.destroy();\n\t\t\t\t}\n\t\t\t\tif (typeof this.client.terminate === \"function\") {\n\t\t\t\t\tthis.client.terminate();\n\t\t\t\t}\n\t\t\t\tthis.client = null;\n\t\t\t}\n\n\t\t\t// Clear cached state\n\t\t\tthis.loadedLanguages.clear();\n\t\t\tthis.supportedLangsCache = null;\n\t\t\tthis.progressCallback = null;\n\t\t} catch (error) {\n\t\t\t// Log error but don't throw - shutdown is best-effort\n\t\t\tconsole.warn(\n\t\t\t\t`Warning during TesseractWasmBackend shutdown: ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Set a progress callback for UI updates\n\t *\n\t * Allows the UI to display progress during OCR processing.\n\t * The callback will be called with values from 0 to 100.\n\t *\n\t * @param callback - Function to call with progress percentage\n\t *\n\t * @example\n\t * ```typescript\n\t * const backend = new TesseractWasmBackend();\n\t * backend.setProgressCallback((progress) => {\n\t * console.log(`OCR Progress: ${progress}%`);\n\t * document.getElementById('progress-bar').style.width = `${progress}%`;\n\t * });\n\t * ```\n\t */\n\tsetProgressCallback(callback: (progress: number) => void): void {\n\t\tthis.progressCallback = callback;\n\t}\n\n\t/**\n\t * Load language model from CDN\n\t *\n\t * Fetches the training data for a specific language from jsDelivr CDN.\n\t * This is an MVP approach - models are cached by the browser.\n\t *\n\t * @param language - ISO 639-2/3 language code\n\t * @throws {Error} If model download fails or language is not available\n\t *\n\t * @internal\n\t */\n\tprivate async loadLanguageModel(language: string): Promise<void> {\n\t\tif (!this.client) {\n\t\t\tthrow new Error(\"Client not initialized\");\n\t\t}\n\n\t\t// Construct model URL - models are named with their language code\n\t\tconst modelFilename = `${language}.traineddata`;\n\t\tconst modelUrl = `${this.CDN_BASE_URL}/${modelFilename}`;\n\n\t\ttry {\n\t\t\tawait this.client.loadModel(modelUrl);\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tthrow new Error(`Failed to load model for language \"${language}\" from ${modelUrl}: ${message}`);\n\t\t}\n\t}\n\n\t/**\n\t * Convert image bytes or Base64 string to ImageBitmap\n\t *\n\t * Handles both Uint8Array and Base64-encoded image data, converting to\n\t * ImageBitmap format required by Tesseract WASM.\n\t *\n\t * @param imageBytes - Image data as Uint8Array or Base64 string\n\t * @returns Promise resolving to ImageBitmap\n\t * @throws {Error} If conversion fails (browser API not available or invalid image data)\n\t *\n\t * @internal\n\t */\n\tprivate async convertToImageBitmap(imageBytes: Uint8Array | string): Promise<ImageBitmap> {\n\t\t// Check if createImageBitmap is available (browser only)\n\t\tif (typeof createImageBitmap === \"undefined\") {\n\t\t\tthrow new Error(\"createImageBitmap is not available. TesseractWasmBackend requires a browser environment.\");\n\t\t}\n\n\t\ttry {\n\t\t\t// Convert to Uint8Array if string (Base64)\n\t\t\tlet bytes = imageBytes;\n\t\t\tif (typeof imageBytes === \"string\") {\n\t\t\t\t// Decode Base64 to binary\n\t\t\t\tconst binaryString = atob(imageBytes);\n\t\t\t\tbytes = new Uint8Array(binaryString.length);\n\t\t\t\tfor (let i = 0; i < binaryString.length; i++) {\n\t\t\t\t\t(bytes as Uint8Array)[i] = binaryString.charCodeAt(i);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Create Blob from bytes\n\t\t\tconst blob = new Blob([bytes as Uint8Array] as BlobPart[]);\n\n\t\t\t// Convert Blob to ImageBitmap\n\t\t\tconst imageBitmap = await createImageBitmap(blob);\n\t\t\treturn imageBitmap;\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tthrow new Error(`Failed to convert image bytes to ImageBitmap: ${message}`);\n\t\t}\n\t}\n\n\t/**\n\t * Get confidence score from OCR result\n\t *\n\t * Attempts to retrieve confidence score from Tesseract.\n\t * Returns a safe default if unavailable.\n\t *\n\t * @returns Confidence score between 0 and 1\n\t *\n\t * @internal\n\t */\n\tprivate async getConfidenceScore(): Promise<number> {\n\t\ttry {\n\t\t\tif (this.client && typeof this.client.getConfidence === \"function\") {\n\t\t\t\tconst confidence = await this.client.getConfidence();\n\t\t\t\t// Normalize to 0-1 range if needed (some versions return 0-100)\n\t\t\t\treturn confidence > 1 ? confidence / 100 : confidence;\n\t\t\t}\n\t\t} catch {\n\t\t\t// Silently fail - confidence is optional\n\t\t}\n\t\treturn 0.9; // Default reasonable confidence\n\t}\n\n\t/**\n\t * Get page metadata from OCR result\n\t *\n\t * Retrieves additional metadata like image dimensions and processing info.\n\t *\n\t * @returns Metadata object (may be empty if unavailable)\n\t *\n\t * @internal\n\t */\n\tprivate async getPageMetadata(): Promise<Record<string, unknown>> {\n\t\ttry {\n\t\t\tif (this.client && typeof this.client.getPageMetadata === \"function\") {\n\t\t\t\treturn await this.client.getPageMetadata();\n\t\t\t}\n\t\t} catch {\n\t\t\t// Silently fail - metadata is optional\n\t\t}\n\t\treturn {};\n\t}\n\n\t/**\n\t * Dynamically load tesseract-wasm module\n\t *\n\t * Uses dynamic import to load tesseract-wasm only when needed,\n\t * avoiding hard dependency in browser environments where it may not be bundled.\n\t *\n\t * @returns tesseract-wasm module object\n\t * @throws {Error} If module cannot be imported\n\t *\n\t * @internal\n\t */\n\tprivate async loadTesseractWasm(): Promise<unknown> {\n\t\ttry {\n\t\t\t// Use dynamic import to handle both ESM and CJS\n\t\t\t// @ts-expect-error - tesseract-wasm has package.json exports issues with TypeScript\n\t\t\t// @vite-ignore - tesseract-wasm package resolution\n\t\t\tconst module = await import(\"tesseract-wasm\");\n\t\t\treturn module;\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tthrow new Error(\n\t\t\t\t`Failed to import tesseract-wasm. Ensure it is installed via: npm install tesseract-wasm. Error: ${message}`,\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Report progress to progress callback\n\t *\n\t * Internal helper for notifying progress updates during OCR processing.\n\t *\n\t * @param progress - Progress percentage (0-100)\n\t *\n\t * @internal\n\t */\n\tprivate reportProgress(progress: number): void {\n\t\tif (this.progressCallback) {\n\t\t\ttry {\n\t\t\t\tthis.progressCallback(Math.min(100, Math.max(0, progress)));\n\t\t\t} catch {\n\t\t\t\t// Ignore callback errors to prevent blocking OCR processing\n\t\t\t}\n\t\t}\n\t}\n}\n"],"mappings":"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","names":["module"]}
1
+ {"version":3,"sources":["../../typescript/ocr/tesseract-wasm-backend.ts"],"sourcesContent":["/**\n * Tesseract WASM OCR Backend\n *\n * Provides OCR capabilities using tesseract-wasm library for browser environments.\n * Loads training data on-demand from jsDelivr CDN and implements the OcrBackendProtocol.\n *\n * ## Browser-Only Requirement\n *\n * This backend requires browser APIs like createImageBitmap and Web Workers.\n * It will NOT work in Node.js environments without additional canvas polyfills.\n *\n * ## Supported Languages\n *\n * Common ISO 639-1 and ISO 639-2 codes:\n * - English: \"eng\"\n * - German: \"deu\"\n * - French: \"fra\"\n * - Spanish: \"spa\"\n * - Italian: \"ita\"\n * - Portuguese: \"por\"\n * - Dutch: \"nld\"\n * - Russian: \"rus\"\n * - Chinese (Simplified): \"chi_sim\"\n * - Chinese (Traditional): \"chi_tra\"\n * - Japanese: \"jpn\"\n * - Korean: \"kor\"\n * - Arabic: \"ara\"\n * - Hindi: \"hin\"\n *\n * For complete language list, see: https://github.com/naptha/tesseract.js\n *\n * @example Basic Usage\n * ```typescript\n * import { TesseractWasmBackend } from '@kreuzberg/wasm/ocr/tesseract-wasm-backend';\n * import { registerOcrBackend, extractBytes, initWasm } from '@kreuzberg/wasm';\n *\n * // Initialize\n * await initWasm();\n * const backend = new TesseractWasmBackend();\n * await backend.initialize();\n * registerOcrBackend(backend);\n *\n * // Use in extraction\n * const imageBytes = new Uint8Array(buffer);\n * const result = await extractBytes(imageBytes, 'image/png', {\n * ocr: { backend: 'tesseract-wasm', language: 'eng' }\n * });\n * console.log(result.content); // Extracted text\n * ```\n *\n * @example With Language Auto-Detection\n * ```typescript\n * const backend = new TesseractWasmBackend();\n * await backend.initialize();\n * registerOcrBackend(backend);\n *\n * // Extract without specifying language - backend will auto-detect\n * const result = await extractBytes(imageBytes, 'image/png', {\n * ocr: { backend: 'tesseract-wasm' } // language will auto-detect\n * });\n * ```\n */\n\nimport type { OcrBackendProtocol } from \"../types.js\";\n\n/**\n * Tesseract WASM Client interface\n * Type definition for tesseract-wasm's OCRClient class\n */\ninterface TesseractClient {\n\tloadModel(modelPath: string): Promise<void>;\n\tloadImage(image: ImageBitmap | Blob): Promise<void>;\n\tgetText(): Promise<string>;\n\tgetConfidence(): Promise<number>;\n\tgetPageMetadata(): Promise<Record<string, unknown>>;\n\tdestroy(): void;\n\tterminate(): void;\n}\n\n/**\n * TesseractWasmBackend - OCR backend using tesseract-wasm library\n *\n * Implements the OcrBackendProtocol for Kreuzberg document extraction pipeline.\n * Provides comprehensive OCR support with model caching, error handling, and progress reporting.\n */\nexport class TesseractWasmBackend implements OcrBackendProtocol {\n\t/** Tesseract WASM client instance */\n\tprivate client: TesseractClient | null = null;\n\n\t/** Track which models are currently loaded to avoid redundant loads */\n\tprivate loadedLanguages: Set<string> = new Set();\n\n\t/** Cache for language availability validation */\n\tprivate supportedLangsCache: string[] | null = null;\n\n\t/** Progress callback for UI updates */\n\tprivate progressCallback: ((progress: number) => void) | null = null;\n\n\t/** Base URL for training data CDN */\n\tprivate readonly CDN_BASE_URL = \"https://cdn.jsdelivr.net/npm/tesseract-wasm@0.11.0/dist\";\n\n\t/**\n\t * Return the unique name of this OCR backend\n\t *\n\t * @returns Backend identifier \"tesseract-wasm\"\n\t */\n\tname(): string {\n\t\treturn \"tesseract-wasm\";\n\t}\n\n\t/**\n\t * Return list of supported language codes\n\t *\n\t * Returns a curated list of commonly available Tesseract language models.\n\t * Tesseract supports many more languages through custom models.\n\t *\n\t * @returns Array of ISO 639-1/2/3 language codes\n\t */\n\tsupportedLanguages(): string[] {\n\t\tif (this.supportedLangsCache) {\n\t\t\treturn this.supportedLangsCache;\n\t\t}\n\n\t\tthis.supportedLangsCache = [\n\t\t\t\"eng\",\n\t\t\t\"deu\",\n\t\t\t\"fra\",\n\t\t\t\"spa\",\n\t\t\t\"ita\",\n\t\t\t\"por\",\n\t\t\t\"nld\",\n\t\t\t\"rus\",\n\t\t\t\"jpn\",\n\t\t\t\"kor\",\n\t\t\t\"chi_sim\",\n\t\t\t\"chi_tra\",\n\n\t\t\t\"pol\",\n\t\t\t\"tur\",\n\t\t\t\"swe\",\n\t\t\t\"dan\",\n\t\t\t\"fin\",\n\t\t\t\"nor\",\n\t\t\t\"ces\",\n\t\t\t\"slk\",\n\t\t\t\"ron\",\n\t\t\t\"hun\",\n\t\t\t\"hrv\",\n\t\t\t\"srp\",\n\t\t\t\"bul\",\n\t\t\t\"ukr\",\n\t\t\t\"ell\",\n\n\t\t\t\"ara\",\n\t\t\t\"heb\",\n\t\t\t\"hin\",\n\t\t\t\"tha\",\n\t\t\t\"vie\",\n\t\t\t\"mkd\",\n\t\t\t\"ben\",\n\t\t\t\"tam\",\n\t\t\t\"tel\",\n\t\t\t\"kan\",\n\t\t\t\"mal\",\n\t\t\t\"mya\",\n\t\t\t\"khm\",\n\t\t\t\"lao\",\n\t\t\t\"sin\",\n\t\t];\n\n\t\treturn this.supportedLangsCache;\n\t}\n\n\t/**\n\t * Initialize the OCR backend\n\t *\n\t * Creates the Tesseract WASM client instance. This is called once when\n\t * the backend is registered with the extraction pipeline.\n\t *\n\t * The actual model loading happens in processImage() on-demand to avoid\n\t * loading all models upfront.\n\t *\n\t * @throws {Error} If tesseract-wasm is not available or initialization fails\n\t *\n\t * @example\n\t * ```typescript\n\t * const backend = new TesseractWasmBackend();\n\t * try {\n\t * await backend.initialize();\n\t * } catch (error) {\n\t * console.error('Failed to initialize OCR:', error);\n\t * }\n\t * ```\n\t */\n\tasync initialize(): Promise<void> {\n\t\tif (this.client) {\n\t\t\treturn;\n\t\t}\n\n\t\ttry {\n\t\t\tconst tesseractModule = await this.loadTesseractWasm();\n\n\t\t\t// @ts-expect-error - tesseract-wasm types are not fully typed\n\t\t\tif (!tesseractModule || typeof tesseractModule.OCRClient !== \"function\") {\n\t\t\t\tthrow new Error(\"tesseract-wasm OCRClient not found. Ensure tesseract-wasm is installed and available.\");\n\t\t\t}\n\n\t\t\t// @ts-expect-error - tesseract-wasm types are not fully typed\n\t\t\tthis.client = new tesseractModule.OCRClient();\n\n\t\t\tthis.loadedLanguages.clear();\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tthrow new Error(`Failed to initialize TesseractWasmBackend: ${message}`);\n\t\t}\n\t}\n\n\t/**\n\t * Process image bytes and extract text via OCR\n\t *\n\t * Handles image loading, model loading, OCR processing, and result formatting.\n\t * Automatically loads the language model on first use and caches it for subsequent calls.\n\t *\n\t * @param imageBytes - Raw image data (Uint8Array) or Base64-encoded string\n\t * @param language - ISO 639-2/3 language code (e.g., \"eng\", \"deu\")\n\t * @returns Promise resolving to OCR result with content and metadata\n\t * @throws {Error} If image processing fails, model loading fails, or language is unsupported\n\t *\n\t * @example\n\t * ```typescript\n\t * const backend = new TesseractWasmBackend();\n\t * await backend.initialize();\n\t *\n\t * const imageBuffer = fs.readFileSync('scanned.png');\n\t * const result = await backend.processImage(\n\t * new Uint8Array(imageBuffer),\n\t * 'eng'\n\t * );\n\t *\n\t * console.log(result.content); // Extracted text\n\t * console.log(result.metadata.confidence); // OCR confidence score\n\t * ```\n\t */\n\tasync processImage(\n\t\timageBytes: Uint8Array | string,\n\t\tlanguage: string,\n\t): Promise<{\n\t\tcontent: string;\n\t\tmime_type: string;\n\t\tmetadata: Record<string, unknown>;\n\t\ttables: unknown[];\n\t}> {\n\t\tif (!this.client) {\n\t\t\tthrow new Error(\"TesseractWasmBackend not initialized. Call initialize() first.\");\n\t\t}\n\n\t\tconst supported = this.supportedLanguages();\n\t\tconst normalizedLang = language.toLowerCase();\n\t\tconst isSupported = supported.some((lang) => lang.toLowerCase() === normalizedLang);\n\n\t\tif (!isSupported) {\n\t\t\tthrow new Error(`Language \"${language}\" is not supported. Supported languages: ${supported.join(\", \")}`);\n\t\t}\n\n\t\ttry {\n\t\t\tif (!this.loadedLanguages.has(normalizedLang)) {\n\t\t\t\tthis.reportProgress(10);\n\t\t\t\tawait this.loadLanguageModel(normalizedLang);\n\t\t\t\tthis.loadedLanguages.add(normalizedLang);\n\t\t\t\tthis.reportProgress(30);\n\t\t\t}\n\n\t\t\tthis.reportProgress(40);\n\t\t\tconst imageBitmap = await this.convertToImageBitmap(imageBytes);\n\n\t\t\tthis.reportProgress(50);\n\t\t\tawait this.client.loadImage(imageBitmap);\n\n\t\t\tthis.reportProgress(70);\n\t\t\tconst text = await this.client.getText();\n\n\t\t\tconst confidence = await this.getConfidenceScore();\n\t\t\tconst pageMetadata = await this.getPageMetadata();\n\n\t\t\tthis.reportProgress(90);\n\n\t\t\treturn {\n\t\t\t\tcontent: text,\n\t\t\t\tmime_type: \"text/plain\",\n\t\t\t\tmetadata: {\n\t\t\t\t\tlanguage: normalizedLang,\n\t\t\t\t\tconfidence,\n\t\t\t\t\t...pageMetadata,\n\t\t\t\t},\n\t\t\t\ttables: [],\n\t\t\t};\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tthrow new Error(`OCR processing failed for language \"${language}\": ${message}`);\n\t\t} finally {\n\t\t\tthis.reportProgress(100);\n\t\t}\n\t}\n\n\t/**\n\t * Shutdown the OCR backend and release resources\n\t *\n\t * Properly cleans up the Tesseract WASM client, freeing memory and Web Workers.\n\t * Called when the backend is unregistered or the application shuts down.\n\t *\n\t * @throws {Error} If cleanup fails (errors are logged but not critical)\n\t *\n\t * @example\n\t * ```typescript\n\t * const backend = new TesseractWasmBackend();\n\t * await backend.initialize();\n\t * // ... use backend ...\n\t * await backend.shutdown(); // Clean up resources\n\t * ```\n\t */\n\tasync shutdown(): Promise<void> {\n\t\ttry {\n\t\t\tif (this.client) {\n\t\t\t\tif (typeof this.client.destroy === \"function\") {\n\t\t\t\t\tthis.client.destroy();\n\t\t\t\t}\n\t\t\t\tif (typeof this.client.terminate === \"function\") {\n\t\t\t\t\tthis.client.terminate();\n\t\t\t\t}\n\t\t\t\tthis.client = null;\n\t\t\t}\n\n\t\t\tthis.loadedLanguages.clear();\n\t\t\tthis.supportedLangsCache = null;\n\t\t\tthis.progressCallback = null;\n\t\t} catch (error) {\n\t\t\tconsole.warn(\n\t\t\t\t`Warning during TesseractWasmBackend shutdown: ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Set a progress callback for UI updates\n\t *\n\t * Allows the UI to display progress during OCR processing.\n\t * The callback will be called with values from 0 to 100.\n\t *\n\t * @param callback - Function to call with progress percentage\n\t *\n\t * @example\n\t * ```typescript\n\t * const backend = new TesseractWasmBackend();\n\t * backend.setProgressCallback((progress) => {\n\t * console.log(`OCR Progress: ${progress}%`);\n\t * document.getElementById('progress-bar').style.width = `${progress}%`;\n\t * });\n\t * ```\n\t */\n\tsetProgressCallback(callback: (progress: number) => void): void {\n\t\tthis.progressCallback = callback;\n\t}\n\n\t/**\n\t * Load language model from CDN\n\t *\n\t * Fetches the training data for a specific language from jsDelivr CDN.\n\t * This is an MVP approach - models are cached by the browser.\n\t *\n\t * @param language - ISO 639-2/3 language code\n\t * @throws {Error} If model download fails or language is not available\n\t *\n\t * @internal\n\t */\n\tprivate async loadLanguageModel(language: string): Promise<void> {\n\t\tif (!this.client) {\n\t\t\tthrow new Error(\"Client not initialized\");\n\t\t}\n\n\t\tconst modelFilename = `${language}.traineddata`;\n\t\tconst modelUrl = `${this.CDN_BASE_URL}/${modelFilename}`;\n\n\t\ttry {\n\t\t\tawait this.client.loadModel(modelUrl);\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tthrow new Error(`Failed to load model for language \"${language}\" from ${modelUrl}: ${message}`);\n\t\t}\n\t}\n\n\t/**\n\t * Convert image bytes or Base64 string to ImageBitmap\n\t *\n\t * Handles both Uint8Array and Base64-encoded image data, converting to\n\t * ImageBitmap format required by Tesseract WASM.\n\t *\n\t * @param imageBytes - Image data as Uint8Array or Base64 string\n\t * @returns Promise resolving to ImageBitmap\n\t * @throws {Error} If conversion fails (browser API not available or invalid image data)\n\t *\n\t * @internal\n\t */\n\tprivate async convertToImageBitmap(imageBytes: Uint8Array | string): Promise<ImageBitmap> {\n\t\tif (typeof createImageBitmap === \"undefined\") {\n\t\t\tthrow new Error(\"createImageBitmap is not available. TesseractWasmBackend requires a browser environment.\");\n\t\t}\n\n\t\ttry {\n\t\t\tlet bytes = imageBytes;\n\t\t\tif (typeof imageBytes === \"string\") {\n\t\t\t\tconst binaryString = atob(imageBytes);\n\t\t\t\tbytes = new Uint8Array(binaryString.length);\n\t\t\t\tfor (let i = 0; i < binaryString.length; i++) {\n\t\t\t\t\t(bytes as Uint8Array)[i] = binaryString.charCodeAt(i);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst blob = new Blob([bytes as Uint8Array] as BlobPart[]);\n\n\t\t\tconst imageBitmap = await createImageBitmap(blob);\n\t\t\treturn imageBitmap;\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tthrow new Error(`Failed to convert image bytes to ImageBitmap: ${message}`);\n\t\t}\n\t}\n\n\t/**\n\t * Get confidence score from OCR result\n\t *\n\t * Attempts to retrieve confidence score from Tesseract.\n\t * Returns a safe default if unavailable.\n\t *\n\t * @returns Confidence score between 0 and 1\n\t *\n\t * @internal\n\t */\n\tprivate async getConfidenceScore(): Promise<number> {\n\t\ttry {\n\t\t\tif (this.client && typeof this.client.getConfidence === \"function\") {\n\t\t\t\tconst confidence = await this.client.getConfidence();\n\t\t\t\treturn confidence > 1 ? confidence / 100 : confidence;\n\t\t\t}\n\t\t} catch {}\n\t\treturn 0.9;\n\t}\n\n\t/**\n\t * Get page metadata from OCR result\n\t *\n\t * Retrieves additional metadata like image dimensions and processing info.\n\t *\n\t * @returns Metadata object (may be empty if unavailable)\n\t *\n\t * @internal\n\t */\n\tprivate async getPageMetadata(): Promise<Record<string, unknown>> {\n\t\ttry {\n\t\t\tif (this.client && typeof this.client.getPageMetadata === \"function\") {\n\t\t\t\treturn await this.client.getPageMetadata();\n\t\t\t}\n\t\t} catch {}\n\t\treturn {};\n\t}\n\n\t/**\n\t * Dynamically load tesseract-wasm module\n\t *\n\t * Uses dynamic import to load tesseract-wasm only when needed,\n\t * avoiding hard dependency in browser environments where it may not be bundled.\n\t *\n\t * @returns tesseract-wasm module object\n\t * @throws {Error} If module cannot be imported\n\t *\n\t * @internal\n\t */\n\tprivate async loadTesseractWasm(): Promise<unknown> {\n\t\ttry {\n\t\t\t// @ts-expect-error - tesseract-wasm has package.json exports issues with TypeScript\n\t\t\tconst module = await import(\"tesseract-wasm\");\n\t\t\treturn module;\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tthrow new Error(\n\t\t\t\t`Failed to import tesseract-wasm. Ensure it is installed via: npm install tesseract-wasm. Error: ${message}`,\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Report progress to progress callback\n\t *\n\t * Internal helper for notifying progress updates during OCR processing.\n\t *\n\t * @param progress - Progress percentage (0-100)\n\t *\n\t * @internal\n\t */\n\tprivate reportProgress(progress: number): void {\n\t\tif (this.progressCallback) {\n\t\t\ttry {\n\t\t\t\tthis.progressCallback(Math.min(100, Math.max(0, progress)));\n\t\t\t} catch {}\n\t\t}\n\t}\n}\n"],"mappings":"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","names":["module"]}
@@ -1,4 +1,4 @@
1
- import { O as OcrBackendProtocol } from '../types-CKjcIYcX.cjs';
1
+ import { O as OcrBackendProtocol } from '../types-wVLLDHkl.cjs';
2
2
 
3
3
  /**
4
4
  * Tesseract WASM OCR Backend
@@ -1,4 +1,4 @@
1
- import { O as OcrBackendProtocol } from '../types-CKjcIYcX.js';
1
+ import { O as OcrBackendProtocol } from '../types-wVLLDHkl.js';
2
2
 
3
3
  /**
4
4
  * Tesseract WASM OCR Backend
@@ -31,93 +31,48 @@ var TesseractWasmBackend = class {
31
31
  return this.supportedLangsCache;
32
32
  }
33
33
  this.supportedLangsCache = [
34
- // Major languages
35
34
  "eng",
36
- // English
37
35
  "deu",
38
- // German
39
36
  "fra",
40
- // French
41
37
  "spa",
42
- // Spanish
43
38
  "ita",
44
- // Italian
45
39
  "por",
46
- // Portuguese
47
40
  "nld",
48
- // Dutch
49
41
  "rus",
50
- // Russian
51
42
  "jpn",
52
- // Japanese
53
43
  "kor",
54
- // Korean
55
44
  "chi_sim",
56
- // Chinese (Simplified)
57
45
  "chi_tra",
58
- // Chinese (Traditional)
59
- // Additional European languages
60
46
  "pol",
61
- // Polish
62
47
  "tur",
63
- // Turkish
64
48
  "swe",
65
- // Swedish
66
49
  "dan",
67
- // Danish
68
50
  "fin",
69
- // Finnish
70
51
  "nor",
71
- // Norwegian
72
52
  "ces",
73
- // Czech
74
53
  "slk",
75
- // Slovak
76
54
  "ron",
77
- // Romanian
78
55
  "hun",
79
- // Hungarian
80
56
  "hrv",
81
- // Croatian
82
57
  "srp",
83
- // Serbian
84
58
  "bul",
85
- // Bulgarian
86
59
  "ukr",
87
- // Ukrainian
88
60
  "ell",
89
- // Greek
90
- // Asian languages
91
61
  "ara",
92
- // Arabic
93
62
  "heb",
94
- // Hebrew
95
63
  "hin",
96
- // Hindi
97
64
  "tha",
98
- // Thai
99
65
  "vie",
100
- // Vietnamese
101
66
  "mkd",
102
- // Macedonian
103
67
  "ben",
104
- // Bengali
105
68
  "tam",
106
- // Tamil
107
69
  "tel",
108
- // Telugu
109
70
  "kan",
110
- // Kannada
111
71
  "mal",
112
- // Malayalam
113
72
  "mya",
114
- // Burmese
115
73
  "khm",
116
- // Khmer
117
74
  "lao",
118
- // Lao
119
75
  "sin"
120
- // Sinhala
121
76
  ];
122
77
  return this.supportedLangsCache;
123
78
  }
@@ -219,7 +174,6 @@ var TesseractWasmBackend = class {
219
174
  ...pageMetadata
220
175
  },
221
176
  tables: []
222
- // Tesseract-wasm doesn't provide structured table detection
223
177
  };
224
178
  } catch (error) {
225
179
  const message = error instanceof Error ? error.message : String(error);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../typescript/ocr/tesseract-wasm-backend.ts"],"sourcesContent":["/**\n * Tesseract WASM OCR Backend\n *\n * Provides OCR capabilities using tesseract-wasm library for browser environments.\n * Loads training data on-demand from jsDelivr CDN and implements the OcrBackendProtocol.\n *\n * ## Browser-Only Requirement\n *\n * This backend requires browser APIs like createImageBitmap and Web Workers.\n * It will NOT work in Node.js environments without additional canvas polyfills.\n *\n * ## Supported Languages\n *\n * Common ISO 639-1 and ISO 639-2 codes:\n * - English: \"eng\"\n * - German: \"deu\"\n * - French: \"fra\"\n * - Spanish: \"spa\"\n * - Italian: \"ita\"\n * - Portuguese: \"por\"\n * - Dutch: \"nld\"\n * - Russian: \"rus\"\n * - Chinese (Simplified): \"chi_sim\"\n * - Chinese (Traditional): \"chi_tra\"\n * - Japanese: \"jpn\"\n * - Korean: \"kor\"\n * - Arabic: \"ara\"\n * - Hindi: \"hin\"\n *\n * For complete language list, see: https://github.com/naptha/tesseract.js\n *\n * @example Basic Usage\n * ```typescript\n * import { TesseractWasmBackend } from '@kreuzberg/wasm/ocr/tesseract-wasm-backend';\n * import { registerOcrBackend, extractBytes, initWasm } from '@kreuzberg/wasm';\n *\n * // Initialize\n * await initWasm();\n * const backend = new TesseractWasmBackend();\n * await backend.initialize();\n * registerOcrBackend(backend);\n *\n * // Use in extraction\n * const imageBytes = new Uint8Array(buffer);\n * const result = await extractBytes(imageBytes, 'image/png', {\n * ocr: { backend: 'tesseract-wasm', language: 'eng' }\n * });\n * console.log(result.content); // Extracted text\n * ```\n *\n * @example With Language Auto-Detection\n * ```typescript\n * const backend = new TesseractWasmBackend();\n * await backend.initialize();\n * registerOcrBackend(backend);\n *\n * // Extract without specifying language - backend will auto-detect\n * const result = await extractBytes(imageBytes, 'image/png', {\n * ocr: { backend: 'tesseract-wasm' } // language will auto-detect\n * });\n * ```\n */\n\nimport type { OcrBackendProtocol } from \"../types.js\";\n\n/**\n * Tesseract WASM Client interface\n * Type definition for tesseract-wasm's OCRClient class\n */\ninterface TesseractClient {\n\tloadModel(modelPath: string): Promise<void>;\n\tloadImage(image: ImageBitmap | Blob): Promise<void>;\n\tgetText(): Promise<string>;\n\tgetConfidence(): Promise<number>;\n\tgetPageMetadata(): Promise<Record<string, unknown>>;\n\tdestroy(): void;\n\tterminate(): void;\n}\n\n/**\n * TesseractWasmBackend - OCR backend using tesseract-wasm library\n *\n * Implements the OcrBackendProtocol for Kreuzberg document extraction pipeline.\n * Provides comprehensive OCR support with model caching, error handling, and progress reporting.\n */\nexport class TesseractWasmBackend implements OcrBackendProtocol {\n\t/** Tesseract WASM client instance */\n\tprivate client: TesseractClient | null = null;\n\n\t/** Track which models are currently loaded to avoid redundant loads */\n\tprivate loadedLanguages: Set<string> = new Set();\n\n\t/** Cache for language availability validation */\n\tprivate supportedLangsCache: string[] | null = null;\n\n\t/** Progress callback for UI updates */\n\tprivate progressCallback: ((progress: number) => void) | null = null;\n\n\t/** Base URL for training data CDN */\n\tprivate readonly CDN_BASE_URL = \"https://cdn.jsdelivr.net/npm/tesseract-wasm@0.11.0/dist\";\n\n\t/**\n\t * Return the unique name of this OCR backend\n\t *\n\t * @returns Backend identifier \"tesseract-wasm\"\n\t */\n\tname(): string {\n\t\treturn \"tesseract-wasm\";\n\t}\n\n\t/**\n\t * Return list of supported language codes\n\t *\n\t * Returns a curated list of commonly available Tesseract language models.\n\t * Tesseract supports many more languages through custom models.\n\t *\n\t * @returns Array of ISO 639-1/2/3 language codes\n\t */\n\tsupportedLanguages(): string[] {\n\t\t// Return cached list if already computed\n\t\tif (this.supportedLangsCache) {\n\t\t\treturn this.supportedLangsCache;\n\t\t}\n\n\t\t// Comprehensive list of languages supported by tesseract-wasm\n\t\t// Includes both 3-letter (ISO 639-2) and 2-letter (ISO 639-1) codes where applicable\n\t\tthis.supportedLangsCache = [\n\t\t\t// Major languages\n\t\t\t\"eng\", // English\n\t\t\t\"deu\", // German\n\t\t\t\"fra\", // French\n\t\t\t\"spa\", // Spanish\n\t\t\t\"ita\", // Italian\n\t\t\t\"por\", // Portuguese\n\t\t\t\"nld\", // Dutch\n\t\t\t\"rus\", // Russian\n\t\t\t\"jpn\", // Japanese\n\t\t\t\"kor\", // Korean\n\t\t\t\"chi_sim\", // Chinese (Simplified)\n\t\t\t\"chi_tra\", // Chinese (Traditional)\n\n\t\t\t// Additional European languages\n\t\t\t\"pol\", // Polish\n\t\t\t\"tur\", // Turkish\n\t\t\t\"swe\", // Swedish\n\t\t\t\"dan\", // Danish\n\t\t\t\"fin\", // Finnish\n\t\t\t\"nor\", // Norwegian\n\t\t\t\"ces\", // Czech\n\t\t\t\"slk\", // Slovak\n\t\t\t\"ron\", // Romanian\n\t\t\t\"hun\", // Hungarian\n\t\t\t\"hrv\", // Croatian\n\t\t\t\"srp\", // Serbian\n\t\t\t\"bul\", // Bulgarian\n\t\t\t\"ukr\", // Ukrainian\n\t\t\t\"ell\", // Greek\n\n\t\t\t// Asian languages\n\t\t\t\"ara\", // Arabic\n\t\t\t\"heb\", // Hebrew\n\t\t\t\"hin\", // Hindi\n\t\t\t\"tha\", // Thai\n\t\t\t\"vie\", // Vietnamese\n\t\t\t\"mkd\", // Macedonian\n\t\t\t\"ben\", // Bengali\n\t\t\t\"tam\", // Tamil\n\t\t\t\"tel\", // Telugu\n\t\t\t\"kan\", // Kannada\n\t\t\t\"mal\", // Malayalam\n\t\t\t\"mya\", // Burmese\n\t\t\t\"khm\", // Khmer\n\t\t\t\"lao\", // Lao\n\t\t\t\"sin\", // Sinhala\n\t\t];\n\n\t\treturn this.supportedLangsCache;\n\t}\n\n\t/**\n\t * Initialize the OCR backend\n\t *\n\t * Creates the Tesseract WASM client instance. This is called once when\n\t * the backend is registered with the extraction pipeline.\n\t *\n\t * The actual model loading happens in processImage() on-demand to avoid\n\t * loading all models upfront.\n\t *\n\t * @throws {Error} If tesseract-wasm is not available or initialization fails\n\t *\n\t * @example\n\t * ```typescript\n\t * const backend = new TesseractWasmBackend();\n\t * try {\n\t * await backend.initialize();\n\t * } catch (error) {\n\t * console.error('Failed to initialize OCR:', error);\n\t * }\n\t * ```\n\t */\n\tasync initialize(): Promise<void> {\n\t\tif (this.client) {\n\t\t\treturn; // Already initialized\n\t\t}\n\n\t\ttry {\n\t\t\t// Dynamically import tesseract-wasm\n\t\t\tconst tesseractModule = await this.loadTesseractWasm();\n\n\t\t\t// @ts-expect-error - tesseract-wasm types are not fully typed\n\t\t\tif (!tesseractModule || typeof tesseractModule.OCRClient !== \"function\") {\n\t\t\t\tthrow new Error(\"tesseract-wasm OCRClient not found. Ensure tesseract-wasm is installed and available.\");\n\t\t\t}\n\n\t\t\t// Create client instance\n\t\t\t// @ts-expect-error - tesseract-wasm types are not fully typed\n\t\t\tthis.client = new tesseractModule.OCRClient();\n\n\t\t\t// Initialize tracking\n\t\t\tthis.loadedLanguages.clear();\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tthrow new Error(`Failed to initialize TesseractWasmBackend: ${message}`);\n\t\t}\n\t}\n\n\t/**\n\t * Process image bytes and extract text via OCR\n\t *\n\t * Handles image loading, model loading, OCR processing, and result formatting.\n\t * Automatically loads the language model on first use and caches it for subsequent calls.\n\t *\n\t * @param imageBytes - Raw image data (Uint8Array) or Base64-encoded string\n\t * @param language - ISO 639-2/3 language code (e.g., \"eng\", \"deu\")\n\t * @returns Promise resolving to OCR result with content and metadata\n\t * @throws {Error} If image processing fails, model loading fails, or language is unsupported\n\t *\n\t * @example\n\t * ```typescript\n\t * const backend = new TesseractWasmBackend();\n\t * await backend.initialize();\n\t *\n\t * const imageBuffer = fs.readFileSync('scanned.png');\n\t * const result = await backend.processImage(\n\t * new Uint8Array(imageBuffer),\n\t * 'eng'\n\t * );\n\t *\n\t * console.log(result.content); // Extracted text\n\t * console.log(result.metadata.confidence); // OCR confidence score\n\t * ```\n\t */\n\tasync processImage(\n\t\timageBytes: Uint8Array | string,\n\t\tlanguage: string,\n\t): Promise<{\n\t\tcontent: string;\n\t\tmime_type: string;\n\t\tmetadata: Record<string, unknown>;\n\t\ttables: unknown[];\n\t}> {\n\t\tif (!this.client) {\n\t\t\tthrow new Error(\"TesseractWasmBackend not initialized. Call initialize() first.\");\n\t\t}\n\n\t\t// Validate language support\n\t\tconst supported = this.supportedLanguages();\n\t\t// Normalize language code for comparison\n\t\tconst normalizedLang = language.toLowerCase();\n\t\tconst isSupported = supported.some((lang) => lang.toLowerCase() === normalizedLang);\n\n\t\tif (!isSupported) {\n\t\t\tthrow new Error(`Language \"${language}\" is not supported. Supported languages: ${supported.join(\", \")}`);\n\t\t}\n\n\t\ttry {\n\t\t\t// Load language model if not already loaded\n\t\t\tif (!this.loadedLanguages.has(normalizedLang)) {\n\t\t\t\tthis.reportProgress(10); // Progress: loading model\n\t\t\t\tawait this.loadLanguageModel(normalizedLang);\n\t\t\t\tthis.loadedLanguages.add(normalizedLang);\n\t\t\t\tthis.reportProgress(30); // Progress: model loaded\n\t\t\t}\n\n\t\t\t// Convert image bytes to ImageBitmap\n\t\t\tthis.reportProgress(40); // Progress: processing image\n\t\t\tconst imageBitmap = await this.convertToImageBitmap(imageBytes);\n\n\t\t\t// Load image into Tesseract\n\t\t\tthis.reportProgress(50); // Progress: loading image\n\t\t\tawait this.client.loadImage(imageBitmap);\n\n\t\t\t// Perform OCR\n\t\t\tthis.reportProgress(70); // Progress: performing OCR\n\t\t\tconst text = await this.client.getText();\n\n\t\t\t// Get confidence and metadata\n\t\t\tconst confidence = await this.getConfidenceScore();\n\t\t\tconst pageMetadata = await this.getPageMetadata();\n\n\t\t\tthis.reportProgress(90); // Progress: nearly complete\n\n\t\t\t// Return result in Kreuzberg format\n\t\t\treturn {\n\t\t\t\tcontent: text,\n\t\t\t\tmime_type: \"text/plain\",\n\t\t\t\tmetadata: {\n\t\t\t\t\tlanguage: normalizedLang,\n\t\t\t\t\tconfidence,\n\t\t\t\t\t...pageMetadata,\n\t\t\t\t},\n\t\t\t\ttables: [], // Tesseract-wasm doesn't provide structured table detection\n\t\t\t};\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tthrow new Error(`OCR processing failed for language \"${language}\": ${message}`);\n\t\t} finally {\n\t\t\tthis.reportProgress(100); // Progress: complete\n\t\t}\n\t}\n\n\t/**\n\t * Shutdown the OCR backend and release resources\n\t *\n\t * Properly cleans up the Tesseract WASM client, freeing memory and Web Workers.\n\t * Called when the backend is unregistered or the application shuts down.\n\t *\n\t * @throws {Error} If cleanup fails (errors are logged but not critical)\n\t *\n\t * @example\n\t * ```typescript\n\t * const backend = new TesseractWasmBackend();\n\t * await backend.initialize();\n\t * // ... use backend ...\n\t * await backend.shutdown(); // Clean up resources\n\t * ```\n\t */\n\tasync shutdown(): Promise<void> {\n\t\ttry {\n\t\t\tif (this.client) {\n\t\t\t\t// Try both destroy and terminate for compatibility\n\t\t\t\tif (typeof this.client.destroy === \"function\") {\n\t\t\t\t\tthis.client.destroy();\n\t\t\t\t}\n\t\t\t\tif (typeof this.client.terminate === \"function\") {\n\t\t\t\t\tthis.client.terminate();\n\t\t\t\t}\n\t\t\t\tthis.client = null;\n\t\t\t}\n\n\t\t\t// Clear cached state\n\t\t\tthis.loadedLanguages.clear();\n\t\t\tthis.supportedLangsCache = null;\n\t\t\tthis.progressCallback = null;\n\t\t} catch (error) {\n\t\t\t// Log error but don't throw - shutdown is best-effort\n\t\t\tconsole.warn(\n\t\t\t\t`Warning during TesseractWasmBackend shutdown: ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Set a progress callback for UI updates\n\t *\n\t * Allows the UI to display progress during OCR processing.\n\t * The callback will be called with values from 0 to 100.\n\t *\n\t * @param callback - Function to call with progress percentage\n\t *\n\t * @example\n\t * ```typescript\n\t * const backend = new TesseractWasmBackend();\n\t * backend.setProgressCallback((progress) => {\n\t * console.log(`OCR Progress: ${progress}%`);\n\t * document.getElementById('progress-bar').style.width = `${progress}%`;\n\t * });\n\t * ```\n\t */\n\tsetProgressCallback(callback: (progress: number) => void): void {\n\t\tthis.progressCallback = callback;\n\t}\n\n\t/**\n\t * Load language model from CDN\n\t *\n\t * Fetches the training data for a specific language from jsDelivr CDN.\n\t * This is an MVP approach - models are cached by the browser.\n\t *\n\t * @param language - ISO 639-2/3 language code\n\t * @throws {Error} If model download fails or language is not available\n\t *\n\t * @internal\n\t */\n\tprivate async loadLanguageModel(language: string): Promise<void> {\n\t\tif (!this.client) {\n\t\t\tthrow new Error(\"Client not initialized\");\n\t\t}\n\n\t\t// Construct model URL - models are named with their language code\n\t\tconst modelFilename = `${language}.traineddata`;\n\t\tconst modelUrl = `${this.CDN_BASE_URL}/${modelFilename}`;\n\n\t\ttry {\n\t\t\tawait this.client.loadModel(modelUrl);\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tthrow new Error(`Failed to load model for language \"${language}\" from ${modelUrl}: ${message}`);\n\t\t}\n\t}\n\n\t/**\n\t * Convert image bytes or Base64 string to ImageBitmap\n\t *\n\t * Handles both Uint8Array and Base64-encoded image data, converting to\n\t * ImageBitmap format required by Tesseract WASM.\n\t *\n\t * @param imageBytes - Image data as Uint8Array or Base64 string\n\t * @returns Promise resolving to ImageBitmap\n\t * @throws {Error} If conversion fails (browser API not available or invalid image data)\n\t *\n\t * @internal\n\t */\n\tprivate async convertToImageBitmap(imageBytes: Uint8Array | string): Promise<ImageBitmap> {\n\t\t// Check if createImageBitmap is available (browser only)\n\t\tif (typeof createImageBitmap === \"undefined\") {\n\t\t\tthrow new Error(\"createImageBitmap is not available. TesseractWasmBackend requires a browser environment.\");\n\t\t}\n\n\t\ttry {\n\t\t\t// Convert to Uint8Array if string (Base64)\n\t\t\tlet bytes = imageBytes;\n\t\t\tif (typeof imageBytes === \"string\") {\n\t\t\t\t// Decode Base64 to binary\n\t\t\t\tconst binaryString = atob(imageBytes);\n\t\t\t\tbytes = new Uint8Array(binaryString.length);\n\t\t\t\tfor (let i = 0; i < binaryString.length; i++) {\n\t\t\t\t\t(bytes as Uint8Array)[i] = binaryString.charCodeAt(i);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Create Blob from bytes\n\t\t\tconst blob = new Blob([bytes as Uint8Array] as BlobPart[]);\n\n\t\t\t// Convert Blob to ImageBitmap\n\t\t\tconst imageBitmap = await createImageBitmap(blob);\n\t\t\treturn imageBitmap;\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tthrow new Error(`Failed to convert image bytes to ImageBitmap: ${message}`);\n\t\t}\n\t}\n\n\t/**\n\t * Get confidence score from OCR result\n\t *\n\t * Attempts to retrieve confidence score from Tesseract.\n\t * Returns a safe default if unavailable.\n\t *\n\t * @returns Confidence score between 0 and 1\n\t *\n\t * @internal\n\t */\n\tprivate async getConfidenceScore(): Promise<number> {\n\t\ttry {\n\t\t\tif (this.client && typeof this.client.getConfidence === \"function\") {\n\t\t\t\tconst confidence = await this.client.getConfidence();\n\t\t\t\t// Normalize to 0-1 range if needed (some versions return 0-100)\n\t\t\t\treturn confidence > 1 ? confidence / 100 : confidence;\n\t\t\t}\n\t\t} catch {\n\t\t\t// Silently fail - confidence is optional\n\t\t}\n\t\treturn 0.9; // Default reasonable confidence\n\t}\n\n\t/**\n\t * Get page metadata from OCR result\n\t *\n\t * Retrieves additional metadata like image dimensions and processing info.\n\t *\n\t * @returns Metadata object (may be empty if unavailable)\n\t *\n\t * @internal\n\t */\n\tprivate async getPageMetadata(): Promise<Record<string, unknown>> {\n\t\ttry {\n\t\t\tif (this.client && typeof this.client.getPageMetadata === \"function\") {\n\t\t\t\treturn await this.client.getPageMetadata();\n\t\t\t}\n\t\t} catch {\n\t\t\t// Silently fail - metadata is optional\n\t\t}\n\t\treturn {};\n\t}\n\n\t/**\n\t * Dynamically load tesseract-wasm module\n\t *\n\t * Uses dynamic import to load tesseract-wasm only when needed,\n\t * avoiding hard dependency in browser environments where it may not be bundled.\n\t *\n\t * @returns tesseract-wasm module object\n\t * @throws {Error} If module cannot be imported\n\t *\n\t * @internal\n\t */\n\tprivate async loadTesseractWasm(): Promise<unknown> {\n\t\ttry {\n\t\t\t// Use dynamic import to handle both ESM and CJS\n\t\t\t// @ts-expect-error - tesseract-wasm has package.json exports issues with TypeScript\n\t\t\t// @vite-ignore - tesseract-wasm package resolution\n\t\t\tconst module = await import(\"tesseract-wasm\");\n\t\t\treturn module;\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tthrow new Error(\n\t\t\t\t`Failed to import tesseract-wasm. Ensure it is installed via: npm install tesseract-wasm. Error: ${message}`,\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Report progress to progress callback\n\t *\n\t * Internal helper for notifying progress updates during OCR processing.\n\t *\n\t * @param progress - Progress percentage (0-100)\n\t *\n\t * @internal\n\t */\n\tprivate reportProgress(progress: number): void {\n\t\tif (this.progressCallback) {\n\t\t\ttry {\n\t\t\t\tthis.progressCallback(Math.min(100, Math.max(0, progress)));\n\t\t\t} catch {\n\t\t\t\t// Ignore callback errors to prevent blocking OCR processing\n\t\t\t}\n\t\t}\n\t}\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../typescript/ocr/tesseract-wasm-backend.ts"],"sourcesContent":["/**\n * Tesseract WASM OCR Backend\n *\n * Provides OCR capabilities using tesseract-wasm library for browser environments.\n * Loads training data on-demand from jsDelivr CDN and implements the OcrBackendProtocol.\n *\n * ## Browser-Only Requirement\n *\n * This backend requires browser APIs like createImageBitmap and Web Workers.\n * It will NOT work in Node.js environments without additional canvas polyfills.\n *\n * ## Supported Languages\n *\n * Common ISO 639-1 and ISO 639-2 codes:\n * - English: \"eng\"\n * - German: \"deu\"\n * - French: \"fra\"\n * - Spanish: \"spa\"\n * - Italian: \"ita\"\n * - Portuguese: \"por\"\n * - Dutch: \"nld\"\n * - Russian: \"rus\"\n * - Chinese (Simplified): \"chi_sim\"\n * - Chinese (Traditional): \"chi_tra\"\n * - Japanese: \"jpn\"\n * - Korean: \"kor\"\n * - Arabic: \"ara\"\n * - Hindi: \"hin\"\n *\n * For complete language list, see: https://github.com/naptha/tesseract.js\n *\n * @example Basic Usage\n * ```typescript\n * import { TesseractWasmBackend } from '@kreuzberg/wasm/ocr/tesseract-wasm-backend';\n * import { registerOcrBackend, extractBytes, initWasm } from '@kreuzberg/wasm';\n *\n * // Initialize\n * await initWasm();\n * const backend = new TesseractWasmBackend();\n * await backend.initialize();\n * registerOcrBackend(backend);\n *\n * // Use in extraction\n * const imageBytes = new Uint8Array(buffer);\n * const result = await extractBytes(imageBytes, 'image/png', {\n * ocr: { backend: 'tesseract-wasm', language: 'eng' }\n * });\n * console.log(result.content); // Extracted text\n * ```\n *\n * @example With Language Auto-Detection\n * ```typescript\n * const backend = new TesseractWasmBackend();\n * await backend.initialize();\n * registerOcrBackend(backend);\n *\n * // Extract without specifying language - backend will auto-detect\n * const result = await extractBytes(imageBytes, 'image/png', {\n * ocr: { backend: 'tesseract-wasm' } // language will auto-detect\n * });\n * ```\n */\n\nimport type { OcrBackendProtocol } from \"../types.js\";\n\n/**\n * Tesseract WASM Client interface\n * Type definition for tesseract-wasm's OCRClient class\n */\ninterface TesseractClient {\n\tloadModel(modelPath: string): Promise<void>;\n\tloadImage(image: ImageBitmap | Blob): Promise<void>;\n\tgetText(): Promise<string>;\n\tgetConfidence(): Promise<number>;\n\tgetPageMetadata(): Promise<Record<string, unknown>>;\n\tdestroy(): void;\n\tterminate(): void;\n}\n\n/**\n * TesseractWasmBackend - OCR backend using tesseract-wasm library\n *\n * Implements the OcrBackendProtocol for Kreuzberg document extraction pipeline.\n * Provides comprehensive OCR support with model caching, error handling, and progress reporting.\n */\nexport class TesseractWasmBackend implements OcrBackendProtocol {\n\t/** Tesseract WASM client instance */\n\tprivate client: TesseractClient | null = null;\n\n\t/** Track which models are currently loaded to avoid redundant loads */\n\tprivate loadedLanguages: Set<string> = new Set();\n\n\t/** Cache for language availability validation */\n\tprivate supportedLangsCache: string[] | null = null;\n\n\t/** Progress callback for UI updates */\n\tprivate progressCallback: ((progress: number) => void) | null = null;\n\n\t/** Base URL for training data CDN */\n\tprivate readonly CDN_BASE_URL = \"https://cdn.jsdelivr.net/npm/tesseract-wasm@0.11.0/dist\";\n\n\t/**\n\t * Return the unique name of this OCR backend\n\t *\n\t * @returns Backend identifier \"tesseract-wasm\"\n\t */\n\tname(): string {\n\t\treturn \"tesseract-wasm\";\n\t}\n\n\t/**\n\t * Return list of supported language codes\n\t *\n\t * Returns a curated list of commonly available Tesseract language models.\n\t * Tesseract supports many more languages through custom models.\n\t *\n\t * @returns Array of ISO 639-1/2/3 language codes\n\t */\n\tsupportedLanguages(): string[] {\n\t\tif (this.supportedLangsCache) {\n\t\t\treturn this.supportedLangsCache;\n\t\t}\n\n\t\tthis.supportedLangsCache = [\n\t\t\t\"eng\",\n\t\t\t\"deu\",\n\t\t\t\"fra\",\n\t\t\t\"spa\",\n\t\t\t\"ita\",\n\t\t\t\"por\",\n\t\t\t\"nld\",\n\t\t\t\"rus\",\n\t\t\t\"jpn\",\n\t\t\t\"kor\",\n\t\t\t\"chi_sim\",\n\t\t\t\"chi_tra\",\n\n\t\t\t\"pol\",\n\t\t\t\"tur\",\n\t\t\t\"swe\",\n\t\t\t\"dan\",\n\t\t\t\"fin\",\n\t\t\t\"nor\",\n\t\t\t\"ces\",\n\t\t\t\"slk\",\n\t\t\t\"ron\",\n\t\t\t\"hun\",\n\t\t\t\"hrv\",\n\t\t\t\"srp\",\n\t\t\t\"bul\",\n\t\t\t\"ukr\",\n\t\t\t\"ell\",\n\n\t\t\t\"ara\",\n\t\t\t\"heb\",\n\t\t\t\"hin\",\n\t\t\t\"tha\",\n\t\t\t\"vie\",\n\t\t\t\"mkd\",\n\t\t\t\"ben\",\n\t\t\t\"tam\",\n\t\t\t\"tel\",\n\t\t\t\"kan\",\n\t\t\t\"mal\",\n\t\t\t\"mya\",\n\t\t\t\"khm\",\n\t\t\t\"lao\",\n\t\t\t\"sin\",\n\t\t];\n\n\t\treturn this.supportedLangsCache;\n\t}\n\n\t/**\n\t * Initialize the OCR backend\n\t *\n\t * Creates the Tesseract WASM client instance. This is called once when\n\t * the backend is registered with the extraction pipeline.\n\t *\n\t * The actual model loading happens in processImage() on-demand to avoid\n\t * loading all models upfront.\n\t *\n\t * @throws {Error} If tesseract-wasm is not available or initialization fails\n\t *\n\t * @example\n\t * ```typescript\n\t * const backend = new TesseractWasmBackend();\n\t * try {\n\t * await backend.initialize();\n\t * } catch (error) {\n\t * console.error('Failed to initialize OCR:', error);\n\t * }\n\t * ```\n\t */\n\tasync initialize(): Promise<void> {\n\t\tif (this.client) {\n\t\t\treturn;\n\t\t}\n\n\t\ttry {\n\t\t\tconst tesseractModule = await this.loadTesseractWasm();\n\n\t\t\t// @ts-expect-error - tesseract-wasm types are not fully typed\n\t\t\tif (!tesseractModule || typeof tesseractModule.OCRClient !== \"function\") {\n\t\t\t\tthrow new Error(\"tesseract-wasm OCRClient not found. Ensure tesseract-wasm is installed and available.\");\n\t\t\t}\n\n\t\t\t// @ts-expect-error - tesseract-wasm types are not fully typed\n\t\t\tthis.client = new tesseractModule.OCRClient();\n\n\t\t\tthis.loadedLanguages.clear();\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tthrow new Error(`Failed to initialize TesseractWasmBackend: ${message}`);\n\t\t}\n\t}\n\n\t/**\n\t * Process image bytes and extract text via OCR\n\t *\n\t * Handles image loading, model loading, OCR processing, and result formatting.\n\t * Automatically loads the language model on first use and caches it for subsequent calls.\n\t *\n\t * @param imageBytes - Raw image data (Uint8Array) or Base64-encoded string\n\t * @param language - ISO 639-2/3 language code (e.g., \"eng\", \"deu\")\n\t * @returns Promise resolving to OCR result with content and metadata\n\t * @throws {Error} If image processing fails, model loading fails, or language is unsupported\n\t *\n\t * @example\n\t * ```typescript\n\t * const backend = new TesseractWasmBackend();\n\t * await backend.initialize();\n\t *\n\t * const imageBuffer = fs.readFileSync('scanned.png');\n\t * const result = await backend.processImage(\n\t * new Uint8Array(imageBuffer),\n\t * 'eng'\n\t * );\n\t *\n\t * console.log(result.content); // Extracted text\n\t * console.log(result.metadata.confidence); // OCR confidence score\n\t * ```\n\t */\n\tasync processImage(\n\t\timageBytes: Uint8Array | string,\n\t\tlanguage: string,\n\t): Promise<{\n\t\tcontent: string;\n\t\tmime_type: string;\n\t\tmetadata: Record<string, unknown>;\n\t\ttables: unknown[];\n\t}> {\n\t\tif (!this.client) {\n\t\t\tthrow new Error(\"TesseractWasmBackend not initialized. Call initialize() first.\");\n\t\t}\n\n\t\tconst supported = this.supportedLanguages();\n\t\tconst normalizedLang = language.toLowerCase();\n\t\tconst isSupported = supported.some((lang) => lang.toLowerCase() === normalizedLang);\n\n\t\tif (!isSupported) {\n\t\t\tthrow new Error(`Language \"${language}\" is not supported. Supported languages: ${supported.join(\", \")}`);\n\t\t}\n\n\t\ttry {\n\t\t\tif (!this.loadedLanguages.has(normalizedLang)) {\n\t\t\t\tthis.reportProgress(10);\n\t\t\t\tawait this.loadLanguageModel(normalizedLang);\n\t\t\t\tthis.loadedLanguages.add(normalizedLang);\n\t\t\t\tthis.reportProgress(30);\n\t\t\t}\n\n\t\t\tthis.reportProgress(40);\n\t\t\tconst imageBitmap = await this.convertToImageBitmap(imageBytes);\n\n\t\t\tthis.reportProgress(50);\n\t\t\tawait this.client.loadImage(imageBitmap);\n\n\t\t\tthis.reportProgress(70);\n\t\t\tconst text = await this.client.getText();\n\n\t\t\tconst confidence = await this.getConfidenceScore();\n\t\t\tconst pageMetadata = await this.getPageMetadata();\n\n\t\t\tthis.reportProgress(90);\n\n\t\t\treturn {\n\t\t\t\tcontent: text,\n\t\t\t\tmime_type: \"text/plain\",\n\t\t\t\tmetadata: {\n\t\t\t\t\tlanguage: normalizedLang,\n\t\t\t\t\tconfidence,\n\t\t\t\t\t...pageMetadata,\n\t\t\t\t},\n\t\t\t\ttables: [],\n\t\t\t};\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tthrow new Error(`OCR processing failed for language \"${language}\": ${message}`);\n\t\t} finally {\n\t\t\tthis.reportProgress(100);\n\t\t}\n\t}\n\n\t/**\n\t * Shutdown the OCR backend and release resources\n\t *\n\t * Properly cleans up the Tesseract WASM client, freeing memory and Web Workers.\n\t * Called when the backend is unregistered or the application shuts down.\n\t *\n\t * @throws {Error} If cleanup fails (errors are logged but not critical)\n\t *\n\t * @example\n\t * ```typescript\n\t * const backend = new TesseractWasmBackend();\n\t * await backend.initialize();\n\t * // ... use backend ...\n\t * await backend.shutdown(); // Clean up resources\n\t * ```\n\t */\n\tasync shutdown(): Promise<void> {\n\t\ttry {\n\t\t\tif (this.client) {\n\t\t\t\tif (typeof this.client.destroy === \"function\") {\n\t\t\t\t\tthis.client.destroy();\n\t\t\t\t}\n\t\t\t\tif (typeof this.client.terminate === \"function\") {\n\t\t\t\t\tthis.client.terminate();\n\t\t\t\t}\n\t\t\t\tthis.client = null;\n\t\t\t}\n\n\t\t\tthis.loadedLanguages.clear();\n\t\t\tthis.supportedLangsCache = null;\n\t\t\tthis.progressCallback = null;\n\t\t} catch (error) {\n\t\t\tconsole.warn(\n\t\t\t\t`Warning during TesseractWasmBackend shutdown: ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Set a progress callback for UI updates\n\t *\n\t * Allows the UI to display progress during OCR processing.\n\t * The callback will be called with values from 0 to 100.\n\t *\n\t * @param callback - Function to call with progress percentage\n\t *\n\t * @example\n\t * ```typescript\n\t * const backend = new TesseractWasmBackend();\n\t * backend.setProgressCallback((progress) => {\n\t * console.log(`OCR Progress: ${progress}%`);\n\t * document.getElementById('progress-bar').style.width = `${progress}%`;\n\t * });\n\t * ```\n\t */\n\tsetProgressCallback(callback: (progress: number) => void): void {\n\t\tthis.progressCallback = callback;\n\t}\n\n\t/**\n\t * Load language model from CDN\n\t *\n\t * Fetches the training data for a specific language from jsDelivr CDN.\n\t * This is an MVP approach - models are cached by the browser.\n\t *\n\t * @param language - ISO 639-2/3 language code\n\t * @throws {Error} If model download fails or language is not available\n\t *\n\t * @internal\n\t */\n\tprivate async loadLanguageModel(language: string): Promise<void> {\n\t\tif (!this.client) {\n\t\t\tthrow new Error(\"Client not initialized\");\n\t\t}\n\n\t\tconst modelFilename = `${language}.traineddata`;\n\t\tconst modelUrl = `${this.CDN_BASE_URL}/${modelFilename}`;\n\n\t\ttry {\n\t\t\tawait this.client.loadModel(modelUrl);\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tthrow new Error(`Failed to load model for language \"${language}\" from ${modelUrl}: ${message}`);\n\t\t}\n\t}\n\n\t/**\n\t * Convert image bytes or Base64 string to ImageBitmap\n\t *\n\t * Handles both Uint8Array and Base64-encoded image data, converting to\n\t * ImageBitmap format required by Tesseract WASM.\n\t *\n\t * @param imageBytes - Image data as Uint8Array or Base64 string\n\t * @returns Promise resolving to ImageBitmap\n\t * @throws {Error} If conversion fails (browser API not available or invalid image data)\n\t *\n\t * @internal\n\t */\n\tprivate async convertToImageBitmap(imageBytes: Uint8Array | string): Promise<ImageBitmap> {\n\t\tif (typeof createImageBitmap === \"undefined\") {\n\t\t\tthrow new Error(\"createImageBitmap is not available. TesseractWasmBackend requires a browser environment.\");\n\t\t}\n\n\t\ttry {\n\t\t\tlet bytes = imageBytes;\n\t\t\tif (typeof imageBytes === \"string\") {\n\t\t\t\tconst binaryString = atob(imageBytes);\n\t\t\t\tbytes = new Uint8Array(binaryString.length);\n\t\t\t\tfor (let i = 0; i < binaryString.length; i++) {\n\t\t\t\t\t(bytes as Uint8Array)[i] = binaryString.charCodeAt(i);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst blob = new Blob([bytes as Uint8Array] as BlobPart[]);\n\n\t\t\tconst imageBitmap = await createImageBitmap(blob);\n\t\t\treturn imageBitmap;\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tthrow new Error(`Failed to convert image bytes to ImageBitmap: ${message}`);\n\t\t}\n\t}\n\n\t/**\n\t * Get confidence score from OCR result\n\t *\n\t * Attempts to retrieve confidence score from Tesseract.\n\t * Returns a safe default if unavailable.\n\t *\n\t * @returns Confidence score between 0 and 1\n\t *\n\t * @internal\n\t */\n\tprivate async getConfidenceScore(): Promise<number> {\n\t\ttry {\n\t\t\tif (this.client && typeof this.client.getConfidence === \"function\") {\n\t\t\t\tconst confidence = await this.client.getConfidence();\n\t\t\t\treturn confidence > 1 ? confidence / 100 : confidence;\n\t\t\t}\n\t\t} catch {}\n\t\treturn 0.9;\n\t}\n\n\t/**\n\t * Get page metadata from OCR result\n\t *\n\t * Retrieves additional metadata like image dimensions and processing info.\n\t *\n\t * @returns Metadata object (may be empty if unavailable)\n\t *\n\t * @internal\n\t */\n\tprivate async getPageMetadata(): Promise<Record<string, unknown>> {\n\t\ttry {\n\t\t\tif (this.client && typeof this.client.getPageMetadata === \"function\") {\n\t\t\t\treturn await this.client.getPageMetadata();\n\t\t\t}\n\t\t} catch {}\n\t\treturn {};\n\t}\n\n\t/**\n\t * Dynamically load tesseract-wasm module\n\t *\n\t * Uses dynamic import to load tesseract-wasm only when needed,\n\t * avoiding hard dependency in browser environments where it may not be bundled.\n\t *\n\t * @returns tesseract-wasm module object\n\t * @throws {Error} If module cannot be imported\n\t *\n\t * @internal\n\t */\n\tprivate async loadTesseractWasm(): Promise<unknown> {\n\t\ttry {\n\t\t\t// @ts-expect-error - tesseract-wasm has package.json exports issues with TypeScript\n\t\t\tconst module = await import(\"tesseract-wasm\");\n\t\t\treturn module;\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tthrow new Error(\n\t\t\t\t`Failed to import tesseract-wasm. Ensure it is installed via: npm install tesseract-wasm. Error: ${message}`,\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Report progress to progress callback\n\t *\n\t * Internal helper for notifying progress updates during OCR processing.\n\t *\n\t * @param progress - Progress percentage (0-100)\n\t *\n\t * @internal\n\t */\n\tprivate reportProgress(progress: number): void {\n\t\tif (this.progressCallback) {\n\t\t\ttry {\n\t\t\t\tthis.progressCallback(Math.min(100, Math.max(0, progress)));\n\t\t\t} catch {}\n\t\t}\n\t}\n}\n"],"mappings":"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","names":[]}
package/dist/pdfium.js CHANGED
@@ -39,8 +39,6 @@
39
39
  * const result = await wasm.extract_from_bytes(pdfBytes, config);
40
40
  */
41
41
  export function initializePdfiumWasm(pdfiumModule, wasmModule, debug = false) {
42
- // pdfium-render exports initialize_pdfium_render as a global function
43
- // when compiled as part of our WASM module
44
42
  if (typeof wasmModule.initialize_pdfium_render === "function") {
45
43
  try {
46
44
  return wasmModule.initialize_pdfium_render(pdfiumModule, wasmModule, debug);
@@ -50,7 +48,6 @@ export function initializePdfiumWasm(pdfiumModule, wasmModule, debug = false) {
50
48
  }
51
49
  }
52
50
 
53
- // Fallback: Try to find it in global scope (legacy behavior)
54
51
  if (typeof initialize_pdfium_render === "function") {
55
52
  try {
56
53
  return initialize_pdfium_render(pdfiumModule, wasmModule, debug);
@@ -72,10 +69,8 @@ export function initializePdfiumWasm(pdfiumModule, wasmModule, debug = false) {
72
69
  * @returns {Promise<Object>} Loaded PDFium module
73
70
  */
74
71
  export async function loadPdfiumModule(pdfiumJsUrl) {
75
- // Dynamic import of PDFium module
76
72
  const pdfiumLoader = await import(pdfiumJsUrl);
77
73
 
78
- // PDFium uses Emscripten module pattern
79
74
  const pdfiumModule = await pdfiumLoader.default();
80
75
 
81
76
  return pdfiumModule;
package/dist/runtime.cjs CHANGED
@@ -124,7 +124,6 @@ function getRuntimeVersion() {
124
124
  switch (runtime) {
125
125
  case "node":
126
126
  return process.version?.substring(1);
127
- // Remove 'v' prefix
128
127
  case "deno": {
129
128
  const deno = globalThis.Deno;
130
129
  const version = deno?.version;
@@ -1 +1 @@
1
- {"version":3,"sources":["../typescript/runtime.ts"],"sourcesContent":["/**\n * Runtime detection and environment-specific utilities\n *\n * This module provides utilities for detecting the JavaScript runtime environment,\n * checking for feature availability, and enabling environment-specific WASM loading strategies.\n *\n * @example Basic Runtime Detection\n * ```typescript\n * import { detectRuntime, isBrowser, isNode } from '@kreuzberg/wasm/runtime';\n *\n * if (isBrowser()) {\n * console.log('Running in browser');\n * } else if (isNode()) {\n * console.log('Running in Node.js');\n * }\n * ```\n *\n * @example Feature Detection\n * ```typescript\n * import { hasFileApi, hasWorkers } from '@kreuzberg/wasm/runtime';\n *\n * if (hasFileApi()) {\n * // Can use File API for browser file uploads\n * }\n *\n * if (hasWorkers()) {\n * // Can use Web Workers for parallel processing\n * }\n * ```\n */\n\nexport type RuntimeType = \"browser\" | \"node\" | \"deno\" | \"bun\" | \"unknown\";\n\n/**\n * WebAssembly capabilities available in the runtime\n */\nexport interface WasmCapabilities {\n\t/** Runtime environment type */\n\truntime: RuntimeType;\n\t/** WebAssembly support available */\n\thasWasm: boolean;\n\t/** Streaming WebAssembly instantiation available */\n\thasWasmStreaming: boolean;\n\t/** File API available (browser) */\n\thasFileApi: boolean;\n\t/** Blob API available */\n\thasBlob: boolean;\n\t/** Worker support available */\n\thasWorkers: boolean;\n\t/** SharedArrayBuffer available (may be restricted) */\n\thasSharedArrayBuffer: boolean;\n\t/** Module Workers available */\n\thasModuleWorkers: boolean;\n\t/** BigInt support */\n\thasBigInt: boolean;\n\t/** Specific runtime version if available */\n\truntimeVersion?: string;\n}\n\n/**\n * Detect the current JavaScript runtime\n *\n * Checks for various global objects and properties to determine\n * which JavaScript runtime environment is currently executing.\n *\n * @returns The detected runtime type\n *\n * @example\n * ```typescript\n * import { detectRuntime } from '@kreuzberg/wasm/runtime';\n *\n * const runtime = detectRuntime();\n * switch (runtime) {\n * case 'browser':\n * console.log('Running in browser');\n * break;\n * case 'node':\n * console.log('Running in Node.js');\n * break;\n * case 'deno':\n * console.log('Running in Deno');\n * break;\n * case 'bun':\n * console.log('Running in Bun');\n * break;\n * }\n * ```\n */\nexport function detectRuntime(): RuntimeType {\n\t// Check for Deno\n\tif (typeof (globalThis as unknown as Record<string, unknown>).Deno !== \"undefined\") {\n\t\treturn \"deno\";\n\t}\n\n\t// Check for Bun\n\tif (typeof (globalThis as unknown as Record<string, unknown>).Bun !== \"undefined\") {\n\t\treturn \"bun\";\n\t}\n\n\t// Check for Node.js\n\tif (typeof process !== \"undefined\" && process.versions && process.versions.node) {\n\t\treturn \"node\";\n\t}\n\n\t// Check for browser\n\tif (typeof window !== \"undefined\" && typeof document !== \"undefined\") {\n\t\treturn \"browser\";\n\t}\n\n\treturn \"unknown\";\n}\n\n/**\n * Check if running in a browser environment\n *\n * @returns True if running in a browser, false otherwise\n */\nexport function isBrowser(): boolean {\n\treturn detectRuntime() === \"browser\";\n}\n\n/**\n * Check if running in Node.js\n *\n * @returns True if running in Node.js, false otherwise\n */\nexport function isNode(): boolean {\n\treturn detectRuntime() === \"node\";\n}\n\n/**\n * Check if running in Deno\n *\n * @returns True if running in Deno, false otherwise\n */\nexport function isDeno(): boolean {\n\treturn detectRuntime() === \"deno\";\n}\n\n/**\n * Check if running in Bun\n *\n * @returns True if running in Bun, false otherwise\n */\nexport function isBun(): boolean {\n\treturn detectRuntime() === \"bun\";\n}\n\n/**\n * Check if running in a web environment (browser or similar)\n *\n * @returns True if running in a web browser, false otherwise\n */\nexport function isWebEnvironment(): boolean {\n\tconst runtime = detectRuntime();\n\treturn runtime === \"browser\";\n}\n\n/**\n * Check if running in a server-like environment (Node.js, Deno, Bun)\n *\n * @returns True if running on a server runtime, false otherwise\n */\nexport function isServerEnvironment(): boolean {\n\tconst runtime = detectRuntime();\n\treturn runtime === \"node\" || runtime === \"deno\" || runtime === \"bun\";\n}\n\n/**\n * Check if File API is available\n *\n * The File API is required for handling browser file uploads.\n *\n * @returns True if File API is available, false otherwise\n *\n * @example\n * ```typescript\n * if (hasFileApi()) {\n * const fileInput = document.getElementById('file');\n * fileInput.addEventListener('change', (e) => {\n * const file = e.target.files?.[0];\n * // Handle file\n * });\n * }\n * ```\n */\nexport function hasFileApi(): boolean {\n\treturn typeof window !== \"undefined\" && typeof File !== \"undefined\" && typeof Blob !== \"undefined\";\n}\n\n/**\n * Check if Blob API is available\n *\n * @returns True if Blob API is available, false otherwise\n */\nexport function hasBlob(): boolean {\n\treturn typeof Blob !== \"undefined\";\n}\n\n/**\n * Check if Web Workers are available\n *\n * @returns True if Web Workers can be created, false otherwise\n */\nexport function hasWorkers(): boolean {\n\treturn typeof Worker !== \"undefined\";\n}\n\n/**\n * Check if SharedArrayBuffer is available\n *\n * Note: SharedArrayBuffer is restricted in some browser contexts\n * due to security considerations (Spectre/Meltdown mitigations).\n *\n * @returns True if SharedArrayBuffer is available, false otherwise\n */\nexport function hasSharedArrayBuffer(): boolean {\n\treturn typeof SharedArrayBuffer !== \"undefined\";\n}\n\n/**\n * Check if module workers are available\n *\n * Module workers allow importing ES modules in worker threads.\n *\n * @returns True if module workers are supported, false otherwise\n */\nexport function hasModuleWorkers(): boolean {\n\tif (!hasWorkers()) {\n\t\treturn false;\n\t}\n\n\ttry {\n\t\t// Try to detect module worker support\n\t\tconst blob = new Blob(['console.log(\"test\")'], {\n\t\t\ttype: \"application/javascript\",\n\t\t});\n\t\tconst workerUrl = URL.createObjectURL(blob);\n\t\ttry {\n\t\t\t// Module workers require type: 'module' option\n\t\t\t// We can't actually instantiate without issues, so we check the API exists\n\t\t\treturn true;\n\t\t} finally {\n\t\t\tURL.revokeObjectURL(workerUrl);\n\t\t}\n\t} catch {\n\t\treturn false;\n\t}\n}\n\n/**\n * Check if WebAssembly is available\n *\n * @returns True if WebAssembly is supported, false otherwise\n */\nexport function hasWasm(): boolean {\n\treturn typeof WebAssembly !== \"undefined\" && WebAssembly.instantiate !== undefined;\n}\n\n/**\n * Check if WebAssembly.instantiateStreaming is available\n *\n * Streaming instantiation is more efficient than buffering the entire WASM module.\n *\n * @returns True if streaming WebAssembly is supported, false otherwise\n */\nexport function hasWasmStreaming(): boolean {\n\treturn typeof WebAssembly !== \"undefined\" && WebAssembly.instantiateStreaming !== undefined;\n}\n\n/**\n * Check if BigInt is available\n *\n * @returns True if BigInt type is supported, false otherwise\n */\nexport function hasBigInt(): boolean {\n\ttry {\n\t\tconst test = BigInt(\"1\");\n\t\treturn typeof test === \"bigint\";\n\t} catch {\n\t\treturn false;\n\t}\n}\n\n/**\n * Get runtime version information\n *\n * @returns Version string if available, undefined otherwise\n *\n * @example\n * ```typescript\n * const version = getRuntimeVersion();\n * console.log(`Running on Node ${version}`); // \"Running on Node 18.12.0\"\n * ```\n */\nexport function getRuntimeVersion(): string | undefined {\n\tconst runtime = detectRuntime();\n\n\tswitch (runtime) {\n\t\tcase \"node\":\n\t\t\treturn process.version?.substring(1); // Remove 'v' prefix\n\t\tcase \"deno\": {\n\t\t\tconst deno = (globalThis as unknown as Record<string, unknown>).Deno as Record<string, unknown> | undefined;\n\t\t\tconst version = deno?.version as Record<string, unknown> | undefined;\n\t\t\treturn version?.deno as string | undefined;\n\t\t}\n\t\tcase \"bun\": {\n\t\t\tconst bun = (globalThis as unknown as Record<string, unknown>).Bun as Record<string, unknown> | undefined;\n\t\t\treturn bun?.version as string | undefined;\n\t\t}\n\t\tdefault:\n\t\t\treturn undefined;\n\t}\n}\n\n/**\n * Get comprehensive WebAssembly capabilities for current runtime\n *\n * Returns detailed information about WASM and related APIs available\n * in the current runtime environment.\n *\n * @returns Object describing available WASM capabilities\n *\n * @example\n * ```typescript\n * import { getWasmCapabilities } from '@kreuzberg/wasm/runtime';\n *\n * const caps = getWasmCapabilities();\n * console.log(`WASM available: ${caps.hasWasm}`);\n * console.log(`Streaming WASM: ${caps.hasWasmStreaming}`);\n * console.log(`Workers available: ${caps.hasWorkers}`);\n *\n * if (caps.hasWasm && caps.hasWorkers) {\n * // Can offload WASM processing to workers\n * }\n * ```\n */\nexport function getWasmCapabilities(): WasmCapabilities {\n\tconst runtime = detectRuntime();\n\tconst version = getRuntimeVersion();\n\tconst capabilities: WasmCapabilities = {\n\t\truntime,\n\t\thasWasm: hasWasm(),\n\t\thasWasmStreaming: hasWasmStreaming(),\n\t\thasFileApi: hasFileApi(),\n\t\thasBlob: hasBlob(),\n\t\thasWorkers: hasWorkers(),\n\t\thasSharedArrayBuffer: hasSharedArrayBuffer(),\n\t\thasModuleWorkers: hasModuleWorkers(),\n\t\thasBigInt: hasBigInt(),\n\t\t...(version !== undefined ? { runtimeVersion: version } : {}),\n\t};\n\treturn capabilities;\n}\n\n/**\n * Get comprehensive runtime information\n *\n * Returns detailed information about the current runtime environment,\n * capabilities, and identifying information.\n *\n * @returns Object with runtime details and capabilities\n *\n * @example\n * ```typescript\n * const info = getRuntimeInfo();\n * console.log(info.runtime); // 'browser' | 'node' | 'deno' | 'bun'\n * console.log(info.isBrowser); // true/false\n * console.log(info.userAgent); // Browser user agent string\n * console.log(info.capabilities); // Detailed capability information\n * ```\n */\nexport function getRuntimeInfo() {\n\tconst runtime = detectRuntime();\n\tconst capabilities = getWasmCapabilities();\n\n\treturn {\n\t\truntime,\n\t\tisBrowser: isBrowser(),\n\t\tisNode: isNode(),\n\t\tisDeno: isDeno(),\n\t\tisBun: isBun(),\n\t\tisWeb: isWebEnvironment(),\n\t\tisServer: isServerEnvironment(),\n\t\truntimeVersion: getRuntimeVersion(),\n\t\tuserAgent: typeof navigator !== \"undefined\" ? navigator.userAgent : \"N/A\",\n\t\tcapabilities,\n\t};\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../typescript/runtime.ts"],"sourcesContent":["/**\n * Runtime detection and environment-specific utilities\n *\n * This module provides utilities for detecting the JavaScript runtime environment,\n * checking for feature availability, and enabling environment-specific WASM loading strategies.\n *\n * @example Basic Runtime Detection\n * ```typescript\n * import { detectRuntime, isBrowser, isNode } from '@kreuzberg/wasm/runtime';\n *\n * if (isBrowser()) {\n * console.log('Running in browser');\n * } else if (isNode()) {\n * console.log('Running in Node.js');\n * }\n * ```\n *\n * @example Feature Detection\n * ```typescript\n * import { hasFileApi, hasWorkers } from '@kreuzberg/wasm/runtime';\n *\n * if (hasFileApi()) {\n * // Can use File API for browser file uploads\n * }\n *\n * if (hasWorkers()) {\n * // Can use Web Workers for parallel processing\n * }\n * ```\n */\n\nexport type RuntimeType = \"browser\" | \"node\" | \"deno\" | \"bun\" | \"unknown\";\n\n/**\n * WebAssembly capabilities available in the runtime\n */\nexport interface WasmCapabilities {\n\t/** Runtime environment type */\n\truntime: RuntimeType;\n\t/** WebAssembly support available */\n\thasWasm: boolean;\n\t/** Streaming WebAssembly instantiation available */\n\thasWasmStreaming: boolean;\n\t/** File API available (browser) */\n\thasFileApi: boolean;\n\t/** Blob API available */\n\thasBlob: boolean;\n\t/** Worker support available */\n\thasWorkers: boolean;\n\t/** SharedArrayBuffer available (may be restricted) */\n\thasSharedArrayBuffer: boolean;\n\t/** Module Workers available */\n\thasModuleWorkers: boolean;\n\t/** BigInt support */\n\thasBigInt: boolean;\n\t/** Specific runtime version if available */\n\truntimeVersion?: string;\n}\n\n/**\n * Detect the current JavaScript runtime\n *\n * Checks for various global objects and properties to determine\n * which JavaScript runtime environment is currently executing.\n *\n * @returns The detected runtime type\n *\n * @example\n * ```typescript\n * import { detectRuntime } from '@kreuzberg/wasm/runtime';\n *\n * const runtime = detectRuntime();\n * switch (runtime) {\n * case 'browser':\n * console.log('Running in browser');\n * break;\n * case 'node':\n * console.log('Running in Node.js');\n * break;\n * case 'deno':\n * console.log('Running in Deno');\n * break;\n * case 'bun':\n * console.log('Running in Bun');\n * break;\n * }\n * ```\n */\nexport function detectRuntime(): RuntimeType {\n\tif (typeof (globalThis as unknown as Record<string, unknown>).Deno !== \"undefined\") {\n\t\treturn \"deno\";\n\t}\n\n\tif (typeof (globalThis as unknown as Record<string, unknown>).Bun !== \"undefined\") {\n\t\treturn \"bun\";\n\t}\n\n\tif (typeof process !== \"undefined\" && process.versions && process.versions.node) {\n\t\treturn \"node\";\n\t}\n\n\tif (typeof window !== \"undefined\" && typeof document !== \"undefined\") {\n\t\treturn \"browser\";\n\t}\n\n\treturn \"unknown\";\n}\n\n/**\n * Check if running in a browser environment\n *\n * @returns True if running in a browser, false otherwise\n */\nexport function isBrowser(): boolean {\n\treturn detectRuntime() === \"browser\";\n}\n\n/**\n * Check if running in Node.js\n *\n * @returns True if running in Node.js, false otherwise\n */\nexport function isNode(): boolean {\n\treturn detectRuntime() === \"node\";\n}\n\n/**\n * Check if running in Deno\n *\n * @returns True if running in Deno, false otherwise\n */\nexport function isDeno(): boolean {\n\treturn detectRuntime() === \"deno\";\n}\n\n/**\n * Check if running in Bun\n *\n * @returns True if running in Bun, false otherwise\n */\nexport function isBun(): boolean {\n\treturn detectRuntime() === \"bun\";\n}\n\n/**\n * Check if running in a web environment (browser or similar)\n *\n * @returns True if running in a web browser, false otherwise\n */\nexport function isWebEnvironment(): boolean {\n\tconst runtime = detectRuntime();\n\treturn runtime === \"browser\";\n}\n\n/**\n * Check if running in a server-like environment (Node.js, Deno, Bun)\n *\n * @returns True if running on a server runtime, false otherwise\n */\nexport function isServerEnvironment(): boolean {\n\tconst runtime = detectRuntime();\n\treturn runtime === \"node\" || runtime === \"deno\" || runtime === \"bun\";\n}\n\n/**\n * Check if File API is available\n *\n * The File API is required for handling browser file uploads.\n *\n * @returns True if File API is available, false otherwise\n *\n * @example\n * ```typescript\n * if (hasFileApi()) {\n * const fileInput = document.getElementById('file');\n * fileInput.addEventListener('change', (e) => {\n * const file = e.target.files?.[0];\n * // Handle file\n * });\n * }\n * ```\n */\nexport function hasFileApi(): boolean {\n\treturn typeof window !== \"undefined\" && typeof File !== \"undefined\" && typeof Blob !== \"undefined\";\n}\n\n/**\n * Check if Blob API is available\n *\n * @returns True if Blob API is available, false otherwise\n */\nexport function hasBlob(): boolean {\n\treturn typeof Blob !== \"undefined\";\n}\n\n/**\n * Check if Web Workers are available\n *\n * @returns True if Web Workers can be created, false otherwise\n */\nexport function hasWorkers(): boolean {\n\treturn typeof Worker !== \"undefined\";\n}\n\n/**\n * Check if SharedArrayBuffer is available\n *\n * Note: SharedArrayBuffer is restricted in some browser contexts\n * due to security considerations (Spectre/Meltdown mitigations).\n *\n * @returns True if SharedArrayBuffer is available, false otherwise\n */\nexport function hasSharedArrayBuffer(): boolean {\n\treturn typeof SharedArrayBuffer !== \"undefined\";\n}\n\n/**\n * Check if module workers are available\n *\n * Module workers allow importing ES modules in worker threads.\n *\n * @returns True if module workers are supported, false otherwise\n */\nexport function hasModuleWorkers(): boolean {\n\tif (!hasWorkers()) {\n\t\treturn false;\n\t}\n\n\ttry {\n\t\tconst blob = new Blob(['console.log(\"test\")'], {\n\t\t\ttype: \"application/javascript\",\n\t\t});\n\t\tconst workerUrl = URL.createObjectURL(blob);\n\t\ttry {\n\t\t\treturn true;\n\t\t} finally {\n\t\t\tURL.revokeObjectURL(workerUrl);\n\t\t}\n\t} catch {\n\t\treturn false;\n\t}\n}\n\n/**\n * Check if WebAssembly is available\n *\n * @returns True if WebAssembly is supported, false otherwise\n */\nexport function hasWasm(): boolean {\n\treturn typeof WebAssembly !== \"undefined\" && WebAssembly.instantiate !== undefined;\n}\n\n/**\n * Check if WebAssembly.instantiateStreaming is available\n *\n * Streaming instantiation is more efficient than buffering the entire WASM module.\n *\n * @returns True if streaming WebAssembly is supported, false otherwise\n */\nexport function hasWasmStreaming(): boolean {\n\treturn typeof WebAssembly !== \"undefined\" && WebAssembly.instantiateStreaming !== undefined;\n}\n\n/**\n * Check if BigInt is available\n *\n * @returns True if BigInt type is supported, false otherwise\n */\nexport function hasBigInt(): boolean {\n\ttry {\n\t\tconst test = BigInt(\"1\");\n\t\treturn typeof test === \"bigint\";\n\t} catch {\n\t\treturn false;\n\t}\n}\n\n/**\n * Get runtime version information\n *\n * @returns Version string if available, undefined otherwise\n *\n * @example\n * ```typescript\n * const version = getRuntimeVersion();\n * console.log(`Running on Node ${version}`); // \"Running on Node 18.12.0\"\n * ```\n */\nexport function getRuntimeVersion(): string | undefined {\n\tconst runtime = detectRuntime();\n\n\tswitch (runtime) {\n\t\tcase \"node\":\n\t\t\treturn process.version?.substring(1);\n\t\tcase \"deno\": {\n\t\t\tconst deno = (globalThis as unknown as Record<string, unknown>).Deno as Record<string, unknown> | undefined;\n\t\t\tconst version = deno?.version as Record<string, unknown> | undefined;\n\t\t\treturn version?.deno as string | undefined;\n\t\t}\n\t\tcase \"bun\": {\n\t\t\tconst bun = (globalThis as unknown as Record<string, unknown>).Bun as Record<string, unknown> | undefined;\n\t\t\treturn bun?.version as string | undefined;\n\t\t}\n\t\tdefault:\n\t\t\treturn undefined;\n\t}\n}\n\n/**\n * Get comprehensive WebAssembly capabilities for current runtime\n *\n * Returns detailed information about WASM and related APIs available\n * in the current runtime environment.\n *\n * @returns Object describing available WASM capabilities\n *\n * @example\n * ```typescript\n * import { getWasmCapabilities } from '@kreuzberg/wasm/runtime';\n *\n * const caps = getWasmCapabilities();\n * console.log(`WASM available: ${caps.hasWasm}`);\n * console.log(`Streaming WASM: ${caps.hasWasmStreaming}`);\n * console.log(`Workers available: ${caps.hasWorkers}`);\n *\n * if (caps.hasWasm && caps.hasWorkers) {\n * // Can offload WASM processing to workers\n * }\n * ```\n */\nexport function getWasmCapabilities(): WasmCapabilities {\n\tconst runtime = detectRuntime();\n\tconst version = getRuntimeVersion();\n\tconst capabilities: WasmCapabilities = {\n\t\truntime,\n\t\thasWasm: hasWasm(),\n\t\thasWasmStreaming: hasWasmStreaming(),\n\t\thasFileApi: hasFileApi(),\n\t\thasBlob: hasBlob(),\n\t\thasWorkers: hasWorkers(),\n\t\thasSharedArrayBuffer: hasSharedArrayBuffer(),\n\t\thasModuleWorkers: hasModuleWorkers(),\n\t\thasBigInt: hasBigInt(),\n\t\t...(version !== undefined ? { runtimeVersion: version } : {}),\n\t};\n\treturn capabilities;\n}\n\n/**\n * Get comprehensive runtime information\n *\n * Returns detailed information about the current runtime environment,\n * capabilities, and identifying information.\n *\n * @returns Object with runtime details and capabilities\n *\n * @example\n * ```typescript\n * const info = getRuntimeInfo();\n * console.log(info.runtime); // 'browser' | 'node' | 'deno' | 'bun'\n * console.log(info.isBrowser); // true/false\n * console.log(info.userAgent); // Browser user agent string\n * console.log(info.capabilities); // Detailed capability information\n * ```\n */\nexport function getRuntimeInfo() {\n\tconst runtime = detectRuntime();\n\tconst capabilities = getWasmCapabilities();\n\n\treturn {\n\t\truntime,\n\t\tisBrowser: isBrowser(),\n\t\tisNode: isNode(),\n\t\tisDeno: isDeno(),\n\t\tisBun: isBun(),\n\t\tisWeb: isWebEnvironment(),\n\t\tisServer: isServerEnvironment(),\n\t\truntimeVersion: getRuntimeVersion(),\n\t\tuserAgent: typeof navigator !== \"undefined\" ? navigator.userAgent : \"N/A\",\n\t\tcapabilities,\n\t};\n}\n"],"mappings":"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","names":[]}
package/dist/runtime.js CHANGED
@@ -83,7 +83,6 @@ function getRuntimeVersion() {
83
83
  switch (runtime) {
84
84
  case "node":
85
85
  return process.version?.substring(1);
86
- // Remove 'v' prefix
87
86
  case "deno": {
88
87
  const deno = globalThis.Deno;
89
88
  const version = deno?.version;