rmapi-js 8.1.1 → 8.3.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/raw.d.ts ADDED
@@ -0,0 +1,558 @@
1
+ /** request types */
2
+ export type RequestMethod = "POST" | "GET" | "PUT" | "DELETE" | "PATCH" | "OPTIONS";
3
+ /**
4
+ * the low-level entry corresponding to a collection of files
5
+ *
6
+ * A collection could be for the root collection, or for an individual document,
7
+ * which is often a collection of files. If an entry represents a collection of
8
+ * files, the high level entry will have the same hash and id as the low-level
9
+ * entry for that collection.
10
+ */
11
+ export interface RawListEntry {
12
+ /** collection type (80000000) */
13
+ type: 80000000;
14
+ /** the hash of the collection this points to */
15
+ hash: string;
16
+ /** the unique id of the collection */
17
+ id: string;
18
+ /** the number of subfiles */
19
+ subfiles: number;
20
+ /** the total size of everything in the collection */
21
+ size: number;
22
+ }
23
+ /** the low-level entry for a single file */
24
+ export interface RawFileEntry {
25
+ /** file type (0) */
26
+ type: 0;
27
+ /** the hash of the file this points to */
28
+ hash: string;
29
+ /** the unique id of the file */
30
+ id: string;
31
+ /** the number of subfiles, always zero */
32
+ subfiles: 0;
33
+ /** the size of the file in bytes */
34
+ size: number;
35
+ }
36
+ /** a low-level stored entry */
37
+ export type RawEntry = RawListEntry | RawFileEntry;
38
+ /** the type of files reMarkable supports */
39
+ export type FileType = "epub" | "pdf" | "notebook";
40
+ /** a tag for an entry */
41
+ export interface Tag {
42
+ /** the name of the tag */
43
+ name: string;
44
+ /** the timestamp when this tag was added */
45
+ timestamp: number;
46
+ }
47
+ /** a tag for individual pages */
48
+ export interface PageTag extends Tag {
49
+ /** the id of the page this is on */
50
+ pageId: string;
51
+ }
52
+ /** all supported document orientations */
53
+ export type Orientation = "portrait" | "landscape";
54
+ /** all supported text alignments */
55
+ export type TextAlignment = "justify" | "left";
56
+ /** types of zoom modes for documents, applies primarily to pdf files */
57
+ export type ZoomMode = "bestFit" | "customFit" | "fitToHeight" | "fitToWidth";
58
+ /**
59
+ * types of background filter
60
+ *
61
+ * off has no background filter, best for images, full page applies the high
62
+ * contrast filter to the entire page. If this is omitted, reMarkable will try
63
+ * to apply the filter only to text areas.
64
+ */
65
+ export type BackgroundFilter = "off" | "fullpage";
66
+ /** document metadata stored in {@link Content} */
67
+ export interface DocumentMetadata {
68
+ /** a list of authors as a string */
69
+ authors?: string[];
70
+ /** the title as a string */
71
+ title?: string;
72
+ /** the publication date as an ISO date or timestamp */
73
+ publicationDate?: string;
74
+ /** the publisher */
75
+ publisher?: string;
76
+ }
77
+ /** [speculative] metadata stored about keyboard interactions */
78
+ export interface KeyboardMetadata {
79
+ /** [unknown] */
80
+ count: number;
81
+ /** [unknown] */
82
+ timestamp: number;
83
+ }
84
+ /** a c-page value who's type is a string */
85
+ export interface CPageStringValue {
86
+ /** a pseudo-timestamp of the form "1:1" or "1:2" */
87
+ timestamp: string;
88
+ /** the stored value */
89
+ value: string;
90
+ }
91
+ /** a c-page value who's type is a string */
92
+ export interface CPageNumberValue {
93
+ /** a pseudo-timestamp of the form "1:1" or "1:2" */
94
+ timestamp: string;
95
+ /** the stored value */
96
+ value: number;
97
+ }
98
+ /** [speculative] information about an individual page */
99
+ export interface CPagePage {
100
+ /** [speculative] the page id */
101
+ id: string;
102
+ /** [unknown] values are like "aa", "ab", "ba", etc. */
103
+ idx: CPageStringValue;
104
+ /** [unknown] */
105
+ redir?: CPageNumberValue;
106
+ /** [speculative] the template name of the page */
107
+ template?: CPageStringValue;
108
+ /** [unknown] the value is a timestamp */
109
+ scrollTime?: CPageStringValue;
110
+ /** [unknown] */
111
+ verticalScroll?: CPageNumberValue;
112
+ /** [unknown] */
113
+ deleted?: CPageNumberValue;
114
+ }
115
+ /** [unknown] */
116
+ export interface CPageUUID {
117
+ /** [unknown] */
118
+ first: string;
119
+ /** [unknown] */
120
+ second: number;
121
+ }
122
+ /** [unknown] metadata about pages */
123
+ export interface CPages {
124
+ /** [speculative] the last time the document was opened */
125
+ lastOpened: CPageStringValue;
126
+ /** [unknown] */
127
+ original: CPageNumberValue;
128
+ /** [speculative] information about individual pages */
129
+ pages: CPagePage[];
130
+ /** [unknown] */
131
+ uuids: CPageUUID[];
132
+ }
133
+ /** the content metadata for collections (folders) */
134
+ export interface CollectionContent {
135
+ /** the tags for the collection */
136
+ tags?: Tag[];
137
+ /** collections don't have a file type */
138
+ fileType?: undefined;
139
+ }
140
+ /**
141
+ * content metadata, stored with the "content" extension
142
+ *
143
+ * This largely contains description of how to render the document, rather than
144
+ * metadata about it.
145
+ */
146
+ export interface DocumentContent {
147
+ /**
148
+ * which page to use for the thumbnail
149
+ *
150
+ * -1 indicates the last visited page, whereas 0 is the first page.
151
+ */
152
+ coverPageNumber: number;
153
+ /** metadata about the author, publishers, etc. */
154
+ documentMetadata: DocumentMetadata;
155
+ /** It's not known what this field is for */
156
+ dummyDocument?: boolean;
157
+ /** the largely contains metadata about what pens were used and their settings */
158
+ extraMetadata: Record<string, string>;
159
+ /** the underlying file type of this document */
160
+ fileType: FileType;
161
+ /**
162
+ * the name of the font to use for text rendering
163
+ *
164
+ * The reMarkable supports five fonts by default: "Noto Sans", "Noto Sans UI",
165
+ * "EB Garamond", "Noto Mono", and "Noto Serif". You can also set the font to
166
+ * the empty string or omit it for the default.
167
+ */
168
+ fontName: string;
169
+ /** the format version, this should always be 1 */
170
+ formatVersion?: number;
171
+ /** the last opened page, starts at zero */
172
+ lastOpenedPage?: number;
173
+ /**
174
+ * the line height
175
+ *
176
+ * The reMarkable uses three built-in line heights: 100, 150, 200, and
177
+ * uses -1 to indicate the default line height, but heights outside of these
178
+ * also work.
179
+ */
180
+ lineHeight: number;
181
+ /**
182
+ * the document margin in pixels
183
+ *
184
+ * The reMarkable uses three built-in margins: 50, 125, 200, but other margins
185
+ * are possible. The reMarkable used to default to margins of 180.
186
+ */
187
+ margins?: number;
188
+ /** the document orientation */
189
+ orientation: Orientation;
190
+ /** this specifies the number of pages, it's not clear how this is different than pageCount */
191
+ originalPageCount?: number;
192
+ /** the number of pages */
193
+ pageCount: number;
194
+ /** the page tags for the document */
195
+ pageTags?: PageTag[];
196
+ /** a list of the ids of each page in the document */
197
+ pages?: string[];
198
+ /** a mapping from page number to page id in pages */
199
+ redirectionPageMap?: number[];
200
+ /** ostensibly the size in bytes of the file, but this differs from other measurements */
201
+ sizeInBytes: string;
202
+ /** document tags for this document */
203
+ tags?: Tag[];
204
+ /** text alignment for this document */
205
+ textAlignment: TextAlignment;
206
+ /**
207
+ * the font size
208
+ *
209
+ * reMarkable uses six built-in text scales: 0.7, 0.8, 1, 1.2, 1.5, 2, but
210
+ * values outside of this range are valid.
211
+ */
212
+ textScale: number;
213
+ /**
214
+ * the center of the zoom for customFit zoom
215
+ *
216
+ * This is an absolute offset from the center of the page. Negative numbers
217
+ * indicate shifted left and positive numbers indicate shifted right. The
218
+ * units are relative to the document pixels, but it's not sure how the
219
+ * document size is calculated.
220
+ */
221
+ customZoomCenterX?: number;
222
+ /**
223
+ * the center of the zoom for customFit documents
224
+ *
225
+ * This is an absolute number relative to the top of the page. Negative
226
+ * numbers indicate shifted up, while positive numbers indicate shifted down.
227
+ * The units are relative to the document pixels, but it's not sure how the
228
+ * document size is calculated.
229
+ */
230
+ customZoomCenterY?: number;
231
+ /** this seems unused */
232
+ customZoomOrientation?: Orientation;
233
+ /** this seems unused */
234
+ customZoomPageHeight?: number;
235
+ /** this seems unused */
236
+ customZoomPageWidth?: number;
237
+ /**
238
+ * the scale for customFit documents
239
+ *
240
+ * 1 indicates no zoom, smaller numbers indicate zoomed out, larger numbers
241
+ * indicate zoomed in. reMarkable generally allows setting this from 0.5 to 5,
242
+ * but values outside that bound are still supported.
243
+ */
244
+ customZoomScale?: number;
245
+ /** what zoom mode is set for the page */
246
+ zoomMode?: ZoomMode;
247
+ /** [speculative] a transform matrix, a. la. css matrix transform */
248
+ transform?: Record<`m${"1" | "2" | "3"}${"1" | "2" | "3"}`, number>;
249
+ /** [speculative] metadata about keyboard use */
250
+ keyboardMetadata?: KeyboardMetadata;
251
+ /** [speculative] various other page metadata */
252
+ cPages?: CPages;
253
+ /**
254
+ * setting for the adaptive contrast filter
255
+ *
256
+ * off has no background filter, best for images, full page applies the high
257
+ * contrast filter to the entire page. If this is omitted, reMarkable will try
258
+ * to apply the filter only to text areas.
259
+ */
260
+ viewBackgroundFilter?: BackgroundFilter;
261
+ }
262
+ /**
263
+ * content metadata, stored with the "content" extension
264
+ *
265
+ * This largely contains description of how to render the document, rather than
266
+ * metadata about it.
267
+ */
268
+ export interface TemplateContent {
269
+ /** the template name */
270
+ name: string;
271
+ /** the template's author */
272
+ author: string;
273
+ /** Base64-encoded SVG icon image */
274
+ iconData: string;
275
+ /** category names this template belongs to (eg: "Planning", "Productivity") */
276
+ categories: string[];
277
+ /** labels associated with this template (eg: "Project management") */
278
+ labels: string[];
279
+ /** the orientation of this template */
280
+ orientation: "portrait" | "landscape";
281
+ /** semantic version for this template */
282
+ templateVersion: string;
283
+ /** template configuration format version (currently just `1`) */
284
+ formatVersion?: number;
285
+ /**
286
+ * which screens the template supports:
287
+ *
288
+ * - `rm2`: reMarkable 2
289
+ * - `rmPP`: reMarkable Paper Pro
290
+ */
291
+ supportedScreens: ("rm2" | "rmPP")[];
292
+ /** constant values used by the commands in `items` */
293
+ constants?: {
294
+ [name: string]: number;
295
+ }[];
296
+ /** the template definition, an SVG-like DSL in JSON */
297
+ items: object[];
298
+ }
299
+ /** content metadata for any item */
300
+ export type Content = CollectionContent | DocumentContent | TemplateContent;
301
+ /**
302
+ * item level metadata
303
+ *
304
+ * Stored with the extension "metadata".
305
+ */
306
+ export interface Metadata {
307
+ /** creation time, a string of the epoch timestamp */
308
+ createdTime?: string;
309
+ /** [speculative] true if the item has been actually deleted */
310
+ deleted?: boolean;
311
+ /** the last modify time, the string of the epoch timestamp */
312
+ lastModified: string;
313
+ /** the last opened epoch timestamp, isn't defined for CollectionType */
314
+ lastOpened?: string;
315
+ /** the last page opened, isn't defined for CollectionType, starts at 0*/
316
+ lastOpenedPage?: number;
317
+ /** [speculative] true if the metadata has been modified */
318
+ metadatamodified?: boolean;
319
+ /** [speculative] true if the item has been modified */
320
+ modified?: boolean;
321
+ /**
322
+ * the id of the parent collection
323
+ *
324
+ * This is the empty string for root (no parent), "trash" if it's in the
325
+ * trash, or the id of the parent.
326
+ */
327
+ parent: string;
328
+ /** true of the item is starred */
329
+ pinned: boolean;
330
+ /** [unknown] */
331
+ synced?: boolean;
332
+ /**
333
+ * the type of item this corresponds to
334
+ *
335
+ * DocumentType is a document, an epub, pdf, or notebook, CollectionType is a
336
+ * folder.
337
+ */
338
+ type: "DocumentType" | "CollectionType" | "TemplateType";
339
+ /** whether this is this a newly-installed template */
340
+ new?: boolean;
341
+ /**
342
+ * the provider from which this item was obtained/installed
343
+ *
344
+ * Example: a template from "com.remarkable.methods".
345
+ */
346
+ source?: string;
347
+ /** [speculative] metadata version, always 0 */
348
+ version?: number;
349
+ /** the visible name of the item, what it's called on the reMarkable */
350
+ visibleName: string;
351
+ }
352
+ /**
353
+ * access to the low-level reMarkable api
354
+ *
355
+ * This class gives more granualar access to the reMarkable cloud, but is more
356
+ * dangerous.
357
+ *
358
+ * ## Overview
359
+ *
360
+ * reMarkable uses an immutable file system, where each file is referenced by
361
+ * the 32 byte sha256 hash of its contents. Each file also has an id used to
362
+ * keep track of updates, so to "update" a file, you upload a new file, and
363
+ * change the hash associated with it's id.
364
+ *
365
+ * Each "item" (a document or a collection) is actually a list of files.
366
+ * The whole reMarkable state is then a list of these lists. Finally, the hash
367
+ * of that list is called the rootHash. To update anything, you have to update
368
+ * the root hash to point to a new list of updated items.
369
+ *
370
+ * This can be dangerous, as corrupting the root hash can destroy all of your
371
+ * files. It is therefore highly recommended to save your current root hash
372
+ * ({@link getRootHash | `getRootHash`}) before using this api to attempt file
373
+ * writes, so you can recover a previous "snapshot" should anything go wrong.
374
+ *
375
+ * ## Items
376
+ *
377
+ * Each item is a collection of individual files. Using
378
+ * {@link getEntries | `getEntries`} on the root hash will give you a list
379
+ * entries that correspond to items. Using `getEntries` on any of those items
380
+ * will get you the files that make up that item.
381
+ *
382
+ * The documented files are:
383
+ * - `<docid>.pdf` - a raw pdf document
384
+ * - `<docid>.epub` - a raw epub document
385
+ * - `<docid>.content` - a json file roughly describing document properties (see {@link DocumentContent | `DocumentContent`})
386
+ * - `<docid>.metadata` - metadata about the document (see {@link Metadata | `Metadata`})
387
+ * - `<docid>.pagedata` - a text file where each line is the template of that page
388
+ * - `<docid>/<pageid>.rm` - [speculative] raw remarkable vectors, text, etc
389
+ * - `<docid>/<pageid>-metadata.json` - [speculative] metadata about the individual page
390
+ * - `<docid>.highlights/<pageid>.json` - [speculative] highlights on the page
391
+ *
392
+ * Some items will have both a `.pdf` and `.epub` file, likely due to preparing
393
+ * for export. Collections only have `.content` and `.metadata` files, with
394
+ * `.content` only containing tags.
395
+ *
396
+ * ## Caching
397
+ *
398
+ * Since everything is tied to the hash of it's contents, we can agressively
399
+ * cache results. We assume that text contents are "small" and so fully cache
400
+ * them, where as binary files we treat as large and only store that we know
401
+ * they exist to prevent future writes.
402
+ *
403
+ * By default, this only persists as long as the api instance is alive. However,
404
+ * for performance reasons, you should call {@link dumpCache | `dumpCache`} to
405
+ * persist the cache between sessions.
406
+ *
407
+ * @remarks
408
+ *
409
+ * Generally all hashes are 64 character hex strings, and all ids are uuid4.
410
+ */
411
+ export interface RawRemarkableApi {
412
+ /**
413
+ * gets the root hash and the current generation
414
+ *
415
+ * When calling `putRootHash`, you should pass the generation you got from
416
+ * this call. That way you tell reMarkable you're updating the previous state.
417
+ *
418
+ * @returns the root hash and the current generation
419
+ */
420
+ getRootHash(): Promise<[string, number]>;
421
+ /**
422
+ * get the raw binary data associated with a hash
423
+ *
424
+ * @param hash - the hash to get the data for
425
+ * @returns the data
426
+ */
427
+ getHash(hash: string): Promise<Uint8Array>;
428
+ /**
429
+ * get raw text data associated with a hash
430
+ *
431
+ * We assume text data are small, and so cache the entire text. If you want to
432
+ * avoid this, use {@link getHash | `getHash`} combined with a TextDecoder.
433
+
434
+ * @param hash - the hash to get text for
435
+ * @returns the text
436
+ */
437
+ getText(hash: string): Promise<string>;
438
+ /**
439
+ * get the entries associated with a list hash
440
+ *
441
+ * A list hash is the root hash, or any hash with the type 80000000. NOTE
442
+ * these are hashed differently than files.
443
+
444
+ * @param hash - the hash to get entries for
445
+ * @returns the entries
446
+ */
447
+ getEntries(hash: string): Promise<RawEntry[]>;
448
+ /**
449
+ * get the parsed and validated `Content` of a content hash
450
+ *
451
+ * Use {@link getText | `getText`} combined with `JSON.parse` to bypass
452
+ * validation
453
+
454
+ * @param hash - the hash to get Content for
455
+ * @returns the content
456
+ */
457
+ getContent(hash: string): Promise<Content>;
458
+ /**
459
+ * get the parsed and validated `Metadata` of a metadata hash
460
+ *
461
+ * Use {@link getText | `getText`} combined with `JSON.parse` to bypass
462
+ * validation
463
+
464
+ * @param hash - the hash to get Metadata for
465
+ * @returns the metadata
466
+ */
467
+ getMetadata(hash: string): Promise<Metadata>;
468
+ /**
469
+ * update the current root hash
470
+ *
471
+ * This will fail if generation doesn't match the current server generation.
472
+ * This ensures that you are updating what you expect. IF you get a
473
+ * {@link GenerationError | `GenerationError`}, that indicates that the server
474
+ * was updated after you last got the generation. You should call
475
+ * {@link getRootHash | `getRootHash`} and then recompute the changes you want
476
+ * from the new root hash. If you ignore the update hash value and just call
477
+ * `putRootHash` again, you will overwrite the changes made by the other
478
+ * update.
479
+ *
480
+ * @param hash - the new root hash
481
+ * @param generation - the generation of the current root hash
482
+ * @param broadcast - [unknown] an option in the request
483
+ *
484
+ * @throws GenerationError if the generation doesn't match the current server generation
485
+ * @returns the new root hash and the new generation
486
+ */
487
+ putRootHash(hash: string, generation: number, broadcast?: boolean): Promise<[string, number]>;
488
+ /**
489
+ * put a raw onto the server
490
+ *
491
+ * This returns the new expeced entry of the file you uploaded, and a promise
492
+ * to finish the upload successful. By splitting these two operations you can
493
+ * start using the uploaded entry while file finishes uploading.
494
+ *
495
+ * NOTE: This won't update the state of the reMarkable until this entry is
496
+ * incorporated into the root hash.
497
+ *
498
+ * @param id - the id of the file to upload
499
+ * @param bytes - the bytes to upload
500
+ * @returns the new entry and a promise to finish the upload
501
+ */
502
+ putFile(id: string, bytes: Uint8Array): Promise<[RawFileEntry, Promise<void>]>;
503
+ /** the same as {@link putFile | `putFile`} but with caching for text */
504
+ putText(id: string, content: string): Promise<[RawFileEntry, Promise<void>]>;
505
+ /** the same as {@link putText | `putText`} but with extra validation for Content */
506
+ putContent(id: string, content: Content): Promise<[RawFileEntry, Promise<void>]>;
507
+ /** the same as {@link putText | `putText`} but with extra validation for Metadata */
508
+ putMetadata(id: string, metadata: Metadata): Promise<[RawFileEntry, Promise<void>]>;
509
+ /**
510
+ * put a set of entries to make an entry list file
511
+ *
512
+ * To fully upload an item:
513
+ * 1. upload all the constituent files and metadata
514
+ * 2. call this with all of the entries
515
+ * 3. append this entry to the root entry and call this again to update this root list
516
+ * 4. put the new root hash
517
+ *
518
+ * @param id - the id of the list to upload - this should be the item id if
519
+ * uploading an item list, or "root" if uploading a new root list.
520
+ * @param entries - the entries to upload
521
+ * @returns the new list entry and a promise to finish the upload
522
+ */
523
+ putEntries(id: string, entries: RawEntry[]): Promise<[RawListEntry, Promise<void>]>;
524
+ /**
525
+ * dump the current cache to a string to preserve between session
526
+ *
527
+ * @returns a serialized version of the cache to pass to a new api instance
528
+ */
529
+ dumpCache(): string;
530
+ /** completely clear the cache */
531
+ clearCache(): void;
532
+ }
533
+ interface AuthedFetch {
534
+ (method: RequestMethod, url: string, init?: {
535
+ body?: string | Uint8Array;
536
+ headers?: Record<string, string>;
537
+ }): Promise<Response>;
538
+ }
539
+ export declare class RawRemarkable implements RawRemarkableApi {
540
+ #private;
541
+ constructor(authedFetch: AuthedFetch, cache: Map<string, string | null>, rawHost: string);
542
+ /** make an authorized request to remarkable */
543
+ getRootHash(): Promise<[string, number]>;
544
+ getHash(hash: string): Promise<Uint8Array>;
545
+ getText(hash: string): Promise<string>;
546
+ getEntries(hash: string): Promise<RawEntry[]>;
547
+ getContent(hash: string): Promise<Content>;
548
+ getMetadata(hash: string): Promise<Metadata>;
549
+ putRootHash(hash: string, generation: number, broadcast?: boolean): Promise<[string, number]>;
550
+ putFile(id: string, bytes: Uint8Array): Promise<[RawFileEntry, Promise<void>]>;
551
+ putText(id: string, text: string): Promise<[RawFileEntry, Promise<void>]>;
552
+ putContent(id: string, content: Content): Promise<[RawFileEntry, Promise<void>]>;
553
+ putMetadata(id: string, metadata: Metadata): Promise<[RawFileEntry, Promise<void>]>;
554
+ putEntries(id: string, entries: RawEntry[]): Promise<[RawListEntry, Promise<void>]>;
555
+ dumpCache(): string;
556
+ clearCache(): void;
557
+ }
558
+ export {};