UNPKG

@readium/shared

Version:

Shared models to be used across other Readium projects and implementations in Typescript

1,723 lines (1,722 loc) 113 kB
class Ae { close() { } links() { return []; } get(t) { throw Error("This is an empty fetcher"); } } class mr { constructor(t, e) { this.client = t || window.fetch.bind(window), this.baseUrl = e; } links() { return []; } get(t) { const e = t.toURL(this.baseUrl); if (e === void 0) throw Error(`Invalid HREF: ${t.href}`); return new Se(this.client, t, e); } close() { } } class Se { constructor(t, e, r) { this.client = t || window.fetch.bind(window), this._link = e, this.url = r; } /** Cached HEAD response to get the expected content length and other metadata. */ async headResponse() { if (this._headResponse) return this._headResponse; const t = await this.client(this.url, { method: "HEAD" }); if (!t.ok) throw new Error( `http HEAD request for ${this.url} failed with HTTP status code ${t.status}` ); return this._headResponse = t, t; } close() { } async link() { return this._link; } async read(t) { if (t) throw new Error("http read range not implemented!"); const e = await this.client(this.url); if (!e.ok) throw new Error( `http GET request for ${this.url} failed with HTTP status code ${e.status}` ); return new Uint8Array(await e.arrayBuffer()); } async length() { const e = (await this.headResponse()).headers.get("content-length"); if (e === null || e === "") throw new Error("length for resource unavailable"); return parseInt(e); } async readAsJSON() { const t = await this.client(this.url); if (!t.ok) throw new Error( `http GET request for ${this.url} failed with HTTP status code ${t.status}` ); return await t.json(); } async readAsString() { const t = await this.client(this.url); if (!t.ok) throw new Error( `http GET request for ${this.url} failed with HTTP status code ${t.status}` ); return await t.text(); } async readAsXML() { const t = await this.client(this.url); if (!t.ok) throw new Error( `http GET request for ${this.url} failed with HTTP status code ${t.status}` ); return new DOMParser().parseFromString( await t.text(), "application/xml" ); } } class Er { constructor(t, e) { this.start = t, this.endInclusive = e; } } class br { readAsString() { return this.read().then((t) => t === void 0 ? t : new TextDecoder().decode(t)); } readAsJSON() { return this.readAsString().then((t) => t === void 0 ? t : JSON.parse(t)); } readAsXML() { return this.readAsString().then((t) => t === void 0 ? t : new DOMParser().parseFromString(t, "text/xml")); } } class ht { /** * Creates a [Encryption]. */ constructor(t) { this.algorithm = t.algorithm, this.compression = t.compression, this.originalLength = t.originalLength, this.profile = t.profile, this.scheme = t.scheme; } /** * Parses a [Encryption] from its RWPM JSON representation. */ static deserialize(t) { if (t && t.algorithm) return new ht({ algorithm: t.algorithm, compression: t.compression, originalLength: t.originalLength, profile: t.profile, scheme: t.scheme }); } /** * Serializes a [Encryption] to its RWPM JSON representation. */ serialize() { const t = { algorithm: this.algorithm }; return this.compression !== void 0 && (t.compression = this.compression), this.originalLength !== void 0 && (t.originalLength = this.originalLength), this.profile !== void 0 && (t.profile = this.profile), this.scheme !== void 0 && (t.scheme = this.scheme), t; } } class m { constructor(t) { this.otherProperties = t; } /** * Creates a [Properties] from its RWPM JSON representation. */ static deserialize(t) { if (t) return new m(t); } /** * Serializes a [Properties] to its RWPM JSON representation. */ serialize() { return this.otherProperties; } /** * Makes a copy of this [Properties] after merging in the given additional other [properties]. */ add(t) { const e = Object.assign({}, this.otherProperties); for (const r in t) e[r] = t[r]; return new m(e); } } Object.defineProperty(m.prototype, "encryption", { get: function() { return ht.deserialize(this.otherProperties.encrypted); } }); var Rt = /* @__PURE__ */ ((i) => (i.fixed = "fixed", i.reflowable = "reflowable", i))(Rt || {}), Ie = /* @__PURE__ */ ((i) => (i.auto = "auto", i.landscape = "landscape", i.portrait = "portrait", i))(Ie || {}), Te = /* @__PURE__ */ ((i) => (i.auto = "auto", i.clipped = "clipped", i.paginated = "paginated", i.scrolled = "scrolled", i))(Te || {}), H = /* @__PURE__ */ ((i) => (i.left = "left", i.right = "right", i.center = "center", i))(H || {}), ze = /* @__PURE__ */ ((i) => (i.auto = "auto", i.both = "both", i.none = "none", i.landscape = "landscape", i))(ze || {}), ve = /* @__PURE__ */ ((i) => (i.contain = "contain", i.cover = "cover", i.width = "width", i.height = "height", i))(ve || {}); class _ { /** Creates a [Presentation]. */ constructor(t) { this.clipped = t.clipped, this.fit = t.fit, this.orientation = t.orientation, this.spread = t.spread, this.layout = t.layout, this.continuous = t.continuous, this.overflow = t.overflow; } /** * Parses a [Presentation] from its RWPM JSON representation. * */ static deserialize(t) { if (t) return new _({ clipped: t.clipped, continuous: t.continuous, fit: t.fit, orientation: t.orientation, overflow: t.overflow, spread: t.spread, layout: t.layout }); } /** * Serializes a [Presentation] to its RWPM JSON representation. */ serialize() { const t = {}; return this.clipped !== void 0 && (t.clipped = this.clipped), this.continuous !== void 0 && (t.continuous = this.continuous), this.fit !== void 0 && (t.fit = this.fit), this.orientation !== void 0 && (t.orientation = this.orientation), this.overflow !== void 0 && (t.overflow = this.overflow), this.spread !== void 0 && (t.spread = this.spread), this.layout !== void 0 && (t.layout = this.layout), t; } } _.prototype.layoutOf = function(i) { var t; return ((t = i.properties) == null ? void 0 : t.getLayout()) || this.layout || Rt.reflowable; }; m.prototype.getContains = function() { return new Set(this.otherProperties.contains || []); }; m.prototype.getLayout = function() { return this.otherProperties.layout; }; class a { /** Creates a MediaType object. */ constructor(t) { let e, r, s = t.mediaType.replace(/\s/g, "").split(";"); const n = s[0].split("/"); if (n.length === 2) { if (e = n[0].toLowerCase().trim(), r = n[1].toLowerCase().trim(), e.length === 0 || r.length === 0) throw new Error("Invalid media type"); } else throw new Error("Invalid media type"); const o = {}; for (let f = 1; f < s.length; f++) { const d = s[f].split("="); if (d.length === 2) { const I = d[0].toLocaleLowerCase(), L = I === "charset" ? d[1].toUpperCase() : d[1]; o[I] = L; } } const l = {}, c = Object.keys(o); c.sort((f, d) => f.localeCompare(d)), c.forEach((f) => l[f] = o[f]); let h = ""; for (const f in l) { const d = l[f]; h += `;${f}=${d}`; } const u = `${e}/${r}${h}`, p = l.encoding; this.string = u, this.type = e, this.subtype = r, this.parameters = l, this.encoding = p, this.name = t.name, this.fileExtension = t.fileExtension; } static parse(t) { return new a(t); } /** Structured syntax suffix, e.g. `+zip` in `application/epub+zip`. * Gives a hint on the underlying structure of this media type. * See. https://tools.ietf.org/html/rfc6838#section-4.2.8 */ get structuredSyntaxSuffix() { const t = this.subtype.split("+"); return t.length > 1 ? `+${t[t.length - 1]}` : void 0; } /** Parameter values might or might not be case-sensitive, depending on the semantics of * the parameter name. * https://tools.ietf.org/html/rfc2616#section-3.7 * * The character set names may be up to 40 characters taken from the printable characters * of US-ASCII. However, no distinction is made between use of upper and lower case * letters. * https://www.iana.org/assignments/character-sets/character-sets.xhtml */ get charset() { return this.parameters.charset; } /** Returns whether the given `other` media type is included in this media type. * For example, `text/html` contains `text/html;charset=utf-8`. * - `other` must match the parameters in the `parameters` property, but extra parameters * are ignored. * - Order of parameters is ignored. * - Wildcards are supported, meaning that `image/*` contains `image/png` */ contains(t) { const e = typeof t == "string" ? a.parse({ mediaType: t }) : t; if (!((this.type === "*" || this.type === e.type) && (this.subtype === "*" || this.subtype === e.subtype))) return !1; const r = new Set( Object.entries(this.parameters).map(([n, o]) => `${n}=${o}`) ), s = new Set( Object.entries(e.parameters).map(([n, o]) => `${n}=${o}`) ); for (const n of Array.from(r.values())) if (!s.has(n)) return !1; return !0; } /** Returns whether this media type and `other` are the same, ignoring parameters that * are not in both media types. * For example, `text/html` matches `text/html;charset=utf-8`, but `text/html;charset=ascii` * doesn't. This is basically like `contains`, but working in both direction. */ matches(t) { const e = typeof t == "string" ? a.parse({ mediaType: t }) : t; return this.contains(e) || e.contains(this); } /** * Returns whether this media type matches any of the [others] media types. */ matchesAny(...t) { for (const e of t) if (this.matches(e)) return !0; return !1; } /** Checks the MediaType equals another one (comparing their string) */ equals(t) { return this.string === t.string; } /** Returns whether this media type is structured as a ZIP archive. */ get isZIP() { return this.matchesAny( a.ZIP, a.LCP_PROTECTED_AUDIOBOOK, a.LCP_PROTECTED_PDF ) || this.structuredSyntaxSuffix === "+zip"; } /** Returns whether this media type is structured as a JSON file. */ get isJSON() { return this.matchesAny(a.JSON) || this.structuredSyntaxSuffix === "+json"; } /** Returns whether this media type is of an OPDS feed. */ get isOPDS() { return this.matchesAny( a.OPDS1, a.OPDS1_ENTRY, a.OPDS2, a.OPDS2_PUBLICATION, a.OPDS_AUTHENTICATION ) || this.structuredSyntaxSuffix === "+json"; } /** Returns whether this media type is of an HTML document. */ get isHTML() { return this.matchesAny(a.HTML, a.XHTML); } /** Returns whether this media type is of a bitmap image, so excluding vectorial formats. */ get isBitmap() { return this.matchesAny( a.BMP, a.GIF, a.JPEG, a.PNG, a.TIFF, a.WEBP ); } /** Returns whether this media type is of an audio clip. */ get isAudio() { return this.type === "audio"; } /** Returns whether this media type is of a video clip. */ get isVideo() { return this.type === "video"; } /** Returns whether this media type is of a Readium Web Publication Manifest. */ get isRWPM() { return this.matchesAny( a.READIUM_AUDIOBOOK_MANIFEST, a.DIVINA_MANIFEST, a.READIUM_WEBPUB_MANIFEST ); } /** Returns whether this media type is of a publication file. */ get isPublication() { return this.matchesAny( a.READIUM_AUDIOBOOK, a.READIUM_AUDIOBOOK_MANIFEST, a.CBZ, a.DIVINA, a.DIVINA_MANIFEST, a.EPUB, a.LCP_PROTECTED_AUDIOBOOK, a.LCP_PROTECTED_PDF, a.LPF, a.PDF, a.W3C_WPUB_MANIFEST, a.READIUM_WEBPUB, a.READIUM_WEBPUB_MANIFEST, a.ZAB ); } // Known Media Types static get AAC() { return a.parse({ mediaType: "audio/aac", fileExtension: "aac" }); } static get ACSM() { return a.parse({ mediaType: "application/vnd.adobe.adept+xml", name: "Adobe Content Server Message", fileExtension: "acsm" }); } static get AIFF() { return a.parse({ mediaType: "audio/aiff", fileExtension: "aiff" }); } static get AVI() { return a.parse({ mediaType: "video/x-msvideo", fileExtension: "avi" }); } static get BINARY() { return a.parse({ mediaType: "application/octet-stream" }); } static get BMP() { return a.parse({ mediaType: "image/bmp", fileExtension: "bmp" }); } static get CBZ() { return a.parse({ mediaType: "application/vnd.comicbook+zip", name: "Comic Book Archive", fileExtension: "cbz" }); } static get CSS() { return a.parse({ mediaType: "text/css", fileExtension: "css" }); } static get DIVINA() { return a.parse({ mediaType: "application/divina+zip", name: "Digital Visual Narratives", fileExtension: "divina" }); } static get DIVINA_MANIFEST() { return a.parse({ mediaType: "application/divina+json", name: "Digital Visual Narratives", fileExtension: "json" }); } static get EPUB() { return a.parse({ mediaType: "application/epub+zip", name: "EPUB", fileExtension: "epub" }); } static get GIF() { return a.parse({ mediaType: "image/gif", fileExtension: "gif" }); } static get GZ() { return a.parse({ mediaType: "application/gzip", fileExtension: "gz" }); } static get HTML() { return a.parse({ mediaType: "text/html", fileExtension: "html" }); } static get JAVASCRIPT() { return a.parse({ mediaType: "text/javascript", fileExtension: "js" }); } static get JPEG() { return a.parse({ mediaType: "image/jpeg", fileExtension: "jpeg" }); } static get JSON() { return a.parse({ mediaType: "application/json" }); } static get LCP_LICENSE_DOCUMENT() { return a.parse({ mediaType: "application/vnd.readium.lcp.license.v1.0+json", name: "LCP License", fileExtension: "lcpl" }); } static get LCP_PROTECTED_AUDIOBOOK() { return a.parse({ mediaType: "application/audiobook+lcp", name: "LCP Protected Audiobook", fileExtension: "lcpa" }); } static get LCP_PROTECTED_PDF() { return a.parse({ mediaType: "application/pdf+lcp", name: "LCP Protected PDF", fileExtension: "lcpdf" }); } static get LCP_STATUS_DOCUMENT() { return a.parse({ mediaType: "application/vnd.readium.license.status.v1.0+json" }); } static get LPF() { return a.parse({ mediaType: "application/lpf+zip", fileExtension: "lpf" }); } static get MP3() { return a.parse({ mediaType: "audio/mpeg", fileExtension: "mp3" }); } static get MPEG() { return a.parse({ mediaType: "video/mpeg", fileExtension: "mpeg" }); } static get NCX() { return a.parse({ mediaType: "application/x-dtbncx+xml", fileExtension: "ncx" }); } static get OGG() { return a.parse({ mediaType: "audio/ogg", fileExtension: "oga" }); } static get OGV() { return a.parse({ mediaType: "video/ogg", fileExtension: "ogv" }); } static get OPDS1() { return a.parse({ mediaType: "application/atom+xml;profile=opds-catalog" }); } static get OPDS1_ENTRY() { return a.parse({ mediaType: "application/atom+xml;type=entry;profile=opds-catalog" }); } static get OPDS2() { return a.parse({ mediaType: "application/opds+json" }); } static get OPDS2_PUBLICATION() { return a.parse({ mediaType: "application/opds-publication+json" }); } static get OPDS_AUTHENTICATION() { return a.parse({ mediaType: "application/opds-authentication+json" }); } static get OPUS() { return a.parse({ mediaType: "audio/opus", fileExtension: "opus" }); } static get OTF() { return a.parse({ mediaType: "font/otf", fileExtension: "otf" }); } static get PDF() { return a.parse({ mediaType: "application/pdf", name: "PDF", fileExtension: "pdf" }); } static get PNG() { return a.parse({ mediaType: "image/png", fileExtension: "png" }); } static get READIUM_AUDIOBOOK() { return a.parse({ mediaType: "application/audiobook+zip", name: "Readium Audiobook", fileExtension: "audiobook" }); } static get READIUM_AUDIOBOOK_MANIFEST() { return a.parse({ mediaType: "application/audiobook+json", name: "Readium Audiobook", fileExtension: "json" }); } static get READIUM_CONTENT_DOCUMENT() { return a.parse({ mediaType: "application/vnd.readium.content+json", name: "Readium Content Document", fileExtension: "json" }); } static get READIUM_GUIDED_NAVIGATION_DOCUMENT() { return a.parse({ mediaType: "application/guided-navigation+json", name: "Readium Guided Navigation Document", fileExtension: "json" }); } static get READIUM_POSITION_LIST() { return a.parse({ mediaType: "application/vnd.readium.position-list+json", name: "Readium Position List", fileExtension: "json" }); } static get READIUM_WEBPUB() { return a.parse({ mediaType: "application/webpub+zip", name: "Readium Web Publication", fileExtension: "webpub" }); } static get READIUM_WEBPUB_MANIFEST() { return a.parse({ mediaType: "application/webpub+json", name: "Readium Web Publication", fileExtension: "json" }); } static get SMIL() { return a.parse({ mediaType: "application/smil+xml", fileExtension: "smil" }); } static get SVG() { return a.parse({ mediaType: "image/svg+xml", fileExtension: "svg" }); } static get TEXT() { return a.parse({ mediaType: "text/plain", fileExtension: "txt" }); } static get TIFF() { return a.parse({ mediaType: "image/tiff", fileExtension: "tiff" }); } static get TTF() { return a.parse({ mediaType: "font/ttf", fileExtension: "ttf" }); } static get W3C_WPUB_MANIFEST() { return a.parse({ mediaType: "application/x.readium.w3c.wpub+json", name: "Web Publication", fileExtension: "json" }); } static get WAV() { return a.parse({ mediaType: "audio/wav", fileExtension: "wav" }); } static get WEBM_AUDIO() { return a.parse({ mediaType: "audio/webm", fileExtension: "webm" }); } static get WEBM_VIDEO() { return a.parse({ mediaType: "video/webm", fileExtension: "webm" }); } static get WEBP() { return a.parse({ mediaType: "image/webp", fileExtension: "webp" }); } static get WOFF() { return a.parse({ mediaType: "font/woff", fileExtension: "woff" }); } static get WOFF2() { return a.parse({ mediaType: "font/woff2", fileExtension: "woff2" }); } static get XHTML() { return a.parse({ mediaType: "application/xhtml+xml", fileExtension: "xhtml" }); } static get XML() { return a.parse({ mediaType: "application/xml", fileExtension: "xml" }); } static get ZAB() { return a.parse({ mediaType: "application/x.readium.zab+zip", name: "Zipped Audio Book", fileExtension: "zab" }); } static get ZIP() { return a.parse({ mediaType: "application/zip", fileExtension: "zip" }); } } class J { constructor(t) { this.uri = t, this.parameters = this.getParameters(t); } /** * List of URI template parameter keys, if the [Link] is templated. */ getParameters(t) { const e = /\{\??([^}]+)\}/g, r = t.match(e); return r ? new Set( r.join(",").replace(e, "$1").split(",").map((s) => s.trim()) ) : /* @__PURE__ */ new Set(); } /** Expands the URI by replacing the template variables by the given parameters. * Any extra parameter is appended as query parameters. * See RFC 6570 on URI template: https://tools.ietf.org/html/rfc6570 */ expand(t) { const e = (s) => s.split(",").map((n) => { const o = t[n]; return o ? encodeURIComponent(o) : ""; }).join(","), r = (s) => "?" + s.split(",").map((n) => { const o = n.split("=")[0], l = t[o]; return l ? `${o}=${encodeURIComponent(l)}` : ""; }).join("&"); return this.uri.replace(/\{(\??)([^}]+)\}/g, (...s) => s[1] ? r(s[2]) : e(s[2])); } } function Oe(i) { return i && i instanceof Array ? i : void 0; } function R(i) { return i && typeof i == "string" ? [i] : Oe(i); } function Y(i) { return typeof i == "string" ? new Date(i) : void 0; } function C(i) { return isNaN(i) ? void 0 : i; } function y(i) { return C(i) !== void 0 && Math.sign(i) >= 0 ? i : void 0; } function ut(i) { const t = new Array(); return i.forEach((e) => t.push(e)), t; } class E { /** * Creates a [Locations]. */ constructor(t) { this.fragments = t.fragments ? t.fragments : new Array(), this.progression = t.progression, this.totalProgression = t.totalProgression, this.position = t.position, this.otherLocations = t.otherLocations; } /** * Parses a [Locations] from its RWPM JSON representation. */ static deserialize(t) { if (!t) return; const e = C(t.progression), r = C(t.totalProgression), s = C(t.position), n = /* @__PURE__ */ new Map(), o = /* @__PURE__ */ new Set([ "fragment", "fragments", "progression", "totalProgression", "position" ]); return Object.entries(t).forEach(([l, c]) => { o.has(l) || n.set(l, c); }), new E({ fragments: R(t.fragments || t.fragment), progression: e !== void 0 && e >= 0 && e <= 1 ? e : void 0, totalProgression: r !== void 0 && r >= 0 && r <= 1 ? r : void 0, position: s !== void 0 && s > 0 ? s : void 0, otherLocations: n.size === 0 ? void 0 : n }); } /** * Serializes a [Locations] to its RWPM JSON representation. */ serialize() { const t = {}; return this.fragments && (t.fragments = this.fragments), this.progression !== void 0 && (t.progression = this.progression), this.totalProgression !== void 0 && (t.totalProgression = this.totalProgression), this.position !== void 0 && (t.position = this.position), this.otherLocations && this.otherLocations.forEach((e, r) => t[r] = e), t; } } class M { /** * Creates a [Text]. */ constructor(t) { this.after = t.after, this.before = t.before, this.highlight = t.highlight; } /** * Parses a [Locations] from its RWPM JSON representation. */ static deserialize(t) { if (t) return new M({ after: t.after, before: t.before, highlight: t.highlight }); } /** * Serializes a [Locations] to its RWPM JSON representation. */ serialize() { const t = {}; return this.after !== void 0 && (t.after = this.after), this.before !== void 0 && (t.before = this.before), this.highlight !== void 0 && (t.highlight = this.highlight), t; } } class A { /** * Creates a [Locator]. */ constructor(t) { this.href = t.href, this.type = t.type, this.title = t.title, this.locations = t.locations ? t.locations : new E({}), this.text = t.text; } /** * Parses a [Link] from its RWPM JSON representation. */ static deserialize(t) { if (t && t.href && t.type) return new A({ href: t.href, type: t.type, title: t.title, locations: E.deserialize(t.locations), text: M.deserialize(t.text) }); } /** * Serializes a [Link] to its RWPM JSON representation. */ serialize() { const t = { href: this.href, type: this.type }; return this.title !== void 0 && (t.title = this.title), this.locations && (t.locations = this.locations.serialize()), this.text && (t.text = this.text.serialize()), t; } /** * Shortcut to get a copy of the [Locator] with different [Locations] sub-properties. */ copyWithLocations(t) { return new A({ href: this.href, type: this.type, title: this.title, text: this.text, locations: new E({ ...this.locations, ...t }) }); } } class S { /** * Creates a [Link]. */ constructor(t) { this.href = t.href, this.templated = t.templated, this.type = t.type, this.title = t.title, this.rels = t.rels, this.properties = t.properties, this.height = t.height, this.width = t.width, this.duration = t.duration, this.bitrate = t.bitrate, this.languages = t.languages, this.alternates = t.alternates, this.children = t.children; } /** * Parses a [Link] from its RWPM JSON representation. */ static deserialize(t) { if (t && t.href && typeof t.href == "string") return new S({ href: t.href, templated: t.templated, type: t.type, title: t.title, rels: t.rel ? t.rel instanceof Array ? new Set(t.rel) : /* @__PURE__ */ new Set([t.rel]) : void 0, properties: m.deserialize(t.properties), height: y(t.height), width: y(t.width), duration: y(t.duration), bitrate: y(t.bitrate), languages: R(t.language), alternates: x.deserialize(t.alternate), children: x.deserialize(t.children) }); } /** * Serializes a [Link] to its RWPM JSON representation. */ serialize() { const t = { href: this.href }; return this.templated !== void 0 && (t.templated = this.templated), this.type !== void 0 && (t.type = this.type), this.title !== void 0 && (t.title = this.title), this.rels && (t.rel = ut(this.rels)), this.properties && (t.properties = this.properties.serialize()), this.height !== void 0 && (t.height = this.height), this.width !== void 0 && (t.width = this.width), this.duration !== void 0 && (t.duration = this.duration), this.bitrate !== void 0 && (t.bitrate = this.bitrate), this.languages && (t.language = this.languages), this.alternates && (t.alternate = this.alternates.serialize()), this.children && (t.children = this.children.serialize()), t; } /** MediaType of the linked resource. */ get mediaType() { return this.type !== void 0 ? a.parse({ mediaType: this.type }) : a.BINARY; } /** Computes an absolute URL to the link, relative to the given `baseURL`. * If the link's `href` is already absolute, the `baseURL` is ignored. */ toURL(t) { const e = this.href.replace(/^(\/)/, ""); if (e.length === 0) return; let r = t || "/"; return r.startsWith("/") && (r = "file://" + r), new URL(e, r).href.replace(/^(file:\/\/)/, ""); } /** List of URI template parameter keys, if the `Link` is templated. */ get templateParameters() { return this.templated ? new J(this.href).parameters : /* @__PURE__ */ new Set(); } /** Expands the `Link`'s HREF by replacing URI template variables by the given parameters. * See RFC 6570 on URI template: https://tools.ietf.org/html/rfc6570 */ expandTemplate(t) { return new S({ href: new J(this.href).expand(t), templated: !1 }); } /** * Makes a copy of this [Link] after merging in the given additional other [properties]. */ addProperties(t) { var r; const e = S.deserialize(this.serialize()); return e.properties = e.properties ? (r = e.properties) == null ? void 0 : r.add(t) : new m(t), e; } /** * Creates a [Locator] from a reading order [Link]. */ get locator() { let t = this.href.split("#"); return new A({ href: t.length > 0 && t[0] !== void 0 ? t[0] : this.href, type: this.type ?? "", title: this.title, locations: new E({ fragments: t.length > 1 && t[1] !== void 0 ? [t[1]] : [] }) }); } } class x { /** * Creates a [Links]. */ constructor(t) { this.items = t; } /** * Creates a list of [Link] from its RWPM JSON representation. */ static deserialize(t) { if (t && t instanceof Array) return new x( t.map((e) => S.deserialize(e)).filter((e) => e !== void 0) ); } /** * Serializes an array of [Link] to its RWPM JSON representation. */ serialize() { return this.items.map((t) => t.serialize()); } /** Finds the first link with the given relation. */ findWithRel(t) { const e = (r) => r.rels && r.rels.has(t); return this.items.find(e); } /** Finds all the links with the given relation. */ filterByRel(t) { const e = (r) => r.rels && r.rels.has(t); return this.items.filter(e); } /** Finds the first link matching the given HREF. */ findWithHref(t) { const e = (r) => r.href === t; return this.items.find(e); } /** Finds the index of the first link matching the given HREF. */ findIndexWithHref(t) { const e = (r) => r.href === t; return this.items.findIndex(e); } /** Finds the first link matching the given media type. */ findWithMediaType(t) { const e = (r) => r.mediaType.matches(t); return this.items.find(e); } /** Finds all the links matching the given media type. */ filterByMediaType(t) { const e = (r) => r.mediaType.matches(t); return this.items.filter(e); } /** Finds all the links matching any of the given media types. */ filterByMediaTypes(t) { const e = (r) => { for (const s of t) if (r.mediaType.matches(s)) return !0; return !1; }; return this.items.filter(e); } /** Returns whether all the resources in the collection are audio clips. */ everyIsAudio() { const t = (e) => e.mediaType.isAudio; return this.items.length > 0 && this.items.every(t); } /** Returns whether all the resources in the collection are bitmaps. */ everyIsBitmap() { const t = (e) => e.mediaType.isBitmap; return this.items.length > 0 && this.items.every(t); } /** Returns whether all the resources in the collection are HTML documents. */ everyIsHTML() { const t = (e) => e.mediaType.isHTML; return this.items.length > 0 && this.items.every(t); } /** Returns whether all the resources in the collection are video clips. */ everyIsVideo() { const t = (e) => e.mediaType.isVideo; return this.items.length > 0 && this.items.every(t); } /** Returns whether all the resources in the collection are matching any of the given media types. */ everyMatchesMediaType(t) { return Array.isArray(t) ? this.items.length > 0 && this.items.every((e) => { for (const r of t) return e.mediaType.matches(r); return !1; }) : this.items.length > 0 && this.items.every((e) => e.mediaType.matches(t)); } filterLinksHasType() { return this.items.filter((t) => t.type); } } class ft { constructor(t) { this.links = t.links, this.guided = t.guided; } static deserialize(t) { if (t) return new ft({ links: x.deserialize(t.links), guided: k.deserializeArray(t.guided) }); } serialize() { const t = {}; return this.links !== void 0 && (t.links = this.links.serialize()), this.guided !== void 0 && (t.guided = this.guided.map((e) => e.serialize())), t; } } class k { /** * Creates a [GuidedNavigation] object. */ constructor(t) { this.audioref = t.audioref, this.children = t.children, this.imgref = t.imgref, this.role = t.role, this.text = t.text, this.textref = t.textref; } /** * Parses a [GuidedNavigationObject] from its RWPM JSON representation. * * A GuidedNavigationObject can be parsed from a single string, or a full-fledged object. */ static deserialize(t) { if (t) return new k({ audioref: t.audioref, children: k.deserializeArray(t.children), imgref: t.imgref, role: t.role ? new Set(R(t.role)) : void 0, text: t.text, textref: t.textref }); } /** * Parses a [GuidedNavigationObject] array from its RWPM JSON representation. */ static deserializeArray(t) { if (t instanceof Array) return t.map((e) => k.deserialize(e)).filter((e) => e !== void 0); } /** * Serializes a [GuidedNavigationObject] to its RWPM JSON representation. */ serialize() { const t = {}; return this.audioref !== void 0 && (t.audioref = this.audioref), this.children !== void 0 && (t.children = this.children.map((e) => e.serialize())), this.imgref !== void 0 && (t.imgref = this.imgref), this.role !== void 0 && (t.role = ut(this.role)), this.text !== void 0 && (t.text = this.text), this.textref !== void 0 && (t.textref = this.textref), t; } get audioFile() { var t; return (t = this.audioref) == null ? void 0 : t.split("#")[0]; } get audioTime() { var t; if ((t = this.audioref) != null && t.includes("#")) return this.audioref.split("#", 2)[1]; } get textFile() { var t; return (t = this.textref) == null ? void 0 : t.split("#")[0]; } get fragmentId() { var t; if ((t = this.textref) != null && t.includes("#")) return this.textref.split("#", 2)[1]; } get clip() { const t = this.audioFile; if (!t) return; const e = this.audioTime, r = { audioResource: t, fragmentId: this.fragmentId }; if (!e) return r; const s = this.parseTimer(e); return r.start = s[0], r.end = s[1], r; } parseTimer(t) { if (!t || !t.startsWith("t=")) return [void 0, void 0]; const e = t.substring(2).split(",").map((r) => parseFloat(r)); return e.length === 1 ? [isNaN(e[0]) ? void 0 : e[0], void 0] : e.length > 2 ? [void 0, void 0] : [isNaN(e[0]) ? void 0 : e[0], isNaN(e[1]) ? void 0 : e[1]]; } } function Ne(i, t) { return t.length > 1 ? t.indexOf(i.slice(-1)) > -1 : i.slice(-1) === t; } function Pe(i, t) { return i.slice(i.length - t.length) === t; } const et = { endsWith: Pe, endsWithChar: Ne }, Ce = [ "ie", "eg", "ext", // + number? "Fig", "fig", "Figs", "figs", "et al", "Co", "Corp", "Ave", "Inc", "Ex", "Viz", "vs", "Vs", "repr", "Rep", "Dem", "trans", "Vol", "pp", "rev", "est", "Ref", "Refs", "Eq", "Eqs", "Ch", "Sec", "Secs", "mi", "Dept", "Univ", "Nos", "No", "Mol", "Cell", "Miss", "Mrs", "Mr", "Ms", "Prof", "Dr", "Sgt", "Col", "Gen", "Rep", "Sen", "Gov", "Lt", "Maj", "Capt", "St", "Sr", "Jr", "jr", "Rev", "PhD", "MD", "BA", "MA", "MM", "BSc", "MSc", "Jan", "Feb", "Mar", "Apr", "Jun", "Jul", "Aug", "Sep", "Sept", "Oct", "Nov", "Dec", "Sun", "Mon", "Tu", "Tue", "Tues", "Wed", "Th", "Thu", "Thur", "Thurs", "Fri", "Sat" ]; function Lt(i) { return /^[A-Z][a-z].*/.test(i) || st(i); } function Re(i) { return Lt(i) || /``|"|'/.test(i.substring(0, 2)); } function Le(i) { return ~Ce.indexOf(i.replace(/\W+/g, "")); } function ke(i, t) { if (i === "a.m." || i === "p.m.") { var e = t.replace(/\W+/g, "").slice(-3).toLowerCase(); if (e === "day") return !0; } return !1; } function St(i) { var t = i.replace(/[\(\)\[\]\{\}]/g, "").match(/(.\.)*/); return t && t[0].length > 0; } function It(i) { return i.length <= 3 ? !0 : Lt(i); } function st(i, t) { return t && (i = i.slice(t - 1, t + 2)), !isNaN(Number(i)); } function De(i) { return i.match(/^(?:(?:\+?1\s*(?:[.-]\s*)?)?(?:\(\s*([2-9]1[02-9]|[2-9][02-8]1|[2-9][02-8][02-9])\s*\)|([2-9]1[02-9]|[2-9][02-8]1|[2-9][02-8][02-9]))\s*(?:[.-]\s*)?)?([2-9]1[02-9]|[2-9][02-9]1|[2-9][02-9]{2})\s*(?:[.-]\s*)?([0-9]{4})(?:\s*(?:#|x\.?|ext\.?|extension)\s*(\d+))?$/); } function Ue(i) { return i.match(/[-a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)/); } function Be(i) { var t = 0; if ((t = i.indexOf(".")) > -1 || (t = i.indexOf("!")) > -1 || (t = i.indexOf("?")) > -1) { var e = i.charAt(t + 1); if (e.match(/[a-zA-Z].*/)) return [i.slice(0, t), i.charAt(t), i.slice(t + 1)]; } return !1; } function Fe(i) { return i === "." || i === "!" || i === "?"; } function We(i, t) { t = Object.assign(t || {}, { newlineBoundary: t && t.newlineBoundary || !0 }); var e = /\s/; return i.serie( // Split into words i.re(e, { split: !0 }), // Merge words as sentences i.splitAndMerge(function(r, s, n, o, l, c) { var h, u = [r, null], p = r, f = c.slice(l + 1).find(function(I) { return !e.test(I.value); }); if (r === ` ` && t.newlineBoundary || Fe(r) || et.endsWithChar(r, "?!")) return u; if (et.endsWithChar(r, ".")) { if (f) { if (r.length === 2 && isNaN(r.charAt(0)) && r.match(/[a-zA-Z]/) || Le(r)) return p; if (Re(f.value)) { if (ke(r, f.value) || st(f.value) && It(r)) return p; } else if (et.endsWith(r, "..") || St(r) || It(r)) return p; } return u; } let d; return (d = r.indexOf(".")) > -1 && (st(r, d) || St(r) || Ue(r) || De(r)) ? p : (h = Be(r)) ? [ h[0] + h[1], null, h[2] ] : p; }), // Filter empty sentences i.filter(function(r) { return r.trim() != ""; }) ); } const Me = (i, ...t) => (...e) => i(...t, ...e); function $e(i) { return { sentences: Me(We, i) }; } function Ge(i, t) { return t ? i.reduce(function(e, r) { var s = [ r.index, r.offset, r.value ].join("-"); return [e, s].join(":"); }, t) : null; } function He(i) { const { index: t, offset: e, value: r, ...s } = i; return s; } function Ve(i, t) { var e = 0; return Array.isArray(t) || (t = [t]), t.map(function(r) { return r === null ? null : (typeof r == "string" && (r = { value: r, index: e, offset: r.length }), typeof r == "object" && (r.index = r.index || 0, e = e + r.index + r.offset, r.index = i.index + r.index, r.offset = r.offset || r.value.length), r); }); } function Je(i, t) { var n; if (i.length == 0) return null; var e = "", r = 0, s = (n = i[0]) == null ? void 0 : n.index; return i.forEach(function(o, l) { var c = i[l - 1]; i[l + 1]; var h = c ? o.index + 1 - (c.index + c.offset) : 0; e = e + new Array(h).join(t) + o.value; var u = o.index - s + o.offset; u > r && (r = u); }), { // Index equal is the one from the first token index: s, value: e, offset: Math.max(r, e.length) }; } const D = { tokensId: Ge, normalize: Ve, properties: He, merge: Je }; var Ye = ' \r\n  !"#$%&()*+,-.\\/:;<=>?@[\\]^_`{|}~', qe = new RegExp( "([^" + Ye + "]+)" ); function w(i) { if (!(this instanceof w)) return new w(i); this.opts = Object.assign({ cacheGet: function(t) { return null; }, cacheSet: function(t, e) { } }, i); } w.prototype.split = function(t, e = {}) { var r = this; return e = Object.assign({ preserveProperties: !0, cache: () => null }, e), function(s, n) { if (arguments.length === 6) return t.apply(null, arguments); var o, l, c; if (s === void 0) return []; if (typeof s == "string" ? s = [{ value: s, index: 0, offset: s.length }] : Array.isArray(s) || (s = [s]), l = D.tokensId(s, e.cache()), l && (c = r.opts.cacheGet(l), c)) return c; var h = s.map(function(u, p) { var f = s[p + 1], d = t( u.value, Object.assign({}, u), o ? Object.assign({}, o) : null, f ? Object.assign({}, f) : null, p, s ) || []; if (d = D.normalize(u, d), e.preserveProperties) { var I = D.properties(u); d = d.map(function(L) { return Object.assign({}, L, I); }); } return o = u, d; }).filter(Boolean).flat(); return l && r.opts.cacheSet(l, h), h; }; }; w.prototype.re = function(t, e = {}) { return e = Object.assign({ split: !1 }, e), this.split(function(r, s) { for (var n = r, o = [], l, c = 0; l = t.exec(r); ) { var h = l.index, u = c + h, p = l[0] || "", f = p.length; if (e.split && c < u) { var d = n.slice(c, u); o.push({ value: d, index: c, offset: d.length }); } o.push({ value: p, index: u, offset: f, match: l }), r = r.slice(h + f), c = u + f; } return e.split && r && o.push({ value: r, index: c, offset: r.length }), o; }, { cache: function() { return t.toString(); } }); }; w.prototype.splitAndMerge = function(t, e = {}) { var r = this; return e = Object.assign({ mergeWith: "" }, e), function(s) { var n = [], o = []; function l() { if (o.length != 0) { var c = D.merge(o, e.mergeWith); n.push(c), o = []; } } return r.split(function(c, h) { var u = t.apply(null, arguments); u = D.normalize(h, u), u.forEach(function(p) { p === null ? l() : o.push(p); }); })(s), l(), n; }; }; w.prototype.filter = function(t) { return this.split(function(e, r) { if (t.apply(null, arguments)) return { value: r.value, index: 0, offset: r.offset }; }); }; w.prototype.extend = function(t) { return this.split(function(e, r) { var s = typeof t == "function" ? t.apply(null, arguments) : t; return Object.assign({ value: r.value, index: 0, offset: r.offset }, s); }); }; w.prototype.ifthen = function(i, t) { return this.split(function(e, r) { if (i.apply(null, arguments)) return t.apply(null, arguments); const { index: s, ...n } = r; return n; }); }; w.prototype.test = function(t) { return this.filter(function(e, r) { return t.test(e); }, { cache: t.toString() }); }; w.prototype.flow = function(...t) { const e = t.reduce((r, s) => (...n) => s(r(...n))); return this.split(e); }; w.prototype.serie = function(...t) { return t.reduce((e, r) => (...s) => r(e(...s))); }; w.prototype.merge = function() { return this.splitAndMerge((i) => [i]); }; w.prototype.sections = function() { return this.re(/([^\n\.,;!?]+)/i, { split: !1 }); }; w.prototype.words = function() { return this.re(qe); }; w.prototype.characters = function() { return this.re(/[^\s]/); }; var Ke = /* @__PURE__ */ ((i) => (i.Word = "word", i.Sentence = "sentence", i.Paragraph = "paragraph", i))(Ke || {}); const Ze = (i, t) => "Segmenter" in Intl ? new Xe(i, t) : new Qe(i, t); class Xe { constructor(t, e) { if (this.unit = e, t = t ?? (navigator == null ? void 0 : navigator.language), !("Segmenter" in Intl)) throw new Error("Intl.Segmenter is not supported in this environment"); if (e === "paragraph") throw new Error("IntlTextTokenizer does not handle TextUnit.Paragraph"); this.segmenter = new Intl.Segmenter(t, { granularity: e }); } tokenize(t) { const e = this.segmenter.segment(t), r = []; for (let s of e) { if (this.unit === "word" && s.isWordLike === !1) continue; const n = kt(s.segment); n !== null && r.push([s.index, s.index + n.length]); } return r; } } class Qe { constructor(t, e) { if (this.unit = e, t = t ?? (navigator == null ? void 0 : navigator.language), this.isEnglish = t.toLowerCase().split("-")[0] === "en", e === "paragraph") throw new Error("NaiveTextTokenizer does not handle TextUnit.Paragraph"); this.tokenizer = new w(); } tokenize(t) { let e = []; switch (this.unit) { case "word": e = this.tokenizer.words()(t); break; case "sentence": this.isEnglish ? e = $e(this.tokenizer).sentences()(t) : e = this.tokenizer.sections()(t); break; default: e = []; } if (!e) return []; const r = []; return e.forEach((s) => { if (s.value.length === 0) return; const n = kt(s.value); n !== null && r.push([s.index, s.index + n.length]); }), r; } } const _e = new RegExp("[\\p{L}\\p{N}]+", "u"), kt = (i) => { const t = i.trimEnd(); return t.length === 0 || t.match(_e) === null ? null : t; }; class N { constructor(t) { this.fetcher = new Ae(), t.fetcher && (this.fetcher = t.fetcher), this.manifest = t.manifest, this.context = t.manifest.context, this.metadata = t.manifest.metadata, this.links = t.manifest.links, this.readingOrder = t.manifest.readingOrder, this.resources = t.manifest.resources, this.tableOfContents = t.manifest.tableOfContents, this.subcollections = t.manifest.subcollections; } /** The URL where this publication is served, computed from the `Link` with `self` relation. * e.g. https://provider.com/pub1293/manifest.json gives https://provider.com/pub1293/ */ get baseURL() { return this.manifest.baseURL; } /** Finds the first Link having the given `href` in the publication's links. */ linkWithHref(t) { return this.manifest.linkWithHref(t); } /** * Returns the [links] of the first child [PublicationCollection] with the given role, or an * empty list. */ linksWithRole(t) { var r; const e = (r = this.subcollections) == null ? void 0 : r.get(t); return e && e.length > 0 ? e[0].links : void 0; } /** Finds all the links with the given relation in the publication's links. */ linksWithRel(t) { return this.manifest.linksWithRel(t); } /** * Finds the first [Link] having the given [rel] in the publications's links. */ linkWithRel(t) { return this.manifest.linkWithRel(t); } async positionsFromManifest() { const t = this.manifest.links.findWithMediaType( "application/vnd.readium.position-list+json" ); if (t === void 0) return []; const e = await this.get( t ).readAsJSON(); return e.total ? e.positions.map((r) => A.deserialize(r)).filter((r) => r !== void 0) : []; } async guideForLink(t) { const e = (o) => { var l; return (l = o.alternates) == null ? void 0 : l.findWithMediaType( "application/guided-navigation+json" ); }; let r = e(t); if (!r) { const o = this.linkWithHref(t.href); o !== void 0 && (r = e(o)); } if (r || (r = this.manifest.links.findWithMediaType( "application/guided-navigation+json" )), !r) return; let s = r.href; if (r.templated) { const o = new J(s), l = {}; o.parameters.has("ref") && (l.ref = t.href), s = new J(s).expand(l); } const n = await this.get(new S({ href: s })).readAsJSON(); return ft.deserialize(n); } /** * Returns the resource targeted by the given non-templated [link]. */ get(t) { return this.fetcher.get(t); } } N.prototype.getPageList = function() { return this.linksWithRole("pageList"); }; N.prototype.getLandmarks = function() { return this.linksWithRole("landmarks"); }; N.prototype.getListOfAudioClips = function() { return this.linksWithRole("loa"); }; N.prototype.getListOfIllustrations = function() { return this.linksWithRole("loi"); }; N.prototype.getListOfTables = function() { return this.linksWithRole("lot"); }; N.prototype.getListOfVideoClips = function() { return this.linksWithRole("lov"); }; class q { /** * Creates a [DomRange]. */ constructor(t) { this.cssSelector = t.cssSelector, this.textNodeIndex = t.textNodeIndex, this.charOffset = t.charOffset; } /** * Parses a [DomRangePoint] from its RWPM JSON representation. */ static deserialize(t) { if (!(t && t.cssSelector)) return; let e = y(t.textNodeIndex); if (e === void 0) return; let r = y(t.charOffset); return r === void 0 && (r = y(t.offset)), new q({ cssSelector: t.cssSelector, textNodeIndex: e, charOffset: r }); } /** * Serializes a [DomRangePoint] to its RWPM JSON representation. */ serialize() { const t = { cssSelector: this.cssSelector, textNodeIndex: this.textNodeIndex }; return this.charOffset !== void 0 && (t.charOffset = this.charOffset), t; } } class pt { /** * Creates a [DomRange]. */ constructor(t) { this.start = t.start, this.end = t.end; } /** * Parses a [DomRange] from its RWPM JSON representation. */ static deserialize(t) { if (!t) return; let e = q.deserialize(t.start); if (e) return new pt({ start: e, end: q.deserialize(t.end) }); } /** * Serializes a [DomRange] to its RWPM JSON representation. */ serialize() { const t = { start: this.start.serialize() }; return this.end && (t.end = this.end.serialize()), t; } } E.prototype.getCssSelector = function() { var i; return (i = this.otherLocations) == null ? void 0 : i.get("cssSelector"); }; E.prototype.getPartialCfi = function() { var i; return (i = this.otherLocations) == null ? void 0 : i.get("partialCfi"); }; E.prototype.getDomRange = function() { var i; return pt.deserialize((i = this.otherLocations) == null ? void 0 : i.get("domRange")); }; E.prototype.fragmentParameters = function() { return new Map( this.fragments.map((i) => i.startsWith("#") ? i.slice(1) : i).join("&").split("&").filter((i) => !i.startsWith("#")).map((i) => i.split("=")).filter((i) => i.length === 2).map((i) => [ i[0].trim().toLowerCase(), i[1].trim() ]) ); }; E.prototype.htmlId = function() { if (!this.fragments.length) return; let i = this.fragments.find((t) => t.length && !t.includes("=")); if (!i) { const t = this.fragmentParameters(); t.has("id") ? i = t.get("id") : t.has("name") && (i = t.get("name")); } return i != null && i.startsWith("#") ? i.slice(1) : i; }; E.prototype.page = function() { const i = parseInt(this.fragmentParameters().get("page")); if (!isNaN(i) && i >= 0)