rmapi-js 10.2.0 → 11.1.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/devices.d.ts +22 -0
- package/dist/devices.js +20 -0
- package/dist/error.d.ts +14 -0
- package/dist/error.js +21 -0
- package/dist/index.d.ts +35 -0
- package/dist/index.js +8 -5
- package/dist/lru.d.ts +8 -0
- package/dist/lru.js +64 -0
- package/dist/raw.d.ts +23 -19
- package/dist/raw.js +0 -3
- package/dist/rmapi-js.esm.min.js +9 -10
- package/dist/utils.d.ts +1 -0
- package/dist/utils.js +10 -0
- package/package.json +11 -5
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/** a reMarkable device display */
|
|
2
|
+
export interface DeviceScreen {
|
|
3
|
+
/** the marketing name */
|
|
4
|
+
name: string;
|
|
5
|
+
/** native portrait width in pixels */
|
|
6
|
+
width: number;
|
|
7
|
+
/** native portrait height in pixels */
|
|
8
|
+
height: number;
|
|
9
|
+
/** display density in dots per inch */
|
|
10
|
+
dpi: number;
|
|
11
|
+
}
|
|
12
|
+
/** the model number of a known reMarkable device */
|
|
13
|
+
export type DeviceModel = "RM100" | "RM110" | "RM02A" | "RM03A" | "RM102";
|
|
14
|
+
/**
|
|
15
|
+
* display specs for known reMarkable devices, keyed by model number
|
|
16
|
+
*
|
|
17
|
+
* These feed the `customFit` zoom math: `customZoomPageWidth`/`customZoomPageHeight`
|
|
18
|
+
* are the source page in device pixels (`pagePt * dpi / 72`), and `width`/`height`
|
|
19
|
+
* give the screen aspect. Every model is 3:4 (0.75) except the Paper Pro Move,
|
|
20
|
+
* which is 9:16.
|
|
21
|
+
*/
|
|
22
|
+
export declare const deviceScreens: Record<DeviceModel, DeviceScreen>;
|
package/dist/devices.js
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* display specs for known reMarkable devices, keyed by model number
|
|
3
|
+
*
|
|
4
|
+
* These feed the `customFit` zoom math: `customZoomPageWidth`/`customZoomPageHeight`
|
|
5
|
+
* are the source page in device pixels (`pagePt * dpi / 72`), and `width`/`height`
|
|
6
|
+
* give the screen aspect. Every model is 3:4 (0.75) except the Paper Pro Move,
|
|
7
|
+
* which is 9:16.
|
|
8
|
+
*/
|
|
9
|
+
export const deviceScreens = {
|
|
10
|
+
RM100: { name: "reMarkable 1", width: 1404, height: 1872, dpi: 226 },
|
|
11
|
+
RM110: { name: "reMarkable 2", width: 1404, height: 1872, dpi: 226 },
|
|
12
|
+
RM02A: { name: "reMarkable Paper Pro", width: 1620, height: 2160, dpi: 229 },
|
|
13
|
+
RM03A: {
|
|
14
|
+
name: "reMarkable Paper Pro Move",
|
|
15
|
+
width: 954,
|
|
16
|
+
height: 1696,
|
|
17
|
+
dpi: 264,
|
|
18
|
+
},
|
|
19
|
+
RM102: { name: "reMarkable Paper Pure", width: 1404, height: 1872, dpi: 226 },
|
|
20
|
+
};
|
package/dist/error.d.ts
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/** an error that results from a failed request */
|
|
2
|
+
export declare class ValidationError extends Error {
|
|
3
|
+
/** the response status number */
|
|
4
|
+
readonly field: string;
|
|
5
|
+
/** the response status text */
|
|
6
|
+
readonly regex: RegExp;
|
|
7
|
+
constructor(field: string, regex: RegExp, message: string);
|
|
8
|
+
}
|
|
9
|
+
/** an error that results while supplying a hash not found in the entries of the root hash */
|
|
10
|
+
export declare class HashNotFoundError extends Error {
|
|
11
|
+
/** the hash that couldn't be found */
|
|
12
|
+
readonly hash: string;
|
|
13
|
+
constructor(hash: string);
|
|
14
|
+
}
|
package/dist/error.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/** an error that results from a failed request */
|
|
2
|
+
export class ValidationError extends Error {
|
|
3
|
+
/** the response status number */
|
|
4
|
+
field;
|
|
5
|
+
/** the response status text */
|
|
6
|
+
regex;
|
|
7
|
+
constructor(field, regex, message) {
|
|
8
|
+
super(message);
|
|
9
|
+
this.field = field;
|
|
10
|
+
this.regex = regex;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
/** an error that results while supplying a hash not found in the entries of the root hash */
|
|
14
|
+
export class HashNotFoundError extends Error {
|
|
15
|
+
/** the hash that couldn't be found */
|
|
16
|
+
hash;
|
|
17
|
+
constructor(hash) {
|
|
18
|
+
super(`'${hash}' not found in the root hash`);
|
|
19
|
+
this.hash = hash;
|
|
20
|
+
}
|
|
21
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
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.js";
|
|
2
|
+
export { type DeviceModel, type DeviceScreen, deviceScreens, } from "./devices.js";
|
|
2
3
|
export { HashNotFoundError, ValidationError } from "./error.js";
|
|
3
4
|
export type { BackgroundFilter, CollectionContent, Content, CPageNumberValue, CPagePage, CPageStringValue, CPages, CPageUUID, DocumentContent, DocumentMetadata, Entries, FileType, KeyboardMetadata, LegacyCollectionContent, LegacyDocumentContent, Metadata, Orientation, PageTag, RawEntry, RawRemarkableApi, SchemaVersion, SimpleEntry, Tag, TemplateContent, TextAlignment, UploadMimeType, ZoomMode, } from "./raw.js";
|
|
4
5
|
/** common properties shared by collections and documents */
|
|
@@ -162,6 +163,18 @@ export interface PutOptions {
|
|
|
162
163
|
zoomMode?: ZoomMode;
|
|
163
164
|
/** the contrast filter setting */
|
|
164
165
|
viewBackgroundFilter?: BackgroundFilter;
|
|
166
|
+
/** the custom zoom scale, applied when zoomMode is "customFit" */
|
|
167
|
+
customZoomScale?: number;
|
|
168
|
+
/** the horizontal center offset for customFit zoom */
|
|
169
|
+
customZoomCenterX?: number;
|
|
170
|
+
/** the vertical center offset for customFit zoom */
|
|
171
|
+
customZoomCenterY?: number;
|
|
172
|
+
/** the rendered page width in pixels, the unit customFit centers use */
|
|
173
|
+
customZoomPageWidth?: number;
|
|
174
|
+
/** the rendered page height in pixels, the unit customFit centers use */
|
|
175
|
+
customZoomPageHeight?: number;
|
|
176
|
+
/** the orientation the customFit zoom was set in */
|
|
177
|
+
customZoomOrientation?: Orientation;
|
|
165
178
|
/**
|
|
166
179
|
* whether to refresh current file structure before putting
|
|
167
180
|
*
|
|
@@ -296,6 +309,28 @@ export interface RemarkableApi {
|
|
|
296
309
|
* doesn't match the current server generation, requiring you to retry until
|
|
297
310
|
* it works.
|
|
298
311
|
*
|
|
312
|
+
* @remarks
|
|
313
|
+
* When `zoomMode` is `"customFit"` the `customZoom*` fields describe the view,
|
|
314
|
+
* all in the source page's device pixels: `customZoomPageWidth` and
|
|
315
|
+
* `customZoomPageHeight` are the page dimensions scaled by the device dpi
|
|
316
|
+
* (`pagePt * dpi / 72`, see {@link deviceScreens | `deviceScreens`}), and the
|
|
317
|
+
* centers are in those pixels.
|
|
318
|
+
*
|
|
319
|
+
* The view always has the device's aspect ratio — you control its height and
|
|
320
|
+
* position, not its shape. `customZoomScale` is a fit-to-height zoom: at `1`
|
|
321
|
+
* the page height fills the screen, and the linear magnification is
|
|
322
|
+
* `customZoomScale` squared. `customZoomCenterX` offsets the center of the
|
|
323
|
+
* view horizontally from the page center, and `customZoomCenterY` is the
|
|
324
|
+
* absolute distance of the center down from the top of the page; the view's
|
|
325
|
+
* width follows from its height and the device aspect ratio.
|
|
326
|
+
*
|
|
327
|
+
* The fields are a single document-wide setting, but `customZoomCenterY` is
|
|
328
|
+
* applied against each page's own rendered height. On a page rendered taller
|
|
329
|
+
* than `customZoomPageHeight` that distance is a smaller fraction of the page,
|
|
330
|
+
* so the view sits higher and cuts off the bottom; on a shorter page it sits
|
|
331
|
+
* lower and cuts off the top. `customZoomScale` (a ratio) and
|
|
332
|
+
* `customZoomCenterX` (an offset from center) do not shift with page size.
|
|
333
|
+
*
|
|
299
334
|
* @param visibleName - the name to display on the reMarkable
|
|
300
335
|
* @param buffer - the raw pdf
|
|
301
336
|
* @param opts - put options
|
package/dist/index.js
CHANGED
|
@@ -57,13 +57,11 @@ import { z } from "zod";
|
|
|
57
57
|
import { HashNotFoundError, ValidationError } from "./error.js";
|
|
58
58
|
import { LruCache } from "./lru.js";
|
|
59
59
|
import { RawRemarkable, } from "./raw.js";
|
|
60
|
+
export { deviceScreens, } from "./devices.js";
|
|
60
61
|
export { HashNotFoundError, ValidationError } from "./error.js";
|
|
61
62
|
const AUTH_HOST = "https://webapp-prod.cloud.remarkable.engineering";
|
|
62
63
|
const RAW_HOST = "https://eu.tectonic.remarkable.com";
|
|
63
64
|
const UPLOAD_HOST = "https://internal.cloud.remarkable.com";
|
|
64
|
-
// ------------ //
|
|
65
|
-
// Request Info //
|
|
66
|
-
// ------------ //
|
|
67
65
|
// The section has all the types that are stored in the remarkable cloud.
|
|
68
66
|
const idReg = /^([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}||trash)$/;
|
|
69
67
|
/** An error that gets thrown when the backend while trying to update
|
|
@@ -295,7 +293,7 @@ class Remarkable {
|
|
|
295
293
|
}
|
|
296
294
|
return zip.generateAsync({ type: "uint8array" });
|
|
297
295
|
}
|
|
298
|
-
async #putFile(visibleName, fileType, buffer, { refresh, parent = "", pinned = false, zoomMode = "bestFit", viewBackgroundFilter, textScale = 1, textAlignment = "justify", fontName = "", coverPageNumber = -1, authors, title, publicationDate, publisher, extraMetadata = {}, lineHeight = -1, margins = 125, orientation = "portrait", tags, }) {
|
|
296
|
+
async #putFile(visibleName, fileType, buffer, { refresh, parent = "", pinned = false, zoomMode = "bestFit", viewBackgroundFilter, textScale = 1, textAlignment = "justify", fontName = "", coverPageNumber = -1, authors, title, publicationDate, publisher, extraMetadata = {}, lineHeight = -1, margins = 125, orientation = "portrait", tags, customZoomScale, customZoomCenterX, customZoomCenterY, customZoomPageWidth, customZoomPageHeight, customZoomOrientation, }) {
|
|
299
297
|
if (parent && !idReg.test(parent)) {
|
|
300
298
|
throw new ValidationError(parent, idReg, "parent must be a valid document id");
|
|
301
299
|
}
|
|
@@ -325,6 +323,12 @@ class Remarkable {
|
|
|
325
323
|
textAlignment,
|
|
326
324
|
textScale,
|
|
327
325
|
zoomMode,
|
|
326
|
+
customZoomScale,
|
|
327
|
+
customZoomCenterX,
|
|
328
|
+
customZoomCenterY,
|
|
329
|
+
customZoomPageWidth,
|
|
330
|
+
customZoomPageHeight,
|
|
331
|
+
customZoomOrientation,
|
|
328
332
|
viewBackgroundFilter,
|
|
329
333
|
// NOTE for some reason we need to "fake" the number of pages at 1, and
|
|
330
334
|
// create "valid" output for that
|
|
@@ -339,7 +343,6 @@ class Remarkable {
|
|
|
339
343
|
const [[contentEntry, uploadContent], [metadataEntry, uploadMetadata], [pagedataEntry, uploadPagedata], [fileEntry, uploadFile], [rootHash, generation, schemaVersion],] = await Promise.all([
|
|
340
344
|
this.raw.putContent(`${id}.content`, content),
|
|
341
345
|
this.raw.putMetadata(`${id}.metadata`, metadata),
|
|
342
|
-
// eslint-disable-next-line spellcheck/spell-checker
|
|
343
346
|
this.raw.putText(`${id}.pagedata`, "\n"),
|
|
344
347
|
this.raw.putFile(`${id}.${fileType}`, buffer),
|
|
345
348
|
this.#getRootHash(refresh),
|
package/dist/lru.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare class LruCache extends Map<string, string | null> {
|
|
2
|
+
#private;
|
|
3
|
+
constructor(maxSize: number, entries?: Iterable<[string, string | null]>);
|
|
4
|
+
get(key: string): string | null | undefined;
|
|
5
|
+
set(key: string, value: string | null): this;
|
|
6
|
+
delete(key: string): boolean;
|
|
7
|
+
clear(): void;
|
|
8
|
+
}
|
package/dist/lru.js
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
export class LruCache extends Map {
|
|
2
|
+
#maxSize;
|
|
3
|
+
#currentSize = 0;
|
|
4
|
+
constructor(maxSize, entries = []) {
|
|
5
|
+
super();
|
|
6
|
+
this.#maxSize = maxSize;
|
|
7
|
+
for (const [key, value] of entries) {
|
|
8
|
+
this.set(key, value);
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
get(key) {
|
|
12
|
+
const res = super.get(key);
|
|
13
|
+
if (res !== undefined) {
|
|
14
|
+
// update order so key is most recent
|
|
15
|
+
super.delete(key);
|
|
16
|
+
super.set(key, res);
|
|
17
|
+
}
|
|
18
|
+
return res;
|
|
19
|
+
}
|
|
20
|
+
set(key, value) {
|
|
21
|
+
const existing = super.get(key);
|
|
22
|
+
if (existing === undefined) {
|
|
23
|
+
this.#currentSize += key.length; // adding a new key
|
|
24
|
+
}
|
|
25
|
+
else if (existing !== null) {
|
|
26
|
+
this.#currentSize -= existing.length; // removing old value
|
|
27
|
+
}
|
|
28
|
+
if (value !== null) {
|
|
29
|
+
this.#currentSize += value.length;
|
|
30
|
+
}
|
|
31
|
+
// delete existing value
|
|
32
|
+
super.delete(key);
|
|
33
|
+
// evict down to desired size
|
|
34
|
+
let entry;
|
|
35
|
+
while (this.#currentSize > this.#maxSize &&
|
|
36
|
+
(entry = this.entries().next().value)) {
|
|
37
|
+
const [oldestKey, oldestValue] = entry;
|
|
38
|
+
super.delete(oldestKey);
|
|
39
|
+
this.#currentSize -= oldestKey.length;
|
|
40
|
+
if (oldestValue !== null) {
|
|
41
|
+
this.#currentSize -= oldestValue.length;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
// finally insert new key and return
|
|
45
|
+
super.set(key, value);
|
|
46
|
+
return this;
|
|
47
|
+
}
|
|
48
|
+
delete(key) {
|
|
49
|
+
const value = super.get(key);
|
|
50
|
+
if (value === undefined) {
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
super.delete(key);
|
|
54
|
+
if (value !== null) {
|
|
55
|
+
this.#currentSize -= value.length;
|
|
56
|
+
}
|
|
57
|
+
this.#currentSize -= key.length;
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
clear() {
|
|
61
|
+
super.clear();
|
|
62
|
+
this.#currentSize = 0;
|
|
63
|
+
}
|
|
64
|
+
}
|
package/dist/raw.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import "core-js/proposals/array-buffer-base64";
|
|
2
1
|
/** request types */
|
|
3
2
|
export type RequestMethod = "POST" | "GET" | "PUT" | "DELETE" | "PATCH" | "OPTIONS";
|
|
4
3
|
/** the supported upload mime types */
|
|
@@ -227,38 +226,43 @@ export interface CommonDocumentContent {
|
|
|
227
226
|
*/
|
|
228
227
|
textScale: number;
|
|
229
228
|
/**
|
|
230
|
-
* the center of
|
|
229
|
+
* the horizontal center of a customFit zoom
|
|
231
230
|
*
|
|
232
|
-
*
|
|
233
|
-
*
|
|
234
|
-
*
|
|
235
|
-
*
|
|
231
|
+
* An offset in device pixels from the horizontal center of the page (0 =
|
|
232
|
+
* centered, negative = left, positive = right). This and
|
|
233
|
+
* {@link customZoomCenterY} are in the page's own frame, so device
|
|
234
|
+
* orientation does not affect them.
|
|
236
235
|
*/
|
|
237
236
|
customZoomCenterX?: number;
|
|
238
237
|
/**
|
|
239
|
-
* the center of
|
|
238
|
+
* the vertical center of a customFit zoom
|
|
240
239
|
*
|
|
241
|
-
*
|
|
242
|
-
*
|
|
243
|
-
* The units are relative to the document pixels, but it's not sure how the
|
|
244
|
-
* document size is calculated.
|
|
240
|
+
* An absolute distance in device pixels from the top of the page (negative =
|
|
241
|
+
* up, positive = down); centering is half the page's rendered height.
|
|
245
242
|
*/
|
|
246
243
|
customZoomCenterY?: number;
|
|
247
|
-
/**
|
|
244
|
+
/** the orientation the customFit zoom was set in */
|
|
248
245
|
customZoomOrientation?: Orientation;
|
|
249
|
-
/**
|
|
246
|
+
/**
|
|
247
|
+
* the rendered height of the pdf page, in device pixels
|
|
248
|
+
*
|
|
249
|
+
* Computed from the pdf page height in points and the device dpi as
|
|
250
|
+
* `heightPt * dpi / 72`; the dpi depends on the model (see
|
|
251
|
+
* {@link deviceScreens | `deviceScreens`}).
|
|
252
|
+
*/
|
|
250
253
|
customZoomPageHeight?: number;
|
|
251
|
-
/**
|
|
254
|
+
/** the rendered width of the pdf page, in device pixels */
|
|
252
255
|
customZoomPageWidth?: number;
|
|
253
256
|
/**
|
|
254
|
-
* the scale for customFit
|
|
257
|
+
* the scale for a customFit zoom
|
|
255
258
|
*
|
|
256
|
-
*
|
|
257
|
-
*
|
|
258
|
-
*
|
|
259
|
+
* Calibrated on the page's fit-to-height: at 1 the rendered page height fills
|
|
260
|
+
* the screen and the linear magnification is customZoomScale squared. 1
|
|
261
|
+
* indicates no zoom; reMarkable generally allows 0.5 to 5, but values outside
|
|
262
|
+
* that bound are still supported.
|
|
259
263
|
*/
|
|
260
264
|
customZoomScale?: number;
|
|
261
|
-
/**
|
|
265
|
+
/** the zoom mode; customFit applies the customZoom* fields, the rest auto-fit */
|
|
262
266
|
zoomMode?: ZoomMode;
|
|
263
267
|
/** [speculative] a transform matrix, a. la. css matrix transform */
|
|
264
268
|
transform?: Partial<Record<`m${"1" | "2" | "3"}${"1" | "2" | "3"}`, number>>;
|
package/dist/raw.js
CHANGED
|
@@ -2,7 +2,6 @@ import CRC32C from "crc-32/crc32c";
|
|
|
2
2
|
import { z } from "zod";
|
|
3
3
|
import { ValidationError } from "./error.js";
|
|
4
4
|
import { concatArrays } from "./utils.js";
|
|
5
|
-
import "core-js/proposals/array-buffer-base64";
|
|
6
5
|
const hashReg = /^[0-9a-f]{64}$/;
|
|
7
6
|
const tag = z
|
|
8
7
|
.object({
|
|
@@ -127,7 +126,6 @@ const documentContentOptional = {
|
|
|
127
126
|
})
|
|
128
127
|
.passthrough()
|
|
129
128
|
.optional(),
|
|
130
|
-
// eslint-disable-next-line spellcheck/spell-checker
|
|
131
129
|
viewBackgroundFilter: z.enum(["off", "fullpage"]).optional(),
|
|
132
130
|
zoomMode: z
|
|
133
131
|
.enum(["bestFit", "customFit", "fitToHeight", "fitToWidth"])
|
|
@@ -380,7 +378,6 @@ export class RawRemarkable {
|
|
|
380
378
|
body: bytes,
|
|
381
379
|
headers: {
|
|
382
380
|
"rm-filename": fileName,
|
|
383
|
-
// eslint-disable-next-line spellcheck/spell-checker
|
|
384
381
|
"x-goog-hash": `crc32c=${crcHash}`,
|
|
385
382
|
},
|
|
386
383
|
});
|