@storyteller-platform/epub 0.7.1 → 0.8.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/README.md +1363 -775
- package/dist/adapters/interface.d.ts +6 -8
- package/dist/adapters/interface.js +1 -0
- package/dist/adapters/memory.d.ts +3 -6
- package/dist/adapters/memory.js +69 -64
- package/dist/adapters/tmpfs.d.ts +2 -5
- package/dist/adapters/tmpfs.js +230 -161
- package/dist/epubcheck.d.ts +4 -6
- package/dist/epubcheck.js +24 -26
- package/dist/index.d.ts +1161 -5
- package/dist/index.js +2581 -2739
- package/dist/upgrade.d.ts +23 -1183
- package/dist/upgrade.js +412 -432
- package/dist/zip.d.ts +2 -5
- package/dist/zip.js +113 -100
- package/package.json +18 -31
- package/dist/adapters/interface.cjs +0 -16
- package/dist/adapters/interface.d.cts +0 -75
- package/dist/adapters/memory.cjs +0 -93
- package/dist/adapters/memory.d.cts +0 -36
- package/dist/adapters/tmpfs.cjs +0 -240
- package/dist/adapters/tmpfs.d.cts +0 -31
- package/dist/chunk-BIEQXUOY.js +0 -50
- package/dist/epubcheck.cjs +0 -60
- package/dist/epubcheck.d.cts +0 -23
- package/dist/index.cjs +0 -2846
- package/dist/index.d.cts +0 -5
- package/dist/upgrade.cjs +0 -523
- package/dist/upgrade.d.cts +0 -1196
- package/dist/zip.cjs +0 -142
- package/dist/zip.d.cts +0 -5
package/dist/zip.d.ts
CHANGED
|
@@ -1,5 +1,2 @@
|
|
|
1
|
-
import { ZipFile } from
|
|
2
|
-
|
|
3
|
-
declare function openZip(source: string | Uint8Array): Promise<ZipFile>;
|
|
4
|
-
|
|
5
|
-
export { openZip };
|
|
1
|
+
import { type ZipFile } from "yauzl-promise";
|
|
2
|
+
export declare function openZip(source: string | Uint8Array): Promise<ZipFile>;
|
package/dist/zip.js
CHANGED
|
@@ -1,124 +1,137 @@
|
|
|
1
|
-
import "./chunk-BIEQXUOY.js";
|
|
2
1
|
import { createReadStream } from "node:fs";
|
|
3
2
|
import { open as openFile } from "node:fs/promises";
|
|
4
|
-
import {
|
|
5
|
-
|
|
6
|
-
fromBuffer,
|
|
7
|
-
fromReader,
|
|
8
|
-
open
|
|
9
|
-
} from "yauzl-promise";
|
|
10
|
-
const EOCDR_SIGNATURE = Buffer.from([80, 75, 5, 6]);
|
|
3
|
+
import { Reader, fromBuffer, fromReader, open, } from "yauzl-promise";
|
|
4
|
+
const EOCDR_SIGNATURE = Buffer.from([0x50, 0x4b, 0x05, 0x06]);
|
|
11
5
|
const EOCDR_SIZE = 22;
|
|
12
6
|
const MAX_TAIL_SCAN = 1024 * 1024;
|
|
13
7
|
function toBuffer(source) {
|
|
14
|
-
|
|
8
|
+
return Buffer.isBuffer(source)
|
|
9
|
+
? source
|
|
10
|
+
: Buffer.from(source.buffer, source.byteOffset, source.byteLength);
|
|
15
11
|
}
|
|
16
12
|
function findArchiveEnd(tail, tailStart, fileSize) {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
13
|
+
let searchFrom = tail.length - EOCDR_SIZE;
|
|
14
|
+
while (searchFrom >= 0) {
|
|
15
|
+
const index = tail.lastIndexOf(EOCDR_SIGNATURE, searchFrom);
|
|
16
|
+
if (index === -1)
|
|
17
|
+
return null;
|
|
18
|
+
const commentLength = tail.readUInt16LE(index + 20);
|
|
19
|
+
const end = tailStart + index + EOCDR_SIZE + commentLength;
|
|
20
|
+
if (end < fileSize)
|
|
21
|
+
return end;
|
|
22
|
+
searchFrom = index - 1;
|
|
23
|
+
}
|
|
24
|
+
return null;
|
|
27
25
|
}
|
|
28
26
|
async function readExactly(handle, length, position) {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
if (bytesRead === 0) return null;
|
|
39
|
-
offset += bytesRead;
|
|
40
|
-
}
|
|
41
|
-
return buffer;
|
|
27
|
+
const buffer = Buffer.allocUnsafe(length);
|
|
28
|
+
let offset = 0;
|
|
29
|
+
while (offset < length) {
|
|
30
|
+
const { bytesRead } = await handle.read(buffer, offset, length - offset, position + offset);
|
|
31
|
+
if (bytesRead === 0)
|
|
32
|
+
return null;
|
|
33
|
+
offset += bytesRead;
|
|
34
|
+
}
|
|
35
|
+
return buffer;
|
|
42
36
|
}
|
|
43
37
|
async function findFileArchiveEnd(path) {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
38
|
+
let handle;
|
|
39
|
+
try {
|
|
40
|
+
handle = await openFile(path, "r");
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
try {
|
|
46
|
+
const { size } = await handle.stat();
|
|
47
|
+
const tailLength = Math.min(size, MAX_TAIL_SCAN);
|
|
48
|
+
if (tailLength < EOCDR_SIZE)
|
|
49
|
+
return null;
|
|
50
|
+
const tailStart = size - tailLength;
|
|
51
|
+
const tail = await readExactly(handle, tailLength, tailStart);
|
|
52
|
+
if (!tail)
|
|
53
|
+
return null;
|
|
54
|
+
return findArchiveEnd(tail, tailStart, size);
|
|
55
|
+
}
|
|
56
|
+
finally {
|
|
57
|
+
await handle.close();
|
|
58
|
+
}
|
|
61
59
|
}
|
|
60
|
+
/**
|
|
61
|
+
* Basically sometimes EPUB 2s have some garbage at the end of the file after
|
|
62
|
+
* the End of Central Directory Record, which leads to
|
|
63
|
+
* `yauzl` throwing an "End of Central Directory Record not found" error
|
|
64
|
+
*
|
|
65
|
+
* 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.
|
|
66
|
+
*/
|
|
62
67
|
class TruncatedFileReader extends Reader {
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
68
|
+
path;
|
|
69
|
+
handle = null;
|
|
70
|
+
constructor(path) {
|
|
71
|
+
super();
|
|
72
|
+
this.path = path;
|
|
73
|
+
}
|
|
74
|
+
async _open() {
|
|
75
|
+
this.handle = await openFile(this.path, "r");
|
|
76
|
+
return {};
|
|
77
|
+
}
|
|
78
|
+
async _close() {
|
|
79
|
+
const handle = this.handle;
|
|
80
|
+
this.handle = null;
|
|
81
|
+
if (handle)
|
|
82
|
+
await handle.close();
|
|
83
|
+
return {};
|
|
84
|
+
}
|
|
85
|
+
async _read(start, length) {
|
|
86
|
+
if (!this.handle)
|
|
87
|
+
throw new Error(`reader for ${this.path} is not open`);
|
|
88
|
+
const buffer = await readExactly(this.handle, length, start);
|
|
89
|
+
if (!buffer) {
|
|
90
|
+
throw new Error(`unexpected end of file reading ${this.path}`);
|
|
91
|
+
}
|
|
92
|
+
return buffer;
|
|
93
|
+
}
|
|
94
|
+
_createReadStream(start, length) {
|
|
95
|
+
return createReadStream(this.path, { start, end: start + length - 1 });
|
|
83
96
|
}
|
|
84
|
-
return buffer;
|
|
85
|
-
}
|
|
86
|
-
_createReadStream(start, length) {
|
|
87
|
-
return createReadStream(this.path, { start, end: start + length - 1 });
|
|
88
|
-
}
|
|
89
97
|
}
|
|
90
98
|
async function openBufferZip(data) {
|
|
91
|
-
try {
|
|
92
|
-
return await fromBuffer(data);
|
|
93
|
-
} catch (error) {
|
|
94
|
-
const tailStart = Math.max(0, data.length - MAX_TAIL_SCAN);
|
|
95
|
-
const end = findArchiveEnd(data.subarray(tailStart), tailStart, data.length);
|
|
96
|
-
if (end === null) throw error;
|
|
97
99
|
try {
|
|
98
|
-
|
|
99
|
-
}
|
|
100
|
-
|
|
100
|
+
return await fromBuffer(data);
|
|
101
|
+
}
|
|
102
|
+
catch (error) {
|
|
103
|
+
const tailStart = Math.max(0, data.length - MAX_TAIL_SCAN);
|
|
104
|
+
const end = findArchiveEnd(data.subarray(tailStart), tailStart, data.length);
|
|
105
|
+
if (end === null)
|
|
106
|
+
throw error;
|
|
107
|
+
try {
|
|
108
|
+
return await fromBuffer(data.subarray(0, end));
|
|
109
|
+
}
|
|
110
|
+
catch {
|
|
111
|
+
throw error;
|
|
112
|
+
}
|
|
101
113
|
}
|
|
102
|
-
}
|
|
103
114
|
}
|
|
104
115
|
async function openFileZip(path) {
|
|
105
|
-
try {
|
|
106
|
-
return await open(path);
|
|
107
|
-
} catch (error) {
|
|
108
|
-
const end = await findFileArchiveEnd(path);
|
|
109
|
-
if (end === null) throw error;
|
|
110
|
-
const reader = new TruncatedFileReader(path);
|
|
111
116
|
try {
|
|
112
|
-
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
|
|
117
|
+
return await open(path);
|
|
118
|
+
}
|
|
119
|
+
catch (error) {
|
|
120
|
+
const end = await findFileArchiveEnd(path);
|
|
121
|
+
if (end === null)
|
|
122
|
+
throw error;
|
|
123
|
+
const reader = new TruncatedFileReader(path);
|
|
124
|
+
try {
|
|
125
|
+
return await fromReader(reader, end);
|
|
126
|
+
}
|
|
127
|
+
catch {
|
|
128
|
+
await reader._close().catch(() => undefined);
|
|
129
|
+
throw error;
|
|
130
|
+
}
|
|
116
131
|
}
|
|
117
|
-
}
|
|
118
132
|
}
|
|
119
|
-
async function openZip(source) {
|
|
120
|
-
|
|
133
|
+
export async function openZip(source) {
|
|
134
|
+
return typeof source === "string"
|
|
135
|
+
? openFileZip(source)
|
|
136
|
+
: openBufferZip(toBuffer(source));
|
|
121
137
|
}
|
|
122
|
-
export {
|
|
123
|
-
openZip
|
|
124
|
-
};
|
package/package.json
CHANGED
|
@@ -1,58 +1,51 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@storyteller-platform/epub",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"type": "module",
|
|
5
|
-
"module": "dist/index.js",
|
|
6
5
|
"types": "dist/index.d.ts",
|
|
7
6
|
"license": "MIT",
|
|
8
7
|
"exports": {
|
|
9
|
-
"
|
|
10
|
-
|
|
11
|
-
"default": "./dist/index.js"
|
|
12
|
-
},
|
|
13
|
-
"require": {
|
|
14
|
-
"types": "./dist/index.d.cts",
|
|
15
|
-
"default": "./dist/index.cjs"
|
|
16
|
-
}
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"default": "./dist/index.js"
|
|
17
10
|
},
|
|
18
11
|
"files": [
|
|
19
12
|
"dist/"
|
|
20
13
|
],
|
|
21
14
|
"scripts": {
|
|
22
|
-
"build": "
|
|
15
|
+
"build": "rm -rf dist .tsbuild && tsc -b tsconfig.build.json",
|
|
23
16
|
"readme:toc": "markdown-toc --maxdepth=5 --append='\n- [API Docs](#api-docs)' --bullets='-' -i readme-stub.md",
|
|
24
17
|
"readme:api": "typedoc",
|
|
25
18
|
"readme": "yarn readme:api && yarn readme:toc && cat readme-stub.md > README.md && tail -n +2 gen/README.md >> README.md",
|
|
26
19
|
"install-epubcheck": "tsx scripts/install-epubcheck.ts",
|
|
27
|
-
"test": "yarn install-epubcheck &&
|
|
28
|
-
"test:watch": "yarn install-epubcheck &&
|
|
20
|
+
"test": "yarn install-epubcheck && vitest run",
|
|
21
|
+
"test:watch": "yarn install-epubcheck && vitest",
|
|
29
22
|
"prepack": "yarn build"
|
|
30
23
|
},
|
|
31
24
|
"devDependencies": {
|
|
32
|
-
"@storyteller-platform/eslint": "0.1.0",
|
|
33
|
-
"@storyteller-platform/tsup": "^0.1.0",
|
|
34
25
|
"@tsconfig/strictest": "^2.0.5",
|
|
35
26
|
"@types/node": "^24.0.0",
|
|
36
27
|
"@types/yauzl-promise": "^4",
|
|
37
28
|
"@types/yazl": "^3",
|
|
38
|
-
"
|
|
29
|
+
"@typescript/native": "npm:typescript@^7.0.2",
|
|
39
30
|
"markdown-toc": "^1.2.0",
|
|
40
31
|
"remark-toc": "^9.0.0",
|
|
41
|
-
"tsup": "^8.5.0",
|
|
42
32
|
"tsx": "^4.19.2",
|
|
43
|
-
"typedoc": "^0.28.
|
|
33
|
+
"typedoc": "^0.28.20",
|
|
44
34
|
"typedoc-plugin-markdown": "^4.6.3",
|
|
45
35
|
"typedoc-plugin-remark": "^1.2.0",
|
|
46
|
-
"typescript": "
|
|
36
|
+
"typescript": "npm:@typescript/typescript6@^6.0.2",
|
|
37
|
+
"vite": "^8.0.0",
|
|
38
|
+
"vitest": "^5.0.0"
|
|
47
39
|
},
|
|
48
40
|
"dependencies": {
|
|
49
41
|
"@readium/shared": "^2.2.0",
|
|
50
|
-
"@storyteller-platform/fs": "^0.
|
|
51
|
-
"@storyteller-platform/media-types": "^0.
|
|
52
|
-
"@storyteller-platform/path": "^0.
|
|
42
|
+
"@storyteller-platform/fs": "^0.3.0",
|
|
43
|
+
"@storyteller-platform/media-types": "^0.2.0",
|
|
44
|
+
"@storyteller-platform/path": "^0.3.0",
|
|
53
45
|
"@zip.js/zip.js": "^2.0.0",
|
|
54
46
|
"async-mutex": "^0.5.0",
|
|
55
|
-
"fast-xml-
|
|
47
|
+
"fast-xml-builder": "^1.3.1",
|
|
48
|
+
"fast-xml-parser": "^5.11.1",
|
|
56
49
|
"mem": "^8.0.0",
|
|
57
50
|
"nanoid": "^5.1.5",
|
|
58
51
|
"yauzl-promise": "^4.0.0",
|
|
@@ -61,14 +54,8 @@
|
|
|
61
54
|
"publishConfig": {
|
|
62
55
|
"access": "public",
|
|
63
56
|
"exports": {
|
|
64
|
-
"
|
|
65
|
-
|
|
66
|
-
"default": "./dist/index.js"
|
|
67
|
-
},
|
|
68
|
-
"require": {
|
|
69
|
-
"types": "./dist/index.d.cts",
|
|
70
|
-
"default": "./dist/index.cjs"
|
|
71
|
-
}
|
|
57
|
+
"types": "./dist/index.d.ts",
|
|
58
|
+
"default": "./dist/index.js"
|
|
72
59
|
}
|
|
73
60
|
}
|
|
74
61
|
}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __defProp = Object.defineProperty;
|
|
3
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
-
var __copyProps = (to, from, except, desc) => {
|
|
7
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
8
|
-
for (let key of __getOwnPropNames(from))
|
|
9
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
10
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
11
|
-
}
|
|
12
|
-
return to;
|
|
13
|
-
};
|
|
14
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
15
|
-
var interface_exports = {};
|
|
16
|
-
module.exports = __toCommonJS(interface_exports);
|
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Pluggable storage backend for an Epub instance
|
|
3
|
-
*
|
|
4
|
-
* Built-in adapters:
|
|
5
|
-
* - {@link TmpFsAdapter} extracts the archive to a tmp directory and
|
|
6
|
-
* supports the full read/write/save/upgrade
|
|
7
|
-
* - {@link MemoryAdapter} keeps an in-memory zip handle and supports
|
|
8
|
-
* reads only
|
|
9
|
-
*/
|
|
10
|
-
type EpubStorageKind = "tmp-dir" | "in-memory" | (string & {});
|
|
11
|
-
interface EpubStorageCapabilities {
|
|
12
|
-
/** when false, the Epub class refuses every mutation method at runtime */
|
|
13
|
-
readonly writable: boolean;
|
|
14
|
-
}
|
|
15
|
-
interface EpubListEntry {
|
|
16
|
-
/** location the adapter can read the entry back from, in whatever form it stores */
|
|
17
|
-
absolutePath: string;
|
|
18
|
-
/** the entry name, as it appears in the archive */
|
|
19
|
-
relativePath: string;
|
|
20
|
-
}
|
|
21
|
-
/**
|
|
22
|
-
* Adapters only receive entry names, which is:
|
|
23
|
-
* - the name a file has in the archive itself
|
|
24
|
-
* - relative to the container root, slash-separated,
|
|
25
|
-
* - already percent-decoded (eg `OEBPS/a b.xhtml`, not `OEBPS/a%20b.xhtml`)
|
|
26
|
-
*
|
|
27
|
-
* Adapter decides where to store files under what name
|
|
28
|
-
* In previous versions of the EPUB lib, this was a little bit more muddled, leading to
|
|
29
|
-
* eg the TmpFsAdapter trying to read `OEBPS/a%20b.xhtml`, whereas it was stored as `OEBPS/a b.xhtml`
|
|
30
|
-
*/
|
|
31
|
-
interface EpubStorageAdapter {
|
|
32
|
-
read(entry: string): Promise<Uint8Array>;
|
|
33
|
-
read(entry: string, encoding: "utf-8"): Promise<string>;
|
|
34
|
-
/**
|
|
35
|
-
* Whether the archive holds an entry under exactly this name.
|
|
36
|
-
* Used to choose between different canditates for an href
|
|
37
|
-
* so should be exact
|
|
38
|
-
*/
|
|
39
|
-
exists(entry: string): Promise<boolean>;
|
|
40
|
-
/**
|
|
41
|
-
* Length of an entry in bytes, for the readium page-count heuristic
|
|
42
|
-
* which expects compressed size when available
|
|
43
|
-
*/
|
|
44
|
-
archiveLength(entry: string): Promise<number>;
|
|
45
|
-
/** Required for any mutation method on Epub */
|
|
46
|
-
write?(entry: string, data: Uint8Array): Promise<void>;
|
|
47
|
-
write?(entry: string, data: string, encoding: "utf-8"): Promise<void>;
|
|
48
|
-
/** Required for removeManifestItem / setCoverImage replacement */
|
|
49
|
-
remove?(entry: string): Promise<void>;
|
|
50
|
-
/** Required for Epub.saveAndClose to walk the contents */
|
|
51
|
-
list?(): AsyncIterable<EpubListEntry>;
|
|
52
|
-
/** Required for Epub.copy */
|
|
53
|
-
duplicate?(): Promise<EpubStorageAdapter>;
|
|
54
|
-
/** Required for Epub.saveAndClose */
|
|
55
|
-
serialize?(targetPath: string): Promise<void>;
|
|
56
|
-
/** Always called on close or error */
|
|
57
|
-
dispose(): void | Promise<void>;
|
|
58
|
-
}
|
|
59
|
-
interface EpubStorageAdapterClass<Opts extends object = object> {
|
|
60
|
-
readonly kind: EpubStorageKind;
|
|
61
|
-
readonly capabilities: EpubStorageCapabilities;
|
|
62
|
-
/**
|
|
63
|
-
* Open an archive from a path or buffer.
|
|
64
|
-
* Will throw if the archive is not a valid EPUB 3
|
|
65
|
-
*/
|
|
66
|
-
init(source: string | Uint8Array, opts?: Opts): Promise<EpubStorageAdapter>;
|
|
67
|
-
/**
|
|
68
|
-
* Initialize an empty extract root for {@link Epub.create}.
|
|
69
|
-
* Only necessary for adapters that can write
|
|
70
|
-
*/
|
|
71
|
-
initEmpty?(opts?: Opts): Promise<EpubStorageAdapter>;
|
|
72
|
-
}
|
|
73
|
-
type AdapterOptions<A> = A extends EpubStorageAdapterClass<infer Opts> ? Opts : object;
|
|
74
|
-
|
|
75
|
-
export type { AdapterOptions, EpubListEntry, EpubStorageAdapter, EpubStorageAdapterClass, EpubStorageCapabilities, EpubStorageKind };
|
package/dist/adapters/memory.cjs
DELETED
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __defProp = Object.defineProperty;
|
|
3
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
-
var __export = (target, all) => {
|
|
7
|
-
for (var name in all)
|
|
8
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
-
};
|
|
10
|
-
var __copyProps = (to, from, except, desc) => {
|
|
11
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
-
for (let key of __getOwnPropNames(from))
|
|
13
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
-
}
|
|
16
|
-
return to;
|
|
17
|
-
};
|
|
18
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
-
var memory_exports = {};
|
|
20
|
-
__export(memory_exports, {
|
|
21
|
-
MemoryAdapter: () => MemoryAdapter
|
|
22
|
-
});
|
|
23
|
-
module.exports = __toCommonJS(memory_exports);
|
|
24
|
-
var import_zip = require("../zip.cjs");
|
|
25
|
-
class MemoryAdapter {
|
|
26
|
-
constructor(zip, entries, cache) {
|
|
27
|
-
this.zip = zip;
|
|
28
|
-
this.entries = entries;
|
|
29
|
-
this.cache = cache;
|
|
30
|
-
}
|
|
31
|
-
static kind = "in-memory";
|
|
32
|
-
static capabilities = { writable: false };
|
|
33
|
-
static async init(source, opts = {}) {
|
|
34
|
-
const { cache = true, signal } = opts;
|
|
35
|
-
signal == null ? void 0 : signal.throwIfAborted();
|
|
36
|
-
const zip = await (0, import_zip.openZip)(source);
|
|
37
|
-
const entries = /* @__PURE__ */ new Map();
|
|
38
|
-
try {
|
|
39
|
-
for await (const entry of zip) {
|
|
40
|
-
signal == null ? void 0 : signal.throwIfAborted();
|
|
41
|
-
if (entry.filename.endsWith("/")) continue;
|
|
42
|
-
entries.set(entry.filename, entry);
|
|
43
|
-
}
|
|
44
|
-
} catch (error) {
|
|
45
|
-
await zip.close();
|
|
46
|
-
throw error;
|
|
47
|
-
}
|
|
48
|
-
return new MemoryAdapter(zip, entries, cache ? /* @__PURE__ */ new Map() : null);
|
|
49
|
-
}
|
|
50
|
-
async read(entry, encoding) {
|
|
51
|
-
var _a, _b;
|
|
52
|
-
const cached = (_a = this.cache) == null ? void 0 : _a.get(entry);
|
|
53
|
-
if (cached) {
|
|
54
|
-
return encoding ? cached.toString(encoding) : new Uint8Array(cached);
|
|
55
|
-
}
|
|
56
|
-
const zipEntry = this.entries.get(entry);
|
|
57
|
-
if (!zipEntry) {
|
|
58
|
-
const err = new Error(
|
|
59
|
-
`ENOENT: zip entry not found in EPUB archive: ${entry}`
|
|
60
|
-
);
|
|
61
|
-
err.code = "ENOENT";
|
|
62
|
-
throw err;
|
|
63
|
-
}
|
|
64
|
-
const stream = await zipEntry.openReadStream();
|
|
65
|
-
const chunks = [];
|
|
66
|
-
for await (const chunk of stream) {
|
|
67
|
-
chunks.push(chunk);
|
|
68
|
-
}
|
|
69
|
-
const buf = Buffer.concat(chunks);
|
|
70
|
-
(_b = this.cache) == null ? void 0 : _b.set(entry, buf);
|
|
71
|
-
return encoding ? buf.toString(encoding) : new Uint8Array(buf);
|
|
72
|
-
}
|
|
73
|
-
// eslint-disable-next-line @typescript-eslint/require-await
|
|
74
|
-
async exists(entry) {
|
|
75
|
-
return this.entries.has(entry);
|
|
76
|
-
}
|
|
77
|
-
// eslint-disable-next-line @typescript-eslint/require-await
|
|
78
|
-
async archiveLength(entry) {
|
|
79
|
-
const zipEntry = this.entries.get(entry);
|
|
80
|
-
if (!zipEntry) return 0;
|
|
81
|
-
return zipEntry.compressedSize || zipEntry.uncompressedSize;
|
|
82
|
-
}
|
|
83
|
-
dispose() {
|
|
84
|
-
var _a;
|
|
85
|
-
this.entries.clear();
|
|
86
|
-
(_a = this.cache) == null ? void 0 : _a.clear();
|
|
87
|
-
this.zip.close().catch(() => void 0);
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
// Annotate the CommonJS export names for ESM import in node:
|
|
91
|
-
0 && (module.exports = {
|
|
92
|
-
MemoryAdapter
|
|
93
|
-
});
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import { EpubStorageAdapter } from './interface.cjs';
|
|
2
|
-
|
|
3
|
-
interface MemoryAdapterOptions {
|
|
4
|
-
/**
|
|
5
|
-
* per-entry decompressed buffer cache
|
|
6
|
-
* turn it off when opening many EPUBs and reading each entry at most once
|
|
7
|
-
* keeps resident size bounded by the entry index, not the decompressed payload sum
|
|
8
|
-
* @default true
|
|
9
|
-
*/
|
|
10
|
-
cache?: boolean;
|
|
11
|
-
signal?: AbortSignal;
|
|
12
|
-
}
|
|
13
|
-
/**
|
|
14
|
-
* Loads an EPUB archive into memory and serves all I/O off the in-memory zip handle.
|
|
15
|
-
*
|
|
16
|
-
* read only
|
|
17
|
-
*
|
|
18
|
-
*/
|
|
19
|
-
declare class MemoryAdapter implements EpubStorageAdapter {
|
|
20
|
-
private zip;
|
|
21
|
-
private entries;
|
|
22
|
-
private cache;
|
|
23
|
-
static readonly kind: "in-memory";
|
|
24
|
-
static readonly capabilities: {
|
|
25
|
-
readonly writable: false;
|
|
26
|
-
};
|
|
27
|
-
static init(source: string | Uint8Array, opts?: MemoryAdapterOptions): Promise<MemoryAdapter>;
|
|
28
|
-
private constructor();
|
|
29
|
-
read(entry: string): Promise<Uint8Array>;
|
|
30
|
-
read(entry: string, encoding: "utf-8"): Promise<string>;
|
|
31
|
-
exists(entry: string): Promise<boolean>;
|
|
32
|
-
archiveLength(entry: string): Promise<number>;
|
|
33
|
-
dispose(): void;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export { MemoryAdapter, type MemoryAdapterOptions };
|