rmapi-js 12.0.2 → 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,5 +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";
4
+ import "core-js/modules/es.uint8-array.from-hex.js";
5
+ import "core-js/modules/es.uint8-array.to-base64.js";
6
+ import "core-js/modules/es.uint8-array.to-hex.js";
1
7
  import { type RmPageV5 } from "./rm5.js";
2
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";
3
15
  /**
4
16
  * a parsed reMarkable `.rm` page
5
17
  *
@@ -19,6 +31,17 @@ export type RmPage = RmPageV5 | RmScene;
19
31
  * @returns the parsed page
20
32
  */
21
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;
22
45
  /** request types */
23
46
  export type RequestMethod = "POST" | "GET" | "PUT" | "DELETE" | "PATCH" | "OPTIONS";
24
47
  /** the supported upload mime types */
@@ -56,8 +79,38 @@ export interface RawEntry extends ItemRef {
56
79
  /** the total size of everything in the collection */
57
80
  size: number;
58
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
+ }
59
105
  /** the type of files reMarkable supports */
60
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";
61
114
  /**
62
115
  * a parsed entries file
63
116
  *
@@ -368,6 +421,44 @@ export interface TemplateContent {
368
421
  }
369
422
  /** content metadata for any item */
370
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
+ }
371
462
  /**
372
463
  * item level metadata
373
464
  *
@@ -399,13 +490,8 @@ export interface Metadata {
399
490
  pinned: boolean;
400
491
  /** [unknown] */
401
492
  synced?: boolean | null;
402
- /**
403
- * the type of item this corresponds to
404
- *
405
- * DocumentType is a document, an epub, pdf, or notebook, CollectionType is a
406
- * folder.
407
- */
408
- type: "DocumentType" | "CollectionType" | "TemplateType";
493
+ /** the type of item this corresponds to */
494
+ type: EntryType;
409
495
  /** whether this is this a newly-installed template */
410
496
  new?: boolean;
411
497
  /**
@@ -461,9 +547,10 @@ type AuthedFetch = (method: RequestMethod, url: string, init?: {
461
547
  * - `<docid>.content` - a json file roughly describing document properties (see {@link DocumentContent | `DocumentContent`})
462
548
  * - `<docid>.metadata` - metadata about the document (see {@link Metadata | `Metadata`})
463
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`})
464
551
  * - `<docid>/<pageid>.rm` - [speculative] raw remarkable vectors, text, etc
465
- * - `<docid>/<pageid>-metadata.json` - [speculative] metadata about the individual page
466
- * - `<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`})
467
554
  *
468
555
  * Some items will have both a `.pdf` and `.epub` file, likely due to preparing
469
556
  * for export. Collections only have `.content` and `.metadata` files, with
@@ -472,9 +559,12 @@ type AuthedFetch = (method: RequestMethod, url: string, init?: {
472
559
  * ## Caching
473
560
  *
474
561
  * Since everything is tied to the hash of it's contents, we can agressively
475
- * cache results. We assume that text contents are "small" and so fully cache
476
- * them, where as binary files we treat as large and only store that we know
477
- * 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.
478
568
  *
479
569
  * By default, this only persists as long as the api instance is alive. However,
480
570
  * for performance reasons, you should call {@link dumpCache | `dumpCache`} to
@@ -486,8 +576,7 @@ type AuthedFetch = (method: RequestMethod, url: string, init?: {
486
576
  */
487
577
  export declare class RawRemarkable {
488
578
  #private;
489
- constructor(authedFetch: AuthedFetch, cache: Map<string, string | null>, rawHost: string, uploadHost: string);
490
- /** make an authorized request to remarkable */
579
+ constructor(authedFetch: AuthedFetch, cache: Map<string, Uint8Array | null>, rawHost: string, uploadHost: string, maxCachedBytes: number);
491
580
  /**
492
581
  * gets the root hash and the current generation
493
582
  *
@@ -517,18 +606,18 @@ export declare class RawRemarkable {
517
606
  * @param ref - a reference to the stored file (see {@link getHash})
518
607
  * @returns the text
519
608
  */
520
- getText({ id: fileName, hash }: ItemRef): Promise<string>;
609
+ getText(ref: ItemRef): Promise<string>;
521
610
  /**
522
611
  * get the entries associated with a list hash
523
612
  *
524
613
  * A list hash is the root hash, or any hash with the type 80000000. NOTE
525
614
  * these are hashed differently than files.
526
615
  *
527
- * @param ref - a reference whose `id` is `"root.docSchema"` for the root, or
528
- * `"<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
529
618
  * @returns the entries
530
619
  */
531
- getEntries(ref: ItemRef): Promise<Entries>;
620
+ getEntries({ id, hash }: ItemRef): Promise<Entries>;
532
621
  /**
533
622
  * get the parsed and validated `Content` of a content hash
534
623
  *
@@ -556,13 +645,34 @@ export declare class RawRemarkable {
556
645
  * @returns the parsed page
557
646
  */
558
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>;
559
670
  /**
560
671
  * the same as {@link putFile | `putFile`} but rendering an `RmPage` to `.rm`
561
672
  * bytes
562
673
  *
563
- * Only version 3 and 5 pages can be rendered; version 6 pages are read-only.
564
674
  */
565
- putRm(fileName: string, page: RmPageV5): Promise<[RawEntry, Promise<void>]>;
675
+ putRm(fileName: string, page: RmPage): Promise<PendingEntry>;
566
676
  /**
567
677
  * update the current root hash
568
678
  *
@@ -584,26 +694,54 @@ export declare class RawRemarkable {
584
694
  */
585
695
  putRootHash(hash: string, generation: number, broadcast?: boolean): Promise<[string, number]>;
586
696
  /**
587
- * put a raw onto the server
697
+ * put a raw file onto the server
588
698
  *
589
- * This returns the new expeced entry of the file you uploaded, and a promise
590
- * to finish the upload successful. By splitting these two operations you can
591
- * 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`}.
592
702
  *
593
703
  * NOTE: This won't update the state of the reMarkable until this entry is
594
704
  * incorporated into the root hash.
595
705
  *
596
706
  * @param fileName - the file name to upload (e.g. `<id>.pdf`)
597
707
  * @param bytes - the bytes to upload
598
- * @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
599
743
  */
600
- putFile(fileName: string, bytes: Uint8Array): Promise<[RawEntry, Promise<void>]>;
601
- /** the same as {@link putFile | `putFile`} but with caching for text */
602
- putText(fileName: string, text: string): Promise<[RawEntry, Promise<void>]>;
603
- /** the same as {@link putText | `putText`} but with extra validation for Content */
604
- putContent(fileName: string, content: Content): Promise<[RawEntry, Promise<void>]>;
605
- /** the same as {@link putText | `putText`} but with extra validation for Metadata */
606
- putMetadata(fileName: string, metadata: Metadata): Promise<[RawEntry, Promise<void>]>;
744
+ putHighlights(fileName: string, highlights: readonly Highlight[][]): Promise<PendingEntry>;
607
745
  /**
608
746
  * put a set of entries to make an entry list file
609
747
  *
@@ -621,13 +759,11 @@ export declare class RawRemarkable {
621
759
  * @param id - the id of the list to upload - this should be the item id if
622
760
  * uploading an item list, or "root" if uploading a new root list. Note the
623
761
  * asymmetry with {@link getEntries | `getEntries`}: `getEntries` takes the
624
- * full `"<id>.docSchema"` file name, whereas `putEntries` takes the bare id
625
- * and appends `.docSchema` (and special-cases `"root"`) itself.
626
762
  * @param entries - the entries to upload
627
763
  *
628
- * @returns the new list entry and a promise to finish the upload
764
+ * @returns the new list entry, pending its upload
629
765
  */
630
- putEntries(id: string, entries: readonly RawEntry[], schemaVersion: SchemaVersion): Promise<[RawEntry, Promise<void>]>;
766
+ putEntries(id: string, entries: readonly RawEntry[], schemaVersion: SchemaVersion): Promise<PendingEntry>;
631
767
  /**
632
768
  * upload a file to the reMarkable cloud using the simple api
633
769
  *