@remix-run/file-storage 0.9.0 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -20,30 +20,30 @@ npm install @remix-run/file-storage
20
20
  ## Usage
21
21
 
22
22
  ```ts
23
- import { LocalFileStorage } from '@remix-run/file-storage/local';
23
+ import { LocalFileStorage } from '@remix-run/file-storage/local'
24
24
 
25
- let storage = new LocalFileStorage('./user/files');
25
+ let storage = new LocalFileStorage('./user/files')
26
26
 
27
- let file = new File(['hello world'], 'hello.txt', { type: 'text/plain' });
28
- let key = 'hello-key';
27
+ let file = new File(['hello world'], 'hello.txt', { type: 'text/plain' })
28
+ let key = 'hello-key'
29
29
 
30
30
  // Put the file in storage.
31
- await storage.set(key, file);
31
+ await storage.set(key, file)
32
32
 
33
33
  // Then, sometime later...
34
- let fileFromStorage = await storage.get(key);
34
+ let fileFromStorage = await storage.get(key)
35
35
  // All of the original file's metadata is intact
36
- fileFromStorage.name; // 'hello.txt'
37
- fileFromStorage.type; // 'text/plain'
36
+ fileFromStorage.name // 'hello.txt'
37
+ fileFromStorage.type // 'text/plain'
38
38
 
39
39
  // To remove from storage
40
- await storage.remove(key);
40
+ await storage.remove(key)
41
41
  ```
42
42
 
43
43
  The `FileStorage` interface allows you to implement your own file storage for custom storage backends:
44
44
 
45
45
  ```ts
46
- import { type FileStorage } from '@remix-run/file-storage';
46
+ import { type FileStorage } from '@remix-run/file-storage'
47
47
 
48
48
  class CustomFileStorage implements FileStorage {
49
49
  /**
@@ -75,9 +75,9 @@ class CustomFileStorage implements FileStorage {
75
75
 
76
76
  ## Related Packages
77
77
 
78
- - [`form-data-parser`](https://github.com/remix-run/remix/tree/v3/packages/form-data-parser) - Pairs well with this library for storing `FileUpload` objects received in `multipart/form-data` requests
79
- - [`lazy-file`](https://github.com/remix-run/remix/tree/v3/packages/lazy-file) - The streaming `File` implementation used internally to stream files from storage
78
+ - [`form-data-parser`](https://github.com/remix-run/remix/tree/main/packages/form-data-parser) - Pairs well with this library for storing `FileUpload` objects received in `multipart/form-data` requests
79
+ - [`lazy-file`](https://github.com/remix-run/remix/tree/main/packages/lazy-file) - The streaming `File` implementation used internally to stream files from storage
80
80
 
81
81
  ## License
82
82
 
83
- See [LICENSE](https://github.com/remix-run/remix/blob/v3/LICENSE)
83
+ See [LICENSE](https://github.com/remix-run/remix/blob/main/LICENSE)
@@ -1,2 +1,2 @@
1
1
  export type { FileStorage, FileKey, FileMetadata, ListOptions, ListResult, } from './lib/file-storage.ts';
2
- //# sourceMappingURL=file-storage.d.ts.map
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,WAAW,EACX,OAAO,EACP,YAAY,EACZ,WAAW,EACX,UAAU,GACX,MAAM,uBAAuB,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1 @@
1
+ //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"file-storage.d.ts","sourceRoot":"","sources":["../../src/lib/file-storage.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B;;;;OAIG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC;IAErD;;;;OAIG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAE7C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA0DG;IACH,IAAI,CAAC,CAAC,SAAS,WAAW,EAAE,OAAO,CAAC,EAAE,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;IAEjF;;;;;;OAMG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEnD;;;;OAIG;IACH,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAE1C;;;;;;OAMG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACpD;AAED,MAAM,WAAW,OAAO;IACtB;;OAEG;IACH,GAAG,EAAE,MAAM,CAAC;CACb;AAED;;GAEG;AACH,MAAM,WAAW,YAAa,SAAQ,OAAO;IAC3C;;OAEG;IACH,YAAY,EAAE,MAAM,CAAC;IACrB;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IACb;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,WAAW;IAC1B;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,UAAU,CAAC,CAAC,SAAS,WAAW;IAC/C;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,KAAK,EAAE,CAAC,CAAC,SAAS;QAAE,eAAe,EAAE,IAAI,CAAA;KAAE,GAAG,YAAY,GAAG,OAAO,CAAC,EAAE,CAAC;CACzE"}
1
+ {"version":3,"file":"file-storage.d.ts","sourceRoot":"","sources":["../../src/lib/file-storage.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B;;;;OAIG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,CAAA;IAEpD;;;;OAIG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IAE5C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA0DG;IACH,IAAI,CAAC,CAAC,SAAS,WAAW,EAAE,OAAO,CAAC,EAAE,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAA;IAEhF;;;;;;OAMG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAElD;;;;OAIG;IACH,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;IAEzC;;;;;;OAMG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;CACnD;AAED,MAAM,WAAW,OAAO;IACtB;;OAEG;IACH,GAAG,EAAE,MAAM,CAAA;CACZ;AAED;;GAEG;AACH,MAAM,WAAW,YAAa,SAAQ,OAAO;IAC3C;;OAEG;IACH,YAAY,EAAE,MAAM,CAAA;IACpB;;OAEG;IACH,IAAI,EAAE,MAAM,CAAA;IACZ;;OAEG;IACH,IAAI,EAAE,MAAM,CAAA;IACZ;;OAEG;IACH,IAAI,EAAE,MAAM,CAAA;CACb;AAED,MAAM,WAAW,WAAW;IAC1B;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAA;IACf;;OAEG;IACH,eAAe,CAAC,EAAE,OAAO,CAAA;IACzB;;OAEG;IACH,KAAK,CAAC,EAAE,MAAM,CAAA;IACd;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,UAAU,CAAC,CAAC,SAAS,WAAW;IAC/C;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAA;IACf;;OAEG;IACH,KAAK,EAAE,CAAC,CAAC,SAAS;QAAE,eAAe,EAAE,IAAI,CAAA;KAAE,GAAG,YAAY,GAAG,OAAO,CAAC,EAAE,CAAA;CACxE"}
@@ -1 +1 @@
1
- {"version":3,"file":"local-file-storage.d.ts","sourceRoot":"","sources":["../../src/lib/local-file-storage.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,WAAW,EAAgB,WAAW,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAI5F;;;;;;;;;;GAUG;AACH,qBAAa,gBAAiB,YAAW,WAAW;;IAGlD;;OAEG;gBACS,SAAS,EAAE,MAAM;IAkBvB,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC;IAoBtC,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAWlC,IAAI,CAAC,CAAC,SAAS,WAAW,EAAE,OAAO,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;IAgDhE,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAK3C,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAkBlC,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;CA2BlD"}
1
+ {"version":3,"file":"local-file-storage.d.ts","sourceRoot":"","sources":["../../src/lib/local-file-storage.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,WAAW,EAAgB,WAAW,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AAI3F;;;;;;;;;;GAUG;AACH,qBAAa,gBAAiB,YAAW,WAAW;;IAGlD;;OAEG;gBACS,SAAS,EAAE,MAAM;IAkBvB,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC;IAoBtC,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAWlC,IAAI,CAAC,CAAC,SAAS,WAAW,EAAE,OAAO,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;IAgDhE,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAK3C,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAkBlC,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;CA2BlD"}
@@ -1 +1 @@
1
- {"version":3,"file":"memory-file-storage.d.ts","sourceRoot":"","sources":["../../src/lib/memory-file-storage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE9E;;GAEG;AACH,qBAAa,iBAAkB,YAAW,WAAW;;IAGnD,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI;IAI7B,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAIzB,IAAI,CAAC,CAAC,SAAS,WAAW,EAAE,OAAO,CAAC,EAAE,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC;IAwCjD,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAKjD,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAInB,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;CASlD"}
1
+ {"version":3,"file":"memory-file-storage.d.ts","sourceRoot":"","sources":["../../src/lib/memory-file-storage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AAE7E;;GAEG;AACH,qBAAa,iBAAkB,YAAW,WAAW;;IAGnD,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI;IAI7B,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAIzB,IAAI,CAAC,CAAC,SAAS,WAAW,EAAE,OAAO,CAAC,EAAE,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC;IAwCjD,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;IAKjD,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI;IAInB,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;CASlD"}
@@ -1 +1 @@
1
- {"version":3,"file":"local.d.ts","sourceRoot":"","sources":["../src/local.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC"}
1
+ {"version":3,"file":"local.d.ts","sourceRoot":"","sources":["../src/local.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAA"}
package/dist/local.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/lib/local-file-storage.ts", "../../lazy-file/src/fs.ts", "../../../node_modules/.pnpm/mrmime@2.0.0/node_modules/mrmime/index.mjs", "../../lazy-file/src/lib/byte-range.ts", "../../lazy-file/src/lib/lazy-file.ts"],
4
- "sourcesContent": ["import * as fs from 'node:fs';\nimport * as fsp from 'node:fs/promises';\nimport * as path from 'node:path';\nimport { openFile, writeFile } from '@remix-run/lazy-file/fs';\n\nimport type { FileStorage, FileMetadata, ListOptions, ListResult } from './file-storage.ts';\n\ntype MetadataJson = Omit<FileMetadata, 'size'>;\n\n/**\n * A `FileStorage` that is backed by a directory on the local filesystem.\n *\n * Important: No attempt is made to avoid overwriting existing files, so the directory used should\n * be a new directory solely dedicated to this storage object.\n *\n * Note: Keys have no correlation to file names on disk, so they may be any string including\n * characters that are not valid in file names. Additionally, individual `File` names have no\n * correlation to names of files on disk, so multiple files with the same name may be stored in the\n * same storage object.\n */\nexport class LocalFileStorage implements FileStorage {\n #dirname: string;\n\n /**\n * @param directory The directory where files are stored\n */\n constructor(directory: string) {\n this.#dirname = path.resolve(directory);\n\n try {\n let stats = fs.statSync(this.#dirname);\n\n if (!stats.isDirectory()) {\n throw new Error(`Path \"${this.#dirname}\" is not a directory`);\n }\n } catch (error) {\n if (!isNoEntityError(error)) {\n throw error;\n }\n\n fs.mkdirSync(this.#dirname, { recursive: true });\n }\n }\n\n async get(key: string): Promise<File | null> {\n let { filePath, metaPath } = await this.#getPaths(key);\n\n try {\n let meta = await readMetadata(metaPath);\n\n return openFile(filePath, {\n lastModified: meta.lastModified,\n name: meta.name,\n type: meta.type,\n });\n } catch (error) {\n if (!isNoEntityError(error)) {\n throw error;\n }\n\n return null;\n }\n }\n\n async has(key: string): Promise<boolean> {\n let { metaPath } = await this.#getPaths(key);\n\n try {\n await fsp.access(metaPath);\n return true;\n } catch {\n return false;\n }\n }\n\n async list<T extends ListOptions>(options?: T): Promise<ListResult<T>> {\n let { cursor, includeMetadata = false, limit = 32, prefix } = options ?? {};\n\n let files: any[] = [];\n let foundCursor = cursor === undefined;\n let nextCursor: string | undefined;\n let lastHash: string | undefined;\n\n outerLoop: for await (let subdir of await fsp.opendir(this.#dirname)) {\n if (!subdir.isDirectory()) continue;\n\n for await (let file of await fsp.opendir(path.join(this.#dirname, subdir.name))) {\n if (!file.isFile() || !file.name.endsWith('.meta.json')) continue;\n\n let hash = file.name.slice(0, -10); // Remove \".meta.json\"\n\n if (foundCursor) {\n let meta = await readMetadata(path.join(this.#dirname, subdir.name, file.name));\n\n if (prefix != null && !meta.key.startsWith(prefix)) {\n continue;\n }\n\n if (files.length >= limit) {\n nextCursor = lastHash;\n break outerLoop;\n }\n\n if (includeMetadata) {\n let size = (await fsp.stat(path.join(this.#dirname, subdir.name, `${hash}.dat`))).size;\n files.push({ ...meta, size });\n } else {\n files.push({ key: meta.key });\n }\n } else if (hash === cursor) {\n foundCursor = true;\n }\n\n lastHash = hash;\n }\n }\n\n return {\n cursor: nextCursor,\n files,\n };\n }\n\n async put(key: string, file: File): Promise<File> {\n await this.set(key, file);\n return (await this.get(key))!;\n }\n\n async remove(key: string): Promise<void> {\n let { directory, filePath, metaPath } = await this.#getPaths(key);\n\n try {\n await Promise.all([fsp.unlink(filePath), fsp.unlink(metaPath)]);\n\n // Check if directory is empty and remove it if so\n let files = await fsp.readdir(directory);\n if (files.length === 0) {\n await fsp.rmdir(directory);\n }\n } catch (error) {\n if (!isNoEntityError(error)) {\n throw error;\n }\n }\n }\n\n async set(key: string, file: File): Promise<void> {\n let { directory, filePath, metaPath } = await this.#getPaths(key);\n\n // Ensure directory exists\n await fsp.mkdir(directory, { recursive: true });\n\n await writeFile(filePath, file);\n\n let meta: MetadataJson = {\n key,\n lastModified: file.lastModified,\n name: file.name,\n type: file.type,\n };\n await fsp.writeFile(metaPath, JSON.stringify(meta));\n }\n\n async #getPaths(key: string): Promise<{ directory: string; filePath: string; metaPath: string }> {\n let hash = await computeHash(key);\n let directory = path.join(this.#dirname, hash.slice(0, 2));\n\n return {\n directory,\n filePath: path.join(directory, `${hash}.dat`),\n metaPath: path.join(directory, `${hash}.meta.json`),\n };\n }\n}\n\nasync function readMetadata(metaPath: string): Promise<MetadataJson> {\n return JSON.parse(await fsp.readFile(metaPath, 'utf-8'));\n}\n\nasync function computeHash(key: string, algorithm = 'SHA-256'): Promise<string> {\n let digest = await crypto.subtle.digest(algorithm, new TextEncoder().encode(key));\n return Array.from(new Uint8Array(digest))\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('');\n}\n\nfunction isNoEntityError(obj: unknown): obj is NodeJS.ErrnoException & { code: 'ENOENT' } {\n return obj instanceof Error && 'code' in obj && (obj as NodeJS.ErrnoException).code === 'ENOENT';\n}\n", "import * as fs from 'node:fs';\nimport * as path from 'node:path';\nimport { lookup } from 'mrmime';\n\nimport { type LazyContent, LazyFile } from './lib/lazy-file.ts';\n\nexport interface OpenFileOptions {\n /**\n * Overrides the name of the file. Default is the name of the file on disk.\n */\n name?: string;\n /**\n * Overrides the MIME type of the file. Default is determined by the file extension.\n */\n type?: string;\n /**\n * Overrides the last modified timestamp of the file. Default is the file's last modified time.\n */\n lastModified?: number;\n}\n\n/**\n * Returns a `File` from the local filesytem.\n *\n * [MDN `File` Reference](https://developer.mozilla.org/en-US/docs/Web/API/File)\n *\n * @param filename The path to the file\n * @param options Options to override the file's metadata\n * @returns A `File` object\n */\nexport function openFile(filename: string, options?: OpenFileOptions): File {\n let stats = fs.statSync(filename);\n\n if (!stats.isFile()) {\n throw new Error(`Path \"${filename}\" is not a file`);\n }\n\n let content: LazyContent = {\n byteLength: stats.size,\n stream(start, end) {\n return streamFile(filename, start, end);\n },\n };\n\n return new LazyFile(content, options?.name ?? path.basename(filename), {\n type: options?.type ?? lookup(filename),\n lastModified: options?.lastModified ?? stats.mtimeMs,\n });\n}\n\nfunction streamFile(filename: string, start = 0, end = Infinity): ReadableStream<Uint8Array> {\n let read = fs.createReadStream(filename, { start, end: end - 1 }).iterator();\n\n return new ReadableStream({\n async pull(controller) {\n let { done, value } = await read.next();\n\n if (done) {\n controller.close();\n } else {\n controller.enqueue(new Uint8Array(value.buffer, value.byteOffset, value.byteLength));\n }\n },\n });\n}\n\n// Preserve backwards compat with v3.0\nexport { type OpenFileOptions as GetFileOptions, openFile as getFile };\n\n/**\n * Writes a `File` to the local filesytem and resolves when the stream is finished.\n *\n * [MDN `File` Reference](https://developer.mozilla.org/en-US/docs/Web/API/File)\n *\n * @param to The path to write the file to, or an open file descriptor\n * @param file The file to write\n * @returns A promise that resolves when the file is written\n */\nexport function writeFile(to: string | number | fs.promises.FileHandle, file: File): Promise<void> {\n return new Promise(async (resolve, reject) => {\n let writeStream =\n typeof to === 'string'\n ? fs.createWriteStream(to)\n : fs.createWriteStream('ignored', { fd: to });\n\n try {\n for await (let chunk of file.stream()) {\n writeStream.write(chunk);\n }\n\n writeStream.end(() => {\n resolve();\n });\n } catch (error) {\n writeStream.end(() => {\n reject(error);\n });\n }\n });\n}\n", "const mimes = {\n \"3g2\": \"video/3gpp2\",\n \"3gp\": \"video/3gpp\",\n \"3gpp\": \"video/3gpp\",\n \"3mf\": \"model/3mf\",\n \"aac\": \"audio/aac\",\n \"ac\": \"application/pkix-attr-cert\",\n \"adp\": \"audio/adpcm\",\n \"adts\": \"audio/aac\",\n \"ai\": \"application/postscript\",\n \"aml\": \"application/automationml-aml+xml\",\n \"amlx\": \"application/automationml-amlx+zip\",\n \"amr\": \"audio/amr\",\n \"apng\": \"image/apng\",\n \"appcache\": \"text/cache-manifest\",\n \"appinstaller\": \"application/appinstaller\",\n \"appx\": \"application/appx\",\n \"appxbundle\": \"application/appxbundle\",\n \"asc\": \"application/pgp-keys\",\n \"atom\": \"application/atom+xml\",\n \"atomcat\": \"application/atomcat+xml\",\n \"atomdeleted\": \"application/atomdeleted+xml\",\n \"atomsvc\": \"application/atomsvc+xml\",\n \"au\": \"audio/basic\",\n \"avci\": \"image/avci\",\n \"avcs\": \"image/avcs\",\n \"avif\": \"image/avif\",\n \"aw\": \"application/applixware\",\n \"bdoc\": \"application/bdoc\",\n \"bin\": \"application/octet-stream\",\n \"bmp\": \"image/bmp\",\n \"bpk\": \"application/octet-stream\",\n \"btf\": \"image/prs.btif\",\n \"btif\": \"image/prs.btif\",\n \"buffer\": \"application/octet-stream\",\n \"ccxml\": \"application/ccxml+xml\",\n \"cdfx\": \"application/cdfx+xml\",\n \"cdmia\": \"application/cdmi-capability\",\n \"cdmic\": \"application/cdmi-container\",\n \"cdmid\": \"application/cdmi-domain\",\n \"cdmio\": \"application/cdmi-object\",\n \"cdmiq\": \"application/cdmi-queue\",\n \"cer\": \"application/pkix-cert\",\n \"cgm\": \"image/cgm\",\n \"cjs\": \"application/node\",\n \"class\": \"application/java-vm\",\n \"coffee\": \"text/coffeescript\",\n \"conf\": \"text/plain\",\n \"cpl\": \"application/cpl+xml\",\n \"cpt\": \"application/mac-compactpro\",\n \"crl\": \"application/pkix-crl\",\n \"css\": \"text/css\",\n \"csv\": \"text/csv\",\n \"cu\": \"application/cu-seeme\",\n \"cwl\": \"application/cwl\",\n \"cww\": \"application/prs.cww\",\n \"davmount\": \"application/davmount+xml\",\n \"dbk\": \"application/docbook+xml\",\n \"deb\": \"application/octet-stream\",\n \"def\": \"text/plain\",\n \"deploy\": \"application/octet-stream\",\n \"dib\": \"image/bmp\",\n \"disposition-notification\": \"message/disposition-notification\",\n \"dist\": \"application/octet-stream\",\n \"distz\": \"application/octet-stream\",\n \"dll\": \"application/octet-stream\",\n \"dmg\": \"application/octet-stream\",\n \"dms\": \"application/octet-stream\",\n \"doc\": \"application/msword\",\n \"dot\": \"application/msword\",\n \"dpx\": \"image/dpx\",\n \"drle\": \"image/dicom-rle\",\n \"dsc\": \"text/prs.lines.tag\",\n \"dssc\": \"application/dssc+der\",\n \"dtd\": \"application/xml-dtd\",\n \"dump\": \"application/octet-stream\",\n \"dwd\": \"application/atsc-dwd+xml\",\n \"ear\": \"application/java-archive\",\n \"ecma\": \"application/ecmascript\",\n \"elc\": \"application/octet-stream\",\n \"emf\": \"image/emf\",\n \"eml\": \"message/rfc822\",\n \"emma\": \"application/emma+xml\",\n \"emotionml\": \"application/emotionml+xml\",\n \"eps\": \"application/postscript\",\n \"epub\": \"application/epub+zip\",\n \"exe\": \"application/octet-stream\",\n \"exi\": \"application/exi\",\n \"exp\": \"application/express\",\n \"exr\": \"image/aces\",\n \"ez\": \"application/andrew-inset\",\n \"fdf\": \"application/fdf\",\n \"fdt\": \"application/fdt+xml\",\n \"fits\": \"image/fits\",\n \"g3\": \"image/g3fax\",\n \"gbr\": \"application/rpki-ghostbusters\",\n \"geojson\": \"application/geo+json\",\n \"gif\": \"image/gif\",\n \"glb\": \"model/gltf-binary\",\n \"gltf\": \"model/gltf+json\",\n \"gml\": \"application/gml+xml\",\n \"gpx\": \"application/gpx+xml\",\n \"gram\": \"application/srgs\",\n \"grxml\": \"application/srgs+xml\",\n \"gxf\": \"application/gxf\",\n \"gz\": \"application/gzip\",\n \"h261\": \"video/h261\",\n \"h263\": \"video/h263\",\n \"h264\": \"video/h264\",\n \"heic\": \"image/heic\",\n \"heics\": \"image/heic-sequence\",\n \"heif\": \"image/heif\",\n \"heifs\": \"image/heif-sequence\",\n \"hej2\": \"image/hej2k\",\n \"held\": \"application/atsc-held+xml\",\n \"hjson\": \"application/hjson\",\n \"hlp\": \"application/winhlp\",\n \"hqx\": \"application/mac-binhex40\",\n \"hsj2\": \"image/hsj2\",\n \"htm\": \"text/html\",\n \"html\": \"text/html\",\n \"ics\": \"text/calendar\",\n \"ief\": \"image/ief\",\n \"ifb\": \"text/calendar\",\n \"iges\": \"model/iges\",\n \"igs\": \"model/iges\",\n \"img\": \"application/octet-stream\",\n \"in\": \"text/plain\",\n \"ini\": \"text/plain\",\n \"ink\": \"application/inkml+xml\",\n \"inkml\": \"application/inkml+xml\",\n \"ipfix\": \"application/ipfix\",\n \"iso\": \"application/octet-stream\",\n \"its\": \"application/its+xml\",\n \"jade\": \"text/jade\",\n \"jar\": \"application/java-archive\",\n \"jhc\": \"image/jphc\",\n \"jls\": \"image/jls\",\n \"jp2\": \"image/jp2\",\n \"jpe\": \"image/jpeg\",\n \"jpeg\": \"image/jpeg\",\n \"jpf\": \"image/jpx\",\n \"jpg\": \"image/jpeg\",\n \"jpg2\": \"image/jp2\",\n \"jpgm\": \"image/jpm\",\n \"jpgv\": \"video/jpeg\",\n \"jph\": \"image/jph\",\n \"jpm\": \"image/jpm\",\n \"jpx\": \"image/jpx\",\n \"js\": \"text/javascript\",\n \"json\": \"application/json\",\n \"json5\": \"application/json5\",\n \"jsonld\": \"application/ld+json\",\n \"jsonml\": \"application/jsonml+json\",\n \"jsx\": \"text/jsx\",\n \"jt\": \"model/jt\",\n \"jxr\": \"image/jxr\",\n \"jxra\": \"image/jxra\",\n \"jxrs\": \"image/jxrs\",\n \"jxs\": \"image/jxs\",\n \"jxsc\": \"image/jxsc\",\n \"jxsi\": \"image/jxsi\",\n \"jxss\": \"image/jxss\",\n \"kar\": \"audio/midi\",\n \"ktx\": \"image/ktx\",\n \"ktx2\": \"image/ktx2\",\n \"less\": \"text/less\",\n \"lgr\": \"application/lgr+xml\",\n \"list\": \"text/plain\",\n \"litcoffee\": \"text/coffeescript\",\n \"log\": \"text/plain\",\n \"lostxml\": \"application/lost+xml\",\n \"lrf\": \"application/octet-stream\",\n \"m1v\": \"video/mpeg\",\n \"m21\": \"application/mp21\",\n \"m2a\": \"audio/mpeg\",\n \"m2v\": \"video/mpeg\",\n \"m3a\": \"audio/mpeg\",\n \"m4a\": \"audio/mp4\",\n \"m4p\": \"application/mp4\",\n \"m4s\": \"video/iso.segment\",\n \"ma\": \"application/mathematica\",\n \"mads\": \"application/mads+xml\",\n \"maei\": \"application/mmt-aei+xml\",\n \"man\": \"text/troff\",\n \"manifest\": \"text/cache-manifest\",\n \"map\": \"application/json\",\n \"mar\": \"application/octet-stream\",\n \"markdown\": \"text/markdown\",\n \"mathml\": \"application/mathml+xml\",\n \"mb\": \"application/mathematica\",\n \"mbox\": \"application/mbox\",\n \"md\": \"text/markdown\",\n \"mdx\": \"text/mdx\",\n \"me\": \"text/troff\",\n \"mesh\": \"model/mesh\",\n \"meta4\": \"application/metalink4+xml\",\n \"metalink\": \"application/metalink+xml\",\n \"mets\": \"application/mets+xml\",\n \"mft\": \"application/rpki-manifest\",\n \"mid\": \"audio/midi\",\n \"midi\": \"audio/midi\",\n \"mime\": \"message/rfc822\",\n \"mj2\": \"video/mj2\",\n \"mjp2\": \"video/mj2\",\n \"mjs\": \"text/javascript\",\n \"mml\": \"text/mathml\",\n \"mods\": \"application/mods+xml\",\n \"mov\": \"video/quicktime\",\n \"mp2\": \"audio/mpeg\",\n \"mp21\": \"application/mp21\",\n \"mp2a\": \"audio/mpeg\",\n \"mp3\": \"audio/mpeg\",\n \"mp4\": \"video/mp4\",\n \"mp4a\": \"audio/mp4\",\n \"mp4s\": \"application/mp4\",\n \"mp4v\": \"video/mp4\",\n \"mpd\": \"application/dash+xml\",\n \"mpe\": \"video/mpeg\",\n \"mpeg\": \"video/mpeg\",\n \"mpf\": \"application/media-policy-dataset+xml\",\n \"mpg\": \"video/mpeg\",\n \"mpg4\": \"video/mp4\",\n \"mpga\": \"audio/mpeg\",\n \"mpp\": \"application/dash-patch+xml\",\n \"mrc\": \"application/marc\",\n \"mrcx\": \"application/marcxml+xml\",\n \"ms\": \"text/troff\",\n \"mscml\": \"application/mediaservercontrol+xml\",\n \"msh\": \"model/mesh\",\n \"msi\": \"application/octet-stream\",\n \"msix\": \"application/msix\",\n \"msixbundle\": \"application/msixbundle\",\n \"msm\": \"application/octet-stream\",\n \"msp\": \"application/octet-stream\",\n \"mtl\": \"model/mtl\",\n \"musd\": \"application/mmt-usd+xml\",\n \"mxf\": \"application/mxf\",\n \"mxmf\": \"audio/mobile-xmf\",\n \"mxml\": \"application/xv+xml\",\n \"n3\": \"text/n3\",\n \"nb\": \"application/mathematica\",\n \"nq\": \"application/n-quads\",\n \"nt\": \"application/n-triples\",\n \"obj\": \"model/obj\",\n \"oda\": \"application/oda\",\n \"oga\": \"audio/ogg\",\n \"ogg\": \"audio/ogg\",\n \"ogv\": \"video/ogg\",\n \"ogx\": \"application/ogg\",\n \"omdoc\": \"application/omdoc+xml\",\n \"onepkg\": \"application/onenote\",\n \"onetmp\": \"application/onenote\",\n \"onetoc\": \"application/onenote\",\n \"onetoc2\": \"application/onenote\",\n \"opf\": \"application/oebps-package+xml\",\n \"opus\": \"audio/ogg\",\n \"otf\": \"font/otf\",\n \"owl\": \"application/rdf+xml\",\n \"oxps\": \"application/oxps\",\n \"p10\": \"application/pkcs10\",\n \"p7c\": \"application/pkcs7-mime\",\n \"p7m\": \"application/pkcs7-mime\",\n \"p7s\": \"application/pkcs7-signature\",\n \"p8\": \"application/pkcs8\",\n \"pdf\": \"application/pdf\",\n \"pfr\": \"application/font-tdpfr\",\n \"pgp\": \"application/pgp-encrypted\",\n \"pkg\": \"application/octet-stream\",\n \"pki\": \"application/pkixcmp\",\n \"pkipath\": \"application/pkix-pkipath\",\n \"pls\": \"application/pls+xml\",\n \"png\": \"image/png\",\n \"prc\": \"model/prc\",\n \"prf\": \"application/pics-rules\",\n \"provx\": \"application/provenance+xml\",\n \"ps\": \"application/postscript\",\n \"pskcxml\": \"application/pskc+xml\",\n \"pti\": \"image/prs.pti\",\n \"qt\": \"video/quicktime\",\n \"raml\": \"application/raml+yaml\",\n \"rapd\": \"application/route-apd+xml\",\n \"rdf\": \"application/rdf+xml\",\n \"relo\": \"application/p2p-overlay+xml\",\n \"rif\": \"application/reginfo+xml\",\n \"rl\": \"application/resource-lists+xml\",\n \"rld\": \"application/resource-lists-diff+xml\",\n \"rmi\": \"audio/midi\",\n \"rnc\": \"application/relax-ng-compact-syntax\",\n \"rng\": \"application/xml\",\n \"roa\": \"application/rpki-roa\",\n \"roff\": \"text/troff\",\n \"rq\": \"application/sparql-query\",\n \"rs\": \"application/rls-services+xml\",\n \"rsat\": \"application/atsc-rsat+xml\",\n \"rsd\": \"application/rsd+xml\",\n \"rsheet\": \"application/urc-ressheet+xml\",\n \"rss\": \"application/rss+xml\",\n \"rtf\": \"text/rtf\",\n \"rtx\": \"text/richtext\",\n \"rusd\": \"application/route-usd+xml\",\n \"s3m\": \"audio/s3m\",\n \"sbml\": \"application/sbml+xml\",\n \"scq\": \"application/scvp-cv-request\",\n \"scs\": \"application/scvp-cv-response\",\n \"sdp\": \"application/sdp\",\n \"senmlx\": \"application/senml+xml\",\n \"sensmlx\": \"application/sensml+xml\",\n \"ser\": \"application/java-serialized-object\",\n \"setpay\": \"application/set-payment-initiation\",\n \"setreg\": \"application/set-registration-initiation\",\n \"sgi\": \"image/sgi\",\n \"sgm\": \"text/sgml\",\n \"sgml\": \"text/sgml\",\n \"shex\": \"text/shex\",\n \"shf\": \"application/shf+xml\",\n \"shtml\": \"text/html\",\n \"sieve\": \"application/sieve\",\n \"sig\": \"application/pgp-signature\",\n \"sil\": \"audio/silk\",\n \"silo\": \"model/mesh\",\n \"siv\": \"application/sieve\",\n \"slim\": \"text/slim\",\n \"slm\": \"text/slim\",\n \"sls\": \"application/route-s-tsid+xml\",\n \"smi\": \"application/smil+xml\",\n \"smil\": \"application/smil+xml\",\n \"snd\": \"audio/basic\",\n \"so\": \"application/octet-stream\",\n \"spdx\": \"text/spdx\",\n \"spp\": \"application/scvp-vp-response\",\n \"spq\": \"application/scvp-vp-request\",\n \"spx\": \"audio/ogg\",\n \"sql\": \"application/sql\",\n \"sru\": \"application/sru+xml\",\n \"srx\": \"application/sparql-results+xml\",\n \"ssdl\": \"application/ssdl+xml\",\n \"ssml\": \"application/ssml+xml\",\n \"stk\": \"application/hyperstudio\",\n \"stl\": \"model/stl\",\n \"stpx\": \"model/step+xml\",\n \"stpxz\": \"model/step-xml+zip\",\n \"stpz\": \"model/step+zip\",\n \"styl\": \"text/stylus\",\n \"stylus\": \"text/stylus\",\n \"svg\": \"image/svg+xml\",\n \"svgz\": \"image/svg+xml\",\n \"swidtag\": \"application/swid+xml\",\n \"t\": \"text/troff\",\n \"t38\": \"image/t38\",\n \"td\": \"application/urc-targetdesc+xml\",\n \"tei\": \"application/tei+xml\",\n \"teicorpus\": \"application/tei+xml\",\n \"text\": \"text/plain\",\n \"tfi\": \"application/thraud+xml\",\n \"tfx\": \"image/tiff-fx\",\n \"tif\": \"image/tiff\",\n \"tiff\": \"image/tiff\",\n \"toml\": \"application/toml\",\n \"tr\": \"text/troff\",\n \"trig\": \"application/trig\",\n \"ts\": \"video/mp2t\",\n \"tsd\": \"application/timestamped-data\",\n \"tsv\": \"text/tab-separated-values\",\n \"ttc\": \"font/collection\",\n \"ttf\": \"font/ttf\",\n \"ttl\": \"text/turtle\",\n \"ttml\": \"application/ttml+xml\",\n \"txt\": \"text/plain\",\n \"u3d\": \"model/u3d\",\n \"u8dsn\": \"message/global-delivery-status\",\n \"u8hdr\": \"message/global-headers\",\n \"u8mdn\": \"message/global-disposition-notification\",\n \"u8msg\": \"message/global\",\n \"ubj\": \"application/ubjson\",\n \"uri\": \"text/uri-list\",\n \"uris\": \"text/uri-list\",\n \"urls\": \"text/uri-list\",\n \"vcard\": \"text/vcard\",\n \"vrml\": \"model/vrml\",\n \"vtt\": \"text/vtt\",\n \"vxml\": \"application/voicexml+xml\",\n \"war\": \"application/java-archive\",\n \"wasm\": \"application/wasm\",\n \"wav\": \"audio/wav\",\n \"weba\": \"audio/webm\",\n \"webm\": \"video/webm\",\n \"webmanifest\": \"application/manifest+json\",\n \"webp\": \"image/webp\",\n \"wgsl\": \"text/wgsl\",\n \"wgt\": \"application/widget\",\n \"wif\": \"application/watcherinfo+xml\",\n \"wmf\": \"image/wmf\",\n \"woff\": \"font/woff\",\n \"woff2\": \"font/woff2\",\n \"wrl\": \"model/vrml\",\n \"wsdl\": \"application/wsdl+xml\",\n \"wspolicy\": \"application/wspolicy+xml\",\n \"x3d\": \"model/x3d+xml\",\n \"x3db\": \"model/x3d+fastinfoset\",\n \"x3dbz\": \"model/x3d+binary\",\n \"x3dv\": \"model/x3d-vrml\",\n \"x3dvz\": \"model/x3d+vrml\",\n \"x3dz\": \"model/x3d+xml\",\n \"xaml\": \"application/xaml+xml\",\n \"xav\": \"application/xcap-att+xml\",\n \"xca\": \"application/xcap-caps+xml\",\n \"xcs\": \"application/calendar+xml\",\n \"xdf\": \"application/xcap-diff+xml\",\n \"xdssc\": \"application/dssc+xml\",\n \"xel\": \"application/xcap-el+xml\",\n \"xenc\": \"application/xenc+xml\",\n \"xer\": \"application/patch-ops-error+xml\",\n \"xfdf\": \"application/xfdf\",\n \"xht\": \"application/xhtml+xml\",\n \"xhtml\": \"application/xhtml+xml\",\n \"xhvml\": \"application/xv+xml\",\n \"xlf\": \"application/xliff+xml\",\n \"xm\": \"audio/xm\",\n \"xml\": \"text/xml\",\n \"xns\": \"application/xcap-ns+xml\",\n \"xop\": \"application/xop+xml\",\n \"xpl\": \"application/xproc+xml\",\n \"xsd\": \"application/xml\",\n \"xsf\": \"application/prs.xsf+xml\",\n \"xsl\": \"application/xml\",\n \"xslt\": \"application/xml\",\n \"xspf\": \"application/xspf+xml\",\n \"xvm\": \"application/xv+xml\",\n \"xvml\": \"application/xv+xml\",\n \"yaml\": \"text/yaml\",\n \"yang\": \"application/yang\",\n \"yin\": \"application/yin+xml\",\n \"yml\": \"text/yaml\",\n \"zip\": \"application/zip\"\n};\n\nfunction lookup(extn) {\n\tlet tmp = ('' + extn).trim().toLowerCase();\n\tlet idx = tmp.lastIndexOf('.');\n\treturn mimes[!~idx ? tmp : tmp.substring(++idx)];\n}\n\nexport { mimes, lookup };\n", "export interface ByteRange {\n /**\n * The start index of the range (inclusive). If this number is negative, it represents an offset\n * from the end of the content.\n */\n start: number;\n /**\n * The end index of the range (exclusive). If this number is negative, it represents an offset\n * from the end of the content. `Infinity` represents the end of the content.\n */\n end: number;\n}\n\n/**\n * Returns the length of the byte range in a buffer of the given `size`.\n */\nexport function getByteLength(range: ByteRange, size: number): number {\n let [start, end] = getIndexes(range, size);\n return end - start;\n}\n\n/**\n * Resolves a byte range to absolute indexes in a buffer of the given `size`.\n */\nexport function getIndexes(range: ByteRange, size: number): [number, number] {\n let start = Math.min(Math.max(0, range.start < 0 ? size + range.start : range.start), size);\n let end = Math.min(Math.max(start, range.end < 0 ? size + range.end : range.end), size);\n return [start, end];\n}\n", "import { type ByteRange, getByteLength, getIndexes } from './byte-range.ts';\n\n/**\n * A streaming interface for blob/file content.\n */\nexport interface LazyContent {\n /**\n * The total length of the content.\n */\n byteLength: number;\n /**\n * Returns a stream that can be used to read the content. When given, the `start` index is\n * inclusive indicating the index of the first byte to read. The `end` index is exclusive\n * indicating the index of the first byte not to read.\n */\n stream(start?: number, end?: number): ReadableStream<Uint8Array>;\n}\n\nexport interface LazyBlobOptions {\n /**\n * The range of bytes to include from the content. If not specified, all content is included.\n */\n range?: ByteRange;\n /**\n * The MIME type of the content. The default is an empty string.\n *\n * [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/API/Blob/Blob#type)\n */\n type?: string;\n}\n\n/**\n * A [`Blob`](https://developer.mozilla.org/en-US/docs/Web/API/Blob) that may be backed by a stream\n * of data. This is useful for working with large blobs that would be impractical to load into\n * memory all at once.\n *\n * This class is an extension of JavaScript's built-in `Blob` class with the following additions:\n *\n * - The constructor may accept a `LazyContent` object instead of a `BlobPart[]` array\n * - The constructor may accept a `range` in the options to specify a subset of the content\n *\n * In normal usage you shouldn't have to specify the `range` yourself. The `slice()` method\n * automatically takes care of creating new `LazyBlob` instances with the correct range.\n *\n * [MDN `Blob` Reference](https://developer.mozilla.org/en-US/docs/Web/API/Blob)\n */\nexport class LazyBlob extends Blob {\n readonly #content: BlobContent;\n\n constructor(parts: BlobPart[] | LazyContent, options?: LazyBlobOptions) {\n super([], options);\n this.#content = new BlobContent(parts, options);\n }\n\n /**\n * Returns the blob's contents as an [`ArrayBuffer`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer).\n *\n * [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/API/Blob/arrayBuffer)\n */\n async arrayBuffer(): Promise<ArrayBuffer> {\n return this.#content.arrayBuffer();\n }\n\n /**\n * Returns the blob's contents as a byte array.\n *\n * [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/API/Blob/bytes)\n */\n async bytes(): Promise<Uint8Array> {\n return this.#content.bytes();\n }\n\n /**\n * The size of the blob in bytes.\n *\n * [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/API/Blob/size)\n */\n get size(): number {\n return this.#content.size;\n }\n\n /**\n * Returns a new [`Blob`](https://developer.mozilla.org/en-US/docs/Web/API/Blob) that contains the data in the specified range.\n *\n * [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/API/Blob/slice)\n */\n slice(start?: number, end?: number, contentType?: string): Blob {\n return this.#content.slice(start, end, contentType);\n }\n\n /**\n * Returns a stream that can be used to read the blob's contents.\n *\n * [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/API/Blob/stream)\n */\n stream(): ReadableStream<Uint8Array> {\n return this.#content.stream();\n }\n\n /**\n * Returns the blob's contents as a string.\n *\n * [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/API/Blob/text)\n */\n async text(): Promise<string> {\n return this.#content.text();\n }\n}\n\nexport interface LazyFileOptions extends LazyBlobOptions {\n /**\n * The last modified timestamp of the file in milliseconds. Defaults to `Date.now()`.\n *\n * [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/API/File/File#lastmodified)\n */\n lastModified?: number;\n}\n\n/**\n * A [`File`](https://developer.mozilla.org/en-US/docs/Web/API/File) that may be backed by a stream\n * of data. This is useful for working with large files that would be impractical to load into\n * memory all at once.\n *\n * This class is an extension of JavaScript's built-in `File` class with the following additions:\n *\n * - The constructor may accept a `LazyContent` object instead of a `BlobPart[]` array\n * - The constructor may accept a `range` in the options to specify a subset of the content\n *\n * In normal usage you shouldn't have to specify the `range` yourself. The `slice()` method\n * automatically takes care of creating new `LazyBlob` instances with the correct range.\n *\n * [MDN `File` Reference](https://developer.mozilla.org/en-US/docs/Web/API/File)\n */\nexport class LazyFile extends File {\n readonly #content: BlobContent;\n\n constructor(parts: BlobPart[] | LazyContent, name: string, options?: LazyFileOptions) {\n super([], name, options);\n this.#content = new BlobContent(parts, options);\n }\n\n /**\n * Returns the file's content as an [`ArrayBuffer`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer).\n *\n * [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/API/Blob/arrayBuffer)\n */\n async arrayBuffer(): Promise<ArrayBuffer> {\n return this.#content.arrayBuffer();\n }\n\n /**\n * Returns the file's contents as a byte array.\n *\n * [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/API/Blob/bytes)\n */\n async bytes(): Promise<Uint8Array> {\n return this.#content.bytes();\n }\n\n /**\n * The size of the file in bytes.\n *\n * [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/API/Blob/size)\n */\n get size(): number {\n return this.#content.size;\n }\n\n /**\n * Returns a new [`Blob`](https://developer.mozilla.org/en-US/docs/Web/API/Blob) that contains the data in the specified range.\n *\n * [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/API/Blob/slice)\n */\n slice(start?: number, end?: number, contentType?: string): Blob {\n return this.#content.slice(start, end, contentType);\n }\n\n /**\n * Returns a stream that can be used to read the file's contents.\n *\n * [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/API/Blob/stream)\n */\n stream(): ReadableStream<Uint8Array> {\n return this.#content.stream();\n }\n\n /**\n * Returns the file's contents as a string.\n *\n * [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/API/Blob/text)\n */\n async text(): Promise<string> {\n return this.#content.text();\n }\n}\n\nclass BlobContent {\n readonly source: (Blob | Uint8Array)[] | LazyContent;\n readonly totalSize: number;\n readonly range?: ByteRange;\n readonly type: string;\n\n constructor(parts: BlobPart[] | LazyContent, options?: LazyBlobOptions) {\n if (Array.isArray(parts)) {\n this.source = [];\n this.totalSize = 0;\n\n for (let part of parts) {\n if (part instanceof Blob) {\n this.source.push(part);\n this.totalSize += part.size;\n } else {\n let array: Uint8Array;\n if (typeof part === 'string') {\n array = new TextEncoder().encode(part);\n } else if (ArrayBuffer.isView(part)) {\n array = new Uint8Array(part.buffer, part.byteOffset, part.byteLength);\n } else {\n array = new Uint8Array(part);\n }\n\n this.source.push(array);\n this.totalSize += array.byteLength;\n }\n }\n } else {\n this.source = parts;\n this.totalSize = parts.byteLength;\n }\n\n this.range = options?.range;\n this.type = options?.type ?? '';\n }\n\n async arrayBuffer(): Promise<ArrayBuffer> {\n return (await this.bytes()).buffer;\n }\n\n async bytes(): Promise<Uint8Array> {\n let result = new Uint8Array(this.size);\n\n let offset = 0;\n for await (let chunk of this.stream()) {\n result.set(chunk, offset);\n offset += chunk.length;\n }\n\n return result;\n }\n\n get size(): number {\n return this.range != null ? getByteLength(this.range, this.totalSize) : this.totalSize;\n }\n\n slice(start = 0, end?: number, contentType = ''): LazyBlob {\n let range: ByteRange =\n this.range != null\n ? // file.slice().slice() is additive\n { start: this.range.start + start, end: this.range.end + (end ?? 0) }\n : { start, end: end ?? this.size };\n\n return new LazyBlob(this.source, { range, type: contentType });\n }\n\n stream(): ReadableStream<Uint8Array> {\n if (this.range != null) {\n let [start, end] = getIndexes(this.range, this.totalSize);\n return Array.isArray(this.source)\n ? streamContentArray(this.source, start, end)\n : this.source.stream(start, end);\n }\n\n return Array.isArray(this.source) ? streamContentArray(this.source) : this.source.stream();\n }\n\n async text(): Promise<string> {\n return new TextDecoder('utf-8').decode(await this.bytes());\n }\n}\n\nfunction streamContentArray(\n content: (Blob | Uint8Array)[],\n start = 0,\n end = Infinity,\n): ReadableStream<Uint8Array> {\n let index = 0;\n let bytesRead = 0;\n\n return new ReadableStream({\n async pull(controller) {\n if (index >= content.length) {\n controller.close();\n return;\n }\n\n let hasPushed = false;\n\n function pushChunk(chunk: Uint8Array) {\n let chunkLength = chunk.byteLength;\n\n if (!(bytesRead + chunkLength < start || bytesRead >= end)) {\n let startIndex = Math.max(start - bytesRead, 0);\n let endIndex = Math.min(end - bytesRead, chunkLength);\n controller.enqueue(chunk.subarray(startIndex, endIndex));\n hasPushed = true;\n }\n\n bytesRead += chunkLength;\n }\n\n async function pushPart(part: Blob | Uint8Array) {\n if (part instanceof Blob) {\n if (bytesRead + part.size <= start) {\n // We can skip this part entirely.\n bytesRead += part.size;\n return;\n }\n\n for await (let chunk of part.stream()) {\n pushChunk(chunk);\n\n if (bytesRead >= end) {\n // We can stop reading now.\n break;\n }\n }\n } else {\n pushChunk(part);\n }\n }\n\n while (!hasPushed && index < content.length) {\n await pushPart(content[index++]);\n\n if (bytesRead >= end) {\n controller.close();\n break;\n }\n }\n },\n });\n}\n"],
4
+ "sourcesContent": ["import * as fs from 'node:fs'\nimport * as fsp from 'node:fs/promises'\nimport * as path from 'node:path'\nimport { openFile, writeFile } from '@remix-run/lazy-file/fs'\n\nimport type { FileStorage, FileMetadata, ListOptions, ListResult } from './file-storage.ts'\n\ntype MetadataJson = Omit<FileMetadata, 'size'>\n\n/**\n * A `FileStorage` that is backed by a directory on the local filesystem.\n *\n * Important: No attempt is made to avoid overwriting existing files, so the directory used should\n * be a new directory solely dedicated to this storage object.\n *\n * Note: Keys have no correlation to file names on disk, so they may be any string including\n * characters that are not valid in file names. Additionally, individual `File` names have no\n * correlation to names of files on disk, so multiple files with the same name may be stored in the\n * same storage object.\n */\nexport class LocalFileStorage implements FileStorage {\n #dirname: string\n\n /**\n * @param directory The directory where files are stored\n */\n constructor(directory: string) {\n this.#dirname = path.resolve(directory)\n\n try {\n let stats = fs.statSync(this.#dirname)\n\n if (!stats.isDirectory()) {\n throw new Error(`Path \"${this.#dirname}\" is not a directory`)\n }\n } catch (error) {\n if (!isNoEntityError(error)) {\n throw error\n }\n\n fs.mkdirSync(this.#dirname, { recursive: true })\n }\n }\n\n async get(key: string): Promise<File | null> {\n let { filePath, metaPath } = await this.#getPaths(key)\n\n try {\n let meta = await readMetadata(metaPath)\n\n return openFile(filePath, {\n lastModified: meta.lastModified,\n name: meta.name,\n type: meta.type,\n })\n } catch (error) {\n if (!isNoEntityError(error)) {\n throw error\n }\n\n return null\n }\n }\n\n async has(key: string): Promise<boolean> {\n let { metaPath } = await this.#getPaths(key)\n\n try {\n await fsp.access(metaPath)\n return true\n } catch {\n return false\n }\n }\n\n async list<T extends ListOptions>(options?: T): Promise<ListResult<T>> {\n let { cursor, includeMetadata = false, limit = 32, prefix } = options ?? {}\n\n let files: any[] = []\n let foundCursor = cursor === undefined\n let nextCursor: string | undefined\n let lastHash: string | undefined\n\n outerLoop: for await (let subdir of await fsp.opendir(this.#dirname)) {\n if (!subdir.isDirectory()) continue\n\n for await (let file of await fsp.opendir(path.join(this.#dirname, subdir.name))) {\n if (!file.isFile() || !file.name.endsWith('.meta.json')) continue\n\n let hash = file.name.slice(0, -10) // Remove \".meta.json\"\n\n if (foundCursor) {\n let meta = await readMetadata(path.join(this.#dirname, subdir.name, file.name))\n\n if (prefix != null && !meta.key.startsWith(prefix)) {\n continue\n }\n\n if (files.length >= limit) {\n nextCursor = lastHash\n break outerLoop\n }\n\n if (includeMetadata) {\n let size = (await fsp.stat(path.join(this.#dirname, subdir.name, `${hash}.dat`))).size\n files.push({ ...meta, size })\n } else {\n files.push({ key: meta.key })\n }\n } else if (hash === cursor) {\n foundCursor = true\n }\n\n lastHash = hash\n }\n }\n\n return {\n cursor: nextCursor,\n files,\n }\n }\n\n async put(key: string, file: File): Promise<File> {\n await this.set(key, file)\n return (await this.get(key))!\n }\n\n async remove(key: string): Promise<void> {\n let { directory, filePath, metaPath } = await this.#getPaths(key)\n\n try {\n await Promise.all([fsp.unlink(filePath), fsp.unlink(metaPath)])\n\n // Check if directory is empty and remove it if so\n let files = await fsp.readdir(directory)\n if (files.length === 0) {\n await fsp.rmdir(directory)\n }\n } catch (error) {\n if (!isNoEntityError(error)) {\n throw error\n }\n }\n }\n\n async set(key: string, file: File): Promise<void> {\n let { directory, filePath, metaPath } = await this.#getPaths(key)\n\n // Ensure directory exists\n await fsp.mkdir(directory, { recursive: true })\n\n await writeFile(filePath, file)\n\n let meta: MetadataJson = {\n key,\n lastModified: file.lastModified,\n name: file.name,\n type: file.type,\n }\n await fsp.writeFile(metaPath, JSON.stringify(meta))\n }\n\n async #getPaths(key: string): Promise<{ directory: string; filePath: string; metaPath: string }> {\n let hash = await computeHash(key)\n let directory = path.join(this.#dirname, hash.slice(0, 2))\n\n return {\n directory,\n filePath: path.join(directory, `${hash}.dat`),\n metaPath: path.join(directory, `${hash}.meta.json`),\n }\n }\n}\n\nasync function readMetadata(metaPath: string): Promise<MetadataJson> {\n return JSON.parse(await fsp.readFile(metaPath, 'utf-8'))\n}\n\nasync function computeHash(key: string, algorithm = 'SHA-256'): Promise<string> {\n let digest = await crypto.subtle.digest(algorithm, new TextEncoder().encode(key))\n return Array.from(new Uint8Array(digest))\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('')\n}\n\nfunction isNoEntityError(obj: unknown): obj is NodeJS.ErrnoException & { code: 'ENOENT' } {\n return obj instanceof Error && 'code' in obj && (obj as NodeJS.ErrnoException).code === 'ENOENT'\n}\n", "import * as fs from 'node:fs'\nimport * as path from 'node:path'\nimport { lookup } from 'mrmime'\n\nimport { type LazyContent, LazyFile } from './lib/lazy-file.ts'\n\nexport interface OpenFileOptions {\n /**\n * Overrides the name of the file. Default is the name of the file on disk.\n */\n name?: string\n /**\n * Overrides the MIME type of the file. Default is determined by the file extension.\n */\n type?: string\n /**\n * Overrides the last modified timestamp of the file. Default is the file's last modified time.\n */\n lastModified?: number\n}\n\n/**\n * Returns a `File` from the local filesytem.\n *\n * [MDN `File` Reference](https://developer.mozilla.org/en-US/docs/Web/API/File)\n *\n * @param filename The path to the file\n * @param options Options to override the file's metadata\n * @returns A `File` object\n */\nexport function openFile(filename: string, options?: OpenFileOptions): File {\n let stats = fs.statSync(filename)\n\n if (!stats.isFile()) {\n throw new Error(`Path \"${filename}\" is not a file`)\n }\n\n let content: LazyContent = {\n byteLength: stats.size,\n stream(start, end) {\n return streamFile(filename, start, end)\n },\n }\n\n return new LazyFile(content, options?.name ?? path.basename(filename), {\n type: options?.type ?? lookup(filename),\n lastModified: options?.lastModified ?? stats.mtimeMs,\n }) as File\n}\n\nfunction streamFile(filename: string, start = 0, end = Infinity): ReadableStream<Uint8Array> {\n let read = fs.createReadStream(filename, { start, end: end - 1 }).iterator()\n\n return new ReadableStream({\n async pull(controller) {\n let { done, value } = await read.next()\n\n if (done) {\n controller.close()\n } else {\n controller.enqueue(new Uint8Array(value.buffer, value.byteOffset, value.byteLength))\n }\n },\n })\n}\n\n// Preserve backwards compat with v3.0\nexport { type OpenFileOptions as GetFileOptions, openFile as getFile }\n\n/**\n * Writes a `File` to the local filesytem and resolves when the stream is finished.\n *\n * [MDN `File` Reference](https://developer.mozilla.org/en-US/docs/Web/API/File)\n *\n * @param to The path to write the file to, or an open file descriptor\n * @param file The file to write\n * @returns A promise that resolves when the file is written\n */\nexport function writeFile(to: string | number | fs.promises.FileHandle, file: File): Promise<void> {\n return new Promise(async (resolve, reject) => {\n let writeStream =\n typeof to === 'string'\n ? fs.createWriteStream(to)\n : fs.createWriteStream('ignored', { fd: to })\n\n try {\n for await (let chunk of file.stream()) {\n writeStream.write(chunk)\n }\n\n writeStream.end(() => {\n resolve()\n })\n } catch (error) {\n writeStream.end(() => {\n reject(error)\n })\n }\n })\n}\n", "const mimes = {\n \"3g2\": \"video/3gpp2\",\n \"3gp\": \"video/3gpp\",\n \"3gpp\": \"video/3gpp\",\n \"3mf\": \"model/3mf\",\n \"aac\": \"audio/aac\",\n \"ac\": \"application/pkix-attr-cert\",\n \"adp\": \"audio/adpcm\",\n \"adts\": \"audio/aac\",\n \"ai\": \"application/postscript\",\n \"aml\": \"application/automationml-aml+xml\",\n \"amlx\": \"application/automationml-amlx+zip\",\n \"amr\": \"audio/amr\",\n \"apng\": \"image/apng\",\n \"appcache\": \"text/cache-manifest\",\n \"appinstaller\": \"application/appinstaller\",\n \"appx\": \"application/appx\",\n \"appxbundle\": \"application/appxbundle\",\n \"asc\": \"application/pgp-keys\",\n \"atom\": \"application/atom+xml\",\n \"atomcat\": \"application/atomcat+xml\",\n \"atomdeleted\": \"application/atomdeleted+xml\",\n \"atomsvc\": \"application/atomsvc+xml\",\n \"au\": \"audio/basic\",\n \"avci\": \"image/avci\",\n \"avcs\": \"image/avcs\",\n \"avif\": \"image/avif\",\n \"aw\": \"application/applixware\",\n \"bdoc\": \"application/bdoc\",\n \"bin\": \"application/octet-stream\",\n \"bmp\": \"image/bmp\",\n \"bpk\": \"application/octet-stream\",\n \"btf\": \"image/prs.btif\",\n \"btif\": \"image/prs.btif\",\n \"buffer\": \"application/octet-stream\",\n \"ccxml\": \"application/ccxml+xml\",\n \"cdfx\": \"application/cdfx+xml\",\n \"cdmia\": \"application/cdmi-capability\",\n \"cdmic\": \"application/cdmi-container\",\n \"cdmid\": \"application/cdmi-domain\",\n \"cdmio\": \"application/cdmi-object\",\n \"cdmiq\": \"application/cdmi-queue\",\n \"cer\": \"application/pkix-cert\",\n \"cgm\": \"image/cgm\",\n \"cjs\": \"application/node\",\n \"class\": \"application/java-vm\",\n \"coffee\": \"text/coffeescript\",\n \"conf\": \"text/plain\",\n \"cpl\": \"application/cpl+xml\",\n \"cpt\": \"application/mac-compactpro\",\n \"crl\": \"application/pkix-crl\",\n \"css\": \"text/css\",\n \"csv\": \"text/csv\",\n \"cu\": \"application/cu-seeme\",\n \"cwl\": \"application/cwl\",\n \"cww\": \"application/prs.cww\",\n \"davmount\": \"application/davmount+xml\",\n \"dbk\": \"application/docbook+xml\",\n \"deb\": \"application/octet-stream\",\n \"def\": \"text/plain\",\n \"deploy\": \"application/octet-stream\",\n \"dib\": \"image/bmp\",\n \"disposition-notification\": \"message/disposition-notification\",\n \"dist\": \"application/octet-stream\",\n \"distz\": \"application/octet-stream\",\n \"dll\": \"application/octet-stream\",\n \"dmg\": \"application/octet-stream\",\n \"dms\": \"application/octet-stream\",\n \"doc\": \"application/msword\",\n \"dot\": \"application/msword\",\n \"dpx\": \"image/dpx\",\n \"drle\": \"image/dicom-rle\",\n \"dsc\": \"text/prs.lines.tag\",\n \"dssc\": \"application/dssc+der\",\n \"dtd\": \"application/xml-dtd\",\n \"dump\": \"application/octet-stream\",\n \"dwd\": \"application/atsc-dwd+xml\",\n \"ear\": \"application/java-archive\",\n \"ecma\": \"application/ecmascript\",\n \"elc\": \"application/octet-stream\",\n \"emf\": \"image/emf\",\n \"eml\": \"message/rfc822\",\n \"emma\": \"application/emma+xml\",\n \"emotionml\": \"application/emotionml+xml\",\n \"eps\": \"application/postscript\",\n \"epub\": \"application/epub+zip\",\n \"exe\": \"application/octet-stream\",\n \"exi\": \"application/exi\",\n \"exp\": \"application/express\",\n \"exr\": \"image/aces\",\n \"ez\": \"application/andrew-inset\",\n \"fdf\": \"application/fdf\",\n \"fdt\": \"application/fdt+xml\",\n \"fits\": \"image/fits\",\n \"g3\": \"image/g3fax\",\n \"gbr\": \"application/rpki-ghostbusters\",\n \"geojson\": \"application/geo+json\",\n \"gif\": \"image/gif\",\n \"glb\": \"model/gltf-binary\",\n \"gltf\": \"model/gltf+json\",\n \"gml\": \"application/gml+xml\",\n \"gpx\": \"application/gpx+xml\",\n \"gram\": \"application/srgs\",\n \"grxml\": \"application/srgs+xml\",\n \"gxf\": \"application/gxf\",\n \"gz\": \"application/gzip\",\n \"h261\": \"video/h261\",\n \"h263\": \"video/h263\",\n \"h264\": \"video/h264\",\n \"heic\": \"image/heic\",\n \"heics\": \"image/heic-sequence\",\n \"heif\": \"image/heif\",\n \"heifs\": \"image/heif-sequence\",\n \"hej2\": \"image/hej2k\",\n \"held\": \"application/atsc-held+xml\",\n \"hjson\": \"application/hjson\",\n \"hlp\": \"application/winhlp\",\n \"hqx\": \"application/mac-binhex40\",\n \"hsj2\": \"image/hsj2\",\n \"htm\": \"text/html\",\n \"html\": \"text/html\",\n \"ics\": \"text/calendar\",\n \"ief\": \"image/ief\",\n \"ifb\": \"text/calendar\",\n \"iges\": \"model/iges\",\n \"igs\": \"model/iges\",\n \"img\": \"application/octet-stream\",\n \"in\": \"text/plain\",\n \"ini\": \"text/plain\",\n \"ink\": \"application/inkml+xml\",\n \"inkml\": \"application/inkml+xml\",\n \"ipfix\": \"application/ipfix\",\n \"iso\": \"application/octet-stream\",\n \"its\": \"application/its+xml\",\n \"jade\": \"text/jade\",\n \"jar\": \"application/java-archive\",\n \"jhc\": \"image/jphc\",\n \"jls\": \"image/jls\",\n \"jp2\": \"image/jp2\",\n \"jpe\": \"image/jpeg\",\n \"jpeg\": \"image/jpeg\",\n \"jpf\": \"image/jpx\",\n \"jpg\": \"image/jpeg\",\n \"jpg2\": \"image/jp2\",\n \"jpgm\": \"image/jpm\",\n \"jpgv\": \"video/jpeg\",\n \"jph\": \"image/jph\",\n \"jpm\": \"image/jpm\",\n \"jpx\": \"image/jpx\",\n \"js\": \"text/javascript\",\n \"json\": \"application/json\",\n \"json5\": \"application/json5\",\n \"jsonld\": \"application/ld+json\",\n \"jsonml\": \"application/jsonml+json\",\n \"jsx\": \"text/jsx\",\n \"jt\": \"model/jt\",\n \"jxr\": \"image/jxr\",\n \"jxra\": \"image/jxra\",\n \"jxrs\": \"image/jxrs\",\n \"jxs\": \"image/jxs\",\n \"jxsc\": \"image/jxsc\",\n \"jxsi\": \"image/jxsi\",\n \"jxss\": \"image/jxss\",\n \"kar\": \"audio/midi\",\n \"ktx\": \"image/ktx\",\n \"ktx2\": \"image/ktx2\",\n \"less\": \"text/less\",\n \"lgr\": \"application/lgr+xml\",\n \"list\": \"text/plain\",\n \"litcoffee\": \"text/coffeescript\",\n \"log\": \"text/plain\",\n \"lostxml\": \"application/lost+xml\",\n \"lrf\": \"application/octet-stream\",\n \"m1v\": \"video/mpeg\",\n \"m21\": \"application/mp21\",\n \"m2a\": \"audio/mpeg\",\n \"m2v\": \"video/mpeg\",\n \"m3a\": \"audio/mpeg\",\n \"m4a\": \"audio/mp4\",\n \"m4p\": \"application/mp4\",\n \"m4s\": \"video/iso.segment\",\n \"ma\": \"application/mathematica\",\n \"mads\": \"application/mads+xml\",\n \"maei\": \"application/mmt-aei+xml\",\n \"man\": \"text/troff\",\n \"manifest\": \"text/cache-manifest\",\n \"map\": \"application/json\",\n \"mar\": \"application/octet-stream\",\n \"markdown\": \"text/markdown\",\n \"mathml\": \"application/mathml+xml\",\n \"mb\": \"application/mathematica\",\n \"mbox\": \"application/mbox\",\n \"md\": \"text/markdown\",\n \"mdx\": \"text/mdx\",\n \"me\": \"text/troff\",\n \"mesh\": \"model/mesh\",\n \"meta4\": \"application/metalink4+xml\",\n \"metalink\": \"application/metalink+xml\",\n \"mets\": \"application/mets+xml\",\n \"mft\": \"application/rpki-manifest\",\n \"mid\": \"audio/midi\",\n \"midi\": \"audio/midi\",\n \"mime\": \"message/rfc822\",\n \"mj2\": \"video/mj2\",\n \"mjp2\": \"video/mj2\",\n \"mjs\": \"text/javascript\",\n \"mml\": \"text/mathml\",\n \"mods\": \"application/mods+xml\",\n \"mov\": \"video/quicktime\",\n \"mp2\": \"audio/mpeg\",\n \"mp21\": \"application/mp21\",\n \"mp2a\": \"audio/mpeg\",\n \"mp3\": \"audio/mpeg\",\n \"mp4\": \"video/mp4\",\n \"mp4a\": \"audio/mp4\",\n \"mp4s\": \"application/mp4\",\n \"mp4v\": \"video/mp4\",\n \"mpd\": \"application/dash+xml\",\n \"mpe\": \"video/mpeg\",\n \"mpeg\": \"video/mpeg\",\n \"mpf\": \"application/media-policy-dataset+xml\",\n \"mpg\": \"video/mpeg\",\n \"mpg4\": \"video/mp4\",\n \"mpga\": \"audio/mpeg\",\n \"mpp\": \"application/dash-patch+xml\",\n \"mrc\": \"application/marc\",\n \"mrcx\": \"application/marcxml+xml\",\n \"ms\": \"text/troff\",\n \"mscml\": \"application/mediaservercontrol+xml\",\n \"msh\": \"model/mesh\",\n \"msi\": \"application/octet-stream\",\n \"msix\": \"application/msix\",\n \"msixbundle\": \"application/msixbundle\",\n \"msm\": \"application/octet-stream\",\n \"msp\": \"application/octet-stream\",\n \"mtl\": \"model/mtl\",\n \"musd\": \"application/mmt-usd+xml\",\n \"mxf\": \"application/mxf\",\n \"mxmf\": \"audio/mobile-xmf\",\n \"mxml\": \"application/xv+xml\",\n \"n3\": \"text/n3\",\n \"nb\": \"application/mathematica\",\n \"nq\": \"application/n-quads\",\n \"nt\": \"application/n-triples\",\n \"obj\": \"model/obj\",\n \"oda\": \"application/oda\",\n \"oga\": \"audio/ogg\",\n \"ogg\": \"audio/ogg\",\n \"ogv\": \"video/ogg\",\n \"ogx\": \"application/ogg\",\n \"omdoc\": \"application/omdoc+xml\",\n \"onepkg\": \"application/onenote\",\n \"onetmp\": \"application/onenote\",\n \"onetoc\": \"application/onenote\",\n \"onetoc2\": \"application/onenote\",\n \"opf\": \"application/oebps-package+xml\",\n \"opus\": \"audio/ogg\",\n \"otf\": \"font/otf\",\n \"owl\": \"application/rdf+xml\",\n \"oxps\": \"application/oxps\",\n \"p10\": \"application/pkcs10\",\n \"p7c\": \"application/pkcs7-mime\",\n \"p7m\": \"application/pkcs7-mime\",\n \"p7s\": \"application/pkcs7-signature\",\n \"p8\": \"application/pkcs8\",\n \"pdf\": \"application/pdf\",\n \"pfr\": \"application/font-tdpfr\",\n \"pgp\": \"application/pgp-encrypted\",\n \"pkg\": \"application/octet-stream\",\n \"pki\": \"application/pkixcmp\",\n \"pkipath\": \"application/pkix-pkipath\",\n \"pls\": \"application/pls+xml\",\n \"png\": \"image/png\",\n \"prc\": \"model/prc\",\n \"prf\": \"application/pics-rules\",\n \"provx\": \"application/provenance+xml\",\n \"ps\": \"application/postscript\",\n \"pskcxml\": \"application/pskc+xml\",\n \"pti\": \"image/prs.pti\",\n \"qt\": \"video/quicktime\",\n \"raml\": \"application/raml+yaml\",\n \"rapd\": \"application/route-apd+xml\",\n \"rdf\": \"application/rdf+xml\",\n \"relo\": \"application/p2p-overlay+xml\",\n \"rif\": \"application/reginfo+xml\",\n \"rl\": \"application/resource-lists+xml\",\n \"rld\": \"application/resource-lists-diff+xml\",\n \"rmi\": \"audio/midi\",\n \"rnc\": \"application/relax-ng-compact-syntax\",\n \"rng\": \"application/xml\",\n \"roa\": \"application/rpki-roa\",\n \"roff\": \"text/troff\",\n \"rq\": \"application/sparql-query\",\n \"rs\": \"application/rls-services+xml\",\n \"rsat\": \"application/atsc-rsat+xml\",\n \"rsd\": \"application/rsd+xml\",\n \"rsheet\": \"application/urc-ressheet+xml\",\n \"rss\": \"application/rss+xml\",\n \"rtf\": \"text/rtf\",\n \"rtx\": \"text/richtext\",\n \"rusd\": \"application/route-usd+xml\",\n \"s3m\": \"audio/s3m\",\n \"sbml\": \"application/sbml+xml\",\n \"scq\": \"application/scvp-cv-request\",\n \"scs\": \"application/scvp-cv-response\",\n \"sdp\": \"application/sdp\",\n \"senmlx\": \"application/senml+xml\",\n \"sensmlx\": \"application/sensml+xml\",\n \"ser\": \"application/java-serialized-object\",\n \"setpay\": \"application/set-payment-initiation\",\n \"setreg\": \"application/set-registration-initiation\",\n \"sgi\": \"image/sgi\",\n \"sgm\": \"text/sgml\",\n \"sgml\": \"text/sgml\",\n \"shex\": \"text/shex\",\n \"shf\": \"application/shf+xml\",\n \"shtml\": \"text/html\",\n \"sieve\": \"application/sieve\",\n \"sig\": \"application/pgp-signature\",\n \"sil\": \"audio/silk\",\n \"silo\": \"model/mesh\",\n \"siv\": \"application/sieve\",\n \"slim\": \"text/slim\",\n \"slm\": \"text/slim\",\n \"sls\": \"application/route-s-tsid+xml\",\n \"smi\": \"application/smil+xml\",\n \"smil\": \"application/smil+xml\",\n \"snd\": \"audio/basic\",\n \"so\": \"application/octet-stream\",\n \"spdx\": \"text/spdx\",\n \"spp\": \"application/scvp-vp-response\",\n \"spq\": \"application/scvp-vp-request\",\n \"spx\": \"audio/ogg\",\n \"sql\": \"application/sql\",\n \"sru\": \"application/sru+xml\",\n \"srx\": \"application/sparql-results+xml\",\n \"ssdl\": \"application/ssdl+xml\",\n \"ssml\": \"application/ssml+xml\",\n \"stk\": \"application/hyperstudio\",\n \"stl\": \"model/stl\",\n \"stpx\": \"model/step+xml\",\n \"stpxz\": \"model/step-xml+zip\",\n \"stpz\": \"model/step+zip\",\n \"styl\": \"text/stylus\",\n \"stylus\": \"text/stylus\",\n \"svg\": \"image/svg+xml\",\n \"svgz\": \"image/svg+xml\",\n \"swidtag\": \"application/swid+xml\",\n \"t\": \"text/troff\",\n \"t38\": \"image/t38\",\n \"td\": \"application/urc-targetdesc+xml\",\n \"tei\": \"application/tei+xml\",\n \"teicorpus\": \"application/tei+xml\",\n \"text\": \"text/plain\",\n \"tfi\": \"application/thraud+xml\",\n \"tfx\": \"image/tiff-fx\",\n \"tif\": \"image/tiff\",\n \"tiff\": \"image/tiff\",\n \"toml\": \"application/toml\",\n \"tr\": \"text/troff\",\n \"trig\": \"application/trig\",\n \"ts\": \"video/mp2t\",\n \"tsd\": \"application/timestamped-data\",\n \"tsv\": \"text/tab-separated-values\",\n \"ttc\": \"font/collection\",\n \"ttf\": \"font/ttf\",\n \"ttl\": \"text/turtle\",\n \"ttml\": \"application/ttml+xml\",\n \"txt\": \"text/plain\",\n \"u3d\": \"model/u3d\",\n \"u8dsn\": \"message/global-delivery-status\",\n \"u8hdr\": \"message/global-headers\",\n \"u8mdn\": \"message/global-disposition-notification\",\n \"u8msg\": \"message/global\",\n \"ubj\": \"application/ubjson\",\n \"uri\": \"text/uri-list\",\n \"uris\": \"text/uri-list\",\n \"urls\": \"text/uri-list\",\n \"vcard\": \"text/vcard\",\n \"vrml\": \"model/vrml\",\n \"vtt\": \"text/vtt\",\n \"vxml\": \"application/voicexml+xml\",\n \"war\": \"application/java-archive\",\n \"wasm\": \"application/wasm\",\n \"wav\": \"audio/wav\",\n \"weba\": \"audio/webm\",\n \"webm\": \"video/webm\",\n \"webmanifest\": \"application/manifest+json\",\n \"webp\": \"image/webp\",\n \"wgsl\": \"text/wgsl\",\n \"wgt\": \"application/widget\",\n \"wif\": \"application/watcherinfo+xml\",\n \"wmf\": \"image/wmf\",\n \"woff\": \"font/woff\",\n \"woff2\": \"font/woff2\",\n \"wrl\": \"model/vrml\",\n \"wsdl\": \"application/wsdl+xml\",\n \"wspolicy\": \"application/wspolicy+xml\",\n \"x3d\": \"model/x3d+xml\",\n \"x3db\": \"model/x3d+fastinfoset\",\n \"x3dbz\": \"model/x3d+binary\",\n \"x3dv\": \"model/x3d-vrml\",\n \"x3dvz\": \"model/x3d+vrml\",\n \"x3dz\": \"model/x3d+xml\",\n \"xaml\": \"application/xaml+xml\",\n \"xav\": \"application/xcap-att+xml\",\n \"xca\": \"application/xcap-caps+xml\",\n \"xcs\": \"application/calendar+xml\",\n \"xdf\": \"application/xcap-diff+xml\",\n \"xdssc\": \"application/dssc+xml\",\n \"xel\": \"application/xcap-el+xml\",\n \"xenc\": \"application/xenc+xml\",\n \"xer\": \"application/patch-ops-error+xml\",\n \"xfdf\": \"application/xfdf\",\n \"xht\": \"application/xhtml+xml\",\n \"xhtml\": \"application/xhtml+xml\",\n \"xhvml\": \"application/xv+xml\",\n \"xlf\": \"application/xliff+xml\",\n \"xm\": \"audio/xm\",\n \"xml\": \"text/xml\",\n \"xns\": \"application/xcap-ns+xml\",\n \"xop\": \"application/xop+xml\",\n \"xpl\": \"application/xproc+xml\",\n \"xsd\": \"application/xml\",\n \"xsf\": \"application/prs.xsf+xml\",\n \"xsl\": \"application/xml\",\n \"xslt\": \"application/xml\",\n \"xspf\": \"application/xspf+xml\",\n \"xvm\": \"application/xv+xml\",\n \"xvml\": \"application/xv+xml\",\n \"yaml\": \"text/yaml\",\n \"yang\": \"application/yang\",\n \"yin\": \"application/yin+xml\",\n \"yml\": \"text/yaml\",\n \"zip\": \"application/zip\"\n};\n\nfunction lookup(extn) {\n\tlet tmp = ('' + extn).trim().toLowerCase();\n\tlet idx = tmp.lastIndexOf('.');\n\treturn mimes[!~idx ? tmp : tmp.substring(++idx)];\n}\n\nexport { mimes, lookup };\n", "export interface ByteRange {\n /**\n * The start index of the range (inclusive). If this number is negative, it represents an offset\n * from the end of the content.\n */\n start: number\n /**\n * The end index of the range (exclusive). If this number is negative, it represents an offset\n * from the end of the content. `Infinity` represents the end of the content.\n */\n end: number\n}\n\n/**\n * Returns the length of the byte range in a buffer of the given `size`.\n */\nexport function getByteLength(range: ByteRange, size: number): number {\n let [start, end] = getIndexes(range, size)\n return end - start\n}\n\n/**\n * Resolves a byte range to absolute indexes in a buffer of the given `size`.\n */\nexport function getIndexes(range: ByteRange, size: number): [number, number] {\n let start = Math.min(Math.max(0, range.start < 0 ? size + range.start : range.start), size)\n let end = Math.min(Math.max(start, range.end < 0 ? size + range.end : range.end), size)\n return [start, end]\n}\n", "import { type ByteRange, getByteLength, getIndexes } from './byte-range.ts'\n\n/**\n * A streaming interface for blob/file content.\n */\nexport interface LazyContent {\n /**\n * The total length of the content.\n */\n byteLength: number\n /**\n * Returns a stream that can be used to read the content. When given, the `start` index is\n * inclusive indicating the index of the first byte to read. The `end` index is exclusive\n * indicating the index of the first byte not to read.\n */\n stream(start?: number, end?: number): ReadableStream<Uint8Array>\n}\n\nexport interface LazyBlobOptions {\n /**\n * The range of bytes to include from the content. If not specified, all content is included.\n */\n range?: ByteRange\n /**\n * The MIME type of the content. The default is an empty string.\n *\n * [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/API/Blob/Blob#type)\n */\n type?: string\n}\n\n/**\n * A [`Blob`](https://developer.mozilla.org/en-US/docs/Web/API/Blob) that may be backed by a stream\n * of data. This is useful for working with large blobs that would be impractical to load into\n * memory all at once.\n *\n * This class is an extension of JavaScript's built-in `Blob` class with the following additions:\n *\n * - The constructor may accept a `LazyContent` object instead of a `BlobPart[]` array\n * - The constructor may accept a `range` in the options to specify a subset of the content\n *\n * In normal usage you shouldn't have to specify the `range` yourself. The `slice()` method\n * automatically takes care of creating new `LazyBlob` instances with the correct range.\n *\n * [MDN `Blob` Reference](https://developer.mozilla.org/en-US/docs/Web/API/Blob)\n */\nexport class LazyBlob extends Blob {\n readonly #content: BlobContent\n\n constructor(parts: BlobPart[] | LazyContent, options?: LazyBlobOptions) {\n super([], options)\n this.#content = new BlobContent(parts, options)\n }\n\n /**\n * Returns the blob's contents as an [`ArrayBuffer`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer).\n *\n * [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/API/Blob/arrayBuffer)\n */\n async arrayBuffer(): Promise<ArrayBuffer> {\n return this.#content.arrayBuffer()\n }\n\n /**\n * Returns the blob's contents as a byte array.\n *\n * [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/API/Blob/bytes)\n */\n async bytes(): Promise<Uint8Array> {\n return this.#content.bytes()\n }\n\n /**\n * The size of the blob in bytes.\n *\n * [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/API/Blob/size)\n */\n get size(): number {\n return this.#content.size\n }\n\n /**\n * Returns a new [`Blob`](https://developer.mozilla.org/en-US/docs/Web/API/Blob) that contains the data in the specified range.\n *\n * [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/API/Blob/slice)\n */\n slice(start?: number, end?: number, contentType?: string): Blob {\n return this.#content.slice(start, end, contentType)\n }\n\n /**\n * Returns a stream that can be used to read the blob's contents.\n *\n * [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/API/Blob/stream)\n */\n stream(): ReadableStream<Uint8Array> {\n return this.#content.stream()\n }\n\n /**\n * Returns the blob's contents as a string.\n *\n * [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/API/Blob/text)\n */\n async text(): Promise<string> {\n return this.#content.text()\n }\n}\n\nexport interface LazyFileOptions extends LazyBlobOptions {\n /**\n * The last modified timestamp of the file in milliseconds. Defaults to `Date.now()`.\n *\n * [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/API/File/File#lastmodified)\n */\n lastModified?: number\n}\n\n/**\n * A [`File`](https://developer.mozilla.org/en-US/docs/Web/API/File) that may be backed by a stream\n * of data. This is useful for working with large files that would be impractical to load into\n * memory all at once.\n *\n * This class is an extension of JavaScript's built-in `File` class with the following additions:\n *\n * - The constructor may accept a `LazyContent` object instead of a `BlobPart[]` array\n * - The constructor may accept a `range` in the options to specify a subset of the content\n *\n * In normal usage you shouldn't have to specify the `range` yourself. The `slice()` method\n * automatically takes care of creating new `LazyBlob` instances with the correct range.\n *\n * [MDN `File` Reference](https://developer.mozilla.org/en-US/docs/Web/API/File)\n */\nexport class LazyFile extends File {\n readonly #content: BlobContent\n\n constructor(parts: BlobPart[] | LazyContent, name: string, options?: LazyFileOptions) {\n super([], name, options)\n this.#content = new BlobContent(parts, options)\n }\n\n /**\n * Returns the file's content as an [`ArrayBuffer`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/ArrayBuffer).\n *\n * [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/API/Blob/arrayBuffer)\n */\n async arrayBuffer(): Promise<ArrayBuffer> {\n return this.#content.arrayBuffer()\n }\n\n /**\n * Returns the file's contents as a byte array.\n *\n * [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/API/Blob/bytes)\n */\n async bytes(): Promise<Uint8Array> {\n return this.#content.bytes()\n }\n\n /**\n * The size of the file in bytes.\n *\n * [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/API/Blob/size)\n */\n get size(): number {\n return this.#content.size\n }\n\n /**\n * Returns a new [`Blob`](https://developer.mozilla.org/en-US/docs/Web/API/Blob) that contains the data in the specified range.\n *\n * [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/API/Blob/slice)\n */\n slice(start?: number, end?: number, contentType?: string): Blob {\n return this.#content.slice(start, end, contentType)\n }\n\n /**\n * Returns a stream that can be used to read the file's contents.\n *\n * [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/API/Blob/stream)\n */\n stream(): ReadableStream<Uint8Array> {\n return this.#content.stream()\n }\n\n /**\n * Returns the file's contents as a string.\n *\n * [MDN Reference](https://developer.mozilla.org/en-US/docs/Web/API/Blob/text)\n */\n async text(): Promise<string> {\n return this.#content.text()\n }\n}\n\nclass BlobContent {\n readonly source: (Blob | Uint8Array)[] | LazyContent\n readonly totalSize: number\n readonly range?: ByteRange\n readonly type: string\n\n constructor(parts: BlobPart[] | LazyContent, options?: LazyBlobOptions) {\n if (Array.isArray(parts)) {\n this.source = []\n this.totalSize = 0\n\n for (let part of parts) {\n if (part instanceof Blob) {\n this.source.push(part)\n this.totalSize += part.size\n } else {\n let array: Uint8Array\n if (typeof part === 'string') {\n array = new TextEncoder().encode(part)\n } else if (ArrayBuffer.isView(part)) {\n array = new Uint8Array(part.buffer, part.byteOffset, part.byteLength)\n } else {\n array = new Uint8Array(part)\n }\n\n this.source.push(array)\n this.totalSize += array.byteLength\n }\n }\n } else {\n this.source = parts\n this.totalSize = parts.byteLength\n }\n\n this.range = options?.range\n this.type = options?.type ?? ''\n }\n\n async arrayBuffer(): Promise<ArrayBuffer> {\n return (await this.bytes()).buffer as ArrayBuffer\n }\n\n async bytes(): Promise<Uint8Array> {\n let result = new Uint8Array(this.size)\n\n let offset = 0\n for await (let chunk of this.stream()) {\n result.set(chunk, offset)\n offset += chunk.length\n }\n\n return result\n }\n\n get size(): number {\n return this.range != null ? getByteLength(this.range, this.totalSize) : this.totalSize\n }\n\n slice(start = 0, end?: number, contentType = ''): LazyBlob {\n let range: ByteRange =\n this.range != null\n ? // file.slice().slice() is additive\n { start: this.range.start + start, end: this.range.end + (end ?? 0) }\n : { start, end: end ?? this.size }\n\n return new LazyBlob(this.source, { range, type: contentType })\n }\n\n stream(): ReadableStream<Uint8Array> {\n if (this.range != null) {\n let [start, end] = getIndexes(this.range, this.totalSize)\n return Array.isArray(this.source)\n ? streamContentArray(this.source, start, end)\n : this.source.stream(start, end)\n }\n\n return Array.isArray(this.source) ? streamContentArray(this.source) : this.source.stream()\n }\n\n async text(): Promise<string> {\n return new TextDecoder('utf-8').decode(await this.bytes())\n }\n}\n\nfunction streamContentArray(\n content: (Blob | Uint8Array)[],\n start = 0,\n end = Infinity,\n): ReadableStream<Uint8Array> {\n let index = 0\n let bytesRead = 0\n\n return new ReadableStream({\n async pull(controller) {\n if (index >= content.length) {\n controller.close()\n return\n }\n\n let hasPushed = false\n\n function pushChunk(chunk: Uint8Array) {\n let chunkLength = chunk.byteLength\n\n if (!(bytesRead + chunkLength < start || bytesRead >= end)) {\n let startIndex = Math.max(start - bytesRead, 0)\n let endIndex = Math.min(end - bytesRead, chunkLength)\n controller.enqueue(chunk.subarray(startIndex, endIndex))\n hasPushed = true\n }\n\n bytesRead += chunkLength\n }\n\n async function pushPart(part: Blob | Uint8Array) {\n if (part instanceof Blob) {\n if (bytesRead + part.size <= start) {\n // We can skip this part entirely.\n bytesRead += part.size\n return\n }\n\n for await (let chunk of part.stream()) {\n pushChunk(chunk)\n\n if (bytesRead >= end) {\n // We can stop reading now.\n break\n }\n }\n } else {\n pushChunk(part)\n }\n }\n\n while (!hasPushed && index < content.length) {\n await pushPart(content[index++])\n\n if (bytesRead >= end) {\n controller.close()\n break\n }\n }\n },\n })\n}\n"],
5
5
  "mappings": "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",
6
6
  "names": ["fs", "path", "resolve"]
7
7
  }
@@ -1 +1 @@
1
- {"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../src/memory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC"}
1
+ {"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../src/memory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAA"}
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/lib/memory-file-storage.ts"],
4
- "sourcesContent": ["import type { FileStorage, ListOptions, ListResult } from './file-storage.ts';\n\n/**\n * A simple, in-memory implementation of the `FileStorage` interface.\n */\nexport class MemoryFileStorage implements FileStorage {\n #map = new Map<string, File>();\n\n get(key: string): File | null {\n return this.#map.get(key) ?? null;\n }\n\n has(key: string): boolean {\n return this.#map.has(key);\n }\n\n list<T extends ListOptions>(options?: T): ListResult<T> {\n let { cursor, includeMetadata = false, limit = Infinity, prefix } = options ?? {};\n\n let files: any[] = [];\n let foundCursor = cursor === undefined;\n let nextCursor: string | undefined;\n\n for (let [key, file] of this.#map.entries()) {\n if (foundCursor) {\n if (prefix != null && !key.startsWith(prefix)) {\n continue;\n }\n\n if (files.length >= limit) {\n nextCursor = files[files.length - 1]?.key;\n break;\n }\n\n if (includeMetadata) {\n files.push({\n key,\n lastModified: file.lastModified,\n name: file.name,\n size: file.size,\n type: file.type,\n });\n } else {\n files.push({ key });\n }\n } else if (key === cursor) {\n foundCursor = true;\n }\n }\n\n return {\n cursor: nextCursor,\n files,\n };\n }\n\n async put(key: string, file: File): Promise<File> {\n await this.set(key, file);\n return this.get(key)!;\n }\n\n remove(key: string): void {\n this.#map.delete(key);\n }\n\n async set(key: string, file: File): Promise<void> {\n let buffer = await file.arrayBuffer();\n let newFile = new File([buffer], file.name, {\n lastModified: file.lastModified,\n type: file.type,\n });\n\n this.#map.set(key, newFile);\n }\n}\n"],
4
+ "sourcesContent": ["import type { FileStorage, ListOptions, ListResult } from './file-storage.ts'\n\n/**\n * A simple, in-memory implementation of the `FileStorage` interface.\n */\nexport class MemoryFileStorage implements FileStorage {\n #map = new Map<string, File>()\n\n get(key: string): File | null {\n return this.#map.get(key) ?? null\n }\n\n has(key: string): boolean {\n return this.#map.has(key)\n }\n\n list<T extends ListOptions>(options?: T): ListResult<T> {\n let { cursor, includeMetadata = false, limit = Infinity, prefix } = options ?? {}\n\n let files: any[] = []\n let foundCursor = cursor === undefined\n let nextCursor: string | undefined\n\n for (let [key, file] of this.#map.entries()) {\n if (foundCursor) {\n if (prefix != null && !key.startsWith(prefix)) {\n continue\n }\n\n if (files.length >= limit) {\n nextCursor = files[files.length - 1]?.key\n break\n }\n\n if (includeMetadata) {\n files.push({\n key,\n lastModified: file.lastModified,\n name: file.name,\n size: file.size,\n type: file.type,\n })\n } else {\n files.push({ key })\n }\n } else if (key === cursor) {\n foundCursor = true\n }\n }\n\n return {\n cursor: nextCursor,\n files,\n }\n }\n\n async put(key: string, file: File): Promise<File> {\n await this.set(key, file)\n return this.get(key)!\n }\n\n remove(key: string): void {\n this.#map.delete(key)\n }\n\n async set(key: string, file: File): Promise<void> {\n let buffer = await file.arrayBuffer()\n let newFile = new File([buffer], file.name, {\n lastModified: file.lastModified,\n type: file.type,\n })\n\n this.#map.set(key, newFile)\n }\n}\n"],
5
5
  "mappings": ";AAKO,IAAM,oBAAN,MAA+C;AAAA,EACpD,OAAO,oBAAI,IAAkB;AAAA,EAE7B,IAAI,KAA0B;AAC5B,WAAO,KAAK,KAAK,IAAI,GAAG,KAAK;AAAA,EAC/B;AAAA,EAEA,IAAI,KAAsB;AACxB,WAAO,KAAK,KAAK,IAAI,GAAG;AAAA,EAC1B;AAAA,EAEA,KAA4B,SAA4B;AACtD,QAAI,EAAE,QAAQ,kBAAkB,OAAO,QAAQ,UAAU,OAAO,IAAI,WAAW,CAAC;AAEhF,QAAI,QAAe,CAAC;AACpB,QAAI,cAAc,WAAW;AAC7B,QAAI;AAEJ,aAAS,CAAC,KAAK,IAAI,KAAK,KAAK,KAAK,QAAQ,GAAG;AAC3C,UAAI,aAAa;AACf,YAAI,UAAU,QAAQ,CAAC,IAAI,WAAW,MAAM,GAAG;AAC7C;AAAA,QACF;AAEA,YAAI,MAAM,UAAU,OAAO;AACzB,uBAAa,MAAM,MAAM,SAAS,CAAC,GAAG;AACtC;AAAA,QACF;AAEA,YAAI,iBAAiB;AACnB,gBAAM,KAAK;AAAA,YACT;AAAA,YACA,cAAc,KAAK;AAAA,YACnB,MAAM,KAAK;AAAA,YACX,MAAM,KAAK;AAAA,YACX,MAAM,KAAK;AAAA,UACb,CAAC;AAAA,QACH,OAAO;AACL,gBAAM,KAAK,EAAE,IAAI,CAAC;AAAA,QACpB;AAAA,MACF,WAAW,QAAQ,QAAQ;AACzB,sBAAc;AAAA,MAChB;AAAA,IACF;AAEA,WAAO;AAAA,MACL,QAAQ;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAM,IAAI,KAAa,MAA2B;AAChD,UAAM,KAAK,IAAI,KAAK,IAAI;AACxB,WAAO,KAAK,IAAI,GAAG;AAAA,EACrB;AAAA,EAEA,OAAO,KAAmB;AACxB,SAAK,KAAK,OAAO,GAAG;AAAA,EACtB;AAAA,EAEA,MAAM,IAAI,KAAa,MAA2B;AAChD,QAAI,SAAS,MAAM,KAAK,YAAY;AACpC,QAAI,UAAU,IAAI,KAAK,CAAC,MAAM,GAAG,KAAK,MAAM;AAAA,MAC1C,cAAc,KAAK;AAAA,MACnB,MAAM,KAAK;AAAA,IACb,CAAC;AAED,SAAK,KAAK,IAAI,KAAK,OAAO;AAAA,EAC5B;AACF;",
6
6
  "names": []
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remix-run/file-storage",
3
- "version": "0.9.0",
3
+ "version": "0.10.0",
4
4
  "description": "Key/value storage for JavaScript File objects",
5
5
  "author": "Michael Jackson <mjijackson@gmail.com>",
6
6
  "repository": {
@@ -8,7 +8,7 @@
8
8
  "url": "git+https://github.com/remix-run/remix.git",
9
9
  "directory": "packages/file-storage"
10
10
  },
11
- "homepage": "https://github.com/remix-run/remix/tree/v3/packages/file-storage#readme",
11
+ "homepage": "https://github.com/remix-run/remix/tree/main/packages/file-storage#readme",
12
12
  "license": "MIT",
13
13
  "files": [
14
14
  "LICENSE",
@@ -18,37 +18,28 @@
18
18
  "!src/**/*.test.ts"
19
19
  ],
20
20
  "type": "module",
21
- "types": "./dist/file-storage.d.ts",
22
- "module": "./dist/file-storage.js",
23
- "main": "./dist/file-storage.cjs",
24
21
  "exports": {
25
22
  ".": {
26
- "types": "./dist/file-storage.d.ts",
27
- "import": "./dist/file-storage.js",
28
- "require": "./dist/file-storage.cjs",
29
- "default": "./dist/file-storage.js"
23
+ "types": "./dist/index.d.ts",
24
+ "default": "./dist/index.js"
30
25
  },
31
26
  "./local": {
32
27
  "types": "./dist/local.d.ts",
33
- "import": "./dist/local.js",
34
- "require": "./dist/local.cjs",
35
28
  "default": "./dist/local.js"
36
29
  },
37
30
  "./memory": {
38
31
  "types": "./dist/memory.d.ts",
39
- "import": "./dist/memory.js",
40
- "require": "./dist/memory.cjs",
41
32
  "default": "./dist/memory.js"
42
33
  },
43
34
  "./package.json": "./package.json"
44
35
  },
45
36
  "dependencies": {
46
- "@remix-run/lazy-file": "^3.5.0"
37
+ "@remix-run/lazy-file": "^3.6.0"
47
38
  },
48
39
  "devDependencies": {
49
- "@types/node": "^20.14.10",
50
- "esbuild": "^0.25.5",
51
- "@remix-run/form-data-parser": "^0.10.1"
40
+ "@types/node": "^24.6.0",
41
+ "esbuild": "^0.25.10",
42
+ "@remix-run/form-data-parser": "^0.12.0"
52
43
  },
53
44
  "keywords": [
54
45
  "file",
@@ -57,15 +48,13 @@
57
48
  "fs"
58
49
  ],
59
50
  "scripts": {
60
- "build:types": "tsc --project tsconfig.build.json",
61
- "build:esm": "esbuild src/file-storage.ts --bundle --outfile=dist/file-storage.js --format=esm --platform=neutral --sourcemap",
62
- "build:cjs": "esbuild src/file-storage.ts --bundle --outfile=dist/file-storage.cjs --format=cjs --platform=neutral --sourcemap",
51
+ "build": "pnpm run clean && pnpm run build:types && pnpm run build:esm && pnpm run build:esm:local && pnpm run build:esm:memory",
52
+ "build:esm": "esbuild src/index.ts --bundle --outfile=dist/index.js --format=esm --platform=neutral --sourcemap",
63
53
  "build:esm:local": "esbuild src/local.ts --bundle --outfile=dist/local.js --format=esm --platform=node --sourcemap",
64
- "build:cjs:local": "esbuild src/local.ts --bundle --outfile=dist/local.cjs --format=cjs --platform=node --sourcemap",
65
54
  "build:esm:memory": "esbuild src/memory.ts --bundle --outfile=dist/memory.js --format=esm --platform=neutral --sourcemap",
66
- "build:cjs:memory": "esbuild src/memory.ts --bundle --outfile=dist/memory.cjs --format=cjs --platform=neutral --sourcemap",
67
- "build": "pnpm run clean && pnpm run build:types && pnpm run build:esm && pnpm run build:cjs && pnpm run build:esm:local && pnpm run build:cjs:local && pnpm run build:esm:memory && pnpm run build:cjs:memory",
55
+ "build:types": "tsc --project tsconfig.build.json",
68
56
  "clean": "rm -rf dist",
69
- "test": "node --disable-warning=ExperimentalWarning --test ./src/**/*.test.ts"
57
+ "test": "node --disable-warning=ExperimentalWarning --test './src/**/*.test.ts'",
58
+ "typecheck": "tsc --noEmit"
70
59
  }
71
60
  }
@@ -4,4 +4,4 @@ export type {
4
4
  FileMetadata,
5
5
  ListOptions,
6
6
  ListResult,
7
- } from './lib/file-storage.ts';
7
+ } from './lib/file-storage.ts'
@@ -7,14 +7,14 @@ export interface FileStorage {
7
7
  * @param key The key to look up
8
8
  * @returns The file with the given key, or `null` if no such key exists
9
9
  */
10
- get(key: string): File | null | Promise<File | null>;
10
+ get(key: string): File | null | Promise<File | null>
11
11
 
12
12
  /**
13
13
  * Check if a file with the given key exists.
14
14
  * @param key The key to look up
15
15
  * @returns `true` if a file with the given key exists, `false` otherwise
16
16
  */
17
- has(key: string): boolean | Promise<boolean>;
17
+ has(key: string): boolean | Promise<boolean>
18
18
 
19
19
  /**
20
20
  * List the files in storage.
@@ -75,7 +75,7 @@ export interface FileStorage {
75
75
  * @param options Options for the list operation
76
76
  * @returns An object with an array of `files` and an optional `cursor` property
77
77
  */
78
- list<T extends ListOptions>(options?: T): ListResult<T> | Promise<ListResult<T>>;
78
+ list<T extends ListOptions>(options?: T): ListResult<T> | Promise<ListResult<T>>
79
79
 
80
80
  /**
81
81
  * Put a [`File`](https://developer.mozilla.org/en-US/docs/Web/API/File) in storage and return
@@ -84,14 +84,14 @@ export interface FileStorage {
84
84
  * @param file The file to store
85
85
  * @returns A new File object backed by this storage
86
86
  */
87
- put(key: string, file: File): File | Promise<File>;
87
+ put(key: string, file: File): File | Promise<File>
88
88
 
89
89
  /**
90
90
  * Remove the file with the given key from storage.
91
91
  * @param key The key to remove
92
92
  * @returns A promise that resolves when the file has been removed
93
93
  */
94
- remove(key: string): void | Promise<void>;
94
+ remove(key: string): void | Promise<void>
95
95
 
96
96
  /**
97
97
  * Put a [`File`](https://developer.mozilla.org/en-US/docs/Web/API/File) in storage at the given
@@ -100,14 +100,14 @@ export interface FileStorage {
100
100
  * @param file The file to store
101
101
  * @returns A promise that resolves when the file has been stored
102
102
  */
103
- set(key: string, file: File): void | Promise<void>;
103
+ set(key: string, file: File): void | Promise<void>
104
104
  }
105
105
 
106
106
  export interface FileKey {
107
107
  /**
108
108
  * The key of the file in storage.
109
109
  */
110
- key: string;
110
+ key: string
111
111
  }
112
112
 
113
113
  /**
@@ -117,38 +117,38 @@ export interface FileMetadata extends FileKey {
117
117
  /**
118
118
  * The last modified time of the file (in ms since the Unix epoch).
119
119
  */
120
- lastModified: number;
120
+ lastModified: number
121
121
  /**
122
122
  * The name of the file.
123
123
  */
124
- name: string;
124
+ name: string
125
125
  /**
126
126
  * The size of the file in bytes.
127
127
  */
128
- size: number;
128
+ size: number
129
129
  /**
130
130
  * The MIME type of the file.
131
131
  */
132
- type: string;
132
+ type: string
133
133
  }
134
134
 
135
135
  export interface ListOptions {
136
136
  /**
137
137
  * An opaque string that allows you to paginate over the keys in storage.
138
138
  */
139
- cursor?: string;
139
+ cursor?: string
140
140
  /**
141
141
  * If `true`, include file metadata in the result.
142
142
  */
143
- includeMetadata?: boolean;
143
+ includeMetadata?: boolean
144
144
  /**
145
145
  * The maximum number of files to return.
146
146
  */
147
- limit?: number;
147
+ limit?: number
148
148
  /**
149
149
  * Only return files with keys that start with this prefix.
150
150
  */
151
- prefix?: string;
151
+ prefix?: string
152
152
  }
153
153
 
154
154
  export interface ListResult<T extends ListOptions> {
@@ -156,9 +156,9 @@ export interface ListResult<T extends ListOptions> {
156
156
  * An opaque string that allows you to paginate over the keys in storage. Pass this back in the
157
157
  * `options` object on the next `list()` call to get the next page of results.
158
158
  */
159
- cursor?: string;
159
+ cursor?: string
160
160
  /**
161
161
  * A list of the files in storage.
162
162
  */
163
- files: (T extends { includeMetadata: true } ? FileMetadata : FileKey)[];
163
+ files: (T extends { includeMetadata: true } ? FileMetadata : FileKey)[]
164
164
  }