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 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
- Both `npm run dev` and `npm run build` refresh the EPUB automatically before Astro runs.
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) {
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
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;;;;;GAqFxF"}
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"}
@@ -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: "npm run export:epub && astro 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", "export-epub.mjs"), buildExportEpubScript(bookRoot), "utf8");
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 buildExportEpubScript(bookRoot) {
99
- return `import { mkdir } from "node:fs/promises";
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
@@ -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.0",
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": "npm run export:epub && astro 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.0",
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
+ }
@@ -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
+ }
@@ -1,13 +1,5 @@
1
- import { mkdir } from "node:fs/promises";
2
- import path from "node:path";
3
- import { exportEpub } from "narrarium";
1
+ import { defaultBookRoot } from "./book-config.mjs";
2
+ import { exportReaderEpub } from "./book-dev-utils.mjs";
4
3
 
5
- const configuredBookRoot = process.env.NARRARIUM_BOOK_ROOT ?? process.env.GHOSTWRITER_BOOK_ROOT;
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
@@ -32,6 +32,7 @@ output.write(
32
32
  "- npm install",
33
33
  "- copy .env.example to .env if you want a local override",
34
34
  "- npm run dev",
35
+ "- The dev server will watch the linked book repo, refresh the EPUB, and reload the site while you write",
35
36
  ].join("\n"),
36
37
  );
37
38
 
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: "npm run export:epub && astro 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", "export-epub.mjs"), buildExportEpubScript(bookRoot), "utf8");
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 buildExportEpubScript(bookRoot: string): string {
137
- return `import { mkdir } from "node:fs/promises";
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 {