wolfy-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 (233) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +277 -0
  3. package/dist/core/book.d.ts +75 -0
  4. package/dist/core/book.d.ts.map +1 -0
  5. package/dist/core/book.js +2 -0
  6. package/dist/core/book.js.map +1 -0
  7. package/dist/core/errors.d.ts +17 -0
  8. package/dist/core/errors.d.ts.map +1 -0
  9. package/dist/core/errors.js +29 -0
  10. package/dist/core/errors.js.map +1 -0
  11. package/dist/core/format.d.ts +13 -0
  12. package/dist/core/format.d.ts.map +1 -0
  13. package/dist/core/format.js +2 -0
  14. package/dist/core/format.js.map +1 -0
  15. package/dist/core/graphemes.d.ts +36 -0
  16. package/dist/core/graphemes.d.ts.map +1 -0
  17. package/dist/core/graphemes.js +62 -0
  18. package/dist/core/graphemes.js.map +1 -0
  19. package/dist/core/index.d.ts +11 -0
  20. package/dist/core/index.d.ts.map +1 -0
  21. package/dist/core/index.js +6 -0
  22. package/dist/core/index.js.map +1 -0
  23. package/dist/core/lookup.d.ts +10 -0
  24. package/dist/core/lookup.d.ts.map +1 -0
  25. package/dist/core/lookup.js +16 -0
  26. package/dist/core/lookup.js.map +1 -0
  27. package/dist/core/open.d.ts +12 -0
  28. package/dist/core/open.d.ts.map +1 -0
  29. package/dist/core/open.js +23 -0
  30. package/dist/core/open.js.map +1 -0
  31. package/dist/core/position.d.ts +121 -0
  32. package/dist/core/position.d.ts.map +1 -0
  33. package/dist/core/position.js +327 -0
  34. package/dist/core/position.js.map +1 -0
  35. package/dist/core/reading-text.d.ts +77 -0
  36. package/dist/core/reading-text.d.ts.map +1 -0
  37. package/dist/core/reading-text.js +144 -0
  38. package/dist/core/reading-text.js.map +1 -0
  39. package/dist/core/source.d.ts +17 -0
  40. package/dist/core/source.d.ts.map +1 -0
  41. package/dist/core/source.js +39 -0
  42. package/dist/core/source.js.map +1 -0
  43. package/dist/core/storage.d.ts +7 -0
  44. package/dist/core/storage.d.ts.map +1 -0
  45. package/dist/core/storage.js +2 -0
  46. package/dist/core/storage.js.map +1 -0
  47. package/dist/core/text.d.ts +18 -0
  48. package/dist/core/text.d.ts.map +1 -0
  49. package/dist/core/text.js +32 -0
  50. package/dist/core/text.js.map +1 -0
  51. package/dist/formats/epub/href.d.ts +14 -0
  52. package/dist/formats/epub/href.d.ts.map +1 -0
  53. package/dist/formats/epub/href.js +52 -0
  54. package/dist/formats/epub/href.js.map +1 -0
  55. package/dist/formats/epub/index.d.ts +3 -0
  56. package/dist/formats/epub/index.d.ts.map +1 -0
  57. package/dist/formats/epub/index.js +223 -0
  58. package/dist/formats/epub/index.js.map +1 -0
  59. package/dist/formats/epub/opf.d.ts +27 -0
  60. package/dist/formats/epub/opf.d.ts.map +1 -0
  61. package/dist/formats/epub/opf.js +110 -0
  62. package/dist/formats/epub/opf.js.map +1 -0
  63. package/dist/formats/epub/toc.d.ts +6 -0
  64. package/dist/formats/epub/toc.d.ts.map +1 -0
  65. package/dist/formats/epub/toc.js +88 -0
  66. package/dist/formats/epub/toc.js.map +1 -0
  67. package/dist/formats/fb2/index.d.ts +13 -0
  68. package/dist/formats/fb2/index.d.ts.map +1 -0
  69. package/dist/formats/fb2/index.js +317 -0
  70. package/dist/formats/fb2/index.js.map +1 -0
  71. package/dist/formats/index.d.ts +4 -0
  72. package/dist/formats/index.d.ts.map +1 -0
  73. package/dist/formats/index.js +4 -0
  74. package/dist/formats/index.js.map +1 -0
  75. package/dist/formats/text/index.d.ts +11 -0
  76. package/dist/formats/text/index.d.ts.map +1 -0
  77. package/dist/formats/text/index.js +201 -0
  78. package/dist/formats/text/index.js.map +1 -0
  79. package/dist/formats/xml.d.ts +33 -0
  80. package/dist/formats/xml.d.ts.map +1 -0
  81. package/dist/formats/xml.js +321 -0
  82. package/dist/formats/xml.js.map +1 -0
  83. package/dist/index.d.ts +27 -0
  84. package/dist/index.d.ts.map +1 -0
  85. package/dist/index.js +28 -0
  86. package/dist/index.js.map +1 -0
  87. package/dist/layout/chunk.d.ts +51 -0
  88. package/dist/layout/chunk.d.ts.map +1 -0
  89. package/dist/layout/chunk.js +131 -0
  90. package/dist/layout/chunk.js.map +1 -0
  91. package/dist/layout/index.d.ts +238 -0
  92. package/dist/layout/index.d.ts.map +1 -0
  93. package/dist/layout/index.js +476 -0
  94. package/dist/layout/index.js.map +1 -0
  95. package/dist/reader/index.d.ts +231 -0
  96. package/dist/reader/index.d.ts.map +1 -0
  97. package/dist/reader/index.js +958 -0
  98. package/dist/reader/index.js.map +1 -0
  99. package/dist/reader/input.d.ts +69 -0
  100. package/dist/reader/input.d.ts.map +1 -0
  101. package/dist/reader/input.js +75 -0
  102. package/dist/reader/input.js.map +1 -0
  103. package/dist/search/extract.d.ts +51 -0
  104. package/dist/search/extract.d.ts.map +1 -0
  105. package/dist/search/extract.js +401 -0
  106. package/dist/search/extract.js.map +1 -0
  107. package/dist/search/index.d.ts +11 -0
  108. package/dist/search/index.d.ts.map +1 -0
  109. package/dist/search/index.js +11 -0
  110. package/dist/search/index.js.map +1 -0
  111. package/dist/search/matcher.d.ts +56 -0
  112. package/dist/search/matcher.d.ts.map +1 -0
  113. package/dist/search/matcher.js +128 -0
  114. package/dist/search/matcher.js.map +1 -0
  115. package/dist/search/normalize.d.ts +48 -0
  116. package/dist/search/normalize.d.ts.map +1 -0
  117. package/dist/search/normalize.js +103 -0
  118. package/dist/search/normalize.js.map +1 -0
  119. package/dist/view/allowlist.d.ts +59 -0
  120. package/dist/view/allowlist.d.ts.map +1 -0
  121. package/dist/view/allowlist.js +198 -0
  122. package/dist/view/allowlist.js.map +1 -0
  123. package/dist/view/appearance.d.ts +137 -0
  124. package/dist/view/appearance.d.ts.map +1 -0
  125. package/dist/view/appearance.js +274 -0
  126. package/dist/view/appearance.js.map +1 -0
  127. package/dist/view/css.d.ts +24 -0
  128. package/dist/view/css.d.ts.map +1 -0
  129. package/dist/view/css.js +153 -0
  130. package/dist/view/css.js.map +1 -0
  131. package/dist/view/frame.d.ts +54 -0
  132. package/dist/view/frame.d.ts.map +1 -0
  133. package/dist/view/frame.js +980 -0
  134. package/dist/view/frame.js.map +1 -0
  135. package/dist/view/host.d.ts +160 -0
  136. package/dist/view/host.d.ts.map +1 -0
  137. package/dist/view/host.js +385 -0
  138. package/dist/view/host.js.map +1 -0
  139. package/dist/view/index.d.ts +12 -0
  140. package/dist/view/index.d.ts.map +1 -0
  141. package/dist/view/index.js +7 -0
  142. package/dist/view/index.js.map +1 -0
  143. package/dist/view/protocol.d.ts +220 -0
  144. package/dist/view/protocol.d.ts.map +1 -0
  145. package/dist/view/protocol.js +246 -0
  146. package/dist/view/protocol.js.map +1 -0
  147. package/dist/view/reference.d.ts +18 -0
  148. package/dist/view/reference.d.ts.map +1 -0
  149. package/dist/view/reference.js +25 -0
  150. package/dist/view/reference.js.map +1 -0
  151. package/dist/view/resources.d.ts +51 -0
  152. package/dist/view/resources.d.ts.map +1 -0
  153. package/dist/view/resources.js +242 -0
  154. package/dist/view/resources.js.map +1 -0
  155. package/dist/view/sanitize.d.ts +32 -0
  156. package/dist/view/sanitize.d.ts.map +1 -0
  157. package/dist/view/sanitize.js +226 -0
  158. package/dist/view/sanitize.js.map +1 -0
  159. package/dist/zip/central.d.ts +12 -0
  160. package/dist/zip/central.d.ts.map +1 -0
  161. package/dist/zip/central.js +72 -0
  162. package/dist/zip/central.js.map +1 -0
  163. package/dist/zip/crc32.d.ts +3 -0
  164. package/dist/zip/crc32.d.ts.map +1 -0
  165. package/dist/zip/crc32.js +28 -0
  166. package/dist/zip/crc32.js.map +1 -0
  167. package/dist/zip/eocd.d.ts +9 -0
  168. package/dist/zip/eocd.d.ts.map +1 -0
  169. package/dist/zip/eocd.js +84 -0
  170. package/dist/zip/eocd.js.map +1 -0
  171. package/dist/zip/errors.d.ts +19 -0
  172. package/dist/zip/errors.d.ts.map +1 -0
  173. package/dist/zip/errors.js +37 -0
  174. package/dist/zip/errors.js.map +1 -0
  175. package/dist/zip/index.d.ts +18 -0
  176. package/dist/zip/index.d.ts.map +1 -0
  177. package/dist/zip/index.js +78 -0
  178. package/dist/zip/index.js.map +1 -0
  179. package/dist/zip/inflate.d.ts +2 -0
  180. package/dist/zip/inflate.d.ts.map +1 -0
  181. package/dist/zip/inflate.js +43 -0
  182. package/dist/zip/inflate.js.map +1 -0
  183. package/dist/zip/source.d.ts +15 -0
  184. package/dist/zip/source.d.ts.map +1 -0
  185. package/dist/zip/source.js +34 -0
  186. package/dist/zip/source.js.map +1 -0
  187. package/package.json +75 -0
  188. package/src/core/book.ts +80 -0
  189. package/src/core/errors.ts +31 -0
  190. package/src/core/format.ts +14 -0
  191. package/src/core/graphemes.ts +73 -0
  192. package/src/core/index.ts +27 -0
  193. package/src/core/lookup.ts +16 -0
  194. package/src/core/open.ts +31 -0
  195. package/src/core/position.ts +485 -0
  196. package/src/core/reading-text.ts +200 -0
  197. package/src/core/source.ts +61 -0
  198. package/src/core/storage.ts +6 -0
  199. package/src/core/text.ts +35 -0
  200. package/src/formats/epub/href.ts +54 -0
  201. package/src/formats/epub/index.ts +235 -0
  202. package/src/formats/epub/opf.ts +143 -0
  203. package/src/formats/epub/toc.ts +120 -0
  204. package/src/formats/fb2/index.ts +348 -0
  205. package/src/formats/index.ts +3 -0
  206. package/src/formats/text/index.ts +208 -0
  207. package/src/formats/xml.ts +326 -0
  208. package/src/index.ts +26 -0
  209. package/src/layout/chunk.ts +169 -0
  210. package/src/layout/index.ts +573 -0
  211. package/src/reader/index.ts +1206 -0
  212. package/src/reader/input.ts +122 -0
  213. package/src/search/extract.ts +403 -0
  214. package/src/search/index.ts +10 -0
  215. package/src/search/matcher.ts +187 -0
  216. package/src/search/normalize.ts +122 -0
  217. package/src/view/allowlist.ts +273 -0
  218. package/src/view/appearance.ts +380 -0
  219. package/src/view/css.ts +172 -0
  220. package/src/view/frame.ts +1018 -0
  221. package/src/view/host.ts +527 -0
  222. package/src/view/index.ts +24 -0
  223. package/src/view/protocol.ts +412 -0
  224. package/src/view/reference.ts +30 -0
  225. package/src/view/resources.ts +265 -0
  226. package/src/view/sanitize.ts +266 -0
  227. package/src/zip/central.ts +85 -0
  228. package/src/zip/crc32.ts +30 -0
  229. package/src/zip/eocd.ts +97 -0
  230. package/src/zip/errors.ts +41 -0
  231. package/src/zip/index.ts +114 -0
  232. package/src/zip/inflate.ts +41 -0
  233. package/src/zip/source.ts +51 -0
@@ -0,0 +1,144 @@
1
+ /**
2
+ * The canonical "reading text" policy — the single definition of which parts of a
3
+ * section's markup become the text a reader actually sees in the frame.
4
+ *
5
+ * Two independent consumers must agree on it, and this module is how they stay one
6
+ * model rather than two:
7
+ *
8
+ * - `src/view` sanitizes and applies resources before rendering: discarded elements
9
+ * vanish with their children (`sanitize.ts`), and an `<img>` that cannot be served
10
+ * is replaced by its `alt` text (`resources.ts`). The frame's measured section
11
+ * text — what a `Position` resolves against — is the `textContent` of that output.
12
+ * - `src/search` captures hit anchors headlessly, without a DOM, over the same text.
13
+ * Its extractor (`src/search/extract.ts`) mirrors the pipeline using the tables
14
+ * and predicates here, so a captured quote/context window exists verbatim in the
15
+ * text the frame resolves against.
16
+ *
17
+ * Internal to the library: nothing here is re-exported from `src/core/index.ts`
18
+ * (same status as `graphemes.ts`), so it is shared implementation, not public
19
+ * surface. It is headless by rule — string tables and string predicates only —
20
+ * because `src/search` may import only `src/core` and platform primitives.
21
+ */
22
+ function set(...names) {
23
+ return new Set(names);
24
+ }
25
+ /**
26
+ * HTML elements the sanitizer removes with everything inside them, because their
27
+ * children are not prose: raw-text elements whose content is source rather than
28
+ * text, form controls, and void elements with no children to keep. Everything
29
+ * else absent from the allowlist is unwrapped instead — the element goes, its
30
+ * text stays. The unwrap-vs-discard rationale lives with the allowlist
31
+ * (`src/view/allowlist.ts`), which re-exports these under their frozen names.
32
+ */
33
+ export const DISCARDED_HTML_ELEMENTS = set('area', 'base', 'button', 'embed', 'frame', 'frameset', 'iframe', 'input', 'keygen', 'listing', 'meta', 'noembed', 'noframes', 'option', 'optgroup', 'param', 'plaintext', 'script', 'select', 'source', 'template', 'textarea', 'title', 'track', 'xmp');
34
+ /**
35
+ * SVG elements discarded whole. SMIL animation is on this list, not merely absent
36
+ * from the allowlist, because `<animate attributeName="href" to="javascript:...">`
37
+ * turns an inert element into a live one after sanitization has already run.
38
+ */
39
+ export const DISCARDED_SVG_ELEMENTS = set('animate', 'animateMotion', 'animateTransform', 'audio', 'canvas', 'discard', 'foreignObject', 'handler', 'iframe', 'listener', 'script', 'set', 'video');
40
+ const SCHEME = /^([a-zA-Z][a-zA-Z0-9+.-]*):/;
41
+ const SPACE = 0x20;
42
+ const TAB = 0x09;
43
+ const NEWLINE = 0x0a;
44
+ const RETURN = 0x0d;
45
+ // The URL parser trims leading and trailing C0 controls and spaces, then drops
46
+ // tab, LF and CR from anywhere in the string. Doing the same here is what makes
47
+ // a reference written as `java&#10;script:alert(1)` classify as a scheme.
48
+ function stripUrlWhitespace(raw) {
49
+ let start = 0;
50
+ let end = raw.length;
51
+ while (start < end && raw.charCodeAt(start) <= SPACE)
52
+ start += 1;
53
+ while (end > start && raw.charCodeAt(end - 1) <= SPACE)
54
+ end -= 1;
55
+ let value = '';
56
+ for (let i = start; i < end; i += 1) {
57
+ const code = raw.charCodeAt(i);
58
+ if (code === TAB || code === NEWLINE || code === RETURN)
59
+ continue;
60
+ value += raw.charAt(i);
61
+ }
62
+ return value;
63
+ }
64
+ export function classifyReference(raw) {
65
+ const value = stripUrlWhitespace(raw);
66
+ if (value === '')
67
+ return { kind: 'empty', value };
68
+ if (value.startsWith('#'))
69
+ return { kind: 'fragment', value };
70
+ const match = SCHEME.exec(value);
71
+ if (match !== null)
72
+ return { kind: 'scheme', value, scheme: (match[1] ?? '').toLowerCase() };
73
+ return { kind: 'relative', value };
74
+ }
75
+ /** Collapses `.` and `..` segments, keeping leading `..` that cannot be resolved. */
76
+ export function normalizeReference(reference) {
77
+ const out = [];
78
+ for (const segment of reference.split('/')) {
79
+ if (segment === '' || segment === '.')
80
+ continue;
81
+ if (segment !== '..') {
82
+ out.push(segment);
83
+ continue;
84
+ }
85
+ const last = out[out.length - 1];
86
+ if (last === undefined || last === '..')
87
+ out.push('..');
88
+ else
89
+ out.pop();
90
+ }
91
+ return (reference.startsWith('/') ? '/' : '') + out.join('/');
92
+ }
93
+ const FONT_TYPES = new Set([
94
+ 'application/font-woff',
95
+ 'application/font-woff2',
96
+ 'application/vnd.ms-fontobject',
97
+ 'application/vnd.ms-opentype',
98
+ 'application/x-font-opentype',
99
+ 'application/x-font-otf',
100
+ 'application/x-font-truetype',
101
+ 'application/x-font-ttf',
102
+ 'application/x-font-woff',
103
+ ]);
104
+ /** The bare media type: parameters trimmed, lowercased. */
105
+ export function baseMediaType(mediaType) {
106
+ return (mediaType.split(';')[0] ?? '').trim().toLowerCase();
107
+ }
108
+ /**
109
+ * Only these media types are minted a `data:` URL by the resource layer. A
110
+ * reference resolving is not evidence it should be served: the seam answers for
111
+ * the whole manifest, so a `text/javascript` entry resolves as readily as an
112
+ * image — and a URL is a capability, not a convenience.
113
+ */
114
+ export function isServableResource(mediaType) {
115
+ const type = baseMediaType(mediaType);
116
+ return type.startsWith('image/') || type.startsWith('font/') || FONT_TYPES.has(type);
117
+ }
118
+ /**
119
+ * The text an `<img>` contributes to the reading text: `''` when the element
120
+ * survives as an image (a served resource, or a remote/`data:` reference left for
121
+ * the CSP to refuse), or its `alt` when the resource layer substitutes the alt
122
+ * text for an image it cannot serve (`applyResources` in `src/view/resources.ts`
123
+ * — Gutenberg drop caps are the motivating case). An empty/absent `alt` on an
124
+ * unservable image means decorative: the element is removed and contributes
125
+ * nothing, which `''` also expresses.
126
+ *
127
+ * This is the headless mirror of the frame-side decision; the one edge it cannot
128
+ * see is a resource whose bytes fail to *load* after resolving servable — the
129
+ * frame substitutes alt there too, and a search anchor over that rare case
130
+ * degrades to the ordinary soft miss. Change this and the `applyResources` image
131
+ * branch together.
132
+ */
133
+ export function imageReadingText(src, alt, resolve) {
134
+ const classified = src === null ? undefined : classifyReference(src);
135
+ if (classified !== undefined && classified.kind !== 'relative')
136
+ return '';
137
+ if (classified !== undefined) {
138
+ const resource = resolve?.(normalizeReference(classified.value));
139
+ if (resource !== undefined && isServableResource(resource.mediaType))
140
+ return '';
141
+ }
142
+ return alt ?? '';
143
+ }
144
+ //# sourceMappingURL=reading-text.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reading-text.js","sourceRoot":"","sources":["../../src/core/reading-text.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ /** Reads `length` bytes starting at `offset`; may return fewer at end of data. */
2
+ export type RangeRead = (offset: number, length: number) => Promise<Uint8Array>;
3
+ /** Streaming input form: total size plus a host-implemented range-read callback. */
4
+ export interface RangeReader {
5
+ readonly size: number;
6
+ readonly read: RangeRead;
7
+ }
8
+ export type BookInput = ArrayBuffer | Blob | RangeReader;
9
+ /** Normalized byte access that every sniffer and decoder consumes. */
10
+ export interface ByteSource {
11
+ readonly size: number;
12
+ read(offset: number, length: number): Promise<Uint8Array>;
13
+ /** The whole input as one buffer, fetched once and cached. */
14
+ bytes(): Promise<Uint8Array>;
15
+ }
16
+ export declare function toByteSource(input: BookInput): ByteSource;
17
+ //# sourceMappingURL=source.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"source.d.ts","sourceRoot":"","sources":["../../src/core/source.ts"],"names":[],"mappings":"AAAA,kFAAkF;AAClF,MAAM,MAAM,SAAS,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,UAAU,CAAC,CAAC;AAEhF,oFAAoF;AACpF,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;CAC1B;AAED,MAAM,MAAM,SAAS,GAAG,WAAW,GAAG,IAAI,GAAG,WAAW,CAAC;AAEzD,sEAAsE;AACtE,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IAC1D,8DAA8D;IAC9D,KAAK,IAAI,OAAO,CAAC,UAAU,CAAC,CAAC;CAC9B;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,SAAS,GAAG,UAAU,CAKzD"}
@@ -0,0 +1,39 @@
1
+ export function toByteSource(input) {
2
+ if (input instanceof ArrayBuffer)
3
+ return fromBytes(new Uint8Array(input));
4
+ if (input instanceof Blob)
5
+ return fromBlob(input);
6
+ if (isRangeReader(input))
7
+ return fromRangeReader(input);
8
+ throw new TypeError('input must be an ArrayBuffer, Blob, File, or RangeReader');
9
+ }
10
+ function isRangeReader(value) {
11
+ return (typeof value === 'object' &&
12
+ value !== null &&
13
+ typeof value.read === 'function' &&
14
+ typeof value.size === 'number');
15
+ }
16
+ function fromBytes(bytes) {
17
+ return {
18
+ size: bytes.byteLength,
19
+ read: (offset, length) => Promise.resolve(bytes.subarray(offset, offset + length)),
20
+ bytes: () => Promise.resolve(bytes),
21
+ };
22
+ }
23
+ function fromBlob(blob) {
24
+ let all;
25
+ return {
26
+ size: blob.size,
27
+ read: async (offset, length) => new Uint8Array(await blob.slice(offset, offset + length).arrayBuffer()),
28
+ bytes: () => (all ??= blob.arrayBuffer().then((buffer) => new Uint8Array(buffer))),
29
+ };
30
+ }
31
+ function fromRangeReader(reader) {
32
+ let all;
33
+ return {
34
+ size: reader.size,
35
+ read: (offset, length) => reader.read(offset, length),
36
+ bytes: () => (all ??= reader.read(0, reader.size)),
37
+ };
38
+ }
39
+ //# sourceMappingURL=source.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"source.js","sourceRoot":"","sources":["../../src/core/source.ts"],"names":[],"mappings":"AAmBA,MAAM,UAAU,YAAY,CAAC,KAAgB;IAC3C,IAAI,KAAK,YAAY,WAAW;QAAE,OAAO,SAAS,CAAC,IAAI,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC;IAC1E,IAAI,KAAK,YAAY,IAAI;QAAE,OAAO,QAAQ,CAAC,KAAK,CAAC,CAAC;IAClD,IAAI,aAAa,CAAC,KAAK,CAAC;QAAE,OAAO,eAAe,CAAC,KAAK,CAAC,CAAC;IACxD,MAAM,IAAI,SAAS,CAAC,0DAA0D,CAAC,CAAC;AAClF,CAAC;AAED,SAAS,aAAa,CAAC,KAAc;IACnC,OAAO,CACL,OAAO,KAAK,KAAK,QAAQ;QACzB,KAAK,KAAK,IAAI;QACd,OAAQ,KAAqB,CAAC,IAAI,KAAK,UAAU;QACjD,OAAQ,KAAqB,CAAC,IAAI,KAAK,QAAQ,CAChD,CAAC;AACJ,CAAC;AAED,SAAS,SAAS,CAAC,KAAiB;IAClC,OAAO;QACL,IAAI,EAAE,KAAK,CAAC,UAAU;QACtB,IAAI,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC;QAClF,KAAK,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC;KACpC,CAAC;AACJ,CAAC;AAED,SAAS,QAAQ,CAAC,IAAU;IAC1B,IAAI,GAAoC,CAAC;IACzC,OAAO;QACL,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE,CAC7B,IAAI,UAAU,CAAC,MAAM,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,CAAC,WAAW,EAAE,CAAC;QACzE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,KAAK,IAAI,CAAC,WAAW,EAAE,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,IAAI,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC;KACnF,CAAC;AACJ,CAAC;AAED,SAAS,eAAe,CAAC,MAAmB;IAC1C,IAAI,GAAoC,CAAC;IACzC,OAAO;QACL,IAAI,EAAE,MAAM,CAAC,IAAI;QACjB,IAAI,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC;QACrD,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC;KACnD,CAAC;AACJ,CAAC"}
@@ -0,0 +1,7 @@
1
+ /** Host-implemented cache. The library only ever calls it; it never fetches and never persists on its own. */
2
+ export interface StorageAdapter {
3
+ get(key: string): Promise<Uint8Array | undefined>;
4
+ set(key: string, value: Uint8Array): Promise<void>;
5
+ delete(key: string): Promise<void>;
6
+ }
7
+ //# sourceMappingURL=storage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../src/core/storage.ts"],"names":[],"mappings":"AAAA,8GAA8G;AAC9G,MAAM,WAAW,cAAc;IAC7B,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC,CAAC;IAClD,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnD,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACpC"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=storage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage.js","sourceRoot":"","sources":["../../src/core/storage.ts"],"names":[],"mappings":""}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Shared text helpers, internal to the library: nothing here is re-exported from
3
+ * `src/core/index.ts` (same status as `graphemes.ts` and `reading-text.ts`), so
4
+ * this is shared implementation, not public surface. It lives in core because its
5
+ * consumers span domains that may not import each other — `src/formats` and
6
+ * `src/layout` escape markup, `src/search` and `src/view` decode section bytes —
7
+ * and everything may import core while core imports nothing back (the headless
8
+ * boundary `npm run check:core` enforces).
9
+ */
10
+ /** Decodes text bytes, honouring the byte order marks EPUB allows. */
11
+ export declare function decodeText(bytes: Uint8Array): string;
12
+ /** Collapses every whitespace run to one space and trims the ends. */
13
+ export declare function collapseWhitespace(s: string): string;
14
+ /** Escapes the markup-significant characters (`& < >`) for text content. */
15
+ export declare function escapeXmlText(s: string): string;
16
+ /** Escapes for a double-quoted attribute value: the text escape plus `"`. */
17
+ export declare function escapeXmlAttribute(s: string): string;
18
+ //# sourceMappingURL=text.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"text.d.ts","sourceRoot":"","sources":["../../src/core/text.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,sEAAsE;AACtE,wBAAgB,UAAU,CAAC,KAAK,EAAE,UAAU,GAAG,MAAM,CAQpD;AAED,sEAAsE;AACtE,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED,4EAA4E;AAC5E,wBAAgB,aAAa,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAE/C;AAED,6EAA6E;AAC7E,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAEpD"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Shared text helpers, internal to the library: nothing here is re-exported from
3
+ * `src/core/index.ts` (same status as `graphemes.ts` and `reading-text.ts`), so
4
+ * this is shared implementation, not public surface. It lives in core because its
5
+ * consumers span domains that may not import each other — `src/formats` and
6
+ * `src/layout` escape markup, `src/search` and `src/view` decode section bytes —
7
+ * and everything may import core while core imports nothing back (the headless
8
+ * boundary `npm run check:core` enforces).
9
+ */
10
+ /** Decodes text bytes, honouring the byte order marks EPUB allows. */
11
+ export function decodeText(bytes) {
12
+ if (bytes[0] === 0xff && bytes[1] === 0xfe) {
13
+ return new TextDecoder('utf-16le').decode(bytes.subarray(2));
14
+ }
15
+ if (bytes[0] === 0xfe && bytes[1] === 0xff) {
16
+ return new TextDecoder('utf-16be').decode(bytes.subarray(2));
17
+ }
18
+ return new TextDecoder().decode(bytes);
19
+ }
20
+ /** Collapses every whitespace run to one space and trims the ends. */
21
+ export function collapseWhitespace(s) {
22
+ return s.replace(/\s+/g, ' ').trim();
23
+ }
24
+ /** Escapes the markup-significant characters (`& < >`) for text content. */
25
+ export function escapeXmlText(s) {
26
+ return s.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
27
+ }
28
+ /** Escapes for a double-quoted attribute value: the text escape plus `"`. */
29
+ export function escapeXmlAttribute(s) {
30
+ return escapeXmlText(s).replace(/"/g, '&quot;');
31
+ }
32
+ //# sourceMappingURL=text.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"text.js","sourceRoot":"","sources":["../../src/core/text.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,sEAAsE;AACtE,MAAM,UAAU,UAAU,CAAC,KAAiB;IAC1C,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QAC3C,OAAO,IAAI,WAAW,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/D,CAAC;IACD,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QAC3C,OAAO,IAAI,WAAW,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/D,CAAC;IACD,OAAO,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACzC,CAAC;AAED,sEAAsE;AACtE,MAAM,UAAU,kBAAkB,CAAC,CAAS;IAC1C,OAAO,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;AACvC,CAAC;AAED,4EAA4E;AAC5E,MAAM,UAAU,aAAa,CAAC,CAAS;IACrC,OAAO,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;AAC9E,CAAC;AAED,6EAA6E;AAC7E,MAAM,UAAU,kBAAkB,CAAC,CAAS;IAC1C,OAAO,aAAa,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;AAClD,CAAC"}
@@ -0,0 +1,14 @@
1
+ export interface HrefTarget {
2
+ /** Normalized zip entry name. */
3
+ readonly path: string;
4
+ readonly fragment?: string;
5
+ }
6
+ /** Directory of a zip entry name: 'OEBPS/content.opf' → 'OEBPS/', 'content.opf' → ''. */
7
+ export declare function directoryOf(path: string): string;
8
+ /**
9
+ * Resolves a package-document href against a base directory into a zip entry
10
+ * name plus optional fragment. Returns undefined for non-relative references
11
+ * (absolute URLs, scheme-carrying links) that cannot name a zip entry.
12
+ */
13
+ export declare function resolveHref(baseDir: string, href: string): HrefTarget | undefined;
14
+ //# sourceMappingURL=href.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"href.d.ts","sourceRoot":"","sources":["../../../src/formats/epub/href.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,UAAU;IACzB,iCAAiC;IACjC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,yFAAyF;AACzF,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAGhD;AAED;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS,CA2BjF"}
@@ -0,0 +1,52 @@
1
+ /** Directory of a zip entry name: 'OEBPS/content.opf' → 'OEBPS/', 'content.opf' → ''. */
2
+ export function directoryOf(path) {
3
+ const slash = path.lastIndexOf('/');
4
+ return slash === -1 ? '' : path.slice(0, slash + 1);
5
+ }
6
+ /**
7
+ * Resolves a package-document href against a base directory into a zip entry
8
+ * name plus optional fragment. Returns undefined for non-relative references
9
+ * (absolute URLs, scheme-carrying links) that cannot name a zip entry.
10
+ */
11
+ export function resolveHref(baseDir, href) {
12
+ const hash = href.indexOf('#');
13
+ const fragment = hash === -1 ? undefined : decodeSegment(href.slice(hash + 1));
14
+ let reference = hash === -1 ? href : href.slice(0, hash);
15
+ if (/^[a-zA-Z][a-zA-Z0-9+.-]*:/.test(reference))
16
+ return undefined;
17
+ if (reference === '') {
18
+ // A pure fragment link targets the referencing document; the caller
19
+ // supplies that context, so there is no path to resolve here.
20
+ return undefined;
21
+ }
22
+ if (reference.startsWith('/')) {
23
+ baseDir = '';
24
+ reference = reference.slice(1);
25
+ }
26
+ const segments = [];
27
+ for (const raw of (baseDir + reference).split('/')) {
28
+ const segment = decodeSegment(raw);
29
+ if (segment === '' || segment === '.')
30
+ continue;
31
+ if (segment === '..') {
32
+ segments.pop();
33
+ continue;
34
+ }
35
+ segments.push(segment);
36
+ }
37
+ if (segments.length === 0)
38
+ return undefined;
39
+ const path = segments.join('/');
40
+ return { path, ...(fragment === undefined ? {} : { fragment }) };
41
+ }
42
+ function decodeSegment(segment) {
43
+ if (!segment.includes('%'))
44
+ return segment;
45
+ try {
46
+ return decodeURIComponent(segment);
47
+ }
48
+ catch {
49
+ return segment;
50
+ }
51
+ }
52
+ //# sourceMappingURL=href.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"href.js","sourceRoot":"","sources":["../../../src/formats/epub/href.ts"],"names":[],"mappings":"AAMA,yFAAyF;AACzF,MAAM,UAAU,WAAW,CAAC,IAAY;IACtC,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;IACpC,OAAO,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,GAAG,CAAC,CAAC,CAAC;AACtD,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,WAAW,CAAC,OAAe,EAAE,IAAY;IACvD,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IAC/B,MAAM,QAAQ,GAAG,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,CAAC;IAC/E,IAAI,SAAS,GAAG,IAAI,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;IACzD,IAAI,2BAA2B,CAAC,IAAI,CAAC,SAAS,CAAC;QAAE,OAAO,SAAS,CAAC;IAClE,IAAI,SAAS,KAAK,EAAE,EAAE,CAAC;QACrB,oEAAoE;QACpE,8DAA8D;QAC9D,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,IAAI,SAAS,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QAC9B,OAAO,GAAG,EAAE,CAAC;QACb,SAAS,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACjC,CAAC;IACD,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,KAAK,MAAM,GAAG,IAAI,CAAC,OAAO,GAAG,SAAS,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAC;QACnD,MAAM,OAAO,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC;QACnC,IAAI,OAAO,KAAK,EAAE,IAAI,OAAO,KAAK,GAAG;YAAE,SAAS;QAChD,IAAI,OAAO,KAAK,IAAI,EAAE,CAAC;YACrB,QAAQ,CAAC,GAAG,EAAE,CAAC;YACf,SAAS;QACX,CAAC;QACD,QAAQ,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACzB,CAAC;IACD,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,SAAS,CAAC;IAC5C,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAChC,OAAO,EAAE,IAAI,EAAE,GAAG,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,CAAC;AACnE,CAAC;AAED,SAAS,aAAa,CAAC,OAAe;IACpC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC;QAAE,OAAO,OAAO,CAAC;IAC3C,IAAI,CAAC;QACH,OAAO,kBAAkB,CAAC,OAAO,CAAC,CAAC;IACrC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,OAAO,CAAC;IACjB,CAAC;AACH,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { BookFormat } from '../../core/index.ts';
2
+ export declare const epub: BookFormat;
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/formats/epub/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,UAAU,EAMX,MAAM,qBAAqB,CAAC;AAY7B,eAAO,MAAM,IAAI,EAAE,UAqClB,CAAC"}
@@ -0,0 +1,223 @@
1
+ /*! wolfy-reader v0.1.0 | @license MIT | (c) Vitaliy Tkachuk | github.com/vitaliy-tkachuk/wolfy-reader */
2
+ import { CorruptContainerError, EncryptedContentError } from '../../core/index.js';
3
+ import { sectionLookup } from '../../core/lookup.js';
4
+ import { openZip, ZipEncryptedEntryError, ZipError } from '../../zip/index.js';
5
+ import { directoryOf, resolveHref } from './href.js';
6
+ import { opfPathFromContainer, parseOpf } from './opf.js';
7
+ import { parseNavToc, parseNcxToc } from './toc.js';
8
+ import { decodeXml } from '../xml.js';
9
+ const EPUB_MIMETYPE = 'application/epub+zip';
10
+ const CONTAINER_PATH = 'META-INF/container.xml';
11
+ export const epub = {
12
+ name: 'epub',
13
+ async sniff(source) {
14
+ if (!(await hasZipSignature(source)))
15
+ return false;
16
+ try {
17
+ const zip = await openZip(asZipSource(source));
18
+ if (zip.entry('mimetype') === undefined)
19
+ return false;
20
+ const mimetype = new TextDecoder().decode(await zip.read('mimetype'));
21
+ // The OCF spec forbids padding, but a trailing newline is a common
22
+ // real-world authoring deviation; tolerate trailing whitespace only.
23
+ return mimetype.trimEnd() === EPUB_MIMETYPE;
24
+ }
25
+ catch {
26
+ return false;
27
+ }
28
+ },
29
+ async decode(source) {
30
+ const zip = await openContainer(source);
31
+ const containerXml = decodeXml(await readEntry(zip, CONTAINER_PATH));
32
+ let opfPath;
33
+ try {
34
+ opfPath = opfPathFromContainer(containerXml);
35
+ }
36
+ catch (error) {
37
+ throw new CorruptContainerError(`${CONTAINER_PATH} is not a valid OCF container document`, {
38
+ cause: error,
39
+ });
40
+ }
41
+ const opfXml = decodeXml(await readEntry(zip, opfPath));
42
+ let pkg;
43
+ try {
44
+ pkg = parseOpf(opfXml, opfPath);
45
+ }
46
+ catch (error) {
47
+ throw new CorruptContainerError(`${opfPath} is not a valid OPF package document`, {
48
+ cause: error,
49
+ });
50
+ }
51
+ return buildBook(zip, pkg);
52
+ },
53
+ };
54
+ async function hasZipSignature(source) {
55
+ const head = await source.read(0, 4);
56
+ return head[0] === 0x50 && head[1] === 0x4b && head[2] === 0x03 && head[3] === 0x04;
57
+ }
58
+ function asZipSource(source) {
59
+ return { size: source.size, read: (offset, length) => source.read(offset, length) };
60
+ }
61
+ async function openContainer(source) {
62
+ try {
63
+ return await openZip(asZipSource(source));
64
+ }
65
+ catch (error) {
66
+ throw bridged(error, 'the EPUB zip container');
67
+ }
68
+ }
69
+ async function readEntry(zip, name) {
70
+ try {
71
+ return await zip.read(name);
72
+ }
73
+ catch (error) {
74
+ throw bridged(error, name);
75
+ }
76
+ }
77
+ function bridged(error, what) {
78
+ if (error instanceof ZipEncryptedEntryError) {
79
+ return new EncryptedContentError(`${what} is encrypted`, { cause: error });
80
+ }
81
+ if (error instanceof ZipError) {
82
+ return new CorruptContainerError(`cannot read ${what}`, { cause: error });
83
+ }
84
+ return error;
85
+ }
86
+ const SPINE_MEDIA_TYPES = new Set(['application/xhtml+xml', 'image/svg+xml', 'text/html']);
87
+ const NCX_MEDIA_TYPE = 'application/x-dtbncx+xml';
88
+ async function buildBook(zip, pkg) {
89
+ const baseDir = directoryOf(pkg.path);
90
+ const entryPath = (item) => resolveHref(baseDir, item.href)?.path ?? item.href;
91
+ // Content references resolve against the document that carries them, and the
92
+ // manifest is the only statement of a media type — so a reference is
93
+ // resolvable only when it names a manifest item that is really in the
94
+ // archive. Absent entries are rejected here rather than deferred to load(),
95
+ // because a consumer building a URL must know before it builds one.
96
+ const present = new Set(zip.entries.map((entry) => entry.name));
97
+ const resourceByPath = new Map();
98
+ for (const item of pkg.manifest) {
99
+ const path = entryPath(item);
100
+ if (!present.has(path) || resourceByPath.has(path))
101
+ continue;
102
+ resourceByPath.set(path, { mediaType: item.mediaType, load: () => readEntry(zip, path) });
103
+ }
104
+ const resolveFrom = (fromDir, reference) => {
105
+ const target = resolveHref(fromDir, reference);
106
+ return target === undefined ? undefined : resourceByPath.get(target.path);
107
+ };
108
+ const sections = [];
109
+ const sectionByPath = new Map();
110
+ const spineIds = new Set();
111
+ for (const idref of pkg.spine) {
112
+ const item = pkg.itemById.get(idref);
113
+ if (item === undefined || spineIds.has(item.id))
114
+ continue;
115
+ spineIds.add(item.id);
116
+ const content = resolveFallback(item, pkg.itemById);
117
+ const path = entryPath(content);
118
+ const scripted = item.properties.includes('scripted') || content.properties.includes('scripted');
119
+ // The section's own directory, not the OPF's: a chapter in OEBPS/text/
120
+ // reaches its images through ../images/, which the OPF's base would
121
+ // resolve one level too high.
122
+ const contentDir = directoryOf(path);
123
+ sections.push({
124
+ id: item.id,
125
+ mediaType: content.mediaType,
126
+ ...(scripted ? { scripted } : {}),
127
+ load: () => readEntry(zip, path),
128
+ resolve: (reference) => resolveFrom(contentDir, reference),
129
+ // Resolve a section-relative href to the section it names, reusing the same
130
+ // resolved-entry-name → section-id table the TOC is built from. `sectionByPath`
131
+ // is fully populated by the time any click fires, so the closure reads it live.
132
+ resolveHref: (reference) => {
133
+ const target = resolveHref(contentDir, reference);
134
+ if (target === undefined)
135
+ return undefined;
136
+ const sectionId = sectionByPath.get(target.path);
137
+ if (sectionId === undefined)
138
+ return undefined;
139
+ return target.fragment === undefined ? { sectionId } : { sectionId, fragment: target.fragment };
140
+ },
141
+ });
142
+ // TOCs point at the spine item's own href even when a fallback supplies
143
+ // the content, so both paths map to the section.
144
+ for (const target of [entryPath(item), path]) {
145
+ if (!sectionByPath.has(target))
146
+ sectionByPath.set(target, item.id);
147
+ }
148
+ }
149
+ const resources = new Map();
150
+ for (const item of pkg.manifest) {
151
+ if (spineIds.has(item.id))
152
+ continue;
153
+ const path = entryPath(item);
154
+ resources.set(item.id, {
155
+ mediaType: item.mediaType,
156
+ load: () => readEntry(zip, path),
157
+ });
158
+ }
159
+ const coverItem = pkg.coverItem;
160
+ const coverPath = coverItem === undefined ? undefined : entryPath(coverItem);
161
+ const cover = coverItem === undefined || coverPath === undefined
162
+ ? undefined
163
+ : { mediaType: coverItem.mediaType, load: () => readEntry(zip, coverPath) };
164
+ const metadata = {
165
+ ...(pkg.title === undefined ? {} : { title: pkg.title }),
166
+ ...(pkg.author === undefined ? {} : { author: pkg.author }),
167
+ ...(pkg.language === undefined ? {} : { language: pkg.language }),
168
+ ...(cover === undefined ? {} : { cover }),
169
+ };
170
+ return {
171
+ metadata,
172
+ toc: await buildToc(zip, pkg, baseDir, sectionByPath),
173
+ sections,
174
+ section: sectionLookup(sections),
175
+ resources,
176
+ ...(pkg.direction === undefined ? {} : { direction: pkg.direction }),
177
+ ...(pkg.fixedLayout === undefined ? {} : { fixedLayout: pkg.fixedLayout }),
178
+ };
179
+ }
180
+ function resolveFallback(item, itemById) {
181
+ if (SPINE_MEDIA_TYPES.has(item.mediaType))
182
+ return item;
183
+ const seen = new Set([item.id]);
184
+ let current = item;
185
+ while (current.fallback !== undefined) {
186
+ if (seen.has(current.fallback)) {
187
+ throw new CorruptContainerError(`the manifest fallback chain for item ${item.id} is circular`);
188
+ }
189
+ const next = itemById.get(current.fallback);
190
+ if (next === undefined)
191
+ break;
192
+ seen.add(next.id);
193
+ if (SPINE_MEDIA_TYPES.has(next.mediaType))
194
+ return next;
195
+ current = next;
196
+ }
197
+ return item;
198
+ }
199
+ // A broken or missing TOC degrades to [] — it never fails an otherwise
200
+ // readable book. The EPUB3 nav document wins over the EPUB2 NCX.
201
+ async function buildToc(zip, pkg, baseDir, sectionByPath) {
202
+ const navItem = pkg.manifest.find((item) => item.properties.includes('nav'));
203
+ const navPath = navItem === undefined ? undefined : resolveHref(baseDir, navItem.href)?.path;
204
+ if (navPath !== undefined) {
205
+ try {
206
+ const toc = parseNavToc(decodeXml(await readEntry(zip, navPath)), navPath, sectionByPath);
207
+ if (toc.length > 0)
208
+ return toc;
209
+ }
210
+ catch { }
211
+ }
212
+ const ncxItem = (pkg.ncxId === undefined ? undefined : pkg.itemById.get(pkg.ncxId)) ??
213
+ pkg.manifest.find((item) => item.mediaType === NCX_MEDIA_TYPE);
214
+ const ncxPath = ncxItem === undefined ? undefined : resolveHref(baseDir, ncxItem.href)?.path;
215
+ if (ncxPath !== undefined) {
216
+ try {
217
+ return parseNcxToc(decodeXml(await readEntry(zip, ncxPath)), ncxPath, sectionByPath);
218
+ }
219
+ catch { }
220
+ }
221
+ return [];
222
+ }
223
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/formats/epub/index.ts"],"names":[],"mappings":"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"}