@d-i-t-a/reader 3.0.0-alpha.14 → 3.0.0-alpha.16
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/dist/esm/index.js +4730 -947
- package/dist/esm/index.js.map +4 -4
- package/dist/reader.js +72 -69
- package/dist/reader.js.map +4 -4
- package/dist/types/fetcher/Base64DecodingFetcher.d.ts +19 -0
- package/dist/types/fetcher/BlobUrlManager.d.ts +91 -0
- package/dist/types/fetcher/CacheFetcher.d.ts +36 -0
- package/dist/types/fetcher/Container.d.ts +21 -0
- package/dist/types/fetcher/ContentFetcher.d.ts +32 -0
- package/dist/types/fetcher/EpubParser.d.ts +48 -0
- package/dist/types/fetcher/Fetcher.d.ts +111 -0
- package/dist/types/fetcher/FontDeobfuscator.d.ts +65 -0
- package/dist/types/fetcher/HttpFetcher.d.ts +29 -0
- package/dist/types/fetcher/ReadError.d.ts +35 -0
- package/dist/types/fetcher/TransformingFetcher.d.ts +38 -0
- package/dist/types/fetcher/ZipContainer.d.ts +16 -0
- package/dist/types/fetcher/ZipFetcher.d.ts +51 -0
- package/dist/types/fetcher/mediaType.d.ts +5 -0
- package/dist/types/fetcher/types.d.ts +27 -0
- package/dist/types/index.d.ts +18 -1
- package/dist/types/model/user-settings/UserSettings.d.ts +2 -1
- package/dist/types/model/v3/Publication.d.ts +4 -4
- package/dist/types/modules/ModuleHost.d.ts +3 -1
- package/dist/types/modules/ModuleRegistry.d.ts +1 -1
- package/dist/types/modules/ReaderModule.d.ts +1 -1
- package/dist/types/modules/epub/search/SearchModule.d.ts +0 -1
- package/dist/types/navigator/EpubNavigator.d.ts +44 -54
- package/dist/types/navigator/InjectableManager.d.ts +32 -0
- package/dist/types/navigator/PDFNavigator.d.ts +3 -1
- package/dist/types/navigator/VisualNavigator.d.ts +1 -1
- package/dist/types/navigator/types.d.ts +166 -0
- package/package.json +2 -1
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { Link } from "../model/v3";
|
|
2
|
+
import type { Fetcher, Resource } from "./Fetcher";
|
|
3
|
+
/**
|
|
4
|
+
* Wraps an inner Fetcher and base64-decodes document responses when
|
|
5
|
+
* needed. Composed into the chain when `RequestConfig.encoded === true`.
|
|
6
|
+
*
|
|
7
|
+
* Detects encoding by first character: document content starts with `<`;
|
|
8
|
+
* base64 doesn't. If text is already a document, pass through. Otherwise
|
|
9
|
+
* attempt atob; if atob succeeds, use the result.
|
|
10
|
+
*/
|
|
11
|
+
export declare class Base64DecodingFetcher implements Fetcher {
|
|
12
|
+
private readonly inner;
|
|
13
|
+
constructor(inner: Fetcher);
|
|
14
|
+
get(link: Link): Promise<Resource>;
|
|
15
|
+
getByHref(href: string): Promise<Resource>;
|
|
16
|
+
cancel(href: string): void;
|
|
17
|
+
destroy(): void;
|
|
18
|
+
private maybeDecode;
|
|
19
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import type { Container } from "./Container";
|
|
2
|
+
import type { Resource } from "./Fetcher";
|
|
3
|
+
import type { EncryptionInfo } from "./FontDeobfuscator";
|
|
4
|
+
import { ZipFetcher } from "./ZipFetcher";
|
|
5
|
+
/**
|
|
6
|
+
* A transform applied to resources before creating blob URLs.
|
|
7
|
+
* Same signature as ResourceTransform from TransformingFetcher.
|
|
8
|
+
*/
|
|
9
|
+
type BlobTransform = (resource: Resource) => Resource | Promise<Resource>;
|
|
10
|
+
/**
|
|
11
|
+
* Creates and manages blob URLs for resources in a Container.
|
|
12
|
+
*
|
|
13
|
+
* When opening an .epub file directly, the browser can't fetch images,
|
|
14
|
+
* CSS, fonts, and scripts from the archive because they don't exist
|
|
15
|
+
* at any HTTP URL. This manager creates blob URLs for each resource
|
|
16
|
+
* so they can be referenced in document.write() iframe content.
|
|
17
|
+
*
|
|
18
|
+
* Transforms (e.g., font deobfuscation) can be applied to resources
|
|
19
|
+
* before blob URLs are created via `addTransform()`.
|
|
20
|
+
*
|
|
21
|
+
* After parsing HTML content with DOMParser, call `rewriteDom(doc, baseDir)`
|
|
22
|
+
* to replace relative src/href attributes with blob URLs. This works at
|
|
23
|
+
* the DOM level — no regex on raw HTML.
|
|
24
|
+
*
|
|
25
|
+
* Call `destroy()` when done to revoke all blob URLs and free memory.
|
|
26
|
+
*/
|
|
27
|
+
export declare class BlobUrlManager {
|
|
28
|
+
private blobUrls;
|
|
29
|
+
private readonly container;
|
|
30
|
+
private transforms;
|
|
31
|
+
private encryptionMap?;
|
|
32
|
+
constructor(source: Container | ZipFetcher);
|
|
33
|
+
/**
|
|
34
|
+
* Set encryption metadata so Resources built during initialize()
|
|
35
|
+
* carry `properties.encrypted`. Transforms (e.g., deobfuscation)
|
|
36
|
+
* read this to know which resources to process.
|
|
37
|
+
*/
|
|
38
|
+
setEncryptionMap(map: Map<string, EncryptionInfo>): void;
|
|
39
|
+
/**
|
|
40
|
+
* Add a transform applied to resources before blob URL creation.
|
|
41
|
+
* Transforms run in order. Must be called before initialize().
|
|
42
|
+
*
|
|
43
|
+
* Example: font deobfuscation
|
|
44
|
+
* ```ts
|
|
45
|
+
* manager.addTransform(createDeobfuscationTransform(identifier));
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
48
|
+
addTransform(transform: BlobTransform): void;
|
|
49
|
+
/**
|
|
50
|
+
* Create blob URLs for all resources in the container.
|
|
51
|
+
* Call once after construction and addTransform().
|
|
52
|
+
*
|
|
53
|
+
* Two-pass process:
|
|
54
|
+
* 1. Create blob URLs for all non-CSS resources (images, fonts, etc.)
|
|
55
|
+
* — applies any registered transforms before creating the blob URL.
|
|
56
|
+
* 2. Process CSS files — rewrite internal url() references to the
|
|
57
|
+
* blob URLs from pass 1, THEN create blob URLs for the rewritten CSS.
|
|
58
|
+
*
|
|
59
|
+
* This ensures that when the browser loads a CSS file via its blob URL,
|
|
60
|
+
* font/image/background references inside it also point to blob URLs.
|
|
61
|
+
*/
|
|
62
|
+
initialize(): Promise<void>;
|
|
63
|
+
/**
|
|
64
|
+
* Rewrite resource references in a parsed DOM to blob URLs.
|
|
65
|
+
*
|
|
66
|
+
* Traverses the document and replaces relative `src`, `href`, and
|
|
67
|
+
* `xlink:href` attributes on img, link, script, image, use, audio,
|
|
68
|
+
* video, and source elements with their corresponding blob URLs.
|
|
69
|
+
*
|
|
70
|
+
* Also strips any Content-Security-Policy meta tags that would block
|
|
71
|
+
* the injected ReadiumCSS stylesheets.
|
|
72
|
+
*
|
|
73
|
+
* @param doc — the parsed XHTML document
|
|
74
|
+
* @param currentPath — the ZIP-internal path of the current HTML file
|
|
75
|
+
* (e.g., "OEBPS/Text/chapter1.xhtml"). Used to resolve relative URLs.
|
|
76
|
+
*/
|
|
77
|
+
rewriteDom(doc: Document, currentPath: string): void;
|
|
78
|
+
/**
|
|
79
|
+
* Rewrite url() and @import references in CSS text.
|
|
80
|
+
*
|
|
81
|
+
* Handles:
|
|
82
|
+
* - `url("path")` / `url('path')` / `url(path)` — standard references
|
|
83
|
+
* - `@import url("path")` — url()-form imports (caught by the url() regex)
|
|
84
|
+
* - `@import "path"` / `@import 'path'` — bare string imports
|
|
85
|
+
*/
|
|
86
|
+
private rewriteCssUrls;
|
|
87
|
+
private isAbsolute;
|
|
88
|
+
private resolve;
|
|
89
|
+
destroy(): void;
|
|
90
|
+
}
|
|
91
|
+
export {};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { Link } from "../model/v3";
|
|
2
|
+
import type { Fetcher, Resource } from "./Fetcher";
|
|
3
|
+
/**
|
|
4
|
+
* Caching wrapper around any Fetcher.
|
|
5
|
+
*
|
|
6
|
+
* Caches fetched resources by href in memory. Serves subsequent
|
|
7
|
+
* requests from cache without hitting the inner Fetcher. Enables
|
|
8
|
+
* predictive spine prefetching — the navigator calls `prefetch(link)`
|
|
9
|
+
* after each resource loads, and the next chapter is already in memory
|
|
10
|
+
* when the user turns the page.
|
|
11
|
+
*
|
|
12
|
+
* Memory management: call `evict(href)` to remove specific entries,
|
|
13
|
+
* or `clear()` to drop all cached resources.
|
|
14
|
+
*/
|
|
15
|
+
export declare class CacheFetcher implements Fetcher {
|
|
16
|
+
private readonly inner;
|
|
17
|
+
private cache;
|
|
18
|
+
private pending;
|
|
19
|
+
constructor(inner: Fetcher);
|
|
20
|
+
get(link: Link): Promise<Resource>;
|
|
21
|
+
getByHref(href: string): Promise<Resource>;
|
|
22
|
+
/**
|
|
23
|
+
* Prefetch a resource into cache without blocking.
|
|
24
|
+
* Used by the navigator to preload adjacent spine items after
|
|
25
|
+
* the current resource finishes loading.
|
|
26
|
+
*/
|
|
27
|
+
prefetch(link: Link): Promise<void>;
|
|
28
|
+
/** Check if a resource is cached. */
|
|
29
|
+
has(link: Link): Promise<boolean>;
|
|
30
|
+
/** Remove a specific resource from cache. */
|
|
31
|
+
evict(href: string): void;
|
|
32
|
+
/** Drop all cached resources. */
|
|
33
|
+
clear(): void;
|
|
34
|
+
cancel(href: string): void;
|
|
35
|
+
destroy(): void;
|
|
36
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Read-only container of named entries.
|
|
3
|
+
*
|
|
4
|
+
* A Container provides access to a collection of resources by path.
|
|
5
|
+
* It knows what entries exist and can return their raw bytes, but
|
|
6
|
+
* doesn't know anything about Fetcher, Resource, or media types.
|
|
7
|
+
*
|
|
8
|
+
* Implementations:
|
|
9
|
+
* - ZipContainer — entries from a ZIP archive (EPUB, CBZ)
|
|
10
|
+
* - Future: HttpContainer, FileSystemContainer, etc.
|
|
11
|
+
*/
|
|
12
|
+
export interface Container {
|
|
13
|
+
/** All entry paths in the container. */
|
|
14
|
+
entries(): string[];
|
|
15
|
+
/** Get raw bytes for an entry, or undefined if not found. */
|
|
16
|
+
get(path: string): Uint8Array | undefined;
|
|
17
|
+
/** Check if an entry exists. */
|
|
18
|
+
has(path: string): boolean;
|
|
19
|
+
/** Release resources (close file handles, free memory). */
|
|
20
|
+
destroy(): void;
|
|
21
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { Link } from "../model/v3";
|
|
2
|
+
import type { GetContent } from "./types";
|
|
3
|
+
import type { Fetcher, Resource } from "./Fetcher";
|
|
4
|
+
import type { Publication } from "../model/v3";
|
|
5
|
+
/**
|
|
6
|
+
* Fetcher that delegates publication-resource requests to the integrator's
|
|
7
|
+
* `api.getContent` callback.
|
|
8
|
+
*
|
|
9
|
+
* For hrefs that belong to the publication (readingOrder + resources in
|
|
10
|
+
* the manifest), `getContent(href)` is called first. If the integrator
|
|
11
|
+
* returns content, that content is used. If it returns `undefined`, the
|
|
12
|
+
* request falls through to the inner Fetcher.
|
|
13
|
+
*
|
|
14
|
+
* Requests for hrefs NOT in the manifest — positions service, external
|
|
15
|
+
* links, browser-chrome URLs — pass straight through to the inner Fetcher
|
|
16
|
+
* without touching getContent.
|
|
17
|
+
*
|
|
18
|
+
* Integrators use `api.getContent` to serve protected/licensed content,
|
|
19
|
+
* fetch from a custom source, or transform content before it reaches the
|
|
20
|
+
* reader.
|
|
21
|
+
*/
|
|
22
|
+
export declare class ContentFetcher implements Fetcher {
|
|
23
|
+
private readonly inner;
|
|
24
|
+
private readonly getContent;
|
|
25
|
+
private readonly publicationResourceHrefs;
|
|
26
|
+
constructor(inner: Fetcher, getContent: GetContent, publication: Publication);
|
|
27
|
+
get(link: Link): Promise<Resource>;
|
|
28
|
+
getByHref(href: string): Promise<Resource>;
|
|
29
|
+
cancel(href: string): void;
|
|
30
|
+
destroy(): void;
|
|
31
|
+
private isPublicationResource;
|
|
32
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { Publication } from "../model/v3/Publication";
|
|
2
|
+
import type { ZipFetcher } from "./ZipFetcher";
|
|
3
|
+
/**
|
|
4
|
+
* Client-side EPUB parser.
|
|
5
|
+
*
|
|
6
|
+
* Reads an EPUB archive (via ZipFetcher) and produces a Publication
|
|
7
|
+
* (Readium RWPM format). Handles EPUB 2 and EPUB 3:
|
|
8
|
+
*
|
|
9
|
+
* 1. META-INF/container.xml → find the OPF rootfile path
|
|
10
|
+
* 2. OPF → parse metadata, manifest items, spine, TOC
|
|
11
|
+
* 3. Convert to the normalized JSON shape that Publication.fromJSON() expects
|
|
12
|
+
*
|
|
13
|
+
* Metadata: title, language, identifier, authors, publisher, description,
|
|
14
|
+
* subjects, published date, modified date, numberOfPages, layout,
|
|
15
|
+
* readingProgression, rendition properties, media overlay classes.
|
|
16
|
+
*
|
|
17
|
+
* Spine: reading order with page-spread properties, linear="no" filtering,
|
|
18
|
+
* page-progression-direction.
|
|
19
|
+
*
|
|
20
|
+
* Resources: non-spine manifest items + non-linear spine items, cover image
|
|
21
|
+
* detection (EPUB3 cover-image property + EPUB2 meta name="cover").
|
|
22
|
+
*
|
|
23
|
+
* TOC: EPUB3 nav document with fallback to EPUB2 NCX.
|
|
24
|
+
*/
|
|
25
|
+
export declare class EpubParser {
|
|
26
|
+
/**
|
|
27
|
+
* Extract just the dc:identifier from an EPUB without full parsing.
|
|
28
|
+
* Used to generate a unique synthetic URL before the full parse.
|
|
29
|
+
*/
|
|
30
|
+
static extractIdentifier(zip: ZipFetcher): Promise<string>;
|
|
31
|
+
/**
|
|
32
|
+
* Parse an EPUB from a ZipFetcher and return a Publication.
|
|
33
|
+
*
|
|
34
|
+
* @param zip — ZipFetcher wrapping the .epub archive
|
|
35
|
+
* @param baseUrl — synthetic base URL for the publication
|
|
36
|
+
* (e.g. `blob:...` or `epub://local/`). Used for href resolution.
|
|
37
|
+
*/
|
|
38
|
+
static parse(zip: ZipFetcher, baseUrl: URL): Promise<Publication>;
|
|
39
|
+
/**
|
|
40
|
+
* Parse the EPUB 3 nav document (XHTML) to extract the TOC.
|
|
41
|
+
* Looks for `<nav epub:type="toc">` and extracts the `<ol>` structure.
|
|
42
|
+
*/
|
|
43
|
+
private static parseNavToc;
|
|
44
|
+
/**
|
|
45
|
+
* Parse an EPUB2 NCX table of contents.
|
|
46
|
+
*/
|
|
47
|
+
private static parseNcxToc;
|
|
48
|
+
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import type { Link } from "../model/v3";
|
|
2
|
+
/**
|
|
3
|
+
* A fetched resource — the result of a Fetcher.get() call.
|
|
4
|
+
*
|
|
5
|
+
* Represents content retrieved from any source (HTTP, ZIP, cache,
|
|
6
|
+
* decryption pipeline). Consumers read `text` for string content
|
|
7
|
+
* (HTML, XML, JSON) or `bytes` for binary content (images, audio, PDF).
|
|
8
|
+
*
|
|
9
|
+
* The `partial` and `range` fields are reserved for future range/partial
|
|
10
|
+
* fetching (DRM workstream — page-level streaming). Fetchers that support
|
|
11
|
+
* partial content set these; consumers that don't need partial content
|
|
12
|
+
* ignore them.
|
|
13
|
+
*/
|
|
14
|
+
export interface Resource {
|
|
15
|
+
/** The resolved content as a string (HTML, XML, JSON, etc.) */
|
|
16
|
+
readonly text: string;
|
|
17
|
+
/** The raw bytes — for binary content (images, audio, PDF) */
|
|
18
|
+
readonly bytes?: ArrayBuffer;
|
|
19
|
+
/** HTTP headers or equivalent metadata */
|
|
20
|
+
readonly headers: Record<string, string>;
|
|
21
|
+
/** The media type (e.g. "application/xhtml+xml", "application/pdf") */
|
|
22
|
+
readonly mediaType: string;
|
|
23
|
+
/** The resolved href */
|
|
24
|
+
readonly href: string;
|
|
25
|
+
/**
|
|
26
|
+
* Extensible metadata about this resource.
|
|
27
|
+
*
|
|
28
|
+
* Used to carry information through the Fetcher chain that
|
|
29
|
+
* isn't part of the content itself:
|
|
30
|
+
* - `encrypted?: { algorithm: string; originalLength?: number }` —
|
|
31
|
+
* encryption/obfuscation info from encryption.xml
|
|
32
|
+
* - `filename?: string` — original filename from the container
|
|
33
|
+
* - Custom properties set by TransformingFetcher or integrators
|
|
34
|
+
*/
|
|
35
|
+
readonly properties?: Record<string, unknown>;
|
|
36
|
+
/**
|
|
37
|
+
* Reserved for future range/partial fetching (3.9).
|
|
38
|
+
* True if this resource contains a partial range, not the full content.
|
|
39
|
+
*/
|
|
40
|
+
readonly partial?: boolean;
|
|
41
|
+
/**
|
|
42
|
+
* Reserved for future range/partial fetching (3.9).
|
|
43
|
+
* The byte range this resource represents within the full content.
|
|
44
|
+
*/
|
|
45
|
+
readonly range?: {
|
|
46
|
+
start: number;
|
|
47
|
+
end: number;
|
|
48
|
+
total: number;
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Content loading abstraction.
|
|
53
|
+
*
|
|
54
|
+
* All content in the reader flows through a Fetcher — chapter HTML,
|
|
55
|
+
* media overlay manifests, audio files, footnote popups, search content.
|
|
56
|
+
* The navigator and modules call `fetcher.get(link)` and receive a
|
|
57
|
+
* Resource without knowing where the content came from (HTTP, ZIP,
|
|
58
|
+
* cache, decryption pipeline).
|
|
59
|
+
*
|
|
60
|
+
* Fetchers are composable — stack them to build a content pipeline:
|
|
61
|
+
*
|
|
62
|
+
* ```ts
|
|
63
|
+
* // Server-based with decryption + caching:
|
|
64
|
+
* const fetcher = new CacheFetcher(
|
|
65
|
+
* new ContentFetcher(
|
|
66
|
+
* new HttpFetcher(requestConfig),
|
|
67
|
+
* api.getContent
|
|
68
|
+
* )
|
|
69
|
+
* )
|
|
70
|
+
*
|
|
71
|
+
* // Client-side EPUB with caching:
|
|
72
|
+
* const fetcher = new CacheFetcher(
|
|
73
|
+
* new ZipFetcher(epubBlob)
|
|
74
|
+
* )
|
|
75
|
+
* ```
|
|
76
|
+
*/
|
|
77
|
+
export interface Fetcher {
|
|
78
|
+
/**
|
|
79
|
+
* Fetch a resource by Link.
|
|
80
|
+
* Returns a Resource with the content, headers, and media type.
|
|
81
|
+
* Throws ReadError on failure (access, decoding, or cancelled).
|
|
82
|
+
*/
|
|
83
|
+
get(link: Link): Promise<Resource>;
|
|
84
|
+
/**
|
|
85
|
+
* Fetch a resource by href string (convenience overload).
|
|
86
|
+
* Throws ReadError on failure.
|
|
87
|
+
*/
|
|
88
|
+
getByHref(href: string): Promise<Resource>;
|
|
89
|
+
/**
|
|
90
|
+
* Cancel an in-flight fetch for the given href.
|
|
91
|
+
* Optional — not all Fetcher implementations support cancellation.
|
|
92
|
+
*/
|
|
93
|
+
cancel?(href: string): void;
|
|
94
|
+
/**
|
|
95
|
+
* Check if a resource is available without fetching it.
|
|
96
|
+
* Optional — useful for CacheFetcher (check cache hit) and
|
|
97
|
+
* ZipFetcher (check if file exists in ZIP).
|
|
98
|
+
*/
|
|
99
|
+
has?(link: Link): Promise<boolean>;
|
|
100
|
+
/**
|
|
101
|
+
* Prefetch a resource into cache without blocking.
|
|
102
|
+
* Optional — only meaningful for Fetchers that cache (CacheFetcher).
|
|
103
|
+
* Non-caching Fetchers can ignore this or no-op.
|
|
104
|
+
*/
|
|
105
|
+
prefetch?(link: Link): Promise<void>;
|
|
106
|
+
/**
|
|
107
|
+
* Release resources held by this Fetcher (close ZIP handles,
|
|
108
|
+
* clear caches, abort pending requests).
|
|
109
|
+
*/
|
|
110
|
+
destroy?(): void;
|
|
111
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Font deobfuscation for EPUB archives.
|
|
3
|
+
*
|
|
4
|
+
* EPUB publishers can obfuscate embedded fonts to prevent casual reuse
|
|
5
|
+
* outside the publication. Two algorithms exist:
|
|
6
|
+
*
|
|
7
|
+
* - **IDPF** (`http://www.idpf.org/2008/embedding`):
|
|
8
|
+
* SHA-1 hash of the publication identifier, XOR first 1040 bytes.
|
|
9
|
+
*
|
|
10
|
+
* - **Adobe** (`http://ns.adobe.com/pdf/enc#RC`):
|
|
11
|
+
* UUID from the identifier (16 bytes), XOR first 1024 bytes.
|
|
12
|
+
*
|
|
13
|
+
* The encryption.xml file in META-INF lists which resources are
|
|
14
|
+
* obfuscated and with which algorithm. The publication's dc:identifier
|
|
15
|
+
* is used to derive the deobfuscation key.
|
|
16
|
+
*
|
|
17
|
+
* Reference implementations:
|
|
18
|
+
* - edrlab/r2-shared-js src/transform/transformer-obf-idpf.ts
|
|
19
|
+
* - edrlab/r2-shared-js src/transform/transformer-obf-adobe.ts
|
|
20
|
+
* - readium/swift-toolkit Sources/Streamer/Parser/EPUB/EPUBDeobfuscator.swift
|
|
21
|
+
*/
|
|
22
|
+
/** Algorithm URIs as defined in the EPUB spec and Adobe's scheme. */
|
|
23
|
+
export declare const ALGORITHM_IDPF = "http://www.idpf.org/2008/embedding";
|
|
24
|
+
export declare const ALGORITHM_ADOBE = "http://ns.adobe.com/pdf/enc#RC";
|
|
25
|
+
/** Encryption info for a single resource, parsed from encryption.xml. */
|
|
26
|
+
export interface EncryptionInfo {
|
|
27
|
+
algorithm: string;
|
|
28
|
+
/** Original uncompressed length (from EncryptionProperties, if present). */
|
|
29
|
+
originalLength?: number;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Parse META-INF/encryption.xml and return a map of href → EncryptionInfo.
|
|
33
|
+
*
|
|
34
|
+
* Only extracts entries with IDPF or Adobe obfuscation algorithms.
|
|
35
|
+
* Other encryption types (e.g., LCP AES-256) are ignored here —
|
|
36
|
+
* those are handled by the integrator's getContent callback.
|
|
37
|
+
*/
|
|
38
|
+
export declare function parseEncryptionXml(xmlText: string): Map<string, EncryptionInfo>;
|
|
39
|
+
/**
|
|
40
|
+
* Deobfuscate font data using the IDPF algorithm.
|
|
41
|
+
*
|
|
42
|
+
* SHA-1 hash of the identifier → XOR first 1040 bytes.
|
|
43
|
+
* Uses Web Crypto API (available in all modern browsers).
|
|
44
|
+
*/
|
|
45
|
+
export declare function deobfuscateIdpf(data: Uint8Array, identifier: string): Promise<Uint8Array>;
|
|
46
|
+
/**
|
|
47
|
+
* Deobfuscate font data using the Adobe algorithm.
|
|
48
|
+
*
|
|
49
|
+
* Extract UUID from identifier (strip urn:uuid:, hyphens, whitespace),
|
|
50
|
+
* convert 16 hex pairs to 16 bytes → XOR first 1024 bytes.
|
|
51
|
+
*/
|
|
52
|
+
export declare function deobfuscateAdobe(data: Uint8Array, identifier: string): Uint8Array;
|
|
53
|
+
/**
|
|
54
|
+
* Create a ResourceTransform that deobfuscates fonts based on
|
|
55
|
+
* encryption info stored in the Resource's `properties.encrypted`.
|
|
56
|
+
*
|
|
57
|
+
* Use with TransformingFetcher:
|
|
58
|
+
* ```ts
|
|
59
|
+
* new TransformingFetcher(inner, createDeobfuscationTransform(identifier))
|
|
60
|
+
* ```
|
|
61
|
+
*
|
|
62
|
+
* Resources without encryption properties pass through unchanged.
|
|
63
|
+
* Only IDPF and Adobe algorithms are handled.
|
|
64
|
+
*/
|
|
65
|
+
export declare function createDeobfuscationTransform(identifier: string): (resource: import("./Fetcher").Resource) => Promise<import("./Fetcher").Resource>;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { Link } from "../model/v3";
|
|
2
|
+
import type { RequestConfig } from "./types";
|
|
3
|
+
import type { Fetcher, Resource } from "./Fetcher";
|
|
4
|
+
/**
|
|
5
|
+
* Default Fetcher implementation — loads resources via HTTP `fetch()`.
|
|
6
|
+
*
|
|
7
|
+
* Drop-in replacement for the current direct `fetch()` calls scattered
|
|
8
|
+
* across EpubNavigator, SearchModule, MediaOverlayModule, and Popup.
|
|
9
|
+
* Existing integrators get this automatically without changing anything.
|
|
10
|
+
*
|
|
11
|
+
* Handles:
|
|
12
|
+
* - Custom headers, credentials, and other RequestInit options via `requestConfig`
|
|
13
|
+
* - Media type detection from Content-Type header
|
|
14
|
+
*
|
|
15
|
+
* Base64-encoded content is handled by `Base64DecodingFetcher`, not here.
|
|
16
|
+
* HttpFetcher returns the response body as plain text. Decoding is
|
|
17
|
+
* composed in when `requestConfig.encoded` is true.
|
|
18
|
+
*/
|
|
19
|
+
export declare class HttpFetcher implements Fetcher {
|
|
20
|
+
private readonly requestConfig?;
|
|
21
|
+
/** Track in-flight requests by href so each can be cancelled independently. */
|
|
22
|
+
private controllers;
|
|
23
|
+
constructor(requestConfig?: RequestConfig | undefined);
|
|
24
|
+
get(link: Link): Promise<Resource>;
|
|
25
|
+
getByHref(href: string): Promise<Resource>;
|
|
26
|
+
private fetchByHref;
|
|
27
|
+
cancel(href?: string): void;
|
|
28
|
+
destroy(): void;
|
|
29
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Typed errors for the Fetcher / Resource system.
|
|
3
|
+
*
|
|
4
|
+
* Every Fetcher implementation throws a ReadError subclass instead of
|
|
5
|
+
* a generic Error. Callers that need to distinguish failure reasons
|
|
6
|
+
* check `error.type`. Callers that don't just catch ReadError.
|
|
7
|
+
*
|
|
8
|
+
* Types:
|
|
9
|
+
* - `access` — the resource couldn't be reached (HTTP 4xx/5xx,
|
|
10
|
+
* missing ZIP entry, network failure)
|
|
11
|
+
* - `decoding` — the resource was reached but its content is
|
|
12
|
+
* invalid or corrupt (bad XML, unexpected format)
|
|
13
|
+
* - `cancelled` — the request was aborted (navigated away,
|
|
14
|
+
* AbortController.abort())
|
|
15
|
+
*/
|
|
16
|
+
export type ReadErrorType = "access" | "decoding" | "cancelled";
|
|
17
|
+
export declare class ReadError extends Error {
|
|
18
|
+
readonly type: ReadErrorType;
|
|
19
|
+
readonly href?: string;
|
|
20
|
+
readonly statusCode?: number;
|
|
21
|
+
readonly cause?: Error;
|
|
22
|
+
constructor(opts: {
|
|
23
|
+
type: ReadErrorType;
|
|
24
|
+
message: string;
|
|
25
|
+
href?: string;
|
|
26
|
+
statusCode?: number;
|
|
27
|
+
cause?: Error;
|
|
28
|
+
});
|
|
29
|
+
/** Resource not found or unreachable. */
|
|
30
|
+
static access(href: string, message: string, statusCode?: number): ReadError;
|
|
31
|
+
/** Content is corrupt or can't be decoded. */
|
|
32
|
+
static decoding(href: string, message: string, cause?: Error): ReadError;
|
|
33
|
+
/** Request was cancelled. */
|
|
34
|
+
static cancelled(href: string): ReadError;
|
|
35
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { Link } from "../model/v3";
|
|
2
|
+
import type { Fetcher, Resource } from "./Fetcher";
|
|
3
|
+
/**
|
|
4
|
+
* A transform function applied to resources in the Fetcher chain.
|
|
5
|
+
*
|
|
6
|
+
* Receives a Resource and returns a (possibly modified) Resource.
|
|
7
|
+
* Return the original resource unchanged to pass it through.
|
|
8
|
+
*
|
|
9
|
+
* Transforms run after the inner Fetcher returns the resource,
|
|
10
|
+
* so the content is already fetched/decoded when the transform sees it.
|
|
11
|
+
*/
|
|
12
|
+
export type ResourceTransform = (resource: Resource) => Resource | Promise<Resource>;
|
|
13
|
+
/**
|
|
14
|
+
* Fetcher that applies one or more transforms to resources.
|
|
15
|
+
*
|
|
16
|
+
* Wraps an inner Fetcher and passes every returned Resource through
|
|
17
|
+
* a list of transform functions. Transforms run in order — the output
|
|
18
|
+
* of one is the input of the next.
|
|
19
|
+
*
|
|
20
|
+
* Used for:
|
|
21
|
+
* - Font deobfuscation (IDPF/Adobe XOR on encrypted font bytes)
|
|
22
|
+
* - Future: LCP content key decryption, accessibility transforms
|
|
23
|
+
*
|
|
24
|
+
* Chain position:
|
|
25
|
+
* CacheFetcher → ContentFetcher → TransformingFetcher → HttpFetcher/ZipFetcher
|
|
26
|
+
*
|
|
27
|
+
* The CacheFetcher caches the TRANSFORMED result, so transforms
|
|
28
|
+
* only run once per resource.
|
|
29
|
+
*/
|
|
30
|
+
export declare class TransformingFetcher implements Fetcher {
|
|
31
|
+
private readonly inner;
|
|
32
|
+
private readonly transforms;
|
|
33
|
+
constructor(inner: Fetcher, ...transforms: ResourceTransform[]);
|
|
34
|
+
get(link: Link): Promise<Resource>;
|
|
35
|
+
getByHref(href: string): Promise<Resource>;
|
|
36
|
+
cancel(href: string): void;
|
|
37
|
+
destroy(): void;
|
|
38
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Container } from "./Container";
|
|
2
|
+
/**
|
|
3
|
+
* Container backed by a ZIP archive (EPUB, CBZ, etc.).
|
|
4
|
+
*
|
|
5
|
+
* Parses the ZIP on construction and provides read-only access to
|
|
6
|
+
* entries by path. All paths are as stored in the ZIP — no
|
|
7
|
+
* basePath resolution happens here (that's the Fetcher's job).
|
|
8
|
+
*/
|
|
9
|
+
export declare class ZipContainer implements Container {
|
|
10
|
+
private data;
|
|
11
|
+
constructor(input: ArrayBuffer | Uint8Array);
|
|
12
|
+
entries(): string[];
|
|
13
|
+
get(path: string): Uint8Array | undefined;
|
|
14
|
+
has(path: string): boolean;
|
|
15
|
+
destroy(): void;
|
|
16
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { Link } from "../model/v3";
|
|
2
|
+
import type { Fetcher, Resource } from "./Fetcher";
|
|
3
|
+
import type { Container } from "./Container";
|
|
4
|
+
import type { EncryptionInfo } from "./FontDeobfuscator";
|
|
5
|
+
/**
|
|
6
|
+
* Fetcher that reads resources from a Container (ZIP archive, etc.).
|
|
7
|
+
*
|
|
8
|
+
* Wraps a Container and builds Resource objects from its raw bytes.
|
|
9
|
+
* The Container owns the data; the ZipFetcher handles path resolution,
|
|
10
|
+
* media type guessing, and text decoding.
|
|
11
|
+
*
|
|
12
|
+
* Accepts raw ZIP bytes (creates a ZipContainer internally) or a
|
|
13
|
+
* pre-built Container for reuse across Fetchers.
|
|
14
|
+
*
|
|
15
|
+
* Used by:
|
|
16
|
+
* - D2Reader.load({ epub: file }) — opens an .epub file directly
|
|
17
|
+
* - DiViNaNavigator (3.11) — opens CBZ comic/manga archives
|
|
18
|
+
*/
|
|
19
|
+
export declare class ZipFetcher implements Fetcher {
|
|
20
|
+
readonly container: Container;
|
|
21
|
+
private basePath;
|
|
22
|
+
private encryptionMap?;
|
|
23
|
+
/**
|
|
24
|
+
* Update the basePath after construction. Used when the identifier
|
|
25
|
+
* is extracted from the ZIP content and incorporated into the path.
|
|
26
|
+
*/
|
|
27
|
+
setBasePath(basePath: string): void;
|
|
28
|
+
/**
|
|
29
|
+
* Set encryption info so Resources carry encryption metadata
|
|
30
|
+
* in their `properties.encrypted` field. The TransformingFetcher
|
|
31
|
+
* reads this to know which resources need deobfuscation.
|
|
32
|
+
*/
|
|
33
|
+
setEncryptionMap(map: Map<string, EncryptionInfo>): void;
|
|
34
|
+
constructor(source: ArrayBuffer | Uint8Array | Container, basePath?: string);
|
|
35
|
+
get(link: Link): Promise<Resource>;
|
|
36
|
+
getByHref(href: string): Promise<Resource>;
|
|
37
|
+
has(link: Link): Promise<boolean>;
|
|
38
|
+
/** List all file paths in the container. */
|
|
39
|
+
list(): string[];
|
|
40
|
+
/** Read a specific entry as raw bytes. */
|
|
41
|
+
getBytes(path: string): Uint8Array | undefined;
|
|
42
|
+
destroy(): void;
|
|
43
|
+
/**
|
|
44
|
+
* Resolve an href to a container entry path.
|
|
45
|
+
* Strips the basePath prefix, query strings, fragments, and
|
|
46
|
+
* leading slashes.
|
|
47
|
+
*/
|
|
48
|
+
private resolvePath;
|
|
49
|
+
/** @deprecated Use `guessMediaType` from `./mediaType` instead. */
|
|
50
|
+
static guessMediaType(path: string): string;
|
|
51
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extends RequestInit with reader-specific options.
|
|
3
|
+
*
|
|
4
|
+
* Passed to HttpFetcher and through the Fetcher chain.
|
|
5
|
+
* `encoded` signals that the server returns base64-encoded content
|
|
6
|
+
* (used by some Readium-compatible streamers).
|
|
7
|
+
*/
|
|
8
|
+
export interface RequestConfig extends RequestInit {
|
|
9
|
+
encoded?: boolean;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Integrator-provided content callback.
|
|
13
|
+
*
|
|
14
|
+
* Called by ContentFetcher for each resource request. If the integrator
|
|
15
|
+
* returns content (string), it's used directly. If it returns undefined,
|
|
16
|
+
* the request falls through to the inner Fetcher (typically HttpFetcher).
|
|
17
|
+
*
|
|
18
|
+
* Used for DRM decryption, custom content sources, content transformation.
|
|
19
|
+
*/
|
|
20
|
+
export type GetContent = (href: string) => Promise<string | undefined>;
|
|
21
|
+
/**
|
|
22
|
+
* Callback to get the byte length of a resource.
|
|
23
|
+
*
|
|
24
|
+
* Used by Publication.autoGeneratePositions() to calculate
|
|
25
|
+
* reading positions from content size.
|
|
26
|
+
*/
|
|
27
|
+
export type GetContentBytesLength = (href: string, requestConfig?: RequestConfig) => Promise<number>;
|
package/dist/types/index.d.ts
CHANGED
|
@@ -18,7 +18,24 @@ export { ModuleRegistry } from "./modules/ModuleRegistry";
|
|
|
18
18
|
export { ModuleAccessors } from "./modules/ModuleAccessors";
|
|
19
19
|
export type { IBookmarkModule, ISearchModule, IAnnotationModule, IHistoryModule, SearchOptions, } from "./modules/interfaces";
|
|
20
20
|
export { getPageFromLocations } from "./model/v3";
|
|
21
|
-
export type {
|
|
21
|
+
export type { Fetcher, Resource } from "./fetcher/Fetcher";
|
|
22
|
+
export type { Container } from "./fetcher/Container";
|
|
23
|
+
export type { RequestConfig, GetContent, GetContentBytesLength, } from "./fetcher/types";
|
|
24
|
+
export { ZipContainer } from "./fetcher/ZipContainer";
|
|
25
|
+
export { ReadError } from "./fetcher/ReadError";
|
|
26
|
+
export type { ReadErrorType } from "./fetcher/ReadError";
|
|
27
|
+
export { HttpFetcher } from "./fetcher/HttpFetcher";
|
|
28
|
+
export { ContentFetcher } from "./fetcher/ContentFetcher";
|
|
29
|
+
export { CacheFetcher } from "./fetcher/CacheFetcher";
|
|
30
|
+
export { ZipFetcher } from "./fetcher/ZipFetcher";
|
|
31
|
+
export { EpubParser } from "./fetcher/EpubParser";
|
|
32
|
+
export { BlobUrlManager } from "./fetcher/BlobUrlManager";
|
|
33
|
+
export { guessMediaType } from "./fetcher/mediaType";
|
|
34
|
+
export { TransformingFetcher } from "./fetcher/TransformingFetcher";
|
|
35
|
+
export type { ResourceTransform } from "./fetcher/TransformingFetcher";
|
|
36
|
+
export { parseEncryptionXml, deobfuscateIdpf, deobfuscateAdobe, createDeobfuscationTransform, } from "./fetcher/FontDeobfuscator";
|
|
37
|
+
export type { EncryptionInfo } from "./fetcher/FontDeobfuscator";
|
|
38
|
+
export type { ReaderConfig, ReaderRights, NavigatorAPI, IFrameAttributes, Injectable, SampleRead, PublicationServices, InitialAnnotations, EpubNavigatorConfig, IFrameNavigatorConfig, } from "./navigator/EpubNavigator";
|
|
22
39
|
export type { IUserSettings, InitialUserSettings, } from "./model/user-settings/UserSettings";
|
|
23
40
|
export type { UserSettingsIncrementable } from "./model/user-settings/UserProperties";
|
|
24
41
|
export type { LocalStorageStoreConfig } from "./store/LocalStorageStore";
|