narrarium-astro-reader 0.1.0 → 0.1.2
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 +3 -1
- package/astro.config.mjs +43 -0
- package/cli-dist/cli.js +1 -0
- package/cli-dist/cli.js.map +1 -1
- package/cli-dist/scaffold.d.ts.map +1 -1
- package/cli-dist/scaffold.js +7 -15
- package/cli-dist/scaffold.js.map +1 -1
- package/package.json +7 -4
- package/scripts/book-config.mjs +1 -0
- package/scripts/book-dev-utils.mjs +56 -0
- package/scripts/dev.mjs +116 -0
- package/scripts/export-epub.mjs +3 -11
- package/src/cli.ts +1 -0
- package/src/scaffold.ts +7 -15
package/README.md
CHANGED
|
@@ -34,6 +34,7 @@ npx narrarium-astro-reader reader --book-root .. --package-name my-book-reader
|
|
|
34
34
|
- timeline index and event detail pages
|
|
35
35
|
- automatic rendering of canonical book, entity, chapter, and scene images when matching assets exist
|
|
36
36
|
- automatic EPUB export for `public/downloads/book.epub`
|
|
37
|
+
- live watcher for book markdown, canon, and assets during `npm run dev`
|
|
37
38
|
- web-only canon mention popups and light or dark theme toggle
|
|
38
39
|
- popup tabs for overview, notes, metadata, and image previews
|
|
39
40
|
- starter GitHub Pages deployment workflow when scaffolded into a standalone app
|
|
@@ -47,6 +48,7 @@ npm run dev
|
|
|
47
48
|
```
|
|
48
49
|
|
|
49
50
|
The generated reader expects `NARRARIUM_BOOK_ROOT` to point at a Narrarium book repository.
|
|
50
|
-
|
|
51
|
+
`npm run dev` now watches the linked book repo, regenerates the EPUB on changes, and triggers a full browser reload.
|
|
52
|
+
`npm run build` also refreshes the EPUB automatically before Astro builds.
|
|
51
53
|
|
|
52
54
|
You can also pass `--pages-domain example.com` when scaffolding to emit `public/CNAME` and a Pages workflow already pointed at that domain.
|
package/astro.config.mjs
CHANGED
|
@@ -1,12 +1,55 @@
|
|
|
1
1
|
import { defineConfig } from "astro/config";
|
|
2
|
+
import chokidar from "chokidar";
|
|
3
|
+
import { defaultBookRoot } from "./scripts/book-config.mjs";
|
|
4
|
+
import { formatWatchedPath, resolveBookRoot, resolveBookWatchTargets } from "./scripts/book-dev-utils.mjs";
|
|
2
5
|
|
|
3
6
|
const repoName = process.env.GITHUB_REPOSITORY?.split("/")[1];
|
|
4
7
|
const base = process.env.SITE_BASE ?? (process.env.GITHUB_ACTIONS === "true" && repoName ? `/${repoName}/` : "/");
|
|
5
8
|
const site = process.env.SITE_URL;
|
|
6
9
|
|
|
10
|
+
function narrariumBookReloadPlugin() {
|
|
11
|
+
return {
|
|
12
|
+
name: "narrarium-book-reload",
|
|
13
|
+
configureServer(server) {
|
|
14
|
+
const bookRoot = resolveBookRoot(defaultBookRoot);
|
|
15
|
+
const watchTargets = resolveBookWatchTargets(bookRoot);
|
|
16
|
+
let reloadTimer = null;
|
|
17
|
+
const watcher = chokidar.watch(watchTargets, {
|
|
18
|
+
ignoreInitial: true,
|
|
19
|
+
awaitWriteFinish: {
|
|
20
|
+
stabilityThreshold: 150,
|
|
21
|
+
pollInterval: 50,
|
|
22
|
+
},
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
const queueReload = (eventName, filePath) => {
|
|
26
|
+
clearTimeout(reloadTimer);
|
|
27
|
+
reloadTimer = setTimeout(() => {
|
|
28
|
+
server.config.logger.info(`[narrarium-reader] Reloading after ${eventName} ${formatWatchedPath(filePath, bookRoot)}`);
|
|
29
|
+
server.ws.send({ type: "full-reload" });
|
|
30
|
+
}, 120);
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
watcher.on("all", (eventName, filePath) => {
|
|
34
|
+
queueReload(eventName, filePath);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
server.config.logger.info(`[narrarium-reader] Hot reload watching ${bookRoot}`);
|
|
38
|
+
|
|
39
|
+
server.httpServer?.once("close", () => {
|
|
40
|
+
clearTimeout(reloadTimer);
|
|
41
|
+
void watcher.close();
|
|
42
|
+
});
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
|
|
7
47
|
export default defineConfig({
|
|
8
48
|
output: "static",
|
|
9
49
|
site,
|
|
10
50
|
base,
|
|
11
51
|
trailingSlash: "always",
|
|
52
|
+
vite: {
|
|
53
|
+
plugins: [narrariumBookReloadPlugin()],
|
|
54
|
+
},
|
|
12
55
|
});
|
package/cli-dist/cli.js
CHANGED
|
@@ -20,6 +20,7 @@ output.write([
|
|
|
20
20
|
"- npm install",
|
|
21
21
|
"- copy .env.example to .env if you want a local override",
|
|
22
22
|
"- npm run dev",
|
|
23
|
+
"- The dev server will watch the linked book repo, refresh the EPUB, and reload the site while you write",
|
|
23
24
|
].join("\n"));
|
|
24
25
|
async function resolveInputs(args) {
|
|
25
26
|
if (args.targetDir) {
|
package/cli-dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,KAAK,IAAI,KAAK,EAAE,MAAM,IAAI,MAAM,EAAE,MAAM,cAAc,CAAC;AAChE,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAUnD,MAAM,IAAI,GAAG,SAAS,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AAC9C,MAAM,QAAQ,GAAG,MAAM,aAAa,CAAC,IAAI,CAAC,CAAC;AAC3C,MAAM,MAAM,GAAG,MAAM,kBAAkB,CAAC,QAAQ,CAAC,SAAS,EAAE;IAC1D,QAAQ,EAAE,QAAQ,CAAC,QAAQ;IAC3B,WAAW,EAAE,QAAQ,CAAC,WAAW;IACjC,cAAc,EAAE,QAAQ,CAAC,cAAc;IACvC,WAAW,EAAE,QAAQ,CAAC,WAAW;CAClC,CAAC,CAAC;AAEH,MAAM,CAAC,KAAK,CACV;IACE,kCAAkC,MAAM,CAAC,UAAU,EAAE;IACrD,sBAAsB,MAAM,CAAC,QAAQ,EAAE;IACvC,oBAAoB,MAAM,CAAC,cAAc,EAAE;IAC3C,EAAE;IACF,aAAa;IACb,QAAQ,MAAM,CAAC,UAAU,EAAE;IAC3B,eAAe;IACf,0DAA0D;IAC1D,eAAe;
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scaffold.d.ts","sourceRoot":"","sources":["../src/scaffold.ts"],"names":[],"mappings":"AAIA,KAAK,eAAe,GAAG;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,wBAAsB,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,GAAE,eAAoB;;;;;
|
|
1
|
+
{"version":3,"file":"scaffold.d.ts","sourceRoot":"","sources":["../src/scaffold.ts"],"names":[],"mappings":"AAIA,KAAK,eAAe,GAAG;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,wBAAsB,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,GAAE,eAAoB;;;;;GAuFxF"}
|
package/cli-dist/scaffold.js
CHANGED
|
@@ -18,6 +18,7 @@ export async function scaffoldReaderSite(targetDir, options = {}) {
|
|
|
18
18
|
await Promise.all([
|
|
19
19
|
copyFile(path.join(packageRoot, "astro.config.mjs"), path.join(targetRoot, "astro.config.mjs")),
|
|
20
20
|
copyFile(path.join(packageRoot, "tsconfig.json"), path.join(targetRoot, "tsconfig.json")),
|
|
21
|
+
cp(path.join(packageRoot, "scripts"), path.join(targetRoot, "scripts"), { recursive: true }),
|
|
21
22
|
cp(path.join(packageRoot, "src", "components"), path.join(targetRoot, "src", "components"), { recursive: true }),
|
|
22
23
|
cp(path.join(packageRoot, "src", "lib"), path.join(targetRoot, "src", "lib"), { recursive: true }),
|
|
23
24
|
cp(path.join(packageRoot, "src", "layouts"), path.join(targetRoot, "src", "layouts"), { recursive: true }),
|
|
@@ -29,13 +30,14 @@ export async function scaffoldReaderSite(targetDir, options = {}) {
|
|
|
29
30
|
type: "module",
|
|
30
31
|
scripts: {
|
|
31
32
|
"export:epub": "node ./scripts/export-epub.mjs",
|
|
32
|
-
dev: "
|
|
33
|
+
dev: "node ./scripts/dev.mjs",
|
|
33
34
|
build: "npm run export:epub && astro build",
|
|
34
35
|
preview: "astro preview",
|
|
35
36
|
},
|
|
36
37
|
dependencies: {
|
|
37
38
|
"narrarium": coreDependency,
|
|
38
39
|
astro: "^5.14.1",
|
|
40
|
+
chokidar: "^4.0.3",
|
|
39
41
|
marked: "^16.3.0",
|
|
40
42
|
},
|
|
41
43
|
devDependencies: {
|
|
@@ -44,7 +46,7 @@ export async function scaffoldReaderSite(targetDir, options = {}) {
|
|
|
44
46
|
},
|
|
45
47
|
}, null, 2) + "\n", "utf8");
|
|
46
48
|
await writeFile(path.join(targetRoot, "src", "lib", "book-config.ts"), `export const defaultBookRoot = ${JSON.stringify(toPosix(bookRoot))};\n`, "utf8");
|
|
47
|
-
await writeFile(path.join(targetRoot, "scripts", "
|
|
49
|
+
await writeFile(path.join(targetRoot, "scripts", "book-config.mjs"), buildBookConfigScript(bookRoot), "utf8");
|
|
48
50
|
await writeFile(path.join(targetRoot, ".github", "workflows", "deploy-pages.yml"), buildPagesWorkflow(pagesDomain), "utf8");
|
|
49
51
|
if (pagesDomain) {
|
|
50
52
|
await writeFile(path.join(targetRoot, "public", "CNAME"), `${pagesDomain}\n`, "utf8");
|
|
@@ -80,6 +82,7 @@ npm run dev
|
|
|
80
82
|
\`\`\`
|
|
81
83
|
|
|
82
84
|
The dev server exports a fresh EPUB to \`public/downloads/book.epub\` before Astro starts.
|
|
85
|
+
It also watches the linked book repository, regenerates the EPUB when canon files change, and triggers a full browser reload.
|
|
83
86
|
|
|
84
87
|
## Build
|
|
85
88
|
|
|
@@ -95,19 +98,8 @@ A starter workflow already exists in \`.github/workflows/deploy-pages.yml\`.
|
|
|
95
98
|
By default it deploys to standard GitHub Pages using the repository name as the base path.
|
|
96
99
|
`;
|
|
97
100
|
}
|
|
98
|
-
function
|
|
99
|
-
return `
|
|
100
|
-
import path from "node:path";
|
|
101
|
-
import { exportEpub } from "narrarium";
|
|
102
|
-
|
|
103
|
-
const configured = process.env.NARRARIUM_BOOK_ROOT ?? process.env.GHOSTWRITER_BOOK_ROOT;
|
|
104
|
-
const root = path.resolve(process.cwd(), configured ?? ${JSON.stringify(toPosix(bookRoot))});
|
|
105
|
-
const outputPath = path.resolve(process.cwd(), "public", "downloads", "book.epub");
|
|
106
|
-
|
|
107
|
-
await mkdir(path.dirname(outputPath), { recursive: true });
|
|
108
|
-
const result = await exportEpub(root, { outputPath });
|
|
109
|
-
console.log(\`Exported EPUB with \${result.chapterCount} chapters to \${result.outputPath}\`);
|
|
110
|
-
`;
|
|
101
|
+
function buildBookConfigScript(bookRoot) {
|
|
102
|
+
return `export const defaultBookRoot = ${JSON.stringify(toPosix(bookRoot))};\n`;
|
|
111
103
|
}
|
|
112
104
|
function buildPagesWorkflow(pagesDomain) {
|
|
113
105
|
const envBlock = pagesDomain
|
package/cli-dist/scaffold.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scaffold.js","sourceRoot":"","sources":["../src/scaffold.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"scaffold.js","sourceRoot":"","sources":["../src/scaffold.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "narrarium-astro-reader",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Astro reader and scaffolding CLI for Narrarium book repositories.",
|
|
6
6
|
"license": "MIT",
|
|
@@ -15,7 +15,9 @@
|
|
|
15
15
|
"exports": {
|
|
16
16
|
"./scaffold": {
|
|
17
17
|
"types": "./cli-dist/scaffold.d.ts",
|
|
18
|
-
"import": "./cli-dist/scaffold.js"
|
|
18
|
+
"import": "./cli-dist/scaffold.js",
|
|
19
|
+
"require": "./cli-dist/scaffold.js",
|
|
20
|
+
"default": "./cli-dist/scaffold.js"
|
|
19
21
|
}
|
|
20
22
|
},
|
|
21
23
|
"files": [
|
|
@@ -41,14 +43,15 @@
|
|
|
41
43
|
"scripts": {
|
|
42
44
|
"build:cli": "tsc -p tsconfig.cli.json",
|
|
43
45
|
"export:epub": "node ./scripts/export-epub.mjs",
|
|
44
|
-
"dev": "
|
|
46
|
+
"dev": "node ./scripts/dev.mjs",
|
|
45
47
|
"build": "npm run build:cli && npm run export:epub && astro build",
|
|
46
48
|
"preview": "astro preview",
|
|
47
49
|
"test": "npm run build:cli && node --test test/**/*.test.mjs"
|
|
48
50
|
},
|
|
49
51
|
"dependencies": {
|
|
50
|
-
"narrarium": "^0.1.
|
|
52
|
+
"narrarium": "^0.1.2",
|
|
51
53
|
"astro": "^5.14.1",
|
|
54
|
+
"chokidar": "^4.0.3",
|
|
52
55
|
"marked": "^16.3.0"
|
|
53
56
|
},
|
|
54
57
|
"devDependencies": {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const defaultBookRoot = "../../example-book";
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { mkdir } from "node:fs/promises";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { exportEpub } from "narrarium";
|
|
4
|
+
|
|
5
|
+
const watchPatterns = [
|
|
6
|
+
"book.md",
|
|
7
|
+
"guidelines/**/*",
|
|
8
|
+
"chapters/**/*",
|
|
9
|
+
"characters/**/*",
|
|
10
|
+
"locations/**/*",
|
|
11
|
+
"factions/**/*",
|
|
12
|
+
"items/**/*",
|
|
13
|
+
"secrets/**/*",
|
|
14
|
+
"timeline/**/*",
|
|
15
|
+
"resumes/**/*",
|
|
16
|
+
"evaluations/**/*",
|
|
17
|
+
"research/**/*",
|
|
18
|
+
"assets/**/*",
|
|
19
|
+
"AGENTS.md",
|
|
20
|
+
"opencode.jsonc",
|
|
21
|
+
".opencode/**/*",
|
|
22
|
+
".claude/**/*",
|
|
23
|
+
];
|
|
24
|
+
|
|
25
|
+
export function resolveBookRoot(defaultBookRoot, cwd = process.cwd()) {
|
|
26
|
+
const configured = process.env.NARRARIUM_BOOK_ROOT ?? process.env.GHOSTWRITER_BOOK_ROOT;
|
|
27
|
+
return path.resolve(cwd, configured ?? defaultBookRoot);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export function resolveBookWatchTargets(bookRoot) {
|
|
31
|
+
return watchPatterns.map((pattern) => path.join(bookRoot, pattern));
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function formatWatchedPath(filePath, basePath) {
|
|
35
|
+
const relative = path.relative(basePath, filePath);
|
|
36
|
+
const target = relative && !relative.startsWith("..") ? relative : filePath;
|
|
37
|
+
return toPosix(target);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export async function exportReaderEpub(defaultBookRoot, cwd = process.cwd()) {
|
|
41
|
+
const bookRoot = resolveBookRoot(defaultBookRoot, cwd);
|
|
42
|
+
const outputPath = path.resolve(cwd, "public", "downloads", "book.epub");
|
|
43
|
+
|
|
44
|
+
await mkdir(path.dirname(outputPath), { recursive: true });
|
|
45
|
+
const result = await exportEpub(bookRoot, { outputPath });
|
|
46
|
+
|
|
47
|
+
return {
|
|
48
|
+
bookRoot,
|
|
49
|
+
outputPath,
|
|
50
|
+
result,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function toPosix(value) {
|
|
55
|
+
return value.split(path.sep).join("/");
|
|
56
|
+
}
|
package/scripts/dev.mjs
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { createRequire } from "node:module";
|
|
3
|
+
import process from "node:process";
|
|
4
|
+
import chokidar from "chokidar";
|
|
5
|
+
import { defaultBookRoot } from "./book-config.mjs";
|
|
6
|
+
import { exportReaderEpub, formatWatchedPath, resolveBookRoot, resolveBookWatchTargets } from "./book-dev-utils.mjs";
|
|
7
|
+
|
|
8
|
+
const require = createRequire(import.meta.url);
|
|
9
|
+
const astroCliPath = require.resolve("astro/astro.js");
|
|
10
|
+
const bookRoot = resolveBookRoot(defaultBookRoot);
|
|
11
|
+
const watchTargets = resolveBookWatchTargets(bookRoot);
|
|
12
|
+
|
|
13
|
+
let queuedReason = null;
|
|
14
|
+
let debounceTimer = null;
|
|
15
|
+
let exportInFlight = false;
|
|
16
|
+
let shuttingDown = false;
|
|
17
|
+
|
|
18
|
+
await runExport("startup");
|
|
19
|
+
|
|
20
|
+
const watcher = chokidar.watch(watchTargets, {
|
|
21
|
+
ignoreInitial: true,
|
|
22
|
+
awaitWriteFinish: {
|
|
23
|
+
stabilityThreshold: 150,
|
|
24
|
+
pollInterval: 50,
|
|
25
|
+
},
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
watcher.on("all", (eventName, filePath) => {
|
|
29
|
+
const action = describeEvent(eventName);
|
|
30
|
+
queueExport(`${action} ${formatWatchedPath(filePath, bookRoot)}`);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
console.log(`[narrarium-reader] Watching book files in ${bookRoot}`);
|
|
34
|
+
|
|
35
|
+
const astroProcess = spawn(process.execPath, [astroCliPath, "dev", ...process.argv.slice(2)], {
|
|
36
|
+
stdio: "inherit",
|
|
37
|
+
env: process.env,
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
astroProcess.on("exit", async (code, signal) => {
|
|
41
|
+
await closeWatcher();
|
|
42
|
+
if (signal) {
|
|
43
|
+
process.exit(0);
|
|
44
|
+
}
|
|
45
|
+
process.exit(code ?? 0);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
for (const signal of ["SIGINT", "SIGTERM"]) {
|
|
49
|
+
process.on(signal, async () => {
|
|
50
|
+
if (shuttingDown) return;
|
|
51
|
+
shuttingDown = true;
|
|
52
|
+
clearTimeout(debounceTimer);
|
|
53
|
+
await closeWatcher();
|
|
54
|
+
astroProcess.kill(signal);
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function queueExport(reason) {
|
|
59
|
+
queuedReason = reason;
|
|
60
|
+
clearTimeout(debounceTimer);
|
|
61
|
+
debounceTimer = setTimeout(() => {
|
|
62
|
+
void flushQueuedExport();
|
|
63
|
+
}, 120);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
async function flushQueuedExport() {
|
|
67
|
+
if (!queuedReason || exportInFlight) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
const reason = queuedReason;
|
|
72
|
+
queuedReason = null;
|
|
73
|
+
await runExport(reason);
|
|
74
|
+
|
|
75
|
+
if (queuedReason) {
|
|
76
|
+
await flushQueuedExport();
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
async function runExport(reason) {
|
|
81
|
+
exportInFlight = true;
|
|
82
|
+
try {
|
|
83
|
+
const { result } = await exportReaderEpub(defaultBookRoot);
|
|
84
|
+
if (reason === "startup") {
|
|
85
|
+
console.log(`[narrarium-reader] Exported EPUB with ${result.chapterCount} chapters to ${result.outputPath}`);
|
|
86
|
+
} else {
|
|
87
|
+
console.log(`[narrarium-reader] Updated EPUB after ${reason}`);
|
|
88
|
+
}
|
|
89
|
+
} catch (error) {
|
|
90
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
91
|
+
console.error(`[narrarium-reader] EPUB export failed: ${message}`);
|
|
92
|
+
} finally {
|
|
93
|
+
exportInFlight = false;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
async function closeWatcher() {
|
|
98
|
+
await watcher.close().catch(() => undefined);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function describeEvent(eventName) {
|
|
102
|
+
switch (eventName) {
|
|
103
|
+
case "add":
|
|
104
|
+
return "added";
|
|
105
|
+
case "addDir":
|
|
106
|
+
return "created";
|
|
107
|
+
case "change":
|
|
108
|
+
return "saved";
|
|
109
|
+
case "unlink":
|
|
110
|
+
return "removed";
|
|
111
|
+
case "unlinkDir":
|
|
112
|
+
return "deleted";
|
|
113
|
+
default:
|
|
114
|
+
return eventName;
|
|
115
|
+
}
|
|
116
|
+
}
|
package/scripts/export-epub.mjs
CHANGED
|
@@ -1,13 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import
|
|
3
|
-
import { exportEpub } from "narrarium";
|
|
1
|
+
import { defaultBookRoot } from "./book-config.mjs";
|
|
2
|
+
import { exportReaderEpub } from "./book-dev-utils.mjs";
|
|
4
3
|
|
|
5
|
-
const
|
|
6
|
-
const bookRoot = configuredBookRoot
|
|
7
|
-
? path.resolve(configuredBookRoot)
|
|
8
|
-
: path.resolve(process.cwd(), "../../example-book");
|
|
9
|
-
const outputPath = path.resolve(process.cwd(), "public", "downloads", "book.epub");
|
|
10
|
-
|
|
11
|
-
await mkdir(path.dirname(outputPath), { recursive: true });
|
|
12
|
-
const result = await exportEpub(bookRoot, { outputPath });
|
|
4
|
+
const { result } = await exportReaderEpub(defaultBookRoot);
|
|
13
5
|
console.log(`Exported EPUB with ${result.chapterCount} chapters to ${result.outputPath}`);
|
package/src/cli.ts
CHANGED
package/src/scaffold.ts
CHANGED
|
@@ -28,6 +28,7 @@ export async function scaffoldReaderSite(targetDir: string, options: ScaffoldOpt
|
|
|
28
28
|
await Promise.all([
|
|
29
29
|
copyFile(path.join(packageRoot, "astro.config.mjs"), path.join(targetRoot, "astro.config.mjs")),
|
|
30
30
|
copyFile(path.join(packageRoot, "tsconfig.json"), path.join(targetRoot, "tsconfig.json")),
|
|
31
|
+
cp(path.join(packageRoot, "scripts"), path.join(targetRoot, "scripts"), { recursive: true }),
|
|
31
32
|
cp(path.join(packageRoot, "src", "components"), path.join(targetRoot, "src", "components"), { recursive: true }),
|
|
32
33
|
cp(path.join(packageRoot, "src", "lib"), path.join(targetRoot, "src", "lib"), { recursive: true }),
|
|
33
34
|
cp(path.join(packageRoot, "src", "layouts"), path.join(targetRoot, "src", "layouts"), { recursive: true }),
|
|
@@ -43,13 +44,14 @@ export async function scaffoldReaderSite(targetDir: string, options: ScaffoldOpt
|
|
|
43
44
|
type: "module",
|
|
44
45
|
scripts: {
|
|
45
46
|
"export:epub": "node ./scripts/export-epub.mjs",
|
|
46
|
-
dev: "
|
|
47
|
+
dev: "node ./scripts/dev.mjs",
|
|
47
48
|
build: "npm run export:epub && astro build",
|
|
48
49
|
preview: "astro preview",
|
|
49
50
|
},
|
|
50
51
|
dependencies: {
|
|
51
52
|
"narrarium": coreDependency,
|
|
52
53
|
astro: "^5.14.1",
|
|
54
|
+
chokidar: "^4.0.3",
|
|
53
55
|
marked: "^16.3.0",
|
|
54
56
|
},
|
|
55
57
|
devDependencies: {
|
|
@@ -69,7 +71,7 @@ export async function scaffoldReaderSite(targetDir: string, options: ScaffoldOpt
|
|
|
69
71
|
"utf8",
|
|
70
72
|
);
|
|
71
73
|
|
|
72
|
-
await writeFile(path.join(targetRoot, "scripts", "
|
|
74
|
+
await writeFile(path.join(targetRoot, "scripts", "book-config.mjs"), buildBookConfigScript(bookRoot), "utf8");
|
|
73
75
|
await writeFile(
|
|
74
76
|
path.join(targetRoot, ".github", "workflows", "deploy-pages.yml"),
|
|
75
77
|
buildPagesWorkflow(pagesDomain),
|
|
@@ -117,6 +119,7 @@ npm run dev
|
|
|
117
119
|
\`\`\`
|
|
118
120
|
|
|
119
121
|
The dev server exports a fresh EPUB to \`public/downloads/book.epub\` before Astro starts.
|
|
122
|
+
It also watches the linked book repository, regenerates the EPUB when canon files change, and triggers a full browser reload.
|
|
120
123
|
|
|
121
124
|
## Build
|
|
122
125
|
|
|
@@ -133,19 +136,8 @@ By default it deploys to standard GitHub Pages using the repository name as the
|
|
|
133
136
|
`;
|
|
134
137
|
}
|
|
135
138
|
|
|
136
|
-
function
|
|
137
|
-
return `
|
|
138
|
-
import path from "node:path";
|
|
139
|
-
import { exportEpub } from "narrarium";
|
|
140
|
-
|
|
141
|
-
const configured = process.env.NARRARIUM_BOOK_ROOT ?? process.env.GHOSTWRITER_BOOK_ROOT;
|
|
142
|
-
const root = path.resolve(process.cwd(), configured ?? ${JSON.stringify(toPosix(bookRoot))});
|
|
143
|
-
const outputPath = path.resolve(process.cwd(), "public", "downloads", "book.epub");
|
|
144
|
-
|
|
145
|
-
await mkdir(path.dirname(outputPath), { recursive: true });
|
|
146
|
-
const result = await exportEpub(root, { outputPath });
|
|
147
|
-
console.log(\`Exported EPUB with \${result.chapterCount} chapters to \${result.outputPath}\`);
|
|
148
|
-
`;
|
|
139
|
+
function buildBookConfigScript(bookRoot: string): string {
|
|
140
|
+
return `export const defaultBookRoot = ${JSON.stringify(toPosix(bookRoot))};\n`;
|
|
149
141
|
}
|
|
150
142
|
|
|
151
143
|
function buildPagesWorkflow(pagesDomain?: string): string {
|