@storyteller-platform/epub 0.8.2 → 1.0.1

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.
@@ -1,21 +0,0 @@
1
- export interface Location {
2
- url: {
3
- hierachical: boolean;
4
- opaque: boolean;
5
- };
6
- path: string;
7
- line: number;
8
- column: number;
9
- context: string | null;
10
- }
11
- export interface Message {
12
- ID: string;
13
- severity: "FATAL" | "ERROR" | "WARNING" | "INFO" | "USAGE";
14
- message: string;
15
- additionalLocations: number;
16
- locations: Location[];
17
- }
18
- export interface Report {
19
- messages: Message[];
20
- }
21
- export declare function epubcheck(epubFile: string): Promise<Report>;
package/dist/epubcheck.js DELETED
@@ -1,34 +0,0 @@
1
- import { execFile } from "node:child_process";
2
- import { randomUUID } from "node:crypto";
3
- import { readFile, unlink } from "node:fs/promises";
4
- import { dirname, join } from "node:path";
5
- import { fileURLToPath } from "node:url";
6
- import { promisify } from "node:util";
7
- import { scratchPath } from "@storyteller-platform/fs";
8
- const here = dirname(fileURLToPath(import.meta.url));
9
- const JAR = join(here, "vendors", "epubcheck-5.3.0", "epubcheck.jar");
10
- export async function epubcheck(epubFile) {
11
- const output = scratchPath(`epubcheck-${randomUUID()}.json`);
12
- const execFilePromise = promisify(execFile);
13
- try {
14
- await execFilePromise("java", [
15
- "-jar",
16
- JAR,
17
- "--json",
18
- output,
19
- epubFile,
20
- ]).catch((error) => {
21
- if (error instanceof Error &&
22
- error.message.includes("Check finished with errors")) {
23
- // dont throw, just let the caller handle it
24
- return;
25
- }
26
- throw error;
27
- });
28
- const json = await readFile(output, "utf8");
29
- return JSON.parse(json);
30
- }
31
- finally {
32
- await unlink(output).catch(() => { });
33
- }
34
- }
package/dist/zip.d.ts DELETED
@@ -1,2 +0,0 @@
1
- import { type ZipFile } from "yauzl-promise";
2
- export declare function openZip(source: string | Uint8Array): Promise<ZipFile>;
package/dist/zip.js DELETED
@@ -1,137 +0,0 @@
1
- import { createReadStream } from "node:fs";
2
- import { open as openFile } from "node:fs/promises";
3
- import { Reader, fromBuffer, fromReader, open, } from "yauzl-promise";
4
- const EOCDR_SIGNATURE = Buffer.from([0x50, 0x4b, 0x05, 0x06]);
5
- const EOCDR_SIZE = 22;
6
- const MAX_TAIL_SCAN = 1024 * 1024;
7
- function toBuffer(source) {
8
- return Buffer.isBuffer(source)
9
- ? source
10
- : Buffer.from(source.buffer, source.byteOffset, source.byteLength);
11
- }
12
- function findArchiveEnd(tail, tailStart, fileSize) {
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;
25
- }
26
- async function readExactly(handle, length, position) {
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;
36
- }
37
- async function findFileArchiveEnd(path) {
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
- }
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
- */
67
- class TruncatedFileReader extends Reader {
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 });
96
- }
97
- }
98
- async function openBufferZip(data) {
99
- try {
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
- }
113
- }
114
- }
115
- async function openFileZip(path) {
116
- try {
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
- }
131
- }
132
- }
133
- export async function openZip(source) {
134
- return typeof source === "string"
135
- ? openFileZip(source)
136
- : openBufferZip(toBuffer(source));
137
- }