@readium/navigator-html-injectables 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/README.MD +13 -0
  2. package/dist/index.js +3144 -0
  3. package/dist/index.umd.cjs +69 -0
  4. package/package.json +58 -0
  5. package/src/Loader.ts +85 -0
  6. package/src/comms/comms.ts +168 -0
  7. package/src/comms/index.ts +3 -0
  8. package/src/comms/keys.ts +42 -0
  9. package/src/comms/mid.ts +5 -0
  10. package/src/helpers/animation.ts +5 -0
  11. package/src/helpers/css.ts +16 -0
  12. package/src/helpers/document.ts +43 -0
  13. package/src/helpers/dom.ts +126 -0
  14. package/src/helpers/locator.ts +67 -0
  15. package/src/helpers/rect.ts +301 -0
  16. package/src/helpers/scrollSnapperHelper.ts +43 -0
  17. package/src/index.ts +3 -0
  18. package/src/modules/Decorator.ts +462 -0
  19. package/src/modules/Module.ts +23 -0
  20. package/src/modules/ModuleLibrary.ts +44 -0
  21. package/src/modules/Peripherals.ts +148 -0
  22. package/src/modules/index.ts +3 -0
  23. package/src/modules/setup/FixedSetup.ts +73 -0
  24. package/src/modules/setup/ReflowableSetup.ts +65 -0
  25. package/src/modules/setup/Setup.ts +131 -0
  26. package/src/modules/snapper/ColumnSnapper.ts +468 -0
  27. package/src/modules/snapper/ScrollSnapper.ts +168 -0
  28. package/src/modules/snapper/Snapper.ts +49 -0
  29. package/src/vendor/approx-string-match/LICENSE +21 -0
  30. package/src/vendor/approx-string-match/README.MD +1 -0
  31. package/src/vendor/approx-string-match/index.ts +362 -0
  32. package/src/vendor/hypothesis/README.MD +1 -0
  33. package/src/vendor/hypothesis/anchoring/api-types.ts +309 -0
  34. package/src/vendor/hypothesis/anchoring/html.ts +134 -0
  35. package/src/vendor/hypothesis/anchoring/match-quote.ts +163 -0
  36. package/src/vendor/hypothesis/anchoring/placeholder.ts +59 -0
  37. package/src/vendor/hypothesis/anchoring/text-range.ts +327 -0
  38. package/src/vendor/hypothesis/anchoring/trim-range.ts +220 -0
  39. package/src/vendor/hypothesis/anchoring/types.ts +377 -0
  40. package/src/vendor/hypothesis/anchoring/xpath.ts +164 -0
  41. package/src/vendor/hypothesis/tsconfig.json +33 -0
  42. package/src/vendor/hypothesis/types/shared.ts +40 -0
  43. package/types/src/Loader.d.ts +33 -0
  44. package/types/src/comms/comms.d.ts +40 -0
  45. package/types/src/comms/index.d.ts +3 -0
  46. package/types/src/comms/keys.d.ts +2 -0
  47. package/types/src/comms/mid.d.ts +1 -0
  48. package/types/src/helpers/animation.d.ts +1 -0
  49. package/types/src/helpers/css.d.ts +4 -0
  50. package/types/src/helpers/document.d.ts +8 -0
  51. package/types/src/helpers/dom.d.ts +15 -0
  52. package/types/src/helpers/locator.d.ts +2 -0
  53. package/types/src/helpers/rect.d.ts +10 -0
  54. package/types/src/helpers/scrollSnapperHelper.d.ts +5 -0
  55. package/types/src/index.d.ts +3 -0
  56. package/types/src/modules/Decorator.d.ts +43 -0
  57. package/types/src/modules/Module.d.ts +11 -0
  58. package/types/src/modules/ModuleLibrary.d.ts +5 -0
  59. package/types/src/modules/Peripherals.d.ts +39 -0
  60. package/types/src/modules/ReflowablePeripherals.d.ts +37 -0
  61. package/types/src/modules/index.d.ts +3 -0
  62. package/types/src/modules/setup/FixedSetup.d.ts +9 -0
  63. package/types/src/modules/setup/ReflowableSetup.d.ts +9 -0
  64. package/types/src/modules/setup/Setup.d.ts +17 -0
  65. package/types/src/modules/snapper/ColumnSnapper.d.ts +41 -0
  66. package/types/src/modules/snapper/ScrollSnapper.d.ts +16 -0
  67. package/types/src/modules/snapper/Snapper.d.ts +11 -0
  68. package/types/src/vendor/approx-string-match/index.d.ts +54 -0
  69. package/types/src/vendor/hypothesis/anchoring/api-types.d.ts +266 -0
  70. package/types/src/vendor/hypothesis/anchoring/html.d.ts +17 -0
  71. package/types/src/vendor/hypothesis/anchoring/match-quote.d.ts +30 -0
  72. package/types/src/vendor/hypothesis/anchoring/placeholder.d.ts +32 -0
  73. package/types/src/vendor/hypothesis/anchoring/text-range.d.ts +103 -0
  74. package/types/src/vendor/hypothesis/anchoring/trim-range.d.ts +17 -0
  75. package/types/src/vendor/hypothesis/anchoring/types.d.ts +102 -0
  76. package/types/src/vendor/hypothesis/anchoring/xpath.d.ts +15 -0
  77. package/types/src/vendor/hypothesis/types/shared.d.ts +32 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2020 Robert Knight
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1 @@
1
+ From https://github.com/robertknight/approx-string-match-js/tree/master
@@ -0,0 +1,362 @@
1
+ /**
2
+ * Implementation of Myers' online approximate string matching algorithm [1],
3
+ * with additional optimizations suggested by [2].
4
+ *
5
+ * This has O((k/w) * n) expected-time where `n` is the length of the
6
+ * text, `k` is the maximum number of errors allowed (always <= the pattern
7
+ * length) and `w` is the word size. Because JS only supports bitwise operations
8
+ * on 32 bit integers, `w` is 32.
9
+ *
10
+ * As far as I am aware, there aren't any online algorithms which are
11
+ * significantly better for a wide range of input parameters. The problem can be
12
+ * solved faster using "filter then verify" approaches which first filter out
13
+ * regions of the text that cannot match using a "cheap" check and then verify
14
+ * the remaining potential matches. The verify step requires an algorithm such
15
+ * as this one however.
16
+ *
17
+ * The algorithm's approach is essentially to optimize the classic dynamic
18
+ * programming solution to the problem by computing columns of the matrix in
19
+ * word-sized chunks (ie. dealing with 32 chars of the pattern at a time) and
20
+ * avoiding calculating regions of the matrix where the minimum error count is
21
+ * guaranteed to exceed the input threshold.
22
+ *
23
+ * The paper consists of two parts, the first describes the core algorithm for
24
+ * matching patterns <= the size of a word (implemented by `advanceBlock` here).
25
+ * The second uses the core algorithm as part of a larger block-based algorithm
26
+ * to handle longer patterns.
27
+ *
28
+ * [1] G. Myers, “A Fast Bit-Vector Algorithm for Approximate String Matching
29
+ * Based on Dynamic Programming,” vol. 46, no. 3, pp. 395–415, 1999.
30
+ *
31
+ * [2] Šošić, M. (2014). An simd dynamic programming c/c++ library (Doctoral
32
+ * dissertation, Fakultet Elektrotehnike i računarstva, Sveučilište u Zagrebu).
33
+ */
34
+
35
+ /**
36
+ * Represents a match returned by a call to `search`.
37
+ */
38
+ export interface Match {
39
+ /** Start offset of match in text. */
40
+ start: number;
41
+ /** End offset of match in text. */
42
+ end: number;
43
+ /**
44
+ * The number of differences (insertions, deletions or substitutions) between
45
+ * the pattern and the approximate match in the text.
46
+ */
47
+ errors: number;
48
+ }
49
+
50
+ function reverse(s: string) {
51
+ return s.split("").reverse().join("");
52
+ }
53
+
54
+ /**
55
+ * Given the ends of approximate matches for `pattern` in `text`, find
56
+ * the start of the matches.
57
+ *
58
+ * @return Matches with the `start` property set.
59
+ */
60
+ function findMatchStarts(text: string, pattern: string, matches: Match[]) {
61
+ const patRev = reverse(pattern);
62
+
63
+ return matches.map((m) => {
64
+ // Find start of each match by reversing the pattern and matching segment
65
+ // of text and searching for an approx match with the same number of
66
+ // errors.
67
+ const minStart = Math.max(0, m.end - pattern.length - m.errors);
68
+ const textRev = reverse(text.slice(minStart, m.end));
69
+
70
+ // If there are multiple possible start points, choose the one that
71
+ // maximizes the length of the match.
72
+ const start = findMatchEnds(textRev, patRev, m.errors).reduce((min, rm) => {
73
+ if (m.end - rm.end < min) {
74
+ return m.end - rm.end;
75
+ }
76
+ return min;
77
+ }, m.end);
78
+
79
+ return {
80
+ start,
81
+ end: m.end,
82
+ errors: m.errors,
83
+ };
84
+ });
85
+ }
86
+
87
+ /**
88
+ * Internal context used when calculating blocks of a column.
89
+ */
90
+ interface Context {
91
+ /**
92
+ * Bit-arrays of positive vertical deltas.
93
+ *
94
+ * ie. `P[b][i]` is set if the vertical delta for the i'th row in the b'th
95
+ * block is positive.
96
+ */
97
+ P: Uint32Array;
98
+ /** Bit-arrays of negative vertical deltas. */
99
+ M: Uint32Array;
100
+ /** Bit masks with a single bit set indicating the last row in each block. */
101
+ lastRowMask: Uint32Array;
102
+ }
103
+
104
+ /**
105
+ * Return 1 if a number is non-zero or zero otherwise, without using
106
+ * conditional operators.
107
+ *
108
+ * This should get inlined into `advanceBlock` below by the JIT.
109
+ *
110
+ * Adapted from https://stackoverflow.com/a/3912218/434243
111
+ */
112
+ function oneIfNotZero(n: number) {
113
+ return ((n | -n) >> 31) & 1;
114
+ }
115
+
116
+ /**
117
+ * Block calculation step of the algorithm.
118
+ *
119
+ * From Fig 8. on p. 408 of [1], additionally optimized to replace conditional
120
+ * checks with bitwise operations as per Section 4.2.3 of [2].
121
+ *
122
+ * @param ctx - The pattern context object
123
+ * @param peq - The `peq` array for the current character (`ctx.peq.get(ch)`)
124
+ * @param b - The block level
125
+ * @param hIn - Horizontal input delta ∈ {1,0,-1}
126
+ * @return Horizontal output delta ∈ {1,0,-1}
127
+ */
128
+ function advanceBlock(ctx: Context, peq: Uint32Array, b: number, hIn: number) {
129
+ let pV = ctx.P[b];
130
+ let mV = ctx.M[b];
131
+ const hInIsNegative = hIn >>> 31; // 1 if hIn < 0 or 0 otherwise.
132
+ const eq = peq[b] | hInIsNegative;
133
+
134
+ // Step 1: Compute horizontal deltas.
135
+ const xV = eq | mV;
136
+ const xH = (((eq & pV) + pV) ^ pV) | eq;
137
+
138
+ let pH = mV | ~(xH | pV);
139
+ let mH = pV & xH;
140
+
141
+ // Step 2: Update score (value of last row of this block).
142
+ const hOut =
143
+ oneIfNotZero(pH & ctx.lastRowMask[b]) -
144
+ oneIfNotZero(mH & ctx.lastRowMask[b]);
145
+
146
+ // Step 3: Update vertical deltas for use when processing next char.
147
+ pH <<= 1;
148
+ mH <<= 1;
149
+
150
+ mH |= hInIsNegative;
151
+ pH |= oneIfNotZero(hIn) - hInIsNegative; // set pH[0] if hIn > 0
152
+
153
+ pV = mH | ~(xV | pH);
154
+ mV = pH & xV;
155
+
156
+ ctx.P[b] = pV;
157
+ ctx.M[b] = mV;
158
+
159
+ return hOut;
160
+ }
161
+
162
+ /**
163
+ * Find the ends and error counts for matches of `pattern` in `text`.
164
+ *
165
+ * Only the matches with the lowest error count are reported. Other matches
166
+ * with error counts <= maxErrors are discarded.
167
+ *
168
+ * This is the block-based search algorithm from Fig. 9 on p.410 of [1].
169
+ */
170
+ function findMatchEnds(text: string, pattern: string, maxErrors: number) {
171
+ if (pattern.length === 0) {
172
+ return [];
173
+ }
174
+
175
+ // Clamp error count so we can rely on the `maxErrors` and `pattern.length`
176
+ // rows being in the same block below.
177
+ maxErrors = Math.min(maxErrors, pattern.length);
178
+
179
+ const matches = [];
180
+
181
+ // Word size.
182
+ const w = 32;
183
+
184
+ // Index of maximum block level.
185
+ const bMax = Math.ceil(pattern.length / w) - 1;
186
+
187
+ // Context used across block calculations.
188
+ const ctx = {
189
+ P: new Uint32Array(bMax + 1),
190
+ M: new Uint32Array(bMax + 1),
191
+ lastRowMask: new Uint32Array(bMax + 1),
192
+ };
193
+ ctx.lastRowMask.fill(1 << 31);
194
+ ctx.lastRowMask[bMax] = 1 << (pattern.length - 1) % w;
195
+
196
+ // Dummy "peq" array for chars in the text which do not occur in the pattern.
197
+ const emptyPeq = new Uint32Array(bMax + 1);
198
+
199
+ // Map of UTF-16 character code to bit vector indicating positions in the
200
+ // pattern that equal that character.
201
+ const peq = new Map<number, Uint32Array>();
202
+
203
+ // Version of `peq` that only stores mappings for small characters. This
204
+ // allows faster lookups when iterating through the text because a simple
205
+ // array lookup can be done instead of a hash table lookup.
206
+ const asciiPeq = [] as Uint32Array[];
207
+ for (let i = 0; i < 256; i++) {
208
+ asciiPeq.push(emptyPeq);
209
+ }
210
+
211
+ // Calculate `ctx.peq` - a map of character values to bitmasks indicating
212
+ // positions of that character within the pattern, where each bit represents
213
+ // a position in the pattern.
214
+ for (let c = 0; c < pattern.length; c += 1) {
215
+ const val = pattern.charCodeAt(c);
216
+ if (peq.has(val)) {
217
+ // Duplicate char in pattern.
218
+ continue;
219
+ }
220
+
221
+ const charPeq = new Uint32Array(bMax + 1);
222
+ peq.set(val, charPeq);
223
+ if (val < asciiPeq.length) {
224
+ asciiPeq[val] = charPeq;
225
+ }
226
+
227
+ for (let b = 0; b <= bMax; b += 1) {
228
+ charPeq[b] = 0;
229
+
230
+ // Set all the bits where the pattern matches the current char (ch).
231
+ // For indexes beyond the end of the pattern, always set the bit as if the
232
+ // pattern contained a wildcard char in that position.
233
+ for (let r = 0; r < w; r += 1) {
234
+ const idx = b * w + r;
235
+ if (idx >= pattern.length) {
236
+ continue;
237
+ }
238
+
239
+ const match = pattern.charCodeAt(idx) === val;
240
+ if (match) {
241
+ charPeq[b] |= 1 << r;
242
+ }
243
+ }
244
+ }
245
+ }
246
+
247
+ // Index of last-active block level in the column.
248
+ let y = Math.max(0, Math.ceil(maxErrors / w) - 1);
249
+
250
+ // Initialize maximum error count at bottom of each block.
251
+ const score = new Uint32Array(bMax + 1);
252
+ for (let b = 0; b <= y; b += 1) {
253
+ score[b] = (b + 1) * w;
254
+ }
255
+ score[bMax] = pattern.length;
256
+
257
+ // Initialize vertical deltas for each block.
258
+ for (let b = 0; b <= y; b += 1) {
259
+ ctx.P[b] = ~0;
260
+ ctx.M[b] = 0;
261
+ }
262
+
263
+ // Process each char of the text, computing the error count for `w` chars of
264
+ // the pattern at a time.
265
+ for (let j = 0; j < text.length; j += 1) {
266
+ // Lookup the bitmask representing the positions of the current char from
267
+ // the text within the pattern.
268
+ const charCode = text.charCodeAt(j);
269
+ let charPeq;
270
+
271
+ if (charCode < asciiPeq.length) {
272
+ // Fast array lookup.
273
+ charPeq = asciiPeq[charCode];
274
+ } else {
275
+ // Slower hash table lookup.
276
+ charPeq = peq.get(charCode);
277
+ if (typeof charPeq === "undefined") {
278
+ charPeq = emptyPeq;
279
+ }
280
+ }
281
+
282
+ // Calculate error count for blocks that we definitely have to process for
283
+ // this column.
284
+ let carry = 0;
285
+ for (let b = 0; b <= y; b += 1) {
286
+ carry = advanceBlock(ctx, charPeq, b, carry);
287
+ score[b] += carry;
288
+ }
289
+
290
+ // Check if we also need to compute an additional block, or if we can reduce
291
+ // the number of blocks processed for the next column.
292
+ if (
293
+ score[y] - carry <= maxErrors &&
294
+ y < bMax &&
295
+ (charPeq[y + 1] & 1 || carry < 0)
296
+ ) {
297
+ // Error count for bottom block is under threshold, increase the number of
298
+ // blocks processed for this column & next by 1.
299
+ y += 1;
300
+
301
+ ctx.P[y] = ~0;
302
+ ctx.M[y] = 0;
303
+
304
+ let maxBlockScore;
305
+ if (y === bMax) {
306
+ const remainder = pattern.length % w;
307
+ maxBlockScore = remainder === 0 ? w : remainder;
308
+ } else {
309
+ maxBlockScore = w;
310
+ }
311
+
312
+ score[y] =
313
+ score[y - 1] +
314
+ maxBlockScore -
315
+ carry +
316
+ advanceBlock(ctx, charPeq, y, carry);
317
+ } else {
318
+ // Error count for bottom block exceeds threshold, reduce the number of
319
+ // blocks processed for the next column.
320
+ while (y > 0 && score[y] >= maxErrors + w) {
321
+ y -= 1;
322
+ }
323
+ }
324
+
325
+ // If error count is under threshold, report a match.
326
+ if (y === bMax && score[y] <= maxErrors) {
327
+ if (score[y] < maxErrors) {
328
+ // Discard any earlier, worse matches.
329
+ matches.splice(0, matches.length);
330
+ }
331
+
332
+ matches.push({
333
+ start: -1,
334
+ end: j + 1,
335
+ errors: score[y],
336
+ });
337
+
338
+ // Because `search` only reports the matches with the lowest error count,
339
+ // we can "ratchet down" the max error threshold whenever a match is
340
+ // encountered and thereby save a small amount of work for the remainder
341
+ // of the text.
342
+ maxErrors = score[y];
343
+ }
344
+ }
345
+
346
+ return matches;
347
+ }
348
+
349
+ /**
350
+ * Search for the closest matches for `pattern` in `text`.
351
+ *
352
+ * Returns all matches that have the lowest number of errors, or an empty
353
+ * array if no match was found with `maxErrors` or fewer errors.
354
+ */
355
+ export default function search(
356
+ text: string,
357
+ pattern: string,
358
+ maxErrors: number
359
+ ): Match[] {
360
+ const matches = findMatchEnds(text, pattern, maxErrors);
361
+ return findMatchStarts(text, pattern, matches);
362
+ }
@@ -0,0 +1 @@
1
+ The code in this module has been directly copied from https://github.com/hypothesis/client/tree/529a0f8e2242d07736d751715974a4356c0a69f1/src/annotator/anchoring, released under the 2-Clause BSD license.
@@ -0,0 +1,309 @@
1
+ import type { ClientAnnotationData } from '../types/shared';
2
+
3
+ /**
4
+ * Type definitions for objects returned from the Hypothesis API.
5
+ *
6
+ * The canonical reference is the API documentation at
7
+ * https://h.readthedocs.io/en/latest/api-reference/
8
+ */
9
+
10
+ /**
11
+ * Metadata specifying how to call an API route.
12
+ */
13
+ export type RouteMetadata = {
14
+ /** HTTP method */
15
+ method: string;
16
+ /** URL template */
17
+ url: string;
18
+ /** Description of API route */
19
+ desc: string;
20
+ };
21
+
22
+ /** A nested map of API route name to route metadata. */
23
+ export type RouteMap = { [key: string]: RouteMap | RouteMetadata };
24
+
25
+ /**
26
+ * Structure of the API index response (`/api`).
27
+ */
28
+ export type IndexResponse = {
29
+ links: RouteMap;
30
+ };
31
+
32
+ /**
33
+ * Structure of the Hypothesis links response (`/api/links`).
34
+ *
35
+ * This is a map of link name (eg. "account.settings") to URL. The URL may
36
+ * include ":"-prefixed placeholders/variables.
37
+ */
38
+ export type LinksResponse = Record<string, string>;
39
+
40
+ /**
41
+ * Selector which indicates the time range within a video or audio file that
42
+ * an annotation refers to.
43
+ */
44
+ export type MediaTimeSelector = {
45
+ type: 'MediaTimeSelector';
46
+
47
+ /** Offset from start of media in seconds. */
48
+ start: number;
49
+ /** Offset from start of media in seconds. */
50
+ end: number;
51
+ };
52
+
53
+ /**
54
+ * Selector which identifies a document region using the selected text plus
55
+ * the surrounding context.
56
+ */
57
+ export type TextQuoteSelector = {
58
+ type: 'TextQuoteSelector';
59
+ exact: string;
60
+ prefix?: string;
61
+ suffix?: string;
62
+ };
63
+
64
+ /**
65
+ * Selector which identifies a document region using UTF-16 character offsets
66
+ * in the document body's `textContent`.
67
+ */
68
+ export type TextPositionSelector = {
69
+ type: 'TextPositionSelector';
70
+ start: number;
71
+ end: number;
72
+ };
73
+
74
+ /**
75
+ * Selector which identifies a document region using XPaths and character offsets.
76
+ */
77
+ export type RangeSelector = {
78
+ type: 'RangeSelector';
79
+ startContainer: string;
80
+ endContainer: string;
81
+ startOffset: number;
82
+ endOffset: number;
83
+ };
84
+
85
+ /**
86
+ * Selector which identifies the Content Document within an EPUB that an
87
+ * annotation was made in.
88
+ */
89
+ export type EPUBContentSelector = {
90
+ type: 'EPUBContentSelector';
91
+
92
+ /**
93
+ * URL of the content document. This should be an absolute HTTPS URL if
94
+ * available, but may be relative to the root of the EPUB.
95
+ */
96
+ url: string;
97
+
98
+ /**
99
+ * EPUB Canonical Fragment Identifier for the table of contents entry that
100
+ * corresponds to the content document.
101
+ */
102
+ cfi?: string;
103
+
104
+ /** Title of the content document. */
105
+ title?: string;
106
+ };
107
+
108
+ /**
109
+ * Selector which identifies the page of a document that an annotation was made
110
+ * on.
111
+ *
112
+ * This selector is only applicable for document types where the association of
113
+ * content and page numbers can be done in a way that is independent of the
114
+ * viewer and display settings. This includes inherently paginated documents
115
+ * such as PDFs, but also content such as EPUBs when they include information
116
+ * about the location of page breaks in printed versions of a book. It does
117
+ * not include ordinary web pages or EPUBs without page break information
118
+ * however.
119
+ */
120
+ export type PageSelector = {
121
+ type: 'PageSelector';
122
+
123
+ /** The zero-based index of the page in the document's page sequence. */
124
+ index: number;
125
+
126
+ /**
127
+ * Either the page number that is displayed on the page, or the 1-based
128
+ * number of the page in the document's page sequence, if the pages do not
129
+ * have numbers on them.
130
+ */
131
+ label?: string;
132
+ };
133
+
134
+ /**
135
+ * Serialized representation of a region of a document which an annotation
136
+ * pertains to.
137
+ */
138
+ export type Selector =
139
+ | TextQuoteSelector
140
+ | TextPositionSelector
141
+ | RangeSelector
142
+ | EPUBContentSelector
143
+ | MediaTimeSelector
144
+ | PageSelector;
145
+
146
+ /**
147
+ * An entry in the `target` field of an annotation which identifies the document
148
+ * and region of the document that it refers to.
149
+ */
150
+ export type Target = {
151
+ /** URI of the document */
152
+ source: string;
153
+ /** Region of the document */
154
+ selector?: Selector[];
155
+ };
156
+
157
+ export type UserInfo = {
158
+ display_name: string | null;
159
+ };
160
+
161
+ export type APIAnnotationData = {
162
+ /**
163
+ * The server-assigned ID for the annotation. This is only set once the
164
+ * annotation has been saved to the backend.
165
+ */
166
+ id?: string;
167
+
168
+ references?: string[];
169
+ created: string;
170
+ flagged?: boolean;
171
+ group: string;
172
+ updated: string;
173
+ tags: string[];
174
+ text: string;
175
+ uri: string;
176
+ user: string;
177
+ hidden: boolean;
178
+
179
+ document: {
180
+ title: string;
181
+ };
182
+
183
+ permissions: {
184
+ read: string[];
185
+ update: string[];
186
+ delete: string[];
187
+ };
188
+
189
+ /**
190
+ * The document and region this annotation refers to.
191
+ *
192
+ * The Hypothesis API structure allows for multiple targets, but the h
193
+ * server only supports one target per annotation.
194
+ */
195
+ target: Target[];
196
+
197
+ moderation?: {
198
+ flagCount: number;
199
+ };
200
+
201
+ links: {
202
+ /**
203
+ * A "bouncer" URL that takes the user to see the annotation in context
204
+ */
205
+ incontext?: string;
206
+
207
+ /** URL to view the annotation by itself. */
208
+ html?: string;
209
+ };
210
+
211
+ user_info?: UserInfo;
212
+ };
213
+
214
+ export type Annotation = ClientAnnotationData & APIAnnotationData;
215
+
216
+ /**
217
+ * An annotation which has been saved to the backend and assigned an ID.
218
+ */
219
+ export type SavedAnnotation = Annotation & { id: string };
220
+
221
+ export type Profile = {
222
+ userid: string | null;
223
+ preferences: {
224
+ show_sidebar_tutorial?: boolean;
225
+ };
226
+ features: Record<string, boolean>;
227
+ user_info?: UserInfo;
228
+ };
229
+
230
+ export type Organization = {
231
+ name: string;
232
+ logo: string;
233
+ id: string;
234
+ default?: boolean;
235
+ };
236
+
237
+ export type GroupScopes = {
238
+ enforced: boolean;
239
+ uri_patterns: string[];
240
+ };
241
+
242
+ export type Group = {
243
+ /** The "pubid" of the group, unique per authority. */
244
+ id: string;
245
+ /** Fully-qualified ID with authority. */
246
+ groupid?: string;
247
+ type: 'private' | 'open';
248
+ /**
249
+ * Note: This field is nullable in the API, but we assign a default organization in the client.
250
+ */
251
+ organization: Organization;
252
+ scopes: GroupScopes | null;
253
+ links: {
254
+ html?: string;
255
+ };
256
+
257
+ // Properties not present on API objects, but added in the client.
258
+ logo: string;
259
+ isMember: boolean;
260
+ isScopedToUri: boolean;
261
+ name: string;
262
+ canLeave: boolean;
263
+ };
264
+
265
+ /**
266
+ * All Groups have an `id`, which is a server-assigned identifier. This is the
267
+ * primary field used to identify a Group.
268
+ *
269
+ * In some cases, specifically LMS, it is necessary for an outside service to
270
+ * be able to specify its own identifier. This gets stored in the `groupid`
271
+ * field of a Group. Only some Groups have a `groupid`.
272
+ *
273
+ * Application logic operates on `id`s, but we may receive `groupid`s in some
274
+ * cases from outside sevices, e.g. the `changeFocusModeUser` RPC method.
275
+ */
276
+ export type GroupIdentifier = NonNullable<Group['id'] | Group['groupid']>;
277
+
278
+ /**
279
+ * Query parameters for an `/api/search` API call.
280
+ *
281
+ * This type currently includes params that we've actually used.
282
+ *
283
+ * See https://h.readthedocs.io/en/latest/api-reference/#tag/annotations/paths/~1search/get
284
+ * for the complete list and usage of each.
285
+ */
286
+ export type SearchQuery = {
287
+ limit?: number;
288
+ uri?: string[];
289
+ group?: string;
290
+ order?: string;
291
+ references?: string;
292
+ search_after?: string;
293
+ sort?: string;
294
+ /** Undocument param that causes replies to be returned in a separate `replies` field. */
295
+ _separate_replies?: boolean;
296
+ };
297
+
298
+ /**
299
+ * Response to an `/api/search` API call.
300
+ *
301
+ * See https://h.readthedocs.io/en/latest/api-reference/#tag/annotations/paths/~1search/get
302
+ */
303
+ export type SearchResponse = {
304
+ total: number;
305
+ rows: Annotation[];
306
+
307
+ /** Undocumented property that is populated if `_separate_replies` query param was specified. */
308
+ replies?: Annotation[];
309
+ };