rmapi-js 5.0.0 → 7.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/LICENSE +1 -1
- package/README.md +45 -98
- package/dist/index.d.ts +731 -491
- package/dist/index.js +774 -686
- package/dist/lru.d.ts +8 -0
- package/dist/lru.js +64 -0
- package/dist/rmapi-js.esm.min.js +21 -1
- package/package.json +18 -17
- package/dist/index.spec.d.ts +0 -1
- package/dist/index.spec.js +0 -800
- package/dist/test-utils.d.ts +0 -22
- package/dist/test-utils.js +0 -71
- package/dist/utils.d.ts +0 -6
- package/dist/utils.js +0 -22
- package/dist/utils.spec.d.ts +0 -1
- package/dist/utils.spec.js +0 -21
- package/dist/validate.d.ts +0 -3
- package/dist/validate.js +0 -8
- package/dist/validate.spec.d.ts +0 -1
- package/dist/validate.spec.js +0 -15
package/dist/index.d.ts
CHANGED
|
@@ -1,240 +1,134 @@
|
|
|
1
1
|
/** request types */
|
|
2
|
-
export type RequestMethod = "POST" | "GET" | "PUT" | "DELETE";
|
|
3
|
-
/**
|
|
2
|
+
export type RequestMethod = "POST" | "GET" | "PUT" | "DELETE" | "PATCH" | "OPTIONS";
|
|
3
|
+
/** a tag for an entry */
|
|
4
|
+
export interface Tag {
|
|
5
|
+
/** the name of the tag */
|
|
6
|
+
name: string;
|
|
7
|
+
/** the timestamp when this tag was added */
|
|
8
|
+
timestamp: number;
|
|
9
|
+
}
|
|
10
|
+
/** a tag for individual pages */
|
|
11
|
+
export interface PageTag extends Tag {
|
|
12
|
+
/** the id of the page this is on */
|
|
13
|
+
pageId: string;
|
|
14
|
+
}
|
|
15
|
+
/** the type of files reMarkable supports */
|
|
16
|
+
export type FileType = "epub" | "pdf" | "notebook";
|
|
17
|
+
/** all supported document orientations */
|
|
18
|
+
export type Orientation = "portrait" | "landscape";
|
|
19
|
+
/** all supported text alignments */
|
|
4
20
|
export type TextAlignment = "justify" | "left";
|
|
5
|
-
/**
|
|
6
|
-
export
|
|
7
|
-
/**
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
|
|
26
|
-
/** small */
|
|
27
|
-
readonly sm: 50;
|
|
28
|
-
/** medium */
|
|
29
|
-
readonly md: 125;
|
|
30
|
-
/** default for read on remarkable */
|
|
31
|
-
readonly rr: 180;
|
|
32
|
-
/** large */
|
|
33
|
-
readonly lg: 200;
|
|
34
|
-
};
|
|
35
|
-
/** line height options */
|
|
36
|
-
export declare const builtinLineHeights: {
|
|
37
|
-
/** default */
|
|
38
|
-
readonly df: -1;
|
|
39
|
-
/** normal */
|
|
40
|
-
readonly md: 100;
|
|
41
|
-
/** half */
|
|
42
|
-
readonly lg: 150;
|
|
43
|
-
/** double */
|
|
44
|
-
readonly xl: 200;
|
|
45
|
-
};
|
|
46
|
-
/** a remarkable entry for a cloud collection */
|
|
47
|
-
export interface CollectionEntry {
|
|
48
|
-
/** collection type */
|
|
49
|
-
type: "80000000";
|
|
21
|
+
/** types of zoom modes for documents, applies primarily to pdf files */
|
|
22
|
+
export type ZoomMode = "bestFit" | "customFit" | "fitToHeight" | "fitToWidth";
|
|
23
|
+
/**
|
|
24
|
+
* types of background filter
|
|
25
|
+
*
|
|
26
|
+
* off has no background filter, best for images, full page applies the high
|
|
27
|
+
* contrast filter to the entire page. If this is omitted, reMarkable will try
|
|
28
|
+
* to apply the filter only to text areas.
|
|
29
|
+
*/
|
|
30
|
+
export type BackgroundFilter = "off" | "fullpage";
|
|
31
|
+
/**
|
|
32
|
+
* the low-level entry corresponding to a collection of files
|
|
33
|
+
*
|
|
34
|
+
* A collection could be for the root collection, or for an individual document,
|
|
35
|
+
* which is often a collection of files. If an entry represents a collection of
|
|
36
|
+
* files, the high level entry will have the same hash and id as the low-level
|
|
37
|
+
* entry for that collection.
|
|
38
|
+
*/
|
|
39
|
+
export interface RawListEntry {
|
|
40
|
+
/** collection type (80000000) */
|
|
41
|
+
type: 80000000;
|
|
50
42
|
/** the hash of the collection this points to */
|
|
51
43
|
hash: string;
|
|
52
44
|
/** the unique id of the collection */
|
|
53
|
-
|
|
45
|
+
id: string;
|
|
54
46
|
/** the number of subfiles */
|
|
55
47
|
subfiles: number;
|
|
56
|
-
/**
|
|
57
|
-
size:
|
|
48
|
+
/** the total size of everything in the collection */
|
|
49
|
+
size: number;
|
|
58
50
|
}
|
|
59
|
-
/**
|
|
60
|
-
export interface
|
|
61
|
-
/** file type */
|
|
62
|
-
type:
|
|
51
|
+
/** the low-level entry for a single file */
|
|
52
|
+
export interface RawFileEntry {
|
|
53
|
+
/** file type (0) */
|
|
54
|
+
type: 0;
|
|
63
55
|
/** the hash of the file this points to */
|
|
64
56
|
hash: string;
|
|
65
57
|
/** the unique id of the file */
|
|
66
|
-
|
|
67
|
-
/**
|
|
58
|
+
id: string;
|
|
59
|
+
/** the number of subfiles, always zero */
|
|
68
60
|
subfiles: 0;
|
|
69
|
-
/** size of the file */
|
|
70
|
-
size:
|
|
61
|
+
/** the size of the file in bytes */
|
|
62
|
+
size: number;
|
|
71
63
|
}
|
|
72
|
-
/** a
|
|
73
|
-
export type
|
|
74
|
-
/**
|
|
75
|
-
export interface
|
|
76
|
-
/** the document id */
|
|
77
|
-
|
|
78
|
-
/** the
|
|
64
|
+
/** a low-level stored entry */
|
|
65
|
+
export type RawEntry = RawListEntry | RawFileEntry;
|
|
66
|
+
/** common properties shared by collections and documents */
|
|
67
|
+
export interface EntryCommon {
|
|
68
|
+
/** the document id, a uuid4 */
|
|
69
|
+
id: string;
|
|
70
|
+
/** the current hash of the state of this entry */
|
|
79
71
|
hash: string;
|
|
80
|
-
|
|
81
|
-
/** common metadata for documents and collections */
|
|
82
|
-
export interface CommonMetadata {
|
|
83
|
-
/** name of content */
|
|
72
|
+
/** the visible display name of this entry */
|
|
84
73
|
visibleName: string;
|
|
85
|
-
/**
|
|
74
|
+
/** the last modified timestamp */
|
|
75
|
+
lastModified: string;
|
|
76
|
+
/** true if the entry is starred in most ui elements */
|
|
77
|
+
pinned: boolean;
|
|
78
|
+
/**
|
|
79
|
+
* the parent of this entry
|
|
80
|
+
*
|
|
81
|
+
* There are two special parents, "" (empty string) for the root directory,
|
|
82
|
+
* and "trash" for the trash
|
|
83
|
+
*/
|
|
86
84
|
parent?: string;
|
|
87
|
-
/**
|
|
88
|
-
|
|
89
|
-
/** unknown significance */
|
|
90
|
-
version?: number;
|
|
91
|
-
/** unknown significance */
|
|
92
|
-
pinned?: boolean;
|
|
93
|
-
/** unknown significance */
|
|
94
|
-
synced?: boolean;
|
|
95
|
-
/** unknown significance */
|
|
96
|
-
modified?: boolean;
|
|
97
|
-
/** if file is deleted */
|
|
98
|
-
deleted?: boolean;
|
|
99
|
-
/** unknown significance */
|
|
100
|
-
metadatamodified?: boolean;
|
|
85
|
+
/** any tags the entry might have */
|
|
86
|
+
tags?: Tag[];
|
|
101
87
|
}
|
|
102
|
-
/**
|
|
103
|
-
export interface
|
|
104
|
-
/** the key for collection
|
|
88
|
+
/** a folder, referred to in the api as a collection */
|
|
89
|
+
export interface CollectionEntry extends EntryCommon {
|
|
90
|
+
/** the key for this as a collection */
|
|
105
91
|
type: "CollectionType";
|
|
106
92
|
}
|
|
107
|
-
/**
|
|
108
|
-
export interface
|
|
109
|
-
/** the key
|
|
93
|
+
/** a file, referred to in the api as a document */
|
|
94
|
+
export interface DocumentType extends EntryCommon {
|
|
95
|
+
/** the key to identify this as a document */
|
|
110
96
|
type: "DocumentType";
|
|
111
|
-
/**
|
|
112
|
-
|
|
113
|
-
/** last
|
|
114
|
-
|
|
115
|
-
/** created time */
|
|
116
|
-
createdTime?: string;
|
|
97
|
+
/** the type of the file */
|
|
98
|
+
fileType: "epub" | "pdf" | "notebook";
|
|
99
|
+
/** the timestamp of the last time this entry was opened */
|
|
100
|
+
lastOpened: string;
|
|
117
101
|
}
|
|
118
|
-
/**
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
*/
|
|
123
|
-
export type Metadata = CollectionTypeMetadata | DocumentTypeMetadata;
|
|
124
|
-
/** fields common to all {@link MetadataEntry | MetadataEntries} */
|
|
125
|
-
export interface BaseMetadataEntry {
|
|
126
|
-
/** the document id of the entry */
|
|
102
|
+
/** a remarkable entry for cloud items */
|
|
103
|
+
export type Entry = CollectionEntry | DocumentType;
|
|
104
|
+
/** an simple entry without any extra information */
|
|
105
|
+
export interface SimpleEntry {
|
|
106
|
+
/** the document id */
|
|
127
107
|
id: string;
|
|
128
|
-
/** the hash
|
|
108
|
+
/** the document hash */
|
|
129
109
|
hash: string;
|
|
130
110
|
}
|
|
131
|
-
/** the
|
|
132
|
-
export interface
|
|
111
|
+
/** the new hash of a modified entry */
|
|
112
|
+
export interface HashEntry {
|
|
113
|
+
/** the actual hash */
|
|
114
|
+
hash: string;
|
|
133
115
|
}
|
|
134
|
-
/** the
|
|
135
|
-
export interface
|
|
136
|
-
/** the
|
|
137
|
-
|
|
116
|
+
/** the mapping from old hashes to new hashes after a bulk modify */
|
|
117
|
+
export interface HashesEntry {
|
|
118
|
+
/** the mapping from old to new hashes */
|
|
119
|
+
hashes: Record<string, string>;
|
|
138
120
|
}
|
|
139
|
-
/**
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
/** document matrix transform */
|
|
146
|
-
export type Transform = Record<`m${1 | 2 | 3}${1 | 2 | 3}`, number>;
|
|
147
|
-
/** content document metadata */
|
|
148
|
-
export interface DocumentMetadata {
|
|
149
|
-
/** document title */
|
|
150
|
-
title?: string;
|
|
151
|
-
/** document authors */
|
|
152
|
-
authors?: string[];
|
|
153
|
-
}
|
|
154
|
-
/**
|
|
155
|
-
* content metadata
|
|
121
|
+
/** An error that gets thrown when the backend while trying to update
|
|
122
|
+
*
|
|
123
|
+
* IF you encounter this error, you likely just need to try th request again. If
|
|
124
|
+
* you're trying to do several high-level `put` operations simultaneously,
|
|
125
|
+
* you'll likely encounter this error. You should either try to do them
|
|
126
|
+
* serially, or call the low level api directly to do one generation update.
|
|
156
127
|
*
|
|
157
|
-
*
|
|
128
|
+
* @see {@link RawRemarkableApi | `RawRemarkableApi`}
|
|
158
129
|
*/
|
|
159
|
-
export
|
|
160
|
-
|
|
161
|
-
dummyDocument: boolean;
|
|
162
|
-
/** document metadata */
|
|
163
|
-
documentMetadata?: DocumentMetadata;
|
|
164
|
-
/** extra metadata */
|
|
165
|
-
extraMetadata: ExtraMetadata;
|
|
166
|
-
/** file type */
|
|
167
|
-
fileType: FileType;
|
|
168
|
-
/** font */
|
|
169
|
-
fontName?: string;
|
|
170
|
-
/** last opened page */
|
|
171
|
-
lastOpenedPage: number;
|
|
172
|
-
/** line height */
|
|
173
|
-
lineHeight: number;
|
|
174
|
-
/** page margins in points */
|
|
175
|
-
margins: number;
|
|
176
|
-
/** orientation */
|
|
177
|
-
orientation?: "portrait" | "landscape";
|
|
178
|
-
/** number of pages */
|
|
179
|
-
pageCount: number;
|
|
180
|
-
/** page ids */
|
|
181
|
-
pages: string[];
|
|
182
|
-
/** number to use for the coverage page, -1 for last opened */
|
|
183
|
-
coverPageNumber: number;
|
|
184
|
-
/** text scale */
|
|
185
|
-
textScale: number;
|
|
186
|
-
/** page transform */
|
|
187
|
-
transform?: Transform;
|
|
188
|
-
/** format version */
|
|
189
|
-
formatVersion: number;
|
|
190
|
-
/** text alignment */
|
|
191
|
-
textAlignment?: TextAlignment;
|
|
192
|
-
}
|
|
193
|
-
/** stripped down version of RequestInit */
|
|
194
|
-
export interface RequestInitLike {
|
|
195
|
-
/** request method */
|
|
196
|
-
readonly method?: RequestMethod | undefined;
|
|
197
|
-
/** request headers */
|
|
198
|
-
readonly headers?: Record<string, string>;
|
|
199
|
-
/** request body */
|
|
200
|
-
readonly body?: ArrayBuffer | string;
|
|
201
|
-
}
|
|
202
|
-
/** stripped down version of Headers */
|
|
203
|
-
export interface HeadersLike {
|
|
204
|
-
/** get a specific header value */
|
|
205
|
-
get(key: string): string | null;
|
|
206
|
-
}
|
|
207
|
-
/** stripped down version of Response */
|
|
208
|
-
export interface ResponseLike {
|
|
209
|
-
/** true if request was successful */
|
|
210
|
-
ok: boolean;
|
|
211
|
-
/** http status */
|
|
212
|
-
status: number;
|
|
213
|
-
/** text associated with status */
|
|
214
|
-
statusText: string;
|
|
215
|
-
/** headers in response */
|
|
216
|
-
headers: HeadersLike;
|
|
217
|
-
/** get response body as text */
|
|
218
|
-
text(): Promise<string>;
|
|
219
|
-
/** get response body as an array buffer */
|
|
220
|
-
arrayBuffer(): Promise<ArrayBuffer>;
|
|
221
|
-
}
|
|
222
|
-
/** stripped down version of fetch */
|
|
223
|
-
export interface FetchLike {
|
|
224
|
-
/** the rough interface to fetch */
|
|
225
|
-
(url: string, options?: RequestInitLike | undefined): Promise<ResponseLike>;
|
|
226
|
-
}
|
|
227
|
-
/** async storage, map like */
|
|
228
|
-
export interface CacheLike {
|
|
229
|
-
/** get value for key or undefined if missing */
|
|
230
|
-
get(key: string): Promise<string | undefined>;
|
|
231
|
-
/** set value for key */
|
|
232
|
-
set(key: string, value: string): Promise<void>;
|
|
233
|
-
}
|
|
234
|
-
/** stripped down version of subtle crypto */
|
|
235
|
-
export interface SubtleCryptoLike {
|
|
236
|
-
/** a digest function */
|
|
237
|
-
digest(algorithm: "SHA-256", data: BufferSource): Promise<ArrayBuffer>;
|
|
130
|
+
export declare class GenerationError extends Error {
|
|
131
|
+
constructor();
|
|
238
132
|
}
|
|
239
133
|
/** an error that results from a failed request */
|
|
240
134
|
export declare class ResponseError extends Error {
|
|
@@ -244,14 +138,13 @@ export declare class ResponseError extends Error {
|
|
|
244
138
|
readonly statusText: string;
|
|
245
139
|
constructor(status: number, statusText: string, message: string);
|
|
246
140
|
}
|
|
247
|
-
/**
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
constructor();
|
|
141
|
+
/** an error that results from a failed request */
|
|
142
|
+
export declare class ValidationError extends Error {
|
|
143
|
+
/** the response status number */
|
|
144
|
+
readonly field: string;
|
|
145
|
+
/** the response status text */
|
|
146
|
+
readonly regex: RegExp;
|
|
147
|
+
constructor(field: string, regex: RegExp, message: string);
|
|
255
148
|
}
|
|
256
149
|
/** options for registering with the api */
|
|
257
150
|
export interface RegisterOptions {
|
|
@@ -268,8 +161,6 @@ export interface RegisterOptions {
|
|
|
268
161
|
uuid?: string;
|
|
269
162
|
/** The host to use for authorization requests */
|
|
270
163
|
authHost?: string;
|
|
271
|
-
/** a function for making fetch requests, see {@link RemarkableOptions.fetch} for more info */
|
|
272
|
-
fetch?: FetchLike;
|
|
273
164
|
}
|
|
274
165
|
/**
|
|
275
166
|
* register a device and get the token needed to access the api
|
|
@@ -281,312 +172,616 @@ export interface RegisterOptions {
|
|
|
281
172
|
* @param code - the eight letter code a user got from `https://my.remarkable.com/device/browser/connect`.
|
|
282
173
|
* @returns the device token necessary for creating an api instace. These never expire so persist as long as necessary.
|
|
283
174
|
*/
|
|
284
|
-
export declare function register(code: string, { deviceDesc, uuid, authHost,
|
|
285
|
-
/** options
|
|
286
|
-
export interface
|
|
287
|
-
/**
|
|
288
|
-
parent?: string
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
/**
|
|
304
|
-
|
|
175
|
+
export declare function register(code: string, { deviceDesc, uuid, authHost, }?: RegisterOptions): Promise<string>;
|
|
176
|
+
/** options available when uploading a document */
|
|
177
|
+
export interface UploadOptions {
|
|
178
|
+
/** an optional parent id to set when uploading */
|
|
179
|
+
parent?: string;
|
|
180
|
+
}
|
|
181
|
+
/** document metadata stored in {@link Content} */
|
|
182
|
+
export interface DocumentMetadata {
|
|
183
|
+
/** a list of authors as a string */
|
|
184
|
+
authors?: string[];
|
|
185
|
+
/** the title as a string */
|
|
186
|
+
title?: string;
|
|
187
|
+
/** the publication date as an ISO date or timestamp */
|
|
188
|
+
publicationDate?: string;
|
|
189
|
+
/** the publisher */
|
|
190
|
+
publisher?: string;
|
|
191
|
+
}
|
|
192
|
+
/** [speculative] metadata stored about keyboard interactions */
|
|
193
|
+
export interface KeyboardMetadata {
|
|
194
|
+
/** [unknown] */
|
|
195
|
+
count: number;
|
|
196
|
+
/** [unknown] */
|
|
197
|
+
timestamp: number;
|
|
198
|
+
}
|
|
199
|
+
/** a c-page value who's type is a string */
|
|
200
|
+
export interface CPageStringValue {
|
|
201
|
+
/** a pseudo-timestamp of the form "1:1" or "1:2" */
|
|
202
|
+
timestamp: string;
|
|
203
|
+
/** the stored value */
|
|
204
|
+
value: string;
|
|
205
|
+
}
|
|
206
|
+
/** a c-page value who's type is a string */
|
|
207
|
+
export interface CPageNumberValue {
|
|
208
|
+
/** a pseudo-timestamp of the form "1:1" or "1:2" */
|
|
209
|
+
timestamp: string;
|
|
210
|
+
/** the stored value */
|
|
211
|
+
value: number;
|
|
212
|
+
}
|
|
213
|
+
/** [speculative] information about an individual page */
|
|
214
|
+
export interface CPagePage {
|
|
215
|
+
/** [speculative] the page id */
|
|
216
|
+
id: string;
|
|
217
|
+
/** [unknown] values are like "aa", "ab", "ba", etc. */
|
|
218
|
+
idx: CPageStringValue;
|
|
219
|
+
/** [unknown] */
|
|
220
|
+
redir?: CPageNumberValue;
|
|
221
|
+
/** [speculative] the template name of the page */
|
|
222
|
+
template?: CPageStringValue;
|
|
223
|
+
/** [unknown] the value is a timestamp */
|
|
224
|
+
scrollTime?: CPageStringValue;
|
|
225
|
+
/** [unknown] */
|
|
226
|
+
verticalScroll?: CPageNumberValue;
|
|
227
|
+
/** [unknown] */
|
|
228
|
+
deleted?: CPageNumberValue;
|
|
229
|
+
}
|
|
230
|
+
/** [unknown] */
|
|
231
|
+
export interface CPageUUID {
|
|
232
|
+
/** [unknown] */
|
|
233
|
+
first: string;
|
|
234
|
+
/** [unknown] */
|
|
235
|
+
second: number;
|
|
236
|
+
}
|
|
237
|
+
/** [unknown] metadata about pages */
|
|
238
|
+
export interface CPages {
|
|
239
|
+
/** [speculative] the last time the document was opened */
|
|
240
|
+
lastOpened: CPageStringValue;
|
|
241
|
+
/** [unknown] */
|
|
242
|
+
original: CPageNumberValue;
|
|
243
|
+
/** [speculative] information about individual pages */
|
|
244
|
+
pages: CPagePage[];
|
|
245
|
+
/** [unknown] */
|
|
246
|
+
uuids: CPageUUID[];
|
|
247
|
+
}
|
|
248
|
+
/** the content metadata for collections (folders) */
|
|
249
|
+
export interface CollectionContent {
|
|
250
|
+
/** the tags for the collection */
|
|
251
|
+
tags?: Tag[];
|
|
252
|
+
/** collections don't have a file type */
|
|
253
|
+
fileType?: undefined;
|
|
305
254
|
}
|
|
306
255
|
/**
|
|
307
|
-
*
|
|
256
|
+
* content metadata, stored with the "content" extension
|
|
257
|
+
*
|
|
258
|
+
* This largely contains description of how to render the document, rather than
|
|
259
|
+
* metadata about it.
|
|
308
260
|
*/
|
|
309
|
-
export interface
|
|
261
|
+
export interface DocumentContent {
|
|
310
262
|
/**
|
|
311
|
-
*
|
|
263
|
+
* which page to use for the thumbnail
|
|
312
264
|
*
|
|
313
|
-
*
|
|
265
|
+
* -1 indicates the last visited page, whereas 0 is the first page.
|
|
314
266
|
*/
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
*/
|
|
321
|
-
|
|
267
|
+
coverPageNumber: number;
|
|
268
|
+
/** metadata about the author, publishers, etc. */
|
|
269
|
+
documentMetadata: DocumentMetadata;
|
|
270
|
+
/** It's not known what this field is for */
|
|
271
|
+
dummyDocument?: boolean;
|
|
272
|
+
/** the largely contains metadata about what pens were used and their settings */
|
|
273
|
+
extraMetadata: Record<string, string>;
|
|
274
|
+
/** the underlying file type of this document */
|
|
275
|
+
fileType: FileType;
|
|
276
|
+
/**
|
|
277
|
+
* the name of the font to use for text rendering
|
|
278
|
+
*
|
|
279
|
+
* The reMarkable supports five fonts by default: "Noto Sans", "Noto Sans UI",
|
|
280
|
+
* "EB Garamond", "Noto Mono", and "Noto Serif". You can also set the font to
|
|
281
|
+
* the empty string or omit it for the default.
|
|
282
|
+
*/
|
|
283
|
+
fontName: string;
|
|
284
|
+
/** the format version, this should always be 1 */
|
|
285
|
+
formatVersion: number;
|
|
286
|
+
/** the last opened page, starts at zero */
|
|
287
|
+
lastOpenedPage?: number;
|
|
322
288
|
/**
|
|
323
|
-
*
|
|
289
|
+
* the line height
|
|
324
290
|
*
|
|
325
|
-
*
|
|
291
|
+
* The reMarkable uses three built-in line heights: 100, 150, 200, and
|
|
292
|
+
* uses -1 to indicate the default line height, but heights outside of these
|
|
293
|
+
* also work.
|
|
326
294
|
*/
|
|
327
|
-
|
|
295
|
+
lineHeight: number;
|
|
328
296
|
/**
|
|
329
|
-
*
|
|
297
|
+
* the document margin in pixels
|
|
330
298
|
*
|
|
331
|
-
*
|
|
299
|
+
* The reMarkable uses three built-in margins: 50, 125, 200, but other margins
|
|
300
|
+
* are possible. The reMarkable used to default to margins of 180.
|
|
332
301
|
*/
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
302
|
+
margins: number;
|
|
303
|
+
/** the document orientation */
|
|
304
|
+
orientation: Orientation;
|
|
305
|
+
/** this specifies the number of pages, it's not clear how this is different than pageCount */
|
|
306
|
+
originalPageCount?: number;
|
|
307
|
+
/** the number of pages */
|
|
308
|
+
pageCount: number;
|
|
309
|
+
/** the page tags for the document */
|
|
310
|
+
pageTags?: PageTag[];
|
|
311
|
+
/** a list of the ids of each page in the document */
|
|
312
|
+
pages?: string[];
|
|
313
|
+
/** a mapping from page number to page id in pages */
|
|
314
|
+
redirectionPageMap?: number[];
|
|
315
|
+
/** ostensibly the size in bytes of the file, but this differs from other measurements */
|
|
316
|
+
sizeInBytes: string;
|
|
317
|
+
/** document tags for this document */
|
|
318
|
+
tags?: Tag[];
|
|
319
|
+
/** text alignment for this document */
|
|
320
|
+
textAlignment: TextAlignment;
|
|
321
|
+
/**
|
|
322
|
+
* the font size
|
|
323
|
+
*
|
|
324
|
+
* reMarkable uses six built-in text scales: 0.7, 0.8, 1, 1.2, 1.5, 2, but
|
|
325
|
+
* values outside of this range are valid.
|
|
326
|
+
*/
|
|
327
|
+
textScale: number;
|
|
328
|
+
/** [speculative] the center of the zoom for zoomed in documents */
|
|
329
|
+
customZoomCenterX?: number;
|
|
330
|
+
/** [speculative] the center of the zoom for zoomed in documents */
|
|
331
|
+
customZoomCenterY?: number;
|
|
332
|
+
/** [speculative] the orientation */
|
|
333
|
+
customZoomOrientation?: Orientation;
|
|
334
|
+
/** [speculative] the zoom height for zoomed in pages */
|
|
335
|
+
customZoomPageHeight?: number;
|
|
336
|
+
/** [speculative] the zoom width for zoomed in pages */
|
|
337
|
+
customZoomPageWidth?: number;
|
|
338
|
+
/** [speculative] the scale for zoomed in pages */
|
|
339
|
+
customZoomScale?: number;
|
|
340
|
+
/** what zoom mode is set for the page */
|
|
341
|
+
zoomMode?: ZoomMode;
|
|
342
|
+
/** [speculative] a transform matrix, a. la. css matrix transform */
|
|
343
|
+
transform?: Record<`m${"1" | "2" | "3"}${"1" | "2" | "3"}`, number>;
|
|
344
|
+
/** [speculative] metadata about keyboard use */
|
|
345
|
+
keyboardMetadata?: KeyboardMetadata;
|
|
346
|
+
/** [speculative] various other page metadata */
|
|
347
|
+
cPages?: CPages;
|
|
348
|
+
/**
|
|
349
|
+
* setting for the adaptive contrast filter
|
|
350
|
+
*
|
|
351
|
+
* off has no background filter, best for images, full page applies the high
|
|
352
|
+
* contrast filter to the entire page. If this is omitted, reMarkable will try
|
|
353
|
+
* to apply the filter only to text areas.
|
|
354
|
+
*/
|
|
355
|
+
viewBackgroundFilter?: BackgroundFilter;
|
|
345
356
|
}
|
|
346
|
-
/**
|
|
347
|
-
export
|
|
357
|
+
/** content metadata for any item */
|
|
358
|
+
export type Content = CollectionContent | DocumentContent;
|
|
359
|
+
/**
|
|
360
|
+
* item level metadata
|
|
361
|
+
*
|
|
362
|
+
* Stored with the extension "metadata".
|
|
363
|
+
*/
|
|
364
|
+
export interface Metadata {
|
|
365
|
+
/** creation time, a string of the epoch timestamp */
|
|
366
|
+
createdTime?: string;
|
|
367
|
+
/** [speculative] true if the item has been actually deleted */
|
|
368
|
+
deleted?: boolean;
|
|
369
|
+
/** the last modify time, the string of the epoch timestamp */
|
|
370
|
+
lastModified: string;
|
|
371
|
+
/** the last opened epoch timestamp, isn't defined for CollectionType */
|
|
372
|
+
lastOpened?: string;
|
|
373
|
+
/** the last page opened, isn't defined for CollectionType, starts at 0*/
|
|
374
|
+
lastOpenedPage?: number;
|
|
375
|
+
/** [speculative] true if the metadata has been modified */
|
|
376
|
+
metadatamodified?: boolean;
|
|
377
|
+
/** [speculative] true if the item has been modified */
|
|
378
|
+
modified?: boolean;
|
|
348
379
|
/**
|
|
349
|
-
*
|
|
380
|
+
* the id of the parent collection
|
|
350
381
|
*
|
|
351
|
-
*
|
|
352
|
-
*
|
|
382
|
+
* This is the empty string for root (no parent), "trash" if it's in the
|
|
383
|
+
* trash, or the id of the parent.
|
|
353
384
|
*/
|
|
354
|
-
|
|
385
|
+
parent: string;
|
|
386
|
+
/** true of the item is starred */
|
|
387
|
+
pinned: boolean;
|
|
388
|
+
/** [unknown] */
|
|
389
|
+
synced?: boolean;
|
|
390
|
+
/**
|
|
391
|
+
* the type of item this corresponds to
|
|
392
|
+
*
|
|
393
|
+
* DocumentType is a document, an epub, pdf, or notebook, CollectionType is a
|
|
394
|
+
* folder.
|
|
395
|
+
*/
|
|
396
|
+
type: "DocumentType" | "CollectionType";
|
|
397
|
+
/** [speculative] metadata version, always 0 */
|
|
398
|
+
version?: number;
|
|
399
|
+
/** the visible name of the item, what it's called on the reMarkable */
|
|
400
|
+
visibleName: string;
|
|
355
401
|
}
|
|
356
402
|
/**
|
|
357
|
-
*
|
|
403
|
+
* options for putting a file onto reMarkable
|
|
404
|
+
*
|
|
405
|
+
* This is a more customizable version of the options available when using the
|
|
406
|
+
* simpler upload api. This comes with the risk that is uses lower level apis,
|
|
407
|
+
* and therefore has more failure points.
|
|
408
|
+
*
|
|
409
|
+
* @see {@link Content | `Content`} and {@link Metadata | `Metadata`} for more
|
|
410
|
+
* information on what these fields correspond to
|
|
358
411
|
*/
|
|
359
|
-
export interface
|
|
412
|
+
export interface PutOptions {
|
|
360
413
|
/**
|
|
361
|
-
*
|
|
414
|
+
* the collection to put this in
|
|
362
415
|
*
|
|
363
|
-
*
|
|
416
|
+
* The empty string ("") (default) is the root, "trash" is in the trash,
|
|
417
|
+
* otherwise this should be the uuid of a collection item to place this in.
|
|
364
418
|
*/
|
|
365
|
-
|
|
419
|
+
parent?: string;
|
|
420
|
+
/** true to star the item */
|
|
421
|
+
pinned?: boolean;
|
|
422
|
+
/** 0 for first page, -1 for last visited */
|
|
423
|
+
coverPageNumber?: number;
|
|
424
|
+
/** document metadata authors */
|
|
425
|
+
authors?: string[];
|
|
426
|
+
/** document metadata tile, NOTE this is not visibleName */
|
|
427
|
+
title?: string;
|
|
428
|
+
/** the publication date, as an ISO date or timestamp */
|
|
429
|
+
publicationDate?: string;
|
|
430
|
+
/** the publisher */
|
|
431
|
+
publisher?: string;
|
|
432
|
+
/** extra metadata often in the form of pen choices */
|
|
433
|
+
extraMetadata?: Record<string, string>;
|
|
434
|
+
/** the font to use for rendering */
|
|
435
|
+
fontName?: string;
|
|
436
|
+
/** the line height to render */
|
|
437
|
+
lineHeight?: number;
|
|
438
|
+
/** the margins to render */
|
|
439
|
+
margins?: number;
|
|
440
|
+
/** the document orientation */
|
|
441
|
+
orientation?: Orientation;
|
|
442
|
+
/** the names of the tags to add */
|
|
443
|
+
tags?: string[];
|
|
444
|
+
/** the document text alignment */
|
|
445
|
+
textAlignment?: TextAlignment;
|
|
446
|
+
/** the text scale of the document */
|
|
447
|
+
textScale?: number;
|
|
448
|
+
/** the document zoom mode */
|
|
449
|
+
zoomMode?: ZoomMode;
|
|
450
|
+
/** the contrast filter setting */
|
|
451
|
+
viewBackgroundFilter?: BackgroundFilter;
|
|
366
452
|
/**
|
|
367
|
-
*
|
|
453
|
+
* whether to refresh current file structure before putting
|
|
368
454
|
*
|
|
369
|
-
*
|
|
370
|
-
*
|
|
371
|
-
*
|
|
455
|
+
* If you suspect that other changes have been made to the remarkable backend
|
|
456
|
+
* between the last put and now, setting this to true will avoid a
|
|
457
|
+
* {@link GenerationError | `GenerationError`}, but will cause an unnecessary
|
|
458
|
+
* GET request otherwise.
|
|
459
|
+
*/
|
|
460
|
+
refresh?: boolean;
|
|
461
|
+
}
|
|
462
|
+
/**
|
|
463
|
+
* access to the low-level reMarkable api
|
|
464
|
+
*
|
|
465
|
+
* This class gives more granualar access to the reMarkable cloud, but is more
|
|
466
|
+
* dangerous.
|
|
467
|
+
*
|
|
468
|
+
* ## Overview
|
|
469
|
+
*
|
|
470
|
+
* reMarkable uses an immutable file system, where each file is referenced by
|
|
471
|
+
* the 32 byte sha256 hash of its contents. Each file also has an id used to
|
|
472
|
+
* keep track of updates, so to "update" a file, you upload a new file, and
|
|
473
|
+
* change the hash associated with it's id.
|
|
474
|
+
*
|
|
475
|
+
* Each "item" (a document or a collection) is actually a list of files.
|
|
476
|
+
* The whole reMarkable state is then a list of these lists. Finally, the hash
|
|
477
|
+
* of that list is called the rootHash. To update anything, you have to update
|
|
478
|
+
* the root hash to point to a new list of updated items.
|
|
479
|
+
*
|
|
480
|
+
* This can be dangerous, as corrupting the root hash can destroy all of your
|
|
481
|
+
* files. It is therefore highly recommended to save your current root hash
|
|
482
|
+
* ({@link getRootHash | `getRootHash`}) before using this api to attempt file
|
|
483
|
+
* writes, so you can recover a previous "snapshot" should anything go wrong.
|
|
484
|
+
*
|
|
485
|
+
* ## Items
|
|
486
|
+
*
|
|
487
|
+
* Each item is a collection of individual files. Using
|
|
488
|
+
* {@link getEntries | `getEntries`} on the root hash will give you a list
|
|
489
|
+
* entries that correspond to items. Using `getEntries` on any of those items
|
|
490
|
+
* will get you the files that make up that item.
|
|
491
|
+
*
|
|
492
|
+
* The documented files are:
|
|
493
|
+
* - `<docid>.pdf` - a raw pdf document
|
|
494
|
+
* - `<docid>.epub` - a raw epub document
|
|
495
|
+
* - `<docid>.content` - a json file roughly describing document properties (see {@link DocumentContent | `DocumentContent`})
|
|
496
|
+
* - `<docid>.metadata` - metadata about the document (see {@link Metadata | `Metadata`})
|
|
497
|
+
* - `<docid>.pagedata` - a text file where each line is the template of that page
|
|
498
|
+
* - `<docid>/<pageid>.rm` - [speculative] raw remarkable vectors, text, etc
|
|
499
|
+
* - `<docid>/<pageid>-metadata.json` - [speculative] metadata about the individual page
|
|
500
|
+
* - `<docid>.highlights/<pageid>.json` - [speculative] highlights on the page
|
|
501
|
+
*
|
|
502
|
+
* Some items will have both a `.pdf` and `.epub` file, likely due to preparing
|
|
503
|
+
* for export. Collections only have `.content` and `.metadata` files, with
|
|
504
|
+
* `.content` only containing tags.
|
|
505
|
+
*
|
|
506
|
+
* ## Caching
|
|
507
|
+
*
|
|
508
|
+
* Since everything is tied to the hash of it's contents, we can agressively
|
|
509
|
+
* cache results. We assume that text contents are "small" and so fully cache
|
|
510
|
+
* them, where as binary files we treat as large and only store that we know
|
|
511
|
+
* they exist to prevent future writes.
|
|
512
|
+
*
|
|
513
|
+
* By default, this only persists as long as the api instance is alive. However,
|
|
514
|
+
* for performance reasons, you should call {@link dumpCache | `dumpCache`} to
|
|
515
|
+
* persist the cache between sessions.
|
|
516
|
+
*
|
|
517
|
+
* @remarks
|
|
518
|
+
*
|
|
519
|
+
* Generally all hashes are 64 character hex strings, and all ids are uuid4.
|
|
520
|
+
*/
|
|
521
|
+
export interface RawRemarkableApi {
|
|
522
|
+
/**
|
|
523
|
+
* gets the root hash and the current generation
|
|
372
524
|
*
|
|
373
|
-
*
|
|
374
|
-
*
|
|
375
|
-
* change what's actually visible. If you're unsure if you're doing the right
|
|
376
|
-
* thing, make sure to first save your inital root hash. Then you can always
|
|
377
|
-
* recover by doing:
|
|
378
|
-
* ```
|
|
379
|
-
* let [, gen] = await api.getRootHash();
|
|
380
|
-
* await api.putRootHash(backup, gen);
|
|
381
|
-
* ```
|
|
525
|
+
* When calling `putRootHash`, you should pass the generation you got from
|
|
526
|
+
* this call. That way you tell reMarkable you're updating the previous state.
|
|
382
527
|
*
|
|
383
|
-
* @
|
|
384
|
-
* @param generation - the current generation this builds off of
|
|
385
|
-
* @returns the new generation
|
|
386
|
-
* @throws {@link GenerationError} if the current cloud generation didn't
|
|
387
|
-
* match the expected pushed generation.
|
|
528
|
+
* @returns the root hash and the current generation
|
|
388
529
|
*/
|
|
389
|
-
|
|
530
|
+
getRootHash(): Promise<[string, number]>;
|
|
390
531
|
/**
|
|
391
|
-
* get
|
|
532
|
+
* get the raw binary data associated with a hash
|
|
392
533
|
*
|
|
393
|
-
* @param hash - the hash to get
|
|
534
|
+
* @param hash - the hash to get the data for
|
|
535
|
+
* @returns the data
|
|
394
536
|
*/
|
|
395
|
-
|
|
537
|
+
getHash(hash: string): Promise<Uint8Array>;
|
|
396
538
|
/**
|
|
397
|
-
* get text
|
|
539
|
+
* get raw text data associated with a hash
|
|
398
540
|
*
|
|
399
|
-
*
|
|
541
|
+
* We assume text data are small, and so cache the entire text. If you want to
|
|
542
|
+
* avoid this, use {@link getHash | `getHash`} combined with a TextDecoder.
|
|
543
|
+
|
|
544
|
+
* @param hash - the hash to get text for
|
|
545
|
+
* @returns the text
|
|
400
546
|
*/
|
|
401
547
|
getText(hash: string): Promise<string>;
|
|
402
548
|
/**
|
|
403
|
-
* get
|
|
549
|
+
* get the entries associated with a list hash
|
|
404
550
|
*
|
|
405
|
-
*
|
|
406
|
-
*
|
|
551
|
+
* A list hash is the root hash, or any hash with the type 80000000. NOTE
|
|
552
|
+
* these are hashed differently than files.
|
|
553
|
+
|
|
554
|
+
* @param hash - the hash to get entries for
|
|
555
|
+
* @returns the entries
|
|
407
556
|
*/
|
|
408
|
-
|
|
409
|
-
/** get metadata from hash */
|
|
410
|
-
getMetadata(hash: string, opts?: GetOptions): Promise<Metadata>;
|
|
557
|
+
getEntries(hash: string): Promise<RawEntry[]>;
|
|
411
558
|
/**
|
|
412
|
-
* get
|
|
559
|
+
* get the parsed and validated `Content` of a content hash
|
|
413
560
|
*
|
|
414
|
-
*
|
|
561
|
+
* Use {@link getText | `getText`} combined with `JSON.parse` to bypass
|
|
562
|
+
* validation
|
|
563
|
+
|
|
564
|
+
* @param hash - the hash to get Content for
|
|
565
|
+
* @returns the content
|
|
415
566
|
*/
|
|
416
|
-
|
|
417
|
-
/** put a reference to a set of entries into the cloud */
|
|
418
|
-
putEntries(documentId: string, entries: Entry[]): Promise<CollectionEntry>;
|
|
419
|
-
/** put a raw buffer in the cloud */
|
|
420
|
-
putBuffer(documentId: string, buffer: ArrayBuffer): Promise<FileEntry>;
|
|
567
|
+
getContent(hash: string): Promise<Content>;
|
|
421
568
|
/**
|
|
422
|
-
*
|
|
569
|
+
* get the parsed and validated `Metadata` of a metadata hash
|
|
423
570
|
*
|
|
424
|
-
*
|
|
571
|
+
* Use {@link getText | `getText`} combined with `JSON.parse` to bypass
|
|
572
|
+
* validation
|
|
573
|
+
|
|
574
|
+
* @param hash - the hash to get Metadata for
|
|
575
|
+
* @returns the metadata
|
|
425
576
|
*/
|
|
426
|
-
|
|
577
|
+
getMetadata(hash: string): Promise<Metadata>;
|
|
427
578
|
/**
|
|
428
|
-
*
|
|
429
|
-
*
|
|
430
|
-
* This
|
|
431
|
-
*
|
|
579
|
+
* update the current root hash
|
|
580
|
+
*
|
|
581
|
+
* This will fail if generation doesn't match the current server generation.
|
|
582
|
+
* This ensures that you are updating what you expect. IF you get a
|
|
583
|
+
* {@link GenerationError | `GenerationError`}, that indicates that the server
|
|
584
|
+
* was updated after you last got the generation. You should call
|
|
585
|
+
* {@link getRootHash | `getRootHash`} and then recompute the changes you want
|
|
586
|
+
* from the new root hash. If you ignore the update hash value and just call
|
|
587
|
+
* `putRootHash` again, you will overwrite the changes made by the other
|
|
588
|
+
* update.
|
|
589
|
+
*
|
|
590
|
+
* @param hash - the new root hash
|
|
591
|
+
* @param generation - the generation of the current root hash
|
|
592
|
+
* @param broadcast - [unknown] an option in the request
|
|
593
|
+
*
|
|
594
|
+
* @throws GenerationError if the generation doesn't match the current server generation
|
|
595
|
+
* @returns the new root hash and the new generation
|
|
432
596
|
*/
|
|
433
|
-
|
|
597
|
+
putRootHash(hash: string, generation: number, broadcast?: boolean): Promise<[string, number]>;
|
|
434
598
|
/**
|
|
435
|
-
* put
|
|
599
|
+
* put a raw onto the server
|
|
600
|
+
*
|
|
601
|
+
* This returns the new expeced entry of the file you uploaded, and a promise
|
|
602
|
+
* to finish the upload successful. By splitting these two operations you can
|
|
603
|
+
* start using the uploaded entry while file finishes uploading.
|
|
436
604
|
*
|
|
437
|
-
* This
|
|
605
|
+
* NOTE: This won't update the state of the reMarkable until this entry is
|
|
606
|
+
* incorporated into the root hash.
|
|
438
607
|
*
|
|
439
|
-
* @param
|
|
440
|
-
*
|
|
441
|
-
* @
|
|
608
|
+
* @param id - the id of the file to upload
|
|
609
|
+
* @param bytes - the bytes to upload
|
|
610
|
+
* @returns the new entry and a promise to finish the upload
|
|
442
611
|
*/
|
|
443
|
-
|
|
612
|
+
putFile(id: string, bytes: Uint8Array): Promise<[RawFileEntry, Promise<void>]>;
|
|
613
|
+
/** the same as {@link putFile | `putFile`} but with caching for text */
|
|
614
|
+
putText(id: string, content: string): Promise<[RawFileEntry, Promise<void>]>;
|
|
615
|
+
/** the same as {@link putText | `putText`} but with extra validation for Content */
|
|
616
|
+
putContent(id: string, content: Content): Promise<[RawFileEntry, Promise<void>]>;
|
|
617
|
+
/** the same as {@link putText | `putText`} but with extra validation for Metadata */
|
|
618
|
+
putMetadata(id: string, metadata: Metadata): Promise<[RawFileEntry, Promise<void>]>;
|
|
444
619
|
/**
|
|
445
|
-
*
|
|
620
|
+
* put a set of entries to make an entry list file
|
|
621
|
+
*
|
|
622
|
+
* To fully upload an item:
|
|
623
|
+
* 1. upload all the constituent files and metadata
|
|
624
|
+
* 2. call this with all of the entries
|
|
625
|
+
* 3. append this entry to the root entry and call this again to update this root list
|
|
626
|
+
* 4. put the new root hash
|
|
627
|
+
*
|
|
628
|
+
* @param id - the id of the list to upload - this should be the item id if
|
|
629
|
+
* uploading an item list, or "root" if uploading a new root list.
|
|
630
|
+
* @param entries - the entries to upload
|
|
631
|
+
* @returns the new list entry and a promise to finish the upload
|
|
632
|
+
*/
|
|
633
|
+
putEntries(id: string, entries: RawEntry[]): Promise<[RawListEntry, Promise<void>]>;
|
|
634
|
+
/**
|
|
635
|
+
* dump the current cache to a string to preserve between session
|
|
446
636
|
*
|
|
447
|
-
* @
|
|
448
|
-
* @param parent - the documentId of the parent collection (folder)
|
|
637
|
+
* @returns a serialized version of the cache to pass to a new api instance
|
|
449
638
|
*/
|
|
450
|
-
|
|
639
|
+
dumpCache(): string;
|
|
640
|
+
/** completely clear the cache */
|
|
641
|
+
clearCache(): void;
|
|
642
|
+
}
|
|
643
|
+
/**
|
|
644
|
+
* the api for accessing remarkable functions
|
|
645
|
+
*
|
|
646
|
+
* There are roughly two types of functions.
|
|
647
|
+
* - high-level api functions that provide simple access with a single round
|
|
648
|
+
* trip based on the web api
|
|
649
|
+
* - low-level wrapped functions that take more round trips, but provide more
|
|
650
|
+
* control and may be faster since they can be cached.
|
|
651
|
+
*
|
|
652
|
+
* Most of these functions validate the return values so that typescript is
|
|
653
|
+
* accurate. However, sometimes those return values are more strict than the
|
|
654
|
+
* "true" underlying types. If this happens, please [submit a an
|
|
655
|
+
* issue](https://github.com/erikbrinkman/rmapi-js/issues). In the mean time,
|
|
656
|
+
* you should be able to use the low level api to work around any restrictive
|
|
657
|
+
* validation.
|
|
658
|
+
*/
|
|
659
|
+
export interface RemarkableApi {
|
|
660
|
+
/** scoped access to the raw low-level api */
|
|
661
|
+
raw: RawRemarkableApi;
|
|
451
662
|
/**
|
|
452
|
-
*
|
|
663
|
+
* list all items
|
|
453
664
|
*
|
|
454
|
-
*
|
|
455
|
-
*
|
|
456
|
-
*
|
|
457
|
-
* other devices.
|
|
665
|
+
* Items include both collections and documents. Documents that are in folders
|
|
666
|
+
* will have their parent set to something other than "" or "trash", but
|
|
667
|
+
* everything will be returned by this function.
|
|
458
668
|
*
|
|
459
669
|
* @example
|
|
460
|
-
* This example shows a full process upload. Note that it may fail if other
|
|
461
|
-
* devices are simultaneously syncing content. See {@link putRootHash} for
|
|
462
|
-
* more information.
|
|
463
|
-
*
|
|
464
670
|
* ```ts
|
|
465
|
-
*
|
|
466
|
-
* await api.create(entry);
|
|
671
|
+
* await api.listItems();
|
|
467
672
|
* ```
|
|
468
673
|
*
|
|
469
|
-
* @
|
|
470
|
-
* @param buffer - the epub contents
|
|
471
|
-
* @param opts - extra options you can specify at upload
|
|
674
|
+
* @returns a list of all items with some metadata
|
|
472
675
|
*/
|
|
473
|
-
|
|
676
|
+
listItems(): Promise<Entry[]>;
|
|
474
677
|
/**
|
|
475
|
-
*
|
|
678
|
+
* similar to {@link listItems | `listItems`} but backed by the low level api
|
|
476
679
|
*
|
|
477
|
-
* @
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
680
|
+
* @param refresh - if true, refresh the root hash before listing
|
|
681
|
+
*/
|
|
682
|
+
listIds(refresh?: boolean): Promise<SimpleEntry[]>;
|
|
683
|
+
/**
|
|
684
|
+
* get the content metadata from an item hash
|
|
481
685
|
*
|
|
482
|
-
*
|
|
483
|
-
*
|
|
484
|
-
* devices are simultaneously syncing content. See {@link putRootHash} for
|
|
485
|
-
* more information.
|
|
686
|
+
* This takes the high level item hash, e.g. the hashes you get from
|
|
687
|
+
* {@link listItems | `listItems`} or {@link listIds | `listIds`}.
|
|
486
688
|
*
|
|
487
|
-
*
|
|
488
|
-
*
|
|
489
|
-
*
|
|
490
|
-
*
|
|
689
|
+
* @remarks
|
|
690
|
+
* If this fails validation and you still want to get the content, you can use
|
|
691
|
+
* the low-level api to get the raw text of the `.content` file in the
|
|
692
|
+
* `RawListEntry` for this hash.
|
|
491
693
|
*
|
|
492
|
-
* @param
|
|
493
|
-
* @
|
|
494
|
-
* @param opts - extra options you can specify at upload
|
|
694
|
+
* @param hash - the hash of the item to get content for
|
|
695
|
+
* @returns the content
|
|
495
696
|
*/
|
|
496
|
-
|
|
697
|
+
getContent(hash: string): Promise<Content>;
|
|
497
698
|
/**
|
|
498
|
-
*
|
|
699
|
+
* get the metadata from an item hash
|
|
499
700
|
*
|
|
500
|
-
*
|
|
501
|
-
*
|
|
701
|
+
* This takes the high level item hash, e.g. the hashes you get from
|
|
702
|
+
* {@link listItems | `listItems`} or {@link listIds | `listIds`}.
|
|
703
|
+
*
|
|
704
|
+
* @remarks
|
|
705
|
+
* If this fails validation and you still want to get the content, you can use
|
|
706
|
+
* the low-level api to get the raw text of the `.metadata` file in the
|
|
707
|
+
* `RawListEntry` for this hash.
|
|
708
|
+
*
|
|
709
|
+
* @param hash - the hash of the item to get metadata for
|
|
710
|
+
* @returns the metadata
|
|
502
711
|
*/
|
|
503
|
-
|
|
712
|
+
getMetadata(hash: string): Promise<Metadata>;
|
|
504
713
|
/**
|
|
505
|
-
*
|
|
714
|
+
* get the pdf associated with a document hash
|
|
506
715
|
*
|
|
507
|
-
*
|
|
508
|
-
* {@link RemarkableApi.putCollection | `putCollection`},
|
|
509
|
-
* {@link RemarkableApi.putEpub | `putEpub`}, or
|
|
510
|
-
* {@link RemarkableApi.putPdf | `putPdf`}, this is a high level API to try
|
|
511
|
-
* syncing the change to the remarkable.
|
|
716
|
+
* This returns the raw input pdf, not the rendered pdf with any markup.
|
|
512
717
|
*
|
|
513
|
-
* @
|
|
514
|
-
*
|
|
515
|
-
*
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
*
|
|
520
|
-
* 2. It includes no handling of concurrent modification or other networking
|
|
521
|
-
* errors, requiring repeat network requests if anything fails.
|
|
522
|
-
*
|
|
523
|
-
* However, with recent changes in the way this library caches results, it
|
|
524
|
-
* won't be terribly inefficient to just do multiple retries of create after
|
|
525
|
-
* uploading the file itself.
|
|
718
|
+
* @param hash - the hash of the document to get the pdf for (e.g. the hash
|
|
719
|
+
* received from `listItems`)
|
|
720
|
+
* @returns the pdf bytes
|
|
721
|
+
*/
|
|
722
|
+
getPdf(hash: string): Promise<Uint8Array>;
|
|
723
|
+
/**
|
|
724
|
+
* get the epub associated with a document hash
|
|
526
725
|
*
|
|
527
|
-
*
|
|
528
|
-
* ```ts
|
|
529
|
-
* const entry = await api.putEpub(...);
|
|
530
|
-
* await api.create(entry);
|
|
531
|
-
* ```
|
|
726
|
+
* This returns the raw input epub if a document was created from an epub.
|
|
532
727
|
*
|
|
533
|
-
* @param
|
|
534
|
-
*
|
|
535
|
-
* @returns
|
|
536
|
-
* @throws error - if any error occurred, in this case, nothing will be
|
|
537
|
-
* changed
|
|
728
|
+
* @param hash - the hash of the document to get the pdf for (e.g. the hash
|
|
729
|
+
* received from `listItems`)
|
|
730
|
+
* @returns the epub bytes
|
|
538
731
|
*/
|
|
539
|
-
|
|
732
|
+
getEpub(hash: string): Promise<Uint8Array>;
|
|
540
733
|
/**
|
|
541
|
-
*
|
|
734
|
+
* get the entire contents of a remarkable document
|
|
542
735
|
*
|
|
543
|
-
*
|
|
736
|
+
* This gets every file of associated with a document, and puts them into a
|
|
737
|
+
* zip archive.
|
|
544
738
|
*
|
|
545
739
|
* @remarks
|
|
546
|
-
* This
|
|
547
|
-
*
|
|
548
|
-
*
|
|
549
|
-
* 1. For most use cases, it will repeat requests to remarkable's servers
|
|
550
|
-
* (even with a cache) making it slower than implementing similar steps
|
|
551
|
-
* manually.
|
|
552
|
-
* 2. It includes no handling of concurrent modification or other networking
|
|
553
|
-
* errors, requiring repeat network requests if anything fails.
|
|
554
|
-
*
|
|
555
|
-
* However, with changes to the way this caches results, it won't be terribly
|
|
556
|
-
* inefficient to just retry calling `move` if there's a failure.
|
|
557
|
-
*
|
|
558
|
-
* @example
|
|
559
|
-
* ```ts
|
|
560
|
-
* const [root] = await api.getRootHash();
|
|
561
|
-
* const entries = await api.getEntries(root);
|
|
562
|
-
* const { documentId } = entries.find(...);
|
|
563
|
-
* await api.move(documentId, "trash");
|
|
564
|
-
* ```
|
|
740
|
+
* This is an experimental feature, that works for downloading the raw version
|
|
741
|
+
* of the document, but this format isn't understood enoguh to reput this on a
|
|
742
|
+
* different remarkable, so that functionality is currently disabled.
|
|
565
743
|
*
|
|
566
|
-
* @param
|
|
567
|
-
*
|
|
568
|
-
* be the document id of an existing collection, an empty string for root,
|
|
569
|
-
* or the string `"trash"` to move to the trash
|
|
570
|
-
* @param opts - any extra options for moving
|
|
571
|
-
* @returns synced - true if synced successfully
|
|
572
|
-
* @throws error - if any error occurred, in this case, nothing will be
|
|
573
|
-
* changed
|
|
744
|
+
* @param hash - the hash of the document to get the contents for (e.g. the
|
|
745
|
+
* hash received from `listItems`)
|
|
574
746
|
*/
|
|
575
|
-
|
|
747
|
+
getDocument(hash: string): Promise<Uint8Array>;
|
|
576
748
|
/**
|
|
577
|
-
*
|
|
578
|
-
*
|
|
579
|
-
*
|
|
580
|
-
*
|
|
749
|
+
* use the low-level api to add a pdf document
|
|
750
|
+
*
|
|
751
|
+
* Since this uses the low-level api, it provides more options than
|
|
752
|
+
* {@link uploadPdf | `uploadPdf`}, but is a little more finicky. Notably, it
|
|
753
|
+
* may throw a {@link GenerationError | `GenerationError`} if the generation
|
|
754
|
+
* doesn't match the current server generation, requiring you to retry until
|
|
755
|
+
* it works.
|
|
756
|
+
*
|
|
757
|
+
* @param visibleName - the name to display on the reMarkable
|
|
758
|
+
* @param buffer - the raw pdf
|
|
759
|
+
* @param opts - put options
|
|
760
|
+
* @throws GenerationError if the generation doesn't match the current server generation
|
|
761
|
+
* @returns the entry for the newly inserted document
|
|
762
|
+
*/
|
|
763
|
+
putPdf(visibleName: string, buffer: Uint8Array, opts?: PutOptions): Promise<SimpleEntry>;
|
|
764
|
+
/**
|
|
765
|
+
* use the low-level api to add an epub document
|
|
766
|
+
*
|
|
767
|
+
* Since this uses the low-level api, it provides more options than
|
|
768
|
+
* {@link uploadEpub | `uploadEpub`}, but is a little more finicky. Notably, it
|
|
769
|
+
* may throw a {@link GenerationError | `GenerationError`} if the generation
|
|
770
|
+
* doesn't match the current server generation, requiring you to retry until
|
|
771
|
+
* it works.
|
|
772
|
+
*
|
|
773
|
+
* @param visibleName - the name to display on the reMarkable
|
|
774
|
+
* @param buffer - the raw epub
|
|
775
|
+
* @param opts - put options
|
|
776
|
+
* @throws GenerationError if the generation doesn't match the current server generation
|
|
777
|
+
* @returns the entry for the newly inserted document
|
|
581
778
|
*/
|
|
582
|
-
|
|
779
|
+
putEpub(visibleName: string, buffer: Uint8Array, opts?: PutOptions): Promise<SimpleEntry>;
|
|
780
|
+
/** create a folder */
|
|
781
|
+
createFolder(visibleName: string, opts?: UploadOptions): Promise<SimpleEntry>;
|
|
583
782
|
/**
|
|
584
783
|
* upload an epub
|
|
585
784
|
*
|
|
586
|
-
* @remarks this uses a newer api that performs a full upload and sync, but
|
|
587
|
-
* doesn't allow adding the same level of extra content data. Useful if you
|
|
588
|
-
* just want to upload a document with no fuss.
|
|
589
|
-
*
|
|
590
785
|
* @example
|
|
591
786
|
* ```ts
|
|
592
787
|
* await api.uploadEpub("My EPub", ...);
|
|
@@ -595,17 +790,10 @@ export interface RemarkableApi {
|
|
|
595
790
|
* @param visibleName - the name to show for the uploaded epub
|
|
596
791
|
* @param buffer - the epub contents
|
|
597
792
|
*/
|
|
598
|
-
uploadEpub(visibleName: string, buffer:
|
|
793
|
+
uploadEpub(visibleName: string, buffer: Uint8Array, opts?: UploadOptions): Promise<SimpleEntry>;
|
|
599
794
|
/**
|
|
600
795
|
* upload a pdf
|
|
601
796
|
*
|
|
602
|
-
* this currently uploads invalid pdfs, but it's not clear why, which is why
|
|
603
|
-
* this is marked as experimental. Potentially some tweak in the formatting
|
|
604
|
-
* of buffer will fix it.
|
|
605
|
-
*
|
|
606
|
-
* @remarks this uses a newer api that performs a full upload and sync, but
|
|
607
|
-
* doesn't allow adding the same level of extra information.
|
|
608
|
-
*
|
|
609
797
|
* @example
|
|
610
798
|
* ```ts
|
|
611
799
|
* await api.uploadPdf("My PDF", ...);
|
|
@@ -613,47 +801,97 @@ export interface RemarkableApi {
|
|
|
613
801
|
*
|
|
614
802
|
* @param visibleName - the name to show for the uploaded epub
|
|
615
803
|
* @param buffer - the epub contents
|
|
616
|
-
* @experimental
|
|
617
804
|
*/
|
|
618
|
-
uploadPdf(visibleName: string, buffer:
|
|
805
|
+
uploadPdf(visibleName: string, buffer: Uint8Array, opts?: UploadOptions): Promise<SimpleEntry>;
|
|
619
806
|
/**
|
|
620
|
-
*
|
|
807
|
+
* move an entry
|
|
621
808
|
*
|
|
622
|
-
*
|
|
623
|
-
*
|
|
809
|
+
* @example
|
|
810
|
+
* ```ts
|
|
811
|
+
* await api.move(doc.hash, dir.id);
|
|
812
|
+
* ```
|
|
813
|
+
*
|
|
814
|
+
* @param hash - the hash of the file to move
|
|
815
|
+
* @param parent - the id of the directory to move the entry to, "" (root) and "trash" are special parents
|
|
624
816
|
*/
|
|
625
|
-
|
|
626
|
-
}
|
|
627
|
-
/** format an entry */
|
|
628
|
-
export declare function formatEntry({ hash, type, documentId, subfiles, size, }: Entry): string;
|
|
629
|
-
/** parse an entry */
|
|
630
|
-
export declare function parseEntry(line: string): Entry;
|
|
631
|
-
/** options for a remarkable instance */
|
|
632
|
-
export interface RemarkableOptions {
|
|
817
|
+
move(hash: string, parent: string): Promise<HashEntry>;
|
|
633
818
|
/**
|
|
634
|
-
*
|
|
819
|
+
* delete an entry
|
|
635
820
|
*
|
|
636
|
-
*
|
|
637
|
-
*
|
|
638
|
-
*
|
|
821
|
+
* @example
|
|
822
|
+
* ```ts
|
|
823
|
+
* await api.delete(file.hash);
|
|
824
|
+
* ```
|
|
825
|
+
* @param hash - the hash of the entry to delete
|
|
826
|
+
*/
|
|
827
|
+
delete(hash: string): Promise<HashEntry>;
|
|
828
|
+
/**
|
|
829
|
+
* rename an entry
|
|
639
830
|
*
|
|
640
|
-
*
|
|
641
|
-
*
|
|
831
|
+
* @example
|
|
832
|
+
* ```ts
|
|
833
|
+
* await api.rename(file.hash, "new name");
|
|
834
|
+
* ```
|
|
835
|
+
* @param hash - the hash of the entry to rename
|
|
836
|
+
* @param visibleName - the new name to assign
|
|
837
|
+
*/
|
|
838
|
+
rename(hash: string, visibleName: string): Promise<HashEntry>;
|
|
839
|
+
/**
|
|
840
|
+
* move many entries
|
|
841
|
+
*
|
|
842
|
+
* @example
|
|
843
|
+
* ```ts
|
|
844
|
+
* await api.bulkMove([file.hash], dir.id);
|
|
845
|
+
* ```
|
|
846
|
+
*
|
|
847
|
+
* @param hashes - an array of entry hashes to move
|
|
848
|
+
* @param parent - the directory id to move the entries to, "" (root) and "trash" are special ids
|
|
849
|
+
*/
|
|
850
|
+
bulkMove(hashes: readonly string[], parent: string): Promise<HashesEntry>;
|
|
851
|
+
/**
|
|
852
|
+
* delete many entries
|
|
853
|
+
*
|
|
854
|
+
* @example
|
|
855
|
+
* ```ts
|
|
856
|
+
* await api.bulkDelete([file.hash]);
|
|
857
|
+
* ```
|
|
858
|
+
*
|
|
859
|
+
* @param hashes - the hashes of the entries to delete
|
|
860
|
+
*/
|
|
861
|
+
bulkDelete(hashes: readonly string[]): Promise<HashesEntry>;
|
|
862
|
+
/**
|
|
863
|
+
* get the current cache value as a string
|
|
642
864
|
*
|
|
643
|
-
*
|
|
865
|
+
* You can use this to warm start a new instance of
|
|
866
|
+
* {@link remarkable | `remarkable`} with any previously cached results.
|
|
644
867
|
*/
|
|
645
|
-
|
|
868
|
+
dumpCache(): string;
|
|
646
869
|
/**
|
|
647
|
-
*
|
|
870
|
+
* prune the cache so that it contains only reachable hashes
|
|
648
871
|
*
|
|
649
|
-
*
|
|
650
|
-
*
|
|
651
|
-
*
|
|
652
|
-
*
|
|
872
|
+
* The cache is append only, so it can grow without bound, even as hashes
|
|
873
|
+
* become unreachable. In the future, this may have better cache management to
|
|
874
|
+
* track this in real time, but for now, you can call this method, to keep it
|
|
875
|
+
* from growing continuously.
|
|
876
|
+
*
|
|
877
|
+
* @remarks
|
|
878
|
+
* This won't necessarily reduce the cache size. In order to see if
|
|
879
|
+
* hashes are reachable we first have to search through all existing entry
|
|
880
|
+
* lists.
|
|
881
|
+
*
|
|
882
|
+
* @param refresh - whether to refresh the root hash before pruning
|
|
883
|
+
*/
|
|
884
|
+
pruneCache(refresh?: boolean): Promise<void>;
|
|
885
|
+
/**
|
|
886
|
+
* completely delete the cache
|
|
653
887
|
*
|
|
654
|
-
*
|
|
888
|
+
* If the cache is causing memory issues, you can clear it, but this will hurt
|
|
889
|
+
* performance.
|
|
655
890
|
*/
|
|
656
|
-
|
|
891
|
+
clearCache(): void;
|
|
892
|
+
}
|
|
893
|
+
/** options for a remarkable instance */
|
|
894
|
+
export interface RemarkableOptions {
|
|
657
895
|
/**
|
|
658
896
|
* the url for making authorization requests
|
|
659
897
|
*
|
|
@@ -663,30 +901,32 @@ export interface RemarkableOptions {
|
|
|
663
901
|
/**
|
|
664
902
|
* the url for making synchronization requests
|
|
665
903
|
*
|
|
666
|
-
* @defaultValue "https://
|
|
904
|
+
* @defaultValue "https://web.eu.tectonic.remarkable.com"
|
|
667
905
|
*/
|
|
668
906
|
syncHost?: string;
|
|
669
907
|
/**
|
|
670
|
-
* the
|
|
671
|
-
*
|
|
672
|
-
* Since the remarkableApi is based around hashes, the value of a hash should
|
|
673
|
-
* never change (barring collisions in ASH256). Any known hash value that's
|
|
674
|
-
* less than this amount will be cached locally to prevent future network
|
|
675
|
-
* requests. In addition, all successful puts and gets will be cached to
|
|
676
|
-
* prevent duplicate puts in the future.
|
|
908
|
+
* the url for making requests using the low-level api
|
|
677
909
|
*
|
|
678
|
-
*
|
|
910
|
+
* @defaultValue "https://eu.tectonic.remarkable.com"
|
|
911
|
+
*/
|
|
912
|
+
rawHost?: string;
|
|
913
|
+
/**
|
|
914
|
+
* an initial cache value
|
|
679
915
|
*
|
|
680
|
-
* @
|
|
916
|
+
* Generated from calling {@link RemarkableApi.dumpCache | `dumpCache`} on a previous
|
|
917
|
+
* instance.
|
|
681
918
|
*/
|
|
682
|
-
|
|
919
|
+
cache?: string;
|
|
683
920
|
/**
|
|
684
|
-
*
|
|
921
|
+
* the maximum size of the cache in terms of total string length
|
|
922
|
+
*
|
|
923
|
+
* By the JavaScript specification there are two bytes per character, but the
|
|
924
|
+
* total memory usage of the cache will also be larger than just the size of
|
|
925
|
+
* the data stored.
|
|
685
926
|
*
|
|
686
|
-
*
|
|
687
|
-
* Often this will come from {@link RemarkableApi.getCache | `getCache`}.
|
|
927
|
+
* @defaultValue Infinity
|
|
688
928
|
*/
|
|
689
|
-
|
|
929
|
+
maxCacheSize?: number;
|
|
690
930
|
}
|
|
691
931
|
/**
|
|
692
932
|
* create an instance of the api
|
|
@@ -698,4 +938,4 @@ export interface RemarkableOptions {
|
|
|
698
938
|
* registered. Create one with {@link register}.
|
|
699
939
|
* @returns an api instance
|
|
700
940
|
*/
|
|
701
|
-
export declare function remarkable(deviceToken: string, {
|
|
941
|
+
export declare function remarkable(deviceToken: string, { authHost, syncHost, rawHost, cache, maxCacheSize, }?: RemarkableOptions): Promise<RemarkableApi>;
|