rmapi-js 1.0.0 → 2.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/CHANGELOG.md +22 -0
- package/README.md +34 -9
- package/bundle/rmapi-js.cjs.min.js +4 -4
- package/bundle/rmapi-js.esm.min.js +4 -4
- package/bundle/rmapi-js.iife.min.js +4 -4
- package/dist/index.d.ts +143 -29
- package/dist/index.js +200 -73
- package/package.json +35 -32
- package/bundle/rmapi.cjs.min.js +0 -4
- package/bundle/rmapi.esm.min.js +0 -4
- package/bundle/rmapi.iife.min.js +0 -4
package/dist/index.js
CHANGED
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Create and interact with reMarkable cloud.
|
|
3
3
|
*
|
|
4
|
+
* After getting a device token with the {@link register | `register`} method,
|
|
5
|
+
* persist it and create api instances using {@link remarkable | `remarkable`}.
|
|
6
|
+
* Outside of registration, all relevant methods are in
|
|
7
|
+
* {@link RemarkableApi | `RemarkableApi`}.
|
|
8
|
+
*
|
|
4
9
|
* @example
|
|
5
10
|
* A simple fetch
|
|
6
11
|
* ```ts
|
|
7
12
|
* import { register, remarkable } from "rmapi-js";
|
|
8
13
|
*
|
|
9
|
-
* const code = "..." // eight letter code from https://my.remarkable.com/device/
|
|
14
|
+
* const code = "..." // eight letter code from https://my.remarkable.com/device/browser/connect
|
|
10
15
|
* const token = await register(code)
|
|
11
16
|
* // persist token
|
|
12
17
|
* const api = await remarkable(token);
|
|
@@ -35,20 +40,22 @@
|
|
|
35
40
|
* const rootEntries = await api.getEntries(root);
|
|
36
41
|
* rootEntries.push(entry);
|
|
37
42
|
* const { hash } = await api.putEntries("", rootEntries);
|
|
38
|
-
* await api.putRootHash(hash, gen);
|
|
39
|
-
* await api.syncComplete();
|
|
43
|
+
* const nextGen = await api.putRootHash(hash, gen);
|
|
44
|
+
* await api.syncComplete(nextGen);
|
|
40
45
|
* ```
|
|
41
46
|
*
|
|
42
47
|
* @packageDocumentation
|
|
43
48
|
*/
|
|
49
|
+
import { fromByteArray } from "base64-js";
|
|
44
50
|
import { v4 as uuid4 } from "uuid";
|
|
45
51
|
import { concatBuffers, fromHex, toHex } from "./utils";
|
|
46
52
|
import { validate } from "./validate";
|
|
47
53
|
const SCHEMA_VERSION = "3";
|
|
48
|
-
const
|
|
49
|
-
const
|
|
54
|
+
const AUTH_HOST = "https://webapp-prod.cloud.remarkable.engineering";
|
|
55
|
+
const SYNC_HOST = "https://internal.cloud.remarkable.com";
|
|
50
56
|
const GENERATION_HEADER = "x-goog-generation";
|
|
51
57
|
const GENERATION_RACE_HEADER = "x-goog-if-generation-match";
|
|
58
|
+
const CONTENT_LENGTH_RANGE_HEADER = "x-goog-content-length-range";
|
|
52
59
|
/** tool options */
|
|
53
60
|
export const builtinTools = [
|
|
54
61
|
"Ballpoint",
|
|
@@ -118,6 +125,12 @@ export const builtinLineHeights = {
|
|
|
118
125
|
/** double */
|
|
119
126
|
xl: 200,
|
|
120
127
|
};
|
|
128
|
+
const uploadEntrySchema = {
|
|
129
|
+
properties: {
|
|
130
|
+
docID: { type: "string" },
|
|
131
|
+
hash: { type: "string" },
|
|
132
|
+
},
|
|
133
|
+
};
|
|
121
134
|
const urlResponseSchema = {
|
|
122
135
|
properties: {
|
|
123
136
|
relative_path: { type: "string" },
|
|
@@ -125,19 +138,22 @@ const urlResponseSchema = {
|
|
|
125
138
|
expires: { type: "timestamp" },
|
|
126
139
|
method: { enum: ["POST", "GET", "PUT", "DELETE"] },
|
|
127
140
|
},
|
|
141
|
+
optionalProperties: {
|
|
142
|
+
maxuploadsize_bytes: { type: "float64" },
|
|
143
|
+
},
|
|
128
144
|
};
|
|
129
145
|
const commonProperties = {
|
|
130
146
|
visibleName: { type: "string" },
|
|
131
|
-
parent: { type: "string" },
|
|
132
147
|
lastModified: { type: "string" },
|
|
133
|
-
version: { type: "int32" },
|
|
134
|
-
synced: { type: "boolean" },
|
|
135
148
|
};
|
|
136
149
|
const commonOptionalProperties = {
|
|
150
|
+
version: { type: "int32" },
|
|
137
151
|
pinned: { type: "boolean" },
|
|
152
|
+
synced: { type: "boolean" },
|
|
138
153
|
modified: { type: "boolean" },
|
|
139
154
|
deleted: { type: "boolean" },
|
|
140
155
|
metadatamodified: { type: "boolean" },
|
|
156
|
+
parent: { type: "string" },
|
|
141
157
|
};
|
|
142
158
|
const metadataSchema = {
|
|
143
159
|
discriminator: "type",
|
|
@@ -156,6 +172,34 @@ const metadataSchema = {
|
|
|
156
172
|
},
|
|
157
173
|
},
|
|
158
174
|
};
|
|
175
|
+
const baseMetadataProperties = {
|
|
176
|
+
id: { type: "string" },
|
|
177
|
+
hash: { type: "string" },
|
|
178
|
+
};
|
|
179
|
+
const metadataEntrySchema = {
|
|
180
|
+
discriminator: "type",
|
|
181
|
+
mapping: {
|
|
182
|
+
CollectionType: {
|
|
183
|
+
properties: {
|
|
184
|
+
...commonProperties,
|
|
185
|
+
...baseMetadataProperties,
|
|
186
|
+
},
|
|
187
|
+
optionalProperties: commonOptionalProperties,
|
|
188
|
+
},
|
|
189
|
+
DocumentType: {
|
|
190
|
+
properties: {
|
|
191
|
+
...commonProperties,
|
|
192
|
+
...baseMetadataProperties,
|
|
193
|
+
fileType: { enum: ["notebook", "epub", "pdf", ""] },
|
|
194
|
+
},
|
|
195
|
+
optionalProperties: {
|
|
196
|
+
...commonOptionalProperties,
|
|
197
|
+
lastOpened: { type: "string" },
|
|
198
|
+
lastOpenedPage: { type: "int32" },
|
|
199
|
+
},
|
|
200
|
+
},
|
|
201
|
+
},
|
|
202
|
+
};
|
|
159
203
|
/** an error that results from a failed request */
|
|
160
204
|
export class ResponseError extends Error {
|
|
161
205
|
/** the response status number */
|
|
@@ -182,18 +226,18 @@ export class GenerationError extends Error {
|
|
|
182
226
|
/**
|
|
183
227
|
* register a device and get the token needed to access the api
|
|
184
228
|
*
|
|
185
|
-
* Have users go to `https://my.remarkable.com/device/
|
|
229
|
+
* Have users go to `https://my.remarkable.com/device/browser/connect` and pass
|
|
186
230
|
* the resulting code into this function to get a device token. Persist that
|
|
187
231
|
* token to use the api.
|
|
188
232
|
*
|
|
189
|
-
* @param code - the eight letter code a user got from `https://my.remarkable.com/device/
|
|
233
|
+
* @param code - the eight letter code a user got from `https://my.remarkable.com/device/browser/connect`.
|
|
190
234
|
* @returns the device token necessary for creating an api instace. These never expire so persist as long as necessary.
|
|
191
235
|
*/
|
|
192
|
-
export async function register(code, { deviceDesc = "
|
|
236
|
+
export async function register(code, { deviceDesc = "browser-chrome", uuid = uuid4(), authHost = AUTH_HOST, fetch = globalThis.fetch, } = {}) {
|
|
193
237
|
if (code.length !== 8) {
|
|
194
238
|
throw new Error(`code should be length 8, but was ${code.length}`);
|
|
195
239
|
}
|
|
196
|
-
const resp = await fetch(`${
|
|
240
|
+
const resp = await fetch(`${authHost}/token/json/2/device/new`, {
|
|
197
241
|
method: "POST",
|
|
198
242
|
headers: {
|
|
199
243
|
Authorization: "Bearer",
|
|
@@ -254,37 +298,45 @@ export function parseEntry(line) {
|
|
|
254
298
|
}
|
|
255
299
|
/** the implementation of that api */
|
|
256
300
|
class Remarkable {
|
|
257
|
-
userToken;
|
|
258
|
-
fetch;
|
|
259
|
-
cache;
|
|
260
|
-
subtle;
|
|
261
|
-
|
|
262
|
-
constructor(userToken, fetch, cache, subtle,
|
|
263
|
-
this
|
|
264
|
-
this
|
|
265
|
-
this
|
|
266
|
-
this
|
|
267
|
-
this
|
|
301
|
+
#userToken;
|
|
302
|
+
#fetch;
|
|
303
|
+
#cache;
|
|
304
|
+
#subtle;
|
|
305
|
+
#syncHost;
|
|
306
|
+
constructor(userToken, fetch, cache, subtle, syncHost) {
|
|
307
|
+
this.#userToken = userToken;
|
|
308
|
+
this.#fetch = fetch;
|
|
309
|
+
this.#cache = cache;
|
|
310
|
+
this.#subtle = subtle;
|
|
311
|
+
this.#syncHost = syncHost;
|
|
268
312
|
}
|
|
269
313
|
/** make an authorized request to remarkable */
|
|
270
|
-
async authedFetch(url, body, method = "POST") {
|
|
271
|
-
const resp = await this
|
|
314
|
+
async #authedFetch(url, { body, method = "POST", headers = {}, }) {
|
|
315
|
+
const resp = await this.#fetch(url, {
|
|
272
316
|
method,
|
|
273
317
|
headers: {
|
|
274
|
-
Authorization: `Bearer ${this
|
|
318
|
+
Authorization: `Bearer ${this.#userToken}`,
|
|
319
|
+
...headers,
|
|
275
320
|
},
|
|
276
|
-
body
|
|
321
|
+
body,
|
|
277
322
|
});
|
|
278
323
|
if (!resp.ok) {
|
|
279
|
-
|
|
324
|
+
const msg = await resp.text();
|
|
325
|
+
throw new ResponseError(resp.status, resp.statusText, `failed reMarkable request: ${msg}`);
|
|
280
326
|
}
|
|
281
327
|
else {
|
|
282
328
|
return resp;
|
|
283
329
|
}
|
|
284
330
|
}
|
|
285
331
|
/** make a signed request to the cloud */
|
|
286
|
-
async signedFetch({ url, method }, body,
|
|
287
|
-
const
|
|
332
|
+
async #signedFetch({ url, method, maxuploadsize_bytes }, body, add_headers = {}) {
|
|
333
|
+
const headers = maxuploadsize_bytes
|
|
334
|
+
? {
|
|
335
|
+
...add_headers,
|
|
336
|
+
[CONTENT_LENGTH_RANGE_HEADER]: `0,${maxuploadsize_bytes}`,
|
|
337
|
+
}
|
|
338
|
+
: add_headers;
|
|
339
|
+
const resp = await this.#fetch(url, {
|
|
288
340
|
method,
|
|
289
341
|
body,
|
|
290
342
|
headers,
|
|
@@ -298,29 +350,24 @@ class Remarkable {
|
|
|
298
350
|
}
|
|
299
351
|
}
|
|
300
352
|
/** get the details for how to make a signed request to remarkable cloud */
|
|
301
|
-
async getUrl(relativePath, gen) {
|
|
353
|
+
async #getUrl(relativePath, gen, rootHash) {
|
|
302
354
|
const key = gen === undefined ? "downloads" : "uploads";
|
|
303
|
-
|
|
304
|
-
const
|
|
305
|
-
http_method:
|
|
306
|
-
relative_path: relativePath
|
|
307
|
-
|
|
308
|
-
});
|
|
355
|
+
// NOTE this is done manually to serialize the bigints appropriately
|
|
356
|
+
const body = rootHash
|
|
357
|
+
? `{ "http_method": "PUT", "relative_path": "${relativePath}", "root_schema": "${rootHash}", "generation": ${gen} }`
|
|
358
|
+
: JSON.stringify({ http_method: "GET", relative_path: relativePath });
|
|
359
|
+
const resp = await this.#authedFetch(`${this.#syncHost}/sync/v2/signed-urls/${key}`, { body });
|
|
309
360
|
const raw = await resp.text();
|
|
310
361
|
const res = JSON.parse(raw);
|
|
311
362
|
validate(urlResponseSchema, res);
|
|
312
363
|
return res;
|
|
313
364
|
}
|
|
314
|
-
/** sends a signal to the server that a sync is complete and other devices should update */
|
|
315
|
-
async syncComplete() {
|
|
316
|
-
await this.authedFetch(`${this.blobUrl}/api/v1/sync-complete`);
|
|
317
|
-
}
|
|
318
365
|
/**
|
|
319
366
|
* get the root hash and the current generation
|
|
320
367
|
*/
|
|
321
368
|
async getRootHash() {
|
|
322
|
-
const signed = await this
|
|
323
|
-
const resp = await this
|
|
369
|
+
const signed = await this.#getUrl("root");
|
|
370
|
+
const resp = await this.#signedFetch(signed);
|
|
324
371
|
const generation = resp.headers.get(GENERATION_HEADER);
|
|
325
372
|
if (!generation) {
|
|
326
373
|
throw new Error("no generation header in root hash");
|
|
@@ -331,10 +378,10 @@ class Remarkable {
|
|
|
331
378
|
* write the root hash, incrementing from the current generation
|
|
332
379
|
*/
|
|
333
380
|
async putRootHash(hash, generation) {
|
|
334
|
-
const signed = await this
|
|
381
|
+
const signed = await this.#getUrl("root", generation, hash);
|
|
335
382
|
let resp;
|
|
336
383
|
try {
|
|
337
|
-
resp = await this
|
|
384
|
+
resp = await this.#signedFetch(signed, hash, {
|
|
338
385
|
[GENERATION_RACE_HEADER]: `${generation}`,
|
|
339
386
|
});
|
|
340
387
|
}
|
|
@@ -356,23 +403,23 @@ class Remarkable {
|
|
|
356
403
|
* get text content associated with hash
|
|
357
404
|
*/
|
|
358
405
|
async getBuffer(hash) {
|
|
359
|
-
const signed = await this
|
|
360
|
-
const resp = await this
|
|
406
|
+
const signed = await this.#getUrl(hash);
|
|
407
|
+
const resp = await this.#signedFetch(signed);
|
|
361
408
|
return await resp.arrayBuffer();
|
|
362
409
|
}
|
|
363
410
|
/**
|
|
364
411
|
* get text content associated with hash
|
|
365
412
|
*/
|
|
366
413
|
async getText(hash) {
|
|
367
|
-
const cached =
|
|
414
|
+
const cached = await this.#cache?.get(hash);
|
|
368
415
|
if (cached) {
|
|
369
416
|
return cached;
|
|
370
417
|
}
|
|
371
418
|
else {
|
|
372
|
-
const signed = await this
|
|
373
|
-
const resp = await this
|
|
419
|
+
const signed = await this.#getUrl(hash);
|
|
420
|
+
const resp = await this.#signedFetch(signed);
|
|
374
421
|
const raw = await resp.text();
|
|
375
|
-
|
|
422
|
+
await this.#cache?.set(hash, raw);
|
|
376
423
|
return raw;
|
|
377
424
|
}
|
|
378
425
|
}
|
|
@@ -398,9 +445,9 @@ class Remarkable {
|
|
|
398
445
|
return lines.map(parseEntry);
|
|
399
446
|
}
|
|
400
447
|
/** upload data to hash */
|
|
401
|
-
async putHash(hash, body) {
|
|
402
|
-
const signed = await this
|
|
403
|
-
await this
|
|
448
|
+
async #putHash(hash, body) {
|
|
449
|
+
const signed = await this.#getUrl(hash, null);
|
|
450
|
+
await this.#signedFetch(signed, body);
|
|
404
451
|
}
|
|
405
452
|
/** put a reference to a set of entries into the cloud */
|
|
406
453
|
async putEntries(documentId, entries) {
|
|
@@ -408,13 +455,13 @@ class Remarkable {
|
|
|
408
455
|
const enc = new TextEncoder();
|
|
409
456
|
entries.sort((a, b) => a.documentId.localeCompare(b.documentId));
|
|
410
457
|
const hashes = concatBuffers(entries.map((ent) => fromHex(ent.hash)));
|
|
411
|
-
const digest = await this
|
|
458
|
+
const digest = await this.#subtle.digest("SHA-256", hashes);
|
|
412
459
|
const hash = toHex(digest);
|
|
413
460
|
const entryContents = entries.map(formatEntry).join("");
|
|
414
461
|
const contents = `${SCHEMA_VERSION}\n${entryContents}`;
|
|
415
462
|
const buffer = enc.encode(contents);
|
|
416
|
-
await this
|
|
417
|
-
|
|
463
|
+
await this.#putHash(hash, buffer);
|
|
464
|
+
await this.#cache?.set(hash, contents);
|
|
418
465
|
return {
|
|
419
466
|
hash,
|
|
420
467
|
type: "80000000",
|
|
@@ -425,9 +472,9 @@ class Remarkable {
|
|
|
425
472
|
}
|
|
426
473
|
/** put a raw buffer in the cloud */
|
|
427
474
|
async putBuffer(documentId, buffer) {
|
|
428
|
-
const digest = await this
|
|
475
|
+
const digest = await this.#subtle.digest("SHA-256", buffer);
|
|
429
476
|
const hash = toHex(digest);
|
|
430
|
-
await this
|
|
477
|
+
await this.#putHash(hash, buffer);
|
|
431
478
|
return {
|
|
432
479
|
hash,
|
|
433
480
|
type: "0",
|
|
@@ -440,16 +487,20 @@ class Remarkable {
|
|
|
440
487
|
async putText(documentId, contents) {
|
|
441
488
|
const enc = new TextEncoder();
|
|
442
489
|
const entry = await this.putBuffer(documentId, enc.encode(contents));
|
|
443
|
-
|
|
490
|
+
await this.#cache?.set(entry.hash, contents);
|
|
444
491
|
return entry;
|
|
445
492
|
}
|
|
446
|
-
/** upload
|
|
447
|
-
async
|
|
493
|
+
/** upload a content file */
|
|
494
|
+
async #putContent(visibleName, buffer, fileType, parent, content) {
|
|
495
|
+
/* istanbul ignore if */
|
|
496
|
+
if (content.fileType !== fileType) {
|
|
497
|
+
throw new Error(`internal error: fileTypes don't match: ${fileType}, ${content.fileType}`);
|
|
498
|
+
}
|
|
448
499
|
const documentId = uuid4();
|
|
449
500
|
const lastModified = `${new Date().valueOf()}`;
|
|
450
501
|
const entryPromises = [];
|
|
451
502
|
// upload main document
|
|
452
|
-
entryPromises.push(this.putBuffer(`${documentId}
|
|
503
|
+
entryPromises.push(this.putBuffer(`${documentId}.${fileType}`, buffer));
|
|
453
504
|
// upload metadata
|
|
454
505
|
const metadata = {
|
|
455
506
|
type: "DocumentType",
|
|
@@ -460,6 +511,15 @@ class Remarkable {
|
|
|
460
511
|
lastModified,
|
|
461
512
|
};
|
|
462
513
|
entryPromises.push(this.putText(`${documentId}.metadata`, JSON.stringify(metadata)));
|
|
514
|
+
entryPromises.push(this.putText(`${documentId}.content`, JSON.stringify(content)));
|
|
515
|
+
// NOTE we technically get the entries a bit earlier, so could upload this
|
|
516
|
+
// before all contents are uploaded, but this also saves us from uploading
|
|
517
|
+
// the contents entry before all have uploaded successfully
|
|
518
|
+
const entries = await Promise.all(entryPromises);
|
|
519
|
+
return await this.putEntries(documentId, entries);
|
|
520
|
+
}
|
|
521
|
+
/** upload an epub */
|
|
522
|
+
async putEpub(visibleName, buffer, { parent = "", margins = 125, orientation, textAlignment, textScale = 1, lineHeight = -1, fontName = "", cover = "visited", lastTool, } = {}) {
|
|
463
523
|
// upload content file
|
|
464
524
|
const content = {
|
|
465
525
|
dummyDocument: false,
|
|
@@ -483,12 +543,78 @@ class Remarkable {
|
|
|
483
543
|
textAlignment,
|
|
484
544
|
fontName,
|
|
485
545
|
};
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
546
|
+
return await this.#putContent(visibleName, buffer, "epub", parent, content);
|
|
547
|
+
}
|
|
548
|
+
/** upload a pdf */
|
|
549
|
+
async putPdf(visibleName, buffer, { parent = "", orientation, cover = "first", lastTool } = {}) {
|
|
550
|
+
// upload content file
|
|
551
|
+
const content = {
|
|
552
|
+
dummyDocument: false,
|
|
553
|
+
extraMetadata: {
|
|
554
|
+
LastTool: lastTool,
|
|
555
|
+
},
|
|
556
|
+
fileType: "pdf",
|
|
557
|
+
pageCount: 0,
|
|
558
|
+
lastOpenedPage: 0,
|
|
559
|
+
lineHeight: -1,
|
|
560
|
+
margins: 125,
|
|
561
|
+
textScale: 1,
|
|
562
|
+
pages: [],
|
|
563
|
+
coverPageNumber: cover === "first" ? 0 : -1,
|
|
564
|
+
formatVersion: 1,
|
|
565
|
+
orientation,
|
|
566
|
+
};
|
|
567
|
+
return await this.#putContent(visibleName, buffer, "pdf", parent, content);
|
|
568
|
+
}
|
|
569
|
+
/** send sync complete request */
|
|
570
|
+
async syncComplete(generation) {
|
|
571
|
+
// NOTE this is done manually to properly serialize the bigint
|
|
572
|
+
const body = `{ "generation": ${generation} }`;
|
|
573
|
+
await this.#authedFetch(`${this.#syncHost}/sync/v2/sync-complete`, {
|
|
574
|
+
body,
|
|
575
|
+
});
|
|
576
|
+
}
|
|
577
|
+
/** get entries and metadata for all files */
|
|
578
|
+
async getEntriesMetadata() {
|
|
579
|
+
const resp = await this.#authedFetch(`${this.#syncHost}/doc/v2/files`, {
|
|
580
|
+
method: "GET",
|
|
581
|
+
headers: {
|
|
582
|
+
"rm-source": "RoR-Browser",
|
|
583
|
+
},
|
|
584
|
+
});
|
|
585
|
+
const raw = await resp.text();
|
|
586
|
+
const res = JSON.parse(raw);
|
|
587
|
+
const schema = {
|
|
588
|
+
elements: metadataEntrySchema,
|
|
589
|
+
};
|
|
590
|
+
validate(schema, res);
|
|
591
|
+
return res;
|
|
592
|
+
}
|
|
593
|
+
/** upload a file */
|
|
594
|
+
async #uploadFile(visibleName, buffer, contentType) {
|
|
595
|
+
const encoder = new TextEncoder();
|
|
596
|
+
const meta = encoder.encode(JSON.stringify({ file_name: visibleName }));
|
|
597
|
+
const resp = await this.#authedFetch(`${this.#syncHost}/doc/v2/files`, {
|
|
598
|
+
body: buffer,
|
|
599
|
+
headers: {
|
|
600
|
+
"content-type": contentType,
|
|
601
|
+
"rm-meta": fromByteArray(meta),
|
|
602
|
+
"rm-source": "RoR-Browser",
|
|
603
|
+
},
|
|
604
|
+
});
|
|
605
|
+
const raw = await resp.text();
|
|
606
|
+
const res = JSON.parse(raw);
|
|
607
|
+
validate(uploadEntrySchema, res);
|
|
608
|
+
return res;
|
|
609
|
+
}
|
|
610
|
+
/** upload an epub */
|
|
611
|
+
async uploadEpub(visibleName, buffer) {
|
|
612
|
+
return await this.#uploadFile(visibleName, buffer, "application/epub+zip");
|
|
613
|
+
}
|
|
614
|
+
/** upload a pdf */
|
|
615
|
+
async uploadPdf(visibleName, buffer) {
|
|
616
|
+
// TODO why doesn't this work
|
|
617
|
+
return await this.#uploadFile(visibleName, buffer, "application/pdf");
|
|
492
618
|
}
|
|
493
619
|
}
|
|
494
620
|
/**
|
|
@@ -497,11 +623,12 @@ class Remarkable {
|
|
|
497
623
|
* This gets a temporary authentication token with the device token. If
|
|
498
624
|
* requests start failing, simply recreate the api instance.
|
|
499
625
|
*
|
|
500
|
-
* @param deviceToken - the device token proving this api instance is
|
|
626
|
+
* @param deviceToken - the device token proving this api instance is
|
|
627
|
+
* registered. Create one with {@link register}.
|
|
501
628
|
* @returns an api instance
|
|
502
629
|
*/
|
|
503
|
-
export async function remarkable(deviceToken, { fetch = globalThis.fetch, cache, subtle = globalThis.crypto?.subtle,
|
|
504
|
-
const resp = await fetch(`${
|
|
630
|
+
export async function remarkable(deviceToken, { fetch = globalThis.fetch, cache, subtle = globalThis.crypto?.subtle, authHost = AUTH_HOST, syncHost = SYNC_HOST, } = {}) {
|
|
631
|
+
const resp = await fetch(`${authHost}/token/json/2/user/new`, {
|
|
505
632
|
method: "POST",
|
|
506
633
|
headers: {
|
|
507
634
|
Authorization: `Bearer ${deviceToken}`,
|
|
@@ -511,5 +638,5 @@ export async function remarkable(deviceToken, { fetch = globalThis.fetch, cache,
|
|
|
511
638
|
throw new Error(`couldn't fetch auth token: ${resp.statusText}`);
|
|
512
639
|
}
|
|
513
640
|
const userToken = await resp.text();
|
|
514
|
-
return new Remarkable(userToken, fetch, cache, subtle,
|
|
641
|
+
return new Remarkable(userToken, fetch, cache, subtle, syncHost);
|
|
515
642
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "rmapi-js",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "JavaScript implementation of the reMarkable 1.5 api",
|
|
5
5
|
"repository": "git@github.com:erikbrinkman/rmapi-js.git",
|
|
6
6
|
"author": "Erik Brinkman <erik.brinkman@gmail.com>",
|
|
@@ -8,54 +8,55 @@
|
|
|
8
8
|
"keywords": [
|
|
9
9
|
"remarkable"
|
|
10
10
|
],
|
|
11
|
-
"types": "dist/index.d.ts",
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
12
|
"module": "bundle/rmapi-js.esm.min.js",
|
|
13
13
|
"main": "bundle/rmapi-js.cjs.min.js",
|
|
14
14
|
"unpkg": "bundle/rmapi-js.iife.min.js",
|
|
15
15
|
"files": [
|
|
16
|
-
"
|
|
17
|
-
"
|
|
18
|
-
"
|
|
16
|
+
"./bundle/*.js",
|
|
17
|
+
"./dist/**/*.js",
|
|
18
|
+
"./dist/**/*.d.ts"
|
|
19
19
|
],
|
|
20
|
-
"packageManager": "yarn@3.
|
|
20
|
+
"packageManager": "yarn@3.3.1",
|
|
21
21
|
"scripts": {
|
|
22
22
|
"doc": "typedoc",
|
|
23
|
-
"fmt": "prettier --cache --write 'src/*.ts' '*.json'
|
|
24
|
-
"lint": "tsc && eslint --cache 'src/*.ts'
|
|
23
|
+
"fmt": "prettier --cache --write 'src/*.ts' '*.json' bundle.mjs",
|
|
24
|
+
"lint": "tsc && eslint --cache 'src/*.ts' bundle.mjs && typedoc --emit none",
|
|
25
25
|
"test": "jest --coverage",
|
|
26
26
|
"build": "tsc -p tsconfig.build.json && yarn node bundle.mjs",
|
|
27
27
|
"prepack": "yarn lint && yarn test && yarn build"
|
|
28
28
|
},
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"ajv": "^8.11.
|
|
31
|
-
"
|
|
30
|
+
"ajv": "^8.11.2",
|
|
31
|
+
"base64-js": "^1.5.1",
|
|
32
|
+
"jtd": "^0.1.1",
|
|
33
|
+
"uuid": "^9.0.0"
|
|
32
34
|
},
|
|
33
35
|
"devDependencies": {
|
|
34
|
-
"@babel/core": "^7.
|
|
35
|
-
"@babel/preset-env": "^7.
|
|
36
|
+
"@babel/core": "^7.20.7",
|
|
37
|
+
"@babel/preset-env": "^7.20.2",
|
|
36
38
|
"@babel/preset-typescript": "^7.18.6",
|
|
37
|
-
"@types/babel__core": "^7.1.
|
|
39
|
+
"@types/babel__core": "^7.1.20",
|
|
38
40
|
"@types/babel__preset-env": "^7.9.2",
|
|
39
|
-
"@types/jest": "^
|
|
40
|
-
"@types/node": "^18.
|
|
41
|
-
"@types/uuid": "^
|
|
42
|
-
"@typescript-eslint/eslint-plugin": "^5.
|
|
43
|
-
"@typescript-eslint/parser": "^5.
|
|
44
|
-
"@yarnpkg/esbuild-plugin-pnp": "^3.0.0-rc.
|
|
45
|
-
"babel-jest": "^
|
|
46
|
-
"chalk": "^5.0
|
|
47
|
-
"esbuild": "^0.
|
|
48
|
-
"eslint": "^8.
|
|
41
|
+
"@types/jest": "^29.2.4",
|
|
42
|
+
"@types/node": "^18.11.18",
|
|
43
|
+
"@types/uuid": "^9.0.0",
|
|
44
|
+
"@typescript-eslint/eslint-plugin": "^5.47.1",
|
|
45
|
+
"@typescript-eslint/parser": "^5.47.1",
|
|
46
|
+
"@yarnpkg/esbuild-plugin-pnp": "^3.0.0-rc.15",
|
|
47
|
+
"babel-jest": "^29.3.1",
|
|
48
|
+
"chalk": "^5.2.0",
|
|
49
|
+
"esbuild": "^0.16.10",
|
|
50
|
+
"eslint": "^8.30.0",
|
|
49
51
|
"eslint-config-prettier": "^8.5.0",
|
|
50
|
-
"eslint-plugin-jest": "^
|
|
51
|
-
"eslint-plugin-spellcheck": "^0.0.
|
|
52
|
-
"eslint-plugin-tsdoc": "^0.2.
|
|
53
|
-
"jest": "^
|
|
54
|
-
"
|
|
55
|
-
"prettier": "^2.
|
|
56
|
-
"
|
|
57
|
-
"
|
|
58
|
-
"typescript": "^4.7.4"
|
|
52
|
+
"eslint-plugin-jest": "^27.1.7",
|
|
53
|
+
"eslint-plugin-spellcheck": "^0.0.20",
|
|
54
|
+
"eslint-plugin-tsdoc": "^0.2.17",
|
|
55
|
+
"jest": "^29.3.1",
|
|
56
|
+
"prettier": "^2.8.1",
|
|
57
|
+
"prettier-plugin-organize-imports": "^3.2.1",
|
|
58
|
+
"typedoc": "^0.23.23",
|
|
59
|
+
"typescript": "^4.9.4"
|
|
59
60
|
},
|
|
60
61
|
"prettier": {
|
|
61
62
|
"plugins": [
|
|
@@ -121,6 +122,7 @@
|
|
|
121
122
|
"Paintbrushv",
|
|
122
123
|
"Pencilv",
|
|
123
124
|
"authed",
|
|
125
|
+
"bigints",
|
|
124
126
|
"ebooks",
|
|
125
127
|
"epub",
|
|
126
128
|
"fineliner",
|
|
@@ -128,6 +130,7 @@
|
|
|
128
130
|
"iife",
|
|
129
131
|
"incrementing",
|
|
130
132
|
"linux",
|
|
133
|
+
"macos",
|
|
131
134
|
"rmapi",
|
|
132
135
|
"subfiles",
|
|
133
136
|
"urls",
|
package/bundle/rmapi.cjs.min.js
DELETED
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
var ct=Object.create;var H=Object.defineProperty;var pt=Object.getOwnPropertyDescriptor;var yt=Object.getOwnPropertyNames;var gt=Object.getPrototypeOf,mt=Object.prototype.hasOwnProperty;var d=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports),ht=(e,t)=>{for(var r in t)H(e,r,{get:t[r],enumerable:!0})},Pe=(e,t,r,i)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of yt(t))!mt.call(e,n)&&n!==r&&H(e,n,{get:()=>t[n],enumerable:!(i=pt(t,n))||i.enumerable});return e};var Te=(e,t,r)=>(r=e!=null?ct(gt(e)):{},Pe(t||!e||!e.__esModule?H(r,"default",{value:e,enumerable:!0}):r,e)),vt=e=>Pe(H({},"__esModule",{value:!0}),e);var ue=d(fe=>{"use strict";Object.defineProperty(fe,"__esModule",{value:!0});fe.default=xt;var bt=_t(require("crypto"));function _t(e){return e&&e.__esModule?e:{default:e}}var z=new Uint8Array(256),j=z.length;function xt(){return j>z.length-16&&(bt.default.randomFillSync(z),j=0),z.slice(j,j+=16)}});var Ee=d(J=>{"use strict";Object.defineProperty(J,"__esModule",{value:!0});J.default=void 0;var wt=/^(?:[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}|00000000-0000-0000-0000-000000000000)$/i;J.default=wt});var B=d(V=>{"use strict";Object.defineProperty(V,"__esModule",{value:!0});V.default=void 0;var Pt=Tt(Ee());function Tt(e){return e&&e.__esModule?e:{default:e}}function Et(e){return typeof e=="string"&&Pt.default.test(e)}var Ot=Et;V.default=Ot});var N=d(G=>{"use strict";Object.defineProperty(G,"__esModule",{value:!0});G.default=void 0;var kt=At(B());function At(e){return e&&e.__esModule?e:{default:e}}var y=[];for(let e=0;e<256;++e)y.push((e+256).toString(16).substr(1));function St(e,t=0){let r=(y[e[t+0]]+y[e[t+1]]+y[e[t+2]]+y[e[t+3]]+"-"+y[e[t+4]]+y[e[t+5]]+"-"+y[e[t+6]]+y[e[t+7]]+"-"+y[e[t+8]]+y[e[t+9]]+"-"+y[e[t+10]]+y[e[t+11]]+y[e[t+12]]+y[e[t+13]]+y[e[t+14]]+y[e[t+15]]).toLowerCase();if(!(0,kt.default)(r))throw TypeError("Stringified UUID is invalid");return r}var Mt=St;G.default=Mt});var Ae=d(Y=>{"use strict";Object.defineProperty(Y,"__esModule",{value:!0});Y.default=void 0;var Rt=ke(ue()),Ft=ke(N());function ke(e){return e&&e.__esModule?e:{default:e}}var Oe,le,de=0,ce=0;function qt(e,t,r){let i=t&&r||0,n=t||new Array(16);e=e||{};let s=e.node||Oe,o=e.clockseq!==void 0?e.clockseq:le;if(s==null||o==null){let l=e.random||(e.rng||Rt.default)();s==null&&(s=Oe=[l[0]|1,l[1],l[2],l[3],l[4],l[5]]),o==null&&(o=le=(l[6]<<8|l[7])&16383)}let a=e.msecs!==void 0?e.msecs:Date.now(),f=e.nsecs!==void 0?e.nsecs:ce+1,c=a-de+(f-ce)/1e4;if(c<0&&e.clockseq===void 0&&(o=o+1&16383),(c<0||a>de)&&e.nsecs===void 0&&(f=0),f>=1e4)throw new Error("uuid.v1(): Can't create more than 10M uuids/sec");de=a,ce=f,le=o,a+=122192928e5;let p=((a&268435455)*1e4+f)%4294967296;n[i++]=p>>>24&255,n[i++]=p>>>16&255,n[i++]=p>>>8&255,n[i++]=p&255;let b=a/4294967296*1e4&268435455;n[i++]=b>>>8&255,n[i++]=b&255,n[i++]=b>>>24&15|16,n[i++]=b>>>16&255,n[i++]=o>>>8|128,n[i++]=o&255;for(let l=0;l<6;++l)n[i+l]=s[l];return t||(0,Ft.default)(n)}var It=qt;Y.default=It});var pe=d(Z=>{"use strict";Object.defineProperty(Z,"__esModule",{value:!0});Z.default=void 0;var Dt=Ut(B());function Ut(e){return e&&e.__esModule?e:{default:e}}function Lt(e){if(!(0,Dt.default)(e))throw TypeError("Invalid UUID");let t,r=new Uint8Array(16);return r[0]=(t=parseInt(e.slice(0,8),16))>>>24,r[1]=t>>>16&255,r[2]=t>>>8&255,r[3]=t&255,r[4]=(t=parseInt(e.slice(9,13),16))>>>8,r[5]=t&255,r[6]=(t=parseInt(e.slice(14,18),16))>>>8,r[7]=t&255,r[8]=(t=parseInt(e.slice(19,23),16))>>>8,r[9]=t&255,r[10]=(t=parseInt(e.slice(24,36),16))/1099511627776&255,r[11]=t/4294967296&255,r[12]=t>>>24&255,r[13]=t>>>16&255,r[14]=t>>>8&255,r[15]=t&255,r}var Bt=Lt;Z.default=Bt});var ye=d(O=>{"use strict";Object.defineProperty(O,"__esModule",{value:!0});O.default=Ht;O.URL=O.DNS=void 0;var Nt=Se(N()),Ct=Se(pe());function Se(e){return e&&e.__esModule?e:{default:e}}function $t(e){e=unescape(encodeURIComponent(e));let t=[];for(let r=0;r<e.length;++r)t.push(e.charCodeAt(r));return t}var Me="6ba7b810-9dad-11d1-80b4-00c04fd430c8";O.DNS=Me;var Re="6ba7b811-9dad-11d1-80b4-00c04fd430c8";O.URL=Re;function Ht(e,t,r){function i(n,s,o,a){if(typeof n=="string"&&(n=$t(n)),typeof s=="string"&&(s=(0,Ct.default)(s)),s.length!==16)throw TypeError("Namespace must be array-like (16 iterable integer values, 0-255)");let f=new Uint8Array(16+n.length);if(f.set(s),f.set(n,s.length),f=r(f),f[6]=f[6]&15|t,f[8]=f[8]&63|128,o){a=a||0;for(let c=0;c<16;++c)o[a+c]=f[c];return o}return(0,Nt.default)(f)}try{i.name=e}catch{}return i.DNS=Me,i.URL=Re,i}});var Fe=d(W=>{"use strict";Object.defineProperty(W,"__esModule",{value:!0});W.default=void 0;var jt=zt(require("crypto"));function zt(e){return e&&e.__esModule?e:{default:e}}function Jt(e){return Array.isArray(e)?e=Buffer.from(e):typeof e=="string"&&(e=Buffer.from(e,"utf8")),jt.default.createHash("md5").update(e).digest()}var Vt=Jt;W.default=Vt});var Ie=d(K=>{"use strict";Object.defineProperty(K,"__esModule",{value:!0});K.default=void 0;var Gt=qe(ye()),Yt=qe(Fe());function qe(e){return e&&e.__esModule?e:{default:e}}var Zt=(0,Gt.default)("v3",48,Yt.default),Wt=Zt;K.default=Wt});var Ue=d(Q=>{"use strict";Object.defineProperty(Q,"__esModule",{value:!0});Q.default=void 0;var Kt=De(ue()),Qt=De(N());function De(e){return e&&e.__esModule?e:{default:e}}function Xt(e,t,r){e=e||{};let i=e.random||(e.rng||Kt.default)();if(i[6]=i[6]&15|64,i[8]=i[8]&63|128,t){r=r||0;for(let n=0;n<16;++n)t[r+n]=i[n];return t}return(0,Qt.default)(i)}var er=Xt;Q.default=er});var Le=d(X=>{"use strict";Object.defineProperty(X,"__esModule",{value:!0});X.default=void 0;var tr=rr(require("crypto"));function rr(e){return e&&e.__esModule?e:{default:e}}function nr(e){return Array.isArray(e)?e=Buffer.from(e):typeof e=="string"&&(e=Buffer.from(e,"utf8")),tr.default.createHash("sha1").update(e).digest()}var ir=nr;X.default=ir});var Ne=d(ee=>{"use strict";Object.defineProperty(ee,"__esModule",{value:!0});ee.default=void 0;var sr=Be(ye()),or=Be(Le());function Be(e){return e&&e.__esModule?e:{default:e}}var ar=(0,sr.default)("v5",80,or.default),fr=ar;ee.default=fr});var Ce=d(te=>{"use strict";Object.defineProperty(te,"__esModule",{value:!0});te.default=void 0;var ur="00000000-0000-0000-0000-000000000000";te.default=ur});var $e=d(re=>{"use strict";Object.defineProperty(re,"__esModule",{value:!0});re.default=void 0;var lr=dr(B());function dr(e){return e&&e.__esModule?e:{default:e}}function cr(e){if(!(0,lr.default)(e))throw TypeError("Invalid UUID");return parseInt(e.substr(14,1),16)}var pr=cr;re.default=pr});var He=d(x=>{"use strict";Object.defineProperty(x,"__esModule",{value:!0});Object.defineProperty(x,"v1",{enumerable:!0,get:function(){return yr.default}});Object.defineProperty(x,"v3",{enumerable:!0,get:function(){return gr.default}});Object.defineProperty(x,"v4",{enumerable:!0,get:function(){return mr.default}});Object.defineProperty(x,"v5",{enumerable:!0,get:function(){return hr.default}});Object.defineProperty(x,"NIL",{enumerable:!0,get:function(){return vr.default}});Object.defineProperty(x,"version",{enumerable:!0,get:function(){return br.default}});Object.defineProperty(x,"validate",{enumerable:!0,get:function(){return _r.default}});Object.defineProperty(x,"stringify",{enumerable:!0,get:function(){return xr.default}});Object.defineProperty(x,"parse",{enumerable:!0,get:function(){return wr.default}});var yr=P(Ae()),gr=P(Ie()),mr=P(Ue()),hr=P(Ne()),vr=P(Ce()),br=P($e()),_r=P(B()),xr=P(N()),wr=P(pe());function P(e){return e&&e.__esModule?e:{default:e}}});var ve=d(u=>{"use strict";var Je=u&&u.__rest||function(e,t){var r={};for(var i in e)Object.prototype.hasOwnProperty.call(e,i)&&t.indexOf(i)<0&&(r[i]=e[i]);if(e!=null&&typeof Object.getOwnPropertySymbols=="function")for(var n=0,i=Object.getOwnPropertySymbols(e);n<i.length;n++)t.indexOf(i[n])<0&&Object.prototype.propertyIsEnumerable.call(e,i[n])&&(r[i[n]]=e[i[n]]);return r};Object.defineProperty(u,"__esModule",{value:!0});u.isSchema=u.isValidSchema=u.isDiscriminatorForm=u.isValuesForm=u.isPropertiesForm=u.isElementsForm=u.isEnumForm=u.isTypeForm=u.isRefForm=u.isEmptyForm=void 0;function Pr(e){let{definitions:t,nullable:r,metadata:i}=e,n=Je(e,["definitions","nullable","metadata"]);return Object.keys(n).length===0}u.isEmptyForm=Pr;function Ve(e){return"ref"in e}u.isRefForm=Ve;function Tr(e){return"type"in e}u.isTypeForm=Tr;function Ge(e){return"enum"in e}u.isEnumForm=Ge;function Ye(e){return"elements"in e}u.isElementsForm=Ye;function he(e){return"properties"in e||"optionalProperties"in e}u.isPropertiesForm=he;function Ze(e){return"values"in e}u.isValuesForm=Ze;function We(e){return"discriminator"in e}u.isDiscriminatorForm=We;function k(e,t){if(t===void 0&&(t=e),e.definitions!==void 0){if(t!==e)return!1;for(let r of Object.values(e.definitions))if(!k(r,t))return!1}if(Ve(e)&&!(e.ref in(t.definitions||{}))||Ge(e)&&(e.enum.length===0||e.enum.length!==new Set(e.enum).size))return!1;if(Ye(e))return k(e.elements,t);if(he(e)){for(let r of Object.values(e.properties||{}))if(!k(r,t))return!1;for(let r of Object.values(e.optionalProperties||{}))if(!k(r,t))return!1;for(let r of Object.keys(e.properties||{}))if(r in(e.optionalProperties||{}))return!1}if(Ze(e))return k(e.values,t);if(We(e)){for(let r of Object.values(e.mapping))if(!k(r,t)||!he(r)||r.nullable||e.discriminator in(r.properties||{})||e.discriminator in(r.optionalProperties||{}))return!1}return!0}u.isValidSchema=k;var Er=[[!1,!1,!1,!1,!1,!1,!1,!1,!1,!1],[!0,!1,!1,!1,!1,!1,!1,!1,!1,!1],[!1,!0,!1,!1,!1,!1,!1,!1,!1,!1],[!1,!1,!0,!1,!1,!1,!1,!1,!1,!1],[!1,!1,!1,!0,!1,!1,!1,!1,!1,!1],[!1,!1,!1,!1,!0,!1,!1,!1,!1,!1],[!1,!1,!1,!1,!1,!0,!1,!1,!1,!1],[!1,!1,!1,!1,!0,!0,!1,!1,!1,!1],[!1,!1,!1,!1,!0,!1,!0,!1,!1,!1],[!1,!1,!1,!1,!1,!0,!0,!1,!1,!1],[!1,!1,!1,!1,!0,!0,!0,!1,!1,!1],[!1,!1,!1,!1,!1,!1,!1,!0,!1,!1],[!1,!1,!1,!1,!1,!1,!1,!1,!0,!0]],Or=["boolean","float32","float64","int8","uint8","int16","uint16","int32","uint32","string","timestamp"];function A(e){if(typeof e!="object"||Array.isArray(e)||e===null)return!1;let t=e,{definitions:r=void 0,nullable:i=void 0,metadata:n=void 0,ref:s=void 0,type:o=void 0,enum:a=void 0,elements:f=void 0,properties:c=void 0,optionalProperties:p=void 0,additionalProperties:b=void 0,values:l=void 0,discriminator:I=void 0,mapping:_=void 0}=t,se=Je(t,["definitions","nullable","metadata","ref","type","enum","elements","properties","optionalProperties","additionalProperties","values","discriminator","mapping"]),D=[s!==void 0,o!==void 0,a!==void 0,f!==void 0,c!==void 0,p!==void 0,b!==void 0,l!==void 0,I!==void 0,_!==void 0],L=!1;for(let v of Er)L=L||v.every((oe,ae)=>oe===D[ae]);if(!L)return!1;if(r!==void 0){if(typeof r!="object"||Array.isArray(r)||r===null)return!1;for(let v of Object.values(r))if(!A(v))return!1}if(i!==void 0&&typeof i!="boolean"||n!==void 0&&(typeof n!="object"||Array.isArray(n)||n===null)||s!==void 0&&typeof s!="string"||o!==void 0&&(typeof o!="string"||!Or.includes(o))||a!==void 0&&(!Array.isArray(a)||!a.every(v=>typeof v=="string"))||f!==void 0&&!A(f))return!1;if(c!==void 0){if(typeof c!="object"||Array.isArray(c)||c===null)return!1;for(let v of Object.values(c))if(!A(v))return!1}if(p!==void 0){if(typeof p!="object"||Array.isArray(p)||p===null)return!1;for(let v of Object.values(p))if(!A(v))return!1}if(b!==void 0&&typeof b!="boolean"||l!==void 0&&!A(l)||I!==void 0&&typeof I!="string")return!1;if(_!==void 0){if(typeof _!="object"||Array.isArray(_)||_===null)return!1;for(let v of Object.values(_))if(!A(v))return!1}return Object.keys(se).length===0}u.isSchema=A});var Ke=d(be=>{"use strict";Object.defineProperty(be,"__esModule",{value:!0});var kr=/^(\d{4})-(\d{2})-(\d{2})[tT](\d{2}):(\d{2}):(\d{2})(\.\d+)?([zZ]|((\+|-)(\d{2}):(\d{2})))$/;function Ar(e){let t=e.match(kr);if(t===null)return!1;let r=parseInt(t[1],10),i=parseInt(t[2],10),n=parseInt(t[3],10),s=parseInt(t[4],10),o=parseInt(t[5],10),a=parseInt(t[6],10);return!(i>12||n>Sr(r,i)||s>23||o>59||a>60)}be.default=Ar;function Sr(e,t){return t===2?Mr(e)?29:28:Rr[t]}function Mr(e){return e%4===0&&(e%100!==0||e%400===0)}var Rr=[0,31,0,31,30,31,30,31,31,30,31,30,31]});var Qe=d(T=>{"use strict";var Fr=T&&T.__importDefault||function(e){return e&&e.__esModule?e:{default:e}};Object.defineProperty(T,"__esModule",{value:!0});T.validate=T.MaxDepthExceededError=void 0;var qr=Fr(Ke()),S=ve(),ne=class extends Error{};T.MaxDepthExceededError=ne;var ie=class extends Error{};function Ir(e,t,r){let i={errors:[],instanceTokens:[],schemaTokens:[[]],root:e,config:r||{maxDepth:0,maxErrors:0}};try{F(i,e,t)}catch(n){if(!(n instanceof ie))throw n}return i.errors}T.validate=Ir;function F(e,t,r,i){if(!(t.nullable&&r===null)){if(S.isRefForm(t)){if(e.schemaTokens.length===e.config.maxDepth)throw new ne;e.schemaTokens.push(["definitions",t.ref]),F(e,e.root.definitions[t.ref],r),e.schemaTokens.pop()}else if(S.isTypeForm(t)){switch(g(e,"type"),t.type){case"boolean":typeof r!="boolean"&&m(e);break;case"float32":case"float64":typeof r!="number"&&m(e);break;case"int8":U(e,r,-128,127);break;case"uint8":U(e,r,0,255);break;case"int16":U(e,r,-32768,32767);break;case"uint16":U(e,r,0,65535);break;case"int32":U(e,r,-2147483648,2147483647);break;case"uint32":U(e,r,0,4294967295);break;case"string":typeof r!="string"&&m(e);break;case"timestamp":typeof r!="string"?m(e):qr.default(r)||m(e);break}h(e)}else if(S.isEnumForm(t))g(e,"enum"),(typeof r!="string"||!t.enum.includes(r))&&m(e),h(e);else if(S.isElementsForm(t)){if(g(e,"elements"),Array.isArray(r))for(let[n,s]of r.entries())M(e,n.toString()),F(e,t.elements,s),R(e);else m(e);h(e)}else if(S.isPropertiesForm(t))if(typeof r=="object"&&r!==null&&!Array.isArray(r)){if(t.properties!==void 0){g(e,"properties");for(let[n,s]of Object.entries(t.properties))g(e,n),r.hasOwnProperty(n)?(M(e,n),F(e,s,r[n]),R(e)):m(e),h(e);h(e)}if(t.optionalProperties!==void 0){g(e,"optionalProperties");for(let[n,s]of Object.entries(t.optionalProperties))g(e,n),r.hasOwnProperty(n)&&(M(e,n),F(e,s,r[n]),R(e)),h(e);h(e)}if(t.additionalProperties!==!0)for(let n of Object.keys(r)){let s=t.properties&&n in t.properties,o=t.optionalProperties&&n in t.optionalProperties;!s&&!o&&n!==i&&(M(e,n),m(e),R(e))}}else t.properties!==void 0?g(e,"properties"):g(e,"optionalProperties"),m(e),h(e);else if(S.isValuesForm(t)){if(g(e,"values"),typeof r=="object"&&r!==null&&!Array.isArray(r))for(let[n,s]of Object.entries(r))M(e,n),F(e,t.values,s),R(e);else m(e);h(e)}else if(S.isDiscriminatorForm(t))if(typeof r=="object"&&r!==null&&!Array.isArray(r))if(r.hasOwnProperty(t.discriminator)){let n=r[t.discriminator];typeof n=="string"?n in t.mapping?(g(e,"mapping"),g(e,n),F(e,t.mapping[n],r,t.discriminator),h(e),h(e)):(g(e,"mapping"),M(e,t.discriminator),m(e),R(e),h(e)):(g(e,"discriminator"),M(e,t.discriminator),m(e),R(e),h(e))}else g(e,"discriminator"),m(e),h(e);else g(e,"discriminator"),m(e),h(e)}}function U(e,t,r,i){(typeof t!="number"||!Number.isInteger(t)||t<r||t>i)&&m(e)}function M(e,t){e.instanceTokens.push(t)}function R(e){e.instanceTokens.pop()}function g(e,t){e.schemaTokens[e.schemaTokens.length-1].push(t)}function h(e){e.schemaTokens[e.schemaTokens.length-1].pop()}function m(e){if(e.errors.push({instancePath:[...e.instanceTokens],schemaPath:[...e.schemaTokens[e.schemaTokens.length-1]]}),e.errors.length===e.config.maxErrors)throw new ie}});var et=d(E=>{"use strict";var Dr=E&&E.__createBinding||(Object.create?function(e,t,r,i){i===void 0&&(i=r),Object.defineProperty(e,i,{enumerable:!0,get:function(){return t[r]}})}:function(e,t,r,i){i===void 0&&(i=r),e[i]=t[r]}),Xe=E&&E.__exportStar||function(e,t){for(var r in e)r!=="default"&&!t.hasOwnProperty(r)&&Dr(t,e,r)};Object.defineProperty(E,"__esModule",{value:!0});Xe(ve(),E);Xe(Qe(),E)});var Vr={};ht(Vr,{GenerationError:()=>C,ResponseError:()=>q,builtinFontNames:()=>Nr,builtinLineHeights:()=>ut,builtinMargins:()=>ft,builtinTextScales:()=>at,builtinTools:()=>Br,register:()=>Hr,remarkable:()=>Jr});module.exports=vt(Vr);var w=Te(He(),1),ln=w.default.v1,dn=w.default.v3,ge=w.default.v4,cn=w.default.v5,pn=w.default.NIL,yn=w.default.version,gn=w.default.validate,mn=w.default.stringify,hn=w.default.parse;function me(e){return[...new Uint8Array(e)].map(t=>t.toString(16).padStart(2,"0")).join("")}function je(e){return new Uint8Array((e.match(/../g)??[]).map(t=>parseInt(t,16)))}function ze(e){let t=0;for(let n of e)t+=n.length;let r=new Uint8Array(t),i=0;for(let n of e)r.set(n,i),i+=n.length;return r}var tt=Te(et());function _e(e,t){if((0,tt.validate)(e,t).length)throw new Error(`couldn't validate schema: ${JSON.stringify(t)} didn't match schema ${JSON.stringify(e)}`)}var rt="3",ot="https://webapp-production-dot-remarkable-production.appspot.com",Ur="https://rm-blob-storage-prod.appspot.com",nt="x-goog-generation",Lr="x-goog-if-generation-match",Br=["Ballpoint","Ballpointv2","Brush","Calligraphy","ClearPage","EraseSection","Eraser","Fineliner","Finelinerv2","Highlighter","Highlighterv2","Marker","Markerv2","Paintbrush","Paintbrushv2","Pencilv2","SharpPencil","SharpPencilv2","SolidPen","ZoomTool"],Nr=["Maison Neue","EB Garamond","Noto Sans","Noto Serif","Noto Mono","Noto Sans UI"],at={xs:.7,sm:.8,md:1,lg:1.2,xl:1.5,xx:2},ft={sm:50,md:125,rr:180,lg:200},ut={df:-1,md:100,lg:150,xl:200},Cr={properties:{relative_path:{type:"string"},url:{type:"string"},expires:{type:"timestamp"},method:{enum:["POST","GET","PUT","DELETE"]}}},it={visibleName:{type:"string"},parent:{type:"string"},lastModified:{type:"string"},version:{type:"int32"},synced:{type:"boolean"}},st={pinned:{type:"boolean"},modified:{type:"boolean"},deleted:{type:"boolean"},metadatamodified:{type:"boolean"}},$r={discriminator:"type",mapping:{CollectionType:{properties:it,optionalProperties:st},DocumentType:{properties:it,optionalProperties:{...st,lastOpened:{type:"string"},lastOpenedPage:{type:"int32"}}}}},q=class extends Error{constructor(r,i,n){super(n);this.status=r,this.statusText=i}},C=class extends Error{constructor(){super("Generation preconditions failed. This means the current state is out of date with the cloud and needs to be re-synced.")}};async function Hr(e,{deviceDesc:t="desktop-linux",uuid:r=ge(),authUrl:i=ot,fetch:n=globalThis.fetch}={}){if(e.length!==8)throw new Error(`code should be length 8, but was ${e.length}`);let s=await n(`${i}/token/json/2/device/new`,{method:"POST",headers:{Authorization:"Bearer"},body:JSON.stringify({code:e,deviceDesc:t,deviceID:r})});if(s.ok)return await s.text();throw new q(s.status,s.statusText,"couldn't register api")}function jr({hash:e,type:t,documentId:r,subfiles:i,size:n}){return`${e}:${t}:${r}:${i}:${n}
|
|
2
|
-
`}function zr(e){let[t,r,i,n,s]=e.split(":");if(t===void 0||r===void 0||i===void 0||n===void 0||s===void 0)throw new Error(`entries line didn't contain five fields: '${e}'`);if(r==="80000000"){if(s!=="0")throw new Error(`collection type entry had nonzero size: ${s}`);return{hash:t,type:r,documentId:i,subfiles:parseInt(n),size:0n}}else if(r==="0"){if(n!=="0")throw new Error(`file type entry had nonzero number of subfiles: ${n}`);return{hash:t,type:r,documentId:i,subfiles:0,size:BigInt(s)}}else throw new Error(`entries line contained invalid type: ${r}`)}var xe=class{constructor(t,r,i,n,s){this.userToken=t;this.fetch=r;this.cache=i;this.subtle=n;this.blobUrl=s}async authedFetch(t,r,i="POST"){let n=await this.fetch(t,{method:i,headers:{Authorization:`Bearer ${this.userToken}`},body:r&&JSON.stringify(r)});if(n.ok)return n;throw new q(n.status,n.statusText,"failed reMarkable request")}async signedFetch({url:t,method:r},i,n){let s=await this.fetch(t,{method:r,body:i,headers:n});if(s.ok)return s;{let o=await s.text();throw new q(s.status,s.statusText,o)}}async getUrl(t,r){let i=r===void 0?"downloads":"uploads",n=r==null?void 0:`${r}`,o=await(await this.authedFetch(`${this.blobUrl}/api/v1/signed-urls/${i}`,{http_method:n===void 0?"GET":"PUT",relative_path:t,generation:n})).text(),a=JSON.parse(o);return _e(Cr,a),a}async syncComplete(){await this.authedFetch(`${this.blobUrl}/api/v1/sync-complete`)}async getRootHash(){let t=await this.getUrl("root"),r=await this.signedFetch(t),i=r.headers.get(nt);if(!i)throw new Error("no generation header in root hash");return[await r.text(),BigInt(i)]}async putRootHash(t,r){let i=await this.getUrl("root",r),n;try{n=await this.signedFetch(i,t,{[Lr]:`${r}`})}catch(o){throw o instanceof q&&o.status===412?new C:o}let s=n.headers.get(nt);if(!s)throw new Error("no generation header in root hash");return BigInt(s)}async getBuffer(t){let r=await this.getUrl(t);return await(await this.signedFetch(r)).arrayBuffer()}async getText(t){let r=this.cache&&await this.cache.get(t);if(r)return r;{let i=await this.getUrl(t),s=await(await this.signedFetch(i)).text();return this.cache&&await this.cache.set(t,s),s}}async getMetadata(t){let r=await this.getText(t),i=JSON.parse(r);return _e($r,i),i}async getEntries(t){let r=await this.getText(t),[i,...n]=r.slice(0,-1).split(`
|
|
3
|
-
`);if(i!==rt)throw new Error(`got unexpected schema version: ${i}`);return n.map(zr)}async putHash(t,r){let i=await this.getUrl(t,null);await this.signedFetch(i,r)}async putEntries(t,r){let i=new TextEncoder;r.sort((p,b)=>p.documentId.localeCompare(b.documentId));let n=ze(r.map(p=>je(p.hash))),s=await this.subtle.digest("SHA-256",n),o=me(s),a=r.map(jr).join(""),f=`${rt}
|
|
4
|
-
${a}`,c=i.encode(f);return await this.putHash(o,c),this.cache&&await this.cache.set(o,f),{hash:o,type:"80000000",documentId:t,subfiles:r.length,size:0n}}async putBuffer(t,r){let i=await this.subtle.digest("SHA-256",r),n=me(i);return await this.putHash(n,r),{hash:n,type:"0",documentId:t,subfiles:0,size:BigInt(r.length)}}async putText(t,r){let i=new TextEncoder,n=await this.putBuffer(t,i.encode(r));return this.cache&&await this.cache.set(n.hash,r),n}async putEpub(t,r,{parent:i="",margins:n=125,orientation:s,textAlignment:o,textScale:a=1,lineHeight:f=-1,fontName:c="",cover:p="visited",lastTool:b,notify:l=!0,retries:I=3}={}){let _=ge(),se=`${new Date().valueOf()}`,D=[];D.push(this.putBuffer(`${_}.epub`,r));let L={type:"DocumentType",visibleName:t,version:0,parent:i,synced:!0,lastModified:se};D.push(this.putText(`${_}.metadata`,JSON.stringify(L)));let v={dummyDocument:!1,extraMetadata:{LastTool:b},fileType:"epub",pageCount:0,lastOpenedPage:0,lineHeight:typeof f=="string"?ut[f]:f,margins:typeof n=="string"?ft[n]:n,textScale:typeof a=="string"?at[a]:a,pages:[],coverPageNumber:p==="first"?0:-1,formatVersion:1,orientation:s,textAlignment:o,fontName:c};D.push(this.putText(`${_}.content`,JSON.stringify(v)));let oe=await Promise.all(D),ae=await this.putEntries(_,oe);for(;;--I)try{let[$,lt]=await this.getRootHash(),we=await this.getEntries($);we.push(ae);let{hash:dt}=await this.putEntries("",we);await this.putRootHash(dt,lt);break}catch($){if(I<=0||!($ instanceof C))throw $}l&&await this.syncComplete()}};async function Jr(e,{fetch:t=globalThis.fetch,cache:r,subtle:i=globalThis.crypto?.subtle,authUrl:n=ot,blobUrl:s=Ur}={}){let o=await t(`${n}/token/json/2/user/new`,{method:"POST",headers:{Authorization:`Bearer ${e}`}});if(!o.ok)throw new Error(`couldn't fetch auth token: ${o.statusText}`);let a=await o.text();return new xe(a,t,r,i,s)}0&&(module.exports={GenerationError,ResponseError,builtinFontNames,builtinLineHeights,builtinMargins,builtinTextScales,builtinTools,register,remarkable});
|