@remix-run/file-storage 0.8.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.
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 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 { filePath, metaPath } = await this.#getPaths(key);\n\n try {\n await Promise.all([fsp.unlink(filePath), fsp.unlink(metaPath)]);\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"],
5
+ "mappings": "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",
6
+ "names": ["fs", "path", "resolve"]
7
+ }
@@ -0,0 +1,86 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/memory.ts
21
+ var memory_exports = {};
22
+ __export(memory_exports, {
23
+ MemoryFileStorage: () => MemoryFileStorage
24
+ });
25
+ module.exports = __toCommonJS(memory_exports);
26
+
27
+ // src/lib/memory-file-storage.ts
28
+ var MemoryFileStorage = class {
29
+ #map = /* @__PURE__ */ new Map();
30
+ get(key) {
31
+ return this.#map.get(key) ?? null;
32
+ }
33
+ has(key) {
34
+ return this.#map.has(key);
35
+ }
36
+ list(options) {
37
+ let { cursor, includeMetadata = false, limit = Infinity, prefix } = options ?? {};
38
+ let files = [];
39
+ let foundCursor = cursor === void 0;
40
+ let nextCursor;
41
+ for (let [key, file] of this.#map.entries()) {
42
+ if (foundCursor) {
43
+ if (prefix != null && !key.startsWith(prefix)) {
44
+ continue;
45
+ }
46
+ if (files.length >= limit) {
47
+ nextCursor = files[files.length - 1]?.key;
48
+ break;
49
+ }
50
+ if (includeMetadata) {
51
+ files.push({
52
+ key,
53
+ lastModified: file.lastModified,
54
+ name: file.name,
55
+ size: file.size,
56
+ type: file.type
57
+ });
58
+ } else {
59
+ files.push({ key });
60
+ }
61
+ } else if (key === cursor) {
62
+ foundCursor = true;
63
+ }
64
+ }
65
+ return {
66
+ cursor: nextCursor,
67
+ files
68
+ };
69
+ }
70
+ async put(key, file) {
71
+ await this.set(key, file);
72
+ return this.get(key);
73
+ }
74
+ remove(key) {
75
+ this.#map.delete(key);
76
+ }
77
+ async set(key, file) {
78
+ let buffer = await file.arrayBuffer();
79
+ let newFile = new File([buffer], file.name, {
80
+ lastModified: file.lastModified,
81
+ type: file.type
82
+ });
83
+ this.#map.set(key, newFile);
84
+ }
85
+ };
86
+ //# sourceMappingURL=memory.cjs.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/memory.ts", "../src/lib/memory-file-storage.ts"],
4
+ "sourcesContent": ["export { MemoryFileStorage } from './lib/memory-file-storage.ts';\n", "import type { FileStorage, ListOptions, ListResult } from './file-storage.ts';\n\n/**\n * A simple, in-memory implementation of the `FileStorage` interface.\n *\n * Note: Any files you put in storage will have their entire contents buffered in memory, so this is not suitable for large files\n * in production scenarios.\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
+ "mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACQO,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
+ "names": []
7
+ }
@@ -0,0 +1,2 @@
1
+ export { MemoryFileStorage } from './lib/memory-file-storage.ts';
2
+ //# sourceMappingURL=memory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../src/memory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC"}
package/dist/memory.js ADDED
@@ -0,0 +1,63 @@
1
+ // src/lib/memory-file-storage.ts
2
+ var MemoryFileStorage = class {
3
+ #map = /* @__PURE__ */ new Map();
4
+ get(key) {
5
+ return this.#map.get(key) ?? null;
6
+ }
7
+ has(key) {
8
+ return this.#map.has(key);
9
+ }
10
+ list(options) {
11
+ let { cursor, includeMetadata = false, limit = Infinity, prefix } = options ?? {};
12
+ let files = [];
13
+ let foundCursor = cursor === void 0;
14
+ let nextCursor;
15
+ for (let [key, file] of this.#map.entries()) {
16
+ if (foundCursor) {
17
+ if (prefix != null && !key.startsWith(prefix)) {
18
+ continue;
19
+ }
20
+ if (files.length >= limit) {
21
+ nextCursor = files[files.length - 1]?.key;
22
+ break;
23
+ }
24
+ if (includeMetadata) {
25
+ files.push({
26
+ key,
27
+ lastModified: file.lastModified,
28
+ name: file.name,
29
+ size: file.size,
30
+ type: file.type
31
+ });
32
+ } else {
33
+ files.push({ key });
34
+ }
35
+ } else if (key === cursor) {
36
+ foundCursor = true;
37
+ }
38
+ }
39
+ return {
40
+ cursor: nextCursor,
41
+ files
42
+ };
43
+ }
44
+ async put(key, file) {
45
+ await this.set(key, file);
46
+ return this.get(key);
47
+ }
48
+ remove(key) {
49
+ this.#map.delete(key);
50
+ }
51
+ async set(key, file) {
52
+ let buffer = await file.arrayBuffer();
53
+ let newFile = new File([buffer], file.name, {
54
+ lastModified: file.lastModified,
55
+ type: file.type
56
+ });
57
+ this.#map.set(key, newFile);
58
+ }
59
+ };
60
+ export {
61
+ MemoryFileStorage
62
+ };
63
+ //# sourceMappingURL=memory.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 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 *\n * Note: Any files you put in storage will have their entire contents buffered in memory, so this is not suitable for large files\n * in production scenarios.\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
+ "mappings": ";AAQO,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
+ "names": []
7
+ }
package/package.json ADDED
@@ -0,0 +1,71 @@
1
+ {
2
+ "name": "@remix-run/file-storage",
3
+ "version": "0.8.0",
4
+ "description": "Key/value storage for JavaScript File objects",
5
+ "author": "Michael Jackson <mjijackson@gmail.com>",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/remix-run/remix.git",
9
+ "directory": "packages/file-storage"
10
+ },
11
+ "homepage": "https://github.com/remix-run/remix/tree/v3/packages/file-storage#readme",
12
+ "license": "MIT",
13
+ "files": [
14
+ "LICENSE",
15
+ "README.md",
16
+ "dist",
17
+ "src",
18
+ "!src/**/*.test.ts"
19
+ ],
20
+ "type": "module",
21
+ "types": "./dist/file-storage.d.ts",
22
+ "module": "./dist/file-storage.js",
23
+ "main": "./dist/file-storage.cjs",
24
+ "exports": {
25
+ ".": {
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"
30
+ },
31
+ "./local": {
32
+ "types": "./dist/local.d.ts",
33
+ "import": "./dist/local.js",
34
+ "require": "./dist/local.cjs",
35
+ "default": "./dist/local.js"
36
+ },
37
+ "./memory": {
38
+ "types": "./dist/memory.d.ts",
39
+ "import": "./dist/memory.js",
40
+ "require": "./dist/memory.cjs",
41
+ "default": "./dist/memory.js"
42
+ },
43
+ "./package.json": "./package.json"
44
+ },
45
+ "dependencies": {
46
+ "@remix-run/lazy-file": "^3.5.0"
47
+ },
48
+ "devDependencies": {
49
+ "@types/node": "^20.14.10",
50
+ "esbuild": "^0.25.5",
51
+ "@remix-run/form-data-parser": "^0.9.1"
52
+ },
53
+ "keywords": [
54
+ "file",
55
+ "storage",
56
+ "stream",
57
+ "fs"
58
+ ],
59
+ "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",
63
+ "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
+ "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",
68
+ "clean": "rm -rf dist",
69
+ "test": "node --disable-warning=ExperimentalWarning --test ./src/**/*.test.ts"
70
+ }
71
+ }
@@ -0,0 +1,7 @@
1
+ export type {
2
+ FileStorage,
3
+ FileKey,
4
+ FileMetadata,
5
+ ListOptions,
6
+ ListResult,
7
+ } from './lib/file-storage.ts';
@@ -0,0 +1,164 @@
1
+ /**
2
+ * A key/value interface for storing `File` objects.
3
+ */
4
+ export interface FileStorage {
5
+ /**
6
+ * Get a [`File`](https://developer.mozilla.org/en-US/docs/Web/API/File) at the given key.
7
+ * @param key The key to look up
8
+ * @returns The file with the given key, or `null` if no such key exists
9
+ */
10
+ get(key: string): File | null | Promise<File | null>;
11
+
12
+ /**
13
+ * Check if a file with the given key exists.
14
+ * @param key The key to look up
15
+ * @returns `true` if a file with the given key exists, `false` otherwise
16
+ */
17
+ has(key: string): boolean | Promise<boolean>;
18
+
19
+ /**
20
+ * List the files in storage.
21
+ *
22
+ * The following `options` are available:
23
+ *
24
+ * - `cursor`: An opaque string that allows you to paginate over the keys in storage
25
+ * - `includeMetadata`: If `true`, include file metadata in the result
26
+ * - `limit`: The maximum number of files to return
27
+ * - `prefix`: Only return keys that start with this string
28
+ *
29
+ * For example, to list all files under keys that start with `user123/`:
30
+ *
31
+ * ```ts
32
+ * let result = await storage.list({ prefix: 'user123/' });
33
+ * console.log(result.files);
34
+ * // [
35
+ * // { key: "user123/..." },
36
+ * // { key: "user123/..." },
37
+ * // ...
38
+ * // ]
39
+ * ```
40
+ *
41
+ * `result.files` will be an array of `{ key: string }` objects. To include metadata about each
42
+ * file, use `includeMetadata: true`.
43
+ *
44
+ * ```ts
45
+ * let result = await storage.list({ prefix: 'user123/', includeMetadata: true });
46
+ * console.log(result.files);
47
+ * // [
48
+ * // {
49
+ * // key: "user123/...",
50
+ * // lastModified: 1737955705270,
51
+ * // name: "hello.txt",
52
+ * // size: 16,
53
+ * // type: "text/plain"
54
+ * // },
55
+ * // ...
56
+ * // ]
57
+ * ```
58
+ *
59
+ * Pagination is done via an opaque `cursor` property in the list result object. If it is not
60
+ * `undefined`, there are more files to list. You can list them by passing the `cursor` back in
61
+ * the `options` object on the next call.
62
+ *
63
+ * ```ts
64
+ * let result = await storage.list();
65
+ *
66
+ * console.log(result.files);
67
+ *
68
+ * if (result.cursor !== undefined) {
69
+ * let result2 = await storage.list({ cursor: result.cursor });
70
+ * }
71
+ * ```
72
+ *
73
+ * Use the `limit` option to limit how many results you get back in the `files` array.
74
+ *
75
+ * @param options Options for the list operation
76
+ * @returns An object with an array of `files` and an optional `cursor` property
77
+ */
78
+ list<T extends ListOptions>(options?: T): ListResult<T> | Promise<ListResult<T>>;
79
+
80
+ /**
81
+ * Put a [`File`](https://developer.mozilla.org/en-US/docs/Web/API/File) in storage and return
82
+ * a new file backed by this storage.
83
+ * @param key The key to store the file under
84
+ * @param file The file to store
85
+ * @returns A new File object backed by this storage
86
+ */
87
+ put(key: string, file: File): File | Promise<File>;
88
+
89
+ /**
90
+ * Remove the file with the given key from storage.
91
+ * @param key The key to remove
92
+ * @returns A promise that resolves when the file has been removed
93
+ */
94
+ remove(key: string): void | Promise<void>;
95
+
96
+ /**
97
+ * Put a [`File`](https://developer.mozilla.org/en-US/docs/Web/API/File) in storage at the given
98
+ * key.
99
+ * @param key The key to store the file under
100
+ * @param file The file to store
101
+ * @returns A promise that resolves when the file has been stored
102
+ */
103
+ set(key: string, file: File): void | Promise<void>;
104
+ }
105
+
106
+ export interface FileKey {
107
+ /**
108
+ * The key of the file in storage.
109
+ */
110
+ key: string;
111
+ }
112
+
113
+ /**
114
+ * Metadata about a file in storage.
115
+ */
116
+ export interface FileMetadata extends FileKey {
117
+ /**
118
+ * The last modified time of the file (in ms since the Unix epoch).
119
+ */
120
+ lastModified: number;
121
+ /**
122
+ * The name of the file.
123
+ */
124
+ name: string;
125
+ /**
126
+ * The size of the file in bytes.
127
+ */
128
+ size: number;
129
+ /**
130
+ * The MIME type of the file.
131
+ */
132
+ type: string;
133
+ }
134
+
135
+ export interface ListOptions {
136
+ /**
137
+ * An opaque string that allows you to paginate over the keys in storage.
138
+ */
139
+ cursor?: string;
140
+ /**
141
+ * If `true`, include file metadata in the result.
142
+ */
143
+ includeMetadata?: boolean;
144
+ /**
145
+ * The maximum number of files to return.
146
+ */
147
+ limit?: number;
148
+ /**
149
+ * Only return files with keys that start with this prefix.
150
+ */
151
+ prefix?: string;
152
+ }
153
+
154
+ export interface ListResult<T extends ListOptions> {
155
+ /**
156
+ * An opaque string that allows you to paginate over the keys in storage. Pass this back in the
157
+ * `options` object on the next `list()` call to get the next page of results.
158
+ */
159
+ cursor?: string;
160
+ /**
161
+ * A list of the files in storage.
162
+ */
163
+ files: (T extends { includeMetadata: true } ? FileMetadata : FileKey)[];
164
+ }