rmapi-js 14.0.0 → 14.2.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 +14 -0
- package/dist/index.d.ts +131 -0
- package/dist/index.js +322 -19
- package/dist/raw.d.ts +15 -1
- package/dist/raw.js +49 -33
- package/dist/rmapi-js.esm.min.js +53 -44
- package/package.json +4 -4
package/dist/raw.js
CHANGED
|
@@ -66,14 +66,14 @@ const tag = z
|
|
|
66
66
|
name: z.string(),
|
|
67
67
|
timestamp: z.number(),
|
|
68
68
|
})
|
|
69
|
-
.
|
|
69
|
+
.loose();
|
|
70
70
|
const pageTag = z
|
|
71
71
|
.object({
|
|
72
72
|
name: z.string(),
|
|
73
73
|
pageId: z.string(),
|
|
74
74
|
timestamp: z.number(),
|
|
75
75
|
})
|
|
76
|
-
.
|
|
76
|
+
.loose();
|
|
77
77
|
const documentMetadata = z
|
|
78
78
|
.object({
|
|
79
79
|
authors: z.array(z.string()).optional(),
|
|
@@ -81,53 +81,51 @@ const documentMetadata = z
|
|
|
81
81
|
publicationDate: z.string().optional(),
|
|
82
82
|
publisher: z.string().optional(),
|
|
83
83
|
})
|
|
84
|
-
.
|
|
84
|
+
.loose();
|
|
85
85
|
const cPagePage = z
|
|
86
86
|
.object({
|
|
87
87
|
id: z.string(),
|
|
88
|
-
idx: z.object({ timestamp: z.string(), value: z.string() }).
|
|
88
|
+
idx: z.object({ timestamp: z.string(), value: z.string() }).loose(),
|
|
89
89
|
template: z
|
|
90
90
|
.object({ timestamp: z.string(), value: z.string() })
|
|
91
|
-
.
|
|
91
|
+
.loose()
|
|
92
92
|
.optional(),
|
|
93
93
|
redir: z
|
|
94
94
|
.object({ timestamp: z.string(), value: z.number().int() })
|
|
95
|
-
.
|
|
95
|
+
.loose()
|
|
96
96
|
.optional(),
|
|
97
97
|
scrollTime: z
|
|
98
98
|
.object({
|
|
99
99
|
timestamp: z.string(),
|
|
100
|
-
value: z.
|
|
100
|
+
value: z.iso.datetime({ offset: true }),
|
|
101
101
|
})
|
|
102
|
-
.
|
|
102
|
+
.loose()
|
|
103
103
|
.optional(),
|
|
104
104
|
verticalScroll: z
|
|
105
105
|
.object({ timestamp: z.string(), value: z.number() })
|
|
106
|
-
.
|
|
106
|
+
.loose()
|
|
107
107
|
.optional(),
|
|
108
108
|
deleted: z
|
|
109
109
|
.object({ timestamp: z.string(), value: z.number().int() })
|
|
110
|
-
.
|
|
110
|
+
.loose()
|
|
111
111
|
.optional(),
|
|
112
112
|
modifed: z.string().optional(),
|
|
113
113
|
})
|
|
114
|
-
.
|
|
114
|
+
.loose();
|
|
115
115
|
const cPages = z
|
|
116
116
|
.object({
|
|
117
|
-
lastOpened: z
|
|
118
|
-
.object({ timestamp: z.string(), value: z.string() })
|
|
119
|
-
.passthrough(),
|
|
117
|
+
lastOpened: z.object({ timestamp: z.string(), value: z.string() }).loose(),
|
|
120
118
|
original: z
|
|
121
119
|
.object({ timestamp: z.string(), value: z.number().int() })
|
|
122
|
-
.
|
|
120
|
+
.loose(),
|
|
123
121
|
pages: z.array(cPagePage),
|
|
124
122
|
uuids: z
|
|
125
123
|
.array(z
|
|
126
124
|
.object({ first: z.string(), second: z.number().int().nonnegative() })
|
|
127
|
-
.
|
|
125
|
+
.loose())
|
|
128
126
|
.nullable(),
|
|
129
127
|
})
|
|
130
|
-
.
|
|
128
|
+
.loose();
|
|
131
129
|
const collectionContent = z
|
|
132
130
|
.object({
|
|
133
131
|
tags: z.array(tag).optional(),
|
|
@@ -162,7 +160,7 @@ const documentContentOptional = {
|
|
|
162
160
|
formatVersion: z.number().int().nonnegative().optional(),
|
|
163
161
|
keyboardMetadata: z
|
|
164
162
|
.object({ count: z.number().int().nonnegative(), timestamp: z.number() })
|
|
165
|
-
.
|
|
163
|
+
.loose()
|
|
166
164
|
.optional(),
|
|
167
165
|
lastOpenedPage: z.number().int().optional(),
|
|
168
166
|
margins: z.number().int().nonnegative().optional(),
|
|
@@ -183,7 +181,7 @@ const documentContentOptional = {
|
|
|
183
181
|
m32: z.number().optional(),
|
|
184
182
|
m33: z.number().optional(),
|
|
185
183
|
})
|
|
186
|
-
.
|
|
184
|
+
.loose()
|
|
187
185
|
.optional(),
|
|
188
186
|
viewBackgroundFilter: z.enum(["off", "fullpage"]).optional(),
|
|
189
187
|
zoomMode: z
|
|
@@ -192,13 +190,13 @@ const documentContentOptional = {
|
|
|
192
190
|
};
|
|
193
191
|
const commonDocumentContent = z
|
|
194
192
|
.object({ ...documentContentRequired, ...documentContentOptional })
|
|
195
|
-
.
|
|
193
|
+
.loose();
|
|
196
194
|
const documentContent = commonDocumentContent
|
|
197
195
|
.extend({ tags: z.array(tag).optional() })
|
|
198
|
-
.
|
|
196
|
+
.loose();
|
|
199
197
|
const legacyDocumentContent = commonDocumentContent
|
|
200
198
|
.extend({ tags: z.array(z.string()).optional() })
|
|
201
|
-
.
|
|
199
|
+
.loose();
|
|
202
200
|
const templateContent = z
|
|
203
201
|
.object({
|
|
204
202
|
id: z.string().optional(),
|
|
@@ -216,7 +214,7 @@ const templateContent = z
|
|
|
216
214
|
items: z.array(z.unknown()),
|
|
217
215
|
formatVersion: z.number().int().nonnegative().optional(),
|
|
218
216
|
})
|
|
219
|
-
.
|
|
217
|
+
.loose();
|
|
220
218
|
// content payloads aren't discriminable (legacy/modern differ only by tags
|
|
221
219
|
// element type), so this is an ordered union: the first matching variant wins
|
|
222
220
|
const content = z.union([
|
|
@@ -242,17 +240,17 @@ const highlightsFile = z
|
|
|
242
240
|
width: z.number(),
|
|
243
241
|
height: z.number(),
|
|
244
242
|
})
|
|
245
|
-
.
|
|
243
|
+
.loose()),
|
|
246
244
|
})
|
|
247
|
-
.
|
|
245
|
+
.loose())),
|
|
248
246
|
})
|
|
249
|
-
.
|
|
247
|
+
.loose();
|
|
250
248
|
const pageMetadataReg = /\/[^/]+-metadata\.json$/;
|
|
251
249
|
const pageMetadata = z
|
|
252
250
|
.object({
|
|
253
|
-
layers: z.array(z.object({ name: z.string() }).
|
|
251
|
+
layers: z.array(z.object({ name: z.string() }).loose()),
|
|
254
252
|
})
|
|
255
|
-
.
|
|
253
|
+
.loose();
|
|
256
254
|
const metadata = z
|
|
257
255
|
.object({
|
|
258
256
|
lastModified: z.string().optional(),
|
|
@@ -271,7 +269,7 @@ const metadata = z
|
|
|
271
269
|
new: z.boolean().optional(),
|
|
272
270
|
source: z.string().optional(),
|
|
273
271
|
})
|
|
274
|
-
.
|
|
272
|
+
.loose();
|
|
275
273
|
/** parse and validate the json text of a `.metadata` file */
|
|
276
274
|
export function parseMetadata(text) {
|
|
277
275
|
const loaded = JSON.parse(text);
|
|
@@ -282,20 +280,20 @@ const updatedRootHash = z
|
|
|
282
280
|
hash: z.string(),
|
|
283
281
|
generation: z.number(),
|
|
284
282
|
})
|
|
285
|
-
.
|
|
283
|
+
.loose();
|
|
286
284
|
const rootHash = z
|
|
287
285
|
.object({
|
|
288
286
|
hash: z.string(),
|
|
289
287
|
generation: z.number(),
|
|
290
288
|
schemaVersion: z.number().int().nonnegative(),
|
|
291
289
|
})
|
|
292
|
-
.
|
|
290
|
+
.loose();
|
|
293
291
|
const nativeItemRef = z
|
|
294
292
|
.object({
|
|
295
293
|
docID: z.string(),
|
|
296
294
|
hash: z.string(),
|
|
297
295
|
})
|
|
298
|
-
.
|
|
296
|
+
.loose();
|
|
299
297
|
async function digest(buff) {
|
|
300
298
|
const digest = await crypto.subtle.digest("SHA-256",
|
|
301
299
|
// NOTE this is type hinted wrong, but it does work correctly on a uint8 view
|
|
@@ -389,6 +387,7 @@ function parseRawEntryLine(line) {
|
|
|
389
387
|
*/
|
|
390
388
|
export class RawRemarkable {
|
|
391
389
|
#authedFetch;
|
|
390
|
+
#authedSocket;
|
|
392
391
|
#rawHost;
|
|
393
392
|
#uploadHost;
|
|
394
393
|
/**
|
|
@@ -402,8 +401,9 @@ export class RawRemarkable {
|
|
|
402
401
|
*/
|
|
403
402
|
#cache;
|
|
404
403
|
#maxCachedBytes;
|
|
405
|
-
constructor(authedFetch, cache, rawHost, uploadHost, maxCachedBytes) {
|
|
404
|
+
constructor(authedFetch, authedSocket, cache, rawHost, uploadHost, maxCachedBytes) {
|
|
406
405
|
this.#authedFetch = authedFetch;
|
|
406
|
+
this.#authedSocket = authedSocket;
|
|
407
407
|
this.#cache = cache;
|
|
408
408
|
this.#rawHost = rawHost;
|
|
409
409
|
this.#uploadHost = uploadHost;
|
|
@@ -867,6 +867,22 @@ export class RawRemarkable {
|
|
|
867
867
|
const { docID, hash } = nativeItemRef.parse(loaded);
|
|
868
868
|
return { id: docID, hash };
|
|
869
869
|
}
|
|
870
|
+
/**
|
|
871
|
+
* open the websocket reMarkable pushes notifications to
|
|
872
|
+
*
|
|
873
|
+
* The server drops the socket every few minutes, so anything long lived has
|
|
874
|
+
* to reopen it. {@link RemarkableApi.listen | `listen`} does that, and parses
|
|
875
|
+
* the sync notifications out of what arrives.
|
|
876
|
+
*
|
|
877
|
+
* reMarkable authorizes the handshake with a header, which node and bun can
|
|
878
|
+
* attach but a browser's `WebSocket` can't, so this is server side only.
|
|
879
|
+
*
|
|
880
|
+
* @returns the connecting socket
|
|
881
|
+
*/
|
|
882
|
+
notifications() {
|
|
883
|
+
const host = this.#rawHost.replace(/^http/, "ws");
|
|
884
|
+
return this.#authedSocket(`${host}/notifications/ws/json/1`);
|
|
885
|
+
}
|
|
870
886
|
/**
|
|
871
887
|
* dump the current cache to a string to preserve between session
|
|
872
888
|
*
|