@willwade/aac-processors 0.0.29 → 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.
Files changed (92) hide show
  1. package/README.md +52 -852
  2. package/dist/browser/core/baseProcessor.js +241 -0
  3. package/dist/browser/core/stringCasing.js +179 -0
  4. package/dist/browser/core/treeStructure.js +255 -0
  5. package/dist/browser/index.browser.js +73 -0
  6. package/dist/browser/processors/applePanelsProcessor.js +582 -0
  7. package/dist/browser/processors/astericsGridProcessor.js +1509 -0
  8. package/dist/browser/processors/dotProcessor.js +221 -0
  9. package/dist/browser/processors/gridset/commands.js +962 -0
  10. package/dist/browser/processors/gridset/crypto.js +53 -0
  11. package/dist/browser/processors/gridset/password.js +43 -0
  12. package/dist/browser/processors/gridset/pluginTypes.js +277 -0
  13. package/dist/browser/processors/gridset/resolver.js +137 -0
  14. package/dist/browser/processors/gridset/symbolAlignment.js +276 -0
  15. package/dist/browser/processors/gridset/symbols.js +421 -0
  16. package/dist/browser/processors/gridsetProcessor.js +2002 -0
  17. package/dist/browser/processors/obfProcessor.js +705 -0
  18. package/dist/browser/processors/opmlProcessor.js +274 -0
  19. package/dist/browser/types/aac.js +38 -0
  20. package/dist/browser/utilities/analytics/utils/idGenerator.js +89 -0
  21. package/dist/browser/utilities/translation/translationProcessor.js +200 -0
  22. package/dist/browser/utils/io.js +95 -0
  23. package/dist/browser/validation/baseValidator.js +156 -0
  24. package/dist/browser/validation/gridsetValidator.js +355 -0
  25. package/dist/browser/validation/obfValidator.js +500 -0
  26. package/dist/browser/validation/validationTypes.js +46 -0
  27. package/dist/cli/index.js +5 -5
  28. package/dist/core/analyze.d.ts +2 -2
  29. package/dist/core/analyze.js +2 -2
  30. package/dist/core/baseProcessor.d.ts +5 -4
  31. package/dist/core/baseProcessor.js +22 -27
  32. package/dist/core/treeStructure.d.ts +5 -5
  33. package/dist/core/treeStructure.js +1 -4
  34. package/dist/index.browser.d.ts +37 -0
  35. package/dist/index.browser.js +99 -0
  36. package/dist/index.d.ts +1 -48
  37. package/dist/index.js +1 -136
  38. package/dist/index.node.d.ts +48 -0
  39. package/dist/index.node.js +152 -0
  40. package/dist/processors/applePanelsProcessor.d.ts +5 -4
  41. package/dist/processors/applePanelsProcessor.js +58 -62
  42. package/dist/processors/astericsGridProcessor.d.ts +7 -6
  43. package/dist/processors/astericsGridProcessor.js +31 -42
  44. package/dist/processors/dotProcessor.d.ts +5 -4
  45. package/dist/processors/dotProcessor.js +25 -33
  46. package/dist/processors/excelProcessor.d.ts +4 -3
  47. package/dist/processors/excelProcessor.js +6 -3
  48. package/dist/processors/gridset/crypto.d.ts +18 -0
  49. package/dist/processors/gridset/crypto.js +57 -0
  50. package/dist/processors/gridset/helpers.d.ts +1 -1
  51. package/dist/processors/gridset/helpers.js +18 -8
  52. package/dist/processors/gridset/password.d.ts +20 -3
  53. package/dist/processors/gridset/password.js +17 -3
  54. package/dist/processors/gridset/wordlistHelpers.d.ts +3 -3
  55. package/dist/processors/gridset/wordlistHelpers.js +21 -20
  56. package/dist/processors/gridsetProcessor.d.ts +7 -12
  57. package/dist/processors/gridsetProcessor.js +118 -77
  58. package/dist/processors/obfProcessor.d.ts +9 -7
  59. package/dist/processors/obfProcessor.js +131 -56
  60. package/dist/processors/obfsetProcessor.d.ts +5 -4
  61. package/dist/processors/obfsetProcessor.js +10 -16
  62. package/dist/processors/opmlProcessor.d.ts +5 -4
  63. package/dist/processors/opmlProcessor.js +27 -34
  64. package/dist/processors/snapProcessor.d.ts +8 -7
  65. package/dist/processors/snapProcessor.js +15 -12
  66. package/dist/processors/touchchatProcessor.d.ts +8 -7
  67. package/dist/processors/touchchatProcessor.js +22 -17
  68. package/dist/types/aac.d.ts +0 -2
  69. package/dist/types/aac.js +2 -0
  70. package/dist/utils/io.d.ts +12 -0
  71. package/dist/utils/io.js +107 -0
  72. package/dist/validation/gridsetValidator.js +7 -7
  73. package/dist/validation/snapValidator.js +28 -35
  74. package/docs/BROWSER_USAGE.md +618 -0
  75. package/examples/README.md +77 -0
  76. package/examples/browser-test-server.js +81 -0
  77. package/examples/browser-test.html +331 -0
  78. package/examples/vitedemo/QUICKSTART.md +74 -0
  79. package/examples/vitedemo/README.md +157 -0
  80. package/examples/vitedemo/index.html +376 -0
  81. package/examples/vitedemo/package-lock.json +1221 -0
  82. package/examples/vitedemo/package.json +18 -0
  83. package/examples/vitedemo/src/main.ts +519 -0
  84. package/examples/vitedemo/test-files/example.dot +14 -0
  85. package/examples/vitedemo/test-files/example.grd +1 -0
  86. package/examples/vitedemo/test-files/example.gridset +0 -0
  87. package/examples/vitedemo/test-files/example.obz +0 -0
  88. package/examples/vitedemo/test-files/example.opml +18 -0
  89. package/examples/vitedemo/test-files/simple.obf +53 -0
  90. package/examples/vitedemo/tsconfig.json +24 -0
  91. package/examples/vitedemo/vite.config.ts +34 -0
  92. package/package.json +20 -4
@@ -0,0 +1,618 @@
1
+ # Browser Usage Guide
2
+
3
+ This guide explains how to use AACProcessors in browser environments.
4
+
5
+ ## ⚠️ Important: Bundler Required
6
+
7
+ **AACProcessors uses TypeScript and outputs CommonJS modules, which requires a bundler for browser use.**
8
+
9
+ You **cannot** directly import from `dist/index.browser.js` in a browser without a bundler.
10
+
11
+ ### Recommended Bundlers
12
+
13
+ - **Vite** (recommended, easiest setup)
14
+ - **Webpack**
15
+ - **Rollup**
16
+ - **esbuild**
17
+ - **Parcel**
18
+
19
+ ## Installation
20
+
21
+ ```bash
22
+ npm install @willwade/aac-processors
23
+ ```
24
+
25
+ ## Quick Start with Vite
26
+
27
+ ### 1. Create a Vite Project
28
+
29
+ ```bash
30
+ npm create vite@latest my-aac-app -- --template vanilla-ts
31
+ cd my-aac-app
32
+ npm install
33
+ ```
34
+
35
+ ### 2. Install AACProcessors
36
+
37
+ ```bash
38
+ npm install @willwade/aac-processors
39
+ ```
40
+
41
+ ### 3. Configure Vite
42
+
43
+ Create `vite.config.ts`:
44
+
45
+ ```typescript
46
+ import { defineConfig } from 'vite';
47
+ import path from 'path';
48
+
49
+ export default defineConfig({
50
+ resolve: {
51
+ alias: {
52
+ 'aac-processors': path.resolve(__dirname, 'node_modules/@willwade/aac-processors/src/index.browser.ts')
53
+ }
54
+ }
55
+ });
56
+ ```
57
+
58
+ ### 4. Use in Your Code
59
+
60
+ ```typescript
61
+ // src/main.ts
62
+ import { getProcessor } from 'aac-processors';
63
+
64
+ async function loadFile(file: File) {
65
+ const arrayBuffer = await file.arrayBuffer();
66
+ const processor = getProcessor('.obf');
67
+ const tree = await processor.loadIntoTree(arrayBuffer);
68
+ console.log('Loaded tree:', tree);
69
+ }
70
+
71
+ // Use with file input
72
+ document.getElementById('fileInput')?.addEventListener('change', async (e) => {
73
+ const file = (e.target as HTMLInputElement).files?.[0];
74
+ if (file) {
75
+ await loadFile(file);
76
+ }
77
+ });
78
+ ```
79
+
80
+ ### 5. Run the Dev Server
81
+
82
+ ```bash
83
+ npm run dev
84
+ ```
85
+
86
+ ## Quick Start with Webpack
87
+
88
+ ### 1. Install Dependencies
89
+
90
+ ```bash
91
+ npm install @willwade/aac-processors webpack webpack-cli ts-loader
92
+ ```
93
+
94
+ ### 2. Configure Webpack
95
+
96
+ Create `webpack.config.js`:
97
+
98
+ ```javascript
99
+ const path = require('path');
100
+
101
+ module.exports = {
102
+ mode: 'development',
103
+ entry: './src/index.ts',
104
+ output: {
105
+ filename: 'bundle.js',
106
+ path: path.resolve(__dirname, 'dist')
107
+ },
108
+ resolve: {
109
+ extensions: ['.ts', '.js'],
110
+ alias: {
111
+ 'aac-processors': path.resolve(__dirname, 'node_modules/@willwade/aac-processors/src/index.browser.ts')
112
+ }
113
+ },
114
+ module: {
115
+ rules: [
116
+ {
117
+ test: /\.ts$/,
118
+ use: 'ts-loader',
119
+ exclude: /node_modules/
120
+ }
121
+ ]
122
+ }
123
+ };
124
+ ```
125
+
126
+ ### 3. Use in Your Code
127
+
128
+ ```typescript
129
+ // src/index.ts
130
+ import { getProcessor } from 'aac-processors';
131
+
132
+ // Same usage as Vite example above
133
+ ```
134
+
135
+ ## Using with CDN (Not Recommended)
136
+
137
+ While you can use the library via CDN, it's **not recommended** because:
138
+
139
+ 1. The library is not currently published as an ESM bundle
140
+ 2. You'll need to use a compatibility layer like SystemJS
141
+ 3. TypeScript types won't work properly
142
+
143
+ For production use, **always use a bundler**.
144
+
145
+ ## Basic Usage
146
+
147
+ ### Loading a File from File Input
148
+
149
+ The most common browser use case is loading files from an `<input type="file">` element:
150
+
151
+ ```html
152
+ <input type="file" id="fileInput" accept=".obf,.obz,.gridset,.dot,.opml">
153
+ <script type="module">
154
+ import { getProcessor } from 'aac-processors';
155
+
156
+ const fileInput = document.getElementById('fileInput');
157
+
158
+ fileInput.addEventListener('change', async (event) => {
159
+ const file = event.target.files[0];
160
+ if (!file) return;
161
+
162
+ try {
163
+ // Get file extension
164
+ const extension = '.' + file.name.split('.').pop();
165
+
166
+ // Get appropriate processor
167
+ const processor = getProcessor(extension);
168
+
169
+ if (!processor) {
170
+ console.error('No processor found for:', extension);
171
+ return;
172
+ }
173
+
174
+ // Read file as ArrayBuffer
175
+ const arrayBuffer = await file.arrayBuffer();
176
+
177
+ // Load into tree
178
+ const tree = await processor.loadIntoTree(arrayBuffer);
179
+
180
+ console.log('Loaded tree:', tree);
181
+ console.log('Pages:', Object.keys(tree.pages));
182
+ console.log('Root page:', tree.pages[tree.rootId]);
183
+
184
+ } catch (error) {
185
+ console.error('Error loading file:', error);
186
+ }
187
+ });
188
+ </script>
189
+ ```
190
+
191
+ ### Extracting Texts from a File
192
+
193
+ ```html
194
+ <script type="module">
195
+ import { ObfProcessor } from 'aac-processors';
196
+
197
+ async function extractTextsFromFile(file) {
198
+ const processor = new ObfProcessor();
199
+ const arrayBuffer = await file.arrayBuffer();
200
+ const texts = await processor.extractTexts(arrayBuffer);
201
+
202
+ console.log(`Extracted ${texts.length} texts:`, texts);
203
+ return texts;
204
+ }
205
+
206
+ // Usage
207
+ document.getElementById('extractButton').addEventListener('click', async () => {
208
+ const file = document.getElementById('fileInput').files[0];
209
+ const texts = await extractTextsFromFile(file);
210
+ displayTexts(texts);
211
+ });
212
+ </script>
213
+ ```
214
+
215
+ ### Processing Translations
216
+
217
+ ```html
218
+ <script type="module">
219
+ import { getProcessor } from 'aac-processors';
220
+
221
+ async function translateFile(file, translations) {
222
+ const extension = '.' + file.name.split('.').pop();
223
+ const processor = getProcessor(extension);
224
+ const arrayBuffer = await file.arrayBuffer();
225
+
226
+ // Process texts with translations
227
+ const translatedBuffer = await processor.processTexts(
228
+ arrayBuffer,
229
+ translations,
230
+ null // Don't save to file, return buffer
231
+ );
232
+
233
+ // Create download link
234
+ const blob = new Blob([translatedBuffer], { type: 'application/octet-stream' });
235
+ const url = URL.createObjectURL(blob);
236
+ const a = document.createElement('a');
237
+ a.href = url;
238
+ a.download = 'translated-' + file.name;
239
+ a.click();
240
+ URL.revokeObjectURL(url);
241
+ }
242
+
243
+ // Usage
244
+ const translations = new Map([
245
+ ['Hello', 'Hola'],
246
+ ['Goodbye', 'Adiós'],
247
+ ['Yes', 'Sí'],
248
+ ['No', 'No']
249
+ ]);
250
+
251
+ translateFile(myFile, translations);
252
+ </script>
253
+ ```
254
+
255
+ ## Supported File Types
256
+
257
+ ### Browser-Compatible Processors
258
+
259
+ These processors work in browser environments:
260
+
261
+ | Processor | Extensions | Description |
262
+ |-----------------|-----------------|----------------------------------|
263
+ | DotProcessor | `.dot` | OpenSymbols Board files |
264
+ | OpmlProcessor | `.opml` | OPML outline files |
265
+ | ObfProcessor | `.obf`, `.obz` | Open Board Format files |
266
+ | GridsetProcessor| `.gridset` | Grid 3 gridset files (not .gridsetx) |
267
+ | ApplePanelsProcessor | `.plist` | Apple Panels files |
268
+ | AstericsGridProcessor | `.grd` | Asterics Grid files |
269
+
270
+ ### Node-Only Processors
271
+
272
+ These processors require Node.js and **do not work** in browser:
273
+
274
+ - **SnapProcessor** (.spb, .sps) - Requires SQLite
275
+ - **TouchChatProcessor** (.ce) - Requires SQLite
276
+ - **ExcelProcessor** (.xlsx) - Uses fs at top level
277
+
278
+ ## Factory Functions
279
+
280
+ ### getProcessor(extension)
281
+
282
+ Get a processor instance for a file extension:
283
+
284
+ ```javascript
285
+ import { getProcessor } from 'aac-processors';
286
+
287
+ const processor = getProcessor('.obf');
288
+ console.log(processor.constructor.name); // 'ObfProcessor'
289
+ ```
290
+
291
+ ### getSupportedExtensions()
292
+
293
+ Get list of supported file extensions:
294
+
295
+ ```javascript
296
+ import { getSupportedExtensions } from 'aac-processors';
297
+
298
+ const extensions = getSupportedExtensions();
299
+ // ['.dot', '.opml', '.obf', '.obz', '.gridset', '.plist', '.grd']
300
+ ```
301
+
302
+ ### isExtensionSupported(extension)
303
+
304
+ Check if an extension is supported:
305
+
306
+ ```javascript
307
+ import { isExtensionSupported } from 'aac-processors';
308
+
309
+ console.log(isExtensionSupported('.obf')); // true
310
+ console.log(isExtensionSupported('.pdf')); // false
311
+ ```
312
+
313
+ ## Working with Tree Structure
314
+
315
+ ### Accessing Pages
316
+
317
+ ```javascript
318
+ const tree = await processor.loadIntoTree(arrayBuffer);
319
+
320
+ // Get all page IDs
321
+ const pageIds = Object.keys(tree.pages);
322
+ console.log('Pages:', pageIds);
323
+
324
+ // Get root page
325
+ const rootPage = tree.pages[tree.rootId];
326
+ console.log('Root page:', rootPage.name);
327
+
328
+ // Get specific page
329
+ const page = tree.pages['page-id'];
330
+ console.log('Page buttons:', page.buttons.length);
331
+ ```
332
+
333
+ ### Accessing Buttons
334
+
335
+ ```javascript
336
+ const page = tree.pages['page-id'];
337
+
338
+ // Iterate through buttons
339
+ page.buttons.forEach(button => {
340
+ console.log('Button:', button.label);
341
+ console.log('Message:', button.message);
342
+ console.log('Type:', button.type);
343
+
344
+ // Check for navigation
345
+ if (button.type === 'NAVIGATE') {
346
+ console.log('Navigates to:', button.targetPageId);
347
+ }
348
+ });
349
+
350
+ // Get buttons with specific type
351
+ const speakButtons = page.buttons.filter(b => b.type === 'SPEAK');
352
+ ```
353
+
354
+ ### Accessing Images
355
+
356
+ ```javascript
357
+ // For OBF/OBZ files with embedded images
358
+ const button = page.buttons[0];
359
+ if (button.imagePath) {
360
+ console.log('Image path:', button.imagePath);
361
+
362
+ // Extract image as data URL (browser-compatible)
363
+ const processor = new ObfProcessor();
364
+ const dataUrl = await processor.extractImageAsDataUrl(arrayBuffer, button.imagePath);
365
+ console.log('Data URL:', dataUrl);
366
+
367
+ // Use in img tag
368
+ const img = document.createElement('img');
369
+ img.src = dataUrl;
370
+ document.body.appendChild(img);
371
+ }
372
+ ```
373
+
374
+ ## Complete Example: AAC File Viewer
375
+
376
+ ```html
377
+ <!DOCTYPE html>
378
+ <html lang="en">
379
+ <head>
380
+ <meta charset="UTF-8">
381
+ <title>AAC File Viewer</title>
382
+ <style>
383
+ .button-grid {
384
+ display: grid;
385
+ grid-template-columns: repeat(auto-fill, minmax(100px, 1fr));
386
+ gap: 10px;
387
+ padding: 20px;
388
+ }
389
+ .aac-button {
390
+ border: 2px solid #333;
391
+ border-radius: 8px;
392
+ padding: 15px;
393
+ text-align: center;
394
+ cursor: pointer;
395
+ background: #f0f0f0;
396
+ }
397
+ .aac-button:hover {
398
+ background: #e0e0e0;
399
+ }
400
+ </style>
401
+ </head>
402
+ <body>
403
+ <h1>AAC File Viewer</h1>
404
+ <input type="file" id="fileInput" accept=".obf,.obz,.gridset,.dot,.opml,.plist,.grd">
405
+ <div id="content"></div>
406
+
407
+ <script type="module">
408
+ import { getProcessor } from 'aac-processors';
409
+
410
+ const fileInput = document.getElementById('fileInput');
411
+ const contentDiv = document.getElementById('content');
412
+
413
+ fileInput.addEventListener('change', async (event) => {
414
+ const file = event.target.files[0];
415
+ if (!file) return;
416
+
417
+ const extension = '.' + file.name.split('.').pop();
418
+ const processor = getProcessor(extension);
419
+ const arrayBuffer = await file.arrayBuffer();
420
+ const tree = await processor.loadIntoTree(arrayBuffer);
421
+
422
+ displayPage(tree.rootId);
423
+ });
424
+
425
+ function displayPage(pageId) {
426
+ const page = tree.pages[pageId];
427
+ contentDiv.innerHTML = `<h2>${page.name}</h2>`;
428
+
429
+ const grid = document.createElement('div');
430
+ grid.className = 'button-grid';
431
+
432
+ page.buttons.forEach(button => {
433
+ const btnDiv = document.createElement('div');
434
+ btnDiv.className = 'aac-button';
435
+ btnDiv.textContent = button.label;
436
+ btnDiv.addEventListener('click', () => {
437
+ if (button.type === 'NAVIGATE') {
438
+ displayPage(button.targetPageId);
439
+ } else {
440
+ console.log('Button clicked:', button.label, button.message);
441
+ }
442
+ });
443
+ grid.appendChild(btnDiv);
444
+ });
445
+
446
+ contentDiv.appendChild(grid);
447
+ }
448
+ </script>
449
+ </body>
450
+ </html>
451
+ ```
452
+
453
+ ## Browser-Specific Considerations
454
+
455
+ ### No File Paths
456
+
457
+ Browsers don't have access to file paths. Always use:
458
+
459
+ - `File` objects from `<input type="file">`
460
+ - `ArrayBuffer` or `Uint8Array` from `fetch()` or `FileReader`
461
+ - `Blob` objects
462
+
463
+ ### CORS for Remote Files
464
+
465
+ When loading files from remote URLs, ensure CORS is enabled:
466
+
467
+ ```javascript
468
+ async function loadFromUrl(url) {
469
+ const response = await fetch(url);
470
+ const arrayBuffer = await response.arrayBuffer();
471
+ const processor = getProcessor('.obf');
472
+ const tree = await processor.loadIntoTree(arrayBuffer);
473
+ return tree;
474
+ }
475
+
476
+ // This will fail if the server doesn't send proper CORS headers
477
+ loadFromUrl('https://example.com/file.obf');
478
+ ```
479
+
480
+ ### Memory Management
481
+
482
+ Large files can consume significant memory. Consider:
483
+
484
+ 1. **Process files one at a time** - Avoid loading multiple files simultaneously
485
+ 2. **Revoke object URLs** - `URL.revokeObjectURL(url)` when done with blobs
486
+ 3. **Clear references** - Set variables to `null` when done
487
+
488
+ ```javascript
489
+ let currentTree = null;
490
+
491
+ async function loadFile(file) {
492
+ // Clear previous
493
+ currentTree = null;
494
+
495
+ // Load new
496
+ const processor = getProcessor('.obf');
497
+ const arrayBuffer = await file.arrayBuffer();
498
+ currentTree = await processor.loadIntoTree(arrayBuffer);
499
+ }
500
+
501
+ function clearTree() {
502
+ currentTree = null;
503
+ // Trigger garbage collection hint
504
+ if (window.gc) window.gc();
505
+ }
506
+ ```
507
+
508
+ ### Performance Tips
509
+
510
+ 1. **Use Web Workers** for large files:
511
+ ```javascript
512
+ // worker.js
513
+ import { getProcessor } from 'aac-processors';
514
+
515
+ self.onmessage = async (event) => {
516
+ const { file } = event.data;
517
+ const processor = getProcessor('.obf');
518
+ const arrayBuffer = await file.arrayBuffer();
519
+ const tree = await processor.loadIntoTree(arrayBuffer);
520
+ self.postMessage({ tree });
521
+ };
522
+ ```
523
+
524
+ 2. **Show progress indicators**:
525
+ ```javascript
526
+ function showLoading(message) {
527
+ document.getElementById('status').textContent = message;
528
+ }
529
+
530
+ async function loadWithProgress(file) {
531
+ showLoading('Loading file...');
532
+ const arrayBuffer = await file.arrayBuffer();
533
+ showLoading('Processing file...');
534
+ const tree = await processor.loadIntoTree(arrayBuffer);
535
+ showLoading('Done!');
536
+ return tree;
537
+ }
538
+ ```
539
+
540
+ ## Error Handling
541
+
542
+ Always wrap processor calls in try/catch:
543
+
544
+ ```javascript
545
+ async function safeLoadFile(file) {
546
+ try {
547
+ const extension = '.' + file.name.split('.').pop();
548
+ const processor = getProcessor(extension);
549
+
550
+ if (!processor) {
551
+ throw new Error(`Unsupported file type: ${extension}`);
552
+ }
553
+
554
+ const arrayBuffer = await file.arrayBuffer();
555
+ const tree = await processor.loadIntoTree(arrayBuffer);
556
+
557
+ return tree;
558
+ } catch (error) {
559
+ console.error('Failed to load file:', error);
560
+ alert(`Error: ${error.message}`);
561
+ return null;
562
+ }
563
+ }
564
+ ```
565
+
566
+ ## Testing
567
+
568
+ See [Browser Test Page](../examples/browser-test.html) for interactive testing.
569
+
570
+ To run the test server:
571
+ ```bash
572
+ node examples/browser-test-server.js
573
+ ```
574
+
575
+ Then open: http://localhost:8080/examples/browser-test.html
576
+
577
+ ## Troubleshooting
578
+
579
+ ### Module Not Found
580
+
581
+ **Problem:** `Cannot resolve 'aac-processors'`
582
+
583
+ **Solution:** Ensure you're importing from the correct path:
584
+ ```javascript
585
+ // For npm installs
586
+ import { getProcessor } from 'aac-processors';
587
+
588
+ // For local development
589
+ import { getProcessor } from './dist/index.browser.js';
590
+ ```
591
+
592
+ ### Buffer vs ArrayBuffer
593
+
594
+ **Problem:** Type mismatch between Buffer and ArrayBuffer
595
+
596
+ **Solution:** Browsers use ArrayBuffer/Uint8Array, not Buffer:
597
+ ```javascript
598
+ // Browser
599
+ const arrayBuffer = await file.arrayBuffer();
600
+ const uint8Array = new Uint8Array(arrayBuffer);
601
+
602
+ // Both work with processors
603
+ await processor.loadIntoTree(arrayBuffer);
604
+ await processor.loadIntoTree(uint8Array);
605
+ ```
606
+
607
+ ### Gridset .gridsetx Files
608
+
609
+ **Problem:** `.gridsetx` files fail to load
610
+
611
+ **Solution:** Encrypted `.gridsetx` files require Node.js crypto. Use regular `.gridset` files in browser.
612
+
613
+ ## Additional Resources
614
+
615
+ - [API Documentation](./API.md)
616
+ - [Examples](../examples/)
617
+ - [Browser Test Page](../examples/browser-test.html)
618
+ - [Test Server](../examples/browser-test-server.js)
@@ -48,3 +48,80 @@ These pagesets are used by:
48
48
  - Integration examples
49
49
 
50
50
  To run demo scripts that use these pagesets, see the [scripts/README.md](../scripts/README.md).
51
+
52
+ ## Browser Testing
53
+
54
+ ### ⚠️ Important Note
55
+
56
+ AACProcessors is built with TypeScript and outputs CommonJS modules. To use it in a browser, you **must use a bundler** (Vite, Webpack, Rollup, etc.). The browser test page below only validates the library structure - it cannot run actual processors without a bundler.
57
+
58
+ ### Browser Test Page
59
+
60
+ A dedicated browser test page is available for validating the library structure:
61
+
62
+ **Start the test server:**
63
+ ```bash
64
+ node examples/browser-test-server.js
65
+ ```
66
+
67
+ **Open in your browser:**
68
+ ```
69
+ http://localhost:8080/examples/browser-test.html
70
+ ```
71
+
72
+ **What it tests:**
73
+ - ✅ Browser build files exist and are accessible
74
+ - ✅ Type definitions are present
75
+ - ✅ Processor exports are available
76
+ - ❌ **Does NOT run actual processors** (requires bundler)
77
+
78
+ ### What Gets Tested
79
+
80
+ The browser test page (`browser-test.html`) verifies:
81
+
82
+ 1. **Module Loading** - Can the browser load the ES modules?
83
+ 2. **Factory Functions** - Do `getProcessor()` and `getSupportedExtensions()` work?
84
+ 3. **Processor Instantiation** - Can processors be created?
85
+ 4. **File Loading** - Can files be loaded from `<input type="file">`?
86
+ 5. **Buffer Handling** - Do ArrayBuffers/Uint8Arrays work correctly?
87
+ 6. **Tree Structure** - Can AACTree be created from files?
88
+ 7. **Text Extraction** - Can texts be extracted from files?
89
+
90
+ ### Supported File Types in Browser
91
+
92
+ The browser test page supports all browser-compatible processors:
93
+
94
+ - **DotProcessor** (.dot) - OpenSymbols Board files
95
+ - **OpmlProcessor** (.opml) - OPML outline files
96
+ - **ObfProcessor** (.obf/.obz) - Open Board Format files
97
+ - **GridsetProcessor** (.gridset) - Grid 3 gridset files (not .gridsetx)
98
+ - **ApplePanelsProcessor** (.plist) - Apple Panels files
99
+ - **AstericsGridProcessor** (.grd) - Asterics Grid files
100
+
101
+ ### Manual Testing
102
+
103
+ 1. Open the browser console (F12 or Cmd+Option+I)
104
+ 2. Click "Select a file to test" to upload an AAC file
105
+ 3. Click "Test File" to process it
106
+ 4. Check the results panel for page count, button count, and extracted texts
107
+
108
+ ### Automated Tests
109
+
110
+ Click "Run All Browser Tests" to run automated checks:
111
+ - Factory function tests
112
+ - Extension support tests
113
+ - Processor instantiation tests
114
+ - Buffer handling tests
115
+
116
+ ### Node-Only Processors
117
+
118
+ The following processors are **not available** in the browser:
119
+ - **SnapProcessor** (.spb/.sps) - Requires SQLite
120
+ - **TouchChatProcessor** (.ce) - Requires SQLite
121
+ - **ExcelProcessor** (.xlsx) - Uses fs at top level
122
+
123
+ ### Notes
124
+
125
+ - Gridset `.gridsetx` files (encrypted) are not supported in browser
126
+ - All processors work with Buffer, Uint8Array, and ArrayBuffer inputs
127
+ - File paths are not supported in browser (use file inputs or fetch)