@storyteller-platform/epub 0.8.1 → 1.0.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/dist/xml.js ADDED
@@ -0,0 +1,248 @@
1
+ import xmldom from "@xmldom/xmldom";
2
+ const { DOMParser } = xmldom;
3
+ export const { XMLSerializer } = xmldom;
4
+ export function isElement(n) {
5
+ return n.nodeType === 1;
6
+ }
7
+ export function isText(n) {
8
+ return n.nodeType === 3;
9
+ }
10
+ export function isCdata(n) {
11
+ return n.nodeType === 4;
12
+ }
13
+ export function isComment(n) {
14
+ return n.nodeType === 8;
15
+ }
16
+ function setNamespace(element, namespace) {
17
+ ;
18
+ element.namespaceURI = namespace;
19
+ }
20
+ /**
21
+ * Give every element in `node`'s subtree the namespace its position implies,
22
+ * without overwriting any element that already has one.
23
+ *
24
+ * @privateremarks
25
+ *
26
+ * `x()` builds elements in no namespace. That serializes correctly, because a
27
+ * child in no namespace inherits the enclosing default namespace on the way
28
+ * out, but in memory the elements report `namespaceURI === null` and so are
29
+ * invisible to namespace-aware queries such as `getElementsByTagNameNS`.
30
+ * Calling this after inserting a node makes the tree report the namespace its
31
+ * position implies.
32
+ */
33
+ export function adoptNamespaces(node) {
34
+ const { parentNode } = node;
35
+ const inherited = parentNode && isElement(parentNode) ? parentNode.namespaceURI : null;
36
+ if (inherited && !node.namespaceURI) {
37
+ setNamespace(node, inherited);
38
+ }
39
+ for (const child of Array.from(node.children)) {
40
+ adoptNamespaces(child);
41
+ }
42
+ }
43
+ /**
44
+ * Declare `uri` as the default namespace of `element` and bring the elements
45
+ * already under it in line with that declaration.
46
+ *
47
+ * xmldom records a namespace declaration without applying it to the tree, so a
48
+ * document read without `xmlns` stays in no namespace in memory even once the
49
+ * declaration is added. Namespace-aware lookups cannot see any of it until the
50
+ * subtree is fixed up, and the document element has no element parent for
51
+ * `adoptNamespaces` to inherit from, so it has to be bound explicitly.
52
+ */
53
+ export function declareDefaultNamespace(element, uri) {
54
+ element.setAttributeNS(NS.xmlns, "xmlns", uri);
55
+ setNamespace(element, uri);
56
+ adoptNamespaces(element);
57
+ }
58
+ /**
59
+ * Insert `child` into `parent`, then adopt its namespace.
60
+ *
61
+ * If `reference` is omitted, appends child to parent.
62
+ */
63
+ export function insert(parent, child, reference) {
64
+ parent.insertBefore(child, reference ?? null);
65
+ if (isElement(child))
66
+ adoptNamespaces(child);
67
+ return child;
68
+ }
69
+ /**
70
+ * Replace `oldChild` with `newChild` in `parent`, then adopt the new child's
71
+ * namespace.
72
+ */
73
+ export function replace(parent, newChild, oldChild) {
74
+ parent.replaceChild(newChild, oldChild);
75
+ if (isElement(newChild))
76
+ adoptNamespaces(newChild);
77
+ return newChild;
78
+ }
79
+ /**
80
+ * Given an XHTML document, return the body element.
81
+ */
82
+ export function getXhtmlBody(document) {
83
+ const html = document.documentElement;
84
+ if (!html)
85
+ throw new Error("Invalid XHTML document: no html element");
86
+ const body = html.getElementsByTagName("body").item(0);
87
+ if (!body)
88
+ throw new Error("Invalid XHTML document: No body element");
89
+ return body;
90
+ }
91
+ /**
92
+ * Given an Element, find the first child matching
93
+ * the provided namespace, name and optional filter.
94
+ */
95
+ export function findXmlChildByNameNS(namespaceUri, name, element, filter) {
96
+ for (const child of Array.from(element.children)) {
97
+ if ((!namespaceUri || namespaceUri === child.namespaceURI) &&
98
+ name === child.localName &&
99
+ (!filter || filter(child))) {
100
+ return child;
101
+ }
102
+ }
103
+ return undefined;
104
+ }
105
+ /**
106
+ * Given an Element, find the first child matching
107
+ * the provided name and optional filter.
108
+ */
109
+ export function findXmlChildByName(name, element, filter) {
110
+ return findXmlChildByNameNS(null, name, element, filter);
111
+ }
112
+ /**
113
+ * Given an Element, find the first descendant matching
114
+ * the provided name and optional filter.
115
+ *
116
+ * Will perform a breadth first search for the element, returning
117
+ * the highest element in the tree matching the name and filter.
118
+ */
119
+ export function findXmlDescendantByNameNS(namespaceUri, name, element, filter) {
120
+ const queue = Array.from(element.children);
121
+ while (queue.length > 0) {
122
+ const candidate = queue.shift();
123
+ if (!candidate)
124
+ continue;
125
+ if ((!namespaceUri || candidate.namespaceURI === namespaceUri) &&
126
+ candidate.localName === name &&
127
+ (!filter || filter(candidate))) {
128
+ return candidate;
129
+ }
130
+ queue.push(...Array.from(candidate.children));
131
+ }
132
+ return undefined;
133
+ }
134
+ /**
135
+ * Given an Element, find the first descendant matching
136
+ * the provided name and optional filter.
137
+ *
138
+ * Will perform a breadth first search for the element, returning
139
+ * the highest element in the tree matching the name and filter.
140
+ */
141
+ export function findXmlDescendantByName(name, element, filter) {
142
+ return findXmlDescendantByNameNS(null, name, element, filter);
143
+ }
144
+ /**
145
+ * Given an XHTML document, add a `link` element to the
146
+ * `head` of the document.
147
+ */
148
+ export function addLinkToXhtmlHead(document, link) {
149
+ const html = document.documentElement;
150
+ if (!html)
151
+ throw new Error("Invalid XHTML document: no html element");
152
+ const head = html.getElementsByTagName("head").item(0);
153
+ if (!head)
154
+ throw new Error("Invalid XHTML document: no head element");
155
+ const linkEl = document.createElement("link");
156
+ linkEl.setAttribute("rel", link.rel);
157
+ linkEl.setAttribute("href", link.href);
158
+ linkEl.setAttribute("type", link.type);
159
+ head.appendChild(linkEl);
160
+ }
161
+ export function parse(xml, mediaType, onError) {
162
+ // A byte order mark ahead of the XML declaration is legal in a file, but once
163
+ // the file has been decoded into a string the mark occupies offset 0, and
164
+ // xmldom then rejects the declaration for not being at the start.
165
+ const source = xml.charCodeAt(0) === 0xfeff ? xml.slice(1) : xml;
166
+ return new DOMParser({
167
+ onError: (level, message) => {
168
+ onError?.({
169
+ level,
170
+ message,
171
+ });
172
+ },
173
+ }).parseFromString(source, mediaType);
174
+ }
175
+ export function serialize(doc, options) {
176
+ const serialized = new XMLSerializer().serializeToString(doc);
177
+ if (options?.validate) {
178
+ new DOMParser({
179
+ onError: (level, message) => {
180
+ if (level === "error" || level === "fatalError") {
181
+ throw new Error(message);
182
+ }
183
+ },
184
+ }).parseFromString(serialized, "text/xml");
185
+ }
186
+ return serialized;
187
+ }
188
+ const xmlDoc = new DOMParser({ onError: () => { } }).parseFromString("<root/>", "text/xml");
189
+ export const NS = {
190
+ xmlns: "http://www.w3.org/2000/xmlns/",
191
+ xml: "http://www.w3.org/XML/1998/namespace",
192
+ xhtml: "http://www.w3.org/1999/xhtml",
193
+ opf: "http://www.idpf.org/2007/opf",
194
+ dc: "http://purl.org/dc/elements/1.1/",
195
+ epub: "http://www.idpf.org/2007/ops",
196
+ };
197
+ const nsPrefixes = Object.keys(NS);
198
+ export function x(name, attributes, ...children) {
199
+ if (name === "xmlns" || name.startsWith("xmlns:")) {
200
+ throw new Error(`Invalid element name ${name}`);
201
+ }
202
+ const nameNs = nsPrefixes.find((prefix) => name.startsWith(`${prefix}:`));
203
+ const element = nameNs
204
+ ? xmlDoc.createElementNS(NS[nameNs], name)
205
+ : xmlDoc.createElement(name);
206
+ for (const [attrName, value] of Object.entries(attributes ?? {})) {
207
+ if (value === undefined)
208
+ continue;
209
+ const attrNs = attrName === "xmlns"
210
+ ? "xmlns"
211
+ : nsPrefixes.find((prefix) => attrName.startsWith(`${prefix}:`));
212
+ if (attrNs) {
213
+ element.setAttributeNS(NS[attrNs], attrName, value);
214
+ }
215
+ else {
216
+ element.setAttribute(attrName, value);
217
+ }
218
+ }
219
+ // An `xmlns` attribute declares this element's own default namespace, but
220
+ // xmldom does not bind it the way the DOM requires. Without this the element
221
+ // reports `namespaceURI === null`, so `adoptNamespaces` re-declares over the
222
+ // top of it: the output carries two `xmlns` attributes, which fails to parse
223
+ // (`Attribute xmlns redefined`), and the element lands in the wrong namespace.
224
+ const defaultNamespace = (attributes ?? {})["xmlns"];
225
+ if (defaultNamespace !== undefined) {
226
+ setNamespace(element, defaultNamespace);
227
+ }
228
+ for (const child of children) {
229
+ if (child == null)
230
+ continue;
231
+ if (typeof child === "string") {
232
+ element.appendChild(xmlDoc.createTextNode(child));
233
+ }
234
+ else {
235
+ element.appendChild(child);
236
+ }
237
+ }
238
+ return element;
239
+ }
240
+ export function text(data) {
241
+ return xmlDoc.createTextNode(data);
242
+ }
243
+ export function createDocument(namespaceUri, qualifiedName, docType) {
244
+ return xmlDoc.implementation.createDocument(namespaceUri, qualifiedName, docType);
245
+ }
246
+ export function createDocumentType(qualifiedName, publicId, systemId) {
247
+ return xmlDoc.implementation.createDocumentType(qualifiedName, publicId, systemId);
248
+ }
@@ -0,0 +1,2 @@
1
+ import type { ArchiveSource, ZipArchive } from "./adapters/interface.ts";
2
+ export declare function openZip(source: ArchiveSource): Promise<ZipArchive>;
@@ -0,0 +1,33 @@
1
+ import { BlobReader, Uint8ArrayReader, Uint8ArrayWriter, ZipReader, } from "@zip.js/zip.js/lib/zip-core-native.js";
2
+ import { openFile } from "#files";
3
+ const MAX_APPENDED_DATA = 1024 * 1024;
4
+ function toZipEntry(entry) {
5
+ return {
6
+ filename: entry.filename,
7
+ compressedSize: entry.compressedSize,
8
+ uncompressedSize: entry.uncompressedSize,
9
+ read: () => entry.getData(new Uint8ArrayWriter()),
10
+ };
11
+ }
12
+ export async function openZip(source) {
13
+ const data = typeof source === "string" ? await openFile(source) : source;
14
+ const reader = new ZipReader(data instanceof Uint8Array
15
+ ? new Uint8ArrayReader(data)
16
+ : new BlobReader(data), {
17
+ useWebWorkers: false,
18
+ // this in combination with maxAppendedDataSize is basically the manual fix
19
+ // we used to have for yauzl: sometimes zips has garbage at the end that
20
+ // would cause an error. zip.js has native support for this
21
+ strictness: "tolerant",
22
+ maxAppendedDataSize: MAX_APPENDED_DATA,
23
+ filenameValidation: "balanced",
24
+ checkCrc32: true,
25
+ });
26
+ const entries = await reader.getEntries();
27
+ return {
28
+ entries: entries
29
+ .filter((entry) => !entry.directory)
30
+ .map(toZipEntry),
31
+ close: () => reader.close(),
32
+ };
33
+ }
@@ -0,0 +1,9 @@
1
+ import { Readable } from "node:stream";
2
+ import type { ArchiveSource, ZipArchive, ZipEntry } from "./adapters/interface.ts";
3
+ export interface NodeZipEntry extends ZipEntry {
4
+ openReadStream(): Promise<Readable>;
5
+ }
6
+ export interface NodeZipArchive extends ZipArchive, AsyncDisposable {
7
+ readonly entries: readonly NodeZipEntry[];
8
+ }
9
+ export declare function openZip(source: ArchiveSource): Promise<NodeZipArchive>;
@@ -0,0 +1,246 @@
1
+ var __addDisposableResource = (this && this.__addDisposableResource) || function (env, value, async) {
2
+ if (value !== null && value !== void 0) {
3
+ if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
4
+ var dispose, inner;
5
+ if (async) {
6
+ if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
7
+ dispose = value[Symbol.asyncDispose];
8
+ }
9
+ if (dispose === void 0) {
10
+ if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
11
+ dispose = value[Symbol.dispose];
12
+ if (async) inner = dispose;
13
+ }
14
+ if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
15
+ if (inner) dispose = function() { try { inner.call(this); } catch (e) { return Promise.reject(e); } };
16
+ env.stack.push({ value: value, dispose: dispose, async: async });
17
+ }
18
+ else if (async) {
19
+ env.stack.push({ async: true });
20
+ }
21
+ return value;
22
+ };
23
+ var __disposeResources = (this && this.__disposeResources) || (function (SuppressedError) {
24
+ return function (env) {
25
+ function fail(e) {
26
+ env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
27
+ env.hasError = true;
28
+ }
29
+ var r, s = 0;
30
+ function next() {
31
+ while (r = env.stack.pop()) {
32
+ try {
33
+ if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);
34
+ if (r.dispose) {
35
+ var result = r.dispose.call(r.value);
36
+ if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
37
+ }
38
+ else s |= 1;
39
+ }
40
+ catch (e) {
41
+ fail(e);
42
+ }
43
+ }
44
+ if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();
45
+ if (env.hasError) throw env.error;
46
+ }
47
+ return next();
48
+ };
49
+ })(typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
50
+ var e = new Error(message);
51
+ return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
52
+ });
53
+ import { createReadStream } from "node:fs";
54
+ import { open as openFile, stat } from "node:fs/promises";
55
+ import { Readable } from "node:stream";
56
+ import { Reader, fromBuffer, fromReader, } from "yauzl-promise";
57
+ const EOCDR_SIGNATURE = Buffer.from([0x50, 0x4b, 0x05, 0x06]);
58
+ const EOCDR_SIZE = 22;
59
+ const MAX_TAIL_SCAN = 1024 * 1024;
60
+ function toBuffer(source) {
61
+ return Buffer.isBuffer(source)
62
+ ? source
63
+ : Buffer.from(source.buffer, source.byteOffset, source.byteLength);
64
+ }
65
+ function findArchiveEnd(tail, tailStart, fileSize) {
66
+ let searchFrom = tail.length - EOCDR_SIZE;
67
+ while (searchFrom >= 0) {
68
+ const index = tail.lastIndexOf(EOCDR_SIGNATURE, searchFrom);
69
+ if (index === -1)
70
+ return null;
71
+ const commentLength = tail.readUInt16LE(index + 20);
72
+ const end = tailStart + index + EOCDR_SIZE + commentLength;
73
+ if (end < fileSize)
74
+ return end;
75
+ searchFrom = index - 1;
76
+ }
77
+ return null;
78
+ }
79
+ async function readExactly(handle, length, position) {
80
+ const buffer = Buffer.allocUnsafe(length);
81
+ let offset = 0;
82
+ while (offset < length) {
83
+ const { bytesRead } = await handle.read(buffer, offset, length - offset, position + offset);
84
+ if (bytesRead === 0)
85
+ return null;
86
+ offset += bytesRead;
87
+ }
88
+ return buffer;
89
+ }
90
+ /**
91
+ * Basically sometimes EPUB 2s have some garbage at the end of the file after
92
+ * the End of Central Directory Record, which leads to
93
+ * `yauzl` throwing an "End of Central Directory Record not found" error
94
+ *
95
+ * This is an attempt to, when that error happens, try to read the file from the end and find the End of Central Directory Record, then clean up the garbage at the end of the file.
96
+ */
97
+ async function openTolerant(size, open, readTail) {
98
+ try {
99
+ return await open(size);
100
+ }
101
+ catch (error) {
102
+ const tailStart = Math.max(0, size - MAX_TAIL_SCAN);
103
+ const tail = await readTail(tailStart).catch(() => null);
104
+ const end = tail && findArchiveEnd(tail, tailStart, size);
105
+ if (!end)
106
+ throw error;
107
+ return await open(end).catch(() => {
108
+ throw error;
109
+ });
110
+ }
111
+ }
112
+ class FileHandleReader extends Reader {
113
+ path;
114
+ handle = null;
115
+ constructor(path) {
116
+ super();
117
+ this.path = path;
118
+ }
119
+ async _open() {
120
+ this.handle = await openFile(this.path, "r");
121
+ return {};
122
+ }
123
+ async _close() {
124
+ const handle = this.handle;
125
+ this.handle = null;
126
+ if (handle)
127
+ await handle.close();
128
+ return {};
129
+ }
130
+ async _read(start, length) {
131
+ if (!this.handle)
132
+ throw new Error(`reader for ${this.path} is not open`);
133
+ const buffer = await readExactly(this.handle, length, start);
134
+ if (!buffer) {
135
+ throw new Error(`unexpected end of file reading ${this.path}`);
136
+ }
137
+ return buffer;
138
+ }
139
+ _createReadStream(start, length) {
140
+ return createReadStream(this.path, { start, end: start + length - 1 });
141
+ }
142
+ async [Symbol.asyncDispose]() {
143
+ await this._close();
144
+ }
145
+ }
146
+ // yauzl-promise's own `open(path)` leaves the file open when parsing fails,
147
+ // so we hand it a reader we close ourselves unless the zip takes it over
148
+ async function openFileZip(path, size) {
149
+ const env_1 = { stack: [], error: void 0, hasError: false };
150
+ try {
151
+ const cleanup = __addDisposableResource(env_1, new AsyncDisposableStack(), true);
152
+ const reader = cleanup.use(new FileHandleReader(path));
153
+ const zip = await fromReader(reader, size);
154
+ cleanup.move();
155
+ return zip;
156
+ }
157
+ catch (e_1) {
158
+ env_1.error = e_1;
159
+ env_1.hasError = true;
160
+ }
161
+ finally {
162
+ const result_1 = __disposeResources(env_1);
163
+ if (result_1)
164
+ await result_1;
165
+ }
166
+ }
167
+ async function readFileTail(path, start) {
168
+ const env_2 = { stack: [], error: void 0, hasError: false };
169
+ try {
170
+ const handle = __addDisposableResource(env_2, await openFile(path, "r"), true);
171
+ const { size } = await handle.stat();
172
+ return await readExactly(handle, size - start, start);
173
+ }
174
+ catch (e_2) {
175
+ env_2.error = e_2;
176
+ env_2.hasError = true;
177
+ }
178
+ finally {
179
+ const result_2 = __disposeResources(env_2);
180
+ if (result_2)
181
+ await result_2;
182
+ }
183
+ }
184
+ class BlobReader extends Reader {
185
+ blob;
186
+ constructor(blob) {
187
+ super();
188
+ this.blob = blob;
189
+ }
190
+ async _read(start, length) {
191
+ return Buffer.from(await this.blob.slice(start, start + length).arrayBuffer());
192
+ }
193
+ _createReadStream(start, length) {
194
+ return Readable.fromWeb(this.blob.slice(start, start + length).stream());
195
+ }
196
+ }
197
+ function toZipEntry(entry) {
198
+ return {
199
+ filename: entry.filename,
200
+ compressedSize: entry.compressedSize,
201
+ uncompressedSize: entry.uncompressedSize,
202
+ openReadStream: () => entry.openReadStream(),
203
+ async read() {
204
+ const chunks = [];
205
+ for await (const chunk of await entry.openReadStream()) {
206
+ chunks.push(chunk);
207
+ }
208
+ return Buffer.concat(chunks);
209
+ },
210
+ };
211
+ }
212
+ async function openYauzl(source) {
213
+ if (typeof source === "string") {
214
+ return await openTolerant((await stat(source)).size, (size) => openFileZip(source, size), (start) => readFileTail(source, start));
215
+ }
216
+ if (source instanceof Uint8Array) {
217
+ const data = toBuffer(source);
218
+ return await openTolerant(data.length, (size) => fromBuffer(data.subarray(0, size)), (start) => Promise.resolve(data.subarray(start)));
219
+ }
220
+ return await openTolerant(source.size, (size) => fromReader(new BlobReader(source), size), async (start) => Buffer.from(await source.slice(start).arrayBuffer()));
221
+ }
222
+ export async function openZip(source) {
223
+ const env_3 = { stack: [], error: void 0, hasError: false };
224
+ try {
225
+ const cleanup = __addDisposableResource(env_3, new AsyncDisposableStack(), true);
226
+ const zip = cleanup.adopt(await openYauzl(source), (zip) => zip.close());
227
+ const entries = await zip.readEntries();
228
+ const owned = cleanup.move();
229
+ return {
230
+ entries: entries
231
+ .filter((entry) => !entry.filename.endsWith("/"))
232
+ .map(toZipEntry),
233
+ close: () => owned.disposeAsync(),
234
+ [Symbol.asyncDispose]: () => owned.disposeAsync(),
235
+ };
236
+ }
237
+ catch (e_3) {
238
+ env_3.error = e_3;
239
+ env_3.hasError = true;
240
+ }
241
+ finally {
242
+ const result_3 = __disposeResources(env_3);
243
+ if (result_3)
244
+ await result_3;
245
+ }
246
+ }
package/package.json CHANGED
@@ -1,12 +1,54 @@
1
1
  {
2
2
  "name": "@storyteller-platform/epub",
3
- "version": "0.8.1",
3
+ "version": "1.0.0",
4
4
  "type": "module",
5
5
  "types": "dist/index.d.ts",
6
6
  "license": "MIT",
7
7
  "exports": {
8
- "types": "./dist/index.d.ts",
9
- "default": "./dist/index.js"
8
+ ".": {
9
+ "types": "./dist/index.d.ts",
10
+ "default": "./dist/index.js"
11
+ },
12
+ "./jsx-runtime": {
13
+ "types": "./dist/jsx-runtime.d.ts",
14
+ "default": "./dist/jsx-runtime.js"
15
+ },
16
+ "./jsx-dev-runtime": {
17
+ "types": "./dist/jsx-dev-runtime.d.ts",
18
+ "default": "./dist/jsx-dev-runtime.js"
19
+ }
20
+ },
21
+ "imports": {
22
+ "#files": {
23
+ "node": {
24
+ "types": "./dist/files.node.d.ts",
25
+ "default": "./dist/files.node.js"
26
+ },
27
+ "default": {
28
+ "types": "./dist/files.browser.d.ts",
29
+ "default": "./dist/files.browser.js"
30
+ }
31
+ },
32
+ "#tmpfs": {
33
+ "node": {
34
+ "types": "./dist/adapters/tmpfs.d.ts",
35
+ "default": "./dist/adapters/tmpfs.js"
36
+ },
37
+ "default": {
38
+ "types": "./dist/adapters/tmpfs.browser.d.ts",
39
+ "default": "./dist/adapters/tmpfs.browser.js"
40
+ }
41
+ },
42
+ "#zip": {
43
+ "node": {
44
+ "types": "./dist/zip.node.d.ts",
45
+ "default": "./dist/zip.node.js"
46
+ },
47
+ "default": {
48
+ "types": "./dist/zip.browser.d.ts",
49
+ "default": "./dist/zip.browser.js"
50
+ }
51
+ }
10
52
  },
11
53
  "files": [
12
54
  "dist/"
@@ -29,7 +71,7 @@
29
71
  "@typescript/native": "npm:typescript@^7.0.2",
30
72
  "markdown-toc": "^1.2.0",
31
73
  "remark-toc": "^9.0.0",
32
- "tsx": "^4.19.2",
74
+ "tsx": "^4.23.12",
33
75
  "typedoc": "^0.28.20",
34
76
  "typedoc-plugin-markdown": "^4.6.3",
35
77
  "typedoc-plugin-remark": "^1.2.0",
@@ -38,14 +80,12 @@
38
80
  "vitest": "^5.0.0"
39
81
  },
40
82
  "dependencies": {
41
- "@readium/shared": "^2.2.0",
42
83
  "@storyteller-platform/fs": "^0.3.0",
43
84
  "@storyteller-platform/media-types": "^0.2.1",
44
85
  "@storyteller-platform/path": "^0.3.1",
45
- "@zip.js/zip.js": "^2.0.0",
86
+ "@xmldom/xmldom": "^0.9.12",
87
+ "@zip.js/zip.js": "^2.18.2",
46
88
  "async-mutex": "^0.5.0",
47
- "fast-xml-builder": "^1.3.1",
48
- "fast-xml-parser": "^5.11.1",
49
89
  "mem": "^8.0.0",
50
90
  "nanoid": "^5.1.5",
51
91
  "yauzl-promise": "^4.0.0",
@@ -54,8 +94,50 @@
54
94
  "publishConfig": {
55
95
  "access": "public",
56
96
  "exports": {
57
- "types": "./dist/index.d.ts",
58
- "default": "./dist/index.js"
97
+ ".": {
98
+ "types": "./dist/index.d.ts",
99
+ "default": "./dist/index.js"
100
+ },
101
+ "./jsx-runtime": {
102
+ "types": "./dist/jsx-runtime.d.ts",
103
+ "default": "./dist/jsx-runtime.js"
104
+ },
105
+ "./jsx-dev-runtime": {
106
+ "types": "./dist/jsx-dev-runtime.d.ts",
107
+ "default": "./dist/jsx-dev-runtime.js"
108
+ }
109
+ },
110
+ "imports": {
111
+ "#files": {
112
+ "node": {
113
+ "types": "./dist/files.node.d.ts",
114
+ "default": "./dist/files.node.js"
115
+ },
116
+ "default": {
117
+ "types": "./dist/files.browser.d.ts",
118
+ "default": "./dist/files.browser.js"
119
+ }
120
+ },
121
+ "#tmpfs": {
122
+ "node": {
123
+ "types": "./dist/adapters/tmpfs.d.ts",
124
+ "default": "./dist/adapters/tmpfs.js"
125
+ },
126
+ "default": {
127
+ "types": "./dist/adapters/tmpfs.browser.d.ts",
128
+ "default": "./dist/adapters/tmpfs.browser.js"
129
+ }
130
+ },
131
+ "#zip": {
132
+ "node": {
133
+ "types": "./dist/zip.node.d.ts",
134
+ "default": "./dist/zip.node.js"
135
+ },
136
+ "default": {
137
+ "types": "./dist/zip.browser.d.ts",
138
+ "default": "./dist/zip.browser.js"
139
+ }
140
+ }
59
141
  }
60
142
  }
61
143
  }