rmapi-js 8.1.0 → 8.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.
package/dist/raw.d.ts ADDED
@@ -0,0 +1,538 @@
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
+ /** [speculative] the center of the zoom for zoomed in documents */
214
+ customZoomCenterX?: number;
215
+ /** [speculative] the center of the zoom for zoomed in documents */
216
+ customZoomCenterY?: number;
217
+ /** [speculative] the orientation */
218
+ customZoomOrientation?: Orientation;
219
+ /** [speculative] the zoom height for zoomed in pages */
220
+ customZoomPageHeight?: number;
221
+ /** [speculative] the zoom width for zoomed in pages */
222
+ customZoomPageWidth?: number;
223
+ /** [speculative] the scale for zoomed in pages */
224
+ customZoomScale?: number;
225
+ /** what zoom mode is set for the page */
226
+ zoomMode?: ZoomMode;
227
+ /** [speculative] a transform matrix, a. la. css matrix transform */
228
+ transform?: Record<`m${"1" | "2" | "3"}${"1" | "2" | "3"}`, number>;
229
+ /** [speculative] metadata about keyboard use */
230
+ keyboardMetadata?: KeyboardMetadata;
231
+ /** [speculative] various other page metadata */
232
+ cPages?: CPages;
233
+ /**
234
+ * setting for the adaptive contrast filter
235
+ *
236
+ * off has no background filter, best for images, full page applies the high
237
+ * contrast filter to the entire page. If this is omitted, reMarkable will try
238
+ * to apply the filter only to text areas.
239
+ */
240
+ viewBackgroundFilter?: BackgroundFilter;
241
+ }
242
+ /**
243
+ * content metadata, stored with the "content" extension
244
+ *
245
+ * This largely contains description of how to render the document, rather than
246
+ * metadata about it.
247
+ */
248
+ export interface TemplateContent {
249
+ /** the template name */
250
+ name: string;
251
+ /** the template's author */
252
+ author: string;
253
+ /** Base64-encoded SVG icon image */
254
+ iconData: string;
255
+ /** category names this template belongs to (eg: "Planning", "Productivity") */
256
+ categories: string[];
257
+ /** labels associated with this template (eg: "Project management") */
258
+ labels: string[];
259
+ /** the orientation of this template */
260
+ orientation: "portrait" | "landscape";
261
+ /** semantic version for this template */
262
+ templateVersion: string;
263
+ /** template configuration format version (currently just `1`) */
264
+ formatVersion: number;
265
+ /**
266
+ * which screens the template supports:
267
+ *
268
+ * - `rm2`: reMarkable 2
269
+ * - `rmPP`: reMarkable Paper Pro
270
+ */
271
+ supportedScreens: ("rm2" | "rmPP")[];
272
+ /** constant values used by the commands in `items` */
273
+ constants?: {
274
+ [name: string]: number;
275
+ }[];
276
+ /** the template definition, an SVG-like DSL in JSON */
277
+ items: object[];
278
+ }
279
+ /** content metadata for any item */
280
+ export type Content = CollectionContent | DocumentContent | TemplateContent;
281
+ /**
282
+ * item level metadata
283
+ *
284
+ * Stored with the extension "metadata".
285
+ */
286
+ export interface Metadata {
287
+ /** creation time, a string of the epoch timestamp */
288
+ createdTime?: string;
289
+ /** [speculative] true if the item has been actually deleted */
290
+ deleted?: boolean;
291
+ /** the last modify time, the string of the epoch timestamp */
292
+ lastModified: string;
293
+ /** the last opened epoch timestamp, isn't defined for CollectionType */
294
+ lastOpened?: string;
295
+ /** the last page opened, isn't defined for CollectionType, starts at 0*/
296
+ lastOpenedPage?: number;
297
+ /** [speculative] true if the metadata has been modified */
298
+ metadatamodified?: boolean;
299
+ /** [speculative] true if the item has been modified */
300
+ modified?: boolean;
301
+ /**
302
+ * the id of the parent collection
303
+ *
304
+ * This is the empty string for root (no parent), "trash" if it's in the
305
+ * trash, or the id of the parent.
306
+ */
307
+ parent: string;
308
+ /** true of the item is starred */
309
+ pinned: boolean;
310
+ /** [unknown] */
311
+ synced?: boolean;
312
+ /**
313
+ * the type of item this corresponds to
314
+ *
315
+ * DocumentType is a document, an epub, pdf, or notebook, CollectionType is a
316
+ * folder.
317
+ */
318
+ type: "DocumentType" | "CollectionType" | "TemplateType";
319
+ /** whether this is this a newly-installed template */
320
+ new?: boolean;
321
+ /**
322
+ * the provider from which this item was obtained/installed
323
+ *
324
+ * Example: a template from "com.remarkable.methods".
325
+ */
326
+ source?: string;
327
+ /** [speculative] metadata version, always 0 */
328
+ version?: number;
329
+ /** the visible name of the item, what it's called on the reMarkable */
330
+ visibleName: string;
331
+ }
332
+ /**
333
+ * access to the low-level reMarkable api
334
+ *
335
+ * This class gives more granualar access to the reMarkable cloud, but is more
336
+ * dangerous.
337
+ *
338
+ * ## Overview
339
+ *
340
+ * reMarkable uses an immutable file system, where each file is referenced by
341
+ * the 32 byte sha256 hash of its contents. Each file also has an id used to
342
+ * keep track of updates, so to "update" a file, you upload a new file, and
343
+ * change the hash associated with it's id.
344
+ *
345
+ * Each "item" (a document or a collection) is actually a list of files.
346
+ * The whole reMarkable state is then a list of these lists. Finally, the hash
347
+ * of that list is called the rootHash. To update anything, you have to update
348
+ * the root hash to point to a new list of updated items.
349
+ *
350
+ * This can be dangerous, as corrupting the root hash can destroy all of your
351
+ * files. It is therefore highly recommended to save your current root hash
352
+ * ({@link getRootHash | `getRootHash`}) before using this api to attempt file
353
+ * writes, so you can recover a previous "snapshot" should anything go wrong.
354
+ *
355
+ * ## Items
356
+ *
357
+ * Each item is a collection of individual files. Using
358
+ * {@link getEntries | `getEntries`} on the root hash will give you a list
359
+ * entries that correspond to items. Using `getEntries` on any of those items
360
+ * will get you the files that make up that item.
361
+ *
362
+ * The documented files are:
363
+ * - `<docid>.pdf` - a raw pdf document
364
+ * - `<docid>.epub` - a raw epub document
365
+ * - `<docid>.content` - a json file roughly describing document properties (see {@link DocumentContent | `DocumentContent`})
366
+ * - `<docid>.metadata` - metadata about the document (see {@link Metadata | `Metadata`})
367
+ * - `<docid>.pagedata` - a text file where each line is the template of that page
368
+ * - `<docid>/<pageid>.rm` - [speculative] raw remarkable vectors, text, etc
369
+ * - `<docid>/<pageid>-metadata.json` - [speculative] metadata about the individual page
370
+ * - `<docid>.highlights/<pageid>.json` - [speculative] highlights on the page
371
+ *
372
+ * Some items will have both a `.pdf` and `.epub` file, likely due to preparing
373
+ * for export. Collections only have `.content` and `.metadata` files, with
374
+ * `.content` only containing tags.
375
+ *
376
+ * ## Caching
377
+ *
378
+ * Since everything is tied to the hash of it's contents, we can agressively
379
+ * cache results. We assume that text contents are "small" and so fully cache
380
+ * them, where as binary files we treat as large and only store that we know
381
+ * they exist to prevent future writes.
382
+ *
383
+ * By default, this only persists as long as the api instance is alive. However,
384
+ * for performance reasons, you should call {@link dumpCache | `dumpCache`} to
385
+ * persist the cache between sessions.
386
+ *
387
+ * @remarks
388
+ *
389
+ * Generally all hashes are 64 character hex strings, and all ids are uuid4.
390
+ */
391
+ export interface RawRemarkableApi {
392
+ /**
393
+ * gets the root hash and the current generation
394
+ *
395
+ * When calling `putRootHash`, you should pass the generation you got from
396
+ * this call. That way you tell reMarkable you're updating the previous state.
397
+ *
398
+ * @returns the root hash and the current generation
399
+ */
400
+ getRootHash(): Promise<[string, number]>;
401
+ /**
402
+ * get the raw binary data associated with a hash
403
+ *
404
+ * @param hash - the hash to get the data for
405
+ * @returns the data
406
+ */
407
+ getHash(hash: string): Promise<Uint8Array>;
408
+ /**
409
+ * get raw text data associated with a hash
410
+ *
411
+ * We assume text data are small, and so cache the entire text. If you want to
412
+ * avoid this, use {@link getHash | `getHash`} combined with a TextDecoder.
413
+
414
+ * @param hash - the hash to get text for
415
+ * @returns the text
416
+ */
417
+ getText(hash: string): Promise<string>;
418
+ /**
419
+ * get the entries associated with a list hash
420
+ *
421
+ * A list hash is the root hash, or any hash with the type 80000000. NOTE
422
+ * these are hashed differently than files.
423
+
424
+ * @param hash - the hash to get entries for
425
+ * @returns the entries
426
+ */
427
+ getEntries(hash: string): Promise<RawEntry[]>;
428
+ /**
429
+ * get the parsed and validated `Content` of a content hash
430
+ *
431
+ * Use {@link getText | `getText`} combined with `JSON.parse` to bypass
432
+ * validation
433
+
434
+ * @param hash - the hash to get Content for
435
+ * @returns the content
436
+ */
437
+ getContent(hash: string): Promise<Content>;
438
+ /**
439
+ * get the parsed and validated `Metadata` of a metadata hash
440
+ *
441
+ * Use {@link getText | `getText`} combined with `JSON.parse` to bypass
442
+ * validation
443
+
444
+ * @param hash - the hash to get Metadata for
445
+ * @returns the metadata
446
+ */
447
+ getMetadata(hash: string): Promise<Metadata>;
448
+ /**
449
+ * update the current root hash
450
+ *
451
+ * This will fail if generation doesn't match the current server generation.
452
+ * This ensures that you are updating what you expect. IF you get a
453
+ * {@link GenerationError | `GenerationError`}, that indicates that the server
454
+ * was updated after you last got the generation. You should call
455
+ * {@link getRootHash | `getRootHash`} and then recompute the changes you want
456
+ * from the new root hash. If you ignore the update hash value and just call
457
+ * `putRootHash` again, you will overwrite the changes made by the other
458
+ * update.
459
+ *
460
+ * @param hash - the new root hash
461
+ * @param generation - the generation of the current root hash
462
+ * @param broadcast - [unknown] an option in the request
463
+ *
464
+ * @throws GenerationError if the generation doesn't match the current server generation
465
+ * @returns the new root hash and the new generation
466
+ */
467
+ putRootHash(hash: string, generation: number, broadcast?: boolean): Promise<[string, number]>;
468
+ /**
469
+ * put a raw onto the server
470
+ *
471
+ * This returns the new expeced entry of the file you uploaded, and a promise
472
+ * to finish the upload successful. By splitting these two operations you can
473
+ * start using the uploaded entry while file finishes uploading.
474
+ *
475
+ * NOTE: This won't update the state of the reMarkable until this entry is
476
+ * incorporated into the root hash.
477
+ *
478
+ * @param id - the id of the file to upload
479
+ * @param bytes - the bytes to upload
480
+ * @returns the new entry and a promise to finish the upload
481
+ */
482
+ putFile(id: string, bytes: Uint8Array): Promise<[RawFileEntry, Promise<void>]>;
483
+ /** the same as {@link putFile | `putFile`} but with caching for text */
484
+ putText(id: string, content: string): Promise<[RawFileEntry, Promise<void>]>;
485
+ /** the same as {@link putText | `putText`} but with extra validation for Content */
486
+ putContent(id: string, content: Content): Promise<[RawFileEntry, Promise<void>]>;
487
+ /** the same as {@link putText | `putText`} but with extra validation for Metadata */
488
+ putMetadata(id: string, metadata: Metadata): Promise<[RawFileEntry, Promise<void>]>;
489
+ /**
490
+ * put a set of entries to make an entry list file
491
+ *
492
+ * To fully upload an item:
493
+ * 1. upload all the constituent files and metadata
494
+ * 2. call this with all of the entries
495
+ * 3. append this entry to the root entry and call this again to update this root list
496
+ * 4. put the new root hash
497
+ *
498
+ * @param id - the id of the list to upload - this should be the item id if
499
+ * uploading an item list, or "root" if uploading a new root list.
500
+ * @param entries - the entries to upload
501
+ * @returns the new list entry and a promise to finish the upload
502
+ */
503
+ putEntries(id: string, entries: RawEntry[]): Promise<[RawListEntry, Promise<void>]>;
504
+ /**
505
+ * dump the current cache to a string to preserve between session
506
+ *
507
+ * @returns a serialized version of the cache to pass to a new api instance
508
+ */
509
+ dumpCache(): string;
510
+ /** completely clear the cache */
511
+ clearCache(): void;
512
+ }
513
+ interface AuthedFetch {
514
+ (method: RequestMethod, url: string, init?: {
515
+ body?: string | Uint8Array;
516
+ headers?: Record<string, string>;
517
+ }): Promise<Response>;
518
+ }
519
+ export declare class RawRemarkable implements RawRemarkableApi {
520
+ #private;
521
+ constructor(authedFetch: AuthedFetch, cache: Map<string, string | null>, rawHost: string);
522
+ /** make an authorized request to remarkable */
523
+ getRootHash(): Promise<[string, number]>;
524
+ getHash(hash: string): Promise<Uint8Array>;
525
+ getText(hash: string): Promise<string>;
526
+ getEntries(hash: string): Promise<RawEntry[]>;
527
+ getContent(hash: string): Promise<Content>;
528
+ getMetadata(hash: string): Promise<Metadata>;
529
+ putRootHash(hash: string, generation: number, broadcast?: boolean): Promise<[string, number]>;
530
+ putFile(id: string, bytes: Uint8Array): Promise<[RawFileEntry, Promise<void>]>;
531
+ putText(id: string, text: string): Promise<[RawFileEntry, Promise<void>]>;
532
+ putContent(id: string, content: Content): Promise<[RawFileEntry, Promise<void>]>;
533
+ putMetadata(id: string, metadata: Metadata): Promise<[RawFileEntry, Promise<void>]>;
534
+ putEntries(id: string, entries: RawEntry[]): Promise<[RawListEntry, Promise<void>]>;
535
+ dumpCache(): string;
536
+ clearCache(): void;
537
+ }
538
+ export {};