rmapi-js 12.0.3 → 13.0.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.
package/dist/lru.d.ts CHANGED
@@ -1,8 +1,8 @@
1
- export declare class LruCache extends Map<string, string | null> {
1
+ export declare class LruCache extends Map<string, Uint8Array | null> {
2
2
  #private;
3
- constructor(maxSize: number, entries?: Iterable<[string, string | null]>);
4
- get(key: string): string | null | undefined;
5
- set(key: string, value: string | null): this;
3
+ constructor(maxSize: number, entries?: Iterable<[string, Uint8Array | null]>);
4
+ get(key: string): Uint8Array | null | undefined;
5
+ set(key: string, value: Uint8Array | null): this;
6
6
  delete(key: string): boolean;
7
7
  clear(): void;
8
8
  }
package/dist/lru.js CHANGED
@@ -23,10 +23,10 @@ export class LruCache extends Map {
23
23
  this.#currentSize += key.length; // adding a new key
24
24
  }
25
25
  else if (existing !== null) {
26
- this.#currentSize -= existing.length; // removing old value
26
+ this.#currentSize -= existing.byteLength; // removing old value
27
27
  }
28
28
  if (value !== null) {
29
- this.#currentSize += value.length;
29
+ this.#currentSize += value.byteLength;
30
30
  }
31
31
  // delete existing value
32
32
  super.delete(key);
@@ -38,7 +38,7 @@ export class LruCache extends Map {
38
38
  super.delete(oldestKey);
39
39
  this.#currentSize -= oldestKey.length;
40
40
  if (oldestValue !== null) {
41
- this.#currentSize -= oldestValue.length;
41
+ this.#currentSize -= oldestValue.byteLength;
42
42
  }
43
43
  }
44
44
  // finally insert new key and return
@@ -52,7 +52,7 @@ export class LruCache extends Map {
52
52
  }
53
53
  super.delete(key);
54
54
  if (value !== null) {
55
- this.#currentSize -= value.length;
55
+ this.#currentSize -= value.byteLength;
56
56
  }
57
57
  this.#currentSize -= key.length;
58
58
  return true;
package/dist/raw.d.ts CHANGED
@@ -1,8 +1,17 @@
1
+ import "core-js/modules/es.async-disposable-stack.constructor.js";
2
+ import "core-js/modules/es.symbol.async-dispose.js";
3
+ import "core-js/modules/es.uint8-array.from-base64.js";
1
4
  import "core-js/modules/es.uint8-array.from-hex.js";
2
5
  import "core-js/modules/es.uint8-array.to-base64.js";
3
6
  import "core-js/modules/es.uint8-array.to-hex.js";
4
7
  import { type RmPageV5 } from "./rm5.js";
5
8
  import { type RmScene } from "./rm6.js";
9
+ /** the dump format version; absent means the original text-only format */
10
+ export declare const CACHE_VERSION = 2;
11
+ /** marks a dumped cache entry stored as utf-8 text */
12
+ export declare const TEXT_PREFIX = "t";
13
+ /** marks a dumped cache entry stored as base64 */
14
+ export declare const BYTES_PREFIX = "b";
6
15
  /**
7
16
  * a parsed reMarkable `.rm` page
8
17
  *
@@ -22,6 +31,17 @@ export type RmPage = RmPageV5 | RmScene;
22
31
  * @returns the parsed page
23
32
  */
24
33
  export declare function parseRm(data: Uint8Array): RmPage;
34
+ /**
35
+ * serialize a parsed reMarkable `.rm` page back to bytes
36
+ *
37
+ * The inverse of {@link parseRm | `parseRm`}: versions 3 and 5 render from a
38
+ * flat {@link RmPageV5 | `RmPageV5`}, version 6 from an
39
+ * {@link RmScene | `RmScene`}.
40
+ *
41
+ * @param page - the page to render
42
+ * @returns the `.rm` file bytes
43
+ */
44
+ export declare function serializeRm(page: RmPage): Uint8Array;
25
45
  /** request types */
26
46
  export type RequestMethod = "POST" | "GET" | "PUT" | "DELETE" | "PATCH" | "OPTIONS";
27
47
  /** the supported upload mime types */
@@ -59,8 +79,38 @@ export interface RawEntry extends ItemRef {
59
79
  /** the total size of everything in the collection */
60
80
  size: number;
61
81
  }
82
+ /**
83
+ * an entry whose upload is still in flight
84
+ *
85
+ * The hash is a digest of the bytes, so the entry describes the upload before
86
+ * the server has it — you can splice it into a parent index immediately.
87
+ * Disposing waits for the upload to land, and throws if it failed, so scoping
88
+ * it keeps a root hash from being written against a file that never arrived:
89
+ *
90
+ * ```ts
91
+ * let hash;
92
+ * {
93
+ * await using entry = await raw.putFile(`${id}.pdf`, bytes);
94
+ * hash = entry.hash;
95
+ * }
96
+ * await raw.putRootHash(hash, generation);
97
+ * ```
98
+ *
99
+ * Where the number of uploads isn't known until runtime, collect them in an
100
+ * `AsyncDisposableStack` with `stack.use(entry)`; the scope holding the stack
101
+ * waits for all of them.
102
+ */
103
+ export interface PendingEntry extends RawEntry, AsyncDisposable {
104
+ }
62
105
  /** the type of files reMarkable supports */
63
106
  export type FileType = "epub" | "pdf" | "notebook";
107
+ /**
108
+ * the kind of entry this is
109
+ *
110
+ * DocumentType is an epub, pdf, or notebook, CollectionType is a folder, and
111
+ * TemplateType is a template.
112
+ */
113
+ export type EntryType = "DocumentType" | "CollectionType" | "TemplateType";
64
114
  /**
65
115
  * a parsed entries file
66
116
  *
@@ -371,6 +421,44 @@ export interface TemplateContent {
371
421
  }
372
422
  /** content metadata for any item */
373
423
  export type Content = CollectionContent | LegacyCollectionContent | DocumentContent | LegacyDocumentContent | TemplateContent;
424
+ /** a rectangle with its origin at the top left of the source document page */
425
+ export interface HighlightRect {
426
+ /** the distance from the left edge of the page */
427
+ x: number;
428
+ /** the distance from the top edge of the page */
429
+ y: number;
430
+ /** the width */
431
+ width: number;
432
+ /** the height */
433
+ height: number;
434
+ }
435
+ /**
436
+ * a single text-highlight fragment on a pdf or epub page
437
+ *
438
+ * reMarkable splits one highlighted passage into a fragment per line it spans.
439
+ */
440
+ export interface Highlight {
441
+ /** the highlighted text */
442
+ text: string;
443
+ /** [speculative] an index into the highlight palette, not the pen palette */
444
+ color: number;
445
+ /** the character offset of the highlight within the page's text */
446
+ start: number;
447
+ /** the number of characters highlighted */
448
+ length: number;
449
+ /** the rectangles the highlight spans, one per line */
450
+ rects: HighlightRect[];
451
+ }
452
+ /** a single layer on a page */
453
+ export interface PageLayer {
454
+ /** the layer's display name */
455
+ name: string;
456
+ }
457
+ /** a page's layer metadata, from `<docid>/<pageid>-metadata.json` */
458
+ export interface PageMetadata {
459
+ /** the page's layers, in order */
460
+ layers: PageLayer[];
461
+ }
374
462
  /**
375
463
  * item level metadata
376
464
  *
@@ -402,13 +490,8 @@ export interface Metadata {
402
490
  pinned: boolean;
403
491
  /** [unknown] */
404
492
  synced?: boolean | null;
405
- /**
406
- * the type of item this corresponds to
407
- *
408
- * DocumentType is a document, an epub, pdf, or notebook, CollectionType is a
409
- * folder.
410
- */
411
- type: "DocumentType" | "CollectionType" | "TemplateType";
493
+ /** the type of item this corresponds to */
494
+ type: EntryType;
412
495
  /** whether this is this a newly-installed template */
413
496
  new?: boolean;
414
497
  /**
@@ -464,9 +547,10 @@ type AuthedFetch = (method: RequestMethod, url: string, init?: {
464
547
  * - `<docid>.content` - a json file roughly describing document properties (see {@link DocumentContent | `DocumentContent`})
465
548
  * - `<docid>.metadata` - metadata about the document (see {@link Metadata | `Metadata`})
466
549
  * - `<docid>.pagedata` - a text file where each line is the template of that page
550
+ * - `<docid>.template` - a template attached to the item (see {@link TemplateContent | `TemplateContent`})
467
551
  * - `<docid>/<pageid>.rm` - [speculative] raw remarkable vectors, text, etc
468
- * - `<docid>/<pageid>-metadata.json` - [speculative] metadata about the individual page
469
- * - `<docid>.highlights/<pageid>.json` - [speculative] highlights on the page
552
+ * - `<docid>/<pageid>-metadata.json` - page layer metadata (see {@link PageMetadata | `PageMetadata`})
553
+ * - `<docid>.highlights/<pageid>.json` - text highlights on the page (see {@link Highlight | `Highlight`})
470
554
  *
471
555
  * Some items will have both a `.pdf` and `.epub` file, likely due to preparing
472
556
  * for export. Collections only have `.content` and `.metadata` files, with
@@ -475,9 +559,12 @@ type AuthedFetch = (method: RequestMethod, url: string, init?: {
475
559
  * ## Caching
476
560
  *
477
561
  * Since everything is tied to the hash of it's contents, we can agressively
478
- * cache results. We assume that text contents are "small" and so fully cache
479
- * them, where as binary files we treat as large and only store that we know
480
- * they exist to prevent future writes.
562
+ * cache results. Anything up to `maxCachedBytes` is kept as the bytes that were
563
+ * transferred; anything larger records only that the hash exists, which is
564
+ * enough to skip writing it again.
565
+ *
566
+ * A dump is tied to the account it came from, since a known hash is taken as
567
+ * proof the server already holds that file. Don't share one between accounts.
481
568
  *
482
569
  * By default, this only persists as long as the api instance is alive. However,
483
570
  * for performance reasons, you should call {@link dumpCache | `dumpCache`} to
@@ -489,8 +576,7 @@ type AuthedFetch = (method: RequestMethod, url: string, init?: {
489
576
  */
490
577
  export declare class RawRemarkable {
491
578
  #private;
492
- constructor(authedFetch: AuthedFetch, cache: Map<string, string | null>, rawHost: string, uploadHost: string);
493
- /** make an authorized request to remarkable */
579
+ constructor(authedFetch: AuthedFetch, cache: Map<string, Uint8Array | null>, rawHost: string, uploadHost: string, maxCachedBytes: number);
494
580
  /**
495
581
  * gets the root hash and the current generation
496
582
  *
@@ -520,18 +606,18 @@ export declare class RawRemarkable {
520
606
  * @param ref - a reference to the stored file (see {@link getHash})
521
607
  * @returns the text
522
608
  */
523
- getText({ id: fileName, hash }: ItemRef): Promise<string>;
609
+ getText(ref: ItemRef): Promise<string>;
524
610
  /**
525
611
  * get the entries associated with a list hash
526
612
  *
527
613
  * A list hash is the root hash, or any hash with the type 80000000. NOTE
528
614
  * these are hashed differently than files.
529
615
  *
530
- * @param ref - a reference whose `id` is `"root.docSchema"` for the root, or
531
- * `"<id>.docSchema"` for a sub-document's entry index
616
+ * @param ref - a reference whose `id` is the bare document id, or `"root"`
617
+ * for the root index
532
618
  * @returns the entries
533
619
  */
534
- getEntries(ref: ItemRef): Promise<Entries>;
620
+ getEntries({ id, hash }: ItemRef): Promise<Entries>;
535
621
  /**
536
622
  * get the parsed and validated `Content` of a content hash
537
623
  *
@@ -559,13 +645,34 @@ export declare class RawRemarkable {
559
645
  * @returns the parsed page
560
646
  */
561
647
  getRm(ref: ItemRef): Promise<RmPage>;
648
+ /**
649
+ * get the parsed text highlights of a page
650
+ *
651
+ * @param ref - a reference to a `<docid>.highlights/<pageid>.json` file
652
+ * @returns the page's highlights; [speculative] each inner array groups the
653
+ * fragments of one highlighted passage
654
+ */
655
+ getHighlights(ref: ItemRef): Promise<Highlight[][]>;
656
+ /**
657
+ * get a template stored as a `<docid>.template` sidecar file
658
+ *
659
+ * @param ref - a reference to a `<docid>.template` file
660
+ * @returns the template content
661
+ */
662
+ getTemplate(ref: ItemRef): Promise<TemplateContent>;
663
+ /**
664
+ * get the parsed layer metadata of a page
665
+ *
666
+ * @param ref - a reference to a `<docid>/<pageid>-metadata.json` file
667
+ * @returns the page metadata
668
+ */
669
+ getPageMetadata(ref: ItemRef): Promise<PageMetadata>;
562
670
  /**
563
671
  * the same as {@link putFile | `putFile`} but rendering an `RmPage` to `.rm`
564
672
  * bytes
565
673
  *
566
- * Only version 3 and 5 pages can be rendered; version 6 pages are read-only.
567
674
  */
568
- putRm(fileName: string, page: RmPageV5): Promise<[RawEntry, Promise<void>]>;
675
+ putRm(fileName: string, page: RmPage): Promise<PendingEntry>;
569
676
  /**
570
677
  * update the current root hash
571
678
  *
@@ -587,26 +694,54 @@ export declare class RawRemarkable {
587
694
  */
588
695
  putRootHash(hash: string, generation: number, broadcast?: boolean): Promise<[string, number]>;
589
696
  /**
590
- * put a raw onto the server
697
+ * put a raw file onto the server
591
698
  *
592
- * This returns the new expeced entry of the file you uploaded, and a promise
593
- * to finish the upload successful. By splitting these two operations you can
594
- * start using the uploaded entry while file finishes uploading.
699
+ * The returned entry is usable immediately, while the upload is still in
700
+ * flight; disposing it waits for the upload to finish. See
701
+ * {@link PendingEntry | `PendingEntry`}.
595
702
  *
596
703
  * NOTE: This won't update the state of the reMarkable until this entry is
597
704
  * incorporated into the root hash.
598
705
  *
599
706
  * @param fileName - the file name to upload (e.g. `<id>.pdf`)
600
707
  * @param bytes - the bytes to upload
601
- * @returns the new entry and a promise to finish the upload
708
+ * @returns the new entry, pending its upload
709
+ */
710
+ putFile(fileName: string, bytes: Uint8Array): Promise<PendingEntry>;
711
+ /** the same as {@link putFile | `putFile`} but with extra validation for Content */
712
+ putContent(fileName: string, content: Content): Promise<PendingEntry>;
713
+ /**
714
+ * the same as {@link putFile | `putFile`} but for a `.pagedata` file
715
+ *
716
+ * @param fileName - the file to write, of the form `<docid>.pagedata`
717
+ * @param templates - one template name per page, in page order
718
+ */
719
+ putPagedata(fileName: string, templates: readonly string[]): Promise<PendingEntry>;
720
+ /**
721
+ * the same as {@link putFile | `putFile`} but with extra validation for page
722
+ * layer metadata
723
+ *
724
+ * @param fileName - the file to write, of the form
725
+ * `<docid>/<pageid>-metadata.json`
726
+ * @param meta - the page's layer metadata
727
+ */
728
+ putPageMetadata(fileName: string, meta: PageMetadata): Promise<PendingEntry>;
729
+ /** the same as {@link putFile | `putFile`} but with extra validation for a template sidecar */
730
+ putTemplate(fileName: string, template: TemplateContent): Promise<PendingEntry>;
731
+ /** the same as {@link putFile | `putFile`} but with extra validation for Metadata */
732
+ putMetadata(fileName: string, metadata: Metadata): Promise<PendingEntry>;
733
+ /**
734
+ * the same as {@link putFile | `putFile`} but with extra validation for
735
+ * highlights
736
+ *
737
+ * Rewraps the array in the file's `highlights` envelope, which
738
+ * {@link getHighlights | `getHighlights`} strips.
739
+ *
740
+ * @param fileName - the file to write, of the form
741
+ * `<docid>.highlights/<pageid>.json`
742
+ * @param highlights - the page's highlights
602
743
  */
603
- putFile(fileName: string, bytes: Uint8Array): Promise<[RawEntry, Promise<void>]>;
604
- /** the same as {@link putFile | `putFile`} but with caching for text */
605
- putText(fileName: string, text: string): Promise<[RawEntry, Promise<void>]>;
606
- /** the same as {@link putText | `putText`} but with extra validation for Content */
607
- putContent(fileName: string, content: Content): Promise<[RawEntry, Promise<void>]>;
608
- /** the same as {@link putText | `putText`} but with extra validation for Metadata */
609
- putMetadata(fileName: string, metadata: Metadata): Promise<[RawEntry, Promise<void>]>;
744
+ putHighlights(fileName: string, highlights: readonly Highlight[][]): Promise<PendingEntry>;
610
745
  /**
611
746
  * put a set of entries to make an entry list file
612
747
  *
@@ -624,13 +759,11 @@ export declare class RawRemarkable {
624
759
  * @param id - the id of the list to upload - this should be the item id if
625
760
  * uploading an item list, or "root" if uploading a new root list. Note the
626
761
  * asymmetry with {@link getEntries | `getEntries`}: `getEntries` takes the
627
- * full `"<id>.docSchema"` file name, whereas `putEntries` takes the bare id
628
- * and appends `.docSchema` (and special-cases `"root"`) itself.
629
762
  * @param entries - the entries to upload
630
763
  *
631
- * @returns the new list entry and a promise to finish the upload
764
+ * @returns the new list entry, pending its upload
632
765
  */
633
- putEntries(id: string, entries: readonly RawEntry[], schemaVersion: SchemaVersion): Promise<[RawEntry, Promise<void>]>;
766
+ putEntries(id: string, entries: readonly RawEntry[], schemaVersion: SchemaVersion): Promise<PendingEntry>;
634
767
  /**
635
768
  * upload a file to the reMarkable cloud using the simple api
636
769
  *