@storyteller-platform/epub 0.6.3 → 0.7.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.
- package/README.md +529 -1075
- package/dist/adapters/interface.d.cts +25 -19
- package/dist/adapters/interface.d.ts +25 -19
- package/dist/adapters/memory.cjs +19 -29
- package/dist/adapters/memory.d.cts +4 -5
- package/dist/adapters/memory.d.ts +4 -5
- package/dist/adapters/memory.js +19 -32
- package/dist/adapters/tmpfs.cjs +50 -45
- package/dist/adapters/tmpfs.d.cts +9 -7
- package/dist/adapters/tmpfs.d.ts +9 -7
- package/dist/adapters/tmpfs.js +50 -45
- package/dist/epubcheck.cjs +2 -2
- package/dist/epubcheck.js +2 -2
- package/dist/index.cjs +585 -94
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +586 -100
- package/dist/upgrade.cjs +12 -44
- package/dist/upgrade.d.cts +175 -11
- package/dist/upgrade.d.ts +175 -11
- package/dist/upgrade.js +12 -44
- package/dist/zip.cjs +142 -0
- package/dist/zip.d.cts +5 -0
- package/dist/zip.d.ts +5 -0
- package/dist/zip.js +124 -0
- package/package.json +4 -5
package/dist/adapters/tmpfs.js
CHANGED
|
@@ -13,38 +13,23 @@ import {
|
|
|
13
13
|
stat,
|
|
14
14
|
writeFile
|
|
15
15
|
} from "node:fs/promises";
|
|
16
|
-
import { tmpdir } from "node:os";
|
|
17
16
|
import { pipeline } from "node:stream/promises";
|
|
18
|
-
import { fromBuffer, open } from "yauzl-promise";
|
|
19
17
|
import { ZipFile } from "yazl";
|
|
18
|
+
import { scratchPath } from "@storyteller-platform/fs";
|
|
19
|
+
import { MediaType } from "@storyteller-platform/media-types";
|
|
20
20
|
import { dirname, join, sep } from "@storyteller-platform/path";
|
|
21
|
-
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
const FLAC_FILE_EXTENSIONS = [".flac"];
|
|
29
|
-
const ALAC_FILE_EXTENSIONS = [".alac"];
|
|
30
|
-
const WEBM_FILE_EXTENSIONS = [".weba"];
|
|
31
|
-
const AUDIO_FILE_EXTENSIONS = [
|
|
32
|
-
...MP3_FILE_EXTENSIONS,
|
|
33
|
-
...AAC_FILE_EXTENSIONS,
|
|
34
|
-
...MPEG4_FILE_EXTENSIONS,
|
|
35
|
-
...OPUS_FILE_EXTENSIONS,
|
|
36
|
-
...OGG_FILE_EXTENSIONS,
|
|
37
|
-
...WAVE_FILE_EXTENSIONS,
|
|
38
|
-
...AIFF_FILE_EXTENSIONS,
|
|
39
|
-
...FLAC_FILE_EXTENSIONS,
|
|
40
|
-
...ALAC_FILE_EXTENSIONS,
|
|
41
|
-
...WEBM_FILE_EXTENSIONS
|
|
42
|
-
];
|
|
43
|
-
function isAudioFile(filenameOrExt) {
|
|
44
|
-
return AUDIO_FILE_EXTENSIONS.some((ext) => filenameOrExt.endsWith(ext));
|
|
45
|
-
}
|
|
21
|
+
import { openZip } from "../zip.js";
|
|
22
|
+
const PRECOMPRESSED_KINDS = /* @__PURE__ */ new Set([
|
|
23
|
+
"audio",
|
|
24
|
+
"image",
|
|
25
|
+
"archive",
|
|
26
|
+
"package"
|
|
27
|
+
]);
|
|
46
28
|
function mintRootPath() {
|
|
47
|
-
return
|
|
29
|
+
return scratchPath(`storyteller-platform-epub-${randomUUID()}`);
|
|
30
|
+
}
|
|
31
|
+
function isStorableEntryName(entry) {
|
|
32
|
+
return !entry.split("/").some((segment) => segment === "" || segment === "." || segment === "..");
|
|
48
33
|
}
|
|
49
34
|
class TmpFsAdapter {
|
|
50
35
|
constructor(rootPath) {
|
|
@@ -57,7 +42,7 @@ class TmpFsAdapter {
|
|
|
57
42
|
try {
|
|
58
43
|
var _stack = [];
|
|
59
44
|
try {
|
|
60
|
-
const zipfile =
|
|
45
|
+
const zipfile = await openZip(source);
|
|
61
46
|
const stack = __using(_stack, new AsyncDisposableStack(), true);
|
|
62
47
|
stack.defer(async () => {
|
|
63
48
|
await zipfile.close();
|
|
@@ -66,7 +51,8 @@ class TmpFsAdapter {
|
|
|
66
51
|
if (entry.filename.endsWith("/")) {
|
|
67
52
|
continue;
|
|
68
53
|
}
|
|
69
|
-
|
|
54
|
+
if (!isStorableEntryName(entry.filename)) continue;
|
|
55
|
+
const writePath = join(rootPath, ...entry.filename.split("/"));
|
|
70
56
|
const readStream = await entry.openReadStream();
|
|
71
57
|
await mkdir(dirname(writePath), { recursive: true });
|
|
72
58
|
const writeStream = createWriteStream(writePath);
|
|
@@ -89,19 +75,36 @@ class TmpFsAdapter {
|
|
|
89
75
|
await mkdir(rootPath, { recursive: true });
|
|
90
76
|
return new TmpFsAdapter(rootPath);
|
|
91
77
|
}
|
|
92
|
-
|
|
93
|
-
|
|
78
|
+
diskPath(entry) {
|
|
79
|
+
if (!isStorableEntryName(entry)) {
|
|
80
|
+
const err = new Error(`ENOENT: no such entry in EPUB archive: ${entry}`);
|
|
81
|
+
err.code = "ENOENT";
|
|
82
|
+
throw err;
|
|
83
|
+
}
|
|
84
|
+
return join(this.rootPath, ...entry.split("/"));
|
|
85
|
+
}
|
|
86
|
+
async read(entry, encoding) {
|
|
87
|
+
return await readFile(this.diskPath(entry), encoding);
|
|
94
88
|
}
|
|
95
|
-
async write(
|
|
89
|
+
async write(entry, data, encoding) {
|
|
90
|
+
const path = this.diskPath(entry);
|
|
96
91
|
await mkdir(dirname(path), { recursive: true });
|
|
97
92
|
await writeFile(path, data, encoding);
|
|
98
93
|
}
|
|
99
|
-
async remove(
|
|
100
|
-
await rm(
|
|
94
|
+
async remove(entry) {
|
|
95
|
+
await rm(this.diskPath(entry));
|
|
96
|
+
}
|
|
97
|
+
async exists(entry) {
|
|
98
|
+
try {
|
|
99
|
+
await stat(this.diskPath(entry));
|
|
100
|
+
return true;
|
|
101
|
+
} catch {
|
|
102
|
+
return false;
|
|
103
|
+
}
|
|
101
104
|
}
|
|
102
|
-
async archiveLength(
|
|
105
|
+
async archiveLength(entry) {
|
|
103
106
|
try {
|
|
104
|
-
const st = await stat(
|
|
107
|
+
const st = await stat(this.diskPath(entry));
|
|
105
108
|
return st.size;
|
|
106
109
|
} catch {
|
|
107
110
|
return 0;
|
|
@@ -117,7 +120,7 @@ class TmpFsAdapter {
|
|
|
117
120
|
const absolutePath = join(entry.parentPath, entry.name);
|
|
118
121
|
yield {
|
|
119
122
|
absolutePath,
|
|
120
|
-
relativePath: absolutePath.
|
|
123
|
+
relativePath: absolutePath.slice(this.rootPath.length + 1).split(sep).join("/")
|
|
121
124
|
};
|
|
122
125
|
}
|
|
123
126
|
}
|
|
@@ -132,31 +135,33 @@ class TmpFsAdapter {
|
|
|
132
135
|
return new TmpFsAdapter(newRoot);
|
|
133
136
|
}
|
|
134
137
|
async serialize(targetPath) {
|
|
138
|
+
var _a;
|
|
135
139
|
var _stack = [];
|
|
136
140
|
try {
|
|
137
|
-
const tmpArchivePath =
|
|
138
|
-
|
|
139
|
-
`storyteller-platform-epub-${randomUUID()}`
|
|
140
|
-
);
|
|
141
|
-
const { promise, resolve } = Promise.withResolvers();
|
|
141
|
+
const tmpArchivePath = mintRootPath();
|
|
142
|
+
const { promise, resolve, reject } = Promise.withResolvers();
|
|
142
143
|
const zipfile = new ZipFile();
|
|
143
144
|
const writeStream = createWriteStream(tmpArchivePath);
|
|
144
145
|
writeStream.on("close", () => {
|
|
145
146
|
resolve();
|
|
146
147
|
});
|
|
148
|
+
writeStream.on("error", reject);
|
|
149
|
+
zipfile.outputStream.on("error", reject);
|
|
147
150
|
const stack = __using(_stack, new AsyncDisposableStack(), true);
|
|
148
151
|
stack.defer(async () => {
|
|
149
152
|
writeStream.close();
|
|
150
153
|
await rm(tmpArchivePath, { force: true });
|
|
151
154
|
});
|
|
152
155
|
zipfile.outputStream.pipe(writeStream);
|
|
153
|
-
zipfile.addBuffer(Buffer.from(
|
|
156
|
+
zipfile.addBuffer(Buffer.from(MediaType.EPUB.mime), "mimetype", {
|
|
154
157
|
compress: false
|
|
155
158
|
});
|
|
156
159
|
for await (const entry of this.list()) {
|
|
157
160
|
if (entry.relativePath === "mimetype") continue;
|
|
158
161
|
zipfile.addFile(entry.absolutePath, entry.relativePath, {
|
|
159
|
-
compress: !
|
|
162
|
+
compress: !PRECOMPRESSED_KINDS.has(
|
|
163
|
+
(_a = MediaType.fromPath(entry.absolutePath)) == null ? void 0 : _a.kind
|
|
164
|
+
)
|
|
160
165
|
});
|
|
161
166
|
}
|
|
162
167
|
zipfile.end();
|
package/dist/epubcheck.cjs
CHANGED
|
@@ -24,15 +24,15 @@ module.exports = __toCommonJS(epubcheck_exports);
|
|
|
24
24
|
var import_node_child_process = require("node:child_process");
|
|
25
25
|
var import_node_crypto = require("node:crypto");
|
|
26
26
|
var import_promises = require("node:fs/promises");
|
|
27
|
-
var import_node_os = require("node:os");
|
|
28
27
|
var import_node_path = require("node:path");
|
|
29
28
|
var import_node_url = require("node:url");
|
|
30
29
|
var import_node_util = require("node:util");
|
|
30
|
+
var import_fs = require("@storyteller-platform/fs");
|
|
31
31
|
const import_meta = {};
|
|
32
32
|
const here = (0, import_node_path.dirname)((0, import_node_url.fileURLToPath)(import_meta.url));
|
|
33
33
|
const JAR = (0, import_node_path.join)(here, "vendors", "epubcheck-5.3.0", "epubcheck.jar");
|
|
34
34
|
async function epubcheck(epubFile) {
|
|
35
|
-
const output = (0,
|
|
35
|
+
const output = (0, import_fs.scratchPath)(`epubcheck-${(0, import_node_crypto.randomUUID)()}.json`);
|
|
36
36
|
const execFilePromise = (0, import_node_util.promisify)(import_node_child_process.execFile);
|
|
37
37
|
try {
|
|
38
38
|
await execFilePromise("java", [
|
package/dist/epubcheck.js
CHANGED
|
@@ -2,14 +2,14 @@ import "./chunk-BIEQXUOY.js";
|
|
|
2
2
|
import { execFile } from "node:child_process";
|
|
3
3
|
import { randomUUID } from "node:crypto";
|
|
4
4
|
import { readFile, unlink } from "node:fs/promises";
|
|
5
|
-
import { tmpdir } from "node:os";
|
|
6
5
|
import { dirname, join } from "node:path";
|
|
7
6
|
import { fileURLToPath } from "node:url";
|
|
8
7
|
import { promisify } from "node:util";
|
|
8
|
+
import { scratchPath } from "@storyteller-platform/fs";
|
|
9
9
|
const here = dirname(fileURLToPath(import.meta.url));
|
|
10
10
|
const JAR = join(here, "vendors", "epubcheck-5.3.0", "epubcheck.jar");
|
|
11
11
|
async function epubcheck(epubFile) {
|
|
12
|
-
const output =
|
|
12
|
+
const output = scratchPath(`epubcheck-${randomUUID()}.json`);
|
|
13
13
|
const execFilePromise = promisify(execFile);
|
|
14
14
|
try {
|
|
15
15
|
await execFilePromise("java", [
|