@willwade/aac-processors 0.1.5 → 0.1.6

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 (40) hide show
  1. package/README.md +14 -0
  2. package/dist/browser/index.browser.js +15 -1
  3. package/dist/browser/processors/gridset/password.js +11 -0
  4. package/dist/browser/processors/gridsetProcessor.js +42 -46
  5. package/dist/browser/processors/obfProcessor.js +47 -63
  6. package/dist/browser/processors/snapProcessor.js +1031 -0
  7. package/dist/browser/processors/touchchatProcessor.js +1004 -0
  8. package/dist/browser/utils/io.js +20 -0
  9. package/dist/browser/utils/sqlite.js +109 -0
  10. package/dist/browser/utils/zip.js +54 -0
  11. package/dist/browser/validation/snapValidator.js +200 -0
  12. package/dist/browser/validation/touchChatValidator.js +202 -0
  13. package/dist/index.browser.d.ts +7 -0
  14. package/dist/index.browser.js +19 -2
  15. package/dist/processors/gridset/helpers.js +3 -4
  16. package/dist/processors/gridset/index.d.ts +1 -1
  17. package/dist/processors/gridset/index.js +3 -2
  18. package/dist/processors/gridset/password.d.ts +3 -2
  19. package/dist/processors/gridset/password.js +12 -0
  20. package/dist/processors/gridset/wordlistHelpers.js +107 -51
  21. package/dist/processors/gridsetProcessor.js +40 -44
  22. package/dist/processors/obfProcessor.js +46 -62
  23. package/dist/processors/snapProcessor.js +60 -54
  24. package/dist/processors/touchchatProcessor.js +38 -36
  25. package/dist/utils/io.d.ts +2 -0
  26. package/dist/utils/io.js +22 -0
  27. package/dist/utils/sqlite.d.ts +21 -0
  28. package/dist/utils/sqlite.js +137 -0
  29. package/dist/utils/zip.d.ts +7 -0
  30. package/dist/utils/zip.js +80 -0
  31. package/docs/BROWSER_USAGE.md +2 -10
  32. package/examples/README.md +3 -75
  33. package/examples/vitedemo/README.md +13 -7
  34. package/examples/vitedemo/index.html +2 -2
  35. package/examples/vitedemo/package-lock.json +9 -0
  36. package/examples/vitedemo/package.json +1 -0
  37. package/examples/vitedemo/src/main.ts +48 -2
  38. package/examples/vitedemo/src/vite-env.d.ts +1 -0
  39. package/package.json +3 -1
  40. package/examples/browser-test-server.js +0 -81
@@ -7,6 +7,10 @@
7
7
  * **NOTE: Gridset .gridsetx files**
8
8
  * GridsetProcessor supports regular `.gridset` files in browser.
9
9
  * Encrypted `.gridsetx` files require Node.js for crypto operations and are not supported in browser.
10
+ *
11
+ * **NOTE: SQLite-backed formats**
12
+ * Snap (.sps/.spb) and TouchChat (.ce) require a WASM-backed SQLite engine.
13
+ * Configure `sql.js` in browser builds via `configureSqlJs()` before loading these formats.
10
14
  */
11
15
  var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
12
16
  if (k2 === undefined) k2 = k;
@@ -23,7 +27,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
23
27
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
24
28
  };
25
29
  Object.defineProperty(exports, "__esModule", { value: true });
26
- exports.AstericsGridProcessor = exports.ApplePanelsProcessor = exports.GridsetProcessor = exports.ObfProcessor = exports.OpmlProcessor = exports.DotProcessor = void 0;
30
+ exports.configureSqlJs = exports.AstericsGridProcessor = exports.ApplePanelsProcessor = exports.TouchChatProcessor = exports.SnapProcessor = exports.GridsetProcessor = exports.ObfProcessor = exports.OpmlProcessor = exports.DotProcessor = void 0;
27
31
  exports.getProcessor = getProcessor;
28
32
  exports.getSupportedExtensions = getSupportedExtensions;
29
33
  exports.isExtensionSupported = isExtensionSupported;
@@ -44,6 +48,10 @@ var obfProcessor_1 = require("./processors/obfProcessor");
44
48
  Object.defineProperty(exports, "ObfProcessor", { enumerable: true, get: function () { return obfProcessor_1.ObfProcessor; } });
45
49
  var gridsetProcessor_1 = require("./processors/gridsetProcessor");
46
50
  Object.defineProperty(exports, "GridsetProcessor", { enumerable: true, get: function () { return gridsetProcessor_1.GridsetProcessor; } });
51
+ var snapProcessor_1 = require("./processors/snapProcessor");
52
+ Object.defineProperty(exports, "SnapProcessor", { enumerable: true, get: function () { return snapProcessor_1.SnapProcessor; } });
53
+ var touchchatProcessor_1 = require("./processors/touchchatProcessor");
54
+ Object.defineProperty(exports, "TouchChatProcessor", { enumerable: true, get: function () { return touchchatProcessor_1.TouchChatProcessor; } });
47
55
  var applePanelsProcessor_1 = require("./processors/applePanelsProcessor");
48
56
  Object.defineProperty(exports, "ApplePanelsProcessor", { enumerable: true, get: function () { return applePanelsProcessor_1.ApplePanelsProcessor; } });
49
57
  var astericsGridProcessor_1 = require("./processors/astericsGridProcessor");
@@ -52,8 +60,12 @@ const dotProcessor_2 = require("./processors/dotProcessor");
52
60
  const opmlProcessor_2 = require("./processors/opmlProcessor");
53
61
  const obfProcessor_2 = require("./processors/obfProcessor");
54
62
  const gridsetProcessor_2 = require("./processors/gridsetProcessor");
63
+ const snapProcessor_2 = require("./processors/snapProcessor");
64
+ const touchchatProcessor_2 = require("./processors/touchchatProcessor");
55
65
  const applePanelsProcessor_2 = require("./processors/applePanelsProcessor");
56
66
  const astericsGridProcessor_2 = require("./processors/astericsGridProcessor");
67
+ var sqlite_1 = require("./utils/sqlite");
68
+ Object.defineProperty(exports, "configureSqlJs", { enumerable: true, get: function () { return sqlite_1.configureSqlJs; } });
57
69
  /**
58
70
  * Factory function to get the appropriate processor for a file extension
59
71
  * @param filePathOrExtension - File path or extension (e.g., '.dot', '/path/to/file.obf')
@@ -74,6 +86,11 @@ function getProcessor(filePathOrExtension) {
74
86
  return new obfProcessor_2.ObfProcessor();
75
87
  case '.gridset':
76
88
  return new gridsetProcessor_2.GridsetProcessor();
89
+ case '.spb':
90
+ case '.sps':
91
+ return new snapProcessor_2.SnapProcessor();
92
+ case '.ce':
93
+ return new touchchatProcessor_2.TouchChatProcessor();
77
94
  case '.plist':
78
95
  return new applePanelsProcessor_2.ApplePanelsProcessor();
79
96
  case '.grd':
@@ -87,7 +104,7 @@ function getProcessor(filePathOrExtension) {
87
104
  * @returns Array of supported file extensions
88
105
  */
89
106
  function getSupportedExtensions() {
90
- return ['.dot', '.opml', '.obf', '.obz', '.gridset', '.plist', '.grd'];
107
+ return ['.dot', '.opml', '.obf', '.obz', '.gridset', '.spb', '.sps', '.ce', '.plist', '.grd'];
91
108
  }
92
109
  /**
93
110
  * Check if a file extension is supported
@@ -50,6 +50,7 @@ const child_process_1 = require("child_process");
50
50
  const better_sqlite3_1 = __importDefault(require("better-sqlite3"));
51
51
  const dotnetTicks_1 = require("../../utils/dotnetTicks");
52
52
  const password_1 = require("./password");
53
+ const zip_1 = require("../../utils/zip");
53
54
  function normalizeZipPath(p) {
54
55
  const unified = p.replace(/\\/g, '/');
55
56
  try {
@@ -97,10 +98,8 @@ function getAllowedImageEntries(tree) {
97
98
  */
98
99
  async function openImage(gridsetBuffer, entryPath, password = (0, password_1.resolveGridsetPasswordFromEnv)()) {
99
100
  try {
100
- // eslint-disable-next-line @typescript-eslint/no-var-requires
101
- const JSZip = require('jszip');
102
- const zip = await JSZip.loadAsync(gridsetBuffer);
103
- const entries = (0, password_1.getZipEntriesWithPassword)(zip, password);
101
+ const { zip } = await (0, zip_1.openZipFromInput)(gridsetBuffer);
102
+ const entries = (0, password_1.getZipEntriesFromAdapter)(zip, password);
104
103
  const want = normalizeZipPath(entryPath);
105
104
  const entry = entries.find((e) => normalizeZipPath(e.entryName) === want);
106
105
  if (!entry)
@@ -15,7 +15,7 @@ import { CellBackgroundShape } from './styleHelpers';
15
15
  import { Grid3CellType } from './pluginTypes';
16
16
  import { Grid3CommandCategory } from './commands';
17
17
  export { ensureAlphaChannel, darkenColor, lightenColor, hexToRgba, rgbaToHex } from './colorUtils';
18
- export { resolveGridsetPassword, getZipEntriesWithPassword, resolveGridsetPasswordFromEnv, } from './password';
18
+ export { resolveGridsetPassword, getZipEntriesWithPassword, getZipEntriesFromAdapter, resolveGridsetPasswordFromEnv, } from './password';
19
19
  export { getPageTokenImageMap, getAllowedImageEntries, openImage, generateGrid3Guid, createSettingsXml, createFileMapXml, getCommonDocumentsPath, findGrid3UserPaths, findGrid3HistoryDatabases, findGrid3Vocabularies, findGrid3UserHistory, findGrid3Users, isGrid3Installed, readGrid3History, readGrid3HistoryForUser, readAllGrid3History, type Grid3UserPath, type Grid3VocabularyPath, type Grid3HistoryEntry, } from './helpers';
20
20
  export { parseSymbolReference, isSymbolReference, resolveSymbolReference, getAvailableSymbolLibraries, getSymbolLibraryInfo, extractSymbolReferences, analyzeSymbolUsage, createSymbolReference, getSymbolLibraryName, getSymbolPath, isKnownSymbolLibrary, getSymbolLibraryDisplayName, getDefaultGrid3Path, getSymbolLibrariesDir, getSymbolSearchIndexesDir, symbolReferenceToFilename, SYMBOL_LIBRARIES, type SymbolReference, type SymbolLibraryInfo, type SymbolResolutionOptions, type SymbolResolutionResult, type SymbolUsageStats, type SymbolLibraryName, } from './symbols';
21
21
  export { getSymbolsDir, getSymbolSearchDir } from './symbols';
@@ -10,8 +10,8 @@
10
10
  * - Image resolution helpers
11
11
  */
12
12
  Object.defineProperty(exports, "__esModule", { value: true });
13
- exports.parseSymbolReference = exports.readAllGrid3History = exports.readGrid3HistoryForUser = exports.readGrid3History = exports.isGrid3Installed = exports.findGrid3Users = exports.findGrid3UserHistory = exports.findGrid3Vocabularies = exports.findGrid3HistoryDatabases = exports.findGrid3UserPaths = exports.getCommonDocumentsPath = exports.createFileMapXml = exports.createSettingsXml = exports.generateGrid3Guid = exports.openImage = exports.getAllowedImageEntries = exports.getPageTokenImageMap = exports.resolveGridsetPasswordFromEnv = exports.getZipEntriesWithPassword = exports.resolveGridsetPassword = exports.rgbaToHex = exports.hexToRgba = exports.lightenColor = exports.darkenColor = exports.ensureAlphaChannel = exports.Grid3CommandCategory = exports.GRID3_COMMANDS = exports.extractCommandParameters = exports.getAllPluginIds = exports.getAllCommandIds = exports.getCommandsByCategory = exports.getCommandsByPlugin = exports.getCommandDefinition = exports.detectCommand = exports.isRegularCell = exports.isAutoContentCell = exports.isLiveCell = exports.isWorkspaceCell = exports.getCellTypeDisplayName = exports.AUTOCONTENT_TYPES = exports.LIVECELL_TYPES = exports.WORKSPACE_TYPES = exports.Grid3CellType = exports.detectPluginCellType = exports.createCategoryStyle = exports.createDefaultStylesXml = exports.CATEGORY_STYLES = exports.DEFAULT_GRID3_STYLES = exports.SHAPE_NAMES = exports.CellBackgroundShape = void 0;
14
- exports.GRID3_COMMAND_CATEGORIES = exports.GRID3_CELL_TYPES = exports.GRID3_CELL_SHAPES = exports.GRID3_PLUGIN_IDS = exports.GRID3_COMMAND_IDS = exports.getSymbolSearchStats = exports.countLibrarySymbols = exports.getSearchSuggestions = exports.getAllSearchTerms = exports.getSymbolDisplayName = exports.getSymbolFilename = exports.searchSymbolsWithReferences = exports.searchSymbols = exports.loadSearchIndexes = exports.parsePixFile = exports.createSymbolManifest = exports.exportSymbolReferencesToCsv = exports.suggestExtractionStrategy = exports.analyzeSymbolExtraction = exports.convertToAstericsImage = exports.extractSymbolLibraryImage = exports.extractButtonImage = exports.parseImageSymbolReference = exports.isSymbolLibraryReference = exports.resolveGrid3CellImage = exports.getSymbolSearchDir = exports.getSymbolsDir = exports.SYMBOL_LIBRARIES = exports.symbolReferenceToFilename = exports.getSymbolSearchIndexesDir = exports.getSymbolLibrariesDir = exports.getDefaultGrid3Path = exports.getSymbolLibraryDisplayName = exports.isKnownSymbolLibrary = exports.getSymbolPath = exports.getSymbolLibraryName = exports.createSymbolReference = exports.analyzeSymbolUsage = exports.extractSymbolReferences = exports.getSymbolLibraryInfo = exports.getAvailableSymbolLibraries = exports.resolveSymbolReference = exports.isSymbolReference = void 0;
13
+ exports.readAllGrid3History = exports.readGrid3HistoryForUser = exports.readGrid3History = exports.isGrid3Installed = exports.findGrid3Users = exports.findGrid3UserHistory = exports.findGrid3Vocabularies = exports.findGrid3HistoryDatabases = exports.findGrid3UserPaths = exports.getCommonDocumentsPath = exports.createFileMapXml = exports.createSettingsXml = exports.generateGrid3Guid = exports.openImage = exports.getAllowedImageEntries = exports.getPageTokenImageMap = exports.resolveGridsetPasswordFromEnv = exports.getZipEntriesFromAdapter = exports.getZipEntriesWithPassword = exports.resolveGridsetPassword = exports.rgbaToHex = exports.hexToRgba = exports.lightenColor = exports.darkenColor = exports.ensureAlphaChannel = exports.Grid3CommandCategory = exports.GRID3_COMMANDS = exports.extractCommandParameters = exports.getAllPluginIds = exports.getAllCommandIds = exports.getCommandsByCategory = exports.getCommandsByPlugin = exports.getCommandDefinition = exports.detectCommand = exports.isRegularCell = exports.isAutoContentCell = exports.isLiveCell = exports.isWorkspaceCell = exports.getCellTypeDisplayName = exports.AUTOCONTENT_TYPES = exports.LIVECELL_TYPES = exports.WORKSPACE_TYPES = exports.Grid3CellType = exports.detectPluginCellType = exports.createCategoryStyle = exports.createDefaultStylesXml = exports.CATEGORY_STYLES = exports.DEFAULT_GRID3_STYLES = exports.SHAPE_NAMES = exports.CellBackgroundShape = void 0;
14
+ exports.GRID3_COMMAND_CATEGORIES = exports.GRID3_CELL_TYPES = exports.GRID3_CELL_SHAPES = exports.GRID3_PLUGIN_IDS = exports.GRID3_COMMAND_IDS = exports.getSymbolSearchStats = exports.countLibrarySymbols = exports.getSearchSuggestions = exports.getAllSearchTerms = exports.getSymbolDisplayName = exports.getSymbolFilename = exports.searchSymbolsWithReferences = exports.searchSymbols = exports.loadSearchIndexes = exports.parsePixFile = exports.createSymbolManifest = exports.exportSymbolReferencesToCsv = exports.suggestExtractionStrategy = exports.analyzeSymbolExtraction = exports.convertToAstericsImage = exports.extractSymbolLibraryImage = exports.extractButtonImage = exports.parseImageSymbolReference = exports.isSymbolLibraryReference = exports.resolveGrid3CellImage = exports.getSymbolSearchDir = exports.getSymbolsDir = exports.SYMBOL_LIBRARIES = exports.symbolReferenceToFilename = exports.getSymbolSearchIndexesDir = exports.getSymbolLibrariesDir = exports.getDefaultGrid3Path = exports.getSymbolLibraryDisplayName = exports.isKnownSymbolLibrary = exports.getSymbolPath = exports.getSymbolLibraryName = exports.createSymbolReference = exports.analyzeSymbolUsage = exports.extractSymbolReferences = exports.getSymbolLibraryInfo = exports.getAvailableSymbolLibraries = exports.resolveSymbolReference = exports.isSymbolReference = exports.parseSymbolReference = void 0;
15
15
  // Style helpers
16
16
  var styleHelpers_1 = require("./styleHelpers");
17
17
  Object.defineProperty(exports, "CellBackgroundShape", { enumerable: true, get: function () { return styleHelpers_1.CellBackgroundShape; } });
@@ -59,6 +59,7 @@ Object.defineProperty(exports, "rgbaToHex", { enumerable: true, get: function ()
59
59
  var password_1 = require("./password");
60
60
  Object.defineProperty(exports, "resolveGridsetPassword", { enumerable: true, get: function () { return password_1.resolveGridsetPassword; } });
61
61
  Object.defineProperty(exports, "getZipEntriesWithPassword", { enumerable: true, get: function () { return password_1.getZipEntriesWithPassword; } });
62
+ Object.defineProperty(exports, "getZipEntriesFromAdapter", { enumerable: true, get: function () { return password_1.getZipEntriesFromAdapter; } });
62
63
  Object.defineProperty(exports, "resolveGridsetPasswordFromEnv", { enumerable: true, get: function () { return password_1.resolveGridsetPasswordFromEnv; } });
63
64
  // Helper functions
64
65
  var helpers_1 = require("./helpers");
@@ -1,6 +1,7 @@
1
1
  import type JSZip from 'jszip';
2
2
  import { ProcessorOptions } from '../../core/baseProcessor';
3
3
  import { ProcessorInput } from '../../utils/io';
4
+ import { type ZipAdapter } from '../../utils/zip';
4
5
  /**
5
6
  * Resolve the password to use for Grid3 archives.
6
7
  * Preference order:
@@ -18,11 +19,11 @@ export declare function resolveGridsetPasswordFromEnv(): string | undefined;
18
19
  * @param password - Optional password (kept for API compatibility, not used with JSZip)
19
20
  * @returns Array of entry objects with name and data
20
21
  */
21
- type ZipEntry = {
22
+ export type ZipEntry = {
22
23
  name: string;
23
24
  entryName: string;
24
25
  dir: boolean;
25
26
  getData: () => Promise<Uint8Array>;
26
27
  };
27
28
  export declare function getZipEntriesWithPassword(zip: JSZip, password?: string): ZipEntry[];
28
- export {};
29
+ export declare function getZipEntriesFromAdapter(zip: ZipAdapter, password?: string): ZipEntry[];
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.resolveGridsetPassword = resolveGridsetPassword;
4
4
  exports.resolveGridsetPasswordFromEnv = resolveGridsetPasswordFromEnv;
5
5
  exports.getZipEntriesWithPassword = getZipEntriesWithPassword;
6
+ exports.getZipEntriesFromAdapter = getZipEntriesFromAdapter;
6
7
  function getExtension(source) {
7
8
  const index = source.lastIndexOf('.');
8
9
  if (index === -1)
@@ -52,3 +53,14 @@ function getZipEntriesWithPassword(zip, password) {
52
53
  });
53
54
  return entries;
54
55
  }
56
+ function getZipEntriesFromAdapter(zip, password) {
57
+ if (password) {
58
+ console.warn('Zip password support is handled at the archive level for .gridsetx files.');
59
+ }
60
+ return zip.listFiles().map((entryName) => ({
61
+ name: entryName,
62
+ entryName,
63
+ dir: false,
64
+ getData: () => zip.readFile(entryName),
65
+ }));
66
+ }
@@ -9,6 +9,29 @@
9
9
  * Note: Wordlists are only supported in Grid3 format. Other AAC formats
10
10
  * do not have equivalent wordlist functionality.
11
11
  */
12
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
13
+ if (k2 === undefined) k2 = k;
14
+ var desc = Object.getOwnPropertyDescriptor(m, k);
15
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
16
+ desc = { enumerable: true, get: function() { return m[k]; } };
17
+ }
18
+ Object.defineProperty(o, k2, desc);
19
+ }) : (function(o, m, k, k2) {
20
+ if (k2 === undefined) k2 = k;
21
+ o[k2] = m[k];
22
+ }));
23
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
24
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
25
+ }) : function(o, v) {
26
+ o["default"] = v;
27
+ });
28
+ var __importStar = (this && this.__importStar) || function (mod) {
29
+ if (mod && mod.__esModule) return mod;
30
+ var result = {};
31
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
32
+ __setModuleDefault(result, mod);
33
+ return result;
34
+ };
12
35
  Object.defineProperty(exports, "__esModule", { value: true });
13
36
  exports.createWordlist = createWordlist;
14
37
  exports.wordlistToXml = wordlistToXml;
@@ -16,7 +39,9 @@ exports.extractWordlists = extractWordlists;
16
39
  exports.updateWordlist = updateWordlist;
17
40
  const fast_xml_parser_1 = require("fast-xml-parser");
18
41
  const password_1 = require("./password");
42
+ const zip_1 = require("../../utils/zip");
19
43
  const io_1 = require("../../utils/io");
44
+ const io_2 = require("../../utils/io");
20
45
  /**
21
46
  * Creates a WordList object from an array of words/phrases or a dictionary
22
47
  *
@@ -105,55 +130,52 @@ function wordlistToXml(wordlist) {
105
130
  async function extractWordlists(gridsetBuffer, password = (0, password_1.resolveGridsetPasswordFromEnv)()) {
106
131
  const wordlists = new Map();
107
132
  const parser = new fast_xml_parser_1.XMLParser();
108
- let zip;
109
133
  try {
110
- // eslint-disable-next-line @typescript-eslint/no-var-requires
111
- const JSZip = require('jszip');
112
- zip = await JSZip.loadAsync(gridsetBuffer);
113
- }
114
- catch (error) {
115
- throw new Error(`Invalid gridset buffer: ${error.message}`);
116
- }
117
- const entries = (0, password_1.getZipEntriesWithPassword)(zip, password);
118
- // Process each grid file
119
- for (const entry of entries) {
120
- if (entry.entryName.startsWith('Grids/') && entry.entryName.endsWith('grid.xml')) {
121
- try {
122
- const xmlContent = (0, io_1.decodeText)(await entry.getData());
123
- const data = parser.parse(xmlContent);
124
- const grid = data.Grid || data.grid;
125
- if (!grid || !grid.WordList) {
126
- continue;
127
- }
128
- // Extract grid name from path (e.g., "Grids/MyGrid/grid.xml" -> "MyGrid")
129
- const match = entry.entryName.match(/^Grids\/([^/]+)\//);
130
- const gridName = match ? match[1] : entry.entryName;
131
- // Parse wordlist items
132
- const wordlistData = grid.WordList;
133
- const itemsContainer = wordlistData.Items || wordlistData.items;
134
- if (!itemsContainer) {
135
- continue;
134
+ const { zip } = await (0, zip_1.openZipFromInput)(gridsetBuffer);
135
+ const entries = (0, password_1.getZipEntriesFromAdapter)(zip, password);
136
+ // Process each grid file
137
+ for (const entry of entries) {
138
+ if (entry.entryName.startsWith('Grids/') && entry.entryName.endsWith('grid.xml')) {
139
+ try {
140
+ const xmlContent = (0, io_2.decodeText)(await entry.getData());
141
+ const data = parser.parse(xmlContent);
142
+ const grid = data.Grid || data.grid;
143
+ if (!grid || !grid.WordList) {
144
+ continue;
145
+ }
146
+ // Extract grid name from path (e.g., "Grids/MyGrid/grid.xml" -> "MyGrid")
147
+ const match = entry.entryName.match(/^Grids\/([^/]+)\//);
148
+ const gridName = match ? match[1] : entry.entryName;
149
+ // Parse wordlist items
150
+ const wordlistData = grid.WordList;
151
+ const itemsContainer = wordlistData.Items || wordlistData.items;
152
+ if (!itemsContainer) {
153
+ continue;
154
+ }
155
+ const itemArray = Array.isArray(itemsContainer.WordListItem)
156
+ ? itemsContainer.WordListItem
157
+ : itemsContainer.WordListItem
158
+ ? [itemsContainer.WordListItem]
159
+ : [];
160
+ const items = itemArray.map((item) => ({
161
+ text: item.Text?.s?.r || item.text?.s?.r || '',
162
+ image: item.Image || item.image || undefined,
163
+ partOfSpeech: item.PartOfSpeech || item.partOfSpeech || 'Unknown',
164
+ }));
165
+ if (items.length > 0) {
166
+ wordlists.set(gridName, { items });
167
+ }
136
168
  }
137
- const itemArray = Array.isArray(itemsContainer.WordListItem)
138
- ? itemsContainer.WordListItem
139
- : itemsContainer.WordListItem
140
- ? [itemsContainer.WordListItem]
141
- : [];
142
- const items = itemArray.map((item) => ({
143
- text: item.Text?.s?.r || item.text?.s?.r || '',
144
- image: item.Image || item.image || undefined,
145
- partOfSpeech: item.PartOfSpeech || item.partOfSpeech || 'Unknown',
146
- }));
147
- if (items.length > 0) {
148
- wordlists.set(gridName, { items });
169
+ catch (error) {
170
+ // Skip grids with parsing errors
171
+ console.warn(`Failed to extract wordlist from ${entry.entryName}:`, error);
149
172
  }
150
173
  }
151
- catch (error) {
152
- // Skip grids with parsing errors
153
- console.warn(`Failed to extract wordlist from ${entry.entryName}:`, error);
154
- }
155
174
  }
156
175
  }
176
+ catch (error) {
177
+ throw new Error(`Invalid gridset buffer: ${error.message}`);
178
+ }
157
179
  return wordlists;
158
180
  }
159
181
  /**
@@ -178,16 +200,45 @@ async function updateWordlist(gridsetBuffer, gridName, wordlist, password = (0,
178
200
  indentBy: ' ',
179
201
  suppressEmptyNode: false,
180
202
  });
181
- let zip;
203
+ let entries;
204
+ let saveZip = null;
205
+ let updateEntry = null;
182
206
  try {
183
- // eslint-disable-next-line @typescript-eslint/no-var-requires
184
- const JSZip = require('jszip');
185
- zip = await JSZip.loadAsync(gridsetBuffer);
207
+ if ((0, io_1.isNodeRuntime)()) {
208
+ const AdmZip = (0, io_1.getNodeRequire)()('adm-zip');
209
+ const zip = new AdmZip(Buffer.from(gridsetBuffer));
210
+ entries = zip.getEntries().map((entry) => ({
211
+ entryName: entry.entryName,
212
+ getData: () => Promise.resolve(entry.getData()),
213
+ }));
214
+ updateEntry = (entryName, xml) => {
215
+ zip.addFile(entryName, Buffer.from(xml, 'utf8'));
216
+ };
217
+ saveZip = () => Promise.resolve(zip.toBuffer());
218
+ }
219
+ else {
220
+ const module = await Promise.resolve().then(() => __importStar(require('jszip')));
221
+ const JSZip = module.default || module;
222
+ const zip = await JSZip.loadAsync(gridsetBuffer);
223
+ entries = (0, password_1.getZipEntriesFromAdapter)({
224
+ listFiles: () => Object.keys(zip.files),
225
+ readFile: async (name) => {
226
+ const file = zip.file(name);
227
+ if (!file) {
228
+ throw new Error(`Zip entry not found: ${name}`);
229
+ }
230
+ return file.async('uint8array');
231
+ },
232
+ }, password);
233
+ updateEntry = (entryName, xml) => {
234
+ zip.file(entryName, xml, { binary: false });
235
+ };
236
+ saveZip = async () => zip.generateAsync({ type: 'uint8array' });
237
+ }
186
238
  }
187
239
  catch (error) {
188
240
  throw new Error(`Invalid gridset buffer: ${error.message}`);
189
241
  }
190
- const entries = (0, password_1.getZipEntriesWithPassword)(zip, password);
191
242
  let found = false;
192
243
  // Find and update the grid
193
244
  for (const entry of entries) {
@@ -196,7 +247,7 @@ async function updateWordlist(gridsetBuffer, gridName, wordlist, password = (0,
196
247
  const currentGridName = match ? match[1] : null;
197
248
  if (currentGridName === gridName) {
198
249
  try {
199
- const xmlContent = (0, io_1.decodeText)(await entry.getData());
250
+ const xmlContent = (0, io_2.decodeText)(await entry.getData());
200
251
  const data = parser.parse(xmlContent);
201
252
  const grid = data.Grid || data.grid;
202
253
  if (!grid) {
@@ -222,7 +273,9 @@ async function updateWordlist(gridsetBuffer, gridName, wordlist, password = (0,
222
273
  };
223
274
  // Rebuild the XML
224
275
  const updatedXml = builder.build(data);
225
- zip.file(entry.entryName, updatedXml, { binary: false });
276
+ if (updateEntry) {
277
+ updateEntry(entry.entryName, updatedXml);
278
+ }
226
279
  found = true;
227
280
  }
228
281
  catch (error) {
@@ -235,5 +288,8 @@ async function updateWordlist(gridsetBuffer, gridName, wordlist, password = (0,
235
288
  if (!found) {
236
289
  throw new Error(`Grid "${gridName}" not found in gridset`);
237
290
  }
238
- return await zip.generateAsync({ type: 'uint8array' });
291
+ if (!saveZip) {
292
+ throw new Error('Failed to serialize updated gridset.');
293
+ }
294
+ return await saveZip();
239
295
  }
@@ -40,31 +40,7 @@ const resolver_2 = require("./gridset/resolver");
40
40
  const idGenerator_1 = require("../utilities/analytics/utils/idGenerator");
41
41
  const symbolAlignment_1 = require("./gridset/symbolAlignment");
42
42
  const io_1 = require("../utils/io");
43
- let JSZipModule;
44
- async function getJSZip() {
45
- if (!JSZipModule) {
46
- try {
47
- // Try ES module import first (browser/Vite)
48
- const module = await Promise.resolve().then(() => __importStar(require('jszip')));
49
- JSZipModule = module.default || module;
50
- }
51
- catch (error) {
52
- // Fall back to CommonJS require (Node.js)
53
- try {
54
- // eslint-disable-next-line @typescript-eslint/no-var-requires
55
- const module = require('jszip');
56
- JSZipModule = module.default || module;
57
- }
58
- catch (err2) {
59
- throw new Error('Zip handling requires JSZip in this environment.');
60
- }
61
- }
62
- }
63
- if (!JSZipModule) {
64
- throw new Error('Zip handling requires JSZip in this environment.');
65
- }
66
- return JSZipModule;
67
- }
43
+ const zip_1 = require("../utils/zip");
68
44
  class GridsetProcessor extends baseProcessor_1.BaseProcessor {
69
45
  constructor(options) {
70
46
  super(options);
@@ -437,17 +413,15 @@ class GridsetProcessor extends baseProcessor_1.BaseProcessor {
437
413
  }
438
414
  async loadIntoTree(filePathOrBuffer) {
439
415
  const tree = new treeStructure_1.AACTree();
440
- let zip;
416
+ let zipResult;
441
417
  try {
442
- const JSZip = await getJSZip();
443
- const zipInput = (0, io_1.readBinaryFromInput)(filePathOrBuffer);
444
- zip = await JSZip.loadAsync(zipInput);
418
+ zipResult = await (0, zip_1.openZipFromInput)((0, io_1.readBinaryFromInput)(filePathOrBuffer));
445
419
  }
446
420
  catch (error) {
447
421
  throw new Error(`Invalid ZIP file format: ${error.message}`);
448
422
  }
449
423
  const password = this.getGridsetPassword(filePathOrBuffer);
450
- const entries = (0, password_1.getZipEntriesWithPassword)(zip, password);
424
+ const entries = (0, password_1.getZipEntriesFromAdapter)(zipResult.zip, password);
451
425
  const parser = new fast_xml_parser_1.XMLParser({ ignoreAttributes: false });
452
426
  const isEncryptedArchive = typeof filePathOrBuffer === 'string' && filePathOrBuffer.toLowerCase().endsWith('.gridsetx');
453
427
  const encryptedContentPassword = this.getGridsetPassword(filePathOrBuffer);
@@ -458,14 +432,11 @@ class GridsetProcessor extends baseProcessor_1.BaseProcessor {
458
432
  passwordProtected: !!password,
459
433
  };
460
434
  const readEntryBuffer = async (entry) => {
461
- // eslint-disable-next-line @typescript-eslint/no-unsafe-return, @typescript-eslint/no-unsafe-argument
462
435
  const raw = await entry.getData();
463
436
  if (!isEncryptedArchive) {
464
- // eslint-disable-next-line @typescript-eslint/no-unsafe-return
465
437
  return raw;
466
438
  }
467
- // eslint-disable-next-line @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-return
468
- return (0, crypto_1.decryptGridsetEntry)(raw, encryptedContentPassword);
439
+ return (0, crypto_1.decryptGridsetEntry)(Buffer.from(raw), encryptedContentPassword);
469
440
  };
470
441
  // Parse FileMap.xml if present to index dynamic files per grid
471
442
  const fileMapIndex = new Map();
@@ -785,7 +756,7 @@ class GridsetProcessor extends baseProcessor_1.BaseProcessor {
785
756
  const gridEntryPath = entry.entryName.replace(/\\/g, '/');
786
757
  const baseDir = gridEntryPath.replace(/\/grid\.xml$/, '/');
787
758
  const dynamicFiles = fileMapIndex.get(gridEntryPath) || [];
788
- const resolvedImageEntry = (0, resolver_1.resolveGrid3CellImage)(zip, {
759
+ const resolvedImageEntry = (0, resolver_1.resolveGrid3CellImage)(null, {
789
760
  baseDir,
790
761
  imageName: declaredImageName,
791
762
  x: cellX + 1,
@@ -1636,11 +1607,36 @@ class GridsetProcessor extends baseProcessor_1.BaseProcessor {
1636
1607
  return (0, io_1.readBinaryFromInput)(outputPath);
1637
1608
  }
1638
1609
  async saveFromTree(tree, outputPath) {
1639
- const JSZip = await getJSZip();
1640
- const zip = new JSZip();
1610
+ const useNodeZip = (0, io_1.isNodeRuntime)();
1611
+ let addText;
1612
+ let addBinary;
1613
+ let finalizeZip;
1614
+ if (useNodeZip) {
1615
+ const AdmZip = (0, io_1.getNodeRequire)()('adm-zip');
1616
+ const zip = new AdmZip();
1617
+ addText = (entryPath, content) => {
1618
+ zip.addFile(entryPath, Buffer.from(content, 'utf8'));
1619
+ };
1620
+ addBinary = (entryPath, content) => {
1621
+ zip.addFile(entryPath, Buffer.from(content));
1622
+ };
1623
+ finalizeZip = () => Promise.resolve(zip.toBuffer());
1624
+ }
1625
+ else {
1626
+ const module = await Promise.resolve().then(() => __importStar(require('jszip')));
1627
+ const JSZip = module.default || module;
1628
+ const zip = new JSZip();
1629
+ addText = (entryPath, content) => {
1630
+ zip.file(entryPath, content, { binary: false });
1631
+ };
1632
+ addBinary = (entryPath, content) => {
1633
+ zip.file(entryPath, content);
1634
+ };
1635
+ finalizeZip = async () => zip.generateAsync({ type: 'uint8array' });
1636
+ }
1641
1637
  if (Object.keys(tree.pages).length === 0) {
1642
1638
  // Create empty zip for empty tree
1643
- const zipBuffer = await zip.generateAsync({ type: 'uint8array' });
1639
+ const zipBuffer = await finalizeZip();
1644
1640
  (0, io_1.writeBinaryToPath)(outputPath, zipBuffer);
1645
1641
  return;
1646
1642
  }
@@ -1713,7 +1709,7 @@ class GridsetProcessor extends baseProcessor_1.BaseProcessor {
1713
1709
  suppressEmptyNode: true,
1714
1710
  });
1715
1711
  const settingsXmlContent = settingsBuilder.build(settingsData);
1716
- zip.file('Settings0/settings.xml', settingsXmlContent, { binary: false });
1712
+ addText('Settings0/settings.xml', settingsXmlContent);
1717
1713
  // Create Settings0/Styles/style.xml if there are styles
1718
1714
  if (uniqueStyles.size > 0) {
1719
1715
  const stylesArray = Array.from(uniqueStyles.values()).map(({ id, style }) => {
@@ -1746,7 +1742,7 @@ class GridsetProcessor extends baseProcessor_1.BaseProcessor {
1746
1742
  indentBy: ' ',
1747
1743
  });
1748
1744
  const styleXmlContent = styleBuilder.build(styleData);
1749
- zip.file('Settings0/Styles/styles.xml', styleXmlContent, { binary: false });
1745
+ addText('Settings0/Styles/styles.xml', styleXmlContent);
1750
1746
  }
1751
1747
  // Collect grid file paths for FileMap.xml
1752
1748
  const gridFilePaths = [];
@@ -1887,14 +1883,14 @@ class GridsetProcessor extends baseProcessor_1.BaseProcessor {
1887
1883
  // Add to zip in Grids folder with proper Grid3 naming
1888
1884
  const gridPath = `Grids/${page.name || page.id}/grid.xml`;
1889
1885
  gridFilePaths.push(gridPath);
1890
- zip.file(gridPath, xmlContent, { binary: false });
1886
+ addText(gridPath, xmlContent);
1891
1887
  });
1892
1888
  // Write image files to ZIP
1893
1889
  buttonImages.forEach((imgData) => {
1894
1890
  if (imgData.imageData && imgData.imageData.length > 0) {
1895
1891
  // Create image path in the grid's directory
1896
1892
  const imagePath = `Grids/${imgData.pageName}/${imgData.x}-${imgData.y}-0-text-0.${imgData.ext}`;
1897
- zip.file(imagePath, imgData.imageData);
1893
+ addBinary(imagePath, imgData.imageData);
1898
1894
  }
1899
1895
  });
1900
1896
  // Create FileMap.xml to map all grid files with their dynamic image files
@@ -1933,9 +1929,9 @@ class GridsetProcessor extends baseProcessor_1.BaseProcessor {
1933
1929
  indentBy: ' ',
1934
1930
  });
1935
1931
  const fileMapXmlContent = fileMapBuilder.build(fileMapData);
1936
- zip.file('FileMap.xml', fileMapXmlContent, { binary: false });
1932
+ addText('FileMap.xml', fileMapXmlContent);
1937
1933
  // Write the zip file
1938
- const zipBuffer = await zip.generateAsync({ type: 'uint8array' });
1934
+ const zipBuffer = await finalizeZip();
1939
1935
  (0, io_1.writeBinaryToPath)(outputPath, zipBuffer);
1940
1936
  }
1941
1937
  // Helper method to calculate column definitions based on page layout