zreader 0.0.0-stage → 0.2.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.
- package/CHANGELOG.md +25 -0
- package/LICENSE +21 -0
- package/README.md +467 -2
- package/dist/agent/index.d.ts +90 -0
- package/dist/agent/index.js +293 -0
- package/dist/agent/index.js.map +1 -0
- package/dist/agent/react/index.d.ts +65 -0
- package/dist/agent/react/index.js +286 -0
- package/dist/agent/react/index.js.map +1 -0
- package/dist/blocks-DwR7l7pz.d.ts +20 -0
- package/dist/chunk-3WQBK6DE.js +47 -0
- package/dist/chunk-3WQBK6DE.js.map +1 -0
- package/dist/chunk-DYQNGV46.js +31 -0
- package/dist/chunk-DYQNGV46.js.map +1 -0
- package/dist/chunk-ISI35TCM.js +62 -0
- package/dist/chunk-ISI35TCM.js.map +1 -0
- package/dist/chunk-RNSAFDZ5.js +105 -0
- package/dist/chunk-RNSAFDZ5.js.map +1 -0
- package/dist/config/index.cjs +196 -0
- package/dist/config/index.cjs.map +1 -0
- package/dist/config/index.d.cts +159 -0
- package/dist/config/index.d.ts +159 -0
- package/dist/config/index.js +182 -0
- package/dist/config/index.js.map +1 -0
- package/dist/content/index.d.ts +143 -0
- package/dist/content/index.js +379 -0
- package/dist/content/index.js.map +1 -0
- package/dist/core/index.d.ts +262 -0
- package/dist/core/index.js +935 -0
- package/dist/core/index.js.map +1 -0
- package/dist/editor/index.d.ts +19 -0
- package/dist/editor/index.js +277 -0
- package/dist/editor/index.js.map +1 -0
- package/dist/index-Bp5oIiZd.d.ts +61 -0
- package/dist/next/client/index.d.ts +8 -0
- package/dist/next/client/index.js +13 -0
- package/dist/next/client/index.js.map +1 -0
- package/dist/next/index.cjs +275 -0
- package/dist/next/index.cjs.map +1 -0
- package/dist/next/index.d.cts +47 -0
- package/dist/next/index.d.ts +47 -0
- package/dist/next/index.js +265 -0
- package/dist/next/index.js.map +1 -0
- package/dist/next/server/index.d.ts +81 -0
- package/dist/next/server/index.js +51 -0
- package/dist/next/server/index.js.map +1 -0
- package/dist/react/index.d.ts +392 -0
- package/dist/react/index.js +2798 -0
- package/dist/react/index.js.map +1 -0
- package/dist/reader.css +116 -0
- package/dist/rehype/index.d.ts +27 -0
- package/dist/rehype/index.js +4 -0
- package/dist/rehype/index.js.map +1 -0
- package/dist/stubs/empty-config.d.ts +9 -0
- package/dist/stubs/empty-config.js +7 -0
- package/dist/stubs/empty-config.js.map +1 -0
- package/dist/stubs/server-only.d.ts +2 -0
- package/dist/stubs/server-only.js +6 -0
- package/dist/stubs/server-only.js.map +1 -0
- package/dist/styles.css +1 -0
- package/dist/tailwind.css +42 -0
- package/dist/types-xkdpkPxA.d.ts +147 -0
- package/dist/user-config/index.d.ts +17 -0
- package/dist/user-config/index.js +35 -0
- package/dist/user-config/index.js.map +1 -0
- package/dist/virtual-config/index.d.ts +6 -0
- package/dist/virtual-config/index.js +10 -0
- package/dist/virtual-config/index.js.map +1 -0
- package/package.json +237 -4
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import { z } from 'zod/v4';
|
|
2
|
+
export { z } from 'zod/v4';
|
|
3
|
+
|
|
4
|
+
/** Shared, framework-agnostic data model for zreader. */
|
|
5
|
+
type ISODate = string;
|
|
6
|
+
type PadScope = {
|
|
7
|
+
kind: "global";
|
|
8
|
+
} | {
|
|
9
|
+
kind: "book";
|
|
10
|
+
bookId: string;
|
|
11
|
+
} | {
|
|
12
|
+
kind: "chapter";
|
|
13
|
+
bookId: string;
|
|
14
|
+
chapterId: string;
|
|
15
|
+
};
|
|
16
|
+
type PadScopeKind = PadScope["kind"];
|
|
17
|
+
type ThemeName = "system" | "light" | "sepia" | "dark";
|
|
18
|
+
type Measure = "narrow" | "normal" | "wide";
|
|
19
|
+
type FontFamily = "serif" | "sans" | "mono";
|
|
20
|
+
type TextSize = "sm" | "base" | "lg" | "xl" | "2xl";
|
|
21
|
+
type Leading = "tight" | "normal" | "relaxed";
|
|
22
|
+
/** The palette the UI ships styles for (`::highlight(zr-<color>)`). */
|
|
23
|
+
declare const HIGHLIGHT_COLORS: readonly ["yellow", "green", "blue", "pink", "purple", "orange"];
|
|
24
|
+
type HighlightColor = (typeof HIGHLIGHT_COLORS)[number];
|
|
25
|
+
interface ReaderSettings {
|
|
26
|
+
textSize: TextSize;
|
|
27
|
+
leading: Leading;
|
|
28
|
+
measure: Measure;
|
|
29
|
+
fontFamily: FontFamily;
|
|
30
|
+
/** Tap a sentence to highlight it with the default colour. */
|
|
31
|
+
highlightMode: boolean;
|
|
32
|
+
updatedAt: ISODate;
|
|
33
|
+
}
|
|
34
|
+
/** Serializable client options (the `reader` half of reader.config.ts). */
|
|
35
|
+
interface ReaderClientOptions {
|
|
36
|
+
storagePrefix: string;
|
|
37
|
+
highlightColors: HighlightColor[];
|
|
38
|
+
defaultHighlightColor: HighlightColor;
|
|
39
|
+
scratchpad: {
|
|
40
|
+
enabled: boolean;
|
|
41
|
+
scopes: PadScopeKind[];
|
|
42
|
+
};
|
|
43
|
+
/** Themes offered in the UI. Applied as a class on <html> via next-themes. */
|
|
44
|
+
themes: ThemeName[];
|
|
45
|
+
defaultTheme: ThemeName;
|
|
46
|
+
defaultSettings: Omit<ReaderSettings, "updatedAt">;
|
|
47
|
+
progress: {
|
|
48
|
+
completeAt: number;
|
|
49
|
+
saveIntervalMs: number;
|
|
50
|
+
};
|
|
51
|
+
/** Show a "your notes only live in this browser" reminder. */
|
|
52
|
+
backupReminder: boolean;
|
|
53
|
+
/** Base path used to build links back into the reader (e.g. quote-to-pad). */
|
|
54
|
+
basePath: string;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
interface GlobLoader {
|
|
58
|
+
kind: "glob";
|
|
59
|
+
/** Directory containing one folder per book. Relative to the project root. */
|
|
60
|
+
base: string;
|
|
61
|
+
/** Chapter files, relative to `base`. */
|
|
62
|
+
pattern: string | string[];
|
|
63
|
+
ignore?: string[];
|
|
64
|
+
}
|
|
65
|
+
/** Astro-style glob loader: `content/books/<book>/{book.json, 01-intro.md, ...}` */
|
|
66
|
+
declare function glob(opts: {
|
|
67
|
+
base: string;
|
|
68
|
+
pattern?: string | string[];
|
|
69
|
+
ignore?: string[];
|
|
70
|
+
}): GlobLoader;
|
|
71
|
+
type PluginList = unknown[];
|
|
72
|
+
interface SanitizeOptions {
|
|
73
|
+
/** Hostnames allowed for <iframe src>. Iframes are stripped unless listed here. */
|
|
74
|
+
allowIframes?: string[];
|
|
75
|
+
/** Extra tags to allow on top of DOMPurify's safe HTML profile. */
|
|
76
|
+
allowTags?: string[];
|
|
77
|
+
/** Extra attributes to allow. */
|
|
78
|
+
allowAttributes?: string[];
|
|
79
|
+
}
|
|
80
|
+
interface ContentConfig {
|
|
81
|
+
loader: GlobLoader;
|
|
82
|
+
schemas: {
|
|
83
|
+
book: z.ZodType;
|
|
84
|
+
chapter: z.ZodType;
|
|
85
|
+
};
|
|
86
|
+
/** Applied to `.md` and `.mdx`. */
|
|
87
|
+
remarkPlugins: PluginList;
|
|
88
|
+
rehypePlugins: PluginList;
|
|
89
|
+
sanitize: SanitizeOptions;
|
|
90
|
+
/** Include chapters with `draft: true`. Defaults to `true` in development. */
|
|
91
|
+
includeDrafts: boolean;
|
|
92
|
+
/** Where compiled chapters are cached. */
|
|
93
|
+
cacheDir: string;
|
|
94
|
+
}
|
|
95
|
+
type DeepPartial<T> = T extends unknown[] ? T : T extends object ? {
|
|
96
|
+
[K in keyof T]?: DeepPartial<T[K]>;
|
|
97
|
+
} : T;
|
|
98
|
+
interface ReaderUserConfig {
|
|
99
|
+
content?: DeepPartial<Omit<ContentConfig, "schemas" | "loader">> & {
|
|
100
|
+
loader?: GlobLoader;
|
|
101
|
+
schemas?: Partial<ContentConfig["schemas"]>;
|
|
102
|
+
};
|
|
103
|
+
reader?: DeepPartial<ReaderClientOptions>;
|
|
104
|
+
}
|
|
105
|
+
interface ResolvedReaderConfig {
|
|
106
|
+
root: string;
|
|
107
|
+
content: ContentConfig;
|
|
108
|
+
reader: ReaderClientOptions;
|
|
109
|
+
}
|
|
110
|
+
declare const defaultBookSchema: z.ZodObject<{
|
|
111
|
+
title: z.ZodString;
|
|
112
|
+
subtitle: z.ZodOptional<z.ZodString>;
|
|
113
|
+
authors: z.ZodDefault<z.ZodArray<z.ZodString>>;
|
|
114
|
+
description: z.ZodOptional<z.ZodString>;
|
|
115
|
+
cover: z.ZodOptional<z.ZodString>;
|
|
116
|
+
/** Optional explicit chapter order (chapter slugs). */
|
|
117
|
+
chapters: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
118
|
+
}, z.core.$loose>;
|
|
119
|
+
declare const defaultChapterSchema: z.ZodObject<{
|
|
120
|
+
title: z.ZodString;
|
|
121
|
+
order: z.ZodOptional<z.ZodNumber>;
|
|
122
|
+
description: z.ZodOptional<z.ZodString>;
|
|
123
|
+
part: z.ZodOptional<z.ZodString>;
|
|
124
|
+
label: z.ZodOptional<z.ZodString>;
|
|
125
|
+
number: z.ZodOptional<z.ZodPipe<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>, z.ZodTransform<string, string | number>>>;
|
|
126
|
+
draft: z.ZodDefault<z.ZodBoolean>;
|
|
127
|
+
}, z.core.$loose>;
|
|
128
|
+
declare function defaultContentConfig(): ContentConfig;
|
|
129
|
+
/** Identity helper that gives `reader.config.ts` full type-checking. */
|
|
130
|
+
declare function defineConfig(config: ReaderUserConfig): ReaderUserConfig;
|
|
131
|
+
/**
|
|
132
|
+
* Deep merge: plain objects merge key-by-key, arrays and class instances
|
|
133
|
+
* (e.g. zod schemas) replace, `undefined` never overrides.
|
|
134
|
+
*/
|
|
135
|
+
declare function mergeConfig<T>(base: T, ...overrides: unknown[]): T;
|
|
136
|
+
declare class ReaderConfigError extends Error {
|
|
137
|
+
readonly issues: {
|
|
138
|
+
path: string;
|
|
139
|
+
message: string;
|
|
140
|
+
}[];
|
|
141
|
+
constructor(message: string, issues?: {
|
|
142
|
+
path: string;
|
|
143
|
+
message: string;
|
|
144
|
+
}[]);
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Resolve the final config: package defaults ← reader.config.ts ← inline overrides.
|
|
148
|
+
* Throws `ReaderConfigError` with readable messages.
|
|
149
|
+
*/
|
|
150
|
+
declare function resolveConfig(user?: ReaderUserConfig | null, inline?: ReaderUserConfig | null, opts?: {
|
|
151
|
+
root?: string;
|
|
152
|
+
source?: string;
|
|
153
|
+
}): ResolvedReaderConfig;
|
|
154
|
+
/** Only the serializable, client-safe half. */
|
|
155
|
+
declare function clientOptions(config: ResolvedReaderConfig): ReaderClientOptions;
|
|
156
|
+
declare const CONFIG_FILE_NAMES: string[];
|
|
157
|
+
|
|
158
|
+
export { CONFIG_FILE_NAMES, ReaderConfigError, clientOptions, defaultBookSchema, defaultChapterSchema, defaultContentConfig, defineConfig, glob, mergeConfig, resolveConfig };
|
|
159
|
+
export type { ContentConfig, GlobLoader, PluginList, ReaderUserConfig, ResolvedReaderConfig, SanitizeOptions };
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
import { z } from 'zod/v4';
|
|
2
|
+
export { z } from 'zod/v4';
|
|
3
|
+
|
|
4
|
+
// src/config/index.ts
|
|
5
|
+
|
|
6
|
+
// src/core/defaults.ts
|
|
7
|
+
var DEFAULT_CLIENT_OPTIONS = {
|
|
8
|
+
storagePrefix: "zr",
|
|
9
|
+
highlightColors: ["yellow", "green", "blue", "pink"],
|
|
10
|
+
defaultHighlightColor: "yellow",
|
|
11
|
+
scratchpad: { enabled: true, scopes: ["chapter", "book", "global"] },
|
|
12
|
+
themes: ["system", "light", "sepia", "dark"],
|
|
13
|
+
defaultTheme: "system",
|
|
14
|
+
defaultSettings: {
|
|
15
|
+
textSize: "lg",
|
|
16
|
+
leading: "relaxed",
|
|
17
|
+
measure: "normal",
|
|
18
|
+
fontFamily: "serif",
|
|
19
|
+
highlightMode: false
|
|
20
|
+
},
|
|
21
|
+
progress: { completeAt: 0.9, saveIntervalMs: 1e3 },
|
|
22
|
+
backupReminder: true,
|
|
23
|
+
basePath: "/books"
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
// src/core/types.ts
|
|
27
|
+
var THEMES = ["system", "light", "sepia", "dark"];
|
|
28
|
+
var TEXT_SIZES = ["sm", "base", "lg", "xl", "2xl"];
|
|
29
|
+
var LEADINGS = ["tight", "normal", "relaxed"];
|
|
30
|
+
var MEASURES = ["narrow", "normal", "wide"];
|
|
31
|
+
var FONT_FAMILIES = ["serif", "sans", "mono"];
|
|
32
|
+
var HIGHLIGHT_COLORS = ["yellow", "green", "blue", "pink", "purple", "orange"];
|
|
33
|
+
|
|
34
|
+
// src/config/index.ts
|
|
35
|
+
function glob(opts) {
|
|
36
|
+
return { kind: "glob", base: opts.base, pattern: opts.pattern ?? "**/*.{md,mdx,html}", ignore: opts.ignore };
|
|
37
|
+
}
|
|
38
|
+
var defaultBookSchema = z.looseObject({
|
|
39
|
+
title: z.string(),
|
|
40
|
+
subtitle: z.string().optional(),
|
|
41
|
+
authors: z.array(z.string()).default([]),
|
|
42
|
+
description: z.string().optional(),
|
|
43
|
+
cover: z.string().optional(),
|
|
44
|
+
/** Optional explicit chapter order (chapter slugs). */
|
|
45
|
+
chapters: z.array(z.string()).optional()
|
|
46
|
+
});
|
|
47
|
+
var defaultChapterSchema = z.looseObject({
|
|
48
|
+
title: z.string(),
|
|
49
|
+
order: z.number().optional(),
|
|
50
|
+
description: z.string().optional(),
|
|
51
|
+
part: z.string().optional(),
|
|
52
|
+
label: z.string().optional(),
|
|
53
|
+
number: z.union([z.string(), z.number()]).transform(String).optional(),
|
|
54
|
+
draft: z.boolean().default(false)
|
|
55
|
+
});
|
|
56
|
+
function isDev() {
|
|
57
|
+
return typeof process !== "undefined" && process.env?.NODE_ENV === "development";
|
|
58
|
+
}
|
|
59
|
+
function defaultContentConfig() {
|
|
60
|
+
return {
|
|
61
|
+
loader: glob({ base: "./content/books" }),
|
|
62
|
+
schemas: { book: defaultBookSchema, chapter: defaultChapterSchema },
|
|
63
|
+
remarkPlugins: [],
|
|
64
|
+
rehypePlugins: [],
|
|
65
|
+
sanitize: {},
|
|
66
|
+
includeDrafts: isDev(),
|
|
67
|
+
cacheDir: typeof process !== "undefined" && process.env?.ZREADER_CACHE_DIR || "node_modules/.cache/zreader"
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
function defineConfig(config) {
|
|
71
|
+
return config;
|
|
72
|
+
}
|
|
73
|
+
function isPlainObject(x) {
|
|
74
|
+
if (typeof x !== "object" || x === null || Array.isArray(x)) return false;
|
|
75
|
+
const proto = Object.getPrototypeOf(x);
|
|
76
|
+
return proto === Object.prototype || proto === null;
|
|
77
|
+
}
|
|
78
|
+
function mergeConfig(base, ...overrides) {
|
|
79
|
+
let out = base;
|
|
80
|
+
for (const o of overrides) out = mergeTwo(out, o);
|
|
81
|
+
return out;
|
|
82
|
+
}
|
|
83
|
+
function mergeTwo(a, b) {
|
|
84
|
+
if (b === void 0) return a;
|
|
85
|
+
if (isPlainObject(a) && isPlainObject(b)) {
|
|
86
|
+
const out = { ...a };
|
|
87
|
+
for (const [k, v] of Object.entries(b)) out[k] = mergeTwo(a[k], v);
|
|
88
|
+
return out;
|
|
89
|
+
}
|
|
90
|
+
return b;
|
|
91
|
+
}
|
|
92
|
+
var themeName = z.enum(THEMES);
|
|
93
|
+
var highlightColor = z.enum(HIGHLIGHT_COLORS);
|
|
94
|
+
var clientSchema = z.object({
|
|
95
|
+
storagePrefix: z.string().regex(/^[a-z0-9_-]+$/i, "use letters, digits, '-' or '_'"),
|
|
96
|
+
highlightColors: z.array(highlightColor).min(1, "must be non-empty"),
|
|
97
|
+
defaultHighlightColor: highlightColor,
|
|
98
|
+
scratchpad: z.object({
|
|
99
|
+
enabled: z.boolean(),
|
|
100
|
+
scopes: z.array(z.enum(["global", "book", "chapter"])).min(1, "must be non-empty")
|
|
101
|
+
}),
|
|
102
|
+
themes: z.array(themeName).min(1),
|
|
103
|
+
defaultTheme: themeName,
|
|
104
|
+
defaultSettings: z.object({
|
|
105
|
+
textSize: z.enum(TEXT_SIZES),
|
|
106
|
+
leading: z.enum(LEADINGS),
|
|
107
|
+
measure: z.enum(MEASURES),
|
|
108
|
+
fontFamily: z.enum(FONT_FAMILIES),
|
|
109
|
+
highlightMode: z.boolean()
|
|
110
|
+
}),
|
|
111
|
+
progress: z.object({ completeAt: z.number().gt(0).max(1), saveIntervalMs: z.number().min(100) }),
|
|
112
|
+
backupReminder: z.boolean(),
|
|
113
|
+
basePath: z.string().startsWith("/")
|
|
114
|
+
}).refine((c) => c.highlightColors.includes(c.defaultHighlightColor), {
|
|
115
|
+
message: "defaultHighlightColor must be one of highlightColors",
|
|
116
|
+
path: ["defaultHighlightColor"]
|
|
117
|
+
}).refine((c) => c.themes.includes(c.defaultTheme), {
|
|
118
|
+
message: "defaultTheme must be one of themes",
|
|
119
|
+
path: ["defaultTheme"]
|
|
120
|
+
});
|
|
121
|
+
function isSchemaLike(v) {
|
|
122
|
+
return typeof v === "object" && v !== null && typeof v.safeParse === "function";
|
|
123
|
+
}
|
|
124
|
+
var contentSchema = z.object({
|
|
125
|
+
loader: z.object({
|
|
126
|
+
kind: z.literal("glob"),
|
|
127
|
+
base: z.string().min(1),
|
|
128
|
+
pattern: z.union([z.string(), z.array(z.string()).min(1)]),
|
|
129
|
+
ignore: z.array(z.string()).optional()
|
|
130
|
+
}),
|
|
131
|
+
schemas: z.object({
|
|
132
|
+
book: z.custom(isSchemaLike, "must be a zod (or safeParse-compatible) schema"),
|
|
133
|
+
chapter: z.custom(isSchemaLike, "must be a zod (or safeParse-compatible) schema")
|
|
134
|
+
}),
|
|
135
|
+
remarkPlugins: z.array(z.any()),
|
|
136
|
+
rehypePlugins: z.array(z.any()),
|
|
137
|
+
sanitize: z.object({
|
|
138
|
+
allowIframes: z.array(z.string()).optional(),
|
|
139
|
+
allowTags: z.array(z.string()).optional(),
|
|
140
|
+
allowAttributes: z.array(z.string()).optional()
|
|
141
|
+
}),
|
|
142
|
+
includeDrafts: z.boolean(),
|
|
143
|
+
cacheDir: z.string()
|
|
144
|
+
});
|
|
145
|
+
var ReaderConfigError = class extends Error {
|
|
146
|
+
constructor(message, issues = []) {
|
|
147
|
+
super(message);
|
|
148
|
+
this.issues = issues;
|
|
149
|
+
this.name = "ReaderConfigError";
|
|
150
|
+
}
|
|
151
|
+
issues;
|
|
152
|
+
};
|
|
153
|
+
function formatIssues(source, section, error) {
|
|
154
|
+
const issues = error.issues.map((i) => ({ path: [section, ...i.path.map(String)].join("."), message: i.message }));
|
|
155
|
+
return new ReaderConfigError(
|
|
156
|
+
`Invalid reader config${source ? ` (${source})` : ""}:
|
|
157
|
+
` + issues.map((i) => ` - ${i.path}: ${i.message}`).join("\n"),
|
|
158
|
+
issues
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
function resolveConfig(user, inline, opts = {}) {
|
|
162
|
+
const root = opts.root ?? (typeof process !== "undefined" && process.cwd ? process.cwd() : "/");
|
|
163
|
+
const reader = mergeConfig(
|
|
164
|
+
structuredClone(DEFAULT_CLIENT_OPTIONS),
|
|
165
|
+
user?.reader,
|
|
166
|
+
inline?.reader
|
|
167
|
+
);
|
|
168
|
+
const content = mergeConfig(defaultContentConfig(), user?.content, inline?.content);
|
|
169
|
+
const r = clientSchema.safeParse(reader);
|
|
170
|
+
if (!r.success) throw formatIssues(opts.source ?? "", "reader", r.error);
|
|
171
|
+
const c = contentSchema.safeParse(content);
|
|
172
|
+
if (!c.success) throw formatIssues(opts.source ?? "", "content", c.error);
|
|
173
|
+
return { root, content, reader };
|
|
174
|
+
}
|
|
175
|
+
function clientOptions(config) {
|
|
176
|
+
return config.reader;
|
|
177
|
+
}
|
|
178
|
+
var CONFIG_FILE_NAMES = ["reader.config.ts", "reader.config.mts", "reader.config.mjs", "reader.config.js"];
|
|
179
|
+
|
|
180
|
+
export { CONFIG_FILE_NAMES, ReaderConfigError, clientOptions, defaultBookSchema, defaultChapterSchema, defaultContentConfig, defineConfig, glob, mergeConfig, resolveConfig };
|
|
181
|
+
//# sourceMappingURL=index.js.map
|
|
182
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/core/defaults.ts","../../src/core/types.ts","../../src/config/index.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import type { ReaderClientOptions } from \"./types\";\n\nexport const DEFAULT_CLIENT_OPTIONS: ReaderClientOptions = {\n storagePrefix: \"zr\",\n highlightColors: [\"yellow\", \"green\", \"blue\", \"pink\"],\n defaultHighlightColor: \"yellow\",\n scratchpad: { enabled: true, scopes: [\"chapter\", \"book\", \"global\"] },\n themes: [\"system\", \"light\", \"sepia\", \"dark\"],\n defaultTheme: \"system\",\n defaultSettings: {\n textSize: \"lg\",\n leading: \"relaxed\",\n measure: \"normal\",\n fontFamily: \"serif\",\n highlightMode: false,\n },\n progress: { completeAt: 0.9, saveIntervalMs: 1000 },\n backupReminder: true,\n basePath: \"/books\",\n};\n","/** Shared, framework-agnostic data model for zreader. */\n\nexport type ISODate = string;\n\n/** W3C Web Annotation-style anchor. Offsets are measured over the chapter root's text. */\nexport interface Anchor {\n /** `data-block-id` of the block containing the start of the selection. */\n blockId: string;\n /** Offsets relative to the start block's text (fast path). */\n blockStart: number;\n /** TextPositionSelector over the whole chapter text. */\n start: number;\n end: number;\n /** TextQuoteSelector. */\n exact: string;\n prefix: string;\n suffix: string;\n /** Content hash of the chapter when the anchor was created. */\n contentHash?: string;\n}\n\nexport interface Highlight {\n id: string;\n bookId: string;\n chapterId: string;\n anchor: Anchor;\n color: string;\n note?: string;\n createdAt: ISODate;\n updatedAt: ISODate;\n}\n\nexport interface Bookmark {\n id: string;\n bookId: string;\n chapterId: string;\n /** Absent for whole-chapter bookmarks. */\n blockId?: string;\n label?: string;\n excerpt?: string;\n createdAt: ISODate;\n updatedAt: ISODate;\n}\n\nexport interface ChapterProgress {\n chapterId: string;\n blockId?: string;\n /** 0..1 */\n percent: number;\n completed: boolean;\n updatedAt: ISODate;\n}\n\nexport interface BookProgress {\n bookId: string;\n chapters: Record<string, ChapterProgress>;\n last?: { chapterId: string; blockId?: string; updatedAt: ISODate };\n}\n\nexport type PadScope =\n | { kind: \"global\" }\n | { kind: \"book\"; bookId: string }\n | { kind: \"chapter\"; bookId: string; chapterId: string };\n\nexport type PadScopeKind = PadScope[\"kind\"];\n\nexport interface Pad {\n /** Markdown is the interchange/source format. */\n markdown: string;\n /** Lossless editor JSON cache. Cleared whenever `markdown` is changed outside the editor. */\n json?: unknown;\n updatedAt: ISODate;\n}\n\nexport type ThemeName = \"system\" | \"light\" | \"sepia\" | \"dark\";\nexport type Measure = \"narrow\" | \"normal\" | \"wide\";\nexport type FontFamily = \"serif\" | \"sans\" | \"mono\";\nexport type TextSize = \"sm\" | \"base\" | \"lg\" | \"xl\" | \"2xl\";\nexport type Leading = \"tight\" | \"normal\" | \"relaxed\";\n\nexport const THEMES = [\"system\", \"light\", \"sepia\", \"dark\"] as const satisfies readonly ThemeName[];\nexport const TEXT_SIZES = [\"sm\", \"base\", \"lg\", \"xl\", \"2xl\"] as const satisfies readonly TextSize[];\nexport const LEADINGS = [\"tight\", \"normal\", \"relaxed\"] as const satisfies readonly Leading[];\nexport const MEASURES = [\"narrow\", \"normal\", \"wide\"] as const satisfies readonly Measure[];\nexport const FONT_FAMILIES = [\"serif\", \"sans\", \"mono\"] as const satisfies readonly FontFamily[];\n/** The palette the UI ships styles for (`::highlight(zr-<color>)`). */\nexport const HIGHLIGHT_COLORS = [\"yellow\", \"green\", \"blue\", \"pink\", \"purple\", \"orange\"] as const;\nexport type HighlightColor = (typeof HIGHLIGHT_COLORS)[number];\n\nexport interface ReaderSettings {\n textSize: TextSize;\n leading: Leading;\n measure: Measure;\n fontFamily: FontFamily;\n /** Tap a sentence to highlight it with the default colour. */\n highlightMode: boolean;\n updatedAt: ISODate;\n}\n\n/** Serializable client options (the `reader` half of reader.config.ts). */\nexport interface ReaderClientOptions {\n storagePrefix: string;\n highlightColors: HighlightColor[];\n defaultHighlightColor: HighlightColor;\n scratchpad: { enabled: boolean; scopes: PadScopeKind[] };\n /** Themes offered in the UI. Applied as a class on <html> via next-themes. */\n themes: ThemeName[];\n defaultTheme: ThemeName;\n defaultSettings: Omit<ReaderSettings, \"updatedAt\">;\n progress: { completeAt: number; saveIntervalMs: number };\n /** Show a \"your notes only live in this browser\" reminder. */\n backupReminder: boolean;\n /** Base path used to build links back into the reader (e.g. quote-to-pad). */\n basePath: string;\n}\n\nexport interface TocEntry {\n id: string;\n depth: number;\n text: string;\n}\n\nexport interface ChapterMeta {\n id: string;\n title: string;\n order: number;\n description?: string;\n /** Section the chapter belongs to, e.g. \"Part I · For the Builders\". Groups the contents list. */\n part?: string;\n /** Eyebrow shown above the title, e.g. \"Chapter 5\" or \"Appendix A\". */\n label?: string;\n /** Short marker for lists, e.g. \"5\" or \"A\". */\n number?: string;\n}\n\nexport interface BookMeta {\n id: string;\n title: string;\n subtitle?: string;\n authors: string[];\n description?: string;\n cover?: string;\n chapters: ChapterMeta[];\n}\n","import { z } from \"zod/v4\";\nimport { DEFAULT_CLIENT_OPTIONS } from \"../core/defaults\";\nimport {\n FONT_FAMILIES,\n HIGHLIGHT_COLORS,\n LEADINGS,\n MEASURES,\n TEXT_SIZES,\n THEMES,\n type ReaderClientOptions,\n} from \"../core/types\";\n\nexport { z };\n\n// ---------------------------------------------------------------- types\n\nexport interface GlobLoader {\n kind: \"glob\";\n /** Directory containing one folder per book. Relative to the project root. */\n base: string;\n /** Chapter files, relative to `base`. */\n pattern: string | string[];\n ignore?: string[];\n}\n\n/** Astro-style glob loader: `content/books/<book>/{book.json, 01-intro.md, ...}` */\nexport function glob(opts: { base: string; pattern?: string | string[]; ignore?: string[] }): GlobLoader {\n return { kind: \"glob\", base: opts.base, pattern: opts.pattern ?? \"**/*.{md,mdx,html}\", ignore: opts.ignore };\n}\n\n// unified's PluggableList, kept loose to avoid a type dependency in this entry.\nexport type PluginList = unknown[];\n\nexport interface SanitizeOptions {\n /** Hostnames allowed for <iframe src>. Iframes are stripped unless listed here. */\n allowIframes?: string[];\n /** Extra tags to allow on top of DOMPurify's safe HTML profile. */\n allowTags?: string[];\n /** Extra attributes to allow. */\n allowAttributes?: string[];\n}\n\nexport interface ContentConfig {\n loader: GlobLoader;\n schemas: { book: z.ZodType; chapter: z.ZodType };\n /** Applied to `.md` and `.mdx`. */\n remarkPlugins: PluginList;\n rehypePlugins: PluginList;\n sanitize: SanitizeOptions;\n /** Include chapters with `draft: true`. Defaults to `true` in development. */\n includeDrafts: boolean;\n /** Where compiled chapters are cached. */\n cacheDir: string;\n}\n\ntype DeepPartial<T> = T extends unknown[] ? T : T extends object ? { [K in keyof T]?: DeepPartial<T[K]> } : T;\n\nexport interface ReaderUserConfig {\n content?: DeepPartial<Omit<ContentConfig, \"schemas\" | \"loader\">> & {\n loader?: GlobLoader;\n schemas?: Partial<ContentConfig[\"schemas\"]>;\n };\n reader?: DeepPartial<ReaderClientOptions>;\n}\n\nexport interface ResolvedReaderConfig {\n root: string;\n content: ContentConfig;\n reader: ReaderClientOptions;\n}\n\n// ------------------------------------------------------------- defaults\n\nexport const defaultBookSchema = z.looseObject({\n title: z.string(),\n subtitle: z.string().optional(),\n authors: z.array(z.string()).default([]),\n description: z.string().optional(),\n cover: z.string().optional(),\n /** Optional explicit chapter order (chapter slugs). */\n chapters: z.array(z.string()).optional(),\n});\n\nexport const defaultChapterSchema = z.looseObject({\n title: z.string(),\n order: z.number().optional(),\n description: z.string().optional(),\n part: z.string().optional(),\n label: z.string().optional(),\n number: z.union([z.string(), z.number()]).transform(String).optional(),\n draft: z.boolean().default(false),\n});\n\nfunction isDev() {\n return typeof process !== \"undefined\" && process.env?.NODE_ENV === \"development\";\n}\n\nexport function defaultContentConfig(): ContentConfig {\n return {\n loader: glob({ base: \"./content/books\" }),\n schemas: { book: defaultBookSchema, chapter: defaultChapterSchema },\n remarkPlugins: [],\n rehypePlugins: [],\n sanitize: {},\n includeDrafts: isDev(),\n cacheDir:\n (typeof process !== \"undefined\" && process.env?.ZREADER_CACHE_DIR) || \"node_modules/.cache/zreader\",\n };\n}\n\n// ------------------------------------------------------------ define/merge\n\n/** Identity helper that gives `reader.config.ts` full type-checking. */\nexport function defineConfig(config: ReaderUserConfig): ReaderUserConfig {\n return config;\n}\n\nfunction isPlainObject(x: unknown): x is Record<string, unknown> {\n if (typeof x !== \"object\" || x === null || Array.isArray(x)) return false;\n const proto = Object.getPrototypeOf(x);\n return proto === Object.prototype || proto === null;\n}\n\n/**\n * Deep merge: plain objects merge key-by-key, arrays and class instances\n * (e.g. zod schemas) replace, `undefined` never overrides.\n */\nexport function mergeConfig<T>(base: T, ...overrides: unknown[]): T {\n let out: unknown = base;\n for (const o of overrides) out = mergeTwo(out, o);\n return out as T;\n}\n\nfunction mergeTwo(a: unknown, b: unknown): unknown {\n if (b === undefined) return a;\n if (isPlainObject(a) && isPlainObject(b)) {\n const out: Record<string, unknown> = { ...a };\n for (const [k, v] of Object.entries(b)) out[k] = mergeTwo(a[k], v);\n return out;\n }\n return b;\n}\n\n// --------------------------------------------------------------- validate\n\nconst themeName = z.enum(THEMES);\nconst highlightColor = z.enum(HIGHLIGHT_COLORS);\nconst clientSchema = z\n .object({\n storagePrefix: z.string().regex(/^[a-z0-9_-]+$/i, \"use letters, digits, '-' or '_'\"),\n highlightColors: z.array(highlightColor).min(1, \"must be non-empty\"),\n defaultHighlightColor: highlightColor,\n scratchpad: z.object({\n enabled: z.boolean(),\n scopes: z.array(z.enum([\"global\", \"book\", \"chapter\"])).min(1, \"must be non-empty\"),\n }),\n themes: z.array(themeName).min(1),\n defaultTheme: themeName,\n defaultSettings: z.object({\n textSize: z.enum(TEXT_SIZES),\n leading: z.enum(LEADINGS),\n measure: z.enum(MEASURES),\n fontFamily: z.enum(FONT_FAMILIES),\n highlightMode: z.boolean(),\n }),\n progress: z.object({ completeAt: z.number().gt(0).max(1), saveIntervalMs: z.number().min(100) }),\n backupReminder: z.boolean(),\n basePath: z.string().startsWith(\"/\"),\n })\n .refine((c) => c.highlightColors.includes(c.defaultHighlightColor), {\n message: \"defaultHighlightColor must be one of highlightColors\",\n path: [\"defaultHighlightColor\"],\n })\n .refine((c) => c.themes.includes(c.defaultTheme), {\n message: \"defaultTheme must be one of themes\",\n path: [\"defaultTheme\"],\n });\n\nfunction isSchemaLike(v: unknown): boolean {\n return typeof v === \"object\" && v !== null && typeof (v as { safeParse?: unknown }).safeParse === \"function\";\n}\n\nconst contentSchema = z.object({\n loader: z.object({\n kind: z.literal(\"glob\"),\n base: z.string().min(1),\n pattern: z.union([z.string(), z.array(z.string()).min(1)]),\n ignore: z.array(z.string()).optional(),\n }),\n schemas: z.object({\n book: z.custom<z.ZodType>(isSchemaLike, \"must be a zod (or safeParse-compatible) schema\"),\n chapter: z.custom<z.ZodType>(isSchemaLike, \"must be a zod (or safeParse-compatible) schema\"),\n }),\n remarkPlugins: z.array(z.any()),\n rehypePlugins: z.array(z.any()),\n sanitize: z.object({\n allowIframes: z.array(z.string()).optional(),\n allowTags: z.array(z.string()).optional(),\n allowAttributes: z.array(z.string()).optional(),\n }),\n includeDrafts: z.boolean(),\n cacheDir: z.string(),\n});\n\nexport class ReaderConfigError extends Error {\n constructor(\n message: string,\n public readonly issues: { path: string; message: string }[] = [],\n ) {\n super(message);\n this.name = \"ReaderConfigError\";\n }\n}\n\nfunction formatIssues(source: string, section: string, error: z.ZodError) {\n const issues = error.issues.map((i) => ({ path: [section, ...i.path.map(String)].join(\".\"), message: i.message }));\n return new ReaderConfigError(\n `Invalid reader config${source ? ` (${source})` : \"\"}:\\n` + issues.map((i) => ` - ${i.path}: ${i.message}`).join(\"\\n\"),\n issues,\n );\n}\n\n/**\n * Resolve the final config: package defaults ← reader.config.ts ← inline overrides.\n * Throws `ReaderConfigError` with readable messages.\n */\nexport function resolveConfig(\n user?: ReaderUserConfig | null,\n inline?: ReaderUserConfig | null,\n opts: { root?: string; source?: string } = {},\n): ResolvedReaderConfig {\n const root = opts.root ?? (typeof process !== \"undefined\" && process.cwd ? process.cwd() : \"/\");\n const reader = mergeConfig<ReaderClientOptions>(\n structuredClone(DEFAULT_CLIENT_OPTIONS),\n user?.reader,\n inline?.reader,\n );\n const content = mergeConfig<ContentConfig>(defaultContentConfig(), user?.content, inline?.content);\n\n const r = clientSchema.safeParse(reader);\n if (!r.success) throw formatIssues(opts.source ?? \"\", \"reader\", r.error);\n const c = contentSchema.safeParse(content);\n if (!c.success) throw formatIssues(opts.source ?? \"\", \"content\", c.error);\n\n return { root, content, reader };\n}\n\n/** Only the serializable, client-safe half. */\nexport function clientOptions(config: ResolvedReaderConfig): ReaderClientOptions {\n return config.reader;\n}\n\nexport const CONFIG_FILE_NAMES = [\"reader.config.ts\", \"reader.config.mts\", \"reader.config.mjs\", \"reader.config.js\"];\n"]}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { S as SanitizeOptions, a as ResolvedReaderConfig, R as ReaderUserConfig } from '../index-Bp5oIiZd.js';
|
|
2
|
+
export { C as ContentConfig, G as GlobLoader, d as defineConfig, g as glob } from '../index-Bp5oIiZd.js';
|
|
3
|
+
import { BookMeta, ChapterMeta, TocEntry } from '../core/index.js';
|
|
4
|
+
import { PluggableList } from 'unified';
|
|
5
|
+
import { ComponentType } from 'react';
|
|
6
|
+
import { BlocksData, BlockInfo } from '../rehype/index.js';
|
|
7
|
+
export { default as rehypeBlocks } from '../rehype/index.js';
|
|
8
|
+
export { h as hashString } from '../blocks-DwR7l7pz.js';
|
|
9
|
+
export { z } from 'zod/v4';
|
|
10
|
+
import 'hast';
|
|
11
|
+
import 'vfile';
|
|
12
|
+
|
|
13
|
+
type ChapterFormat = "md" | "mdx" | "html";
|
|
14
|
+
interface PipelineOptions {
|
|
15
|
+
sanitize?: SanitizeOptions;
|
|
16
|
+
remarkPlugins?: PluggableList;
|
|
17
|
+
rehypePlugins?: PluggableList;
|
|
18
|
+
}
|
|
19
|
+
interface HtmlResult extends BlocksData {
|
|
20
|
+
kind: "html";
|
|
21
|
+
html: string;
|
|
22
|
+
}
|
|
23
|
+
interface MdxCompiled extends BlocksData {
|
|
24
|
+
kind: "mdx";
|
|
25
|
+
/** Compiled function body; run with `runMdx`. Serializable (cacheable). */
|
|
26
|
+
code: string;
|
|
27
|
+
}
|
|
28
|
+
/** Add block ids / heading ids / TOC to already-sanitized HTML. */
|
|
29
|
+
declare function annotateHtml(html: string): Promise<HtmlResult>;
|
|
30
|
+
/** Untrusted HTML string → sanitized, annotated HTML. */
|
|
31
|
+
declare function renderHtml(html: string, opts?: PipelineOptions): Promise<HtmlResult>;
|
|
32
|
+
/**
|
|
33
|
+
* Markdown (GFM, inline HTML allowed) → sanitized, annotated HTML.
|
|
34
|
+
* Inline HTML is parsed, then the whole output goes through DOMPurify.
|
|
35
|
+
*/
|
|
36
|
+
declare function renderMarkdown(markdown: string, opts?: PipelineOptions): Promise<HtmlResult>;
|
|
37
|
+
/**
|
|
38
|
+
* Trusted MDX → compiled function body. MDX is code: only compile files you
|
|
39
|
+
* author (e.g. from your repo), never user-supplied input.
|
|
40
|
+
*/
|
|
41
|
+
declare function compileMdx(source: string, opts?: PipelineOptions): Promise<MdxCompiled>;
|
|
42
|
+
type MdxComponents = Record<string, ComponentType<Record<string, unknown>>>;
|
|
43
|
+
type MdxContent = ComponentType<{
|
|
44
|
+
components?: MdxComponents;
|
|
45
|
+
}>;
|
|
46
|
+
declare function runMdx(code: string): Promise<MdxContent>;
|
|
47
|
+
|
|
48
|
+
interface ChapterEntry extends ChapterMeta {
|
|
49
|
+
bookId: string;
|
|
50
|
+
file: string;
|
|
51
|
+
format: ChapterFormat;
|
|
52
|
+
/** Validated frontmatter. */
|
|
53
|
+
data: Record<string, unknown>;
|
|
54
|
+
body: string;
|
|
55
|
+
draft: boolean;
|
|
56
|
+
mtimeMs: number;
|
|
57
|
+
}
|
|
58
|
+
interface BookEntry extends BookMeta {
|
|
59
|
+
/** Validated book.json. */
|
|
60
|
+
data: Record<string, unknown>;
|
|
61
|
+
dir: string;
|
|
62
|
+
chapterEntries: ChapterEntry[];
|
|
63
|
+
}
|
|
64
|
+
declare class ContentError extends Error {
|
|
65
|
+
readonly file?: string | undefined;
|
|
66
|
+
constructor(message: string, file?: string | undefined);
|
|
67
|
+
}
|
|
68
|
+
/** Read every book + chapter frontmatter (bodies are compiled lazily). */
|
|
69
|
+
declare function loadBooks(config: ResolvedReaderConfig): Promise<BookEntry[]>;
|
|
70
|
+
declare function compileChapter(entry: ChapterEntry, config: ResolvedReaderConfig): Promise<HtmlResult | MdxCompiled>;
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Sanitize untrusted HTML with DOMPurify (html profile, no scripts, no event
|
|
74
|
+
* handlers, no javascript: URLs, no inline styles, no forms). Iframes are
|
|
75
|
+
* stripped unless their https host is in `allowIframes`. External links opened
|
|
76
|
+
* in a new tab get `rel="noopener noreferrer"`.
|
|
77
|
+
*/
|
|
78
|
+
declare function sanitizeHtml(html: string, options?: SanitizeOptions): string;
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* `zreader/content` — Astro-style content layer (server/build only).
|
|
82
|
+
*
|
|
83
|
+
* const books = await getBooks();
|
|
84
|
+
* const { chapter } = await getChapter("my-book", "intro");
|
|
85
|
+
* const rendered = await renderChapter(chapter);
|
|
86
|
+
*/
|
|
87
|
+
|
|
88
|
+
type RenderedChapter = {
|
|
89
|
+
kind: "html";
|
|
90
|
+
html: string;
|
|
91
|
+
toc: TocEntry[];
|
|
92
|
+
blocks: BlockInfo[];
|
|
93
|
+
contentHash: string;
|
|
94
|
+
} | {
|
|
95
|
+
kind: "mdx";
|
|
96
|
+
Content: MdxContent;
|
|
97
|
+
toc: TocEntry[];
|
|
98
|
+
blocks: BlockInfo[];
|
|
99
|
+
contentHash: string;
|
|
100
|
+
};
|
|
101
|
+
interface ChapterLookup {
|
|
102
|
+
book: BookEntry;
|
|
103
|
+
chapter: ChapterEntry;
|
|
104
|
+
index: number;
|
|
105
|
+
prev: ChapterMeta | null;
|
|
106
|
+
next: ChapterMeta | null;
|
|
107
|
+
}
|
|
108
|
+
declare function globalConfig(): Promise<ResolvedReaderConfig>;
|
|
109
|
+
declare function toBookMeta(book: BookEntry): BookMeta;
|
|
110
|
+
declare const getBooks: () => Promise<BookEntry[]>;
|
|
111
|
+
declare const getBookMetas: () => Promise<BookMeta[]>;
|
|
112
|
+
declare const getBook: (bookId: string) => Promise<BookEntry | null>;
|
|
113
|
+
declare const getChapter: (bookId: string, chapterId: string) => Promise<ChapterLookup | null>;
|
|
114
|
+
declare const renderChapter: (entry: ChapterEntry) => Promise<RenderedChapter>;
|
|
115
|
+
declare const getStaticParams: <B extends string = "book", C extends string = "chapter">(names?: {
|
|
116
|
+
book?: B;
|
|
117
|
+
chapter?: C;
|
|
118
|
+
}) => Promise<Array<Record<B | C, string>>>;
|
|
119
|
+
declare const getReaderConfig: typeof globalConfig;
|
|
120
|
+
type InlineContent = ReaderUserConfig["content"];
|
|
121
|
+
/**
|
|
122
|
+
* Inline form: merge content options on top of the global reader.config.ts.
|
|
123
|
+
*
|
|
124
|
+
* export const handbook = defineBooks({ loader: glob({ base: "./content/handbook" }) });
|
|
125
|
+
* await handbook.getBooks();
|
|
126
|
+
*/
|
|
127
|
+
declare function defineBooks(inline?: InlineContent | ResolvedReaderConfig): {
|
|
128
|
+
config: () => Promise<ResolvedReaderConfig>;
|
|
129
|
+
getBooks(): Promise<BookEntry[]>;
|
|
130
|
+
/** Plain, serializable book metadata (safe to pass to client components). */
|
|
131
|
+
getBookMetas(): Promise<BookMeta[]>;
|
|
132
|
+
getBook(bookId: string): Promise<BookEntry | null>;
|
|
133
|
+
getChapter(bookId: string, chapterId: string): Promise<ChapterLookup | null>;
|
|
134
|
+
renderChapter(entry: ChapterEntry): Promise<RenderedChapter>;
|
|
135
|
+
/** For `generateStaticParams`. Param names are configurable. */
|
|
136
|
+
getStaticParams<B extends string = "book", C extends string = "chapter">(names?: {
|
|
137
|
+
book?: B;
|
|
138
|
+
chapter?: C;
|
|
139
|
+
}): Promise<Array<Record<B | C, string>>>;
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
export { BlockInfo, BlocksData, ContentError, ReaderUserConfig, ResolvedReaderConfig, SanitizeOptions, annotateHtml, compileChapter, compileMdx, defineBooks, getBook, getBookMetas, getBooks, getChapter, getReaderConfig, getStaticParams, loadBooks, renderChapter, renderHtml, renderMarkdown, runMdx, sanitizeHtml, toBookMeta };
|
|
143
|
+
export type { BookEntry, ChapterEntry, ChapterFormat, ChapterLookup, HtmlResult, MdxCompiled, MdxComponents, MdxContent, PipelineOptions, RenderedChapter };
|