rmapi-js 1.1.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/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 -26
- package/dist/index.js +200 -68
- package/package.json +32 -29
- 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,19 +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);
|
|
43
|
+
* const nextGen = await api.putRootHash(hash, gen);
|
|
44
|
+
* await api.syncComplete(nextGen);
|
|
39
45
|
* ```
|
|
40
46
|
*
|
|
41
47
|
* @packageDocumentation
|
|
42
48
|
*/
|
|
49
|
+
import { fromByteArray } from "base64-js";
|
|
43
50
|
import { v4 as uuid4 } from "uuid";
|
|
44
51
|
import { concatBuffers, fromHex, toHex } from "./utils";
|
|
45
52
|
import { validate } from "./validate";
|
|
46
53
|
const SCHEMA_VERSION = "3";
|
|
47
|
-
const
|
|
48
|
-
const
|
|
54
|
+
const AUTH_HOST = "https://webapp-prod.cloud.remarkable.engineering";
|
|
55
|
+
const SYNC_HOST = "https://internal.cloud.remarkable.com";
|
|
49
56
|
const GENERATION_HEADER = "x-goog-generation";
|
|
50
57
|
const GENERATION_RACE_HEADER = "x-goog-if-generation-match";
|
|
58
|
+
const CONTENT_LENGTH_RANGE_HEADER = "x-goog-content-length-range";
|
|
51
59
|
/** tool options */
|
|
52
60
|
export const builtinTools = [
|
|
53
61
|
"Ballpoint",
|
|
@@ -117,6 +125,12 @@ export const builtinLineHeights = {
|
|
|
117
125
|
/** double */
|
|
118
126
|
xl: 200,
|
|
119
127
|
};
|
|
128
|
+
const uploadEntrySchema = {
|
|
129
|
+
properties: {
|
|
130
|
+
docID: { type: "string" },
|
|
131
|
+
hash: { type: "string" },
|
|
132
|
+
},
|
|
133
|
+
};
|
|
120
134
|
const urlResponseSchema = {
|
|
121
135
|
properties: {
|
|
122
136
|
relative_path: { type: "string" },
|
|
@@ -124,19 +138,22 @@ const urlResponseSchema = {
|
|
|
124
138
|
expires: { type: "timestamp" },
|
|
125
139
|
method: { enum: ["POST", "GET", "PUT", "DELETE"] },
|
|
126
140
|
},
|
|
141
|
+
optionalProperties: {
|
|
142
|
+
maxuploadsize_bytes: { type: "float64" },
|
|
143
|
+
},
|
|
127
144
|
};
|
|
128
145
|
const commonProperties = {
|
|
129
146
|
visibleName: { type: "string" },
|
|
130
|
-
parent: { type: "string" },
|
|
131
147
|
lastModified: { type: "string" },
|
|
132
|
-
version: { type: "int32" },
|
|
133
|
-
synced: { type: "boolean" },
|
|
134
148
|
};
|
|
135
149
|
const commonOptionalProperties = {
|
|
150
|
+
version: { type: "int32" },
|
|
136
151
|
pinned: { type: "boolean" },
|
|
152
|
+
synced: { type: "boolean" },
|
|
137
153
|
modified: { type: "boolean" },
|
|
138
154
|
deleted: { type: "boolean" },
|
|
139
155
|
metadatamodified: { type: "boolean" },
|
|
156
|
+
parent: { type: "string" },
|
|
140
157
|
};
|
|
141
158
|
const metadataSchema = {
|
|
142
159
|
discriminator: "type",
|
|
@@ -155,6 +172,34 @@ const metadataSchema = {
|
|
|
155
172
|
},
|
|
156
173
|
},
|
|
157
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
|
+
};
|
|
158
203
|
/** an error that results from a failed request */
|
|
159
204
|
export class ResponseError extends Error {
|
|
160
205
|
/** the response status number */
|
|
@@ -181,18 +226,18 @@ export class GenerationError extends Error {
|
|
|
181
226
|
/**
|
|
182
227
|
* register a device and get the token needed to access the api
|
|
183
228
|
*
|
|
184
|
-
* Have users go to `https://my.remarkable.com/device/
|
|
229
|
+
* Have users go to `https://my.remarkable.com/device/browser/connect` and pass
|
|
185
230
|
* the resulting code into this function to get a device token. Persist that
|
|
186
231
|
* token to use the api.
|
|
187
232
|
*
|
|
188
|
-
* @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`.
|
|
189
234
|
* @returns the device token necessary for creating an api instace. These never expire so persist as long as necessary.
|
|
190
235
|
*/
|
|
191
|
-
export async function register(code, { deviceDesc = "
|
|
236
|
+
export async function register(code, { deviceDesc = "browser-chrome", uuid = uuid4(), authHost = AUTH_HOST, fetch = globalThis.fetch, } = {}) {
|
|
192
237
|
if (code.length !== 8) {
|
|
193
238
|
throw new Error(`code should be length 8, but was ${code.length}`);
|
|
194
239
|
}
|
|
195
|
-
const resp = await fetch(`${
|
|
240
|
+
const resp = await fetch(`${authHost}/token/json/2/device/new`, {
|
|
196
241
|
method: "POST",
|
|
197
242
|
headers: {
|
|
198
243
|
Authorization: "Bearer",
|
|
@@ -253,37 +298,45 @@ export function parseEntry(line) {
|
|
|
253
298
|
}
|
|
254
299
|
/** the implementation of that api */
|
|
255
300
|
class Remarkable {
|
|
256
|
-
userToken;
|
|
257
|
-
fetch;
|
|
258
|
-
cache;
|
|
259
|
-
subtle;
|
|
260
|
-
|
|
261
|
-
constructor(userToken, fetch, cache, subtle,
|
|
262
|
-
this
|
|
263
|
-
this
|
|
264
|
-
this
|
|
265
|
-
this
|
|
266
|
-
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;
|
|
267
312
|
}
|
|
268
313
|
/** make an authorized request to remarkable */
|
|
269
|
-
async authedFetch(url, body, method = "POST") {
|
|
270
|
-
const resp = await this
|
|
314
|
+
async #authedFetch(url, { body, method = "POST", headers = {}, }) {
|
|
315
|
+
const resp = await this.#fetch(url, {
|
|
271
316
|
method,
|
|
272
317
|
headers: {
|
|
273
|
-
Authorization: `Bearer ${this
|
|
318
|
+
Authorization: `Bearer ${this.#userToken}`,
|
|
319
|
+
...headers,
|
|
274
320
|
},
|
|
275
|
-
body
|
|
321
|
+
body,
|
|
276
322
|
});
|
|
277
323
|
if (!resp.ok) {
|
|
278
|
-
|
|
324
|
+
const msg = await resp.text();
|
|
325
|
+
throw new ResponseError(resp.status, resp.statusText, `failed reMarkable request: ${msg}`);
|
|
279
326
|
}
|
|
280
327
|
else {
|
|
281
328
|
return resp;
|
|
282
329
|
}
|
|
283
330
|
}
|
|
284
331
|
/** make a signed request to the cloud */
|
|
285
|
-
async signedFetch({ url, method }, body,
|
|
286
|
-
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, {
|
|
287
340
|
method,
|
|
288
341
|
body,
|
|
289
342
|
headers,
|
|
@@ -297,14 +350,13 @@ class Remarkable {
|
|
|
297
350
|
}
|
|
298
351
|
}
|
|
299
352
|
/** get the details for how to make a signed request to remarkable cloud */
|
|
300
|
-
async getUrl(relativePath, gen) {
|
|
353
|
+
async #getUrl(relativePath, gen, rootHash) {
|
|
301
354
|
const key = gen === undefined ? "downloads" : "uploads";
|
|
302
|
-
|
|
303
|
-
const
|
|
304
|
-
http_method:
|
|
305
|
-
relative_path: relativePath
|
|
306
|
-
|
|
307
|
-
});
|
|
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 });
|
|
308
360
|
const raw = await resp.text();
|
|
309
361
|
const res = JSON.parse(raw);
|
|
310
362
|
validate(urlResponseSchema, res);
|
|
@@ -314,8 +366,8 @@ class Remarkable {
|
|
|
314
366
|
* get the root hash and the current generation
|
|
315
367
|
*/
|
|
316
368
|
async getRootHash() {
|
|
317
|
-
const signed = await this
|
|
318
|
-
const resp = await this
|
|
369
|
+
const signed = await this.#getUrl("root");
|
|
370
|
+
const resp = await this.#signedFetch(signed);
|
|
319
371
|
const generation = resp.headers.get(GENERATION_HEADER);
|
|
320
372
|
if (!generation) {
|
|
321
373
|
throw new Error("no generation header in root hash");
|
|
@@ -326,10 +378,10 @@ class Remarkable {
|
|
|
326
378
|
* write the root hash, incrementing from the current generation
|
|
327
379
|
*/
|
|
328
380
|
async putRootHash(hash, generation) {
|
|
329
|
-
const signed = await this
|
|
381
|
+
const signed = await this.#getUrl("root", generation, hash);
|
|
330
382
|
let resp;
|
|
331
383
|
try {
|
|
332
|
-
resp = await this
|
|
384
|
+
resp = await this.#signedFetch(signed, hash, {
|
|
333
385
|
[GENERATION_RACE_HEADER]: `${generation}`,
|
|
334
386
|
});
|
|
335
387
|
}
|
|
@@ -351,23 +403,23 @@ class Remarkable {
|
|
|
351
403
|
* get text content associated with hash
|
|
352
404
|
*/
|
|
353
405
|
async getBuffer(hash) {
|
|
354
|
-
const signed = await this
|
|
355
|
-
const resp = await this
|
|
406
|
+
const signed = await this.#getUrl(hash);
|
|
407
|
+
const resp = await this.#signedFetch(signed);
|
|
356
408
|
return await resp.arrayBuffer();
|
|
357
409
|
}
|
|
358
410
|
/**
|
|
359
411
|
* get text content associated with hash
|
|
360
412
|
*/
|
|
361
413
|
async getText(hash) {
|
|
362
|
-
const cached =
|
|
414
|
+
const cached = await this.#cache?.get(hash);
|
|
363
415
|
if (cached) {
|
|
364
416
|
return cached;
|
|
365
417
|
}
|
|
366
418
|
else {
|
|
367
|
-
const signed = await this
|
|
368
|
-
const resp = await this
|
|
419
|
+
const signed = await this.#getUrl(hash);
|
|
420
|
+
const resp = await this.#signedFetch(signed);
|
|
369
421
|
const raw = await resp.text();
|
|
370
|
-
|
|
422
|
+
await this.#cache?.set(hash, raw);
|
|
371
423
|
return raw;
|
|
372
424
|
}
|
|
373
425
|
}
|
|
@@ -393,9 +445,9 @@ class Remarkable {
|
|
|
393
445
|
return lines.map(parseEntry);
|
|
394
446
|
}
|
|
395
447
|
/** upload data to hash */
|
|
396
|
-
async putHash(hash, body) {
|
|
397
|
-
const signed = await this
|
|
398
|
-
await this
|
|
448
|
+
async #putHash(hash, body) {
|
|
449
|
+
const signed = await this.#getUrl(hash, null);
|
|
450
|
+
await this.#signedFetch(signed, body);
|
|
399
451
|
}
|
|
400
452
|
/** put a reference to a set of entries into the cloud */
|
|
401
453
|
async putEntries(documentId, entries) {
|
|
@@ -403,13 +455,13 @@ class Remarkable {
|
|
|
403
455
|
const enc = new TextEncoder();
|
|
404
456
|
entries.sort((a, b) => a.documentId.localeCompare(b.documentId));
|
|
405
457
|
const hashes = concatBuffers(entries.map((ent) => fromHex(ent.hash)));
|
|
406
|
-
const digest = await this
|
|
458
|
+
const digest = await this.#subtle.digest("SHA-256", hashes);
|
|
407
459
|
const hash = toHex(digest);
|
|
408
460
|
const entryContents = entries.map(formatEntry).join("");
|
|
409
461
|
const contents = `${SCHEMA_VERSION}\n${entryContents}`;
|
|
410
462
|
const buffer = enc.encode(contents);
|
|
411
|
-
await this
|
|
412
|
-
|
|
463
|
+
await this.#putHash(hash, buffer);
|
|
464
|
+
await this.#cache?.set(hash, contents);
|
|
413
465
|
return {
|
|
414
466
|
hash,
|
|
415
467
|
type: "80000000",
|
|
@@ -420,9 +472,9 @@ class Remarkable {
|
|
|
420
472
|
}
|
|
421
473
|
/** put a raw buffer in the cloud */
|
|
422
474
|
async putBuffer(documentId, buffer) {
|
|
423
|
-
const digest = await this
|
|
475
|
+
const digest = await this.#subtle.digest("SHA-256", buffer);
|
|
424
476
|
const hash = toHex(digest);
|
|
425
|
-
await this
|
|
477
|
+
await this.#putHash(hash, buffer);
|
|
426
478
|
return {
|
|
427
479
|
hash,
|
|
428
480
|
type: "0",
|
|
@@ -435,16 +487,20 @@ class Remarkable {
|
|
|
435
487
|
async putText(documentId, contents) {
|
|
436
488
|
const enc = new TextEncoder();
|
|
437
489
|
const entry = await this.putBuffer(documentId, enc.encode(contents));
|
|
438
|
-
|
|
490
|
+
await this.#cache?.set(entry.hash, contents);
|
|
439
491
|
return entry;
|
|
440
492
|
}
|
|
441
|
-
/** upload
|
|
442
|
-
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
|
+
}
|
|
443
499
|
const documentId = uuid4();
|
|
444
500
|
const lastModified = `${new Date().valueOf()}`;
|
|
445
501
|
const entryPromises = [];
|
|
446
502
|
// upload main document
|
|
447
|
-
entryPromises.push(this.putBuffer(`${documentId}
|
|
503
|
+
entryPromises.push(this.putBuffer(`${documentId}.${fileType}`, buffer));
|
|
448
504
|
// upload metadata
|
|
449
505
|
const metadata = {
|
|
450
506
|
type: "DocumentType",
|
|
@@ -455,6 +511,15 @@ class Remarkable {
|
|
|
455
511
|
lastModified,
|
|
456
512
|
};
|
|
457
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, } = {}) {
|
|
458
523
|
// upload content file
|
|
459
524
|
const content = {
|
|
460
525
|
dummyDocument: false,
|
|
@@ -478,12 +543,78 @@ class Remarkable {
|
|
|
478
543
|
textAlignment,
|
|
479
544
|
fontName,
|
|
480
545
|
};
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
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");
|
|
487
618
|
}
|
|
488
619
|
}
|
|
489
620
|
/**
|
|
@@ -492,11 +623,12 @@ class Remarkable {
|
|
|
492
623
|
* This gets a temporary authentication token with the device token. If
|
|
493
624
|
* requests start failing, simply recreate the api instance.
|
|
494
625
|
*
|
|
495
|
-
* @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}.
|
|
496
628
|
* @returns an api instance
|
|
497
629
|
*/
|
|
498
|
-
export async function remarkable(deviceToken, { fetch = globalThis.fetch, cache, subtle = globalThis.crypto?.subtle,
|
|
499
|
-
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`, {
|
|
500
632
|
method: "POST",
|
|
501
633
|
headers: {
|
|
502
634
|
Authorization: `Bearer ${deviceToken}`,
|
|
@@ -506,5 +638,5 @@ export async function remarkable(deviceToken, { fetch = globalThis.fetch, cache,
|
|
|
506
638
|
throw new Error(`couldn't fetch auth token: ${resp.statusText}`);
|
|
507
639
|
}
|
|
508
640
|
const userToken = await resp.text();
|
|
509
|
-
return new Remarkable(userToken, fetch, cache, subtle,
|
|
641
|
+
return new Remarkable(userToken, fetch, cache, subtle, syncHost);
|
|
510
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.
|
|
30
|
+
"ajv": "^8.11.2",
|
|
31
|
+
"base64-js": "^1.5.1",
|
|
32
|
+
"jtd": "^0.1.1",
|
|
31
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": "^29.
|
|
40
|
-
"@types/node": "^18.
|
|
41
|
-
"@types/uuid": "^
|
|
42
|
-
"@typescript-eslint/eslint-plugin": "^5.
|
|
43
|
-
"@typescript-eslint/parser": "^5.
|
|
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",
|
|
44
46
|
"@yarnpkg/esbuild-plugin-pnp": "^3.0.0-rc.15",
|
|
45
|
-
"babel-jest": "^29.1
|
|
46
|
-
"chalk": "^5.
|
|
47
|
-
"esbuild": "^0.
|
|
48
|
-
"eslint": "^8.
|
|
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": "^27.1.
|
|
51
|
-
"eslint-plugin-spellcheck": "^0.0.
|
|
52
|
+
"eslint-plugin-jest": "^27.1.7",
|
|
53
|
+
"eslint-plugin-spellcheck": "^0.0.20",
|
|
52
54
|
"eslint-plugin-tsdoc": "^0.2.17",
|
|
53
|
-
"jest": "^29.1
|
|
54
|
-
"
|
|
55
|
-
"prettier": "^2.
|
|
56
|
-
"
|
|
57
|
-
"
|
|
58
|
-
"typescript": "^4.8.4"
|
|
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});
|