UNPKG

@huggingface/blob

Version:

Utilities to convert URLs and files to Blobs, internally used by Hugging Face libs

224 lines (217 loc) 7.13 kB
"use strict"; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __hasOwnProp = Object.prototype.hasOwnProperty; var __esm = (fn, res) => function __init() { return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res; }; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/utils/FileBlob.ts var FileBlob_exports = {}; __export(FileBlob_exports, { FileBlob: () => FileBlob }); var import_node_fs, import_promises, import_node_stream, import_node_url, FileBlob; var init_FileBlob = __esm({ "src/utils/FileBlob.ts"() { "use strict"; import_node_fs = require("fs"); import_promises = require("fs/promises"); import_node_stream = require("stream"); import_node_url = require("url"); FileBlob = class extends Blob { /** * Creates a new FileBlob on the provided file. * * @param path Path to the file to be lazy readed */ static async create(path) { path = path instanceof URL ? (0, import_node_url.fileURLToPath)(path) : path; const { size } = await (0, import_promises.stat)(path); const fileBlob = new FileBlob(path, 0, size); return fileBlob; } path; start; end; constructor(path, start, end) { super(); this.path = path; this.start = start; this.end = end; } /** * Returns the size of the blob. */ get size() { return this.end - this.start; } /** * Returns a new instance of FileBlob that is a slice of the current one. * * The slice is inclusive of the start and exclusive of the end. * * The slice method does not supports negative start/end. * * @param start beginning of the slice * @param end end of the slice */ slice(start = 0, end = this.size) { if (start < 0 || end < 0) { new TypeError("Unsupported negative start/end on FileBlob.slice"); } const slice = new FileBlob(this.path, this.start + start, Math.min(this.start + end, this.end)); return slice; } /** * Read the part of the file delimited by the FileBlob and returns it as an ArrayBuffer. */ async arrayBuffer() { const slice = await this.execute((file) => file.read(Buffer.alloc(this.size), 0, this.size, this.start)); return slice.buffer; } /** * Read the part of the file delimited by the FileBlob and returns it as a string. */ async text() { const buffer = await this.arrayBuffer(); return buffer.toString("utf8"); } /** * Returns a stream around the part of the file delimited by the FileBlob. */ stream() { return import_node_stream.Readable.toWeb((0, import_node_fs.createReadStream)(this.path, { start: this.start, end: this.end - 1 })); } /** * We are opening and closing the file for each action to prevent file descriptor leaks. * * It is an intended choice of developer experience over performances. */ async execute(action) { const file = await (0, import_promises.open)(this.path, "r"); try { return await action(file); } finally { await file.close(); } } }; } }); // index.ts var blob_exports = {}; __export(blob_exports, { createBlob: () => createBlob }); module.exports = __toCommonJS(blob_exports); // src/utils/WebBlob.ts var WebBlob = class extends Blob { static async create(url, opts) { const customFetch = opts?.fetch ?? fetch; const response = await customFetch(url, { method: "HEAD" }); const size = Number(response.headers.get("content-length")); const contentType = response.headers.get("content-type") || ""; const supportRange = response.headers.get("accept-ranges") === "bytes"; if (!supportRange || size < (opts?.cacheBelow ?? 1e6)) { return await (await customFetch(url)).blob(); } return new WebBlob(url, 0, size, contentType, true, customFetch); } url; start; end; contentType; full; fetch; constructor(url, start, end, contentType, full, customFetch) { super([]); this.url = url; this.start = start; this.end = end; this.contentType = contentType; this.full = full; this.fetch = customFetch; } get size() { return this.end - this.start; } get type() { return this.contentType; } slice(start = 0, end = this.size) { if (start < 0 || end < 0) { new TypeError("Unsupported negative start/end on FileBlob.slice"); } const slice = new WebBlob( this.url, this.start + start, Math.min(this.start + end, this.end), this.contentType, start === 0 && end === this.size ? this.full : false, this.fetch ); return slice; } async arrayBuffer() { const result = await this.fetchRange(); return result.arrayBuffer(); } async text() { const result = await this.fetchRange(); return result.text(); } stream() { const stream = new TransformStream(); this.fetchRange().then((response) => response.body?.pipeThrough(stream)).catch((error) => stream.writable.abort(error.message)); return stream.readable; } fetchRange() { const fetch2 = this.fetch; if (this.full) { return fetch2(this.url); } return fetch2(this.url, { headers: { Range: `bytes=${this.start}-${this.end - 1}` } }); } }; // src/utils/isBackend.ts var isBrowser = typeof window !== "undefined" && typeof window.document !== "undefined"; var isWebWorker = typeof self === "object" && self.constructor && self.constructor.name === "DedicatedWorkerGlobalScope"; var isBackend = !isBrowser && !isWebWorker; // src/utils/isFrontend.ts var isFrontend = !isBackend; // src/utils/createBlob.ts async function createBlob(url, opts) { if (url.protocol === "http:" || url.protocol === "https:") { return WebBlob.create(url, { fetch: opts?.fetch }); } if (isFrontend) { throw new TypeError(`Unsupported URL protocol "${url.protocol}"`); } if (url.protocol === "file:") { const { FileBlob: FileBlob2 } = await Promise.resolve().then(() => (init_FileBlob(), FileBlob_exports)); return FileBlob2.create(url); } throw new TypeError(`Unsupported URL protocol "${url.protocol}"`); } // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { createBlob });