UNPKG

11.7 kBMarkdownView Raw
1# NodeJS / TypeScript Readium-2 "streamer"
2
3NodeJS implementation (written in TypeScript) and HTTP micro-services (Express middleware) for https://github.com/readium/architecture/tree/master/streamer
4
5[![License](https://img.shields.io/badge/License-BSD%203--Clause-blue.svg)](/LICENSE)
6
7## Build status
8
9[![NPM](https://img.shields.io/npm/v/dita-streamer-js.svg)](https://www.npmjs.com/package/dita-streamer-js) [![David](https://david-dm.org/d-i-t-a/dita-streamer-js/status.svg)](https://david-dm.org/d-i-t-a/dita-streamer-js) [![Travis](https://travis-ci.org/d-i-t-a/dita-streamer-js.svg?branch=develop)](https://travis-ci.org/d-i-t-a/dita-streamer-js) [![Heroku](https://img.shields.io/badge/app-Heroku-blue.svg)](https://readium2.herokuapp.com)
10
11[Changelog](/CHANGELOG.md)
12
13## Prerequisites
14
151) https://nodejs.org NodeJS >= 8, NPM >= 5 (check with command line `node --version` and `npm --version`)
162) OPTIONAL: https://yarnpkg.com Yarn >= 1.0 (check with command line `yarn --version`)
17
18## GitHub repository
19
20https://github.com/d-i-t-a/dita-streamer-js
21
22There is no [github.io](https://d-i-t-a.github.io/dita-streamer-js) site for this project (no [gh-pages](https://github.com/d-i-t-a/dita-streamer-js/tree/gh-pages) branch).
23
24## NPM package
25
26https://www.npmjs.com/package/dita-streamer-js
27
28Command line install:
29
30`npm install dita-streamer-js`
31OR
32`yarn add dita-streamer-js`
33
34...or manually add in your `package.json`:
35```json
36 "dependencies": {
37 "dita-streamer-js": "latest"
38 }
39```
40
41The JavaScript code distributed in the NPM package is usable as-is (no transpilation required), as it is automatically-generated from the TypeScript source.
42
43Several ECMAScript flavours are provided out-of-the-box: ES5, ES6-2015, ES7-2016, ES8-2017:
44
45https://unpkg.com/dita-streamer-js/dist/
46
47(alternatively, GitHub mirror with semantic-versioning release tags: https://github.com/d-i-t-a/dita-streamer-js-dist/tree/develop/dist/ )
48
49The JavaScript code is not bundled, and it uses `require()` statement for imports (NodeJS style).
50
51More information about NodeJS compatibility:
52
53http://node.green
54
55Note that web-browser Javascript is currently not supported (only NodeJS runtimes).
56
57The type definitions (aka "typings") are included as `*.d.ts` files in `./node_modules/dita-streamer-js/dist/**`, so this package can be used directly in a TypeScript project.
58
59Example usage:
60
61```javascript
62// from the index file
63import { Server } from "dita-streamer-js";
64
65// ES5 import (assuming node_modules/dita-streamer-js/):
66import { Server } from "dita-streamer-js/dist/es5/src/http/server";
67
68// ... or alternatively using a convenient path alias in the TypeScript config (+ WebPack etc.):
69import { Server } from "@dita-streamer-js/http/server";
70```
71
72## Dependencies
73
74https://david-dm.org/d-i-t-a/dita-streamer-js
75
76A [package-lock.json](https://github.com/d-i-t-a/dita-streamer-js/blob/develop/package-lock.json) is provided (modern NPM replacement for `npm-shrinkwrap.json`).
77
78A [yarn.lock](https://github.com/d-i-t-a/dita-streamer-js/blob/develop/yarn.lock) file is currently *not* provided at the root of the source tree.
79
80## Continuous Integration
81
82https://travis-ci.org/d-i-t-a/dita-streamer-js
83
84TravisCI builds are triggered automatically at every Git "push" in the `develop` branch.
85
86## Live demos
87
88A test server app (not production-ready) is automatically deployed at **Heroku**, at every Git "push" in the `develop` branch:
89
90https://readium2.herokuapp.com
91
92A mirror app used to be deployed at **Now.sh** (https://readium2.now.sh), but this is not available anymore due to technical reasons (i.e. the new Now deployment model does not support our custom Express server)
93
94Deployed servers run NodeJS 10+, and the apps are based on the ES8-2017 code transpiled from TypeScript.
95
96HTTP CORS headers are served to allow cross-origin / remote API requests.
97
98## Version(s), Git revision(s)
99
100NPM package (latest published):
101
102https://unpkg.com/dita-streamer-js/dist/gitrev.json
103
104Alternatively, GitHub mirror with semantic-versioning release tags:
105
106https://raw.githack.com/edrd-i-t-a/dita-streamer-js-dist/develop/dist/gitrev.json
107
108Heroku app (latest deployed):
109
110https://readium2.herokuapp.com/version
111
112## Developer quick start
113
114Command line steps (NPM, but similar with YARN):
115
1161) `cd dita-streamer-js`
1172) `git status` (please ensure there are no local changes, especially in `package-lock.json` and the dependency versions in `package.json`)
1183) `rm -rf node_modules` (to start from a clean slate)
1194) `npm install`, or alternatively `npm ci` (both commands initialize the `node_modules` tree of package dependencies, based on the strict `package-lock.json` definition)
1205) `npm run build:all` (invoke the main build script: clean, lint, compile)
1216) `ls dist` (that's the build output which gets published as NPM package)
1227) `npm run server-debug -- PATH_TO_EPUB_OR_DIR " -1"` (ES8-2017 dist, path is relative or absolute, -1 means no limits for HTTP header prefetch Links)
1238) or: `npm run start -- 99` (ES6-2015 dist, default `./misc/epubs` folder, the 99 value overrides the default maximum number of HTTP header prefetch Links)
124
125## Documentation
126
127### Basic usage
128
129```javascript
130// ES5 import (assuming node_modules/dita-streamer-js/):
131import { Server } from "dita-streamer-js/dist/es5/src/http/server";
132
133// ... or alternatively using a convenient path alias in the TypeScript config (+ WebPack etc.):
134import { Server } from "@dita-streamer-js/http/server";
135
136// Constructor parameter is optional:
137// disableDecryption: true
138// disableOPDS
139// disableReaders: true
140// disableRemotePubUrl: true to deactivate
141const server = new Server({
142 disableDecryption: false, // deactivates the decryption of encrypted resources (Readium LCP).
143 disableOPDS: true, // deactivates the HTTP routes for the OPDS "micro services" (browser, converter)
144 disableReaders: true, // deactivates the built-in "readers" for ReadiumWebPubManifest (HTTP static host / route).
145 disableRemotePubUrl: true, // deactivates the HTTP route for loading a remote publication.
146 maxPrefetchLinks: 5, // Link HTTP header, with rel = prefetch, see server.ts MAX_PREFETCH_LINKS (default = 10)
147 readers: [ // the example readers that will show up on the publication page
148 {
149 title: "My Example",
150 getUrl: manifestUrl => `/myreader?url=${manifestUrl}`
151 }
152 ]
153});
154
155// First parameter: port number, zero means default (3000),
156// unless specified via the environment variable `PORT` (process.env.PORT).
157// Tip: the NPM package `portfinder` can be used to automatically find an available port number.
158const url = await server.start(3000, false);
159
160// Second constructor parameter: if true, HTTPS instead of HTTP, using a randomly-generated self-signed certificate.
161// Also validates encrypted HTTP header during request-request cycles, so should only be used in runtime
162// contexts where the client side has access to the private encryption key (i.e. Electron app, see r2-navigator-js)
163console.log(server.isSecured()); // false
164
165// A client app that is capable of setting HTTP headers for every request originating from content webviews
166// can obtain the special encrypted header using this function:
167// (as used internally by the Electron-based `r2-navigator-js` component to secure the transport layer)
168const nameValuePair = server.getSecureHTTPHeader(url + "/PATH_TO_RESOURCE");
169console.log(nameValuePair.name);
170console.log(nameValuePair.value);
171
172// http://127.0.0.1:3000
173// Note that ports 80 and 443 (HTTPS) are always implicit (ommitted).
174console.log(url);
175
176// `serverInfo.urlScheme` ("http")
177// `serverInfo.urlHost` ("127.0.0.1")
178// `serverInfo.urlPort` (3000)
179console.log(server.serverInfo());
180
181// Calls `uncachePublications()` (see below)
182server.stop();
183
184console.log(server.isStarted()); // false
185```
186
187To serve a `/robots.txt` file that completely disables search robots:
188
189```javascript
190// Call this before `server.start()`
191server.preventRobots();
192```
193
194To add custom HTTP routes:
195
196```javascript
197// Call these before `server.start()`.
198// They are equivalent to `app.use()` and `app.get()`, where `app` is the underlying Express instance:
199
200server.expressUse("/static-files", express.static("/path/to/files", {
201 dotfiles: "ignore",
202 etag: true,
203 fallthrough: false,
204 immutable: true,
205 index: false,
206 maxAge: "1d",
207 redirect: false,
208}));
209
210server.expressGet(["/hello.html"], (req: express.Request, res: express.Response) => {
211
212 // Optionally, to add permissive CORS headers to the HTTP response
213 server.setResponseCORS(res);
214
215 res.status(200).send("<html><body>Hello</body></html>");
216});
217```
218
219To register publications references (local filesystem paths) inside the internal server state
220(which is used to create the OPDS2 feed, see below):
221
222```javascript
223// This can be called before or after `server.start()`:
224
225// the returned array contains URL routes to the ReadiumWebPubManifests,
226// e.g. `/pub/ID/manifest.json`, where `ID` is the base64 encoding of the registered path.
227// Note that the returned base64 URL path components are already URI-encoded (escaped).
228// (`=` and `/` are typically problematic edge-cases)
229const publicationURLs = server.addPublications(["/path/to/book.epub"]);
230
231// ...then:
232const publicationPaths = server.getPublications(); // ["/path/to/book.epub"]
233
234// ...and (calls `uncachePublication()`, see below):
235const publicationURLs = server.removePublications(["/path/to/book.epub"]);
236```
237
238To get the OPDS2 feed for the currently registered publications:
239
240```javascript
241// This launches a potentially time-consuming Node process that scans (loads) each registered Publication,
242// and stores the generated OPDS2 feed inside a temporary filesystem location.
243// So this returns `undefined` at the first call, and the client must invoke the function again later.
244// Note that both `addPublications()` and `removePublications()` clear the OPDS2 feed entirely,
245// requiring its subsequent re-generation (full scan of registered publication paths).
246// (poor design, but at this stage really just an OPDS2 demo without real use-case)
247const opds2 = server.publicationsOPDS();
248```
249
250To actually load+parse a publication reference (local filesystem path) into a ReadiumWebPubManifest
251Publication instance, stored in the server's state:
252
253```javascript
254// The Publication object model is defined in `r2-shared-js`
255const publication = await server.loadOrGetCachedPublication("/path/to/book.epub");
256
257// The above is basically a lazy-loader that checks the cache before loading+parsing a publication,
258// equivalent to:
259const publication = server.cachedPublication("/path/to/book.epub");
260if (!publication) {
261 publication = ...; // load and parse "/path/to/book.epub"
262 server.cachePublication("/path/to/book.epub", publication);
263}
264
265console.log(server.isPublicationCached("/path/to/book.epub")); // true
266
267// see also:
268// (calls `publication.freeDestroy()` to cleanup allocated objects in the Publication,
269// particularly the file handle to the underlying zip/EPUB/CBZ file)
270server.uncachePublication("/path/to/book.epub");
271server.uncachePublications();
272```
273
274Note that HTTP/remote publications URLs can be loaded into the server's cache
275and subsequently served by the streamer without prior registration via `addPublications()`.
276However, publications from the local filesytem will only be served when registered,
277even if they are cached (in other words, the HTTP route is disabled when the publication is non-registered).
278
279### HTTP API (built-in routes / micro-services)
280
281[docs/http.md](/docs/http.md)
282
283### Support for remote publications
284
285[docs/remote-epub.md](/docs/remote-epub.md)
286
287### Support for OPDS feeds
288
289[docs/opds.md](/docs/opds.md)
290
291### Support for encrypted content
292
293[docs/encryption.md](/docs/encryption.md)