rmapi-js 8.3.0 → 8.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +21 -20
- package/dist/index.js +20 -14
- package/dist/raw.d.ts +26 -1
- package/dist/raw.js +27 -2
- package/dist/rmapi-js.esm.min.js +10 -10
- package/package.json +11 -11
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { type BackgroundFilter, type CollectionContent, type Content, type DocumentContent, type Metadata, type Orientation, type RawRemarkableApi, type Tag, type TemplateContent, type TextAlignment, type ZoomMode } from "./raw";
|
|
1
|
+
import { type BackgroundFilter, type CollectionContent, type Content, type DocumentContent, type Metadata, type Orientation, type RawRemarkableApi, type SimpleEntry, type Tag, type TemplateContent, type TextAlignment, type ZoomMode } from "./raw";
|
|
2
2
|
export { HashNotFoundError, ValidationError } from "./error";
|
|
3
|
-
export type { BackgroundFilter, CollectionContent, Content, CPageNumberValue, CPagePage, CPages, CPageStringValue, CPageUUID, DocumentContent, DocumentMetadata, FileType, KeyboardMetadata, Metadata, Orientation, PageTag, RawEntry, RawFileEntry, RawListEntry, RawRemarkableApi, Tag, TemplateContent, TextAlignment, ZoomMode, } from "./raw";
|
|
3
|
+
export type { BackgroundFilter, CollectionContent, Content, CPageNumberValue, CPagePage, CPages, CPageStringValue, CPageUUID, DocumentContent, DocumentMetadata, FileType, KeyboardMetadata, Metadata, Orientation, PageTag, RawEntry, RawFileEntry, RawListEntry, RawRemarkableApi, SimpleEntry, Tag, TemplateContent, TextAlignment, UploadMimeType, ZoomMode, } from "./raw";
|
|
4
4
|
/** common properties shared by collections and documents */
|
|
5
5
|
export interface EntryCommon {
|
|
6
6
|
/** the document id, a uuid4 */
|
|
@@ -50,13 +50,6 @@ export interface TemplateType extends EntryCommon {
|
|
|
50
50
|
}
|
|
51
51
|
/** a remarkable entry for cloud items */
|
|
52
52
|
export type Entry = CollectionEntry | DocumentType | TemplateType;
|
|
53
|
-
/** an simple entry without any extra information */
|
|
54
|
-
export interface SimpleEntry {
|
|
55
|
-
/** the document id */
|
|
56
|
-
id: string;
|
|
57
|
-
/** the document hash */
|
|
58
|
-
hash: string;
|
|
59
|
-
}
|
|
60
53
|
/** the new hash of a modified entry */
|
|
61
54
|
export interface HashEntry {
|
|
62
55
|
/** the actual hash */
|
|
@@ -67,6 +60,11 @@ export interface HashesEntry {
|
|
|
67
60
|
/** the mapping from old to new hashes */
|
|
68
61
|
hashes: Record<string, string>;
|
|
69
62
|
}
|
|
63
|
+
/** options for creating a folder */
|
|
64
|
+
export interface FolderOptions {
|
|
65
|
+
/** the id of the folder's parent directory, "" or omitted for root */
|
|
66
|
+
parent?: string;
|
|
67
|
+
}
|
|
70
68
|
/** An error that gets thrown when the backend while trying to update
|
|
71
69
|
*
|
|
72
70
|
* IF you encounter this error, you likely just need to try th request again. If
|
|
@@ -114,11 +112,6 @@ export interface RegisterOptions {
|
|
|
114
112
|
* @returns the device token necessary for creating an api instace. These never expire so persist as long as necessary.
|
|
115
113
|
*/
|
|
116
114
|
export declare function register(code: string, { deviceDesc, uuid, authHost, }?: RegisterOptions): Promise<string>;
|
|
117
|
-
/** options available when uploading a document */
|
|
118
|
-
export interface UploadOptions {
|
|
119
|
-
/** an optional parent id to set when uploading */
|
|
120
|
-
parent?: string;
|
|
121
|
-
}
|
|
122
115
|
/**
|
|
123
116
|
* options for putting a file onto reMarkable
|
|
124
117
|
*
|
|
@@ -322,7 +315,7 @@ export interface RemarkableApi {
|
|
|
322
315
|
*/
|
|
323
316
|
putEpub(visibleName: string, buffer: Uint8Array, opts?: PutOptions): Promise<SimpleEntry>;
|
|
324
317
|
/** create a folder */
|
|
325
|
-
|
|
318
|
+
putFolder(visibleName: string, opts?: FolderOptions, refresh?: boolean): Promise<SimpleEntry>;
|
|
326
319
|
/**
|
|
327
320
|
* upload an epub
|
|
328
321
|
*
|
|
@@ -332,12 +325,12 @@ export interface RemarkableApi {
|
|
|
332
325
|
* ```
|
|
333
326
|
*
|
|
334
327
|
* @remarks
|
|
335
|
-
* this
|
|
328
|
+
* this uses a simpler api that works even with schema version 4.
|
|
336
329
|
*
|
|
337
330
|
* @param visibleName - the name to show for the uploaded epub
|
|
338
331
|
* @param buffer - the epub contents
|
|
339
332
|
*/
|
|
340
|
-
uploadEpub(visibleName: string, buffer: Uint8Array
|
|
333
|
+
uploadEpub(visibleName: string, buffer: Uint8Array): Promise<SimpleEntry>;
|
|
341
334
|
/**
|
|
342
335
|
* upload a pdf
|
|
343
336
|
*
|
|
@@ -347,12 +340,14 @@ export interface RemarkableApi {
|
|
|
347
340
|
* ```
|
|
348
341
|
*
|
|
349
342
|
* @remarks
|
|
350
|
-
* this
|
|
343
|
+
* this uses a simpler api that works even with schema version 4.
|
|
351
344
|
*
|
|
352
345
|
* @param visibleName - the name to show for the uploaded epub
|
|
353
346
|
* @param buffer - the epub contents
|
|
354
347
|
*/
|
|
355
|
-
uploadPdf(visibleName: string, buffer: Uint8Array
|
|
348
|
+
uploadPdf(visibleName: string, buffer: Uint8Array): Promise<SimpleEntry>;
|
|
349
|
+
/** create a folder using the simple api */
|
|
350
|
+
uploadFolder(visibleName: string): Promise<SimpleEntry>;
|
|
356
351
|
/**
|
|
357
352
|
* update content metadata for a document
|
|
358
353
|
*
|
|
@@ -501,6 +496,12 @@ export interface RemarkableOptions {
|
|
|
501
496
|
* @defaultValue "https://web.eu.tectonic.remarkable.com"
|
|
502
497
|
*/
|
|
503
498
|
syncHost?: string;
|
|
499
|
+
/**
|
|
500
|
+
* the base url for making upload requests
|
|
501
|
+
*
|
|
502
|
+
* @defaultValue "https://internal.cloud.remarkable.com"
|
|
503
|
+
*/
|
|
504
|
+
uploadHost?: string;
|
|
504
505
|
/**
|
|
505
506
|
* the url for making requests using the low-level api
|
|
506
507
|
*
|
|
@@ -535,4 +536,4 @@ export interface RemarkableOptions {
|
|
|
535
536
|
* registered. Create one with {@link register}.
|
|
536
537
|
* @returns an api instance
|
|
537
538
|
*/
|
|
538
|
-
export declare function remarkable(deviceToken: string, { authHost, rawHost, cache, maxCacheSize, }?: RemarkableOptions): Promise<RemarkableApi>;
|
|
539
|
+
export declare function remarkable(deviceToken: string, { authHost, rawHost, uploadHost, cache, maxCacheSize, }?: RemarkableOptions): Promise<RemarkableApi>;
|
package/dist/index.js
CHANGED
|
@@ -60,6 +60,7 @@ import { RawRemarkable, } from "./raw";
|
|
|
60
60
|
export { HashNotFoundError, ValidationError } from "./error";
|
|
61
61
|
const AUTH_HOST = "https://webapp-prod.cloud.remarkable.engineering";
|
|
62
62
|
const RAW_HOST = "https://eu.tectonic.remarkable.com";
|
|
63
|
+
const UPLOAD_HOST = "https://internal.cloud.remarkable.com";
|
|
63
64
|
// ------------ //
|
|
64
65
|
// Request Info //
|
|
65
66
|
// ------------ //
|
|
@@ -130,10 +131,10 @@ class Remarkable {
|
|
|
130
131
|
#cache;
|
|
131
132
|
raw;
|
|
132
133
|
#lastHashGen;
|
|
133
|
-
constructor(userToken, rawHost, cache) {
|
|
134
|
+
constructor(userToken, rawHost, uploadHost, cache) {
|
|
134
135
|
this.#userToken = userToken;
|
|
135
136
|
this.#cache = cache;
|
|
136
|
-
this.raw = new RawRemarkable((method, url, { body, headers } = {}) => this.#authedFetch(url, { method, body, headers }), cache, rawHost);
|
|
137
|
+
this.raw = new RawRemarkable((method, url, { body, headers } = {}) => this.#authedFetch(url, { method, body, headers }), cache, rawHost, uploadHost);
|
|
137
138
|
}
|
|
138
139
|
async #getRootHash(refresh = false) {
|
|
139
140
|
if (refresh || this.#lastHashGen === undefined) {
|
|
@@ -160,7 +161,8 @@ class Remarkable {
|
|
|
160
161
|
Authorization: `Bearer ${this.#userToken}`,
|
|
161
162
|
...headers,
|
|
162
163
|
},
|
|
163
|
-
|
|
164
|
+
// fetch works correctly with uint8 arrays, but is not hinted correctly
|
|
165
|
+
body: body,
|
|
164
166
|
});
|
|
165
167
|
if (!resp.ok) {
|
|
166
168
|
const msg = await resp.text();
|
|
@@ -182,12 +184,12 @@ class Remarkable {
|
|
|
182
184
|
if (metaEnt === undefined) {
|
|
183
185
|
throw new Error(`couldn't find metadata for hash ${hash}`);
|
|
184
186
|
}
|
|
185
|
-
else if (contentEnt === undefined) {
|
|
186
|
-
throw new Error(`couldn't find content for hash ${hash}`);
|
|
187
|
-
}
|
|
188
187
|
const [{ visibleName, lastModified, pinned, parent, lastOpened, new: isNew, source, }, content,] = await Promise.all([
|
|
189
188
|
this.raw.getMetadata(metaEnt.hash),
|
|
190
|
-
|
|
189
|
+
// collections don't always have content, since content only lists tags
|
|
190
|
+
contentEnt === undefined
|
|
191
|
+
? Promise.resolve({ fileType: undefined, tags: undefined })
|
|
192
|
+
: this.raw.getContent(contentEnt.hash),
|
|
191
193
|
]);
|
|
192
194
|
if ("templateVersion" in content) {
|
|
193
195
|
return {
|
|
@@ -373,7 +375,7 @@ class Remarkable {
|
|
|
373
375
|
return await this.#putFile(visibleName, "epub", buffer, opts);
|
|
374
376
|
}
|
|
375
377
|
/** create a folder */
|
|
376
|
-
async
|
|
378
|
+
async putFolder(visibleName, { parent = "" } = {}, refresh = false) {
|
|
377
379
|
if (parent && !idReg.test(parent)) {
|
|
378
380
|
throw new ValidationError(parent, idReg, "parent must be a valid document id");
|
|
379
381
|
}
|
|
@@ -416,12 +418,16 @@ class Remarkable {
|
|
|
416
418
|
return { id, hash: collectionEntry.hash };
|
|
417
419
|
}
|
|
418
420
|
/** upload an epub */
|
|
419
|
-
async uploadEpub(visibleName, buffer
|
|
420
|
-
return await this.
|
|
421
|
+
async uploadEpub(visibleName, buffer) {
|
|
422
|
+
return await this.raw.uploadFile(visibleName, buffer, "application/epub+zip");
|
|
421
423
|
}
|
|
422
424
|
/** upload a pdf */
|
|
423
|
-
async uploadPdf(visibleName, buffer
|
|
424
|
-
return await this.
|
|
425
|
+
async uploadPdf(visibleName, buffer) {
|
|
426
|
+
return await this.raw.uploadFile(visibleName, buffer, "application/pdf");
|
|
427
|
+
}
|
|
428
|
+
/** upload a folder */
|
|
429
|
+
async uploadFolder(visibleName) {
|
|
430
|
+
return await this.raw.uploadFile(visibleName, new Uint8Array(0), "folder");
|
|
425
431
|
}
|
|
426
432
|
/** edit just a content entry */
|
|
427
433
|
async #editContentRaw(id, hash, update) {
|
|
@@ -599,7 +605,7 @@ const cached = values(nullable(string()));
|
|
|
599
605
|
* registered. Create one with {@link register}.
|
|
600
606
|
* @returns an api instance
|
|
601
607
|
*/
|
|
602
|
-
export async function remarkable(deviceToken, { authHost = AUTH_HOST, rawHost = RAW_HOST, cache, maxCacheSize = Infinity, } = {}) {
|
|
608
|
+
export async function remarkable(deviceToken, { authHost = AUTH_HOST, rawHost = RAW_HOST, uploadHost = UPLOAD_HOST, cache, maxCacheSize = Infinity, } = {}) {
|
|
603
609
|
const resp = await fetch(`${authHost}/token/json/2/user/new`, {
|
|
604
610
|
method: "POST",
|
|
605
611
|
headers: {
|
|
@@ -616,7 +622,7 @@ export async function remarkable(deviceToken, { authHost = AUTH_HOST, rawHost =
|
|
|
616
622
|
const cache = maxCacheSize === Infinity
|
|
617
623
|
? new Map(entries)
|
|
618
624
|
: new LruCache(maxCacheSize, entries);
|
|
619
|
-
return new Remarkable(userToken, rawHost, cache);
|
|
625
|
+
return new Remarkable(userToken, rawHost, uploadHost, cache);
|
|
620
626
|
}
|
|
621
627
|
else {
|
|
622
628
|
throw new Error("cache was not a valid cache (json string mapping); your cache must be corrupted somehow. Either initialize remarkable without a cache, or fix its format.");
|
package/dist/raw.d.ts
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
/** request types */
|
|
2
2
|
export type RequestMethod = "POST" | "GET" | "PUT" | "DELETE" | "PATCH" | "OPTIONS";
|
|
3
|
+
/** the supported upload mime types */
|
|
4
|
+
export type UploadMimeType = "application/pdf" | "application/epub+zip" | "folder";
|
|
5
|
+
/** an simple entry without any extra information */
|
|
6
|
+
export interface SimpleEntry {
|
|
7
|
+
/** the document id */
|
|
8
|
+
id: string;
|
|
9
|
+
/** the document hash */
|
|
10
|
+
hash: string;
|
|
11
|
+
}
|
|
3
12
|
/**
|
|
4
13
|
* the low-level entry corresponding to a collection of files
|
|
5
14
|
*
|
|
@@ -518,9 +527,24 @@ export interface RawRemarkableApi {
|
|
|
518
527
|
* @param id - the id of the list to upload - this should be the item id if
|
|
519
528
|
* uploading an item list, or "root" if uploading a new root list.
|
|
520
529
|
* @param entries - the entries to upload
|
|
530
|
+
*
|
|
521
531
|
* @returns the new list entry and a promise to finish the upload
|
|
522
532
|
*/
|
|
523
533
|
putEntries(id: string, entries: RawEntry[]): Promise<[RawListEntry, Promise<void>]>;
|
|
534
|
+
/**
|
|
535
|
+
* upload a file to the reMarkable cloud using the simple api
|
|
536
|
+
*
|
|
537
|
+
* This api is the same as used by the native reMarkable extension and works
|
|
538
|
+
* even if the backend schema version is version 4. Setting mime to "folder"
|
|
539
|
+
* allows folder creation.
|
|
540
|
+
*
|
|
541
|
+
* @param visibleName - the name of the file as it should appear on the reMarkable
|
|
542
|
+
* @param bytes - the bytes of the file to upload
|
|
543
|
+
* @param mime - the mime type of the file to upload
|
|
544
|
+
|
|
545
|
+
* @returns a simple entry with the id and hash of the uploaded file
|
|
546
|
+
*/
|
|
547
|
+
uploadFile(visibleName: string, bytes: Uint8Array, mime: UploadMimeType): Promise<SimpleEntry>;
|
|
524
548
|
/**
|
|
525
549
|
* dump the current cache to a string to preserve between session
|
|
526
550
|
*
|
|
@@ -538,7 +562,7 @@ interface AuthedFetch {
|
|
|
538
562
|
}
|
|
539
563
|
export declare class RawRemarkable implements RawRemarkableApi {
|
|
540
564
|
#private;
|
|
541
|
-
constructor(authedFetch: AuthedFetch, cache: Map<string, string | null>, rawHost: string);
|
|
565
|
+
constructor(authedFetch: AuthedFetch, cache: Map<string, string | null>, rawHost: string, uploadHost: string);
|
|
542
566
|
/** make an authorized request to remarkable */
|
|
543
567
|
getRootHash(): Promise<[string, number]>;
|
|
544
568
|
getHash(hash: string): Promise<Uint8Array>;
|
|
@@ -552,6 +576,7 @@ export declare class RawRemarkable implements RawRemarkableApi {
|
|
|
552
576
|
putContent(id: string, content: Content): Promise<[RawFileEntry, Promise<void>]>;
|
|
553
577
|
putMetadata(id: string, metadata: Metadata): Promise<[RawFileEntry, Promise<void>]>;
|
|
554
578
|
putEntries(id: string, entries: RawEntry[]): Promise<[RawListEntry, Promise<void>]>;
|
|
579
|
+
uploadFile(visibleName: string, bytes: Uint8Array, mime: UploadMimeType): Promise<SimpleEntry>;
|
|
555
580
|
dumpCache(): string;
|
|
556
581
|
clearCache(): void;
|
|
557
582
|
}
|
package/dist/raw.js
CHANGED
|
@@ -151,8 +151,14 @@ const rootHash = properties({
|
|
|
151
151
|
generation: float64(),
|
|
152
152
|
schemaVersion: uint8(),
|
|
153
153
|
}, undefined, true);
|
|
154
|
+
const NativeSimpleEntry = properties({
|
|
155
|
+
docID: string(),
|
|
156
|
+
hash: string(),
|
|
157
|
+
}, undefined, true);
|
|
154
158
|
async function digest(buff) {
|
|
155
|
-
const digest = await crypto.subtle.digest("SHA-256",
|
|
159
|
+
const digest = await crypto.subtle.digest("SHA-256",
|
|
160
|
+
// NOTE this is type hinted wrong, but it does work correctly on a uint8 view
|
|
161
|
+
buff);
|
|
156
162
|
return [...new Uint8Array(digest)]
|
|
157
163
|
.map((x) => x.toString(16).padStart(2, "0"))
|
|
158
164
|
.join("");
|
|
@@ -160,6 +166,7 @@ async function digest(buff) {
|
|
|
160
166
|
export class RawRemarkable {
|
|
161
167
|
#authedFetch;
|
|
162
168
|
#rawHost;
|
|
169
|
+
#uploadHost;
|
|
163
170
|
/**
|
|
164
171
|
* a cache of all hashes we know exist
|
|
165
172
|
*
|
|
@@ -170,10 +177,11 @@ export class RawRemarkable {
|
|
|
170
177
|
* not to write a a cached value again, but we'll still need to read it.
|
|
171
178
|
*/
|
|
172
179
|
#cache;
|
|
173
|
-
constructor(authedFetch, cache, rawHost) {
|
|
180
|
+
constructor(authedFetch, cache, rawHost, uploadHost) {
|
|
174
181
|
this.#authedFetch = authedFetch;
|
|
175
182
|
this.#cache = cache;
|
|
176
183
|
this.#rawHost = rawHost;
|
|
184
|
+
this.#uploadHost = uploadHost;
|
|
177
185
|
}
|
|
178
186
|
/** make an authorized request to remarkable */
|
|
179
187
|
async getRootHash() {
|
|
@@ -418,6 +426,23 @@ export class RawRemarkable {
|
|
|
418
426
|
this.#putFile(hash, `${id}.docSchema`, enc.encode(records.join(""))),
|
|
419
427
|
];
|
|
420
428
|
}
|
|
429
|
+
async uploadFile(visibleName, bytes, mime) {
|
|
430
|
+
const enc = new TextEncoder();
|
|
431
|
+
const meta = fromByteArray(enc.encode(JSON.stringify({ file_name: visibleName })));
|
|
432
|
+
const resp = await this.#authedFetch("POST", `${this.#uploadHost}/doc/v2/files`, {
|
|
433
|
+
body: bytes,
|
|
434
|
+
headers: {
|
|
435
|
+
"Content-Type": mime,
|
|
436
|
+
"rm-meta": meta,
|
|
437
|
+
"rm-source": "RoR-Browser",
|
|
438
|
+
},
|
|
439
|
+
});
|
|
440
|
+
const loaded = (await resp.json());
|
|
441
|
+
if (!NativeSimpleEntry.guardAssert(loaded))
|
|
442
|
+
throw Error("invalid upload response");
|
|
443
|
+
const { docID, hash } = loaded;
|
|
444
|
+
return { id: docID, hash };
|
|
445
|
+
}
|
|
421
446
|
dumpCache() {
|
|
422
447
|
return JSON.stringify(Object.fromEntries(this.#cache));
|
|
423
448
|
}
|