rmapi-js 10.0.1 → 10.1.1

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.js CHANGED
@@ -348,7 +348,7 @@ class Remarkable {
348
348
  ]);
349
349
  // now upload a new root entry
350
350
  rootEntries.push(collectionEntry);
351
- const [rootEntry, uploadRoot] = await this.raw.putEntries("root", rootEntries, schemaVersion);
351
+ const [rootEntry, uploadRoot] = await this.raw.putEntries("root", rootEntries, 4);
352
352
  // before updating the root hash, first upload everything
353
353
  await Promise.all([
354
354
  uploadContent,
@@ -402,7 +402,7 @@ class Remarkable {
402
402
  ]);
403
403
  // now upload a new root entry
404
404
  rootEntries.push(collectionEntry);
405
- const [rootEntry, uploadRoot] = await this.raw.putEntries("root", rootEntries, schemaVersion);
405
+ const [rootEntry, uploadRoot] = await this.raw.putEntries("root", rootEntries, 4);
406
406
  // before updating the root hash, first upload everything
407
407
  await Promise.all([
408
408
  uploadContent,
@@ -459,7 +459,7 @@ class Remarkable {
459
459
  throw new Error(`expected type ${expectedType} but got ${meta.type} for hash ${hash}`);
460
460
  }
461
461
  entries[hashInd] = newEnt;
462
- const [rootEntry, uploadRoot] = await this.raw.putEntries("root", entries, schemaVersion);
462
+ const [rootEntry, uploadRoot] = await this.raw.putEntries("root", entries, 4);
463
463
  await Promise.all([uploadEnt, uploadRoot]);
464
464
  await this.#putRootHash(rootEntry.hash, generation);
465
465
  return { hash: newEnt.hash };
@@ -501,7 +501,7 @@ class Remarkable {
501
501
  }
502
502
  const [newEnt, uploadEnt] = await this.#editMetaRaw(hashEnt.id, hash, update, schemaVersion);
503
503
  entries[hashInd] = newEnt;
504
- const [rootEntry, uploadRoot] = await this.raw.putEntries("root", entries, schemaVersion);
504
+ const [rootEntry, uploadRoot] = await this.raw.putEntries("root", entries, 4);
505
505
  await Promise.all([uploadEnt, uploadRoot]);
506
506
  await this.#putRootHash(rootEntry.hash, generation);
507
507
  return { hash: newEnt.hash };
@@ -547,7 +547,7 @@ class Remarkable {
547
547
  uploads.push(upload);
548
548
  result[toUpdate[i].hash] = newEnt.hash;
549
549
  }
550
- const [rootEntry, uploadRoot] = await this.raw.putEntries("root", newEntries, schemaVersion);
550
+ const [rootEntry, uploadRoot] = await this.raw.putEntries("root", newEntries, 4);
551
551
  await Promise.all([Promise.all(uploads), uploadRoot]);
552
552
  await this.#putRootHash(rootEntry.hash, generation);
553
553
  return { hashes: result };
package/dist/raw.d.ts CHANGED
@@ -216,7 +216,7 @@ export interface CommonDocumentContent {
216
216
  /** a mapping from page number to page id in pages */
217
217
  redirectionPageMap?: number[];
218
218
  /** ostensibly the size in bytes of the file, but this differs from other measurements */
219
- sizeInBytes: string;
219
+ sizeInBytes?: string;
220
220
  /** text alignment for this document */
221
221
  textAlignment: TextAlignment;
222
222
  /**
@@ -549,6 +549,11 @@ export interface RawRemarkableApi {
549
549
  * 3. append this entry to the root entry and call this again to update this root list
550
550
  * 4. put the new root hash
551
551
  *
552
+ * NOTE: reMarkable currently rejects newly written schema 3 root indexes
553
+ * with a 400 "Software must be updated" error, even for accounts that still
554
+ * report schema 3, so the root list should always be written as schema 4. A
555
+ * warning is logged if a schema 3 root index is written.
556
+ *
552
557
  * @param id - the id of the list to upload - this should be the item id if
553
558
  * uploading an item list, or "root" if uploading a new root list.
554
559
  * @param entries - the entries to upload
package/dist/raw.js CHANGED
@@ -77,7 +77,6 @@ const documentContentRequired = {
77
77
  lineHeight: int32(),
78
78
  orientation: enumeration("portrait", "landscape"),
79
79
  pageCount: uint32(),
80
- sizeInBytes: string(),
81
80
  textAlignment: enumeration("", "justify", "left"),
82
81
  textScale: float64(),
83
82
  };
@@ -101,6 +100,7 @@ const documentContentOptional = {
101
100
  pages: nullable(elements(string())),
102
101
  pageTags: elements(pageTag),
103
102
  redirectionPageMap: elements(int32()),
103
+ sizeInBytes: string(),
104
104
  transform: properties(undefined, {
105
105
  m11: float64(),
106
106
  m12: float64(),
@@ -420,6 +420,9 @@ export class RawRemarkable {
420
420
  }
421
421
  }
422
422
  async putEntries(id, entries, schemaVersion) {
423
+ if (id === "root" && schemaVersion === 3) {
424
+ console.warn('writing a schema 3 root index, which reMarkable rejects with a 400 "Software must be updated" error; write the root index with schema version 4 instead');
425
+ }
423
426
  // NOTE v3 collections have a special hash function, the hash of their
424
427
  // contents, so this needs to be different
425
428
  entries.sort((a, b) => a.id.localeCompare(b.id));
@@ -430,7 +433,8 @@ export class RawRemarkable {
430
433
  records.push(`0:${name}:${entries.length}:${size}\n`);
431
434
  }
432
435
  for (const { hash, type, id, subfiles, size } of entries) {
433
- records.push(`${hash}:${type}:${id}:${subfiles}:${size}\n`);
436
+ const lineType = schemaVersion === 4 ? 0 : type;
437
+ records.push(`${hash}:${lineType}:${id}:${subfiles}:${size}\n`);
434
438
  }
435
439
  const enc = new TextEncoder();
436
440
  const entryBuff = enc.encode(records.join(""));
@@ -9,15 +9,15 @@ While trying to validate:
9
9
  ${$}
10
10
 
11
11
  Against schema:
12
- ${X}`)}else return!0}}class NX extends S0{#Q;definitions;nullable=!0;constructor(Q){super();this.#Q=Q,this.definitions=Q.definitions}*pathErrors(Q){if(Q!==null)for(let[q,$]of this.#Q.pathErrors(Q))yield[q,`${$} or ${$2(Q)} is not null`]}fuzz(){return v6(0.1)?null:this.#Q.fuzz()}schema(){return{...this.#Q.schema(),nullable:!0}}}function E6(Q){return new NX(Q)}class yZ extends S0{#Q;#q;definitions;nullable;constructor(Q,q){super();this.#Q=Q,this.#q=q,this.definitions=Q.definitions,this.nullable=Q.nullable}*pathErrors(Q){yield*this.#Q.pathErrors(Q)}fuzz(){return this.#Q.fuzz()}schema(){return{...this.#Q.schema(),metadata:this.#q}}}class DX extends S0{*pathErrors(Q){if(Q===void 0)yield[[],"value is undefined"]}fuzz(){return k8([()=>null,v6,m4,()=>i1(V2()),()=>Array(V2()).fill(null).map(()=>this.fuzz()),()=>Object.fromEntries(Array(V2()).fill(null).map(()=>[i1(V2(3)),this.fuzz()]))])()}schema(){return{}}}function AX(){return new DX}class OX extends S0{*pathErrors(Q){if(typeof Q!=="boolean")yield[[],`${$2(Q)} is not a boolean`]}fuzz(){return v6()}schema(){return{type:"boolean"}}}function w1(){return new OX}class g8 extends S0{#Q;#q;#$;constructor(Q){super();this.#Q=Q,[this.#q,this.#$]=SZ[Q]}*pathErrors(Q){if(typeof Q!=="number")yield[[],`${$2(Q)} is not a number`];else if(Q%1!==0)yield[[],`${Q.toPrecision()} is not an integer`];else if(Q<this.#q)yield[[],`${Q.toFixed()} is less than ${this.#q.toFixed()}`];else if(Q>=this.#$)yield[[],`${Q.toFixed()} is greater than ${(this.#$-1).toFixed()}`]}fuzz(){return CX(this.#q,this.#$)}schema(){return{type:this.#Q}}}function y8(){return new g8("uint8")}function z2(){return new g8("int32")}function o1(){return new g8("uint32")}class RX extends S0{#Q;constructor(Q){super();this.#Q=Q}*pathErrors(Q){if(typeof Q!=="number")yield[[],`${$2(Q)} is not number, expected a float`]}fuzz(){return m4()}schema(){return{type:this.#Q}}}function O0(){return new RX("float64")}class xX extends S0{*pathErrors(Q){if(typeof Q!=="string")yield[[],`${$2(Q)} is not a string`]}fuzz(){return i1(V2(3))}schema(){return{type:"string"}}}function F0(){return new xX}class TX extends S0{*pathErrors(Q){if(typeof Q!=="string")yield[[],`${$2(Q)} is not a string`];else if(!xZ(Q))yield[[],`${Q} is not a valid timestamp`]}fuzz(){return new Date(Math.random()*3153600000000).toISOString()}schema(){return{type:"timestamp"}}}function vX(){return new TX}class EX extends S0{#Q;#q;constructor(Q,q){super();this.#Q=Q,this.#q=q}*pathErrors(Q){if(typeof Q!=="string")yield[[],`${$2(Q)} is not a string`];else if(!this.#q.has(Q))yield[[],`${Q} is not one of ${this.#Q.join(", ")}`]}fuzz(){return k8(this.#Q)}schema(){return{enum:[...this.#Q]}}}function C2(...Q){let q=new Set(Q);if(q.size!==Q.length)throw Error("enum can't contain duplicates");else return new EX(Q,q)}class SX extends S0{#Q;constructor(Q){super();this.#Q=Q}*pathErrors(Q){if(!Array.isArray(Q))yield[[],`${$2(Q)} is not an array`];else for(let[q,$]of Q.entries())for(let[X,Y]of this.#Q.pathErrors($))X.push(`[${q.toFixed()}]`),yield[X,Y]}fuzz(){return Array(V2()).fill(null).map(()=>this.#Q.fuzz())}schema(){return{elements:this.#Q.schema()}}}function h0(Q){if(Q.definitions)throw Error("definitions can only exist on a root schema");else return new SX(Q)}class kX extends S0{#Q;constructor(Q){super();this.#Q=Q}*pathErrors(Q){if(!S8(Q))yield[[],`${$2(Q)} is not a record`];else for(let[q,$]of Object.entries(Q))for(let[X,Y]of this.#Q.pathErrors($))X.push(l1(q)),yield[X,Y]}fuzz(){return Object.fromEntries(Array(V2()).fill(null).map(()=>[i1(V2(3)),this.#Q.fuzz()]))}schema(){return{values:this.#Q.schema()}}}function S6(Q){if(Q.definitions)throw Error("definitions can only exist on a root schema");else return new kX(Q)}class gX extends S0{#Q;#q;#$;keys;constructor(Q,q,$,X){super();this.#Q=Q,this.#q=q,this.#$=$,this.keys=X}*pathErrors(Q){if(!S8(Q))yield[[],`${$2(Q)} is not a record`];else{if(this.#Q)for(let[q,$]of this.#Q){let X=Q[q];if(X===void 0)yield[[],`required key '${q}' is missing`];else for(let[Y,J]of $.pathErrors(X))Y.push(l1(q)),yield[Y,J]}if(this.#q){for(let[q,$]of this.#q)if(Q[q]!==void 0)for(let[X,Y]of $.pathErrors(Q[q]))X.push(l1(q)),yield[X,Y]}if(!this.#$){for(let q of Object.keys(Q))if(!this.keys.has(q))yield[[l1(q)],`'${q}' is not a valid property and additional properties are not allowed`]}}}fuzz(){let Q=E8(this.#Q??[],([X,Y])=>[X,Y.fuzz()]),q=E8(kZ(this.#q??[],()=>v6()),([X,Y])=>[X,Y.fuzz()]),$=this.#$?E8(gZ(V2()),()=>[i1(V2(3)),k8([()=>null,v6,m4,()=>i1(V2()),()=>[],()=>({})])()]):[];return Object.fromEntries(IX(Q,q,$))}schema(){let Q={};if(this.#Q)Q.properties=Object.fromEntries(this.#Q.map(([q,$])=>[q,$.schema()]));if(this.#q)Q.optionalProperties=Object.fromEntries(this.#q.map(([q,$])=>[q,$.schema()]));if(this.#$)Q.additionalProperties=!0;return Q}}function fZ(Q,q,$){let X=new Set(E8(IX(Q??[],q??[]),([Y])=>Y));if(Q?.some(([,Y])=>Y.definitions))throw Error("definitions can only exist on a root schema");else if(q?.some(([,Y])=>Y.definitions))throw Error("definitions can only exist on a root schema");else if(X.size!==(Q?.length??0)+(q?.length??0))throw Error("properties and optionalProperties keys must be unique");else return new gX(Q,q,$??!1,X)}function C0(Q,q,$){return fZ(Q?Object.entries(Q):void 0,q?Object.entries(q):void 0,$)}class hZ extends S0{#Q;#q;#$;constructor(Q,q,$){super();this.#Q=Q,this.#q=q,this.#$=$}guard(Q){if(!S8(Q))return!1;let{[this.#Q]:q,...$}=Q;if(typeof q!=="string")return!1;return this.#q[q]?.guard($)??!1}*pathErrors(Q){if(!S8(Q))yield[[],`${$2(Q)} is not an object`];else{let{[this.#Q]:q,...$}=Q;if(q===void 0)yield[[],`discriminator key '${this.#Q}' is missing`];else if(typeof q!=="string")yield[[l1(this.#Q)],`${$2(q)} is not a string`];else{let X=this.#q[q];if(X===void 0)yield[[l1(this.#Q)],`'${q}' is not a valid discriminator value (${Object.keys(this.#q).join(", ")})`];else yield*X.pathErrors($)}}}fuzz(){let[Q,q]=k8(this.#$);return{...q.fuzz(),[this.#Q]:Q}}schema(){let Q=Object.fromEntries(this.#$.map(([q,$])=>[q,$.schema()]));return{discriminator:this.#Q,mapping:Q}}}class yX extends S0{#Q;#q;definitions=!0;constructor(Q,q){super();this.#Q=Q,this.#q=q}*pathErrors(Q){yield*this.#q.pathErrors(Q)}fuzz(){return this.#q.fuzz()}schema(){let Q=Object.fromEntries(Object.entries(this.#Q).map(([q,$])=>[q,$.schema()]));return{...this.#q.schema(),definitions:Q}}}class fX extends S0{#Q;#q;constructor(Q,q){super();this.#Q=Q,this.#q=q}*pathErrors(Q){yield*this.#q.pathErrors(Q)}fuzz(){return this.#q.fuzz()}schema(){return{ref:this.#Q}}}class hX{#Q;#q;constructor(Q,q){this.#Q=Q,this.#q=q}def(Q,q){let $=q(this.#q);return new hX({...this.#Q,[Q]:$},{...this.#q,[Q]:new fX(Q,$)})}build(Q){return new yX(this.#Q,Q(this.#q))}}class _Z extends S0{#Q;#q;constructor(Q,q){super();this.#q=Q,this.#Q=q}#$(){let Q=this.#q[this.#Q];if(Q===void 0)throw Error(`ref ${this.#Q} was not in definitions after ref builder was finished`);else return Q}*pathErrors(Q){yield*this.#$().pathErrors(Q)}fuzz(){return this.#$().fuzz()}schema(){return{ref:this.#Q}}}var bZ=new Uint8Array(16);function d4(){return crypto.getRandomValues(bZ)}var k0=[];for(let Q=0;Q<256;++Q)k0.push((Q+256).toString(16).slice(1));function _X(Q,q=0){return(k0[Q[q+0]]+k0[Q[q+1]]+k0[Q[q+2]]+k0[Q[q+3]]+"-"+k0[Q[q+4]]+k0[Q[q+5]]+"-"+k0[Q[q+6]]+k0[Q[q+7]]+"-"+k0[Q[q+8]]+k0[Q[q+9]]+"-"+k0[Q[q+10]]+k0[Q[q+11]]+k0[Q[q+12]]+k0[Q[q+13]]+k0[Q[q+14]]+k0[Q[q+15]]).toLowerCase()}function uZ(Q,q,$){if(!q&&!Q&&crypto.randomUUID)return crypto.randomUUID();return cZ(Q,q,$)}function cZ(Q,q,$){Q=Q||{};let X=Q.random??Q.rng?.()??d4();if(X.length<16)throw Error("Random bytes length must be >= 16");if(X[6]=X[6]&15|64,X[8]=X[8]&63|128,q){if($=$||0,$<0||$+16>q.length)throw RangeError(`UUID byte range ${$}:${$+15} is out of buffer bounds`);for(let Y=0;Y<16;++Y)q[$+Y]=X[Y];return q}return _X(X)}var n1=uZ;class I2 extends Error{field;regex;constructor(Q,q,$){super($);this.field=Q,this.regex=q}}class k6 extends Error{hash;constructor(Q){super(`'${Q}' not found in the root hash`);this.hash=Q}}class l4 extends Map{#Q;#q=0;constructor(Q,q=[]){super();this.#Q=Q;for(let[$,X]of q)this.set($,X)}get(Q){let q=super.get(Q);if(q!==void 0)super.delete(Q),super.set(Q,q);return q}set(Q,q){let $=super.get(Q);if($===void 0)this.#q+=Q.length;else if($!==null)this.#q-=$.length;if(q!==null)this.#q+=q.length;super.delete(Q);let X;while(this.#q>this.#Q&&(X=this.entries().next().value)){let[Y,J]=X;if(super.delete(Y),this.#q-=Y.length,J!==null)this.#q-=J.length}return super.set(Q,q),this}delete(Q){let q=super.get(Q);if(q===void 0)return!1;if(super.delete(Q),q!==null)this.#q-=q.length;return this.#q-=Q.length,!0}clear(){super.clear(),this.#q=0}}var eK=V5(uX(),1);function cX(Q){let q=Q.reduce((Y,J)=>Y+J.length,0),$=new Uint8Array(q),X=0;for(let Y of Q)$.set(Y,X),X+=Y.length;return $}var kC=V5(sK(),1),$5=/^[0-9a-f]{64}$/,QU=C0({name:F0(),timestamp:O0()},void 0,!0),xw=C0({name:F0(),pageId:F0(),timestamp:O0()},void 0,!0),Tw=C0(void 0,{authors:h0(F0()),title:F0(),publicationDate:F0(),publisher:F0()},!0),vw=C0({id:F0(),idx:C0({timestamp:F0(),value:F0()},void 0,!0)},{template:C0({timestamp:F0(),value:F0()},void 0,!0),redir:C0({timestamp:F0(),value:z2()},void 0,!0),scrollTime:C0({timestamp:F0(),value:vX()},void 0,!0),verticalScroll:C0({timestamp:F0(),value:O0()},void 0,!0),deleted:C0({timestamp:F0(),value:z2()},void 0,!0)},!0),Ew=C0({lastOpened:C0({timestamp:F0(),value:F0()},void 0,!0),original:C0({timestamp:F0(),value:z2()},void 0,!0),pages:h0(vw),uuids:E6(h0(C0({first:F0(),second:o1()},void 0,!0)))},void 0,!0),Sw=C0(void 0,{tags:h0(QU)}),kw=C0(void 0,{tags:h0(F0())}),qU={coverPageNumber:z2(),documentMetadata:Tw,extraMetadata:S6(F0()),fileType:C2("epub","notebook","pdf"),fontName:F0(),lineHeight:z2(),orientation:C2("portrait","landscape"),pageCount:o1(),sizeInBytes:F0(),textAlignment:C2("","justify","left"),textScale:O0()},$U={cPages:Ew,customZoomCenterX:O0(),customZoomCenterY:O0(),customZoomOrientation:C2("portrait","landscape"),customZoomPageHeight:O0(),customZoomPageWidth:O0(),customZoomScale:O0(),dummyDocument:w1(),formatVersion:y8(),keyboardMetadata:C0({count:o1(),timestamp:O0()},void 0,!0),lastOpenedPage:z2(),margins:o1(),originalPageCount:z2(),pages:E6(h0(F0())),pageTags:h0(xw),redirectionPageMap:h0(z2()),transform:C0(void 0,{m11:O0(),m12:O0(),m13:O0(),m21:O0(),m22:O0(),m23:O0(),m31:O0(),m32:O0(),m33:O0()},!0),viewBackgroundFilter:C2("off","fullpage"),zoomMode:C2("bestFit","customFit","fitToHeight","fitToWidth")},gw=C0(qU,{...$U,tags:h0(QU)},!0),yw=C0(qU,{...$U,tags:h0(F0())},!0),fw=C0({name:F0(),author:F0(),iconData:F0(),categories:h0(F0()),labels:h0(F0()),orientation:C2("portrait","landscape"),templateVersion:F0(),supportedScreens:h0(C2("rm2","rmPP")),constants:h0(S6(z2())),items:h0(AX())},{formatVersion:y8()}),hw=C0({lastModified:F0(),parent:F0(),pinned:w1(),type:C2("DocumentType","CollectionType","TemplateType"),visibleName:F0()},{lastOpened:F0(),lastOpenedPage:z2(),createdTime:F0(),deleted:w1(),metadatamodified:w1(),modified:w1(),synced:w1(),version:o1()},!0),_w=C0({hash:F0(),generation:O0()},void 0,!0),bw=C0({hash:F0(),generation:O0(),schemaVersion:y8()},void 0,!0),uw=C0({docID:F0(),hash:F0()},void 0,!0);async function dQ(Q){let q=await crypto.subtle.digest("SHA-256",Q);return new Uint8Array(q).toHex()}function tK(Q){let[q,$,X,Y,J]=Q.split(":");if(q===void 0||$===void 0||X===void 0||Y===void 0||J===void 0)throw Error(`line '${Q}' was not formatted correctly`);else if($==="80000000"||$==="0")return{hash:q,type:$==="0"?0:80000000,id:X,subfiles:parseInt(Y,10),size:parseInt(J,10)};else throw Error(`line '${Q}' was not formatted correctly`)}class lQ{#Q;#q;#$;#X;constructor(Q,q,$,X){this.#Q=Q,this.#X=q,this.#q=$,this.#$=X}async getRootHash(){let q=await(await this.#Q("GET",`${this.#q}/sync/v4/root`)).text(),$=JSON.parse(q);if(!bw.guardAssert($))throw Error("invalid root hash");let{hash:X,generation:Y,schemaVersion:J}=$;if(J!==3&&J!==4)throw Error(`schema version ${J} not supported`);else if(!Number.isSafeInteger(Y))throw Error(`generation ${Y} was not a safe integer; please file a bug report`);else return[X,Y,J]}async#Y(Q,q){if(!$5.test(q))throw new I2(q,$5,"hash was not a valid hash");let X=await(await this.#Q("GET",`${this.#q}/sync/v3/files/${q}`,{headers:{"rm-filename":Q}})).arrayBuffer();return new Uint8Array(X)}async getHash(Q,q){let $=this.#X.get(q);if($!=null)return new TextEncoder().encode($);else{let X=await this.#Y(Q,q);if(this.#X.get(q)===void 0)this.#X.set(q,null);return X}}async getText(Q,q){let $=this.#X.get(q);if($!=null)return $;else{let X=await this.#Y(Q,q),J=new TextDecoder().decode(X);return this.#X.set(q,J),J}}async getEntries(Q,q){let $=await this.getText(Q,q),[X,...Y]=$.slice(0,-1).split(`
12
+ ${X}`)}else return!0}}class NX extends S0{#Q;definitions;nullable=!0;constructor(Q){super();this.#Q=Q,this.definitions=Q.definitions}*pathErrors(Q){if(Q!==null)for(let[q,$]of this.#Q.pathErrors(Q))yield[q,`${$} or ${$2(Q)} is not null`]}fuzz(){return v6(0.1)?null:this.#Q.fuzz()}schema(){return{...this.#Q.schema(),nullable:!0}}}function E6(Q){return new NX(Q)}class yZ extends S0{#Q;#q;definitions;nullable;constructor(Q,q){super();this.#Q=Q,this.#q=q,this.definitions=Q.definitions,this.nullable=Q.nullable}*pathErrors(Q){yield*this.#Q.pathErrors(Q)}fuzz(){return this.#Q.fuzz()}schema(){return{...this.#Q.schema(),metadata:this.#q}}}class DX extends S0{*pathErrors(Q){if(Q===void 0)yield[[],"value is undefined"]}fuzz(){return k8([()=>null,v6,m4,()=>i1(V2()),()=>Array(V2()).fill(null).map(()=>this.fuzz()),()=>Object.fromEntries(Array(V2()).fill(null).map(()=>[i1(V2(3)),this.fuzz()]))])()}schema(){return{}}}function AX(){return new DX}class OX extends S0{*pathErrors(Q){if(typeof Q!=="boolean")yield[[],`${$2(Q)} is not a boolean`]}fuzz(){return v6()}schema(){return{type:"boolean"}}}function w1(){return new OX}class g8 extends S0{#Q;#q;#$;constructor(Q){super();this.#Q=Q,[this.#q,this.#$]=SZ[Q]}*pathErrors(Q){if(typeof Q!=="number")yield[[],`${$2(Q)} is not a number`];else if(Q%1!==0)yield[[],`${Q.toPrecision()} is not an integer`];else if(Q<this.#q)yield[[],`${Q.toFixed()} is less than ${this.#q.toFixed()}`];else if(Q>=this.#$)yield[[],`${Q.toFixed()} is greater than ${(this.#$-1).toFixed()}`]}fuzz(){return CX(this.#q,this.#$)}schema(){return{type:this.#Q}}}function y8(){return new g8("uint8")}function z2(){return new g8("int32")}function o1(){return new g8("uint32")}class RX extends S0{#Q;constructor(Q){super();this.#Q=Q}*pathErrors(Q){if(typeof Q!=="number")yield[[],`${$2(Q)} is not number, expected a float`]}fuzz(){return m4()}schema(){return{type:this.#Q}}}function O0(){return new RX("float64")}class xX extends S0{*pathErrors(Q){if(typeof Q!=="string")yield[[],`${$2(Q)} is not a string`]}fuzz(){return i1(V2(3))}schema(){return{type:"string"}}}function F0(){return new xX}class TX extends S0{*pathErrors(Q){if(typeof Q!=="string")yield[[],`${$2(Q)} is not a string`];else if(!xZ(Q))yield[[],`${Q} is not a valid timestamp`]}fuzz(){return new Date(Math.random()*3153600000000).toISOString()}schema(){return{type:"timestamp"}}}function vX(){return new TX}class EX extends S0{#Q;#q;constructor(Q,q){super();this.#Q=Q,this.#q=q}*pathErrors(Q){if(typeof Q!=="string")yield[[],`${$2(Q)} is not a string`];else if(!this.#q.has(Q))yield[[],`${Q} is not one of ${this.#Q.join(", ")}`]}fuzz(){return k8(this.#Q)}schema(){return{enum:[...this.#Q]}}}function C2(...Q){let q=new Set(Q);if(q.size!==Q.length)throw Error("enum can't contain duplicates");else return new EX(Q,q)}class SX extends S0{#Q;constructor(Q){super();this.#Q=Q}*pathErrors(Q){if(!Array.isArray(Q))yield[[],`${$2(Q)} is not an array`];else for(let[q,$]of Q.entries())for(let[X,Y]of this.#Q.pathErrors($))X.push(`[${q.toFixed()}]`),yield[X,Y]}fuzz(){return Array(V2()).fill(null).map(()=>this.#Q.fuzz())}schema(){return{elements:this.#Q.schema()}}}function h0(Q){if(Q.definitions)throw Error("definitions can only exist on a root schema");else return new SX(Q)}class kX extends S0{#Q;constructor(Q){super();this.#Q=Q}*pathErrors(Q){if(!S8(Q))yield[[],`${$2(Q)} is not a record`];else for(let[q,$]of Object.entries(Q))for(let[X,Y]of this.#Q.pathErrors($))X.push(l1(q)),yield[X,Y]}fuzz(){return Object.fromEntries(Array(V2()).fill(null).map(()=>[i1(V2(3)),this.#Q.fuzz()]))}schema(){return{values:this.#Q.schema()}}}function S6(Q){if(Q.definitions)throw Error("definitions can only exist on a root schema");else return new kX(Q)}class gX extends S0{#Q;#q;#$;keys;constructor(Q,q,$,X){super();this.#Q=Q,this.#q=q,this.#$=$,this.keys=X}*pathErrors(Q){if(!S8(Q))yield[[],`${$2(Q)} is not a record`];else{if(this.#Q)for(let[q,$]of this.#Q){let X=Q[q];if(X===void 0)yield[[],`required key '${q}' is missing`];else for(let[Y,J]of $.pathErrors(X))Y.push(l1(q)),yield[Y,J]}if(this.#q){for(let[q,$]of this.#q)if(Q[q]!==void 0)for(let[X,Y]of $.pathErrors(Q[q]))X.push(l1(q)),yield[X,Y]}if(!this.#$){for(let q of Object.keys(Q))if(!this.keys.has(q))yield[[l1(q)],`'${q}' is not a valid property and additional properties are not allowed`]}}}fuzz(){let Q=E8(this.#Q??[],([X,Y])=>[X,Y.fuzz()]),q=E8(kZ(this.#q??[],()=>v6()),([X,Y])=>[X,Y.fuzz()]),$=this.#$?E8(gZ(V2()),()=>[i1(V2(3)),k8([()=>null,v6,m4,()=>i1(V2()),()=>[],()=>({})])()]):[];return Object.fromEntries(IX(Q,q,$))}schema(){let Q={};if(this.#Q)Q.properties=Object.fromEntries(this.#Q.map(([q,$])=>[q,$.schema()]));if(this.#q)Q.optionalProperties=Object.fromEntries(this.#q.map(([q,$])=>[q,$.schema()]));if(this.#$)Q.additionalProperties=!0;return Q}}function fZ(Q,q,$){let X=new Set(E8(IX(Q??[],q??[]),([Y])=>Y));if(Q?.some(([,Y])=>Y.definitions))throw Error("definitions can only exist on a root schema");else if(q?.some(([,Y])=>Y.definitions))throw Error("definitions can only exist on a root schema");else if(X.size!==(Q?.length??0)+(q?.length??0))throw Error("properties and optionalProperties keys must be unique");else return new gX(Q,q,$??!1,X)}function C0(Q,q,$){return fZ(Q?Object.entries(Q):void 0,q?Object.entries(q):void 0,$)}class hZ extends S0{#Q;#q;#$;constructor(Q,q,$){super();this.#Q=Q,this.#q=q,this.#$=$}guard(Q){if(!S8(Q))return!1;let{[this.#Q]:q,...$}=Q;if(typeof q!=="string")return!1;return this.#q[q]?.guard($)??!1}*pathErrors(Q){if(!S8(Q))yield[[],`${$2(Q)} is not an object`];else{let{[this.#Q]:q,...$}=Q;if(q===void 0)yield[[],`discriminator key '${this.#Q}' is missing`];else if(typeof q!=="string")yield[[l1(this.#Q)],`${$2(q)} is not a string`];else{let X=this.#q[q];if(X===void 0)yield[[l1(this.#Q)],`'${q}' is not a valid discriminator value (${Object.keys(this.#q).join(", ")})`];else yield*X.pathErrors($)}}}fuzz(){let[Q,q]=k8(this.#$);return{...q.fuzz(),[this.#Q]:Q}}schema(){let Q=Object.fromEntries(this.#$.map(([q,$])=>[q,$.schema()]));return{discriminator:this.#Q,mapping:Q}}}class yX extends S0{#Q;#q;definitions=!0;constructor(Q,q){super();this.#Q=Q,this.#q=q}*pathErrors(Q){yield*this.#q.pathErrors(Q)}fuzz(){return this.#q.fuzz()}schema(){let Q=Object.fromEntries(Object.entries(this.#Q).map(([q,$])=>[q,$.schema()]));return{...this.#q.schema(),definitions:Q}}}class fX extends S0{#Q;#q;constructor(Q,q){super();this.#Q=Q,this.#q=q}*pathErrors(Q){yield*this.#q.pathErrors(Q)}fuzz(){return this.#q.fuzz()}schema(){return{ref:this.#Q}}}class hX{#Q;#q;constructor(Q,q){this.#Q=Q,this.#q=q}def(Q,q){let $=q(this.#q);return new hX({...this.#Q,[Q]:$},{...this.#q,[Q]:new fX(Q,$)})}build(Q){return new yX(this.#Q,Q(this.#q))}}class _Z extends S0{#Q;#q;constructor(Q,q){super();this.#q=Q,this.#Q=q}#$(){let Q=this.#q[this.#Q];if(Q===void 0)throw Error(`ref ${this.#Q} was not in definitions after ref builder was finished`);else return Q}*pathErrors(Q){yield*this.#$().pathErrors(Q)}fuzz(){return this.#$().fuzz()}schema(){return{ref:this.#Q}}}var bZ=new Uint8Array(16);function d4(){return crypto.getRandomValues(bZ)}var k0=[];for(let Q=0;Q<256;++Q)k0.push((Q+256).toString(16).slice(1));function _X(Q,q=0){return(k0[Q[q+0]]+k0[Q[q+1]]+k0[Q[q+2]]+k0[Q[q+3]]+"-"+k0[Q[q+4]]+k0[Q[q+5]]+"-"+k0[Q[q+6]]+k0[Q[q+7]]+"-"+k0[Q[q+8]]+k0[Q[q+9]]+"-"+k0[Q[q+10]]+k0[Q[q+11]]+k0[Q[q+12]]+k0[Q[q+13]]+k0[Q[q+14]]+k0[Q[q+15]]).toLowerCase()}function uZ(Q,q,$){if(!q&&!Q&&crypto.randomUUID)return crypto.randomUUID();return cZ(Q,q,$)}function cZ(Q,q,$){Q=Q||{};let X=Q.random??Q.rng?.()??d4();if(X.length<16)throw Error("Random bytes length must be >= 16");if(X[6]=X[6]&15|64,X[8]=X[8]&63|128,q){if($=$||0,$<0||$+16>q.length)throw RangeError(`UUID byte range ${$}:${$+15} is out of buffer bounds`);for(let Y=0;Y<16;++Y)q[$+Y]=X[Y];return q}return _X(X)}var n1=uZ;class I2 extends Error{field;regex;constructor(Q,q,$){super($);this.field=Q,this.regex=q}}class k6 extends Error{hash;constructor(Q){super(`'${Q}' not found in the root hash`);this.hash=Q}}class l4 extends Map{#Q;#q=0;constructor(Q,q=[]){super();this.#Q=Q;for(let[$,X]of q)this.set($,X)}get(Q){let q=super.get(Q);if(q!==void 0)super.delete(Q),super.set(Q,q);return q}set(Q,q){let $=super.get(Q);if($===void 0)this.#q+=Q.length;else if($!==null)this.#q-=$.length;if(q!==null)this.#q+=q.length;super.delete(Q);let X;while(this.#q>this.#Q&&(X=this.entries().next().value)){let[Y,J]=X;if(super.delete(Y),this.#q-=Y.length,J!==null)this.#q-=J.length}return super.set(Q,q),this}delete(Q){let q=super.get(Q);if(q===void 0)return!1;if(super.delete(Q),q!==null)this.#q-=q.length;return this.#q-=Q.length,!0}clear(){super.clear(),this.#q=0}}var eK=V5(uX(),1);function cX(Q){let q=Q.reduce((Y,J)=>Y+J.length,0),$=new Uint8Array(q),X=0;for(let Y of Q)$.set(Y,X),X+=Y.length;return $}var kC=V5(sK(),1),$5=/^[0-9a-f]{64}$/,QU=C0({name:F0(),timestamp:O0()},void 0,!0),xw=C0({name:F0(),pageId:F0(),timestamp:O0()},void 0,!0),Tw=C0(void 0,{authors:h0(F0()),title:F0(),publicationDate:F0(),publisher:F0()},!0),vw=C0({id:F0(),idx:C0({timestamp:F0(),value:F0()},void 0,!0)},{template:C0({timestamp:F0(),value:F0()},void 0,!0),redir:C0({timestamp:F0(),value:z2()},void 0,!0),scrollTime:C0({timestamp:F0(),value:vX()},void 0,!0),verticalScroll:C0({timestamp:F0(),value:O0()},void 0,!0),deleted:C0({timestamp:F0(),value:z2()},void 0,!0)},!0),Ew=C0({lastOpened:C0({timestamp:F0(),value:F0()},void 0,!0),original:C0({timestamp:F0(),value:z2()},void 0,!0),pages:h0(vw),uuids:E6(h0(C0({first:F0(),second:o1()},void 0,!0)))},void 0,!0),Sw=C0(void 0,{tags:h0(QU)}),kw=C0(void 0,{tags:h0(F0())}),qU={coverPageNumber:z2(),documentMetadata:Tw,extraMetadata:S6(F0()),fileType:C2("epub","notebook","pdf"),fontName:F0(),lineHeight:z2(),orientation:C2("portrait","landscape"),pageCount:o1(),textAlignment:C2("","justify","left"),textScale:O0()},$U={cPages:Ew,customZoomCenterX:O0(),customZoomCenterY:O0(),customZoomOrientation:C2("portrait","landscape"),customZoomPageHeight:O0(),customZoomPageWidth:O0(),customZoomScale:O0(),dummyDocument:w1(),formatVersion:y8(),keyboardMetadata:C0({count:o1(),timestamp:O0()},void 0,!0),lastOpenedPage:z2(),margins:o1(),originalPageCount:z2(),pages:E6(h0(F0())),pageTags:h0(xw),redirectionPageMap:h0(z2()),sizeInBytes:F0(),transform:C0(void 0,{m11:O0(),m12:O0(),m13:O0(),m21:O0(),m22:O0(),m23:O0(),m31:O0(),m32:O0(),m33:O0()},!0),viewBackgroundFilter:C2("off","fullpage"),zoomMode:C2("bestFit","customFit","fitToHeight","fitToWidth")},gw=C0(qU,{...$U,tags:h0(QU)},!0),yw=C0(qU,{...$U,tags:h0(F0())},!0),fw=C0({name:F0(),author:F0(),iconData:F0(),categories:h0(F0()),labels:h0(F0()),orientation:C2("portrait","landscape"),templateVersion:F0(),supportedScreens:h0(C2("rm2","rmPP")),constants:h0(S6(z2())),items:h0(AX())},{formatVersion:y8()}),hw=C0({lastModified:F0(),parent:F0(),pinned:w1(),type:C2("DocumentType","CollectionType","TemplateType"),visibleName:F0()},{lastOpened:F0(),lastOpenedPage:z2(),createdTime:F0(),deleted:w1(),metadatamodified:w1(),modified:w1(),synced:w1(),version:o1()},!0),_w=C0({hash:F0(),generation:O0()},void 0,!0),bw=C0({hash:F0(),generation:O0(),schemaVersion:y8()},void 0,!0),uw=C0({docID:F0(),hash:F0()},void 0,!0);async function dQ(Q){let q=await crypto.subtle.digest("SHA-256",Q);return new Uint8Array(q).toHex()}function tK(Q){let[q,$,X,Y,J]=Q.split(":");if(q===void 0||$===void 0||X===void 0||Y===void 0||J===void 0)throw Error(`line '${Q}' was not formatted correctly`);else if($==="80000000"||$==="0")return{hash:q,type:$==="0"?0:80000000,id:X,subfiles:parseInt(Y,10),size:parseInt(J,10)};else throw Error(`line '${Q}' was not formatted correctly`)}class lQ{#Q;#q;#$;#X;constructor(Q,q,$,X){this.#Q=Q,this.#X=q,this.#q=$,this.#$=X}async getRootHash(){let q=await(await this.#Q("GET",`${this.#q}/sync/v4/root`)).text(),$=JSON.parse(q);if(!bw.guardAssert($))throw Error("invalid root hash");let{hash:X,generation:Y,schemaVersion:J}=$;if(J!==3&&J!==4)throw Error(`schema version ${J} not supported`);else if(!Number.isSafeInteger(Y))throw Error(`generation ${Y} was not a safe integer; please file a bug report`);else return[X,Y,J]}async#Y(Q,q){if(!$5.test(q))throw new I2(q,$5,"hash was not a valid hash");let X=await(await this.#Q("GET",`${this.#q}/sync/v3/files/${q}`,{headers:{"rm-filename":Q}})).arrayBuffer();return new Uint8Array(X)}async getHash(Q,q){let $=this.#X.get(q);if($!=null)return new TextEncoder().encode($);else{let X=await this.#Y(Q,q);if(this.#X.get(q)===void 0)this.#X.set(q,null);return X}}async getText(Q,q){let $=this.#X.get(q);if($!=null)return $;else{let X=await this.#Y(Q,q),J=new TextDecoder().decode(X);return this.#X.set(q,J),J}}async getEntries(Q,q){let $=await this.getText(Q,q),[X,...Y]=$.slice(0,-1).split(`
13
13
  `);if(X==="3")return{entries:Y.map(tK)};else if(X==="4"){let[J,...K]=Y;if(!J)throw Error("missing info line for schema version 4");let[U,G,V,z]=J.split(":");if(U!=="0"||G===void 0||V===void 0||z===void 0)throw Error(`schema 4 info line '${J}' was not formatted correctly`);let H=K.map(tK);if(parseInt(V,10)!==H.length)throw Error(`schema 4 expected ${V} entries, but found ${H.length}`);else return{entries:H,id:G,size:parseInt(z,10)}}else throw Error(`schema version ${X} not supported`)}async getContent(Q,q){let $=await this.getText(Q,q),X=JSON.parse($),Y=[];for(let[K,U]of[["collection",Sw],["legacy collection",kw],["template",fw],["document",gw],["legacy document",yw]])try{if(U.guardAssert(X))return X}catch(G){let V=G instanceof Error?G.message:"unknown error type";Y.push(`Couldn't validate as ${K} because:
14
14
  ${V}`)}let J=Y.join(`
15
15
 
16
16
  or
17
17
 
18
- `);throw Error(`invalid content: ${J}`)}async getMetadata(Q,q){let $=await this.getText(Q,q),X=JSON.parse($);if(!hw.guardAssert(X))throw Error("invalid metadata");return X}async putRootHash(Q,q,$=!0){if(!Number.isSafeInteger(q))throw Error(`generation ${q} was not a safe integer`);else if(!$5.test(Q))throw new I2(Q,$5,"rootHash was not a valid hash");let X=JSON.stringify({hash:Q,generation:q,broadcast:$}),J=await(await this.#Q("PUT",`${this.#q}/sync/v3/root`,{body:X})).text(),K=JSON.parse(J);if(!_w.guardAssert(K))throw Error("invalid root hash");let{hash:U,generation:G}=K;if(Number.isSafeInteger(G))return[U,G];else throw Error(`new generation ${G} was not a safe integer; please file a bug report`)}async#J(Q,q,$){if(!this.#X.has(q)){let X=eK.default.buf($,0),Y=new ArrayBuffer(4);new DataView(Y).setInt32(0,X,!1);let J=new Uint8Array(Y).toBase64();if(await this.#Q("PUT",`${this.#q}/sync/v3/files/${q}`,{body:$,headers:{"rm-filename":Q,"x-goog-hash":`crc32c=${J}`}}),this.#X.get(q)===void 0)this.#X.set(q,null)}}async putFile(Q,q){let $=await dQ(q);return[{id:Q,hash:$,type:0,subfiles:0,size:q.length},this.#J(Q,$,q)]}async putText(Q,q){let X=new TextEncoder().encode(q),[Y,J]=await this.putFile(Q,X);return[Y,J.then(()=>{this.#X.set(Y.hash,q)})]}async putContent(Q,q){if(!Q.endsWith(".content"))throw Error(`id ${Q} did not end with '.content'`);else return await this.putText(Q,JSON.stringify(q))}async putMetadata(Q,q){if(!Q.endsWith(".metadata"))throw Error(`id ${Q} did not end with '.metadata'`);else return await this.putText(Q,JSON.stringify(q))}async putEntries(Q,q,$){q.sort((V,z)=>V.id.localeCompare(z.id));let X=q.reduce((V,z)=>V+z.size,0),Y=[`${$}
18
+ `);throw Error(`invalid content: ${J}`)}async getMetadata(Q,q){let $=await this.getText(Q,q),X=JSON.parse($);if(!hw.guardAssert(X))throw Error("invalid metadata");return X}async putRootHash(Q,q,$=!0){if(!Number.isSafeInteger(q))throw Error(`generation ${q} was not a safe integer`);else if(!$5.test(Q))throw new I2(Q,$5,"rootHash was not a valid hash");let X=JSON.stringify({hash:Q,generation:q,broadcast:$}),J=await(await this.#Q("PUT",`${this.#q}/sync/v3/root`,{body:X})).text(),K=JSON.parse(J);if(!_w.guardAssert(K))throw Error("invalid root hash");let{hash:U,generation:G}=K;if(Number.isSafeInteger(G))return[U,G];else throw Error(`new generation ${G} was not a safe integer; please file a bug report`)}async#J(Q,q,$){if(!this.#X.has(q)){let X=eK.default.buf($,0),Y=new ArrayBuffer(4);new DataView(Y).setInt32(0,X,!1);let J=new Uint8Array(Y).toBase64();if(await this.#Q("PUT",`${this.#q}/sync/v3/files/${q}`,{body:$,headers:{"rm-filename":Q,"x-goog-hash":`crc32c=${J}`}}),this.#X.get(q)===void 0)this.#X.set(q,null)}}async putFile(Q,q){let $=await dQ(q);return[{id:Q,hash:$,type:0,subfiles:0,size:q.length},this.#J(Q,$,q)]}async putText(Q,q){let X=new TextEncoder().encode(q),[Y,J]=await this.putFile(Q,X);return[Y,J.then(()=>{this.#X.set(Y.hash,q)})]}async putContent(Q,q){if(!Q.endsWith(".content"))throw Error(`id ${Q} did not end with '.content'`);else return await this.putText(Q,JSON.stringify(q))}async putMetadata(Q,q){if(!Q.endsWith(".metadata"))throw Error(`id ${Q} did not end with '.metadata'`);else return await this.putText(Q,JSON.stringify(q))}async putEntries(Q,q,$){if(Q==="root"&&$===3)console.warn('writing a schema 3 root index, which reMarkable rejects with a 400 "Software must be updated" error; write the root index with schema version 4 instead');q.sort((V,z)=>V.id.localeCompare(z.id));let X=q.reduce((V,z)=>V+z.size,0),Y=[`${$}
19
19
  `];if($===4){let V=Q==="root"?".":Q;Y.push(`0:${V}:${q.length}:${X}
20
- `)}for(let{hash:V,type:z,id:H,subfiles:j,size:Z}of q)Y.push(`${V}:${z}:${H}:${j}:${Z}
21
- `);let K=new TextEncoder().encode(Y.join("")),U;if($===3){let V=[];for(let{hash:z}of q)V.push(Uint8Array.fromHex(z));U=await dQ(cX(V))}else if($===4)U=await dQ(K);else throw Error(`unsupported schema version ${$}`);return[{id:Q,hash:U,type:$>3?0:80000000,subfiles:q.length,size:X},this.#J(`${Q}.docSchema`,U,K)]}async uploadFile(Q,q,$){let Y=new TextEncoder().encode(JSON.stringify({file_name:Q})).toBase64(),K=await(await this.#Q("POST",`${this.#$}/doc/v2/files`,{body:q,headers:{"Content-Type":$,"rm-meta":Y,"rm-source":"RoR-Browser"}})).json();if(!uw.guardAssert(K))throw Error("invalid upload response");let{docID:U,hash:G}=K;return{id:U,hash:G}}dumpCache(){return JSON.stringify(Object.fromEntries(this.#X))}clearCache(){this.#X.clear()}}var YU="https://webapp-prod.cloud.remarkable.engineering",cw="https://eu.tectonic.remarkable.com",pw="https://internal.cloud.remarkable.com",t2=/^([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}||trash)$/;class iQ extends Error{constructor(){super("root generation was stale; try put again")}}class oQ extends Error{status;statusText;constructor(Q,q,$){super($);this.status=Q,this.statusText=q}}async function uC(Q,{deviceDesc:q="browser-chrome",uuid:$=n1(),authHost:X=YU}={}){if(Q.length!==8)throw Error(`code should be length 8, but was ${Q.length}`);let Y=await fetch(`${X}/token/json/2/device/new`,{method:"POST",headers:{Authorization:"Bearer"},body:JSON.stringify({code:Q,deviceDesc:q,deviceID:$})});if(!Y.ok)throw new oQ(Y.status,Y.statusText,"couldn't register api");else return await Y.text()}class JU{#Q;#q;raw;#$;constructor(Q,q,$,X){this.#Q=Q,this.#q=X,this.raw=new lQ((Y,J,{body:K,headers:U}={})=>this.#J(J,{method:Y,body:K,headers:U}),X,q,$)}async#X(Q=!1){if(Q||this.#$===void 0)this.#$=await this.raw.getRootHash();return this.#$}async#Y(Q,q){try{let[$,X]=await this.raw.putRootHash(Q,q),[,,Y]=this.#$;this.#$=[$,X,Y]}catch($){if($ instanceof iQ)this.#$=void 0;throw $}}async#J(Q,{body:q,method:$="POST",headers:X={}}){let Y=await fetch(Q,{method:$,headers:{Authorization:`Bearer ${this.#Q}`,...X},body:q});if(!Y.ok){let J=await Y.text();if(J===`{"message":"precondition failed"}
20
+ `)}for(let{hash:V,type:z,id:H,subfiles:j,size:Z}of q){let h=$===4?0:z;Y.push(`${V}:${h}:${H}:${j}:${Z}
21
+ `)}let K=new TextEncoder().encode(Y.join("")),U;if($===3){let V=[];for(let{hash:z}of q)V.push(Uint8Array.fromHex(z));U=await dQ(cX(V))}else if($===4)U=await dQ(K);else throw Error(`unsupported schema version ${$}`);return[{id:Q,hash:U,type:$>3?0:80000000,subfiles:q.length,size:X},this.#J(`${Q}.docSchema`,U,K)]}async uploadFile(Q,q,$){let Y=new TextEncoder().encode(JSON.stringify({file_name:Q})).toBase64(),K=await(await this.#Q("POST",`${this.#$}/doc/v2/files`,{body:q,headers:{"Content-Type":$,"rm-meta":Y,"rm-source":"RoR-Browser"}})).json();if(!uw.guardAssert(K))throw Error("invalid upload response");let{docID:U,hash:G}=K;return{id:U,hash:G}}dumpCache(){return JSON.stringify(Object.fromEntries(this.#X))}clearCache(){this.#X.clear()}}var YU="https://webapp-prod.cloud.remarkable.engineering",cw="https://eu.tectonic.remarkable.com",pw="https://internal.cloud.remarkable.com",t2=/^([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}||trash)$/;class iQ extends Error{constructor(){super("root generation was stale; try put again")}}class oQ extends Error{status;statusText;constructor(Q,q,$){super($);this.status=Q,this.statusText=q}}async function uC(Q,{deviceDesc:q="browser-chrome",uuid:$=n1(),authHost:X=YU}={}){if(Q.length!==8)throw Error(`code should be length 8, but was ${Q.length}`);let Y=await fetch(`${X}/token/json/2/device/new`,{method:"POST",headers:{Authorization:"Bearer"},body:JSON.stringify({code:Q,deviceDesc:q,deviceID:$})});if(!Y.ok)throw new oQ(Y.status,Y.statusText,"couldn't register api");else return await Y.text()}class JU{#Q;#q;raw;#$;constructor(Q,q,$,X){this.#Q=Q,this.#q=X,this.raw=new lQ((Y,J,{body:K,headers:U}={})=>this.#J(J,{method:Y,body:K,headers:U}),X,q,$)}async#X(Q=!1){if(Q||this.#$===void 0)this.#$=await this.raw.getRootHash();return this.#$}async#Y(Q,q){try{let[$,X]=await this.raw.putRootHash(Q,q),[,,Y]=this.#$;this.#$=[$,X,Y]}catch($){if($ instanceof iQ)this.#$=void 0;throw $}}async#J(Q,{body:q,method:$="POST",headers:X={}}){let Y=await fetch(Q,{method:$,headers:{Authorization:`Bearer ${this.#Q}`,...X},body:q});if(!Y.ok){let J=await Y.text();if(J===`{"message":"precondition failed"}
22
22
  `)throw new iQ;else throw new oQ(Y.status,Y.statusText,`failed reMarkable request: ${J}`)}else return Y}async#G({hash:Q,id:q}){let{entries:$}=await this.raw.getEntries(`${q}.docSchema`,Q),X=$.find((Z)=>Z.id.endsWith(".metadata")),Y=$.find((Z)=>Z.id.endsWith(".content"));if(X===void 0)throw Error(`couldn't find metadata for hash ${Q}`);let[{visibleName:J,lastModified:K,pinned:U,parent:G,lastOpened:V,new:z,source:H},j]=await Promise.all([this.raw.getMetadata(X.id,X.hash),Y===void 0?Promise.resolve({fileType:void 0,tags:void 0}):this.raw.getContent(Y.id,Y.hash)]);if("templateVersion"in j)return{id:q,hash:Q,visibleName:J,lastModified:K,new:z,pinned:U,source:H,parent:G,type:"TemplateType"};else if(j.fileType===void 0)return{id:q,hash:Q,visibleName:J,lastModified:K,pinned:U,parent:G,tags:j.tags,type:"CollectionType"};else return{id:q,hash:Q,visibleName:J,lastModified:K,pinned:U,parent:G,tags:j.tags,lastOpened:V??"",fileType:j.fileType,type:"DocumentType"}}async listItems(Q=!1){let q=await this.listIds(Q);return await Promise.all(q.map(($)=>this.#G($)))}async listIds(Q=!1){let[q]=await this.#X(Q),{entries:$}=await this.raw.getEntries("root.docSchema",q);return $.map(({id:X,hash:Y})=>({id:X,hash:Y}))}async getContent(Q,q){let{entries:$}=await this.raw.getEntries(`${Q}.docSchema`,q),[X]=$.filter((Y)=>Y.id.endsWith(".content"));if(X===void 0)throw Error(`couldn't find contents for hash ${q}`);else return await this.raw.getContent(X.id,X.hash)}async getMetadata(Q,q){let{entries:$}=await this.raw.getEntries(`${Q}.docSchema`,q),[X]=$.filter((Y)=>Y.id.endsWith(".metadata"));if(X===void 0)throw Error(`couldn't find metadata for hash ${q}`);else return await this.raw.getMetadata(X.id,X.hash)}async getPdf(Q,q){let{entries:$}=await this.raw.getEntries(`${Q}.docSchema`,q),[X]=$.filter((Y)=>Y.id.endsWith(".pdf"));if(X===void 0)throw Error(`couldn't find pdf for hash ${q}`);else return await this.raw.getHash(X.id,X.hash)}async getEpub(Q,q){let{entries:$}=await this.raw.getEntries(`${Q}.docSchema`,q),[X]=$.filter((Y)=>Y.id.endsWith(".epub"));if(X===void 0)throw Error(`couldn't find epub for hash ${q}`);else return await this.raw.getHash(X.id,X.hash)}async getDocument(Q,q){let{entries:$}=await this.raw.getEntries(`${Q}.docSchema`,q),X=new XU.default;for(let Y of $)X.file(Y.id,this.raw.getHash(Y.id,Y.hash));return X.generateAsync({type:"uint8array"})}async#V(Q,q,$,{refresh:X,parent:Y="",pinned:J=!1,zoomMode:K="bestFit",viewBackgroundFilter:U,textScale:G=1,textAlignment:V="justify",fontName:z="",coverPageNumber:H=-1,authors:j,title:Z,publicationDate:h,publisher:g,extraMetadata:C={},lineHeight:N=-1,margins:W=125,orientation:M="portrait",tags:w}){if(Y&&!t2.test(Y))throw new I2(Y,t2,"parent must be a valid document id");let I=n1(),f=new Date,E={parent:Y,pinned:J,lastModified:(+f).toFixed(),createdTime:(+f).toFixed(),type:"DocumentType",visibleName:Q,lastOpened:"0",lastOpenedPage:0},d={coverPageNumber:H,documentMetadata:{authors:j,title:Z,publicationDate:h,publisher:g},extraMetadata:C,lineHeight:N,margins:W,orientation:M,fileType:q,formatVersion:1,tags:w?.map((u)=>({name:u,timestamp:+f}))??[],fontName:z,textAlignment:V,textScale:G,zoomMode:K,viewBackgroundFilter:U,originalPageCount:1,pageCount:1,pageTags:[],pages:[n1()],redirectionPageMap:[0],sizeInBytes:$.length.toFixed()},[[R,x],[D,L],[S,y],[v,a],[Q0,Y0,B0]]=await Promise.all([this.raw.putContent(`${I}.content`,d),this.raw.putMetadata(`${I}.metadata`,E),this.raw.putText(`${I}.pagedata`,`
23
- `),this.raw.putFile(`${I}.${q}`,$),this.#X(X)]),[[c,U0],{entries:P}]=await Promise.all([this.raw.putEntries(I,[R,D,S,v],B0),this.raw.getEntries("root.docSchema",Q0)]);P.push(c);let[l,$0]=await this.raw.putEntries("root",P,B0);return await Promise.all([x,L,y,a,U0,$0]),await this.#Y(l.hash,Y0),{id:I,hash:c.hash}}async putPdf(Q,q,$={}){return await this.#V(Q,"pdf",q,$)}async putEpub(Q,q,$={}){return await this.#V(Q,"epub",q,$)}async putFolder(Q,{parent:q=""}={},$=!1){if(q&&!t2.test(q))throw new I2(q,t2,"parent must be a valid document id");let X=n1(),Y=new Date,J={tags:[]},K={lastModified:(+Y).toFixed(),createdTime:(+Y).toFixed(),parent:q,pinned:!1,type:"CollectionType",visibleName:Q},[[U,G],[V,z],[H,j,Z]]=await Promise.all([this.raw.putContent(`${X}.content`,J),this.raw.putMetadata(`${X}.metadata`,K),this.#X($)]),[[h,g],{entries:C}]=await Promise.all([this.raw.putEntries(X,[U,V],Z),this.raw.getEntries("root.docSchema",H)]);C.push(h);let[N,W]=await this.raw.putEntries("root",C,Z);return await Promise.all([G,z,g,W]),await this.#Y(N.hash,j),{id:X,hash:h.hash}}async uploadEpub(Q,q){return await this.raw.uploadFile(Q,q,"application/epub+zip")}async uploadPdf(Q,q){return await this.raw.uploadFile(Q,q,"application/pdf")}async uploadFolder(Q){return await this.raw.uploadFile(Q,new Uint8Array(0),"folder")}async#W(Q,q,$,X){let{entries:Y}=await this.raw.getEntries(`${Q}.docSchema`,q),J=Y.findIndex((Z)=>Z.id.endsWith(".content")),K=Y[J];if(K===void 0)throw Error("internal error: couldn't find content in entry hash");let U=await this.raw.getContent(K.id,K.hash);Object.assign(U,$);let[G,V]=await this.raw.putContent(K.id,U);Y[J]=G;let[z,H]=await this.raw.putEntries(Q,Y,X),j=Promise.all([V,H]);return[z,j]}async#K(Q,q,$,X){let[Y,J,K]=await this.#X(X),{entries:U}=await this.raw.getEntries("root.docSchema",Y),G=U.findIndex((g)=>g.hash===Q),V=U[G];if(V===void 0)throw new k6(Q);let[[z,H],j]=await Promise.all([this.#W(V.id,Q,q,K),this.getMetadata(V.id,Q)]);if(j.type!==$)throw Error(`expected type ${$} but got ${j.type} for hash ${Q}`);U[G]=z;let[Z,h]=await this.raw.putEntries("root",U,K);return await Promise.all([H,h]),await this.#Y(Z.hash,J),{hash:z.hash}}async updateDocument(Q,q,$=!1){return await this.#K(Q,q,"DocumentType",$)}async updateCollection(Q,q,$=!1){return await this.#K(Q,q,"CollectionType",$)}async updateTemplate(Q,q,$=!1){return await this.#K(Q,q,"TemplateType",$)}async#z(Q,q,$,X){let{entries:Y}=await this.raw.getEntries(`${Q}.docSchema`,q),J=Y.findIndex((Z)=>Z.id.endsWith(".metadata")),K=Y[J];if(K===void 0)throw Error("internal error: couldn't find metadata in entry hash");let U=await this.raw.getMetadata(K.id,K.hash);Object.assign(U,$);let[G,V]=await this.raw.putMetadata(K.id,U);Y[J]=G;let[z,H]=await this.raw.putEntries(Q,Y,X),j=Promise.all([V,H]);return[z,j]}async#U(Q,q,$=!1){let[X,Y,J]=await this.#X($),{entries:K}=await this.raw.getEntries("root.docSchema",X),U=K.findIndex((Z)=>Z.hash===Q),G=K[U];if(G===void 0)throw new k6(Q);let[V,z]=await this.#z(G.id,Q,q,J);K[U]=V;let[H,j]=await this.raw.putEntries("root",K,J);return await Promise.all([z,j]),await this.#Y(H.hash,Y),{hash:V.hash}}async move(Q,q,$=!1){if(!t2.test(q))throw new I2(q,t2,"parent must be a valid document id");return await this.#U(Q,{parent:q},$)}async delete(Q,q=!1){return await this.move(Q,"trash",q)}async rename(Q,q,$=!1){return await this.#U(Q,{visibleName:q},$)}async stared(Q,q,$=!1){return await this.#U(Q,{pinned:q},$)}async bulkMove(Q,q,$=!1){if(!t2.test(q))throw new I2(q,t2,"parent must be a valid document id");let[X,Y,J]=await this.#X($),{entries:K}=await this.raw.getEntries("root.docSchema",X),U=new Set(Q),G=[],V=[];for(let g of K)(U.has(g.hash)?G:V).push(g);let z=await Promise.all(G.map(({id:g,hash:C})=>this.#z(g,C,{parent:q},J))),H=[],j={};for(let[g,[C,N]]of z.entries())V.push(C),H.push(N),j[G[g].hash]=C.hash;let[Z,h]=await this.raw.putEntries("root",V,J);return await Promise.all([Promise.all(H),h]),await this.#Y(Z.hash,Y),{hashes:j}}async bulkDelete(Q,q=!1){return await this.bulkMove(Q,"trash",q)}dumpCache(){return this.raw.dumpCache()}async pruneCache(Q){let[q]=await this.#X(Q),$=new Set(this.#q.keys()),Y=[(await this.raw.getEntries("root.docSchema",q)).entries],J=[];while(Y.length){for(let U of Y)for(let{hash:G,type:V,id:z}of U)if($.add(G),V===80000000)J.push(this.raw.getEntries(`${z}.docSchema`,G));Y=(await Promise.all(J)).map((U)=>U.entries),J=[]}for(let K of $)this.#q.delete(K)}clearCache(){this.raw.clearCache()}}var mw=S6(E6(F0()));async function dw(Q,{authHost:q=YU}={}){let $=await fetch(`${q}/token/json/2/user/new`,{method:"POST",headers:{Authorization:`Bearer ${Q}`}});if(!$.ok)throw Error(`couldn't fetch auth token: ${$.statusText}`);return await $.text()}function lw(Q,{rawHost:q=cw,uploadHost:$=pw,cache:X,maxCacheSize:Y=1/0}={}){let J=JSON.parse(X??"{}");if(mw.guard(J)){let K=Object.entries(J),U=Y===1/0?new Map(K):new l4(Y,K);return new JU(Q,q,$,U)}throw 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.")}async function cC(Q,q={}){let{authHost:$,rawHost:X,uploadHost:Y,cache:J,maxCacheSize:K,syncHost:U}=q??{},G=await dw(Q,{authHost:$});return lw(G,{rawHost:X,uploadHost:Y,cache:J,maxCacheSize:K,syncHost:U})}export{lw as session,cC as remarkable,uC as register,dw as auth,I2 as ValidationError,oQ as ResponseError,k6 as HashNotFoundError,iQ as GenerationError};
23
+ `),this.raw.putFile(`${I}.${q}`,$),this.#X(X)]),[[c,U0],{entries:P}]=await Promise.all([this.raw.putEntries(I,[R,D,S,v],B0),this.raw.getEntries("root.docSchema",Q0)]);P.push(c);let[l,$0]=await this.raw.putEntries("root",P,4);return await Promise.all([x,L,y,a,U0,$0]),await this.#Y(l.hash,Y0),{id:I,hash:c.hash}}async putPdf(Q,q,$={}){return await this.#V(Q,"pdf",q,$)}async putEpub(Q,q,$={}){return await this.#V(Q,"epub",q,$)}async putFolder(Q,{parent:q=""}={},$=!1){if(q&&!t2.test(q))throw new I2(q,t2,"parent must be a valid document id");let X=n1(),Y=new Date,J={tags:[]},K={lastModified:(+Y).toFixed(),createdTime:(+Y).toFixed(),parent:q,pinned:!1,type:"CollectionType",visibleName:Q},[[U,G],[V,z],[H,j,Z]]=await Promise.all([this.raw.putContent(`${X}.content`,J),this.raw.putMetadata(`${X}.metadata`,K),this.#X($)]),[[h,g],{entries:C}]=await Promise.all([this.raw.putEntries(X,[U,V],Z),this.raw.getEntries("root.docSchema",H)]);C.push(h);let[N,W]=await this.raw.putEntries("root",C,4);return await Promise.all([G,z,g,W]),await this.#Y(N.hash,j),{id:X,hash:h.hash}}async uploadEpub(Q,q){return await this.raw.uploadFile(Q,q,"application/epub+zip")}async uploadPdf(Q,q){return await this.raw.uploadFile(Q,q,"application/pdf")}async uploadFolder(Q){return await this.raw.uploadFile(Q,new Uint8Array(0),"folder")}async#W(Q,q,$,X){let{entries:Y}=await this.raw.getEntries(`${Q}.docSchema`,q),J=Y.findIndex((Z)=>Z.id.endsWith(".content")),K=Y[J];if(K===void 0)throw Error("internal error: couldn't find content in entry hash");let U=await this.raw.getContent(K.id,K.hash);Object.assign(U,$);let[G,V]=await this.raw.putContent(K.id,U);Y[J]=G;let[z,H]=await this.raw.putEntries(Q,Y,X),j=Promise.all([V,H]);return[z,j]}async#K(Q,q,$,X){let[Y,J,K]=await this.#X(X),{entries:U}=await this.raw.getEntries("root.docSchema",Y),G=U.findIndex((g)=>g.hash===Q),V=U[G];if(V===void 0)throw new k6(Q);let[[z,H],j]=await Promise.all([this.#W(V.id,Q,q,K),this.getMetadata(V.id,Q)]);if(j.type!==$)throw Error(`expected type ${$} but got ${j.type} for hash ${Q}`);U[G]=z;let[Z,h]=await this.raw.putEntries("root",U,4);return await Promise.all([H,h]),await this.#Y(Z.hash,J),{hash:z.hash}}async updateDocument(Q,q,$=!1){return await this.#K(Q,q,"DocumentType",$)}async updateCollection(Q,q,$=!1){return await this.#K(Q,q,"CollectionType",$)}async updateTemplate(Q,q,$=!1){return await this.#K(Q,q,"TemplateType",$)}async#z(Q,q,$,X){let{entries:Y}=await this.raw.getEntries(`${Q}.docSchema`,q),J=Y.findIndex((Z)=>Z.id.endsWith(".metadata")),K=Y[J];if(K===void 0)throw Error("internal error: couldn't find metadata in entry hash");let U=await this.raw.getMetadata(K.id,K.hash);Object.assign(U,$);let[G,V]=await this.raw.putMetadata(K.id,U);Y[J]=G;let[z,H]=await this.raw.putEntries(Q,Y,X),j=Promise.all([V,H]);return[z,j]}async#U(Q,q,$=!1){let[X,Y,J]=await this.#X($),{entries:K}=await this.raw.getEntries("root.docSchema",X),U=K.findIndex((Z)=>Z.hash===Q),G=K[U];if(G===void 0)throw new k6(Q);let[V,z]=await this.#z(G.id,Q,q,J);K[U]=V;let[H,j]=await this.raw.putEntries("root",K,4);return await Promise.all([z,j]),await this.#Y(H.hash,Y),{hash:V.hash}}async move(Q,q,$=!1){if(!t2.test(q))throw new I2(q,t2,"parent must be a valid document id");return await this.#U(Q,{parent:q},$)}async delete(Q,q=!1){return await this.move(Q,"trash",q)}async rename(Q,q,$=!1){return await this.#U(Q,{visibleName:q},$)}async stared(Q,q,$=!1){return await this.#U(Q,{pinned:q},$)}async bulkMove(Q,q,$=!1){if(!t2.test(q))throw new I2(q,t2,"parent must be a valid document id");let[X,Y,J]=await this.#X($),{entries:K}=await this.raw.getEntries("root.docSchema",X),U=new Set(Q),G=[],V=[];for(let g of K)(U.has(g.hash)?G:V).push(g);let z=await Promise.all(G.map(({id:g,hash:C})=>this.#z(g,C,{parent:q},J))),H=[],j={};for(let[g,[C,N]]of z.entries())V.push(C),H.push(N),j[G[g].hash]=C.hash;let[Z,h]=await this.raw.putEntries("root",V,4);return await Promise.all([Promise.all(H),h]),await this.#Y(Z.hash,Y),{hashes:j}}async bulkDelete(Q,q=!1){return await this.bulkMove(Q,"trash",q)}dumpCache(){return this.raw.dumpCache()}async pruneCache(Q){let[q]=await this.#X(Q),$=new Set(this.#q.keys()),Y=[(await this.raw.getEntries("root.docSchema",q)).entries],J=[];while(Y.length){for(let U of Y)for(let{hash:G,type:V,id:z}of U)if($.add(G),V===80000000)J.push(this.raw.getEntries(`${z}.docSchema`,G));Y=(await Promise.all(J)).map((U)=>U.entries),J=[]}for(let K of $)this.#q.delete(K)}clearCache(){this.raw.clearCache()}}var mw=S6(E6(F0()));async function dw(Q,{authHost:q=YU}={}){let $=await fetch(`${q}/token/json/2/user/new`,{method:"POST",headers:{Authorization:`Bearer ${Q}`}});if(!$.ok)throw Error(`couldn't fetch auth token: ${$.statusText}`);return await $.text()}function lw(Q,{rawHost:q=cw,uploadHost:$=pw,cache:X,maxCacheSize:Y=1/0}={}){let J=JSON.parse(X??"{}");if(mw.guard(J)){let K=Object.entries(J),U=Y===1/0?new Map(K):new l4(Y,K);return new JU(Q,q,$,U)}throw 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.")}async function cC(Q,q={}){let{authHost:$,rawHost:X,uploadHost:Y,cache:J,maxCacheSize:K,syncHost:U}=q??{},G=await dw(Q,{authHost:$});return lw(G,{rawHost:X,uploadHost:Y,cache:J,maxCacheSize:K,syncHost:U})}export{lw as session,cC as remarkable,uC as register,dw as auth,I2 as ValidationError,oQ as ResponseError,k6 as HashNotFoundError,iQ as GenerationError};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rmapi-js",
3
- "version": "10.0.1",
3
+ "version": "10.1.1",
4
4
  "description": "JavaScript implementation of the reMarkable 1.5 api",
5
5
  "repository": {
6
6
  "type": "git",