narrarium-astro-reader 0.1.5 → 0.1.6

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
@@ -54,10 +54,9 @@ NARRARIUM_READER_ALLOW_FULL_CANON=true
54
54
 
55
55
  ## Local development
56
56
 
57
- Create `.env` from the example and point it at your book repo:
57
+ The scaffold creates `.env` with the computed book root already filled in. Update it if the reader should point somewhere else:
58
58
 
59
59
  ```bash
60
- cp .env.example .env
61
60
  npm install
62
61
  npm run dev
63
62
  ```
package/cli-dist/cli.js CHANGED
@@ -18,7 +18,7 @@ output.write([
18
18
  "Next steps:",
19
19
  `- cd ${result.targetRoot}`,
20
20
  "- npm install",
21
- "- copy .env.example to .env if you want a local override",
21
+ "- adjust .env if this reader should point at a different book root",
22
22
  "- npm run dev",
23
23
  "- The dev server will watch the linked book repo, refresh the EPUB, and reload the site while you write",
24
24
  ].join("\n"));
@@ -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":";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,oEAAoE;IACpE,eAAe;IACf,yGAAyG;CAC1G,CAAC,IAAI,CAAC,IAAI,CAAC,CACb,CAAC;AAEF,KAAK,UAAU,aAAa,CAAC,IAAgB;IAC3C,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;QACnB,OAAO;YACL,SAAS,EAAE,IAAI,CAAC,SAAS;YACzB,QAAQ,EAAE,IAAI,CAAC,QAAQ,IAAI,IAAI;YAC/B,WAAW,EAAE,IAAI,CAAC,WAAW;YAC7B,cAAc,EAAE,IAAI,CAAC,cAAc;YACnC,WAAW,EAAE,IAAI,CAAC,WAAW;SAC9B,CAAC;IACJ,CAAC;IAED,IAAI,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;QAClC,MAAM,IAAI,KAAK,CAAC,0IAA0I,CAAC,CAAC;IAC9J,CAAC;IAED,MAAM,EAAE,GAAG,eAAe,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;IAC9C,IAAI,CAAC;QACH,MAAM,SAAS,GAAG,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,0BAA0B,CAAC,CAAC,IAAI,QAAQ,CAAC;QAC9E,MAAM,QAAQ,GAAG,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,sDAAsD,CAAC,CAAC,IAAI,IAAI,CAAC;QACrG,MAAM,WAAW,GAAG,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,2BAA2B,CAAC,CAAC,IAAI,SAAS,CAAC;QAClF,MAAM,cAAc,GAAG,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,iDAAiD,CAAC,CAAC,IAAI,SAAS,CAAC;QAC3G,MAAM,WAAW,GAAG,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,yCAAyC,CAAC,CAAC,IAAI,SAAS,CAAC;QAChG,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,WAAW,EAAE,cAAc,EAAE,WAAW,EAAE,CAAC;IAC3E,CAAC;YAAS,CAAC;QACT,EAAE,CAAC,KAAK,EAAE,CAAC;IACb,CAAC;AACH,CAAC;AAED,SAAS,SAAS,CAAC,IAAc;IAC/B,MAAM,MAAM,GAAe,EAAE,CAAC;IAE9B,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,IAAI,CAAC,MAAM,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QACpD,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC;QAE1B,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YAC3B,IAAI,CAAC,MAAM,CAAC,SAAS;gBAAE,MAAM,CAAC,SAAS,GAAG,KAAK,CAAC;YAChD,SAAS;QACX,CAAC;QAED,QAAQ,KAAK,EAAE,CAAC;YACd,KAAK,aAAa;gBAChB,MAAM,CAAC,QAAQ,GAAG,IAAI,CAAC,EAAE,KAAK,CAAC,CAAC;gBAChC,MAAM;YACR,KAAK,gBAAgB;gBACnB,MAAM,CAAC,WAAW,GAAG,IAAI,CAAC,EAAE,KAAK,CAAC,CAAC;gBACnC,MAAM;YACR,KAAK,mBAAmB;gBACtB,MAAM,CAAC,cAAc,GAAG,IAAI,CAAC,EAAE,KAAK,CAAC,CAAC;gBACtC,MAAM;YACR,KAAK,gBAAgB;gBACnB,MAAM,CAAC,WAAW,GAAG,IAAI,CAAC,EAAE,KAAK,CAAC,CAAC;gBACnC,MAAM;YACR;gBACE,MAAM;QACV,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"book.d.ts","sourceRoot":"","sources":["../../src/lib/book.ts"],"names":[],"mappings":"AAYA,KAAK,gBAAgB,GACjB,WAAW,GACX,UAAU,GACV,SAAS,GACT,MAAM,GACN,QAAQ,GACR,gBAAgB,CAAC;AAErB,wBAAgB,WAAW,IAAI,MAAM,CAIpC;AAED,wBAAsB,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CrC;AAED,wBAAsB,mBAAmB,CAAC,WAAW,EAAE,MAAM;;;;;;;;GAG5D;AAED,wBAAsB,mBAAmB,CAAC,IAAI,EAAE,gBAAgB;;;;;;;;;GAa/D;AAED,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,gBAAgB,EAAE,IAAI,EAAE,MAAM;;;;;GAG5E;AAED,wBAAsB,oBAAoB;;;;;;;;;;;;;GAoBzC"}
1
+ {"version":3,"file":"book.d.ts","sourceRoot":"","sources":["../../src/lib/book.ts"],"names":[],"mappings":"AAaA,KAAK,gBAAgB,GACjB,WAAW,GACX,UAAU,GACV,SAAS,GACT,MAAM,GACN,QAAQ,GACR,gBAAgB,CAAC;AAErB,wBAAgB,WAAW,IAAI,MAAM,CAIpC;AAED,wBAAsB,gBAAgB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0CrC;AAED,wBAAsB,mBAAmB,CAAC,WAAW,EAAE,MAAM;;;;;;;;GAG5D;AAED,wBAAsB,mBAAmB,CAAC,IAAI,EAAE,gBAAgB;;;;;;;;;GAa/D;AAED,wBAAsB,kBAAkB,CAAC,IAAI,EAAE,gBAAgB,EAAE,IAAI,EAAE,MAAM;;;;;GAG5E;AAED,wBAAsB,oBAAoB;;;;;;;;;;;;;GAoBzC"}
@@ -1,8 +1,9 @@
1
1
  import path from "node:path";
2
2
  import { listChapters, listEntities, pathExists, readBook, readChapter, readEntity, readTimelineMain, } from "narrarium";
3
3
  import { defaultBookRoot } from "./book-config.js";
4
+ import { readReaderBookRootEnv } from "./env.js";
4
5
  export function getBookRoot() {
5
- const configured = process.env.NARRARIUM_BOOK_ROOT ?? process.env.GHOSTWRITER_BOOK_ROOT;
6
+ const configured = readReaderBookRootEnv();
6
7
  if (configured)
7
8
  return path.resolve(configured);
8
9
  return path.resolve(process.cwd(), defaultBookRoot);
@@ -1 +1 @@
1
- {"version":3,"file":"book.js","sourceRoot":"","sources":["../../src/lib/book.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"book.js","sourceRoot":"","sources":["../../src/lib/book.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ type EnvSource = Record<string, string | undefined> | null | undefined;
2
+ export declare function normalizeReaderEnvValue(value: string | null | undefined): string | undefined;
3
+ export declare function isClearlyInvalidBookRootValue(value: string | null | undefined): boolean;
4
+ export declare function readReaderEnv(keys: string[], sources?: EnvSource[]): string | undefined;
5
+ export declare function readReaderBookRootEnv(sources?: EnvSource[]): string | undefined;
6
+ export {};
7
+ //# sourceMappingURL=env.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env.d.ts","sourceRoot":"","sources":["../../src/lib/env.ts"],"names":[],"mappings":"AAAA,KAAK,SAAS,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,GAAG,IAAI,GAAG,SAAS,CAAC;AAOvE,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,CAkB5F;AAED,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAOvF;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO,GAAE,SAAS,EAA4B,GAAG,MAAM,GAAG,SAAS,CAehH;AAED,wBAAgB,qBAAqB,CAAC,OAAO,GAAE,SAAS,EAA4B,GAAG,MAAM,GAAG,SAAS,CAOxG"}
@@ -0,0 +1,44 @@
1
+ const astroEnv = (import.meta.env ?? {});
2
+ export function normalizeReaderEnvValue(value) {
3
+ if (typeof value !== "string") {
4
+ return undefined;
5
+ }
6
+ const trimmed = value.trim();
7
+ if (!trimmed) {
8
+ return undefined;
9
+ }
10
+ if ((trimmed.startsWith('"') && trimmed.endsWith('"')) ||
11
+ (trimmed.startsWith("'") && trimmed.endsWith("'"))) {
12
+ return trimmed.slice(1, -1).trim() || undefined;
13
+ }
14
+ return trimmed;
15
+ }
16
+ export function isClearlyInvalidBookRootValue(value) {
17
+ const normalized = normalizeReaderEnvValue(value);
18
+ if (!normalized) {
19
+ return true;
20
+ }
21
+ return normalized === "/" || normalized === "\\" || /^[a-zA-Z]:(?:[\\/])?$/.test(normalized);
22
+ }
23
+ export function readReaderEnv(keys, sources = [process.env, astroEnv]) {
24
+ for (const source of sources) {
25
+ if (!source) {
26
+ continue;
27
+ }
28
+ for (const key of keys) {
29
+ const value = normalizeReaderEnvValue(source[key]);
30
+ if (value) {
31
+ return value;
32
+ }
33
+ }
34
+ }
35
+ return undefined;
36
+ }
37
+ export function readReaderBookRootEnv(sources = [process.env, astroEnv]) {
38
+ const value = readReaderEnv(["NARRARIUM_BOOK_ROOT", "GHOSTWRITER_BOOK_ROOT"], sources);
39
+ if (!value || isClearlyInvalidBookRootValue(value)) {
40
+ return undefined;
41
+ }
42
+ return value;
43
+ }
44
+ //# sourceMappingURL=env.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"env.js","sourceRoot":"","sources":["../../src/lib/env.ts"],"names":[],"mappings":"AAEA,MAAM,QAAQ,GAAG,CAAE,MAAM,CAAC,IAAkE,CAAC,GAAG,IAAI,EAAE,CAGrG,CAAC;AAEF,MAAM,UAAU,uBAAuB,CAAC,KAAgC;IACtE,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;IAC7B,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,IACE,CAAC,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;QAClD,CAAC,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,EAClD,CAAC;QACD,OAAO,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,IAAI,SAAS,CAAC;IAClD,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,MAAM,UAAU,6BAA6B,CAAC,KAAgC;IAC5E,MAAM,UAAU,GAAG,uBAAuB,CAAC,KAAK,CAAC,CAAC;IAClD,IAAI,CAAC,UAAU,EAAE,CAAC;QAChB,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,UAAU,KAAK,GAAG,IAAI,UAAU,KAAK,IAAI,IAAI,uBAAuB,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;AAC/F,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,IAAc,EAAE,UAAuB,CAAC,OAAO,CAAC,GAAG,EAAE,QAAQ,CAAC;IAC1F,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,SAAS;QACX,CAAC;QAED,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACvB,MAAM,KAAK,GAAG,uBAAuB,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;YACnD,IAAI,KAAK,EAAE,CAAC;gBACV,OAAO,KAAK,CAAC;YACf,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,SAAS,CAAC;AACnB,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,UAAuB,CAAC,OAAO,CAAC,GAAG,EAAE,QAAQ,CAAC;IAClF,MAAM,KAAK,GAAG,aAAa,CAAC,CAAC,qBAAqB,EAAE,uBAAuB,CAAC,EAAE,OAAO,CAAC,CAAC;IACvF,IAAI,CAAC,KAAK,IAAI,6BAA6B,CAAC,KAAK,CAAC,EAAE,CAAC;QACnD,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"reader-mode.d.ts","sourceRoot":"","sources":["../../src/lib/reader-mode.ts"],"names":[],"mappings":"AAAA,wBAAgB,eAAe,IAAI,OAAO,CAQzC"}
1
+ {"version":3,"file":"reader-mode.d.ts","sourceRoot":"","sources":["../../src/lib/reader-mode.ts"],"names":[],"mappings":"AAEA,wBAAgB,eAAe,IAAI,OAAO,CAMzC"}
@@ -1,5 +1,6 @@
1
+ import { readReaderEnv } from "./env.js";
1
2
  export function isFullCanonMode() {
2
- const raw = String(process.env.NARRARIUM_READER_CANON_MODE ?? process.env.NARRARIUM_READER_ALLOW_FULL_CANON ?? "")
3
+ const raw = String(readReaderEnv(["NARRARIUM_READER_CANON_MODE", "NARRARIUM_READER_ALLOW_FULL_CANON"]) ?? "")
3
4
  .trim()
4
5
  .toLowerCase();
5
6
  return raw === "1" || raw === "true" || raw === "full" || raw === "author" || raw === "spoilers";
@@ -1 +1 @@
1
- {"version":3,"file":"reader-mode.js","sourceRoot":"","sources":["../../src/lib/reader-mode.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,eAAe;IAC7B,MAAM,GAAG,GAAG,MAAM,CAChB,OAAO,CAAC,GAAG,CAAC,2BAA2B,IAAI,OAAO,CAAC,GAAG,CAAC,iCAAiC,IAAI,EAAE,CAC/F;SACE,IAAI,EAAE;SACN,WAAW,EAAE,CAAC;IAEjB,OAAO,GAAG,KAAK,GAAG,IAAI,GAAG,KAAK,MAAM,IAAI,GAAG,KAAK,MAAM,IAAI,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,UAAU,CAAC;AACnG,CAAC"}
1
+ {"version":3,"file":"reader-mode.js","sourceRoot":"","sources":["../../src/lib/reader-mode.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,MAAM,UAAU,eAAe;IAC7B,MAAM,GAAG,GAAG,MAAM,CAAC,aAAa,CAAC,CAAC,6BAA6B,EAAE,mCAAmC,CAAC,CAAC,IAAI,EAAE,CAAC;SAC1G,IAAI,EAAE;SACN,WAAW,EAAE,CAAC;IAEjB,OAAO,GAAG,KAAK,GAAG,IAAI,GAAG,KAAK,MAAM,IAAI,GAAG,KAAK,MAAM,IAAI,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,UAAU,CAAC;AACnG,CAAC"}
@@ -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;;;;;GAkGxF"}
1
+ {"version":3,"file":"scaffold.d.ts","sourceRoot":"","sources":["../src/scaffold.ts"],"names":[],"mappings":"AAKA,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;;;;;GAkGxF"}
@@ -1,6 +1,7 @@
1
1
  import { cp, copyFile, mkdir, readFile, writeFile } from "node:fs/promises";
2
2
  import path from "node:path";
3
3
  import { fileURLToPath } from "node:url";
4
+ import { isClearlyInvalidBookRootValue, normalizeReaderEnvValue } from "./lib/env.js";
4
5
  export async function scaffoldReaderSite(targetDir, options = {}) {
5
6
  const targetRoot = path.resolve(targetDir);
6
7
  const packageRoot = path.dirname(fileURLToPath(new URL("../package.json", import.meta.url)));
@@ -52,13 +53,13 @@ export async function scaffoldReaderSite(targetDir, options = {}) {
52
53
  if (pagesDomain) {
53
54
  await writeFile(path.join(targetRoot, "public", "CNAME"), `${pagesDomain}\n`, "utf8");
54
55
  }
55
- await writeFile(path.join(targetRoot, ".env.example"), [
56
- `NARRARIUM_BOOK_ROOT=${toPosix(bookRoot)}`,
57
- "# NARRARIUM_READER_CANON_MODE=full",
58
- "# EPUBCHECK_CMD=epubcheck",
59
- "# EPUBCHECK_JAR=/absolute/path/to/epubcheck.jar",
60
- "",
61
- ].join("\n"), "utf8");
56
+ await writeFile(path.join(targetRoot, ".env.example"), buildReaderEnvFile(bookRoot), "utf8");
57
+ const envPath = path.join(targetRoot, ".env");
58
+ const existingEnv = await readFile(envPath, "utf8").catch(() => null);
59
+ const nextEnv = mergeReaderEnvFile(existingEnv, bookRoot);
60
+ if (nextEnv !== existingEnv) {
61
+ await writeFile(envPath, nextEnv, "utf8");
62
+ }
62
63
  await writeFile(path.join(targetRoot, ".gitignore"), "node_modules/\ndist/\n.astro/\n.env\npublic/downloads/\n", "utf8");
63
64
  await writeFile(path.join(targetRoot, "README.md"), buildReaderReadme(bookRoot), "utf8");
64
65
  return {
@@ -75,7 +76,7 @@ This site was scaffolded from \`narrarium-astro-reader\`.
75
76
 
76
77
  ## Configure
77
78
 
78
- Set the book root in a local environment file:
79
+ The scaffold creates a local \`.env\` with the book root already filled in. Adjust it if this reader should point somewhere else:
79
80
 
80
81
  \`\`\`bash
81
82
  NARRARIUM_BOOK_ROOT=${toPosix(bookRoot)}
@@ -123,6 +124,39 @@ By default it deploys to standard GitHub Pages using the repository name as the
123
124
  function buildBookConfigScript(bookRoot) {
124
125
  return `export const defaultBookRoot = ${JSON.stringify(toPosix(bookRoot))};\n`;
125
126
  }
127
+ function buildReaderEnvFile(bookRoot) {
128
+ return [
129
+ `NARRARIUM_BOOK_ROOT=${toPosix(bookRoot)}`,
130
+ "# NARRARIUM_READER_CANON_MODE=full",
131
+ "# EPUBCHECK_CMD=epubcheck",
132
+ "# EPUBCHECK_JAR=/absolute/path/to/epubcheck.jar",
133
+ "",
134
+ ].join("\n");
135
+ }
136
+ function mergeReaderEnvFile(existingContent, bookRoot) {
137
+ const desiredRoot = toPosix(bookRoot);
138
+ if (existingContent === null) {
139
+ return buildReaderEnvFile(bookRoot);
140
+ }
141
+ const lines = existingContent.split(/\r?\n/);
142
+ let handled = false;
143
+ const nextLines = lines.map((line) => {
144
+ const match = line.match(/^(\s*NARRARIUM_BOOK_ROOT\s*=\s*)(.*)$/);
145
+ if (!match) {
146
+ return line;
147
+ }
148
+ handled = true;
149
+ const currentValue = normalizeReaderEnvValue(match[2]);
150
+ if (currentValue && !isClearlyInvalidBookRootValue(currentValue)) {
151
+ return line;
152
+ }
153
+ return `${match[1]}${desiredRoot}`;
154
+ });
155
+ if (handled) {
156
+ return nextLines.join("\n");
157
+ }
158
+ return `${buildReaderEnvFile(bookRoot).trimEnd()}\n${existingContent}`;
159
+ }
126
160
  function buildPagesWorkflow(pagesDomain) {
127
161
  const envBlock = pagesDomain
128
162
  ? [" SITE_BASE: /", ` SITE_URL: https://${pagesDomain}`].join("\n")
@@ -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.5",
3
+ "version": "0.1.6",
4
4
  "type": "module",
5
5
  "description": "Astro reader and scaffolding CLI for Narrarium book repositories.",
6
6
  "license": "MIT",
@@ -50,7 +50,7 @@
50
50
  "test": "npm run build:cli && node --test test/**/*.test.mjs"
51
51
  },
52
52
  "dependencies": {
53
- "narrarium": "^0.1.5",
53
+ "narrarium": "^0.1.6",
54
54
  "astro": "^5.14.1",
55
55
  "chokidar": "^4.0.3",
56
56
  "marked": "^16.3.0"
@@ -2,6 +2,9 @@ import { spawn } from "node:child_process";
2
2
  import { mkdir } from "node:fs/promises";
3
3
  import path from "node:path";
4
4
  import { exportEpub } from "narrarium";
5
+ import { loadReaderEnvFiles } from "./env-loader.mjs";
6
+
7
+ loadReaderEnvFiles();
5
8
 
6
9
  const watchPatterns = [
7
10
  "book.md",
@@ -24,7 +27,7 @@ const watchPatterns = [
24
27
  ];
25
28
 
26
29
  export function resolveBookRoot(defaultBookRoot, cwd = process.cwd()) {
27
- const configured = process.env.NARRARIUM_BOOK_ROOT ?? process.env.GHOSTWRITER_BOOK_ROOT;
30
+ const configured = readBookRootEnv();
28
31
  return path.resolve(cwd, configured ?? defaultBookRoot);
29
32
  }
30
33
 
@@ -99,3 +102,35 @@ function runCommand(command, args) {
99
102
  function toPosix(value) {
100
103
  return value.split(path.sep).join("/");
101
104
  }
105
+
106
+ function readBookRootEnv() {
107
+ for (const key of ["NARRARIUM_BOOK_ROOT", "GHOSTWRITER_BOOK_ROOT"]) {
108
+ const value = normalizeEnvValue(process.env[key]);
109
+ if (value && !isClearlyInvalidBookRootValue(value)) {
110
+ return value;
111
+ }
112
+ }
113
+
114
+ return undefined;
115
+ }
116
+
117
+ function normalizeEnvValue(value) {
118
+ if (typeof value !== "string") {
119
+ return undefined;
120
+ }
121
+
122
+ const trimmed = value.trim();
123
+ if (!trimmed) {
124
+ return undefined;
125
+ }
126
+
127
+ if ((trimmed.startsWith('"') && trimmed.endsWith('"')) || (trimmed.startsWith("'") && trimmed.endsWith("'"))) {
128
+ return trimmed.slice(1, -1).trim() || undefined;
129
+ }
130
+
131
+ return trimmed;
132
+ }
133
+
134
+ function isClearlyInvalidBookRootValue(value) {
135
+ return value === "/" || value === "\\" || /^[a-zA-Z]:(?:[\\/])?$/.test(value);
136
+ }
@@ -0,0 +1,12 @@
1
+ import path from "node:path";
2
+ import process from "node:process";
3
+
4
+ export function loadReaderEnvFiles(cwd = process.cwd()) {
5
+ for (const fileName of [".env.local", ".env"]) {
6
+ try {
7
+ process.loadEnvFile(path.join(cwd, fileName));
8
+ } catch {
9
+ // Ignore missing or unreadable local env files.
10
+ }
11
+ }
12
+ }
package/src/cli.ts CHANGED
@@ -30,7 +30,7 @@ output.write(
30
30
  "Next steps:",
31
31
  `- cd ${result.targetRoot}`,
32
32
  "- npm install",
33
- "- copy .env.example to .env if you want a local override",
33
+ "- adjust .env if this reader should point at a different book root",
34
34
  "- npm run dev",
35
35
  "- The dev server will watch the linked book repo, refresh the EPUB, and reload the site while you write",
36
36
  ].join("\n"),
@@ -141,8 +141,8 @@ const chaptersJson = JSON.stringify(chapters).replace(/</g, "\\u003c");
141
141
  const toggle = document.querySelector("[data-theme-toggle]");
142
142
  if (!toggle) return;
143
143
 
144
- const saved = localStorage.getItem(themeStorageKey);
145
- const initialTheme = saved || (window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light");
144
+ const saved = readStorage(themeStorageKey);
145
+ const initialTheme = saved || (prefersDarkTheme() ? "dark" : "light");
146
146
  applyTheme(initialTheme);
147
147
 
148
148
  toggle.addEventListener("click", () => {
@@ -158,7 +158,7 @@ const chaptersJson = JSON.stringify(chapters).replace(/</g, "\\u003c");
158
158
  toggle.setAttribute("aria-label", theme === "dark" ? "Switch to light mode" : "Switch to dark mode");
159
159
  }
160
160
  if (persist) {
161
- localStorage.setItem(themeStorageKey, theme);
161
+ writeStorage(themeStorageKey, theme);
162
162
  }
163
163
  }
164
164
 
@@ -184,7 +184,7 @@ const chaptersJson = JSON.stringify(chapters).replace(/</g, "\\u003c");
184
184
  root.style.setProperty("--reader-leading", String(preferences.lineHeight || 1.72));
185
185
  root.style.setProperty("--reader-measure", preferences.measure || "72ch");
186
186
  root.style.setProperty("--reader-copy-family", fontFamilyValue(preferences.fontFamily));
187
- localStorage.setItem(preferencesStorageKey, JSON.stringify(preferences));
187
+ writeStorage(preferencesStorageKey, JSON.stringify(preferences));
188
188
  }
189
189
 
190
190
  function initializeReaderSettings() {
@@ -235,7 +235,7 @@ const chaptersJson = JSON.stringify(chapters).replace(/</g, "\\u003c");
235
235
  );
236
236
  spoilerLimitInput.value = String(getSelectedSpoilerLimit() || currentPageChapterNumber);
237
237
  spoilerLimitInput.addEventListener("change", () => {
238
- localStorage.setItem(spoilerLimitStorageKey, spoilerLimitInput.value);
238
+ writeStorage(spoilerLimitStorageKey, spoilerLimitInput.value);
239
239
  window.location.reload();
240
240
  });
241
241
  }
@@ -294,7 +294,7 @@ const chaptersJson = JSON.stringify(chapters).replace(/</g, "\\u003c");
294
294
  };
295
295
 
296
296
  if (!progress.chapterNumber || currentPageChapterNumber >= progress.chapterNumber) {
297
- localStorage.setItem(progressStorageKey, JSON.stringify(nextProgress));
297
+ writeStorage(progressStorageKey, JSON.stringify(nextProgress));
298
298
  }
299
299
 
300
300
  const bookmarkButton = document.querySelector("[data-bookmark-toggle]");
@@ -547,7 +547,7 @@ const chaptersJson = JSON.stringify(chapters).replace(/</g, "\\u003c");
547
547
  return null;
548
548
  }
549
549
 
550
- const saved = Number(localStorage.getItem(spoilerLimitStorageKey) || "");
550
+ const saved = Number(readStorage(spoilerLimitStorageKey) || "");
551
551
  if (Number.isFinite(saved)) {
552
552
  return Math.min(saved, currentPageChapterNumber);
553
553
  }
@@ -578,9 +578,9 @@ const chaptersJson = JSON.stringify(chapters).replace(/</g, "\\u003c");
578
578
  function toggleBookmark(button, bookmark) {
579
579
  const current = readJson(bookmarkStorageKey);
580
580
  if (current?.href === bookmark.href) {
581
- localStorage.removeItem(bookmarkStorageKey);
581
+ removeStorage(bookmarkStorageKey);
582
582
  } else {
583
- localStorage.setItem(bookmarkStorageKey, JSON.stringify(bookmark));
583
+ writeStorage(bookmarkStorageKey, JSON.stringify(bookmark));
584
584
  }
585
585
  syncBookmarkButton(button, bookmark);
586
586
  }
@@ -638,8 +638,8 @@ const chaptersJson = JSON.stringify(chapters).replace(/</g, "\\u003c");
638
638
  glossaryRules: buildPronunciationRules(glossaryEntries),
639
639
  triggers,
640
640
  voices: [],
641
- voiceUri: localStorage.getItem(ttsVoiceStorageKey) || "",
642
- rate: clampNumber(Number(localStorage.getItem(ttsRateStorageKey) || "1"), 0.7, 1.35, 1),
641
+ voiceUri: readStorage(ttsVoiceStorageKey) || "",
642
+ rate: clampNumber(Number(readStorage(ttsRateStorageKey) || "1"), 0.7, 1.35, 1),
643
643
  scopeId: "chapter",
644
644
  index: 0,
645
645
  runId: 0,
@@ -851,7 +851,7 @@ const chaptersJson = JSON.stringify(chapters).replace(/</g, "\\u003c");
851
851
 
852
852
  state.voiceSelect.addEventListener("change", () => {
853
853
  state.voiceUri = state.voiceSelect.value;
854
- localStorage.setItem(ttsVoiceStorageKey, state.voiceUri);
854
+ writeStorage(ttsVoiceStorageKey, state.voiceUri);
855
855
  updateTtsUi(state);
856
856
  if (state.speech.speaking && !state.speech.paused) {
857
857
  restartCurrentTtsSegment(state);
@@ -860,7 +860,7 @@ const chaptersJson = JSON.stringify(chapters).replace(/</g, "\\u003c");
860
860
 
861
861
  state.rateInput.addEventListener("input", () => {
862
862
  state.rate = clampNumber(Number(state.rateInput.value || "1"), 0.7, 1.35, 1);
863
- localStorage.setItem(ttsRateStorageKey, String(state.rate));
863
+ writeStorage(ttsRateStorageKey, String(state.rate));
864
864
  updateTtsUi(state);
865
865
  if (state.speech.speaking && !state.speech.paused) {
866
866
  restartCurrentTtsSegment(state);
@@ -1038,7 +1038,7 @@ const chaptersJson = JSON.stringify(chapters).replace(/</g, "\\u003c");
1038
1038
  return;
1039
1039
  }
1040
1040
 
1041
- localStorage.setItem(ttsProgressStorageKey, JSON.stringify({
1041
+ writeStorage(ttsProgressStorageKey, JSON.stringify({
1042
1042
  path: window.location.pathname,
1043
1043
  scopeId: state.scopeId,
1044
1044
  scopeLabel: scope.label,
@@ -1047,7 +1047,7 @@ const chaptersJson = JSON.stringify(chapters).replace(/</g, "\\u003c");
1047
1047
  }
1048
1048
 
1049
1049
  function clearTtsProgress() {
1050
- localStorage.removeItem(ttsProgressStorageKey);
1050
+ removeStorage(ttsProgressStorageKey);
1051
1051
  }
1052
1052
 
1053
1053
  function updateTtsUi(state) {
@@ -1145,9 +1145,37 @@ const chaptersJson = JSON.stringify(chapters).replace(/</g, "\\u003c");
1145
1145
  return Math.max(min, Math.min(max, value));
1146
1146
  }
1147
1147
 
1148
+ function prefersDarkTheme() {
1149
+ return typeof window.matchMedia === "function" && window.matchMedia("(prefers-color-scheme: dark)").matches;
1150
+ }
1151
+
1152
+ function readStorage(key) {
1153
+ try {
1154
+ return localStorage.getItem(key);
1155
+ } catch {
1156
+ return null;
1157
+ }
1158
+ }
1159
+
1160
+ function writeStorage(key, value) {
1161
+ try {
1162
+ localStorage.setItem(key, value);
1163
+ } catch {
1164
+ // Ignore storage failures so reader controls still work in restricted contexts.
1165
+ }
1166
+ }
1167
+
1168
+ function removeStorage(key) {
1169
+ try {
1170
+ localStorage.removeItem(key);
1171
+ } catch {
1172
+ // Ignore storage failures so reader controls still work in restricted contexts.
1173
+ }
1174
+ }
1175
+
1148
1176
  function readJson(key) {
1149
1177
  try {
1150
- return JSON.parse(localStorage.getItem(key) || "null");
1178
+ return JSON.parse(readStorage(key) || "null");
1151
1179
  } catch {
1152
1180
  return null;
1153
1181
  }
@@ -37,6 +37,21 @@ const fullCanonMode = isFullCanonMode();
37
37
  <title>{title}</title>
38
38
  {description && <meta name="description" content={description} />}
39
39
  <base href={import.meta.env.BASE_URL} />
40
+ <script is:inline>
41
+ (() => {
42
+ const themeStorageKey = "narrarium-reader-theme";
43
+ const root = document.documentElement;
44
+ const prefersDark =
45
+ typeof window.matchMedia === "function" && window.matchMedia("(prefers-color-scheme: dark)").matches;
46
+
47
+ try {
48
+ const saved = localStorage.getItem(themeStorageKey);
49
+ root.dataset.theme = saved || (prefersDark ? "dark" : "light");
50
+ } catch {
51
+ root.dataset.theme = prefersDark ? "dark" : "light";
52
+ }
53
+ })();
54
+ </script>
40
55
  <style>
41
56
  :root {
42
57
  --paper: #f3ecdd;
@@ -319,6 +334,13 @@ const fullCanonMode = isFullCanonMode();
319
334
  font-size: 1.15rem;
320
335
  }
321
336
 
337
+ .value-path {
338
+ overflow-wrap: anywhere;
339
+ word-break: break-word;
340
+ font-family: "Cascadia Code", "SFMono-Regular", Consolas, monospace;
341
+ font-size: 0.98rem;
342
+ }
343
+
322
344
  .chapter-list {
323
345
  margin-top: 2rem;
324
346
  display: grid;
package/src/lib/book.ts CHANGED
@@ -9,6 +9,7 @@ import {
9
9
  readTimelineMain,
10
10
  } from "narrarium";
11
11
  import { defaultBookRoot } from "./book-config.js";
12
+ import { readReaderBookRootEnv } from "./env.js";
12
13
 
13
14
  type ReaderEntityKind =
14
15
  | "character"
@@ -19,7 +20,7 @@ type ReaderEntityKind =
19
20
  | "timeline-event";
20
21
 
21
22
  export function getBookRoot(): string {
22
- const configured = process.env.NARRARIUM_BOOK_ROOT ?? process.env.GHOSTWRITER_BOOK_ROOT;
23
+ const configured = readReaderBookRootEnv();
23
24
  if (configured) return path.resolve(configured);
24
25
  return path.resolve(process.cwd(), defaultBookRoot);
25
26
  }
package/src/lib/env.ts ADDED
@@ -0,0 +1,61 @@
1
+ type EnvSource = Record<string, string | undefined> | null | undefined;
2
+
3
+ const astroEnv = ((import.meta as ImportMeta & { env?: Record<string, string | undefined> }).env ?? {}) as Record<
4
+ string,
5
+ string | undefined
6
+ >;
7
+
8
+ export function normalizeReaderEnvValue(value: string | null | undefined): string | undefined {
9
+ if (typeof value !== "string") {
10
+ return undefined;
11
+ }
12
+
13
+ const trimmed = value.trim();
14
+ if (!trimmed) {
15
+ return undefined;
16
+ }
17
+
18
+ if (
19
+ (trimmed.startsWith('"') && trimmed.endsWith('"')) ||
20
+ (trimmed.startsWith("'") && trimmed.endsWith("'"))
21
+ ) {
22
+ return trimmed.slice(1, -1).trim() || undefined;
23
+ }
24
+
25
+ return trimmed;
26
+ }
27
+
28
+ export function isClearlyInvalidBookRootValue(value: string | null | undefined): boolean {
29
+ const normalized = normalizeReaderEnvValue(value);
30
+ if (!normalized) {
31
+ return true;
32
+ }
33
+
34
+ return normalized === "/" || normalized === "\\" || /^[a-zA-Z]:(?:[\\/])?$/.test(normalized);
35
+ }
36
+
37
+ export function readReaderEnv(keys: string[], sources: EnvSource[] = [process.env, astroEnv]): string | undefined {
38
+ for (const source of sources) {
39
+ if (!source) {
40
+ continue;
41
+ }
42
+
43
+ for (const key of keys) {
44
+ const value = normalizeReaderEnvValue(source[key]);
45
+ if (value) {
46
+ return value;
47
+ }
48
+ }
49
+ }
50
+
51
+ return undefined;
52
+ }
53
+
54
+ export function readReaderBookRootEnv(sources: EnvSource[] = [process.env, astroEnv]): string | undefined {
55
+ const value = readReaderEnv(["NARRARIUM_BOOK_ROOT", "GHOSTWRITER_BOOK_ROOT"], sources);
56
+ if (!value || isClearlyInvalidBookRootValue(value)) {
57
+ return undefined;
58
+ }
59
+
60
+ return value;
61
+ }
@@ -1,7 +1,7 @@
1
+ import { readReaderEnv } from "./env.js";
2
+
1
3
  export function isFullCanonMode(): boolean {
2
- const raw = String(
3
- process.env.NARRARIUM_READER_CANON_MODE ?? process.env.NARRARIUM_READER_ALLOW_FULL_CANON ?? "",
4
- )
4
+ const raw = String(readReaderEnv(["NARRARIUM_READER_CANON_MODE", "NARRARIUM_READER_ALLOW_FULL_CANON"]) ?? "")
5
5
  .trim()
6
6
  .toLowerCase();
7
7
 
@@ -40,7 +40,7 @@ const chapterCards = await Promise.all(
40
40
  <div class="grid stats">
41
41
  <div class="card">
42
42
  <div class="label">Book Root</div>
43
- <div class="value">{root}</div>
43
+ <div class="value value-path">{root}</div>
44
44
  </div>
45
45
  <div class="card">
46
46
  <div class="label">Chapters</div>
package/src/scaffold.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import { cp, copyFile, mkdir, readFile, writeFile } from "node:fs/promises";
2
2
  import path from "node:path";
3
3
  import { fileURLToPath } from "node:url";
4
+ import { isClearlyInvalidBookRootValue, normalizeReaderEnvValue } from "./lib/env.js";
4
5
 
5
6
  type ScaffoldOptions = {
6
7
  bookRoot?: string;
@@ -85,15 +86,15 @@ export async function scaffoldReaderSite(targetDir: string, options: ScaffoldOpt
85
86
 
86
87
  await writeFile(
87
88
  path.join(targetRoot, ".env.example"),
88
- [
89
- `NARRARIUM_BOOK_ROOT=${toPosix(bookRoot)}`,
90
- "# NARRARIUM_READER_CANON_MODE=full",
91
- "# EPUBCHECK_CMD=epubcheck",
92
- "# EPUBCHECK_JAR=/absolute/path/to/epubcheck.jar",
93
- "",
94
- ].join("\n"),
89
+ buildReaderEnvFile(bookRoot),
95
90
  "utf8",
96
91
  );
92
+ const envPath = path.join(targetRoot, ".env");
93
+ const existingEnv = await readFile(envPath, "utf8").catch(() => null);
94
+ const nextEnv = mergeReaderEnvFile(existingEnv, bookRoot);
95
+ if (nextEnv !== existingEnv) {
96
+ await writeFile(envPath, nextEnv, "utf8");
97
+ }
97
98
  await writeFile(path.join(targetRoot, ".gitignore"), "node_modules/\ndist/\n.astro/\n.env\npublic/downloads/\n", "utf8");
98
99
  await writeFile(
99
100
  path.join(targetRoot, "README.md"),
@@ -116,7 +117,7 @@ This site was scaffolded from \`narrarium-astro-reader\`.
116
117
 
117
118
  ## Configure
118
119
 
119
- Set the book root in a local environment file:
120
+ The scaffold creates a local \`.env\` with the book root already filled in. Adjust it if this reader should point somewhere else:
120
121
 
121
122
  \`\`\`bash
122
123
  NARRARIUM_BOOK_ROOT=${toPosix(bookRoot)}
@@ -166,6 +167,47 @@ function buildBookConfigScript(bookRoot: string): string {
166
167
  return `export const defaultBookRoot = ${JSON.stringify(toPosix(bookRoot))};\n`;
167
168
  }
168
169
 
170
+ function buildReaderEnvFile(bookRoot: string): string {
171
+ return [
172
+ `NARRARIUM_BOOK_ROOT=${toPosix(bookRoot)}`,
173
+ "# NARRARIUM_READER_CANON_MODE=full",
174
+ "# EPUBCHECK_CMD=epubcheck",
175
+ "# EPUBCHECK_JAR=/absolute/path/to/epubcheck.jar",
176
+ "",
177
+ ].join("\n");
178
+ }
179
+
180
+ function mergeReaderEnvFile(existingContent: string | null, bookRoot: string): string {
181
+ const desiredRoot = toPosix(bookRoot);
182
+ if (existingContent === null) {
183
+ return buildReaderEnvFile(bookRoot);
184
+ }
185
+
186
+ const lines = existingContent.split(/\r?\n/);
187
+ let handled = false;
188
+
189
+ const nextLines = lines.map((line) => {
190
+ const match = line.match(/^(\s*NARRARIUM_BOOK_ROOT\s*=\s*)(.*)$/);
191
+ if (!match) {
192
+ return line;
193
+ }
194
+
195
+ handled = true;
196
+ const currentValue = normalizeReaderEnvValue(match[2]);
197
+ if (currentValue && !isClearlyInvalidBookRootValue(currentValue)) {
198
+ return line;
199
+ }
200
+
201
+ return `${match[1]}${desiredRoot}`;
202
+ });
203
+
204
+ if (handled) {
205
+ return nextLines.join("\n");
206
+ }
207
+
208
+ return `${buildReaderEnvFile(bookRoot).trimEnd()}\n${existingContent}`;
209
+ }
210
+
169
211
  function buildPagesWorkflow(pagesDomain?: string): string {
170
212
  const envBlock = pagesDomain
171
213
  ? [" SITE_BASE: /", ` SITE_URL: https://${pagesDomain}`].join("\n")