narrarium-astro-reader 0.1.0

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.
Files changed (67) hide show
  1. package/README.md +52 -0
  2. package/astro.config.mjs +12 -0
  3. package/cli-dist/cli.d.ts +3 -0
  4. package/cli-dist/cli.d.ts.map +1 -0
  5. package/cli-dist/cli.js +78 -0
  6. package/cli-dist/cli.js.map +1 -0
  7. package/cli-dist/lib/assets.d.ts +8 -0
  8. package/cli-dist/lib/assets.d.ts.map +1 -0
  9. package/cli-dist/lib/assets.js +35 -0
  10. package/cli-dist/lib/assets.js.map +1 -0
  11. package/cli-dist/lib/book-config.d.ts +2 -0
  12. package/cli-dist/lib/book-config.d.ts.map +1 -0
  13. package/cli-dist/lib/book-config.js +2 -0
  14. package/cli-dist/lib/book-config.js.map +1 -0
  15. package/cli-dist/lib/book.d.ts +103 -0
  16. package/cli-dist/lib/book.d.ts.map +1 -0
  17. package/cli-dist/lib/book.js +89 -0
  18. package/cli-dist/lib/book.js.map +1 -0
  19. package/cli-dist/lib/canon.d.ts +16 -0
  20. package/cli-dist/lib/canon.d.ts.map +1 -0
  21. package/cli-dist/lib/canon.js +164 -0
  22. package/cli-dist/lib/canon.js.map +1 -0
  23. package/cli-dist/lib/glossary.d.ts +25 -0
  24. package/cli-dist/lib/glossary.d.ts.map +1 -0
  25. package/cli-dist/lib/glossary.js +195 -0
  26. package/cli-dist/lib/glossary.js.map +1 -0
  27. package/cli-dist/lib/search.d.ts +9 -0
  28. package/cli-dist/lib/search.d.ts.map +1 -0
  29. package/cli-dist/lib/search.js +55 -0
  30. package/cli-dist/lib/search.js.map +1 -0
  31. package/cli-dist/scaffold.d.ts +14 -0
  32. package/cli-dist/scaffold.d.ts.map +1 -0
  33. package/cli-dist/scaffold.js +190 -0
  34. package/cli-dist/scaffold.js.map +1 -0
  35. package/package.json +58 -0
  36. package/scripts/export-epub.mjs +13 -0
  37. package/src/cli.ts +96 -0
  38. package/src/components/AssetFigure.astro +17 -0
  39. package/src/components/ChapterPager.astro +40 -0
  40. package/src/components/LinkedValue.astro +18 -0
  41. package/src/components/MetadataSection.astro +22 -0
  42. package/src/components/ReaderRuntime.astro +310 -0
  43. package/src/components/RelatedLinks.astro +19 -0
  44. package/src/components/SiteSearch.astro +91 -0
  45. package/src/layouts/BaseLayout.astro +676 -0
  46. package/src/lib/assets.ts +44 -0
  47. package/src/lib/book-config.ts +1 -0
  48. package/src/lib/book.ts +116 -0
  49. package/src/lib/canon.ts +212 -0
  50. package/src/lib/glossary.ts +247 -0
  51. package/src/lib/search.ts +74 -0
  52. package/src/pages/chapters/[chapter].astro +102 -0
  53. package/src/pages/characters/[slug].astro +65 -0
  54. package/src/pages/characters/index.astro +45 -0
  55. package/src/pages/factions/[slug].astro +64 -0
  56. package/src/pages/factions/index.astro +45 -0
  57. package/src/pages/index.astro +129 -0
  58. package/src/pages/items/[slug].astro +63 -0
  59. package/src/pages/items/index.astro +45 -0
  60. package/src/pages/locations/[slug].astro +61 -0
  61. package/src/pages/locations/index.astro +45 -0
  62. package/src/pages/secrets/[slug].astro +67 -0
  63. package/src/pages/secrets/index.astro +46 -0
  64. package/src/pages/timeline/[slug].astro +58 -0
  65. package/src/pages/timeline/index.astro +52 -0
  66. package/src/scaffold.ts +232 -0
  67. package/tsconfig.json +6 -0
package/README.md ADDED
@@ -0,0 +1,52 @@
1
+ # narrarium-astro-reader
2
+
3
+ Astro reader and reader scaffolding CLI for Narrarium book repositories.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install narrarium-astro-reader
9
+ ```
10
+
11
+ ## Scaffold a reader app
12
+
13
+ ```bash
14
+ npx narrarium-reader-init reader --book-root ..
15
+ ```
16
+
17
+ Or directly from the published package:
18
+
19
+ ```bash
20
+ npx narrarium-astro-reader reader --book-root .. --package-name my-book-reader
21
+ ```
22
+
23
+ ## What the reader includes
24
+
25
+ - book landing page
26
+ - chapter index and chapter reading pages
27
+ - previous, next, and jump chapter navigation
28
+ - live search across canon, chapters, and scenes
29
+ - character index and detail pages
30
+ - location index and detail pages
31
+ - faction index and detail pages
32
+ - item index and detail pages
33
+ - secret index and detail pages
34
+ - timeline index and event detail pages
35
+ - automatic rendering of canonical book, entity, chapter, and scene images when matching assets exist
36
+ - automatic EPUB export for `public/downloads/book.epub`
37
+ - web-only canon mention popups and light or dark theme toggle
38
+ - popup tabs for overview, notes, metadata, and image previews
39
+ - starter GitHub Pages deployment workflow when scaffolded into a standalone app
40
+
41
+ ## Local development
42
+
43
+ ```bash
44
+ cp .env.example .env
45
+ npm install
46
+ npm run dev
47
+ ```
48
+
49
+ 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
+
52
+ You can also pass `--pages-domain example.com` when scaffolding to emit `public/CNAME` and a Pages workflow already pointed at that domain.
@@ -0,0 +1,12 @@
1
+ import { defineConfig } from "astro/config";
2
+
3
+ const repoName = process.env.GITHUB_REPOSITORY?.split("/")[1];
4
+ const base = process.env.SITE_BASE ?? (process.env.GITHUB_ACTIONS === "true" && repoName ? `/${repoName}/` : "/");
5
+ const site = process.env.SITE_URL;
6
+
7
+ export default defineConfig({
8
+ output: "static",
9
+ site,
10
+ base,
11
+ trailingSlash: "always",
12
+ });
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":""}
@@ -0,0 +1,78 @@
1
+ #!/usr/bin/env node
2
+ import { stdin as input, stdout as output } from "node:process";
3
+ import { createInterface } from "node:readline/promises";
4
+ import { scaffoldReaderSite } from "./scaffold.js";
5
+ const args = parseArgs(process.argv.slice(2));
6
+ const resolved = await resolveInputs(args);
7
+ const result = await scaffoldReaderSite(resolved.targetDir, {
8
+ bookRoot: resolved.bookRoot,
9
+ packageName: resolved.packageName,
10
+ coreDependency: resolved.coreDependency,
11
+ pagesDomain: resolved.pagesDomain,
12
+ });
13
+ output.write([
14
+ `Narrarium reader scaffolded at ${result.targetRoot}`,
15
+ `Book root default: ${result.bookRoot}`,
16
+ `Core dependency: ${result.coreDependency}`,
17
+ "",
18
+ "Next steps:",
19
+ `- cd ${result.targetRoot}`,
20
+ "- npm install",
21
+ "- copy .env.example to .env if you want a local override",
22
+ "- npm run dev",
23
+ ].join("\n"));
24
+ async function resolveInputs(args) {
25
+ if (args.targetDir) {
26
+ return {
27
+ targetDir: args.targetDir,
28
+ bookRoot: args.bookRoot ?? "..",
29
+ packageName: args.packageName,
30
+ coreDependency: args.coreDependency,
31
+ pagesDomain: args.pagesDomain,
32
+ };
33
+ }
34
+ if (!input.isTTY || !output.isTTY) {
35
+ throw new Error("Missing target directory. Use narrarium-reader-init <target-dir> [--book-root <path>] [--package-name <name>] [--pages-domain <domain>].");
36
+ }
37
+ const rl = createInterface({ input, output });
38
+ try {
39
+ const targetDir = (await rl.question("Reader folder [reader]: ")) || "reader";
40
+ const bookRoot = (await rl.question("Book root relative to reader [. . becomes ..] [..]: ")) || "..";
41
+ const packageName = (await rl.question("Package name (optional): ")) || undefined;
42
+ const coreDependency = (await rl.question("Core dependency [published latest compatible]: ")) || undefined;
43
+ const pagesDomain = (await rl.question("GitHub Pages custom domain (optional): ")) || undefined;
44
+ return { targetDir, bookRoot, packageName, coreDependency, pagesDomain };
45
+ }
46
+ finally {
47
+ rl.close();
48
+ }
49
+ }
50
+ function parseArgs(argv) {
51
+ const parsed = {};
52
+ for (let index = 0; index < argv.length; index += 1) {
53
+ const token = argv[index];
54
+ if (!token.startsWith("-")) {
55
+ if (!parsed.targetDir)
56
+ parsed.targetDir = token;
57
+ continue;
58
+ }
59
+ switch (token) {
60
+ case "--book-root":
61
+ parsed.bookRoot = argv[++index];
62
+ break;
63
+ case "--package-name":
64
+ parsed.packageName = argv[++index];
65
+ break;
66
+ case "--core-dependency":
67
+ parsed.coreDependency = argv[++index];
68
+ break;
69
+ case "--pages-domain":
70
+ parsed.pagesDomain = argv[++index];
71
+ break;
72
+ default:
73
+ break;
74
+ }
75
+ }
76
+ return parsed;
77
+ }
78
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ export type ReaderFigure = {
2
+ src: string;
3
+ alt: string;
4
+ aspectRatio: string;
5
+ orientation: "portrait" | "landscape" | "square";
6
+ };
7
+ export declare function loadAssetFigure(subject: string, alt: string, assetKind?: string): Promise<ReaderFigure | null>;
8
+ //# sourceMappingURL=assets.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assets.d.ts","sourceRoot":"","sources":["../../src/lib/assets.ts"],"names":[],"mappings":"AAKA,MAAM,MAAM,YAAY,GAAG;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,UAAU,GAAG,WAAW,GAAG,QAAQ,CAAC;CAClD,CAAC;AAEF,wBAAsB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAapH"}
@@ -0,0 +1,35 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { readAsset } from "narrarium";
4
+ import { getBookRoot } from "./book.js";
5
+ export async function loadAssetFigure(subject, alt, assetKind) {
6
+ const asset = await readAsset(getBookRoot(), subject, assetKind);
7
+ if (!asset || !asset.imageExists) {
8
+ return null;
9
+ }
10
+ const buffer = await readFile(asset.imagePath);
11
+ return {
12
+ src: `data:${mimeTypeForExtension(path.extname(asset.imagePath))};base64,${buffer.toString("base64")}`,
13
+ alt,
14
+ aspectRatio: asset.metadata.aspect_ratio,
15
+ orientation: asset.metadata.orientation,
16
+ };
17
+ }
18
+ function mimeTypeForExtension(extension) {
19
+ switch (extension.toLowerCase()) {
20
+ case ".jpg":
21
+ case ".jpeg":
22
+ return "image/jpeg";
23
+ case ".webp":
24
+ return "image/webp";
25
+ case ".gif":
26
+ return "image/gif";
27
+ case ".avif":
28
+ return "image/avif";
29
+ case ".svg":
30
+ return "image/svg+xml";
31
+ default:
32
+ return "image/png";
33
+ }
34
+ }
35
+ //# sourceMappingURL=assets.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"assets.js","sourceRoot":"","sources":["../../src/lib/assets.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AASxC,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,OAAe,EAAE,GAAW,EAAE,SAAkB;IACpF,MAAM,KAAK,GAAG,MAAM,SAAS,CAAC,WAAW,EAAE,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC;IACjE,IAAI,CAAC,KAAK,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC;QACjC,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IAC/C,OAAO;QACL,GAAG,EAAE,QAAQ,oBAAoB,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,WAAW,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE;QACtG,GAAG;QACH,WAAW,EAAE,KAAK,CAAC,QAAQ,CAAC,YAAY;QACxC,WAAW,EAAE,KAAK,CAAC,QAAQ,CAAC,WAAW;KACxC,CAAC;AACJ,CAAC;AAED,SAAS,oBAAoB,CAAC,SAAiB;IAC7C,QAAQ,SAAS,CAAC,WAAW,EAAE,EAAE,CAAC;QAChC,KAAK,MAAM,CAAC;QACZ,KAAK,OAAO;YACV,OAAO,YAAY,CAAC;QACtB,KAAK,OAAO;YACV,OAAO,YAAY,CAAC;QACtB,KAAK,MAAM;YACT,OAAO,WAAW,CAAC;QACrB,KAAK,OAAO;YACV,OAAO,YAAY,CAAC;QACtB,KAAK,MAAM;YACT,OAAO,eAAe,CAAC;QACzB;YACE,OAAO,WAAW,CAAC;IACvB,CAAC;AACH,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare const defaultBookRoot = "../../example-book";
2
+ //# sourceMappingURL=book-config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"book-config.d.ts","sourceRoot":"","sources":["../../src/lib/book-config.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,eAAe,uBAAuB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export const defaultBookRoot = "../../example-book";
2
+ //# sourceMappingURL=book-config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"book-config.js","sourceRoot":"","sources":["../../src/lib/book-config.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,eAAe,GAAG,oBAAoB,CAAC"}
@@ -0,0 +1,103 @@
1
+ type ReaderEntityKind = "character" | "location" | "faction" | "item" | "secret" | "timeline-event";
2
+ export declare function getBookRoot(): string;
3
+ export declare function loadHomePageData(): Promise<{
4
+ ready: boolean;
5
+ root: string;
6
+ book: {
7
+ frontmatter: {
8
+ [x: string]: unknown;
9
+ type: "book";
10
+ id: "book";
11
+ title: string;
12
+ language: string;
13
+ canon: "canon" | "draft" | "deprecated";
14
+ author?: string | undefined;
15
+ genre?: string | undefined;
16
+ audience?: string | undefined;
17
+ };
18
+ body: string;
19
+ path: string;
20
+ } | null;
21
+ chapters: {
22
+ slug: string;
23
+ path: string;
24
+ metadata: import("narrarium").ChapterFrontmatter;
25
+ }[];
26
+ characters: {
27
+ slug: string;
28
+ path: string;
29
+ metadata: Record<string, unknown>;
30
+ body: string;
31
+ }[];
32
+ locations: {
33
+ slug: string;
34
+ path: string;
35
+ metadata: Record<string, unknown>;
36
+ body: string;
37
+ }[];
38
+ factions: {
39
+ slug: string;
40
+ path: string;
41
+ metadata: Record<string, unknown>;
42
+ body: string;
43
+ }[];
44
+ items: {
45
+ slug: string;
46
+ path: string;
47
+ metadata: Record<string, unknown>;
48
+ body: string;
49
+ }[];
50
+ secrets: {
51
+ slug: string;
52
+ path: string;
53
+ metadata: Record<string, unknown>;
54
+ body: string;
55
+ }[];
56
+ timelineEvents: {
57
+ slug: string;
58
+ path: string;
59
+ metadata: Record<string, unknown>;
60
+ body: string;
61
+ }[];
62
+ }>;
63
+ export declare function loadChapterPageData(chapterSlug: string): Promise<{
64
+ metadata: import("narrarium").ChapterFrontmatter;
65
+ body: string;
66
+ paragraphs: Array<{
67
+ path: string;
68
+ metadata: import("narrarium").ParagraphFrontmatter;
69
+ body: string;
70
+ }>;
71
+ }>;
72
+ export declare function loadEntityIndexData(kind: ReaderEntityKind): Promise<{
73
+ ready: boolean;
74
+ root: string;
75
+ entities: {
76
+ slug: string;
77
+ path: string;
78
+ metadata: Record<string, unknown>;
79
+ body: string;
80
+ }[];
81
+ }>;
82
+ export declare function loadEntityPageData(kind: ReaderEntityKind, slug: string): Promise<{
83
+ slug: string;
84
+ path: string;
85
+ metadata: Record<string, unknown>;
86
+ body: string;
87
+ }>;
88
+ export declare function loadTimelinePageData(): Promise<{
89
+ ready: boolean;
90
+ root: string;
91
+ main: {
92
+ metadata: Record<string, unknown>;
93
+ body: string;
94
+ } | null;
95
+ events: {
96
+ slug: string;
97
+ path: string;
98
+ metadata: Record<string, unknown>;
99
+ body: string;
100
+ }[];
101
+ }>;
102
+ export {};
103
+ //# sourceMappingURL=book.d.ts.map
@@ -0,0 +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"}
@@ -0,0 +1,89 @@
1
+ import path from "node:path";
2
+ import { listChapters, listEntities, pathExists, readBook, readChapter, readEntity, readTimelineMain, } from "narrarium";
3
+ import { defaultBookRoot } from "./book-config.js";
4
+ export function getBookRoot() {
5
+ const configured = process.env.NARRARIUM_BOOK_ROOT ?? process.env.GHOSTWRITER_BOOK_ROOT;
6
+ if (configured)
7
+ return path.resolve(configured);
8
+ return path.resolve(process.cwd(), defaultBookRoot);
9
+ }
10
+ export async function loadHomePageData() {
11
+ const root = getBookRoot();
12
+ const hasBook = await pathExists(path.join(root, "book.md"));
13
+ if (!hasBook) {
14
+ return {
15
+ ready: false,
16
+ root,
17
+ book: null,
18
+ chapters: [],
19
+ characters: [],
20
+ locations: [],
21
+ factions: [],
22
+ items: [],
23
+ secrets: [],
24
+ timelineEvents: [],
25
+ };
26
+ }
27
+ const [book, chapters, characters, locations, factions, items, secrets, timelineEvents] = await Promise.all([
28
+ readBook(root),
29
+ listChapters(root),
30
+ listEntities(root, "character"),
31
+ listEntities(root, "location"),
32
+ listEntities(root, "faction"),
33
+ listEntities(root, "item"),
34
+ listEntities(root, "secret"),
35
+ listEntities(root, "timeline-event"),
36
+ ]);
37
+ return {
38
+ ready: true,
39
+ root,
40
+ book,
41
+ chapters,
42
+ characters,
43
+ locations,
44
+ factions,
45
+ items,
46
+ secrets,
47
+ timelineEvents,
48
+ };
49
+ }
50
+ export async function loadChapterPageData(chapterSlug) {
51
+ const root = getBookRoot();
52
+ return readChapter(root, chapterSlug);
53
+ }
54
+ export async function loadEntityIndexData(kind) {
55
+ const root = getBookRoot();
56
+ const ready = await pathExists(path.join(root, "book.md"));
57
+ if (!ready) {
58
+ return { ready: false, root, entities: [] };
59
+ }
60
+ return {
61
+ ready: true,
62
+ root,
63
+ entities: await listEntities(root, kind),
64
+ };
65
+ }
66
+ export async function loadEntityPageData(kind, slug) {
67
+ const root = getBookRoot();
68
+ return readEntity(root, kind, slug);
69
+ }
70
+ export async function loadTimelinePageData() {
71
+ const root = getBookRoot();
72
+ const ready = await pathExists(path.join(root, "book.md"));
73
+ if (!ready) {
74
+ return {
75
+ ready: false,
76
+ root,
77
+ main: null,
78
+ events: [],
79
+ };
80
+ }
81
+ const [main, events] = await Promise.all([readTimelineMain(root), listEntities(root, "timeline-event")]);
82
+ return {
83
+ ready: true,
84
+ root,
85
+ main,
86
+ events,
87
+ };
88
+ }
89
+ //# sourceMappingURL=book.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"book.js","sourceRoot":"","sources":["../../src/lib/book.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,UAAU,EACV,QAAQ,EACR,WAAW,EACX,UAAU,EACV,gBAAgB,GACjB,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAUnD,MAAM,UAAU,WAAW;IACzB,MAAM,UAAU,GAAG,OAAO,CAAC,GAAG,CAAC,mBAAmB,IAAI,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC;IACxF,IAAI,UAAU;QAAE,OAAO,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IAChD,OAAO,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,eAAe,CAAC,CAAC;AACtD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,gBAAgB;IACpC,MAAM,IAAI,GAAG,WAAW,EAAE,CAAC;IAC3B,MAAM,OAAO,GAAG,MAAM,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC;IAE7D,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO;YACL,KAAK,EAAE,KAAK;YACZ,IAAI;YACJ,IAAI,EAAE,IAAI;YACV,QAAQ,EAAE,EAAE;YACZ,UAAU,EAAE,EAAE;YACd,SAAS,EAAE,EAAE;YACb,QAAQ,EAAE,EAAE;YACZ,KAAK,EAAE,EAAE;YACT,OAAO,EAAE,EAAE;YACX,cAAc,EAAE,EAAE;SACnB,CAAC;IACJ,CAAC;IAED,MAAM,CAAC,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,SAAS,EAAE,QAAQ,EAAE,KAAK,EAAE,OAAO,EAAE,cAAc,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;QAC1G,QAAQ,CAAC,IAAI,CAAC;QACd,YAAY,CAAC,IAAI,CAAC;QAClB,YAAY,CAAC,IAAI,EAAE,WAAW,CAAC;QAC/B,YAAY,CAAC,IAAI,EAAE,UAAU,CAAC;QAC9B,YAAY,CAAC,IAAI,EAAE,SAAS,CAAC;QAC7B,YAAY,CAAC,IAAI,EAAE,MAAM,CAAC;QAC1B,YAAY,CAAC,IAAI,EAAE,QAAQ,CAAC;QAC5B,YAAY,CAAC,IAAI,EAAE,gBAAgB,CAAC;KACrC,CAAC,CAAC;IAEH,OAAO;QACL,KAAK,EAAE,IAAI;QACX,IAAI;QACJ,IAAI;QACJ,QAAQ;QACR,UAAU;QACV,SAAS;QACT,QAAQ;QACR,KAAK;QACL,OAAO;QACP,cAAc;KACf,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,WAAmB;IAC3D,MAAM,IAAI,GAAG,WAAW,EAAE,CAAC;IAC3B,OAAO,WAAW,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;AACxC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,IAAsB;IAC9D,MAAM,IAAI,GAAG,WAAW,EAAE,CAAC;IAC3B,MAAM,KAAK,GAAG,MAAM,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC;IAE3D,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;IAC9C,CAAC;IAED,OAAO;QACL,KAAK,EAAE,IAAI;QACX,IAAI;QACJ,QAAQ,EAAE,MAAM,YAAY,CAAC,IAAI,EAAE,IAAI,CAAC;KACzC,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,IAAsB,EAAE,IAAY;IAC3E,MAAM,IAAI,GAAG,WAAW,EAAE,CAAC;IAC3B,OAAO,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;AACtC,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,oBAAoB;IACxC,MAAM,IAAI,GAAG,WAAW,EAAE,CAAC;IAC3B,MAAM,KAAK,GAAG,MAAM,UAAU,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC;IAE3D,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO;YACL,KAAK,EAAE,KAAK;YACZ,IAAI;YACJ,IAAI,EAAE,IAAI;YACV,MAAM,EAAE,EAAE;SACX,CAAC;IACJ,CAAC;IAED,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,CAAC,gBAAgB,CAAC,IAAI,CAAC,EAAE,YAAY,CAAC,IAAI,EAAE,gBAAgB,CAAC,CAAC,CAAC,CAAC;IACzG,OAAO;QACL,KAAK,EAAE,IAAI;QACX,IAAI;QACJ,IAAI;QACJ,MAAM;KACP,CAAC;AACJ,CAAC"}
@@ -0,0 +1,16 @@
1
+ export type CanonLink = {
2
+ href: string;
3
+ label: string;
4
+ kind: string;
5
+ };
6
+ export type ValuePart = {
7
+ text: string;
8
+ href?: undefined;
9
+ } | {
10
+ text: string;
11
+ href: string;
12
+ };
13
+ export declare function resolveValueParts(value: unknown): Promise<ValuePart[]>;
14
+ export declare function loadRelatedCanonLinks(id: string, values: unknown): Promise<CanonLink[]>;
15
+ export declare function resolveReference(value: string): Promise<CanonLink | null>;
16
+ //# sourceMappingURL=canon.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"canon.d.ts","sourceRoot":"","sources":["../../src/lib/canon.ts"],"names":[],"mappings":"AAYA,MAAM,MAAM,SAAS,GAAG;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd,CAAC;AAEF,MAAM,MAAM,SAAS,GACjB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,CAAC,EAAE,SAAS,CAAA;CAAE,GAClC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAQnC,wBAAsB,iBAAiB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CAoB5E;AAED,wBAAsB,qBAAqB,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,OAAO,CAAC,SAAS,EAAE,CAAC,CAwB7F;AAED,wBAAsB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,IAAI,CAAC,CAS/E"}
@@ -0,0 +1,164 @@
1
+ import path from "node:path";
2
+ import { listChapters, listEntities, listRelatedCanon, readChapter, toPosixPath } from "narrarium";
3
+ import { getBookRoot } from "./book.js";
4
+ const entityKinds = ["character", "location", "faction", "item", "secret", "timeline-event"];
5
+ let referenceIndexPromise = null;
6
+ export async function resolveValueParts(value) {
7
+ const strings = Array.isArray(value) ? value : [value];
8
+ const parts = [];
9
+ for (const entry of strings) {
10
+ if (entry === undefined || entry === null || entry === "")
11
+ continue;
12
+ if (parts.length > 0)
13
+ parts.push({ text: ", " });
14
+ if (typeof entry === "string") {
15
+ const link = await resolveReference(entry);
16
+ if (link) {
17
+ parts.push({ text: link.label, href: link.href });
18
+ continue;
19
+ }
20
+ }
21
+ parts.push({ text: String(entry) });
22
+ }
23
+ return parts;
24
+ }
25
+ export async function loadRelatedCanonLinks(id, values) {
26
+ const explicitRefs = collectReferenceStrings(values);
27
+ const [resolvedRefs, relatedHits] = await Promise.all([
28
+ Promise.all(explicitRefs.map((value) => resolveReference(value))),
29
+ id ? listRelatedCanon(getBookRoot(), id, { limit: 8 }) : Promise.resolve([]),
30
+ ]);
31
+ const links = [];
32
+ const seen = new Set();
33
+ for (const link of resolvedRefs) {
34
+ if (!link || seen.has(link.href))
35
+ continue;
36
+ seen.add(link.href);
37
+ links.push(link);
38
+ }
39
+ for (const hit of relatedHits) {
40
+ const href = resolveContentPathToHref(hit.path);
41
+ if (!href || seen.has(href))
42
+ continue;
43
+ seen.add(href);
44
+ links.push({ href, label: hit.title, kind: hit.type });
45
+ }
46
+ return links;
47
+ }
48
+ export async function resolveReference(value) {
49
+ const normalized = value.trim();
50
+ if (!normalized)
51
+ return null;
52
+ const index = await loadReferenceIndex();
53
+ const exact = index.get(normalized.toLowerCase());
54
+ if (exact)
55
+ return exact;
56
+ return buildFallbackReference(normalized);
57
+ }
58
+ function collectReferenceStrings(value) {
59
+ if (Array.isArray(value)) {
60
+ return value.flatMap((entry) => collectReferenceStrings(entry));
61
+ }
62
+ if (typeof value !== "string")
63
+ return [];
64
+ return isSupportedReference(value) ? [value] : [];
65
+ }
66
+ async function loadReferenceIndex() {
67
+ referenceIndexPromise ??= buildReferenceIndex();
68
+ return referenceIndexPromise;
69
+ }
70
+ async function buildReferenceIndex() {
71
+ const index = new Map();
72
+ const root = getBookRoot();
73
+ const entitiesByKind = await Promise.all(entityKinds.map((kind) => listEntities(root, kind)));
74
+ entitiesByKind.forEach((entities, offset) => {
75
+ const kind = entityKinds[offset];
76
+ for (const entity of entities) {
77
+ const label = String(entity.metadata.name ?? entity.metadata.title ?? entity.slug);
78
+ const href = entityHref(kind, entity.slug);
79
+ const id = String(entity.metadata.id ?? `${kind}:${entity.slug}`);
80
+ setReference(index, id, { href, label, kind });
81
+ setReference(index, `${kind}:${entity.slug}`, { href, label, kind });
82
+ }
83
+ });
84
+ const chapters = await listChapters(root);
85
+ for (const chapter of chapters) {
86
+ const chapterId = String(chapter.metadata.id ?? `chapter:${chapter.slug}`);
87
+ const chapterLink = { href: `chapters/${chapter.slug}/`, label: chapter.metadata.title, kind: "chapter" };
88
+ setReference(index, chapterId, chapterLink);
89
+ setReference(index, `chapter:${chapter.slug}`, chapterLink);
90
+ const chapterData = await readChapter(root, chapter.slug);
91
+ for (const paragraph of chapterData.paragraphs) {
92
+ const paragraphSlug = path.basename(paragraph.path, ".md");
93
+ const href = `chapters/${chapter.slug}/#scene-${paragraphSlug}`;
94
+ const label = paragraph.metadata.title;
95
+ setReference(index, String(paragraph.metadata.id), { href, label, kind: "paragraph" });
96
+ setReference(index, `paragraph:${chapter.slug}:${paragraphSlug}`, { href, label, kind: "paragraph" });
97
+ }
98
+ }
99
+ return index;
100
+ }
101
+ function setReference(index, key, link) {
102
+ index.set(key.toLowerCase(), link);
103
+ }
104
+ function entityHref(kind, slug) {
105
+ switch (kind) {
106
+ case "timeline-event":
107
+ return `timeline/${slug}/`;
108
+ default:
109
+ return `${kind}s/${slug}/`;
110
+ }
111
+ }
112
+ function resolveContentPathToHref(filePath) {
113
+ const normalized = toPosixPath(filePath);
114
+ const entityMatch = normalized.match(/^(characters|locations|factions|items|secrets|timelines\/events)\/([^/]+)\.md$/);
115
+ if (entityMatch) {
116
+ const section = entityMatch[1] === "timelines/events" ? "timeline" : entityMatch[1];
117
+ return `${section}/${entityMatch[2]}/`;
118
+ }
119
+ const chapterMatch = normalized.match(/^chapters\/([^/]+)\/chapter\.md$/);
120
+ if (chapterMatch) {
121
+ return `chapters/${chapterMatch[1]}/`;
122
+ }
123
+ const paragraphMatch = normalized.match(/^chapters\/([^/]+)\/([^/]+)\.md$/);
124
+ if (paragraphMatch) {
125
+ return `chapters/${paragraphMatch[1]}/#scene-${paragraphMatch[2]}`;
126
+ }
127
+ return null;
128
+ }
129
+ function buildFallbackReference(value) {
130
+ if (value.startsWith("chapter:")) {
131
+ const slug = value.slice("chapter:".length);
132
+ return { href: `chapters/${slug}/`, label: humanizeSlug(slug), kind: "chapter" };
133
+ }
134
+ if (value.startsWith("paragraph:")) {
135
+ const [, chapterSlug, paragraphSlug] = value.split(":");
136
+ if (!chapterSlug || !paragraphSlug)
137
+ return null;
138
+ return {
139
+ href: `chapters/${chapterSlug}/#scene-${paragraphSlug}`,
140
+ label: humanizeSlug(paragraphSlug),
141
+ kind: "paragraph",
142
+ };
143
+ }
144
+ for (const kind of entityKinds) {
145
+ const prefix = `${kind}:`;
146
+ if (!value.startsWith(prefix))
147
+ continue;
148
+ const slug = value.slice(prefix.length);
149
+ return { href: entityHref(kind, slug), label: humanizeSlug(slug), kind };
150
+ }
151
+ return null;
152
+ }
153
+ function isSupportedReference(value) {
154
+ return value.startsWith("chapter:") || value.startsWith("paragraph:") || entityKinds.some((kind) => value.startsWith(`${kind}:`));
155
+ }
156
+ function humanizeSlug(value) {
157
+ return value
158
+ .replace(/^[0-9]+-/, "")
159
+ .split("-")
160
+ .filter(Boolean)
161
+ .map((part) => part.charAt(0).toUpperCase() + part.slice(1))
162
+ .join(" ");
163
+ }
164
+ //# sourceMappingURL=canon.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"canon.js","sourceRoot":"","sources":["../../src/lib/canon.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ type ReaderEntityKind = "character" | "location" | "faction" | "item" | "secret" | "timeline-event";
2
+ export type GlossaryEntry = {
3
+ id: string;
4
+ kind: ReaderEntityKind;
5
+ kindLabel: string;
6
+ label: string;
7
+ href: string;
8
+ terms: string[];
9
+ summary: string;
10
+ meta: string[];
11
+ metadataEntries: Array<{
12
+ label: string;
13
+ value: string;
14
+ }>;
15
+ mentions: Array<{
16
+ label: string;
17
+ href: string;
18
+ }>;
19
+ bodyHtml?: string;
20
+ imageSrc?: string;
21
+ imageAlt?: string;
22
+ };
23
+ export declare function loadCanonGlossary(): Promise<GlossaryEntry[]>;
24
+ export {};
25
+ //# sourceMappingURL=glossary.d.ts.map