rmapi-js 10.0.1 → 10.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/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
@@ -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
@@ -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(""));
@@ -15,9 +15,9 @@ ${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.0",
4
4
  "description": "JavaScript implementation of the reMarkable 1.5 api",
5
5
  "repository": {
6
6
  "type": "git",