rmapi-js 8.4.0 → 8.5.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 +13 -4
- package/dist/index.d.ts +30 -6
- package/dist/index.js +43 -16
- package/dist/raw.d.ts +7 -9
- package/dist/raw.js +9 -9
- package/dist/rmapi-js.esm.min.js +13 -18
- package/package.json +9 -17
package/README.md
CHANGED
|
@@ -21,19 +21,28 @@ and folders ("collections"). The hash indicates the full current state to manage
|
|
|
21
21
|
## Usage
|
|
22
22
|
|
|
23
23
|
To explore files in the cloud, you need to first register your api and persist
|
|
24
|
-
the token. Then you can use `
|
|
24
|
+
the token. Then you can use `listItems` to explore entries of different file
|
|
25
25
|
collections.
|
|
26
26
|
|
|
27
27
|
```ts
|
|
28
|
-
import { register, remarkable } from "rmapi-js";
|
|
28
|
+
import { auth, register, remarkable, session } from "rmapi-js";
|
|
29
29
|
|
|
30
30
|
const code = "..."; // eight letter code from https://my.remarkable.com/device/desktop/connect
|
|
31
31
|
const token = await register(code);
|
|
32
32
|
// persist token so you don't have to register again
|
|
33
33
|
const api = await remarkable(token);
|
|
34
|
-
const fileEntries = await api.
|
|
34
|
+
const fileEntries = await api.listItems();
|
|
35
|
+
|
|
36
|
+
// In stateless environments, exchange once and reuse.
|
|
37
|
+
const sessionToken = await auth(token);
|
|
38
|
+
const api = session(sessionToken);
|
|
39
|
+
// cache `sessionToken` and reuse it across workers
|
|
35
40
|
```
|
|
36
41
|
|
|
42
|
+
`auth` performs the same network call that `remarkable` does for you internally,
|
|
43
|
+
returning a short-lived session token. `session` is synchronous,
|
|
44
|
+
letting you construct clients from cached tokens without making a network call.
|
|
45
|
+
|
|
37
46
|
To upload an epub or pdf, simply call upload with the appropriate name and buffer.
|
|
38
47
|
|
|
39
48
|
```ts
|
|
@@ -53,7 +62,7 @@ Using these apis is a little riskier since they can potentially result in data l
|
|
|
53
62
|
// upload with custom line height not avilable through reMarkable
|
|
54
63
|
await api.putEpub("name", buffer, { lineHeight: 180 })
|
|
55
64
|
|
|
56
|
-
// fetch an uploaded pdf, using the hash (from
|
|
65
|
+
// fetch an uploaded pdf, using the hash (from listItems)
|
|
57
66
|
const buffer = await api.getEpub(hash)
|
|
58
67
|
```
|
|
59
68
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
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,
|
|
3
|
+
export type { BackgroundFilter, CollectionContent, Content, CPageNumberValue, CPagePage, CPageStringValue, CPages, 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 */
|
|
@@ -482,14 +482,17 @@ export interface RemarkableApi {
|
|
|
482
482
|
*/
|
|
483
483
|
clearCache(): void;
|
|
484
484
|
}
|
|
485
|
-
/**
|
|
486
|
-
export interface
|
|
485
|
+
/** configuration for exchanging a device token */
|
|
486
|
+
export interface AuthOptions {
|
|
487
487
|
/**
|
|
488
488
|
* the url for making authorization requests
|
|
489
489
|
*
|
|
490
490
|
* @defaultValue "https://webapp-prod.cloud.remarkable.engineering"
|
|
491
491
|
*/
|
|
492
492
|
authHost?: string;
|
|
493
|
+
}
|
|
494
|
+
/** options for constructing an api instance from a session token */
|
|
495
|
+
export interface RemarkableSessionOptions {
|
|
493
496
|
/**
|
|
494
497
|
* the url for making synchronization requests
|
|
495
498
|
*
|
|
@@ -526,14 +529,35 @@ export interface RemarkableOptions {
|
|
|
526
529
|
*/
|
|
527
530
|
maxCacheSize?: number;
|
|
528
531
|
}
|
|
532
|
+
/** options for a remarkable instance */
|
|
533
|
+
export interface RemarkableOptions extends AuthOptions, RemarkableSessionOptions {
|
|
534
|
+
}
|
|
535
|
+
/**
|
|
536
|
+
* Exchange a device token for a session token.
|
|
537
|
+
*
|
|
538
|
+
* @param deviceToken - the device token proving this api instance is
|
|
539
|
+
* registered. Create one with {@link register}.
|
|
540
|
+
* @returns the session token returned by the reMarkable service
|
|
541
|
+
*/
|
|
542
|
+
export declare function auth(deviceToken: string, { authHost }?: AuthOptions): Promise<string>;
|
|
543
|
+
/**
|
|
544
|
+
* Create an API instance from an existing session token.
|
|
545
|
+
*
|
|
546
|
+
* If requests start failing, simply recreate the api instance with a freshly
|
|
547
|
+
* fetched session token.
|
|
548
|
+
*
|
|
549
|
+
* @param sessionToken - the session token used for authorization
|
|
550
|
+
* @returns an api instance
|
|
551
|
+
*/
|
|
552
|
+
export declare function session(sessionToken: string, { rawHost, uploadHost, cache, maxCacheSize, }?: RemarkableSessionOptions): RemarkableApi;
|
|
529
553
|
/**
|
|
530
554
|
* create an instance of the api
|
|
531
555
|
*
|
|
532
|
-
* This gets a temporary authentication token with the device token
|
|
533
|
-
*
|
|
556
|
+
* This gets a temporary authentication token with the device token and then
|
|
557
|
+
* constructs the api instance.
|
|
534
558
|
*
|
|
535
559
|
* @param deviceToken - the device token proving this api instance is
|
|
536
560
|
* registered. Create one with {@link register}.
|
|
537
561
|
* @returns an api instance
|
|
538
562
|
*/
|
|
539
|
-
export declare function remarkable(deviceToken: string,
|
|
563
|
+
export declare function remarkable(deviceToken: string, options?: RemarkableOptions): Promise<RemarkableApi>;
|
package/dist/index.js
CHANGED
|
@@ -126,13 +126,13 @@ export async function register(code, { deviceDesc = "browser-chrome", uuid = uui
|
|
|
126
126
|
}
|
|
127
127
|
/** the implementation of that api */
|
|
128
128
|
class Remarkable {
|
|
129
|
-
#
|
|
129
|
+
#sessionToken;
|
|
130
130
|
/** the same cache that underlies the raw api, allowing us to modify it */
|
|
131
131
|
#cache;
|
|
132
132
|
raw;
|
|
133
133
|
#lastHashGen;
|
|
134
|
-
constructor(
|
|
135
|
-
this.#
|
|
134
|
+
constructor(sessionToken, rawHost, uploadHost, cache) {
|
|
135
|
+
this.#sessionToken = sessionToken;
|
|
136
136
|
this.#cache = cache;
|
|
137
137
|
this.raw = new RawRemarkable((method, url, { body, headers } = {}) => this.#authedFetch(url, { method, body, headers }), cache, rawHost, uploadHost);
|
|
138
138
|
}
|
|
@@ -158,7 +158,7 @@ class Remarkable {
|
|
|
158
158
|
const resp = await fetch(url, {
|
|
159
159
|
method,
|
|
160
160
|
headers: {
|
|
161
|
-
Authorization: `Bearer ${this.#
|
|
161
|
+
Authorization: `Bearer ${this.#sessionToken}`,
|
|
162
162
|
...headers,
|
|
163
163
|
},
|
|
164
164
|
// fetch works correctly with uint8 arrays, but is not hinted correctly
|
|
@@ -596,16 +596,13 @@ class Remarkable {
|
|
|
596
596
|
}
|
|
597
597
|
const cached = values(nullable(string()));
|
|
598
598
|
/**
|
|
599
|
-
*
|
|
600
|
-
*
|
|
601
|
-
* This gets a temporary authentication token with the device token. If
|
|
602
|
-
* requests start failing, simply recreate the api instance.
|
|
599
|
+
* Exchange a device token for a session token.
|
|
603
600
|
*
|
|
604
601
|
* @param deviceToken - the device token proving this api instance is
|
|
605
602
|
* registered. Create one with {@link register}.
|
|
606
|
-
* @returns
|
|
603
|
+
* @returns the session token returned by the reMarkable service
|
|
607
604
|
*/
|
|
608
|
-
export async function
|
|
605
|
+
export async function auth(deviceToken, { authHost = AUTH_HOST } = {}) {
|
|
609
606
|
const resp = await fetch(`${authHost}/token/json/2/user/new`, {
|
|
610
607
|
method: "POST",
|
|
611
608
|
headers: {
|
|
@@ -615,16 +612,46 @@ export async function remarkable(deviceToken, { authHost = AUTH_HOST, rawHost =
|
|
|
615
612
|
if (!resp.ok) {
|
|
616
613
|
throw new Error(`couldn't fetch auth token: ${resp.statusText}`);
|
|
617
614
|
}
|
|
618
|
-
|
|
615
|
+
return await resp.text();
|
|
616
|
+
}
|
|
617
|
+
/**
|
|
618
|
+
* Create an API instance from an existing session token.
|
|
619
|
+
*
|
|
620
|
+
* If requests start failing, simply recreate the api instance with a freshly
|
|
621
|
+
* fetched session token.
|
|
622
|
+
*
|
|
623
|
+
* @param sessionToken - the session token used for authorization
|
|
624
|
+
* @returns an api instance
|
|
625
|
+
*/
|
|
626
|
+
export function session(sessionToken, { rawHost = RAW_HOST, uploadHost = UPLOAD_HOST, cache, maxCacheSize = Infinity, } = {}) {
|
|
619
627
|
const initCache = JSON.parse(cache ?? "{}");
|
|
620
628
|
if (cached.guard(initCache)) {
|
|
621
629
|
const entries = Object.entries(initCache);
|
|
622
|
-
const
|
|
630
|
+
const cacheMap = maxCacheSize === Infinity
|
|
623
631
|
? new Map(entries)
|
|
624
632
|
: new LruCache(maxCacheSize, entries);
|
|
625
|
-
return new Remarkable(
|
|
626
|
-
}
|
|
627
|
-
else {
|
|
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.");
|
|
633
|
+
return new Remarkable(sessionToken, rawHost, uploadHost, cacheMap);
|
|
629
634
|
}
|
|
635
|
+
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.");
|
|
636
|
+
}
|
|
637
|
+
/**
|
|
638
|
+
* create an instance of the api
|
|
639
|
+
*
|
|
640
|
+
* This gets a temporary authentication token with the device token and then
|
|
641
|
+
* constructs the api instance.
|
|
642
|
+
*
|
|
643
|
+
* @param deviceToken - the device token proving this api instance is
|
|
644
|
+
* registered. Create one with {@link register}.
|
|
645
|
+
* @returns an api instance
|
|
646
|
+
*/
|
|
647
|
+
export async function remarkable(deviceToken, options = {}) {
|
|
648
|
+
const { authHost, rawHost, uploadHost, cache, maxCacheSize, syncHost } = options ?? {};
|
|
649
|
+
const sessionToken = await auth(deviceToken, { authHost });
|
|
650
|
+
return session(sessionToken, {
|
|
651
|
+
rawHost,
|
|
652
|
+
uploadHost,
|
|
653
|
+
cache,
|
|
654
|
+
maxCacheSize,
|
|
655
|
+
syncHost,
|
|
656
|
+
});
|
|
630
657
|
}
|
package/dist/raw.d.ts
CHANGED
|
@@ -61,7 +61,7 @@ export interface PageTag extends Tag {
|
|
|
61
61
|
/** all supported document orientations */
|
|
62
62
|
export type Orientation = "portrait" | "landscape";
|
|
63
63
|
/** all supported text alignments */
|
|
64
|
-
export type TextAlignment = "justify" | "left";
|
|
64
|
+
export type TextAlignment = "" | "justify" | "left";
|
|
65
65
|
/** types of zoom modes for documents, applies primarily to pdf files */
|
|
66
66
|
export type ZoomMode = "bestFit" | "customFit" | "fitToHeight" | "fitToWidth";
|
|
67
67
|
/**
|
|
@@ -202,8 +202,8 @@ export interface DocumentContent {
|
|
|
202
202
|
pageCount: number;
|
|
203
203
|
/** the page tags for the document */
|
|
204
204
|
pageTags?: PageTag[];
|
|
205
|
-
/** a list of the ids of each page in the document */
|
|
206
|
-
pages?: string[];
|
|
205
|
+
/** a list of the ids of each page in the document, or null when never opened */
|
|
206
|
+
pages?: string[] | null;
|
|
207
207
|
/** a mapping from page number to page id in pages */
|
|
208
208
|
redirectionPageMap?: number[];
|
|
209
209
|
/** ostensibly the size in bytes of the file, but this differs from other measurements */
|
|
@@ -554,12 +554,10 @@ export interface RawRemarkableApi {
|
|
|
554
554
|
/** completely clear the cache */
|
|
555
555
|
clearCache(): void;
|
|
556
556
|
}
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
}): Promise<Response>;
|
|
562
|
-
}
|
|
557
|
+
type AuthedFetch = (method: RequestMethod, url: string, init?: {
|
|
558
|
+
body?: string | Uint8Array;
|
|
559
|
+
headers?: Record<string, string>;
|
|
560
|
+
}) => Promise<Response>;
|
|
563
561
|
export declare class RawRemarkable implements RawRemarkableApi {
|
|
564
562
|
#private;
|
|
565
563
|
constructor(authedFetch: AuthedFetch, cache: Map<string, string | null>, rawHost: string, uploadHost: string);
|
package/dist/raw.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { fromByteArray } from "base64-js";
|
|
2
2
|
import CRC32C from "crc-32/crc32c";
|
|
3
|
-
import { boolean, elements, empty, enumeration, float64, int32, properties, string, timestamp,
|
|
3
|
+
import { boolean, elements, empty, enumeration, float64, int32, nullable, properties, string, timestamp, uint8, uint32, values, } from "jtd-ts";
|
|
4
4
|
import { ValidationError } from "./error.js";
|
|
5
5
|
const hashReg = /^[0-9a-f]{64}$/;
|
|
6
6
|
const tag = properties({
|
|
@@ -74,7 +74,7 @@ const documentContent = properties({
|
|
|
74
74
|
orientation: enumeration("portrait", "landscape"),
|
|
75
75
|
pageCount: uint32(),
|
|
76
76
|
sizeInBytes: string(),
|
|
77
|
-
textAlignment: enumeration("justify", "left"),
|
|
77
|
+
textAlignment: enumeration("", "justify", "left"),
|
|
78
78
|
textScale: float64(),
|
|
79
79
|
}, {
|
|
80
80
|
cPages,
|
|
@@ -90,10 +90,10 @@ const documentContent = properties({
|
|
|
90
90
|
count: uint32(),
|
|
91
91
|
timestamp: float64(),
|
|
92
92
|
}, undefined, true),
|
|
93
|
-
lastOpenedPage:
|
|
93
|
+
lastOpenedPage: int32(),
|
|
94
94
|
margins: uint32(),
|
|
95
95
|
originalPageCount: int32(),
|
|
96
|
-
pages: elements(string()),
|
|
96
|
+
pages: nullable(elements(string())),
|
|
97
97
|
pageTags: elements(pageTag),
|
|
98
98
|
redirectionPageMap: elements(int32()),
|
|
99
99
|
tags: elements(tag),
|
|
@@ -134,7 +134,7 @@ const metadata = properties({
|
|
|
134
134
|
visibleName: string(),
|
|
135
135
|
}, {
|
|
136
136
|
lastOpened: string(),
|
|
137
|
-
lastOpenedPage:
|
|
137
|
+
lastOpenedPage: int32(),
|
|
138
138
|
createdTime: string(),
|
|
139
139
|
deleted: boolean(),
|
|
140
140
|
metadatamodified: boolean(),
|
|
@@ -243,7 +243,7 @@ export class RawRemarkable {
|
|
|
243
243
|
async getEntries(hash) {
|
|
244
244
|
const rawFile = await this.getText(hash);
|
|
245
245
|
const [version, ...rest] = rawFile.slice(0, -1).split("\n");
|
|
246
|
-
if (version
|
|
246
|
+
if (version !== "3") {
|
|
247
247
|
throw new Error(`schema version ${version} not supported`);
|
|
248
248
|
}
|
|
249
249
|
else {
|
|
@@ -261,8 +261,8 @@ export class RawRemarkable {
|
|
|
261
261
|
hash,
|
|
262
262
|
type: 80000000,
|
|
263
263
|
id,
|
|
264
|
-
subfiles: parseInt(subfiles),
|
|
265
|
-
size: parseInt(size),
|
|
264
|
+
subfiles: parseInt(subfiles, 10),
|
|
265
|
+
size: parseInt(size, 10),
|
|
266
266
|
};
|
|
267
267
|
}
|
|
268
268
|
else if (type === "0" && subfiles === "0") {
|
|
@@ -271,7 +271,7 @@ export class RawRemarkable {
|
|
|
271
271
|
type: 0,
|
|
272
272
|
id,
|
|
273
273
|
subfiles: 0,
|
|
274
|
-
size: parseInt(size),
|
|
274
|
+
size: parseInt(size, 10),
|
|
275
275
|
};
|
|
276
276
|
}
|
|
277
277
|
else {
|