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
@@ -0,0 +1 @@
1
+ {"version":3,"file":"glossary.d.ts","sourceRoot":"","sources":["../../src/lib/glossary.ts"],"names":[],"mappings":"AAKA,KAAK,gBAAgB,GACjB,WAAW,GACX,UAAU,GACV,SAAS,GACT,MAAM,GACN,QAAQ,GACR,gBAAgB,CAAC;AAErB,MAAM,MAAM,aAAa,GAAG;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,gBAAgB,CAAC;IACvB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,eAAe,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACzD,QAAQ,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACjD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB,CAAC;AAMF,wBAAsB,iBAAiB,IAAI,OAAO,CAAC,aAAa,EAAE,CAAC,CAGlE"}
@@ -0,0 +1,195 @@
1
+ import { listEntities, listRelatedCanon, readEntity, toPosixPath } from "narrarium";
2
+ import { marked } from "marked";
3
+ import { loadAssetFigure } from "./assets.js";
4
+ import { getBookRoot } from "./book.js";
5
+ const entityKinds = ["character", "location", "faction", "item", "secret", "timeline-event"];
6
+ let glossaryPromise = null;
7
+ export async function loadCanonGlossary() {
8
+ glossaryPromise ??= buildCanonGlossary();
9
+ return glossaryPromise;
10
+ }
11
+ async function buildCanonGlossary() {
12
+ const root = getBookRoot();
13
+ const groups = await Promise.all(entityKinds.map((kind) => listEntities(root, kind)));
14
+ const entries = await Promise.all(groups.flatMap((entities, offset) => entities.map(async (entity) => {
15
+ const kind = entityKinds[offset];
16
+ const id = String(entity.metadata.id ?? `${kind}:${entity.slug}`);
17
+ const label = String(entity.metadata.name ?? entity.metadata.title ?? entity.slug);
18
+ const fullEntry = await readEntity(root, kind, entity.slug);
19
+ const related = await listRelatedCanon(root, id, { limit: 8 });
20
+ const figure = await loadAssetFigure(id, label);
21
+ return {
22
+ id,
23
+ kind,
24
+ kindLabel: kindLabel(kind),
25
+ label,
26
+ href: entityHref(kind, entity.slug),
27
+ terms: uniqueStrings([label, ...readAliases(entity.metadata.aliases)]),
28
+ summary: summaryFor(kind, entity.metadata),
29
+ meta: metaFor(kind, entity.metadata),
30
+ metadataEntries: metadataEntriesFor(kind, entity.metadata),
31
+ mentions: mentionLinksFor(related),
32
+ bodyHtml: fullEntry.body ? await marked.parse(fullEntry.body) : undefined,
33
+ imageSrc: figure?.src,
34
+ imageAlt: figure?.alt,
35
+ };
36
+ })));
37
+ return entries.sort((left, right) => left.label.localeCompare(right.label));
38
+ }
39
+ function mentionLinksFor(hits) {
40
+ const seen = new Set();
41
+ const links = [];
42
+ for (const hit of hits) {
43
+ const href = readerHrefFromPath(hit.path);
44
+ if (!href || seen.has(href))
45
+ continue;
46
+ seen.add(href);
47
+ links.push({ label: hit.title, href });
48
+ }
49
+ return links;
50
+ }
51
+ function readerHrefFromPath(filePath) {
52
+ const normalized = toPosixPath(filePath);
53
+ const chapterMatch = normalized.match(/^chapters\/([^/]+)\/chapter\.md$/);
54
+ if (chapterMatch) {
55
+ return `chapters/${chapterMatch[1]}/`;
56
+ }
57
+ const paragraphMatch = normalized.match(/^chapters\/([^/]+)\/([^/]+)\.md$/);
58
+ if (paragraphMatch && paragraphMatch[2] !== "chapter") {
59
+ return `chapters/${paragraphMatch[1]}/#scene-${paragraphMatch[2]}`;
60
+ }
61
+ return null;
62
+ }
63
+ function entityHref(kind, slug) {
64
+ switch (kind) {
65
+ case "timeline-event":
66
+ return `timeline/${slug}/`;
67
+ default:
68
+ return `${kind}s/${slug}/`;
69
+ }
70
+ }
71
+ function kindLabel(kind) {
72
+ switch (kind) {
73
+ case "timeline-event":
74
+ return "Timeline Event";
75
+ default:
76
+ return kind.charAt(0).toUpperCase() + kind.slice(1);
77
+ }
78
+ }
79
+ function summaryFor(kind, metadata) {
80
+ switch (kind) {
81
+ case "character":
82
+ return String(metadata.function_in_book ?? metadata.story_role ?? metadata.background_summary ?? "Canonical character entry.");
83
+ case "location":
84
+ return String(metadata.atmosphere ?? metadata.function_in_book ?? "Canonical location entry.");
85
+ case "faction":
86
+ return String(metadata.function_in_book ?? metadata.mission ?? metadata.ideology ?? "Canonical faction entry.");
87
+ case "item":
88
+ return String(metadata.function_in_book ?? metadata.purpose ?? metadata.significance ?? "Canonical item entry.");
89
+ case "secret":
90
+ return String(metadata.function_in_book ?? metadata.stakes ?? metadata.reveal_strategy ?? "Canonical secret entry.");
91
+ case "timeline-event":
92
+ return String(metadata.significance ?? metadata.function_in_book ?? "Canonical timeline event.");
93
+ }
94
+ }
95
+ function metaFor(kind, metadata) {
96
+ switch (kind) {
97
+ case "character":
98
+ return compactStrings([metadata.role_tier, metadata.story_role, metadata.home_location]);
99
+ case "location":
100
+ return compactStrings([metadata.location_kind, metadata.region, metadata.timeline_ref]);
101
+ case "faction":
102
+ return compactStrings([metadata.faction_kind, metadata.base_location, metadata.public_image]);
103
+ case "item":
104
+ return compactStrings([metadata.item_kind, metadata.owner, metadata.introduced_in]);
105
+ case "secret":
106
+ return compactStrings([metadata.secret_kind, metadata.reveal_in, metadata.known_from]);
107
+ case "timeline-event":
108
+ return compactStrings([metadata.date, metadata.function_in_book]);
109
+ }
110
+ }
111
+ function metadataEntriesFor(kind, metadata) {
112
+ switch (kind) {
113
+ case "character":
114
+ return compactEntries([
115
+ ["Role tier", metadata.role_tier],
116
+ ["Story role", metadata.story_role],
117
+ ["Occupation", metadata.occupation],
118
+ ["Origin", metadata.origin],
119
+ ["Home", metadata.home_location],
120
+ ["Introduced in", metadata.introduced_in],
121
+ ]);
122
+ case "location":
123
+ return compactEntries([
124
+ ["Kind", metadata.location_kind],
125
+ ["Region", metadata.region],
126
+ ["Timeline", metadata.timeline_ref],
127
+ ["Real world basis", metadata.based_on_real_place],
128
+ ]);
129
+ case "faction":
130
+ return compactEntries([
131
+ ["Kind", metadata.faction_kind],
132
+ ["Base", metadata.base_location],
133
+ ["Public image", metadata.public_image],
134
+ ["Historical", metadata.historical],
135
+ ]);
136
+ case "item":
137
+ return compactEntries([
138
+ ["Kind", metadata.item_kind],
139
+ ["Owner", metadata.owner],
140
+ ["Introduced in", metadata.introduced_in],
141
+ ["Significance", metadata.significance],
142
+ ]);
143
+ case "secret":
144
+ return compactEntries([
145
+ ["Kind", metadata.secret_kind],
146
+ ["Reveal in", metadata.reveal_in],
147
+ ["Known from", metadata.known_from],
148
+ ["Holders", metadata.holders],
149
+ ]);
150
+ case "timeline-event":
151
+ return compactEntries([
152
+ ["Date", metadata.date],
153
+ ["Participants", metadata.participants],
154
+ ["Function", metadata.function_in_book],
155
+ ["Consequences", metadata.consequences],
156
+ ]);
157
+ }
158
+ }
159
+ function compactStrings(values) {
160
+ return values
161
+ .map((value) => (typeof value === "string" ? value.trim() : ""))
162
+ .filter(Boolean);
163
+ }
164
+ function compactEntries(entries) {
165
+ return entries.flatMap(([label, value]) => {
166
+ const normalized = normalizeEntryValue(value);
167
+ return normalized ? [{ label, value: normalized }] : [];
168
+ });
169
+ }
170
+ function normalizeEntryValue(value) {
171
+ if (Array.isArray(value)) {
172
+ const normalized = value
173
+ .map((entry) => normalizeEntryValue(entry))
174
+ .filter(Boolean)
175
+ .join(", ");
176
+ return normalized;
177
+ }
178
+ if (typeof value === "boolean") {
179
+ return value ? "Yes" : "No";
180
+ }
181
+ if (value === undefined || value === null) {
182
+ return "";
183
+ }
184
+ return String(value).trim();
185
+ }
186
+ function readAliases(value) {
187
+ if (!Array.isArray(value)) {
188
+ return [];
189
+ }
190
+ return value.filter((entry) => typeof entry === "string" && entry.trim().length > 0);
191
+ }
192
+ function uniqueStrings(values) {
193
+ return [...new Set(values.map((value) => value.trim()).filter(Boolean))];
194
+ }
195
+ //# sourceMappingURL=glossary.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"glossary.js","sourceRoot":"","sources":["../../src/lib/glossary.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ export type SearchEntry = {
2
+ title: string;
3
+ href: string;
4
+ kind: string;
5
+ summary: string;
6
+ keywords: string[];
7
+ };
8
+ export declare function loadSearchIndex(): Promise<SearchEntry[]>;
9
+ //# sourceMappingURL=search.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../src/lib/search.ts"],"names":[],"mappings":"AAKA,MAAM,MAAM,WAAW,GAAG;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,MAAM,EAAE,CAAC;CACpB,CAAC;AAIF,wBAAsB,eAAe,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC,CAG9D"}
@@ -0,0 +1,55 @@
1
+ import path from "node:path";
2
+ import { listChapters, readChapter } from "narrarium";
3
+ import { getBookRoot } from "./book.js";
4
+ import { loadCanonGlossary } from "./glossary.js";
5
+ let searchIndexPromise = null;
6
+ export async function loadSearchIndex() {
7
+ searchIndexPromise ??= buildSearchIndex();
8
+ return searchIndexPromise;
9
+ }
10
+ async function buildSearchIndex() {
11
+ const root = getBookRoot();
12
+ const glossary = await loadCanonGlossary();
13
+ const chapters = await listChapters(root);
14
+ const chapterEntries = await Promise.all(chapters.flatMap(async (chapter) => {
15
+ const chapterData = await readChapter(root, chapter.slug);
16
+ const chapterEntry = {
17
+ title: chapter.metadata.title,
18
+ href: `chapters/${chapter.slug}/`,
19
+ kind: "Chapter",
20
+ summary: String(chapter.metadata.summary ?? "Read this chapter."),
21
+ keywords: compactStrings([chapter.metadata.summary, ...(chapter.metadata.tags ?? []), ...(chapter.metadata.pov ?? [])]),
22
+ };
23
+ const sceneEntries = chapterData.paragraphs.map((paragraph) => ({
24
+ title: paragraph.metadata.title,
25
+ href: `chapters/${chapter.slug}/#scene-${path.basename(paragraph.path, ".md")}`,
26
+ kind: "Scene",
27
+ summary: String(paragraph.metadata.summary ?? `Scene in ${chapter.metadata.title}.`),
28
+ keywords: compactStrings([chapter.metadata.title, paragraph.metadata.viewpoint, paragraph.metadata.summary]),
29
+ }));
30
+ return [chapterEntry, ...sceneEntries];
31
+ }));
32
+ return [
33
+ ...glossary.map((entry) => ({
34
+ title: entry.label,
35
+ href: entry.href,
36
+ kind: entry.kindLabel,
37
+ summary: entry.summary,
38
+ keywords: [...entry.terms, ...entry.meta, ...entry.metadataEntries.map((item) => item.value)],
39
+ })),
40
+ ...chapterEntries.flat(),
41
+ ];
42
+ }
43
+ function compactStrings(values) {
44
+ return values.flatMap((value) => {
45
+ if (Array.isArray(value)) {
46
+ return compactStrings(value);
47
+ }
48
+ if (value === undefined || value === null) {
49
+ return [];
50
+ }
51
+ const normalized = String(value).trim();
52
+ return normalized ? [normalized] : [];
53
+ });
54
+ }
55
+ //# sourceMappingURL=search.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"search.js","sourceRoot":"","sources":["../../src/lib/search.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,14 @@
1
+ type ScaffoldOptions = {
2
+ bookRoot?: string;
3
+ packageName?: string;
4
+ coreDependency?: string;
5
+ pagesDomain?: string;
6
+ };
7
+ export declare function scaffoldReaderSite(targetDir: string, options?: ScaffoldOptions): Promise<{
8
+ targetRoot: string;
9
+ packageName: string;
10
+ coreDependency: string;
11
+ bookRoot: string;
12
+ }>;
13
+ export {};
14
+ //# sourceMappingURL=scaffold.d.ts.map
@@ -0,0 +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"}
@@ -0,0 +1,190 @@
1
+ import { cp, copyFile, mkdir, readFile, writeFile } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+ export async function scaffoldReaderSite(targetDir, options = {}) {
5
+ const targetRoot = path.resolve(targetDir);
6
+ const packageRoot = path.dirname(fileURLToPath(new URL("../package.json", import.meta.url)));
7
+ const bookRoot = options.bookRoot ?? "..";
8
+ const packageName = options.packageName ?? inferPackageName(targetRoot);
9
+ const coreDependency = options.coreDependency ?? `^${await readCurrentPackageVersion(packageRoot)}`;
10
+ const pagesDomain = options.pagesDomain?.trim() || undefined;
11
+ await mkdir(path.join(targetRoot, "src", "layouts"), { recursive: true });
12
+ await mkdir(path.join(targetRoot, "src", "lib"), { recursive: true });
13
+ await mkdir(path.join(targetRoot, "src", "pages"), { recursive: true });
14
+ await mkdir(path.join(targetRoot, "src", "components"), { recursive: true });
15
+ await mkdir(path.join(targetRoot, "scripts"), { recursive: true });
16
+ await mkdir(path.join(targetRoot, ".github", "workflows"), { recursive: true });
17
+ await mkdir(path.join(targetRoot, "public", "downloads"), { recursive: true });
18
+ await Promise.all([
19
+ copyFile(path.join(packageRoot, "astro.config.mjs"), path.join(targetRoot, "astro.config.mjs")),
20
+ copyFile(path.join(packageRoot, "tsconfig.json"), path.join(targetRoot, "tsconfig.json")),
21
+ cp(path.join(packageRoot, "src", "components"), path.join(targetRoot, "src", "components"), { recursive: true }),
22
+ cp(path.join(packageRoot, "src", "lib"), path.join(targetRoot, "src", "lib"), { recursive: true }),
23
+ cp(path.join(packageRoot, "src", "layouts"), path.join(targetRoot, "src", "layouts"), { recursive: true }),
24
+ cp(path.join(packageRoot, "src", "pages"), path.join(targetRoot, "src", "pages"), { recursive: true }),
25
+ ]);
26
+ await writeFile(path.join(targetRoot, "package.json"), JSON.stringify({
27
+ name: packageName,
28
+ private: true,
29
+ type: "module",
30
+ scripts: {
31
+ "export:epub": "node ./scripts/export-epub.mjs",
32
+ dev: "npm run export:epub && astro dev",
33
+ build: "npm run export:epub && astro build",
34
+ preview: "astro preview",
35
+ },
36
+ dependencies: {
37
+ "narrarium": coreDependency,
38
+ astro: "^5.14.1",
39
+ marked: "^16.3.0",
40
+ },
41
+ devDependencies: {
42
+ "@types/node": "^24.6.0",
43
+ typescript: "^5.9.3",
44
+ },
45
+ }, null, 2) + "\n", "utf8");
46
+ 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");
48
+ await writeFile(path.join(targetRoot, ".github", "workflows", "deploy-pages.yml"), buildPagesWorkflow(pagesDomain), "utf8");
49
+ if (pagesDomain) {
50
+ await writeFile(path.join(targetRoot, "public", "CNAME"), `${pagesDomain}\n`, "utf8");
51
+ }
52
+ await writeFile(path.join(targetRoot, ".env.example"), `NARRARIUM_BOOK_ROOT=${toPosix(bookRoot)}\n`, "utf8");
53
+ await writeFile(path.join(targetRoot, ".gitignore"), "node_modules/\ndist/\n.astro/\n.env\npublic/downloads/\n", "utf8");
54
+ await writeFile(path.join(targetRoot, "README.md"), buildReaderReadme(bookRoot), "utf8");
55
+ return {
56
+ targetRoot,
57
+ packageName,
58
+ coreDependency,
59
+ bookRoot,
60
+ };
61
+ }
62
+ function buildReaderReadme(bookRoot) {
63
+ return `# Narrarium Reader Site
64
+
65
+ This site was scaffolded from \`narrarium-astro-reader\`.
66
+
67
+ ## Configure
68
+
69
+ Set the book root in a local environment file:
70
+
71
+ \`\`\`bash
72
+ NARRARIUM_BOOK_ROOT=${toPosix(bookRoot)}
73
+ \`\`\`
74
+
75
+ ## Run
76
+
77
+ \`\`\`bash
78
+ npm install
79
+ npm run dev
80
+ \`\`\`
81
+
82
+ The dev server exports a fresh EPUB to \`public/downloads/book.epub\` before Astro starts.
83
+
84
+ ## Build
85
+
86
+ \`\`\`bash
87
+ npm run build
88
+ \`\`\`
89
+
90
+ The build also refreshes the EPUB automatically and ships a ready-to-deploy static site.
91
+
92
+ ## GitHub Pages
93
+
94
+ A starter workflow already exists in \`.github/workflows/deploy-pages.yml\`.
95
+ By default it deploys to standard GitHub Pages using the repository name as the base path.
96
+ `;
97
+ }
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
+ `;
111
+ }
112
+ function buildPagesWorkflow(pagesDomain) {
113
+ const envBlock = pagesDomain
114
+ ? [" SITE_BASE: /", ` SITE_URL: https://${pagesDomain}`].join("\n")
115
+ : " SITE_BASE: /${{ github.event.repository.name }}/";
116
+ return `name: Deploy Reader To GitHub Pages
117
+
118
+ on:
119
+ workflow_dispatch:
120
+ push:
121
+ branches:
122
+ - main
123
+ - master
124
+
125
+ permissions:
126
+ contents: read
127
+ pages: write
128
+ id-token: write
129
+
130
+ concurrency:
131
+ group: github-pages
132
+ cancel-in-progress: true
133
+
134
+ jobs:
135
+ build:
136
+ runs-on: ubuntu-latest
137
+ steps:
138
+ - name: Checkout
139
+ uses: actions/checkout@v4
140
+
141
+ - name: Setup Node
142
+ uses: actions/setup-node@v4
143
+ with:
144
+ node-version: 22
145
+ cache: npm
146
+
147
+ - name: Install dependencies
148
+ run: npm ci
149
+
150
+ - name: Configure Pages
151
+ uses: actions/configure-pages@v5
152
+
153
+ - name: Build site
154
+ env:
155
+ ${envBlock}
156
+ run: npm run build
157
+
158
+ - name: Upload artifact
159
+ uses: actions/upload-pages-artifact@v3
160
+ with:
161
+ path: dist
162
+
163
+ deploy:
164
+ needs: build
165
+ runs-on: ubuntu-latest
166
+ environment:
167
+ name: github-pages
168
+ url: \${{ steps.deployment.outputs.page_url }}
169
+ steps:
170
+ - name: Deploy
171
+ id: deployment
172
+ uses: actions/deploy-pages@v4
173
+ `;
174
+ }
175
+ function toPosix(value) {
176
+ return value.split(path.sep).join("/");
177
+ }
178
+ function inferPackageName(targetRoot) {
179
+ const base = path.basename(targetRoot)
180
+ .toLowerCase()
181
+ .replace(/[^a-z0-9]+/g, "-")
182
+ .replace(/^-+|-+$/g, "") || "narrarium-reader-site";
183
+ return base;
184
+ }
185
+ async function readCurrentPackageVersion(packageRoot) {
186
+ const raw = await readFile(path.join(packageRoot, "package.json"), "utf8");
187
+ const parsed = JSON.parse(raw);
188
+ return parsed.version ?? "0.1.0";
189
+ }
190
+ //# sourceMappingURL=scaffold.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scaffold.js","sourceRoot":"","sources":["../src/scaffold.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,58 @@
1
+ {
2
+ "name": "narrarium-astro-reader",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "description": "Astro reader and scaffolding CLI for Narrarium book repositories.",
6
+ "license": "MIT",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/KeyserDSoze/GhostWriterFramework",
10
+ "directory": "packages/astro-reader"
11
+ },
12
+ "bin": {
13
+ "narrarium-reader-init": "cli-dist/cli.js"
14
+ },
15
+ "exports": {
16
+ "./scaffold": {
17
+ "types": "./cli-dist/scaffold.d.ts",
18
+ "import": "./cli-dist/scaffold.js"
19
+ }
20
+ },
21
+ "files": [
22
+ "cli-dist",
23
+ "scripts",
24
+ "src",
25
+ "astro.config.mjs",
26
+ "tsconfig.json"
27
+ ],
28
+ "keywords": [
29
+ "narrarium",
30
+ "astro",
31
+ "books",
32
+ "reader",
33
+ "markdown"
34
+ ],
35
+ "engines": {
36
+ "node": ">=20"
37
+ },
38
+ "publishConfig": {
39
+ "access": "public"
40
+ },
41
+ "scripts": {
42
+ "build:cli": "tsc -p tsconfig.cli.json",
43
+ "export:epub": "node ./scripts/export-epub.mjs",
44
+ "dev": "npm run export:epub && astro dev",
45
+ "build": "npm run build:cli && npm run export:epub && astro build",
46
+ "preview": "astro preview",
47
+ "test": "npm run build:cli && node --test test/**/*.test.mjs"
48
+ },
49
+ "dependencies": {
50
+ "narrarium": "^0.1.0",
51
+ "astro": "^5.14.1",
52
+ "marked": "^16.3.0"
53
+ },
54
+ "devDependencies": {
55
+ "@types/node": "^24.6.0",
56
+ "typescript": "^5.9.3"
57
+ }
58
+ }
@@ -0,0 +1,13 @@
1
+ import { mkdir } from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { exportEpub } from "narrarium";
4
+
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 });
13
+ console.log(`Exported EPUB with ${result.chapterCount} chapters to ${result.outputPath}`);