@prose-reader/streamer 0.0.22

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 (39) hide show
  1. package/dist/archives/createArchiveFromArrayBufferList.d.ts +10 -0
  2. package/dist/archives/createArchiveFromArrayBufferList.js +35 -0
  3. package/dist/archives/createArchiveFromJszip.d.ts +34 -0
  4. package/dist/archives/createArchiveFromJszip.js +26 -0
  5. package/dist/archives/createArchiveFromText.d.ts +7 -0
  6. package/dist/archives/createArchiveFromText.js +67 -0
  7. package/dist/archives/createArchiveFromUrls.d.ts +7 -0
  8. package/dist/archives/createArchiveFromUrls.js +29 -0
  9. package/dist/archives/getArchiveOpfInfo.d.ts +15 -0
  10. package/dist/archives/getArchiveOpfInfo.js +8 -0
  11. package/dist/archives/types.d.ts +20 -0
  12. package/dist/archives/types.js +1 -0
  13. package/dist/generators/manifest.d.ts +10 -0
  14. package/dist/generators/manifest.js +141 -0
  15. package/dist/generators/resources.d.ts +2 -0
  16. package/dist/generators/resources.js +95 -0
  17. package/dist/index.d.ts +10 -0
  18. package/dist/index.js +5709 -0
  19. package/dist/index.js.LICENSE.txt +10 -0
  20. package/dist/index.js.map +1 -0
  21. package/dist/parsers/kobo.d.ts +6 -0
  22. package/dist/parsers/kobo.js +26 -0
  23. package/dist/parsers/nav.d.ts +5 -0
  24. package/dist/parsers/nav.js +121 -0
  25. package/dist/report.d.ts +13 -0
  26. package/dist/report.js +68 -0
  27. package/dist/streamer/src/archives/createArchiveFromJszip.d.ts +34 -0
  28. package/dist/streamer/src/generators/manifest.d.ts +10 -0
  29. package/dist/streamer/src/generators/resources.d.ts +2 -0
  30. package/dist/streamer/src/index.d.ts +10 -0
  31. package/dist/streamer/src/parsers/kobo.d.ts +6 -0
  32. package/dist/streamer/src/parsers/nav.d.ts +5 -0
  33. package/dist/utils/blobToBAse64.d.ts +1 -0
  34. package/dist/utils/blobToBAse64.js +19 -0
  35. package/dist/utils/sortByTitleComparator.d.ts +1 -0
  36. package/dist/utils/sortByTitleComparator.js +18 -0
  37. package/dist/utils/uri.d.ts +1 -0
  38. package/dist/utils/uri.js +1 -0
  39. package/package.json +41 -0
@@ -0,0 +1,121 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ import xmldoc from 'xmldoc';
11
+ import { getArchiveOpfInfo } from '..';
12
+ const extractNavChapter = (li, { opfBasePath, baseUrl }) => {
13
+ const chp = {
14
+ contents: [],
15
+ path: ``,
16
+ href: ``,
17
+ title: ``
18
+ };
19
+ let contentNode = li.childNamed(`span`) || li.childNamed(`a`);
20
+ chp.title = (contentNode === null || contentNode === void 0 ? void 0 : contentNode.attr.title) || (contentNode === null || contentNode === void 0 ? void 0 : contentNode.val.trim()) || chp.title;
21
+ let node = contentNode === null || contentNode === void 0 ? void 0 : contentNode.name;
22
+ if (node !== `a`) {
23
+ contentNode = li.descendantWithPath(`${node}.a`);
24
+ if (contentNode) {
25
+ node = contentNode.name.toLowerCase();
26
+ }
27
+ }
28
+ if (node === `a` && (contentNode === null || contentNode === void 0 ? void 0 : contentNode.attr.href)) {
29
+ chp.path = opfBasePath ? `${opfBasePath}/${contentNode.attr.href}` : `${contentNode.attr.href}`;
30
+ chp.href = opfBasePath ? `${baseUrl}/${opfBasePath}/${contentNode.attr.href}` : `${baseUrl}/${contentNode.attr.href}`;
31
+ }
32
+ const sublistNode = li.childNamed(`ol`);
33
+ if (sublistNode) {
34
+ const children = sublistNode.childrenNamed(`li`);
35
+ if (children && children.length > 0) {
36
+ chp.contents = children.map((child) => extractNavChapter(child, { opfBasePath, baseUrl }));
37
+ }
38
+ }
39
+ return chp;
40
+ };
41
+ const buildTOCFromNav = (doc, { opfBasePath, baseUrl }) => {
42
+ var _a, _b;
43
+ const toc = [];
44
+ let navDataChildren;
45
+ if (doc.descendantWithPath(`body.nav.ol`)) {
46
+ navDataChildren = (_a = doc.descendantWithPath(`body.nav.ol`)) === null || _a === void 0 ? void 0 : _a.children;
47
+ }
48
+ else if (doc.descendantWithPath(`body.section.nav.ol`)) {
49
+ navDataChildren = (_b = doc.descendantWithPath(`body.section.nav.ol`)) === null || _b === void 0 ? void 0 : _b.children;
50
+ }
51
+ if (navDataChildren && navDataChildren.length > 0) {
52
+ navDataChildren
53
+ .filter((li) => li.name === `li`)
54
+ .forEach((li) => toc.push(extractNavChapter(li, { opfBasePath, baseUrl })));
55
+ }
56
+ return toc;
57
+ };
58
+ const parseTocFromNavPath = (opfXmlDoc, archive, { opfBasePath, baseUrl }) => __awaiter(void 0, void 0, void 0, function* () {
59
+ var _a;
60
+ // Try to detect if there is a nav item
61
+ const navItem = (_a = opfXmlDoc.childNamed(`manifest`)) === null || _a === void 0 ? void 0 : _a.childrenNamed(`item`).find((child) => child.attr.properties === `nav`);
62
+ if (navItem) {
63
+ const tocFile = Object.values(archive.files).find(item => item.uri.endsWith(navItem.attr.href || ``));
64
+ if (tocFile) {
65
+ const doc = new xmldoc.XmlDocument(yield tocFile.string());
66
+ return buildTOCFromNav(doc, { opfBasePath, baseUrl });
67
+ }
68
+ }
69
+ });
70
+ const mapNcxChapter = (point, { opfBasePath, baseUrl, prefix }) => {
71
+ var _a, _b;
72
+ const src = ((_a = point === null || point === void 0 ? void 0 : point.childNamed(`${prefix}content`)) === null || _a === void 0 ? void 0 : _a.attr.src) || ``;
73
+ const out = {
74
+ title: ((_b = point === null || point === void 0 ? void 0 : point.descendantWithPath(`${prefix}navLabel.${prefix}text`)) === null || _b === void 0 ? void 0 : _b.val) || ``,
75
+ path: opfBasePath ? `${opfBasePath}/${src}` : `${src}`,
76
+ href: opfBasePath ? `${baseUrl}/${opfBasePath}/${src}` : `${baseUrl}/${src}`,
77
+ contents: []
78
+ };
79
+ const children = point.childrenNamed(`${prefix}navPoint`);
80
+ if (children && children.length > 0) {
81
+ out.contents = children.map((pt) => mapNcxChapter(pt, { opfBasePath, baseUrl, prefix }));
82
+ }
83
+ return out;
84
+ };
85
+ const buildTOCFromNCX = (ncxData, { opfBasePath, baseUrl }) => {
86
+ var _a;
87
+ const toc = [];
88
+ const rootTagName = ncxData.name;
89
+ let prefix = ``;
90
+ if (rootTagName.indexOf(`:`) !== -1) {
91
+ prefix = rootTagName.split(`:`)[0] + `:`;
92
+ }
93
+ (_a = ncxData
94
+ .childNamed(`${prefix}navMap`)) === null || _a === void 0 ? void 0 : _a.childrenNamed(`${prefix}navPoint`).forEach((point) => toc.push(mapNcxChapter(point, { opfBasePath, baseUrl, prefix })));
95
+ return toc;
96
+ };
97
+ const parseTocFromNcx = ({ opfData, opfBasePath, baseUrl, archive }) => __awaiter(void 0, void 0, void 0, function* () {
98
+ var _b;
99
+ const spine = opfData.childNamed(`spine`);
100
+ const ncxId = spine && spine.attr.toc;
101
+ if (ncxId) {
102
+ const ncxItem = (_b = opfData
103
+ .childNamed(`manifest`)) === null || _b === void 0 ? void 0 : _b.childrenNamed(`item`).find((item) => item.attr.id === ncxId);
104
+ if (ncxItem) {
105
+ const ncxPath = `${opfBasePath}${opfBasePath === `` ? `` : `/`}${ncxItem.attr.href}`;
106
+ const file = Object.values(archive.files).find(item => item.uri.endsWith(ncxPath));
107
+ if (file) {
108
+ const ncxData = new xmldoc.XmlDocument(yield file.string());
109
+ return buildTOCFromNCX(ncxData, { opfBasePath, baseUrl });
110
+ }
111
+ }
112
+ }
113
+ });
114
+ export const parseToc = (opfXmlDoc, archive, { baseUrl }) => __awaiter(void 0, void 0, void 0, function* () {
115
+ const { basePath: opfBasePath } = getArchiveOpfInfo(archive) || {};
116
+ const tocFromNcx = yield parseTocFromNcx({ opfData: opfXmlDoc, opfBasePath, archive, baseUrl });
117
+ if (tocFromNcx) {
118
+ return tocFromNcx;
119
+ }
120
+ return yield parseTocFromNavPath(opfXmlDoc, archive, { opfBasePath, baseUrl });
121
+ });
@@ -0,0 +1,13 @@
1
+ export declare const Report: {
2
+ enable: (enable: boolean) => void;
3
+ log: (...data: any[]) => void;
4
+ warn: (...data: any[]) => void;
5
+ error: (...data: any[]) => void;
6
+ time: (label?: string | undefined) => void;
7
+ timeEnd: (label?: string | undefined) => void;
8
+ metric: (performanceEntry: PerformanceEntry | {
9
+ name: string;
10
+ duration: number;
11
+ }, targetDuration?: number) => void;
12
+ measurePerformance: <F extends (...args: any[]) => any>(name: string, targetDuration: number | undefined, functionToMeasure: F) => (...args: Parameters<F>) => ReturnType<F>;
13
+ };
package/dist/report.js ADDED
@@ -0,0 +1,68 @@
1
+ let enabled = false;
2
+ export const Report = {
3
+ enable: (enable) => {
4
+ enabled = enable;
5
+ },
6
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
7
+ log: (...data) => {
8
+ if (enabled) {
9
+ // eslint-disable-next-line no-console
10
+ console.log(`[prose-reader-streamer]`, ...data);
11
+ }
12
+ },
13
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
14
+ warn: (...data) => {
15
+ if (enabled) {
16
+ // eslint-disable-next-line no-console
17
+ console.warn(`[prose-reader-streamer]`, ...data);
18
+ }
19
+ },
20
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
21
+ error: (...data) => {
22
+ // eslint-disable-next-line no-console
23
+ console.error(...data);
24
+ },
25
+ time: (label) => {
26
+ if (enabled) {
27
+ // eslint-disable-next-line no-console
28
+ console.time(`[prose-reader-streamer] [metric] ${label}`);
29
+ }
30
+ },
31
+ timeEnd: (label) => {
32
+ if (enabled) {
33
+ // eslint-disable-next-line no-console
34
+ console.timeEnd(`[prose-reader-streamer] [metric] ${label}`);
35
+ }
36
+ },
37
+ metric: (performanceEntry, targetDuration = Infinity) => {
38
+ const duration = typeof performanceEntry === `number` ? performanceEntry : performanceEntry.duration;
39
+ if (enabled) {
40
+ if (performanceEntry.duration <= targetDuration) {
41
+ // eslint-disable-next-line no-console
42
+ console.log(`[prose-reader-streamer] [metric] `, `${performanceEntry.name} took ${duration}ms`);
43
+ }
44
+ else {
45
+ // eslint-disable-next-line no-console
46
+ console.warn(`[prose-reader-streamer] [metric] `, `${performanceEntry.name} took ${performanceEntry.duration}ms which is above the ${targetDuration}ms target for this function`);
47
+ }
48
+ }
49
+ },
50
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
51
+ measurePerformance: (name, targetDuration = 10, functionToMeasure) => {
52
+ return (...args) => {
53
+ const t0 = performance.now();
54
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
55
+ const response = functionToMeasure(...args);
56
+ if (response && response.then) {
57
+ return response.then((res) => {
58
+ const t1 = performance.now();
59
+ Report.metric({ name, duration: t1 - t0 }, targetDuration);
60
+ return res;
61
+ });
62
+ }
63
+ const t1 = performance.now();
64
+ Report.metric({ name, duration: t1 - t0 }, targetDuration);
65
+ return response;
66
+ };
67
+ }
68
+ };
@@ -0,0 +1,34 @@
1
+ /// <reference types="node" />
2
+ import { Archive, StreamResult } from "./types";
3
+ interface OutputByType {
4
+ base64: string;
5
+ string: string;
6
+ text: string;
7
+ binarystring: string;
8
+ array: number[];
9
+ uint8array: Uint8Array;
10
+ arraybuffer: ArrayBuffer;
11
+ blob: Blob;
12
+ nodebuffer: Buffer;
13
+ }
14
+ declare type OutputType = keyof OutputByType;
15
+ interface JSZipObject {
16
+ name: string;
17
+ dir: boolean;
18
+ date: Date;
19
+ comment: string;
20
+ unixPermissions: number | string | null;
21
+ dosPermissions: number | null;
22
+ async<T extends OutputType>(type: T): Promise<OutputByType[T]>;
23
+ internalStream?: (type?: `uint8array`) => StreamResult;
24
+ }
25
+ interface JSZip {
26
+ files: {
27
+ [key: string]: JSZipObject;
28
+ };
29
+ }
30
+ export declare const createArchiveFromJszip: (jszip: JSZip, { orderByAlpha, name }?: {
31
+ orderByAlpha?: boolean | undefined;
32
+ name?: string | undefined;
33
+ }) => Promise<Archive>;
34
+ export {};
@@ -0,0 +1,10 @@
1
+ import xmldoc from 'xmldoc';
2
+ import { Archive } from '..';
3
+ export declare const getManifestFromArchive: (archive: Archive, { baseUrl }?: {
4
+ baseUrl?: string | undefined;
5
+ }) => Promise<Response>;
6
+ export declare const getItemsFromDoc: (doc: xmldoc.XmlDocument) => {
7
+ href: string;
8
+ id: string;
9
+ mediaType: string | undefined;
10
+ }[];
@@ -0,0 +1,2 @@
1
+ import { Archive } from '..';
2
+ export declare const getResourceFromArchive: (archive: Archive, resourcePath: string) => Promise<Response>;
@@ -0,0 +1,10 @@
1
+ export { getResourceFromArchive } from './generators/resources';
2
+ export { getManifestFromArchive } from './generators/manifest';
3
+ export type { Manifest } from '@oboku/shared';
4
+ export { Report } from './report';
5
+ export { Archive } from './archives/types';
6
+ export { getArchiveOpfInfo } from './archives/getArchiveOpfInfo';
7
+ export { createArchiveFromUrls } from './archives/createArchiveFromUrls';
8
+ export { createArchiveFromText } from './archives/createArchiveFromText';
9
+ export { createArchiveFromJszip } from './archives/createArchiveFromJszip';
10
+ export { createArchiveFromArrayBufferList } from './archives/createArchiveFromArrayBufferList';
@@ -0,0 +1,6 @@
1
+ import { Archive } from '..';
2
+ declare type KoboInformation = {
3
+ renditionLayout?: `reflowable` | `pre-paginated` | undefined;
4
+ };
5
+ export declare const extractKoboInformationFromArchive: (archive: Archive) => Promise<KoboInformation>;
6
+ export {};
@@ -0,0 +1,5 @@
1
+ import xmldoc from 'xmldoc';
2
+ import { Archive } from '..';
3
+ export declare const parseToc: (opfXmlDoc: xmldoc.XmlDocument, archive: Archive, { baseUrl }: {
4
+ baseUrl: string;
5
+ }) => Promise<import("@oboku/shared").TocItem[] | undefined>;
@@ -0,0 +1 @@
1
+ export declare const blobToBase64: (blob: Blob | File) => Promise<string>;
@@ -0,0 +1,19 @@
1
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
+ return new (P || (P = Promise))(function (resolve, reject) {
4
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
8
+ });
9
+ };
10
+ export const blobToBase64 = (blob) => __awaiter(void 0, void 0, void 0, function* () {
11
+ return new Promise(resolve => {
12
+ const reader = new FileReader();
13
+ reader.readAsDataURL(blob);
14
+ reader.onloadend = function () {
15
+ const base64data = reader.result;
16
+ resolve(base64data);
17
+ };
18
+ });
19
+ });
@@ -0,0 +1 @@
1
+ export declare const sortByTitleComparator: (a: string, b: string) => number;
@@ -0,0 +1,18 @@
1
+ export const sortByTitleComparator = (a, b) => {
2
+ var _a;
3
+ const alist = a.split(/(\d+)/);
4
+ const blist = b.split(/(\d+)/);
5
+ alist.slice(-1) === [``] && alist.pop();
6
+ blist.slice(-1) === [``] && blist.pop();
7
+ for (let i = 0, len = alist.length; i < len; i++) {
8
+ if (alist[i] !== blist[i]) {
9
+ if ((_a = alist[i]) === null || _a === void 0 ? void 0 : _a.match(/\d/)) {
10
+ return +(alist[i] || ``) - +(blist[i] || ``);
11
+ }
12
+ else {
13
+ return (alist[i] || ``).localeCompare((blist[i] || ``));
14
+ }
15
+ }
16
+ }
17
+ return 1;
18
+ };
@@ -0,0 +1 @@
1
+ export declare const getUriBasename: (uri: string) => string;
@@ -0,0 +1 @@
1
+ export const getUriBasename = (uri) => uri.substring(uri.lastIndexOf(`/`) + 1) || uri;
package/package.json ADDED
@@ -0,0 +1,41 @@
1
+ {
2
+ "name": "@prose-reader/streamer",
3
+ "version": "0.0.22",
4
+ "main": "dist/index.js",
5
+ "license": "MIT",
6
+ "files": [
7
+ "/dist"
8
+ ],
9
+ "scripts": {
10
+ "start": "NODE_ENV=development webpack build --config ./webpack.config.js --watch",
11
+ "build": "NODE_ENV=development webpack build --config ./webpack.config.js",
12
+ "build:prod": "rm -rf dist && NODE_ENV=production webpack build --config ./webpack.config.js",
13
+ "lint": "eslint '**/*.{js,ts,tsx}'",
14
+ "test": "jest"
15
+ },
16
+ "dependencies": {
17
+ "@prose-reader/shared": "^0.0.4",
18
+ "@types/xmldoc": "^1.1.5",
19
+ "buffer": "6.0.3",
20
+ "xmldoc": "^1.1.2"
21
+ },
22
+ "devDependencies": {
23
+ "@babel/preset-typescript": "^7.16.0",
24
+ "@types/jest": "^27.0.3",
25
+ "@typescript-eslint/eslint-plugin": "^5.0.0",
26
+ "@typescript-eslint/parser": "^5.0.0",
27
+ "eslint": "^7.32.0",
28
+ "eslint-config-standard": "^16.0.3",
29
+ "eslint-plugin-import": "^2.25.2",
30
+ "eslint-plugin-jest": "^25.3.0",
31
+ "eslint-plugin-node": "^11.1.0",
32
+ "eslint-plugin-promise": "^5.1.1",
33
+ "jest": "^27.3.1",
34
+ "ts-loader": "^9.2.6",
35
+ "typescript": "*",
36
+ "webpack": "^5.64.3",
37
+ "webpack-cli": "^4.9.1",
38
+ "webpack-dev-server": "^4.6.0"
39
+ },
40
+ "gitHead": "a005ccf2d302179a488d3f5e79c1f043d3ce29de"
41
+ }