rmapi-js 9.0.3 → 10.0.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.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { type BackgroundFilter, type CollectionContent, type Content, type DocumentContent, type Metadata, type Orientation, type RawRemarkableApi, type SimpleEntry, type Tag, type TemplateContent, type TextAlignment, type ZoomMode } from "./raw";
2
2
  export { HashNotFoundError, ValidationError } from "./error";
3
- export type { BackgroundFilter, CollectionContent, Content, CPageNumberValue, CPagePage, CPageStringValue, CPages, CPageUUID, DocumentContent, DocumentMetadata, Entries, FileType, KeyboardMetadata, Metadata, Orientation, PageTag, RawEntry, RawRemarkableApi, SchemaVersion, SimpleEntry, Tag, TemplateContent, TextAlignment, UploadMimeType, ZoomMode, } from "./raw";
3
+ 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";
4
4
  /** common properties shared by collections and documents */
5
5
  export interface EntryCommon {
6
6
  /** the document id, a uuid4 */
@@ -21,7 +21,7 @@ export interface EntryCommon {
21
21
  */
22
22
  parent?: string;
23
23
  /** any tags the entry might have */
24
- tags?: Tag[];
24
+ tags?: Tag[] | string[];
25
25
  }
26
26
  /** a folder, referred to in the api as a collection */
27
27
  export interface CollectionEntry extends EntryCommon {
@@ -228,10 +228,11 @@ export interface RemarkableApi {
228
228
  * the low-level api to get the raw text of the `.content` file in the
229
229
  * `RawEntry` for this hash.
230
230
  *
231
+ * @param id - the id of the item (as returned by `listIds`)
231
232
  * @param hash - the hash of the item to get content for
232
233
  * @returns the content
233
234
  */
234
- getContent(hash: string): Promise<Content>;
235
+ getContent(id: string, hash: string): Promise<Content>;
235
236
  /**
236
237
  * get the metadata from an item hash
237
238
  *
@@ -243,30 +244,33 @@ export interface RemarkableApi {
243
244
  * the low-level api to get the raw text of the `.metadata` file in the
244
245
  * `RawEntry` for this hash.
245
246
  *
247
+ * @param id - the id of the item (as returned by `listIds`)
246
248
  * @param hash - the hash of the item to get metadata for
247
249
  * @returns the metadata
248
250
  */
249
- getMetadata(hash: string): Promise<Metadata>;
251
+ getMetadata(id: string, hash: string): Promise<Metadata>;
250
252
  /**
251
253
  * get the pdf associated with a document hash
252
254
  *
253
255
  * This returns the raw input pdf, not the rendered pdf with any markup.
254
256
  *
257
+ * @param id - the id of the document (as returned by `listIds`)
255
258
  * @param hash - the hash of the document to get the pdf for (e.g. the hash
256
259
  * received from `listItems`)
257
260
  * @returns the pdf bytes
258
261
  */
259
- getPdf(hash: string): Promise<Uint8Array>;
262
+ getPdf(id: string, hash: string): Promise<Uint8Array>;
260
263
  /**
261
264
  * get the epub associated with a document hash
262
265
  *
263
266
  * This returns the raw input epub if a document was created from an epub.
264
267
  *
265
- * @param hash - the hash of the document to get the pdf for (e.g. the hash
268
+ * @param id - the id of the document (as returned by `listIds`)
269
+ * @param hash - the hash of the document to get the epub for (e.g. the hash
266
270
  * received from `listItems`)
267
271
  * @returns the epub bytes
268
272
  */
269
- getEpub(hash: string): Promise<Uint8Array>;
273
+ getEpub(id: string, hash: string): Promise<Uint8Array>;
270
274
  /**
271
275
  * get the entire contents of a remarkable document
272
276
  *
@@ -278,10 +282,11 @@ export interface RemarkableApi {
278
282
  * of the document, but this format isn't understood enoguh to reput this on a
279
283
  * different remarkable, so that functionality is currently disabled.
280
284
  *
281
- * @param hash - the hash of the document to get the contents for (e.g. the
285
+ * @param id - the id of the document (as returned by `listIds`)
286
+ * @param hash - the hash of the document to get contents for (e.g. the
282
287
  * hash received from `listItems`)
283
288
  */
284
- getDocument(hash: string): Promise<Uint8Array>;
289
+ getDocument(id: string, hash: string): Promise<Uint8Array>;
285
290
  /**
286
291
  * use the low-level api to add a pdf document
287
292
  *
package/dist/index.js CHANGED
@@ -180,18 +180,18 @@ class Remarkable {
180
180
  }
181
181
  }
182
182
  async #convertEntry({ hash, id }) {
183
- const { entries } = await this.raw.getEntries(hash);
183
+ const { entries } = await this.raw.getEntries(`${id}.docSchema`, hash);
184
184
  const metaEnt = entries.find((ent) => ent.id.endsWith(".metadata"));
185
185
  const contentEnt = entries.find((ent) => ent.id.endsWith(".content"));
186
186
  if (metaEnt === undefined) {
187
187
  throw new Error(`couldn't find metadata for hash ${hash}`);
188
188
  }
189
189
  const [{ visibleName, lastModified, pinned, parent, lastOpened, new: isNew, source, }, content,] = await Promise.all([
190
- this.raw.getMetadata(metaEnt.hash),
190
+ this.raw.getMetadata(metaEnt.id, metaEnt.hash),
191
191
  // collections don't always have content, since content only lists tags
192
192
  contentEnt === undefined
193
193
  ? Promise.resolve({ fileType: undefined, tags: undefined })
194
- : this.raw.getContent(contentEnt.hash),
194
+ : this.raw.getContent(contentEnt.id, contentEnt.hash),
195
195
  ]);
196
196
  if ("templateVersion" in content) {
197
197
  return {
@@ -240,55 +240,55 @@ class Remarkable {
240
240
  }
241
241
  async listIds(refresh = false) {
242
242
  const [hash] = await this.#getRootHash(refresh);
243
- const { entries } = await this.raw.getEntries(hash);
243
+ const { entries } = await this.raw.getEntries("root.docSchema", hash);
244
244
  return entries.map(({ id, hash }) => ({ id, hash }));
245
245
  }
246
- async getContent(hash) {
247
- const { entries } = await this.raw.getEntries(hash);
246
+ async getContent(id, hash) {
247
+ const { entries } = await this.raw.getEntries(`${id}.docSchema`, hash);
248
248
  const [cont] = entries.filter((e) => e.id.endsWith(".content"));
249
249
  if (cont === undefined) {
250
250
  throw new Error(`couldn't find contents for hash ${hash}`);
251
251
  }
252
252
  else {
253
- return await this.raw.getContent(cont.hash);
253
+ return await this.raw.getContent(cont.id, cont.hash);
254
254
  }
255
255
  }
256
- async getMetadata(hash) {
257
- const { entries } = await this.raw.getEntries(hash);
256
+ async getMetadata(id, hash) {
257
+ const { entries } = await this.raw.getEntries(`${id}.docSchema`, hash);
258
258
  const [meta] = entries.filter((e) => e.id.endsWith(".metadata"));
259
259
  if (meta === undefined) {
260
260
  throw new Error(`couldn't find metadata for hash ${hash}`);
261
261
  }
262
262
  else {
263
- return await this.raw.getMetadata(meta.hash);
263
+ return await this.raw.getMetadata(meta.id, meta.hash);
264
264
  }
265
265
  }
266
- async getPdf(hash) {
267
- const { entries } = await this.raw.getEntries(hash);
266
+ async getPdf(id, hash) {
267
+ const { entries } = await this.raw.getEntries(`${id}.docSchema`, hash);
268
268
  const [pdf] = entries.filter((e) => e.id.endsWith(".pdf"));
269
269
  if (pdf === undefined) {
270
270
  throw new Error(`couldn't find pdf for hash ${hash}`);
271
271
  }
272
272
  else {
273
- return await this.raw.getHash(pdf.hash);
273
+ return await this.raw.getHash(pdf.id, pdf.hash);
274
274
  }
275
275
  }
276
- async getEpub(hash) {
277
- const { entries } = await this.raw.getEntries(hash);
276
+ async getEpub(id, hash) {
277
+ const { entries } = await this.raw.getEntries(`${id}.docSchema`, hash);
278
278
  const [epub] = entries.filter((e) => e.id.endsWith(".epub"));
279
279
  if (epub === undefined) {
280
280
  throw new Error(`couldn't find epub for hash ${hash}`);
281
281
  }
282
282
  else {
283
- return await this.raw.getHash(epub.hash);
283
+ return await this.raw.getHash(epub.id, epub.hash);
284
284
  }
285
285
  }
286
- async getDocument(hash) {
287
- const { entries } = await this.raw.getEntries(hash);
286
+ async getDocument(id, hash) {
287
+ const { entries } = await this.raw.getEntries(`${id}.docSchema`, hash);
288
288
  const zip = new JSZip();
289
289
  for (const entry of entries) {
290
290
  // TODO if this is .metadata we might want to assert type === "DocumentType"
291
- zip.file(entry.id, this.raw.getHash(entry.hash));
291
+ zip.file(entry.id, this.raw.getHash(entry.id, entry.hash));
292
292
  }
293
293
  return zip.generateAsync({ type: "uint8array" });
294
294
  }
@@ -344,7 +344,7 @@ class Remarkable {
344
344
  // now fetch root entries and upload this file entry
345
345
  const [[collectionEntry, uploadCollection], { entries: rootEntries }] = await Promise.all([
346
346
  this.raw.putEntries(id, [contentEntry, metadataEntry, pagedataEntry, fileEntry], schemaVersion),
347
- this.raw.getEntries(rootHash),
347
+ this.raw.getEntries("root.docSchema", rootHash),
348
348
  ]);
349
349
  // now upload a new root entry
350
350
  rootEntries.push(collectionEntry);
@@ -398,7 +398,7 @@ class Remarkable {
398
398
  // now fetch root entries and upload this file entry
399
399
  const [[collectionEntry, uploadCollection], { entries: rootEntries }] = await Promise.all([
400
400
  this.raw.putEntries(id, [contentEntry, metadataEntry], schemaVersion),
401
- this.raw.getEntries(rootHash),
401
+ this.raw.getEntries("root.docSchema", rootHash),
402
402
  ]);
403
403
  // now upload a new root entry
404
404
  rootEntries.push(collectionEntry);
@@ -428,13 +428,13 @@ class Remarkable {
428
428
  }
429
429
  /** edit just a content entry */
430
430
  async #editContentRaw(id, hash, update, schemaVersion) {
431
- const { entries } = await this.raw.getEntries(hash);
431
+ const { entries } = await this.raw.getEntries(`${id}.docSchema`, hash);
432
432
  const contInd = entries.findIndex((ent) => ent.id.endsWith(".content"));
433
433
  const contEntry = entries[contInd];
434
434
  if (contEntry === undefined) {
435
435
  throw new Error("internal error: couldn't find content in entry hash");
436
436
  }
437
- const cont = await this.raw.getContent(contEntry.hash);
437
+ const cont = await this.raw.getContent(contEntry.id, contEntry.hash);
438
438
  Object.assign(cont, update);
439
439
  const [newContEntry, uploadCont] = await this.raw.putContent(contEntry.id, cont);
440
440
  entries[contInd] = newContEntry;
@@ -445,7 +445,7 @@ class Remarkable {
445
445
  /** fully sync a content edit */
446
446
  async #editContent(hash, update, expectedType, refresh) {
447
447
  const [rootHash, generation, schemaVersion] = await this.#getRootHash(refresh);
448
- const { entries } = await this.raw.getEntries(rootHash);
448
+ const { entries } = await this.raw.getEntries("root.docSchema", rootHash);
449
449
  const hashInd = entries.findIndex((ent) => ent.hash === hash);
450
450
  const hashEnt = entries[hashInd];
451
451
  if (hashEnt === undefined) {
@@ -453,7 +453,7 @@ class Remarkable {
453
453
  }
454
454
  const [[newEnt, uploadEnt], meta] = await Promise.all([
455
455
  this.#editContentRaw(hashEnt.id, hash, update, schemaVersion),
456
- this.getMetadata(hash),
456
+ this.getMetadata(hashEnt.id, hash),
457
457
  ]);
458
458
  if (meta.type !== expectedType) {
459
459
  throw new Error(`expected type ${expectedType} but got ${meta.type} for hash ${hash}`);
@@ -477,13 +477,13 @@ class Remarkable {
477
477
  return await this.#editContent(hash, content, "TemplateType", refresh);
478
478
  }
479
479
  async #editMetaRaw(id, hash, update, schemaVersion) {
480
- const { entries } = await this.raw.getEntries(hash);
480
+ const { entries } = await this.raw.getEntries(`${id}.docSchema`, hash);
481
481
  const metaInd = entries.findIndex((ent) => ent.id.endsWith(".metadata"));
482
482
  const metaEntry = entries[metaInd];
483
483
  if (metaEntry === undefined) {
484
484
  throw new Error("internal error: couldn't find metadata in entry hash");
485
485
  }
486
- const meta = await this.raw.getMetadata(metaEntry.hash);
486
+ const meta = await this.raw.getMetadata(metaEntry.id, metaEntry.hash);
487
487
  Object.assign(meta, update);
488
488
  const [newMetaEntry, uploadMeta] = await this.raw.putMetadata(metaEntry.id, meta);
489
489
  entries[metaInd] = newMetaEntry;
@@ -493,7 +493,7 @@ class Remarkable {
493
493
  }
494
494
  async #editMeta(hash, update, refresh = false) {
495
495
  const [rootHash, generation, schemaVersion] = await this.#getRootHash(refresh);
496
- const { entries } = await this.raw.getEntries(rootHash);
496
+ const { entries } = await this.raw.getEntries("root.docSchema", rootHash);
497
497
  const hashInd = entries.findIndex((ent) => ent.hash === hash);
498
498
  const hashEnt = entries[hashInd];
499
499
  if (hashEnt === undefined) {
@@ -531,7 +531,7 @@ class Remarkable {
531
531
  throw new ValidationError(parent, idReg, "parent must be a valid document id");
532
532
  }
533
533
  const [rootHash, generation, schemaVersion] = await this.#getRootHash(refresh);
534
- const { entries } = await this.raw.getEntries(rootHash);
534
+ const { entries } = await this.raw.getEntries("root.docSchema", rootHash);
535
535
  const hashSet = new Set(hashes);
536
536
  const toUpdate = [];
537
537
  const newEntries = [];
@@ -568,15 +568,15 @@ class Remarkable {
568
568
  // should only go one step) to track all hashes encountered
569
569
  // NOTE that we could increase the cache in this process, or it's possible
570
570
  // for other calls to increase the cache with misc values.
571
- const base = await this.raw.getEntries(rootHash);
571
+ const base = await this.raw.getEntries("root.docSchema", rootHash);
572
572
  let entries = [base.entries];
573
573
  let nextEntries = [];
574
574
  while (entries.length) {
575
575
  for (const entryList of entries) {
576
- for (const { hash, type } of entryList) {
576
+ for (const { hash, type, id } of entryList) {
577
577
  toDelete.add(hash);
578
578
  if (type === 80000000) {
579
- nextEntries.push(this.raw.getEntries(hash));
579
+ nextEntries.push(this.raw.getEntries(`${id}.docSchema`, hash));
580
580
  }
581
581
  }
582
582
  }
package/dist/raw.d.ts CHANGED
@@ -147,13 +147,21 @@ export interface CollectionContent {
147
147
  /** collections don't have a file type */
148
148
  fileType?: undefined;
149
149
  }
150
+ /** legacy collection content can store tags as raw strings */
151
+ export interface LegacyCollectionContent {
152
+ /** the legacy tag names for the collection */
153
+ tags?: string[];
154
+ /** collections don't have a file type */
155
+ fileType?: undefined;
156
+ }
150
157
  /**
151
158
  * content metadata, stored with the "content" extension
152
159
  *
153
160
  * This largely contains description of how to render the document, rather than
154
161
  * metadata about it.
155
162
  */
156
- export interface DocumentContent {
163
+ /** fields shared by current and legacy document content payloads */
164
+ export interface CommonDocumentContent {
157
165
  /**
158
166
  * which page to use for the thumbnail
159
167
  *
@@ -209,8 +217,6 @@ export interface DocumentContent {
209
217
  redirectionPageMap?: number[];
210
218
  /** ostensibly the size in bytes of the file, but this differs from other measurements */
211
219
  sizeInBytes: string;
212
- /** document tags for this document */
213
- tags?: Tag[];
214
220
  /** text alignment for this document */
215
221
  textAlignment: TextAlignment;
216
222
  /**
@@ -269,6 +275,16 @@ export interface DocumentContent {
269
275
  */
270
276
  viewBackgroundFilter?: BackgroundFilter;
271
277
  }
278
+ /** document content with modern structured tag payloads */
279
+ export interface DocumentContent extends CommonDocumentContent {
280
+ /** document tags for this document */
281
+ tags?: Tag[];
282
+ }
283
+ /** legacy document content can store tags as raw strings */
284
+ export interface LegacyDocumentContent extends CommonDocumentContent {
285
+ /** the legacy tag names for this document */
286
+ tags?: string[];
287
+ }
272
288
  /**
273
289
  * content metadata, stored with the "content" extension
274
290
  *
@@ -307,7 +323,7 @@ export interface TemplateContent {
307
323
  items: object[];
308
324
  }
309
325
  /** content metadata for any item */
310
- export type Content = CollectionContent | DocumentContent | TemplateContent;
326
+ export type Content = CollectionContent | LegacyCollectionContent | DocumentContent | LegacyDocumentContent | TemplateContent;
311
327
  /**
312
328
  * item level metadata
313
329
  *
@@ -431,50 +447,58 @@ export interface RawRemarkableApi {
431
447
  /**
432
448
  * get the raw binary data associated with a hash
433
449
  *
450
+ * @param fileName - the logical file name (`<id>.<ext>` for files, or
451
+ * `<id>.docSchema` / `"root.docSchema"` for entry indexes). reMarkable
452
+ * validates this against the rm-filename header.
434
453
  * @param hash - the hash to get the data for
435
454
  * @returns the data
436
455
  */
437
- getHash(hash: string): Promise<Uint8Array>;
456
+ getHash(fileName: string, hash: string): Promise<Uint8Array>;
438
457
  /**
439
458
  * get raw text data associated with a hash
440
459
  *
441
460
  * We assume text data are small, and so cache the entire text. If you want to
442
461
  * avoid this, use {@link getHash | `getHash`} combined with a TextDecoder.
443
462
 
463
+ * @param fileName - the logical file name (see {@link getHash})
444
464
  * @param hash - the hash to get text for
445
465
  * @returns the text
446
466
  */
447
- getText(hash: string): Promise<string>;
467
+ getText(fileName: string, hash: string): Promise<string>;
448
468
  /**
449
469
  * get the entries associated with a list hash
450
470
  *
451
471
  * A list hash is the root hash, or any hash with the type 80000000. NOTE
452
472
  * these are hashed differently than files.
453
473
 
474
+ * @param fileName - `"root.docSchema"` for the root, or `"<id>.docSchema"`
475
+ * for a sub-document's entry index
454
476
  * @param hash - the hash to get entries for
455
477
  * @returns the entries
456
478
  */
457
- getEntries(hash: string): Promise<Entries>;
479
+ getEntries(fileName: string, hash: string): Promise<Entries>;
458
480
  /**
459
481
  * get the parsed and validated `Content` of a content hash
460
482
  *
461
483
  * Use {@link getText | `getText`} combined with `JSON.parse` to bypass
462
484
  * validation
463
485
 
486
+ * @param fileName - typically `"<id>.content"`
464
487
  * @param hash - the hash to get Content for
465
488
  * @returns the content
466
489
  */
467
- getContent(hash: string): Promise<Content>;
490
+ getContent(fileName: string, hash: string): Promise<Content>;
468
491
  /**
469
492
  * get the parsed and validated `Metadata` of a metadata hash
470
493
  *
471
494
  * Use {@link getText | `getText`} combined with `JSON.parse` to bypass
472
495
  * validation
473
496
 
497
+ * @param fileName - typically `"<id>.metadata"`
474
498
  * @param hash - the hash to get Metadata for
475
499
  * @returns the metadata
476
500
  */
477
- getMetadata(hash: string): Promise<Metadata>;
501
+ getMetadata(fileName: string, hash: string): Promise<Metadata>;
478
502
  /**
479
503
  * update the current root hash
480
504
  *
@@ -564,11 +588,11 @@ export declare class RawRemarkable implements RawRemarkableApi {
564
588
  constructor(authedFetch: AuthedFetch, cache: Map<string, string | null>, rawHost: string, uploadHost: string);
565
589
  /** make an authorized request to remarkable */
566
590
  getRootHash(): Promise<[string, number, SchemaVersion]>;
567
- getHash(hash: string): Promise<Uint8Array>;
568
- getText(hash: string): Promise<string>;
569
- getEntries(hash: string): Promise<Entries>;
570
- getContent(hash: string): Promise<Content>;
571
- getMetadata(hash: string): Promise<Metadata>;
591
+ getHash(fileName: string, hash: string): Promise<Uint8Array>;
592
+ getText(fileName: string, hash: string): Promise<string>;
593
+ getEntries(fileName: string, hash: string): Promise<Entries>;
594
+ getContent(fileName: string, hash: string): Promise<Content>;
595
+ getMetadata(fileName: string, hash: string): Promise<Metadata>;
572
596
  putRootHash(hash: string, generation: number, broadcast?: boolean): Promise<[string, number]>;
573
597
  putFile(id: string, bytes: Uint8Array): Promise<[RawEntry, Promise<void>]>;
574
598
  putText(id: string, text: string): Promise<[RawEntry, Promise<void>]>;
package/dist/raw.js CHANGED
@@ -65,7 +65,10 @@ const cPages = properties({
65
65
  const collectionContent = properties(undefined, {
66
66
  tags: elements(tag),
67
67
  });
68
- const documentContent = properties({
68
+ const legacyCollectionContent = properties(undefined, {
69
+ tags: elements(string()),
70
+ });
71
+ const documentContentRequired = {
69
72
  coverPageNumber: int32(),
70
73
  documentMetadata,
71
74
  extraMetadata: values(string()),
@@ -77,7 +80,8 @@ const documentContent = properties({
77
80
  sizeInBytes: string(),
78
81
  textAlignment: enumeration("", "justify", "left"),
79
82
  textScale: float64(),
80
- }, {
83
+ };
84
+ const documentContentOptional = {
81
85
  cPages,
82
86
  customZoomCenterX: float64(),
83
87
  customZoomCenterY: float64(),
@@ -97,7 +101,6 @@ const documentContent = properties({
97
101
  pages: nullable(elements(string())),
98
102
  pageTags: elements(pageTag),
99
103
  redirectionPageMap: elements(int32()),
100
- tags: elements(tag),
101
104
  transform: properties(undefined, {
102
105
  m11: float64(),
103
106
  m12: float64(),
@@ -112,6 +115,14 @@ const documentContent = properties({
112
115
  // eslint-disable-next-line spellcheck/spell-checker
113
116
  viewBackgroundFilter: enumeration("off", "fullpage"),
114
117
  zoomMode: enumeration("bestFit", "customFit", "fitToHeight", "fitToWidth"),
118
+ };
119
+ const documentContent = properties(documentContentRequired, {
120
+ ...documentContentOptional,
121
+ tags: elements(tag),
122
+ }, true);
123
+ const legacyDocumentContent = properties(documentContentRequired, {
124
+ ...documentContentOptional,
125
+ tags: elements(string()),
115
126
  }, true);
116
127
  const templateContent = properties({
117
128
  name: string(),
@@ -222,23 +233,23 @@ export class RawRemarkable {
222
233
  return [hash, generation, schemaVersion];
223
234
  }
224
235
  }
225
- async #getHash(hash) {
236
+ async #getHash(fileName, hash) {
226
237
  if (!hashReg.test(hash)) {
227
238
  throw new ValidationError(hash, hashReg, "hash was not a valid hash");
228
239
  }
229
- const resp = await this.#authedFetch("GET", `${this.#rawHost}/sync/v3/files/${hash}`);
240
+ const resp = await this.#authedFetch("GET", `${this.#rawHost}/sync/v3/files/${hash}`, { headers: { "rm-filename": fileName } });
230
241
  // TODO switch to `.bytes()`.
231
242
  const raw = await resp.arrayBuffer();
232
243
  return new Uint8Array(raw);
233
244
  }
234
- async getHash(hash) {
245
+ async getHash(fileName, hash) {
235
246
  const cached = this.#cache.get(hash);
236
247
  if (cached != null) {
237
248
  const enc = new TextEncoder();
238
249
  return enc.encode(cached);
239
250
  }
240
251
  else {
241
- const res = await this.#getHash(hash);
252
+ const res = await this.#getHash(fileName, hash);
242
253
  // mark that we know hash exists
243
254
  const cacheVal = this.#cache.get(hash);
244
255
  if (cacheVal === undefined) {
@@ -247,22 +258,22 @@ export class RawRemarkable {
247
258
  return res;
248
259
  }
249
260
  }
250
- async getText(hash) {
261
+ async getText(fileName, hash) {
251
262
  const cached = this.#cache.get(hash);
252
263
  if (cached != null) {
253
264
  return cached;
254
265
  }
255
266
  else {
256
267
  // NOTE two simultaneous requests will fetch twice
257
- const raw = await this.#getHash(hash);
268
+ const raw = await this.#getHash(fileName, hash);
258
269
  const dec = new TextDecoder();
259
270
  const res = dec.decode(raw);
260
271
  this.#cache.set(hash, res);
261
272
  return res;
262
273
  }
263
274
  }
264
- async getEntries(hash) {
265
- const rawFile = await this.getText(hash);
275
+ async getEntries(fileName, hash) {
276
+ const rawFile = await this.getText(fileName, hash);
266
277
  const [version, ...rest] = rawFile.slice(0, -1).split("\n");
267
278
  if (version === "3") {
268
279
  return { entries: rest.map(parseRawEntryLine) };
@@ -290,16 +301,18 @@ export class RawRemarkable {
290
301
  throw new Error(`schema version ${version} not supported`);
291
302
  }
292
303
  }
293
- async getContent(hash) {
294
- const raw = await this.getText(hash);
304
+ async getContent(fileName, hash) {
305
+ const raw = await this.getText(fileName, hash);
295
306
  const loaded = JSON.parse(raw);
296
307
  // jtd can't verify non-discriminated unions, in this case, we have fileType
297
308
  // defined or not. As a result, we try each, and concatenate the errors at the end
298
309
  const errors = [];
299
310
  for (const [name, valid] of [
300
311
  ["collection", collectionContent],
312
+ ["legacy collection", legacyCollectionContent],
301
313
  ["template", templateContent],
302
314
  ["document", documentContent],
315
+ ["legacy document", legacyDocumentContent],
303
316
  ]) {
304
317
  try {
305
318
  if (valid.guardAssert(loaded))
@@ -313,8 +326,8 @@ export class RawRemarkable {
313
326
  const joined = errors.join("\n\nor\n\n");
314
327
  throw new Error(`invalid content: ${joined}`);
315
328
  }
316
- async getMetadata(hash) {
317
- const raw = await this.getText(hash);
329
+ async getMetadata(fileName, hash) {
330
+ const raw = await this.getText(fileName, hash);
318
331
  const loaded = JSON.parse(raw);
319
332
  if (!metadata.guardAssert(loaded))
320
333
  throw Error("invalid metadata");
@@ -345,7 +358,7 @@ export class RawRemarkable {
345
358
  throw new Error(`new generation ${newGen} was not a safe integer; please file a bug report`);
346
359
  }
347
360
  }
348
- async #putFile(hash, fileName, bytes) {
361
+ async #putFile(fileName, hash, bytes) {
349
362
  // if the hash is already in the cache, writing is pointless
350
363
  if (!this.#cache.has(hash)) {
351
364
  const crc = CRC32C.buf(bytes, 0);
@@ -376,7 +389,7 @@ export class RawRemarkable {
376
389
  subfiles: 0,
377
390
  size: bytes.length,
378
391
  };
379
- return [res, this.#putFile(hash, id, bytes)];
392
+ return [res, this.#putFile(id, hash, bytes)];
380
393
  }
381
394
  async putText(id, text) {
382
395
  const enc = new TextEncoder();
@@ -444,11 +457,7 @@ export class RawRemarkable {
444
457
  subfiles: entries.length,
445
458
  size,
446
459
  };
447
- return [
448
- res,
449
- // NOTE when monitoring requests, this had the extension .docSchema appended, but I'm not entirely sure why
450
- this.#putFile(hash, `${id}.docSchema`, entryBuff),
451
- ];
460
+ return [res, this.#putFile(`${id}.docSchema`, hash, entryBuff)];
452
461
  }
453
462
  async uploadFile(visibleName, bytes, mime) {
454
463
  const enc = new TextEncoder();