@2018kguo/recto 0.3.0 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/pool.js CHANGED
@@ -39,6 +39,7 @@ class Pool {
39
39
  #limit;
40
40
  #ceiling;
41
41
  #assetBase;
42
+ #maxDecodedBytes;
42
43
  #threads = [];
43
44
  /** Started and not yet ready. */
44
45
  #startingThreads = new Set();
@@ -46,10 +47,11 @@ class Pool {
46
47
  #nextFile = 0;
47
48
  #nextId = 0;
48
49
  #closed = false;
49
- constructor(limit, assetBase) {
50
+ constructor(limit, assetBase, maxDecodedBytes) {
50
51
  this.#limit = limit;
51
52
  this.#ceiling = limit;
52
53
  this.#assetBase = assetBase;
54
+ this.#maxDecodedBytes = maxDecodedBytes;
53
55
  }
54
56
  #spawn() {
55
57
  const thread = { worker: null, running: null };
@@ -147,7 +149,7 @@ class Pool {
147
149
  };
148
150
  thread.worker = worker;
149
151
  }
150
- const start = { assetBase: this.#assetBase };
152
+ const start = { assetBase: this.#assetBase, maxDecodedBytes: this.#maxDecodedBytes };
151
153
  thread.worker.postMessage(start);
152
154
  }
153
155
  catch (error) {
@@ -240,13 +242,15 @@ class Pool {
240
242
  text: (index) => call("text", index),
241
243
  objects: (index) => call("objects", index),
242
244
  annotations: (index) => call("annotations", index),
245
+ links: (index) => call("links", index),
243
246
  outline: () => call("outline"),
244
- render: (index, renderOptions) => {
247
+ render: ((index, renderOptions) => {
245
248
  if (renderOptions?.signal) {
246
249
  return Promise.reject(new TypeError("a pool's render takes no signal: a call that's running can't be stopped. pool.close() ends all of them."));
247
250
  }
248
- return call("render", index, { width: renderOptions?.width, maxHeight: renderOptions?.maxHeight });
249
- },
251
+ const { width, maxHeight, region } = renderOptions ?? {};
252
+ return call("render", index, region === undefined ? { width, maxHeight } : { width, maxHeight, region });
253
+ }),
250
254
  close,
251
255
  [Symbol.asyncDispose]: close,
252
256
  };
@@ -283,5 +287,9 @@ export function startPool(options) {
283
287
  const assetBase = options.assetBase !== undefined && typeof location !== "undefined"
284
288
  ? new URL(options.assetBase, location.href).href
285
289
  : options.assetBase;
286
- return new Pool(threads, assetBase);
290
+ const maxDecodedBytes = options.maxDecodedBytes;
291
+ if (maxDecodedBytes !== undefined && !(typeof maxDecodedBytes === "number" && maxDecodedBytes >= 0)) {
292
+ throw new RangeError("maxDecodedBytes must be a number of bytes, 0 or more");
293
+ }
294
+ return new Pool(threads, assetBase, maxDecodedBytes);
287
295
  }
package/dist/ranged.d.ts CHANGED
@@ -43,19 +43,37 @@ export type PdfRangedStats = {
43
43
  export type PdfRangedDocument = PdfDocument & {
44
44
  stats(): PdfRangedStats;
45
45
  };
46
+ /**
47
+ * Bytes `start..end`. With `yieldTail`, read no further than that many bytes before the file's
48
+ * end, where a suffix asked for beside it starts, so no byte comes twice.
49
+ */
46
50
  type Range = {
47
51
  start: number;
48
52
  end: number;
53
+ yieldTail?: number;
54
+ };
55
+ /** The file's last `suffix` bytes (`bytes=-n`), asked for before its size is known. */
56
+ type Suffix = {
57
+ suffix: number;
49
58
  };
59
+ type Request = Range | Suffix;
60
+ /** `received`: the bytes read off the response, `bytes` and any read past it. */
50
61
  type Answer = {
51
62
  start: number;
52
63
  bytes: Uint8Array;
53
64
  length: number;
54
65
  etag: string | null;
55
66
  status: number;
67
+ received: number;
56
68
  };
57
- /** Fetches `ranges`; `limit` is how many bytes may still arrive. */
58
- type Fetch = (ranges: Range[], timeoutMs: number, limit: number) => Answer[];
69
+ /**
70
+ * Fetches `requests` in parallel; `limit` is how many bytes may still arrive. A range that
71
+ * fails throws. A suffix that isn't answered as one (a server that ignores or refuses it)
72
+ * gives null, and isn't counted: the caller asks for the tail by its offset instead.
73
+ */
74
+ type Answers = (Answer | null)[];
75
+ type Fetch = (requests: Request[], timeoutMs: number, limit: number) => Answers;
76
+ type FetchAsync = (requests: Request[], timeoutMs: number, limit: number) => Promise<Answers>;
59
77
  /** Fetched chunks of one file and the policy for fetching more. */
60
78
  declare class RangeLoader {
61
79
  #private;
@@ -71,25 +89,37 @@ declare class RangeLoader {
71
89
  signal: AbortSignal | undefined;
72
90
  });
73
91
  stats(): PdfRangedStats;
74
- /** Fetches chunks `firstChunk..endChunk`, keeping only those not held yet. */
75
- fetchChunks(firstChunk: number, endChunk: number): void;
92
+ /**
93
+ * The first round: the head and, in parallel, the tail as a suffix, then the last
94
+ * cross-reference section if the tail didn't hold it. A file the head covers needs no more;
95
+ * a server that doesn't answer the suffix gets the tail by offset in a round of its own.
96
+ */
97
+ begin(fetchAsync: FetchAsync | null): Promise<void>;
98
+ /**
99
+ * `failure`, or when what's held shows the file isn't a PDF (see `notPdfBytes`), that it isn't: an
100
+ * error or sign-in page fails to parse, or runs into `maxBytes`, and neither says why. Only when
101
+ * enough of the first KiB is held to tell.
102
+ */
103
+ explain(failure: unknown): unknown;
76
104
  /**
77
105
  * The `startxref` offset in the fetched last chunk, if it names one. Null for a linearized
78
106
  * file, whose trailer points at the first-page section near the head.
79
107
  */
80
108
  startxref(): number | null;
81
109
  /**
82
- * Copies [offset, offset + out.length) into `out`, fetching what is missing first. On a
83
- * failed fetch it records the failure and fails the read; the call that made it then
84
- * throws the failure.
110
+ * Copies [offset, offset + out.length) into `out`, fetching what is missing first, and if it
111
+ * fetches, `ahead` bytes past it too, as far as the budget allows: the engine's guess at what
112
+ * it reads next, which then costs no round trip of its own. On a failed fetch it records the
113
+ * failure and fails the read; the call that made it then throws the failure.
85
114
  */
86
- read(offset: number, out: Uint8Array): boolean;
115
+ read(offset: number, out: Uint8Array, ahead?: number): boolean;
87
116
  }
88
117
  /**
89
- * Starts a ranged read of `source`: the head, then (for a larger file) the tail and its last
90
- * cross-reference section. Blocks while it fetches.
118
+ * Starts a ranged read of `source`: the head and tail, then the last cross-reference section
119
+ * if the tail didn't hold it. Blocks while it fetches, except in a browser, where these
120
+ * rounds are `fetch` calls.
91
121
  */
92
- export declare function startRangeLoader(source: string | Uint8Array, options?: PdfRangedOpenOptions): RangeLoader;
122
+ export declare function startRangeLoader(source: string | Uint8Array, options?: PdfRangedOpenOptions): Promise<RangeLoader>;
93
123
  /**
94
124
  * The caller's source in a form that stays valid across an await: bytes copied, a URL as an
95
125
  * absolute http(s) string. Runs before anything asynchronous.