@siglum/engine 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/hash.js ADDED
@@ -0,0 +1,102 @@
1
+ // Centralized hashing using BLAKE3 (WASM) for ~10x faster hashing on large documents
2
+ // Falls back to DJB2 for sync contexts before BLAKE3 is initialized
3
+
4
+ let blake3Module = null;
5
+ let blake3LoadPromise = null;
6
+
7
+ // 8 bytes = 64-bit hash, sufficient for change detection (not cryptographic security)
8
+ const HASH_LENGTH = 8;
9
+ // Skip WASM overhead for tiny inputs where DJB2 is faster
10
+ const SMALL_INPUT_THRESHOLD = 128;
11
+ // Pre-allocated options object to avoid allocation on every hash call
12
+ const BLAKE3_OPTIONS = Object.freeze({ length: HASH_LENGTH });
13
+
14
+ /**
15
+ * DJB2 hash - fast fallback for small inputs or before BLAKE3 loads
16
+ * @param {string} content
17
+ * @returns {string} hex hash
18
+ */
19
+ function djb2Hash(content) {
20
+ let hash = 5381 >>> 0;
21
+ const len = content.length;
22
+ for (let i = 0; i < len; i++) {
23
+ hash = ((hash * 33) ^ content.charCodeAt(i)) >>> 0;
24
+ }
25
+ return hash.toString(16).padStart(8, '0');
26
+ }
27
+
28
+ /**
29
+ * Initialize BLAKE3 module (called once, cached)
30
+ * @returns {Promise<object>}
31
+ */
32
+ async function loadBlake3() {
33
+ if (blake3Module) return blake3Module;
34
+ if (blake3LoadPromise) return blake3LoadPromise;
35
+
36
+ blake3LoadPromise = import('blake3-wasm/browser.js').then(module => {
37
+ blake3Module = module;
38
+ return module;
39
+ }).catch(err => {
40
+ console.warn('BLAKE3 load failed, using DJB2 fallback:', err.message);
41
+ return null;
42
+ });
43
+
44
+ return blake3LoadPromise;
45
+ }
46
+
47
+ /**
48
+ * Hash content using BLAKE3 (async, preferred for large documents)
49
+ * @param {string} content
50
+ * @returns {Promise<string>} hex hash
51
+ */
52
+ export async function hashAsync(content) {
53
+ // Use DJB2 for small inputs - WASM overhead not worth it
54
+ if (content.length < SMALL_INPUT_THRESHOLD) {
55
+ return djb2Hash(content);
56
+ }
57
+ const module = await loadBlake3();
58
+ if (module) {
59
+ return module.hash(content, BLAKE3_OPTIONS).toString('hex');
60
+ }
61
+ return djb2Hash(content);
62
+ }
63
+
64
+ /**
65
+ * Hash content synchronously - uses BLAKE3 if loaded, else DJB2
66
+ * Call initHash() early to ensure BLAKE3 is available for sync hashing
67
+ * @param {string} content
68
+ * @returns {string} hex hash
69
+ */
70
+ export function hashSync(content) {
71
+ // Use DJB2 for small inputs - WASM overhead not worth it
72
+ if (content.length < SMALL_INPUT_THRESHOLD) {
73
+ return djb2Hash(content);
74
+ }
75
+ if (blake3Module) {
76
+ return blake3Module.hash(content, BLAKE3_OPTIONS).toString('hex');
77
+ }
78
+ return djb2Hash(content);
79
+ }
80
+
81
+ /**
82
+ * Initialize BLAKE3 for use with hashSync
83
+ * Call this early in app startup for best performance
84
+ * @returns {Promise<boolean>} true if BLAKE3 loaded successfully
85
+ */
86
+ export async function initHash() {
87
+ const module = await loadBlake3();
88
+ return !!module;
89
+ }
90
+
91
+ /**
92
+ * Check if BLAKE3 is ready for sync hashing
93
+ * @returns {boolean}
94
+ */
95
+ export function isBlake3Ready() {
96
+ return !!blake3Module;
97
+ }
98
+
99
+ // Legacy export names for drop-in replacement
100
+ export { hashSync as hashContent };
101
+ export { hashSync as hashDocument };
102
+ export { hashSync as hashPreamble };
package/src/index.js ADDED
@@ -0,0 +1,32 @@
1
+ /**
2
+ * @module @siglum/engine
3
+ * Browser-based LaTeX compilation with lazy bundle loading.
4
+ *
5
+ * @example
6
+ * ```js
7
+ * import { SiglumCompiler } from '@siglum/engine';
8
+ *
9
+ * const compiler = new SiglumCompiler({
10
+ * bundlesUrl: '/bundles',
11
+ * onLog: console.log
12
+ * });
13
+ *
14
+ * await compiler.init();
15
+ * const result = await compiler.compile('\\documentclass{article}...');
16
+ * if (result.pdf) {
17
+ * // Use result.pdf (Uint8Array)
18
+ * }
19
+ * ```
20
+ */
21
+
22
+ export { SiglumCompiler, BusyTeXCompiler } from './compiler.js';
23
+ export { BundleManager, detectEngine, extractPreamble, hashPreamble } from './bundles.js';
24
+ export { CTANFetcher, getPackageFromFile, isValidPackageName, forceRefreshPackage } from './ctan.js';
25
+ export {
26
+ clearCTANCache,
27
+ hashDocument,
28
+ getCachedPdf,
29
+ saveCachedPdf,
30
+ listAllCachedPackages,
31
+ } from './storage.js';
32
+ export { createBatchedLogger } from './utils.js';