Spaces:
Sleeping
Sleeping
| ; | |
| var __create = Object.create; | |
| var __defProp = Object.defineProperty; | |
| var __getOwnPropDesc = Object.getOwnPropertyDescriptor; | |
| var __getOwnPropNames = Object.getOwnPropertyNames; | |
| var __getProtoOf = Object.getPrototypeOf; | |
| var __hasOwnProp = Object.prototype.hasOwnProperty; | |
| var __esm = (fn, res) => function __init() { | |
| return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res; | |
| }; | |
| var __commonJS = (cb, mod) => function __require() { | |
| return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; | |
| }; | |
| 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 __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( | |
| // If the importer is in node compatibility mode or this is not an ESM | |
| // file that has been converted to a CommonJS file using a Babel- | |
| // compatible transform (i.e. "__esModule" has not been set), then set | |
| // "default" to the CommonJS "module.exports" for node compatibility. | |
| isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, | |
| mod | |
| )); | |
| // src/vendor/hash-wasm/sha256.js | |
| var import_meta, Module, sha256_default; | |
| var init_sha256 = __esm({ | |
| "src/vendor/hash-wasm/sha256.js"() { | |
| "use strict"; | |
| import_meta = {}; | |
| Module = (() => { | |
| var _unused = import_meta.url; | |
| return function(moduleArg = {}) { | |
| var Module2 = moduleArg; | |
| var readyPromiseResolve, readyPromiseReject; | |
| Module2["ready"] = new Promise((resolve3, reject) => { | |
| readyPromiseResolve = resolve3; | |
| readyPromiseReject = reject; | |
| }); | |
| var moduleOverrides = Object.assign({}, Module2); | |
| var arguments_ = []; | |
| var thisProgram = "./this.program"; | |
| var quit_ = (status, toThrow) => { | |
| throw toThrow; | |
| }; | |
| var ENVIRONMENT_IS_WEB = typeof window == "object"; | |
| var ENVIRONMENT_IS_WORKER = typeof importScripts == "function"; | |
| var ENVIRONMENT_IS_NODE = typeof process == "object" && typeof process.versions == "object" && typeof process.versions.node == "string"; | |
| var ENVIRONMENT_IS_SHELL = !ENVIRONMENT_IS_WEB && !ENVIRONMENT_IS_NODE && !ENVIRONMENT_IS_WORKER; | |
| var scriptDirectory = ""; | |
| function locateFile(path2) { | |
| if (Module2["locateFile"]) { | |
| return Module2["locateFile"](path2, scriptDirectory); | |
| } | |
| return scriptDirectory + path2; | |
| } | |
| var read_, readAsync, readBinary; | |
| if (ENVIRONMENT_IS_WEB || ENVIRONMENT_IS_WORKER) { | |
| if (ENVIRONMENT_IS_WORKER) { | |
| scriptDirectory = self.location.href; | |
| } else if (typeof document != "undefined" && document.currentScript) { | |
| scriptDirectory = document.currentScript.src; | |
| } | |
| if (false) { | |
| scriptDirectory = false; | |
| } | |
| if (scriptDirectory.startsWith("blob:")) { | |
| scriptDirectory = ""; | |
| } else { | |
| scriptDirectory = scriptDirectory.substr(0, scriptDirectory.replace(/[?#].*/, "").lastIndexOf("/") + 1); | |
| } | |
| { | |
| read_ = (url) => { | |
| var xhr = new XMLHttpRequest(); | |
| xhr.open("GET", url, false); | |
| xhr.send(null); | |
| return xhr.responseText; | |
| }; | |
| if (ENVIRONMENT_IS_WORKER) { | |
| readBinary = (url) => { | |
| var xhr = new XMLHttpRequest(); | |
| xhr.open("GET", url, false); | |
| xhr.responseType = "arraybuffer"; | |
| xhr.send(null); | |
| return new Uint8Array( | |
| /** @type{!ArrayBuffer} */ | |
| xhr.response | |
| ); | |
| }; | |
| } | |
| readAsync = (url, onload, onerror) => { | |
| var xhr = new XMLHttpRequest(); | |
| xhr.open("GET", url, true); | |
| xhr.responseType = "arraybuffer"; | |
| xhr.onload = () => { | |
| if (xhr.status == 200 || xhr.status == 0 && xhr.response) { | |
| onload(xhr.response); | |
| return; | |
| } | |
| onerror(); | |
| }; | |
| xhr.onerror = onerror; | |
| xhr.send(null); | |
| }; | |
| } | |
| } else { | |
| } | |
| var out = Module2["print"] || console.log.bind(console); | |
| var err = Module2["printErr"] || console.error.bind(console); | |
| Object.assign(Module2, moduleOverrides); | |
| moduleOverrides = null; | |
| if (Module2["arguments"]) | |
| arguments_ = Module2["arguments"]; | |
| if (Module2["thisProgram"]) | |
| thisProgram = Module2["thisProgram"]; | |
| if (Module2["quit"]) | |
| quit_ = Module2["quit"]; | |
| var wasmBinary; | |
| if (Module2["wasmBinary"]) | |
| wasmBinary = Module2["wasmBinary"]; | |
| if (typeof WebAssembly != "object") { | |
| abort("no native wasm support detected"); | |
| } | |
| function intArrayFromBase64(s) { | |
| var decoded = atob(s); | |
| var bytes = new Uint8Array(decoded.length); | |
| for (var i = 0; i < decoded.length; ++i) { | |
| bytes[i] = decoded.charCodeAt(i); | |
| } | |
| return bytes; | |
| } | |
| function tryParseAsDataURI(filename) { | |
| if (!isDataURI(filename)) { | |
| return; | |
| } | |
| return intArrayFromBase64(filename.slice(dataURIPrefix.length)); | |
| } | |
| var wasmMemory; | |
| var ABORT = false; | |
| var EXITSTATUS; | |
| function assert(condition, text) { | |
| if (!condition) { | |
| abort(text); | |
| } | |
| } | |
| var HEAP, HEAP8, HEAPU8, HEAP16, HEAPU16, HEAP32, HEAPU32, HEAPF32, HEAPF64; | |
| function updateMemoryViews() { | |
| var b = wasmMemory.buffer; | |
| Module2["HEAP8"] = HEAP8 = new Int8Array(b); | |
| Module2["HEAP16"] = HEAP16 = new Int16Array(b); | |
| Module2["HEAPU8"] = HEAPU8 = new Uint8Array(b); | |
| Module2["HEAPU16"] = HEAPU16 = new Uint16Array(b); | |
| Module2["HEAP32"] = HEAP32 = new Int32Array(b); | |
| Module2["HEAPU32"] = HEAPU32 = new Uint32Array(b); | |
| Module2["HEAPF32"] = HEAPF32 = new Float32Array(b); | |
| Module2["HEAPF64"] = HEAPF64 = new Float64Array(b); | |
| } | |
| var __ATPRERUN__ = []; | |
| var __ATINIT__ = []; | |
| var __ATEXIT__ = []; | |
| var __ATPOSTRUN__ = []; | |
| var runtimeInitialized = false; | |
| function preRun() { | |
| if (Module2["preRun"]) { | |
| if (typeof Module2["preRun"] == "function") | |
| Module2["preRun"] = [Module2["preRun"]]; | |
| while (Module2["preRun"].length) { | |
| addOnPreRun(Module2["preRun"].shift()); | |
| } | |
| } | |
| callRuntimeCallbacks(__ATPRERUN__); | |
| } | |
| function initRuntime() { | |
| runtimeInitialized = true; | |
| callRuntimeCallbacks(__ATINIT__); | |
| } | |
| function postRun() { | |
| if (Module2["postRun"]) { | |
| if (typeof Module2["postRun"] == "function") | |
| Module2["postRun"] = [Module2["postRun"]]; | |
| while (Module2["postRun"].length) { | |
| addOnPostRun(Module2["postRun"].shift()); | |
| } | |
| } | |
| callRuntimeCallbacks(__ATPOSTRUN__); | |
| } | |
| function addOnPreRun(cb) { | |
| __ATPRERUN__.unshift(cb); | |
| } | |
| function addOnInit(cb) { | |
| __ATINIT__.unshift(cb); | |
| } | |
| function addOnExit(cb) { | |
| } | |
| function addOnPostRun(cb) { | |
| __ATPOSTRUN__.unshift(cb); | |
| } | |
| var runDependencies = 0; | |
| var runDependencyWatcher = null; | |
| var dependenciesFulfilled = null; | |
| function getUniqueRunDependency(id) { | |
| return id; | |
| } | |
| function addRunDependency(id) { | |
| runDependencies++; | |
| Module2["monitorRunDependencies"]?.(runDependencies); | |
| } | |
| function removeRunDependency(id) { | |
| runDependencies--; | |
| Module2["monitorRunDependencies"]?.(runDependencies); | |
| if (runDependencies == 0) { | |
| if (runDependencyWatcher !== null) { | |
| clearInterval(runDependencyWatcher); | |
| runDependencyWatcher = null; | |
| } | |
| if (dependenciesFulfilled) { | |
| var callback = dependenciesFulfilled; | |
| dependenciesFulfilled = null; | |
| callback(); | |
| } | |
| } | |
| } | |
| function abort(what) { | |
| Module2["onAbort"]?.(what); | |
| what = "Aborted(" + what + ")"; | |
| err(what); | |
| ABORT = true; | |
| EXITSTATUS = 1; | |
| what += ". Build with -sASSERTIONS for more info."; | |
| var e = new WebAssembly.RuntimeError(what); | |
| readyPromiseReject(e); | |
| throw e; | |
| } | |
| var dataURIPrefix = "data:application/octet-stream;base64,"; | |
| var isDataURI = (filename) => filename.startsWith(dataURIPrefix); | |
| var isFileURI = (filename) => filename.startsWith("file://"); | |
| var wasmBinaryFile; | |
| wasmBinaryFile = "data:application/octet-stream;base64,AGFzbQEAAAABHQZgAX8AYAABf2AAAGABfwF/YAJ/fwBgA39/fwF/Aw0MAgAEAgMBBQABAQADBAUBcAEBAQUGAQGAAoACBg4CfwFB8IuEBAt/AUEACweYAQoGbWVtb3J5AgARX193YXNtX2NhbGxfY3RvcnMAAAtIYXNoX1VwZGF0ZQABCkhhc2hfRmluYWwAAwlIYXNoX0luaXQABAxHZXRCdWZmZXJQdHIABRlfX2luZGlyZWN0X2Z1bmN0aW9uX3RhYmxlAQAJc3RhY2tTYXZlAAkMc3RhY2tSZXN0b3JlAAoKc3RhY2tBbGxvYwALCossDAIAC+4CAgV/AX5BACgCwAoiASABKQNAIgYgAK18NwNAAkACQAJAIAanQT9xIgINAEGACyEBIAAhAgwBC0HAACACayEDAkAgAEUNACADIAAgAyAASRshBCABIAJqIQVBACEBA0AgBSABIgFqQYALIAFqLQAAOgAAIAFBAWoiAiEBIAIgBEcNAAsLAkACQCAAIANJIgRFDQBBgAshASAAIQIMAQtBACgCwAoiAUHIAGogARACQYALIANqIQEgACADayECCyABIQEgAiECIAQNAQsgASEBAkACQCACIgJBwABPDQAgASEFIAIhAAwBCyACIQIgASEEA0BBACgCwApByABqIAQiBBACIAJBQGoiASECIARBwABqIgUhBCAFIQUgASEAIAFBP0sNAAsLIAUhBSAAIgBFDQBBACEBQQAhAgNAQQAoAsAKIAEiAWogBSABai0AADoAACACQQFqIgJB/wFxIgQhASACIQIgACAESw0ACwsLqCEBK38gACgCCCICIAAoAgQiAyAAKAIAIgRzcSADIARxcyAEQR53IARBE3dzIARBCndzaiAAKAIQIgVBGncgBUEVd3MgBUEHd3MgACgCHCIGaiAAKAIYIgcgACgCFCIIcyAFcSAHc2ogASgCACIJQRh0IAlBgP4DcUEIdHIgCUEIdkGA/gNxIAlBGHZyciIKakGY36iUBGoiC2oiCSAEcyADcSAJIARxcyAJQR53IAlBE3dzIAlBCndzaiAHIAEoAgQiDEEYdCAMQYD+A3FBCHRyIAxBCHZBgP4DcSAMQRh2cnIiDWogCyAAKAIMIg5qIg8gCCAFc3EgCHNqIA9BGncgD0EVd3MgD0EHd3NqQZGJ3YkHaiIQaiIMIAlzIARxIAwgCXFzIAxBHncgDEETd3MgDEEKd3NqIAggASgCCCILQRh0IAtBgP4DcUEIdHIgC0EIdkGA/gNxIAtBGHZyciIRaiAQIAJqIhIgDyAFc3EgBXNqIBJBGncgEkEVd3MgEkEHd3NqQc/3g657aiITaiILIAxzIAlxIAsgDHFzIAtBHncgC0ETd3MgC0EKd3NqIAUgASgCDCIQQRh0IBBBgP4DcUEIdHIgEEEIdkGA/gNxIBBBGHZyciIUaiATIANqIhMgEiAPc3EgD3NqIBNBGncgE0EVd3MgE0EHd3NqQaW3181+aiIVaiIQIAtzIAxxIBAgC3FzIBBBHncgEEETd3MgEEEKd3NqIA8gASgCECIWQRh0IBZBgP4DcUEIdHIgFkEIdkGA/gNxIBZBGHZyciIXaiAVIARqIhYgEyASc3EgEnNqIBZBGncgFkEVd3MgFkEHd3NqQduE28oDaiIYaiIPIBBzIAtxIA8gEHFzIA9BHncgD0ETd3MgD0EKd3NqIAEoAhQiFUEYdCAVQYD+A3FBCHRyIBVBCHZBgP4DcSAVQRh2cnIiGSASaiAYIAlqIhIgFiATc3EgE3NqIBJBGncgEkEVd3MgEkEHd3NqQfGjxM8FaiIYaiIJIA9zIBBxIAkgD3FzIAlBHncgCUETd3MgCUEKd3NqIAEoAhgiFUEYdCAVQYD+A3FBCHRyIBVBCHZBgP4DcSAVQRh2cnIiGiATaiAYIAxqIhMgEiAWc3EgFnNqIBNBGncgE0EVd3MgE0EHd3NqQaSF/pF5aiIYaiIMIAlzIA9xIAwgCXFzIAxBHncgDEETd3MgDEEKd3NqIAEoAhwiFUEYdCAVQYD+A3FBCHRyIBVBCHZBgP4DcSAVQRh2cnIiGyAWaiAYIAtqIhYgEyASc3EgEnNqIBZBGncgFkEVd3MgFkEHd3NqQdW98dh6aiIYaiILIAxzIAlxIAsgDHFzIAtBHncgC0ETd3MgC0EKd3NqIAEoAiAiFUEYdCAVQYD+A3FBCHRyIBVBCHZBgP4DcSAVQRh2cnIiHCASaiAYIBBqIhIgFiATc3EgE3NqIBJBGncgEkEVd3MgEkEHd3NqQZjVnsB9aiIYaiIQIAtzIAxxIBAgC3FzIBBBHncgEEETd3MgEEEKd3NqIAEoAiQiFUEYdCAVQYD+A3FBCHRyIBVBCHZBgP4DcSAVQRh2cnIiHSATaiAYIA9qIhMgEiAWc3EgFnNqIBNBGncgE0EVd3MgE0EHd3NqQYG2jZQBaiIYaiIPIBBzIAtxIA8gEHFzIA9BHncgD0ETd3MgD0EKd3NqIAEoAigiFUEYdCAVQYD+A3FBCHRyIBVBCHZBgP4DcSAVQRh2cnIiHiAWaiAYIAlqIhYgEyASc3EgEnNqIBZBGncgFkEVd3MgFkEHd3NqQb6LxqECaiIYaiIJIA9zIBBxIAkgD3FzIAlBHncgCUETd3MgCUEKd3NqIAEoAiwiFUEYdCAVQYD+A3FBCHRyIBVBCHZBgP4DcSAVQRh2cnIiHyASaiAYIAxqIhIgFiATc3EgE3NqIBJBGncgEkEVd3MgEkEHd3NqQcP7sagFaiIYaiIMIAlzIA9xIAwgCXFzIAxBHncgDEETd3MgDEEKd3NqIAEoAjAiFUEYdCAVQYD+A3FBCHRyIBVBCHZBgP4DcSAVQRh2cnIiICATaiAYIAtqIhMgEiAWc3EgFnNqIBNBGncgE0EVd3MgE0EHd3NqQfS6+ZUHaiIYaiILIAxzIAlxIAsgDHFzIAtBHncgC0ETd3MgC0EKd3NqIAEoAjQiFUEYdCAVQYD+A3FBCHRyIBVBCHZBgP4DcSAVQRh2cnIiISAWaiAYIBBqIhAgEyASc3EgEnNqIBBBGncgEEEVd3MgEEEHd3NqQf7j+oZ4aiIYaiIWIAtzIAxxIBYgC3FzIBZBHncgFkETd3MgFkEKd3NqIAEoAjgiFUEYdCAVQYD+A3FBCHRyIBVBCHZBgP4DcSAVQRh2cnIiIiASaiAYIA9qIg8gECATc3EgE3NqIA9BGncgD0EVd3MgD0EHd3NqQaeN8N55aiIVaiISIBZzIAtxIBIgFnFzIBJBHncgEkETd3MgEkEKd3NqIAEoAjwiAUEYdCABQYD+A3FBCHRyIAFBCHZBgP4DcSABQRh2cnIiIyATaiAVIAlqIgEgDyAQc3EgEHNqIAFBGncgAUEVd3MgAUEHd3NqQfTi74x8aiIJaiEVIBIhGCAWISQgCyElIAkgDGohJiABIScgDyEoIBAhKSAjISMgIiEiICEhISAgISAgHyEfIB4hHiAdIR0gHCEcIBshGyAaIRogGSEZIBchFyAUIRQgESERIA0hECAKIQxBgAkhAUEQISoDQCAVIgkgGCIKcyAkIitxIAkgCnFzIAlBHncgCUETd3MgCUEKd3NqIBAiEEEZdyAQQQ53cyAQQQN2cyAMaiAdIh1qICIiFkEPdyAWQQ13cyAWQQp2c2oiDCApaiAmIhIgJyIPICgiE3NxIBNzaiASQRp3IBJBFXdzIBJBB3dzaiABIgEoAgBqIiRqIgsgCXMgCnEgCyAJcXMgC0EedyALQRN3cyALQQp3c2ogESIYQRl3IBhBDndzIBhBA3ZzIBBqIB4iHmogIyIVQQ93IBVBDXdzIBVBCnZzaiINIBNqIAEoAgRqICQgJWoiEyASIA9zcSAPc2ogE0EadyATQRV3cyATQQd3c2oiJWoiECALcyAJcSAQIAtxcyAQQR53IBBBE3dzIBBBCndzaiAUIiRBGXcgJEEOd3MgJEEDdnMgGGogHyIfaiAMQQ93IAxBDXdzIAxBCnZzaiIRIA9qIAEoAghqICUgK2oiGCATIBJzcSASc2ogGEEadyAYQRV3cyAYQQd3c2oiJWoiDyAQcyALcSAPIBBxcyAPQR53IA9BE3dzIA9BCndzaiAXIhdBGXcgF0EOd3MgF0EDdnMgJGogICIgaiANQQ93IA1BDXdzIA1BCnZzaiIUIBJqIAEoAgxqICUgCmoiCiAYIBNzcSATc2ogCkEadyAKQRV3cyAKQQd3c2oiJWoiEiAPcyAQcSASIA9xcyASQR53IBJBE3dzIBJBCndzaiATIBkiJEEZdyAkQQ53cyAkQQN2cyAXaiAhIiFqIBFBD3cgEUENd3MgEUEKdnNqIhdqIAEoAhBqICUgCWoiEyAKIBhzcSAYc2ogE0EadyATQRV3cyATQQd3c2oiJWoiCSAScyAPcSAJIBJxcyAJQR53IAlBE3dzIAlBCndzaiABKAIUIBoiGkEZdyAaQQ53cyAaQQN2cyAkaiAWaiAUQQ93IBRBDXdzIBRBCnZzaiIZaiAYaiAlIAtqIhggEyAKc3EgCnNqIBhBGncgGEEVd3MgGEEHd3NqIiVqIgsgCXMgEnEgCyAJcXMgC0EedyALQRN3cyALQQp3c2ogASgCGCAbIiRBGXcgJEEOd3MgJEEDdnMgGmogFWogF0EPdyAXQQ13cyAXQQp2c2oiGmogCmogJSAQaiIKIBggE3NxIBNzaiAKQRp3IApBFXdzIApBB3dzaiIlaiIQIAtzIAlxIBAgC3FzIBBBHncgEEETd3MgEEEKd3NqIAEoAhwgHCIcQRl3IBxBDndzIBxBA3ZzICRqIAxqIBlBD3cgGUENd3MgGUEKdnNqIhtqIBNqICUgD2oiJCAKIBhzcSAYc2ogJEEadyAkQRV3cyAkQQd3c2oiE2oiDyAQcyALcSAPIBBxcyAPQR53IA9BE3dzIA9BCndzaiABKAIgIB1BGXcgHUEOd3MgHUEDdnMgHGogDWogGkEPdyAaQQ13cyAaQQp2c2oiHGogGGogEyASaiIYICQgCnNxIApzaiAYQRp3IBhBFXdzIBhBB3dzaiITaiISIA9zIBBxIBIgD3FzIBJBHncgEkETd3MgEkEKd3NqIAEoAiQgHkEZdyAeQQ53cyAeQQN2cyAdaiARaiAbQQ93IBtBDXdzIBtBCnZzaiIdaiAKaiATIAlqIgkgGCAkc3EgJHNqIAlBGncgCUEVd3MgCUEHd3NqIgpqIhMgEnMgD3EgEyAScXMgE0EedyATQRN3cyATQQp3c2ogASgCKCAfQRl3IB9BDndzIB9BA3ZzIB5qIBRqIBxBD3cgHEENd3MgHEEKdnNqIh5qICRqIAogC2oiCiAJIBhzcSAYc2ogCkEadyAKQRV3cyAKQQd3c2oiJGoiCyATcyAScSALIBNxcyALQR53IAtBE3dzIAtBCndzaiABKAIsICBBGXcgIEEOd3MgIEEDdnMgH2ogF2ogHUEPdyAdQQ13cyAdQQp2c2oiH2ogGGogJCAQaiIYIAogCXNxIAlzaiAYQRp3IBhBFXdzIBhBB3dzaiIkaiIQIAtzIBNxIBAgC3FzIBBBHncgEEETd3MgEEEKd3NqIAEoAjAgIUEZdyAhQQ53cyAhQQN2cyAgaiAZaiAeQQ93IB5BDXdzIB5BCnZzaiIgaiAJaiAkIA9qIiQgGCAKc3EgCnNqICRBGncgJEEVd3MgJEEHd3NqIg9qIgkgEHMgC3EgCSAQcXMgCUEedyAJQRN3cyAJQQp3c2ogASgCNCAWQRl3IBZBDndzIBZBA3ZzICFqIBpqIB9BD3cgH0ENd3MgH0EKdnNqIiFqIApqIA8gEmoiDyAkIBhzcSAYc2ogD0EadyAPQRV3cyAPQQd3c2oiCmoiEiAJcyAQcSASIAlxcyASQR53IBJBE3dzIBJBCndzaiABKAI4IBVBGXcgFUEOd3MgFUEDdnMgFmogG2ogIEEPdyAgQQ13cyAgQQp2c2oiImogGGogCiATaiITIA8gJHNxICRzaiATQRp3IBNBFXdzIBNBB3dzaiIYaiIWIBJzIAlxIBYgEnFzIBZBHncgFkETd3MgFkEKd3NqIAEoAjwgDEEZdyAMQQ53cyAMQQN2cyAVaiAcaiAhQQ93ICFBDXdzICFBCnZzaiIKaiAkaiAYIAtqIgsgEyAPc3EgD3NqIAtBGncgC0EVd3MgC0EHd3NqIiZqIishFSAWIRggEiEkIAkhJSAmIBBqIiwhJiALIScgEyEoIA8hKSAKISMgIiEiICEhISAgISAgHyEfIB4hHiAdIR0gHCEcIBshGyAaIRogGSEZIBchFyAUIRQgESERIA0hECAMIQwgAUHAAGohASAqIgpBEGohKiAKQTBJDQALIAAgDyAGajYCHCAAIBMgB2o2AhggACALIAhqNgIUIAAgLCAFajYCECAAIAkgDmo2AgwgACASIAJqNgIIIAAgFiADajYCBCAAICsgBGo2AgAL1AMDBX8BfgF7QQAoAsAKIgAgACgCQCIBQQJ2QQ9xIgJBAnRqIgMgAygCAEF/IAFBA3QiAXRBf3NxQYABIAF0czYCAAJAAkAgAkEOTw0AIAJBAWohAAwBCwJAIAJBDkcNACAAQQA2AjwLIABByABqIAAQAkEAIQALAkAgACIAQQ1LDQBBACgCwAogAEECdCIAakEAQTggAGsQBhoLQQAoAsAKIgAgACkDQCIFpyICQRt0IAJBC3RBgID8B3FyIAJBBXZBgP4DcSACQQN0QRh2cnI2AjwgACAFQh2IpyICQRh0IAJBgP4DcUEIdHIgAkEIdkGA/gNxIAJBGHZycjYCOCAAQcgAaiAAEAJBACgCwApBPGohAUEAIQADQCABQQcgACIAa0ECdGoiAiAC/QACACAG/Q0MDQ4PCAkKCwQFBgcAAQIDIAb9DQMCAQAHBgUECwoJCA8ODQwgBv0NDA0ODwgJCgsEBQYHAAECA/0LAgAgAEEEaiICIQAgAkEIRw0ACwJAQQAoAsAKIgMoAmhFDQAgA0HIAGohBEEAIQBBACECA0BBgAsgACIAaiAEIABqLQAAOgAAIAJBAWoiAkH/AXEiASEAIAIhAiADKAJoIAFLDQALCwtxAQJ/QQAoAsAKIgFCADcDQCABQcgAaiECAkAgAEHgAUcNACABQRw2AmggAkEQakEA/QAEsAj9CwIAIAJBAP0ABKAI/QsCAEEADwsgAUEgNgJoIAJBEGpBAP0ABJAI/QsCACACQQD9AASACP0LAgBBAAsFAEGACwvyAgIDfwF+AkAgAkUNACAAIAE6AAAgACACaiIDQX9qIAE6AAAgAkEDSQ0AIAAgAToAAiAAIAE6AAEgA0F9aiABOgAAIANBfmogAToAACACQQdJDQAgACABOgADIANBfGogAToAACACQQlJDQAgAEEAIABrQQNxIgRqIgMgAUH/AXFBgYKECGwiATYCACADIAIgBGtBfHEiBGoiAkF8aiABNgIAIARBCUkNACADIAE2AgggAyABNgIEIAJBeGogATYCACACQXRqIAE2AgAgBEEZSQ0AIAMgATYCGCADIAE2AhQgAyABNgIQIAMgATYCDCACQXBqIAE2AgAgAkFsaiABNgIAIAJBaGogATYCACACQWRqIAE2AgAgBCADQQRxQRhyIgVrIgJBIEkNACABrUKBgICAEH4hBiADIAVqIQEDQCABIAY3AxggASAGNwMQIAEgBjcDCCABIAY3AwAgAUEgaiEBIAJBYGoiAkEfSw0ACwsgAAsGACAAJAELBAAjAQsEACMACwYAIAAkAAsSAQJ/IwAgAGtBcHEiASQAIAELC9ICAgBBgAgLwAJn5glqha5nu3Lzbjw69U+lf1IOUYxoBZur2YMfGc3gW9ieBcEH1Xw2F91wMDlZDvcxC8D/ERVYaKeP+WSkT/q+mC+KQpFEN3HP+8C1pdu16VvCVjnxEfFZpII/ktVeHKuYqgfYAVuDEr6FMSTDfQxVdF2+cv6x3oCnBtybdPGbwcFpm+SGR77vxp3BD8yhDCRvLOktqoR0StypsFzaiPl2UlE+mG3GMajIJwOwx39Zv/ML4MZHkafVUWPKBmcpKRSFCrcnOCEbLvxtLE0TDThTVHMKZbsKanYuycKBhSxykqHov6JLZhqocItLwqNRbMcZ6JLRJAaZ1oU1DvRwoGoQFsGkGQhsNx5Md0gntbywNLMMHDlKqthOT8qcW/NvLmjugo90b2OleBR4yIQIAseM+v++kOtsUKT3o/m+8nhxxgBBwAoLBIAFgAA="; | |
| if (!isDataURI(wasmBinaryFile)) { | |
| wasmBinaryFile = locateFile(wasmBinaryFile); | |
| } | |
| function getBinarySync(file) { | |
| if (file == wasmBinaryFile && wasmBinary) { | |
| return new Uint8Array(wasmBinary); | |
| } | |
| var binary = tryParseAsDataURI(file); | |
| if (binary) { | |
| return binary; | |
| } | |
| if (readBinary) { | |
| return readBinary(file); | |
| } | |
| throw "both async and sync fetching of the wasm failed"; | |
| } | |
| function getBinaryPromise(binaryFile) { | |
| return Promise.resolve().then(() => getBinarySync(binaryFile)); | |
| } | |
| function instantiateArrayBuffer(binaryFile, imports, receiver) { | |
| return getBinaryPromise(binaryFile).then((binary) => { | |
| return WebAssembly.instantiate(binary, imports); | |
| }).then(receiver, (reason) => { | |
| err(`failed to asynchronously prepare wasm: ${reason}`); | |
| abort(reason); | |
| }); | |
| } | |
| function instantiateAsync(binary, binaryFile, imports, callback) { | |
| return instantiateArrayBuffer(binaryFile, imports, callback); | |
| } | |
| function createWasm() { | |
| var info = { | |
| "env": wasmImports, | |
| "wasi_snapshot_preview1": wasmImports | |
| }; | |
| function receiveInstance(instance, module2) { | |
| wasmExports = instance.exports; | |
| wasmMemory = wasmExports["memory"]; | |
| updateMemoryViews(); | |
| addOnInit(wasmExports["__wasm_call_ctors"]); | |
| removeRunDependency("wasm-instantiate"); | |
| return wasmExports; | |
| } | |
| addRunDependency("wasm-instantiate"); | |
| function receiveInstantiationResult(result) { | |
| receiveInstance(result["instance"]); | |
| } | |
| if (Module2["instantiateWasm"]) { | |
| try { | |
| return Module2["instantiateWasm"](info, receiveInstance); | |
| } catch (e) { | |
| err(`Module.instantiateWasm callback failed with error: ${e}`); | |
| readyPromiseReject(e); | |
| } | |
| } | |
| instantiateAsync(wasmBinary, wasmBinaryFile, info, receiveInstantiationResult).catch(readyPromiseReject); | |
| return {}; | |
| } | |
| var tempDouble; | |
| var tempI64; | |
| function ExitStatus(status) { | |
| this.name = "ExitStatus"; | |
| this.message = `Program terminated with exit(${status})`; | |
| this.status = status; | |
| } | |
| var callRuntimeCallbacks = (callbacks) => { | |
| while (callbacks.length > 0) { | |
| callbacks.shift()(Module2); | |
| } | |
| }; | |
| function getValue(ptr, type = "i8") { | |
| if (type.endsWith("*")) | |
| type = "*"; | |
| switch (type) { | |
| case "i1": | |
| return HEAP8[ptr]; | |
| case "i8": | |
| return HEAP8[ptr]; | |
| case "i16": | |
| return HEAP16[ptr >> 1]; | |
| case "i32": | |
| return HEAP32[ptr >> 2]; | |
| case "i64": | |
| abort("to do getValue(i64) use WASM_BIGINT"); | |
| case "float": | |
| return HEAPF32[ptr >> 2]; | |
| case "double": | |
| return HEAPF64[ptr >> 3]; | |
| case "*": | |
| return HEAPU32[ptr >> 2]; | |
| default: | |
| abort(`invalid type for getValue: ${type}`); | |
| } | |
| } | |
| var noExitRuntime = Module2["noExitRuntime"] || true; | |
| function setValue(ptr, value, type = "i8") { | |
| if (type.endsWith("*")) | |
| type = "*"; | |
| switch (type) { | |
| case "i1": | |
| HEAP8[ptr] = value; | |
| break; | |
| case "i8": | |
| HEAP8[ptr] = value; | |
| break; | |
| case "i16": | |
| HEAP16[ptr >> 1] = value; | |
| break; | |
| case "i32": | |
| HEAP32[ptr >> 2] = value; | |
| break; | |
| case "i64": | |
| abort("to do setValue(i64) use WASM_BIGINT"); | |
| case "float": | |
| HEAPF32[ptr >> 2] = value; | |
| break; | |
| case "double": | |
| HEAPF64[ptr >> 3] = value; | |
| break; | |
| case "*": | |
| HEAPU32[ptr >> 2] = value; | |
| break; | |
| default: | |
| abort(`invalid type for setValue: ${type}`); | |
| } | |
| } | |
| var wasmImports = {}; | |
| var wasmExports = createWasm(); | |
| var ___wasm_call_ctors = () => (___wasm_call_ctors = wasmExports["__wasm_call_ctors"])(); | |
| var _Hash_Update = Module2["_Hash_Update"] = (a0) => (_Hash_Update = Module2["_Hash_Update"] = wasmExports["Hash_Update"])(a0); | |
| var _Hash_Final = Module2["_Hash_Final"] = () => (_Hash_Final = Module2["_Hash_Final"] = wasmExports["Hash_Final"])(); | |
| var _Hash_Init = Module2["_Hash_Init"] = (a0) => (_Hash_Init = Module2["_Hash_Init"] = wasmExports["Hash_Init"])(a0); | |
| var _GetBufferPtr = Module2["_GetBufferPtr"] = () => (_GetBufferPtr = Module2["_GetBufferPtr"] = wasmExports["GetBufferPtr"])(); | |
| var stackSave = () => (stackSave = wasmExports["stackSave"])(); | |
| var stackRestore = (a0) => (stackRestore = wasmExports["stackRestore"])(a0); | |
| var stackAlloc = (a0) => (stackAlloc = wasmExports["stackAlloc"])(a0); | |
| var calledRun; | |
| dependenciesFulfilled = function runCaller() { | |
| if (!calledRun) | |
| run2(); | |
| if (!calledRun) | |
| dependenciesFulfilled = runCaller; | |
| }; | |
| function run2() { | |
| if (runDependencies > 0) { | |
| return; | |
| } | |
| preRun(); | |
| if (runDependencies > 0) { | |
| return; | |
| } | |
| function doRun() { | |
| if (calledRun) | |
| return; | |
| calledRun = true; | |
| Module2["calledRun"] = true; | |
| if (ABORT) | |
| return; | |
| initRuntime(); | |
| readyPromiseResolve(Module2); | |
| if (Module2["onRuntimeInitialized"]) | |
| Module2["onRuntimeInitialized"](); | |
| postRun(); | |
| } | |
| if (Module2["setStatus"]) { | |
| Module2["setStatus"]("Running..."); | |
| setTimeout(function() { | |
| setTimeout(function() { | |
| Module2["setStatus"](""); | |
| }, 1); | |
| doRun(); | |
| }, 1); | |
| } else { | |
| doRun(); | |
| } | |
| } | |
| if (Module2["preInit"]) { | |
| if (typeof Module2["preInit"] == "function") | |
| Module2["preInit"] = [Module2["preInit"]]; | |
| while (Module2["preInit"].length > 0) { | |
| Module2["preInit"].pop()(); | |
| } | |
| } | |
| run2(); | |
| return moduleArg.ready; | |
| }; | |
| })(); | |
| sha256_default = Module; | |
| } | |
| }); | |
| // src/vendor/hash-wasm/sha256-wrapper.ts | |
| var sha256_wrapper_exports = {}; | |
| __export(sha256_wrapper_exports, { | |
| createSHA256: () => createSHA256, | |
| createSHA256WorkerCode: () => createSHA256WorkerCode | |
| }); | |
| async function createSHA256(isInsideWorker = false) { | |
| const BUFFER_MAX_SIZE = 8 * 1024 * 1024; | |
| const wasm = isInsideWorker ? ( | |
| // @ts-expect-error WasmModule will be populated inside self object | |
| await self["SHA256WasmModule"]() | |
| ) : await sha256_default(); | |
| const heap = wasm.HEAPU8.subarray(wasm._GetBufferPtr()); | |
| return { | |
| init() { | |
| wasm._Hash_Init(256); | |
| }, | |
| update(data) { | |
| let byteUsed = 0; | |
| while (byteUsed < data.byteLength) { | |
| const bytesLeft = data.byteLength - byteUsed; | |
| const length = Math.min(bytesLeft, BUFFER_MAX_SIZE); | |
| heap.set(data.subarray(byteUsed, byteUsed + length)); | |
| wasm._Hash_Update(length); | |
| byteUsed += length; | |
| } | |
| }, | |
| digest(method) { | |
| if (method !== "hex") { | |
| throw new Error("Only digest hex is supported"); | |
| } | |
| wasm._Hash_Final(); | |
| const result = Array.from(heap.slice(0, 32)); | |
| return result.map((b) => b.toString(16).padStart(2, "0")).join(""); | |
| } | |
| }; | |
| } | |
| function createSHA256WorkerCode() { | |
| return ` | |
| self.addEventListener('message', async (event) => { | |
| const { file } = event.data; | |
| const sha256 = await self.createSHA256(true); | |
| sha256.init(); | |
| const reader = file.stream().getReader(); | |
| const total = file.size; | |
| let bytesDone = 0; | |
| while (true) { | |
| const { done, value } = await reader.read(); | |
| if (done) { | |
| break; | |
| } | |
| sha256.update(value); | |
| bytesDone += value.length; | |
| postMessage({ progress: bytesDone / total }); | |
| } | |
| postMessage({ sha256: sha256.digest('hex') }); | |
| }); | |
| self.SHA256WasmModule = ${sha256_default.toString()}; | |
| self.createSHA256 = ${createSHA256.toString()}; | |
| `; | |
| } | |
| var init_sha256_wrapper = __esm({ | |
| "src/vendor/hash-wasm/sha256-wrapper.ts"() { | |
| "use strict"; | |
| init_sha256(); | |
| } | |
| }); | |
| // src/utils/sha256-node.ts | |
| var sha256_node_exports = {}; | |
| __export(sha256_node_exports, { | |
| sha256Node: () => sha256Node | |
| }); | |
| async function* sha256Node(buffer, opts) { | |
| const sha256Stream = (0, import_node_crypto.createHash)("sha256"); | |
| const size = buffer instanceof Blob ? buffer.size : buffer.byteLength; | |
| let done = 0; | |
| const readable = buffer instanceof Blob ? import_node_stream.Readable.fromWeb(buffer.stream()) : import_node_stream.Readable.from(Buffer.from(buffer)); | |
| for await (const buffer2 of readable) { | |
| sha256Stream.update(buffer2); | |
| done += buffer2.length; | |
| yield done / size; | |
| opts?.abortSignal?.throwIfAborted(); | |
| } | |
| return sha256Stream.digest("hex"); | |
| } | |
| var import_node_stream, import_node_crypto; | |
| var init_sha256_node = __esm({ | |
| "src/utils/sha256-node.ts"() { | |
| "use strict"; | |
| import_node_stream = require("stream"); | |
| import_node_crypto = require("crypto"); | |
| } | |
| }); | |
| // src/utils/FileBlob.ts | |
| var FileBlob_exports = {}; | |
| __export(FileBlob_exports, { | |
| FileBlob: () => FileBlob | |
| }); | |
| var import_node_fs, import_promises2, import_node_stream2, import_node_url, FileBlob; | |
| var init_FileBlob = __esm({ | |
| "src/utils/FileBlob.ts"() { | |
| "use strict"; | |
| import_node_fs = require("fs"); | |
| import_promises2 = require("fs/promises"); | |
| import_node_stream2 = 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(path2) { | |
| path2 = path2 instanceof URL ? (0, import_node_url.fileURLToPath)(path2) : path2; | |
| const { size } = await (0, import_promises2.stat)(path2); | |
| const fileBlob = new FileBlob(path2, 0, size); | |
| return fileBlob; | |
| } | |
| path; | |
| start; | |
| end; | |
| constructor(path2, start, end) { | |
| super(); | |
| this.path = path2; | |
| 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() { | |
| if (this.start === this.end) { | |
| return new Blob([]).stream(); | |
| } | |
| return import_node_stream2.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_promises2.open)(this.path, "r"); | |
| try { | |
| return await action(file); | |
| } finally { | |
| await file.close(); | |
| } | |
| } | |
| }; | |
| } | |
| }); | |
| // src/utils/sub-paths.ts | |
| var sub_paths_exports = {}; | |
| __export(sub_paths_exports, { | |
| subPaths: () => subPaths | |
| }); | |
| async function subPaths(path2, maxDepth = 10) { | |
| const state = await (0, import_promises3.stat)(path2); | |
| if (!state.isDirectory()) { | |
| return [{ path: path2, relativePath: "." }]; | |
| } | |
| const files = await (0, import_promises3.readdir)(path2, { withFileTypes: true }); | |
| const ret = []; | |
| for (const file of files) { | |
| const filePath = (0, import_node_url2.pathToFileURL)((0, import_node_url2.fileURLToPath)(path2) + "/" + file.name); | |
| if (file.isDirectory()) { | |
| ret.push( | |
| ...(await subPaths(filePath, maxDepth - 1)).map((subPath) => ({ | |
| ...subPath, | |
| relativePath: `${file.name}/${subPath.relativePath}` | |
| })) | |
| ); | |
| } else { | |
| ret.push({ path: filePath, relativePath: file.name }); | |
| } | |
| } | |
| return ret; | |
| } | |
| var import_promises3, import_node_url2; | |
| var init_sub_paths = __esm({ | |
| "src/utils/sub-paths.ts"() { | |
| "use strict"; | |
| import_promises3 = require("fs/promises"); | |
| import_node_url2 = require("url"); | |
| } | |
| }); | |
| // node_modules/.pnpm/cli-progress@3.12.0/node_modules/cli-progress/lib/eta.js | |
| var require_eta = __commonJS({ | |
| "node_modules/.pnpm/cli-progress@3.12.0/node_modules/cli-progress/lib/eta.js"(exports, module2) { | |
| var ETA = class { | |
| constructor(length, initTime, initValue) { | |
| this.etaBufferLength = length || 100; | |
| this.valueBuffer = [initValue]; | |
| this.timeBuffer = [initTime]; | |
| this.eta = "0"; | |
| } | |
| // add new values to calculation buffer | |
| update(time, value, total) { | |
| this.valueBuffer.push(value); | |
| this.timeBuffer.push(time); | |
| this.calculate(total - value); | |
| } | |
| // fetch estimated time | |
| getTime() { | |
| return this.eta; | |
| } | |
| // eta calculation - request number of remaining events | |
| calculate(remaining) { | |
| const currentBufferSize = this.valueBuffer.length; | |
| const buffer = Math.min(this.etaBufferLength, currentBufferSize); | |
| const v_diff = this.valueBuffer[currentBufferSize - 1] - this.valueBuffer[currentBufferSize - buffer]; | |
| const t_diff = this.timeBuffer[currentBufferSize - 1] - this.timeBuffer[currentBufferSize - buffer]; | |
| const vt_rate = v_diff / t_diff; | |
| this.valueBuffer = this.valueBuffer.slice(-this.etaBufferLength); | |
| this.timeBuffer = this.timeBuffer.slice(-this.etaBufferLength); | |
| const eta = Math.ceil(remaining / vt_rate / 1e3); | |
| if (isNaN(eta)) { | |
| this.eta = "NULL"; | |
| } else if (!isFinite(eta)) { | |
| this.eta = "INF"; | |
| } else if (eta > 1e7) { | |
| this.eta = "INF"; | |
| } else if (eta < 0) { | |
| this.eta = 0; | |
| } else { | |
| this.eta = eta; | |
| } | |
| } | |
| }; | |
| module2.exports = ETA; | |
| } | |
| }); | |
| // node_modules/.pnpm/cli-progress@3.12.0/node_modules/cli-progress/lib/terminal.js | |
| var require_terminal = __commonJS({ | |
| "node_modules/.pnpm/cli-progress@3.12.0/node_modules/cli-progress/lib/terminal.js"(exports, module2) { | |
| var _readline = require("readline"); | |
| var Terminal = class { | |
| constructor(outputStream) { | |
| this.stream = outputStream; | |
| this.linewrap = true; | |
| this.dy = 0; | |
| } | |
| // save cursor position + settings | |
| cursorSave() { | |
| if (!this.stream.isTTY) { | |
| return; | |
| } | |
| this.stream.write("\x1B7"); | |
| } | |
| // restore last cursor position + settings | |
| cursorRestore() { | |
| if (!this.stream.isTTY) { | |
| return; | |
| } | |
| this.stream.write("\x1B8"); | |
| } | |
| // show/hide cursor | |
| cursor(enabled) { | |
| if (!this.stream.isTTY) { | |
| return; | |
| } | |
| if (enabled) { | |
| this.stream.write("\x1B[?25h"); | |
| } else { | |
| this.stream.write("\x1B[?25l"); | |
| } | |
| } | |
| // change cursor positionn | |
| cursorTo(x = null, y = null) { | |
| if (!this.stream.isTTY) { | |
| return; | |
| } | |
| _readline.cursorTo(this.stream, x, y); | |
| } | |
| // change relative cursor position | |
| cursorRelative(dx = null, dy = null) { | |
| if (!this.stream.isTTY) { | |
| return; | |
| } | |
| this.dy = this.dy + dy; | |
| _readline.moveCursor(this.stream, dx, dy); | |
| } | |
| // relative reset | |
| cursorRelativeReset() { | |
| if (!this.stream.isTTY) { | |
| return; | |
| } | |
| _readline.moveCursor(this.stream, 0, -this.dy); | |
| _readline.cursorTo(this.stream, 0, null); | |
| this.dy = 0; | |
| } | |
| // clear to the right from cursor | |
| clearRight() { | |
| if (!this.stream.isTTY) { | |
| return; | |
| } | |
| _readline.clearLine(this.stream, 1); | |
| } | |
| // clear the full line | |
| clearLine() { | |
| if (!this.stream.isTTY) { | |
| return; | |
| } | |
| _readline.clearLine(this.stream, 0); | |
| } | |
| // clear everyting beyond the current line | |
| clearBottom() { | |
| if (!this.stream.isTTY) { | |
| return; | |
| } | |
| _readline.clearScreenDown(this.stream); | |
| } | |
| // add new line; increment counter | |
| newline() { | |
| this.stream.write("\n"); | |
| this.dy++; | |
| } | |
| // write content to output stream | |
| // @TODO use string-width to strip length | |
| write(s, rawWrite = false) { | |
| if (this.linewrap === true && rawWrite === false) { | |
| this.stream.write(s.substr(0, this.getWidth())); | |
| } else { | |
| this.stream.write(s); | |
| } | |
| } | |
| // control line wrapping | |
| lineWrapping(enabled) { | |
| if (!this.stream.isTTY) { | |
| return; | |
| } | |
| this.linewrap = enabled; | |
| if (enabled) { | |
| this.stream.write("\x1B[?7h"); | |
| } else { | |
| this.stream.write("\x1B[?7l"); | |
| } | |
| } | |
| // tty environment ? | |
| isTTY() { | |
| return this.stream.isTTY === true; | |
| } | |
| // get terminal width | |
| getWidth() { | |
| return this.stream.columns || (this.stream.isTTY ? 80 : 200); | |
| } | |
| }; | |
| module2.exports = Terminal; | |
| } | |
| }); | |
| // node_modules/.pnpm/ansi-regex@5.0.1/node_modules/ansi-regex/index.js | |
| var require_ansi_regex = __commonJS({ | |
| "node_modules/.pnpm/ansi-regex@5.0.1/node_modules/ansi-regex/index.js"(exports, module2) { | |
| "use strict"; | |
| module2.exports = ({ onlyFirst = false } = {}) => { | |
| const pattern = [ | |
| "[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]+)*|[a-zA-Z\\d]+(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)", | |
| "(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-ntqry=><~]))" | |
| ].join("|"); | |
| return new RegExp(pattern, onlyFirst ? void 0 : "g"); | |
| }; | |
| } | |
| }); | |
| // node_modules/.pnpm/strip-ansi@6.0.1/node_modules/strip-ansi/index.js | |
| var require_strip_ansi = __commonJS({ | |
| "node_modules/.pnpm/strip-ansi@6.0.1/node_modules/strip-ansi/index.js"(exports, module2) { | |
| "use strict"; | |
| var ansiRegex = require_ansi_regex(); | |
| module2.exports = (string) => typeof string === "string" ? string.replace(ansiRegex(), "") : string; | |
| } | |
| }); | |
| // node_modules/.pnpm/is-fullwidth-code-point@3.0.0/node_modules/is-fullwidth-code-point/index.js | |
| var require_is_fullwidth_code_point = __commonJS({ | |
| "node_modules/.pnpm/is-fullwidth-code-point@3.0.0/node_modules/is-fullwidth-code-point/index.js"(exports, module2) { | |
| "use strict"; | |
| var isFullwidthCodePoint = (codePoint) => { | |
| if (Number.isNaN(codePoint)) { | |
| return false; | |
| } | |
| if (codePoint >= 4352 && (codePoint <= 4447 || // Hangul Jamo | |
| codePoint === 9001 || // LEFT-POINTING ANGLE BRACKET | |
| codePoint === 9002 || // RIGHT-POINTING ANGLE BRACKET | |
| // CJK Radicals Supplement .. Enclosed CJK Letters and Months | |
| 11904 <= codePoint && codePoint <= 12871 && codePoint !== 12351 || // Enclosed CJK Letters and Months .. CJK Unified Ideographs Extension A | |
| 12880 <= codePoint && codePoint <= 19903 || // CJK Unified Ideographs .. Yi Radicals | |
| 19968 <= codePoint && codePoint <= 42182 || // Hangul Jamo Extended-A | |
| 43360 <= codePoint && codePoint <= 43388 || // Hangul Syllables | |
| 44032 <= codePoint && codePoint <= 55203 || // CJK Compatibility Ideographs | |
| 63744 <= codePoint && codePoint <= 64255 || // Vertical Forms | |
| 65040 <= codePoint && codePoint <= 65049 || // CJK Compatibility Forms .. Small Form Variants | |
| 65072 <= codePoint && codePoint <= 65131 || // Halfwidth and Fullwidth Forms | |
| 65281 <= codePoint && codePoint <= 65376 || 65504 <= codePoint && codePoint <= 65510 || // Kana Supplement | |
| 110592 <= codePoint && codePoint <= 110593 || // Enclosed Ideographic Supplement | |
| 127488 <= codePoint && codePoint <= 127569 || // CJK Unified Ideographs Extension B .. Tertiary Ideographic Plane | |
| 131072 <= codePoint && codePoint <= 262141)) { | |
| return true; | |
| } | |
| return false; | |
| }; | |
| module2.exports = isFullwidthCodePoint; | |
| module2.exports.default = isFullwidthCodePoint; | |
| } | |
| }); | |
| // node_modules/.pnpm/emoji-regex@8.0.0/node_modules/emoji-regex/index.js | |
| var require_emoji_regex = __commonJS({ | |
| "node_modules/.pnpm/emoji-regex@8.0.0/node_modules/emoji-regex/index.js"(exports, module2) { | |
| "use strict"; | |
| module2.exports = function() { | |
| return /\uD83C\uDFF4\uDB40\uDC67\uDB40\uDC62(?:\uDB40\uDC65\uDB40\uDC6E\uDB40\uDC67|\uDB40\uDC73\uDB40\uDC63\uDB40\uDC74|\uDB40\uDC77\uDB40\uDC6C\uDB40\uDC73)\uDB40\uDC7F|\uD83D\uDC68(?:\uD83C\uDFFC\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68\uD83C\uDFFB|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFF\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFE])|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFE\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFD])|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFD\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB\uDFFC])|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\u200D(?:\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D)?\uD83D\uDC68|(?:\uD83D[\uDC68\uDC69])\u200D(?:\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67]))|\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67])|(?:\uD83D[\uDC68\uDC69])\u200D(?:\uD83D[\uDC66\uDC67])|[\u2695\u2696\u2708]\uFE0F|\uD83D[\uDC66\uDC67]|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|(?:\uD83C\uDFFB\u200D[\u2695\u2696\u2708]|\uD83C\uDFFF\u200D[\u2695\u2696\u2708]|\uD83C\uDFFE\u200D[\u2695\u2696\u2708]|\uD83C\uDFFD\u200D[\u2695\u2696\u2708]|\uD83C\uDFFC\u200D[\u2695\u2696\u2708])\uFE0F|\uD83C\uDFFB\u200D(?:\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C[\uDFFB-\uDFFF])|(?:\uD83E\uDDD1\uD83C\uDFFB\u200D\uD83E\uDD1D\u200D\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFC\u200D\uD83E\uDD1D\u200D\uD83D\uDC69)\uD83C\uDFFB|\uD83E\uDDD1(?:\uD83C\uDFFF\u200D\uD83E\uDD1D\u200D\uD83E\uDDD1(?:\uD83C[\uDFFB-\uDFFF])|\u200D\uD83E\uDD1D\u200D\uD83E\uDDD1)|(?:\uD83E\uDDD1\uD83C\uDFFE\u200D\uD83E\uDD1D\u200D\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFF\u200D\uD83E\uDD1D\u200D(?:\uD83D[\uDC68\uDC69]))(?:\uD83C[\uDFFB-\uDFFE])|(?:\uD83E\uDDD1\uD83C\uDFFC\u200D\uD83E\uDD1D\u200D\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFD\u200D\uD83E\uDD1D\u200D\uD83D\uDC69)(?:\uD83C[\uDFFB\uDFFC])|\uD83D\uDC69(?:\uD83C\uDFFE\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB-\uDFFD\uDFFF])|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFC\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB\uDFFD-\uDFFF])|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFB\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFC-\uDFFF])|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFD\u200D(?:\uD83E\uDD1D\u200D\uD83D\uDC68(?:\uD83C[\uDFFB\uDFFC\uDFFE\uDFFF])|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\u200D(?:\u2764\uFE0F\u200D(?:\uD83D\uDC8B\u200D(?:\uD83D[\uDC68\uDC69])|\uD83D[\uDC68\uDC69])|\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD])|\uD83C\uDFFF\u200D(?:\uD83C[\uDF3E\uDF73\uDF93\uDFA4\uDFA8\uDFEB\uDFED]|\uD83D[\uDCBB\uDCBC\uDD27\uDD2C\uDE80\uDE92]|\uD83E[\uDDAF-\uDDB3\uDDBC\uDDBD]))|\uD83D\uDC69\u200D\uD83D\uDC69\u200D(?:\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67]))|(?:\uD83E\uDDD1\uD83C\uDFFD\u200D\uD83E\uDD1D\u200D\uD83E\uDDD1|\uD83D\uDC69\uD83C\uDFFE\u200D\uD83E\uDD1D\u200D\uD83D\uDC69)(?:\uD83C[\uDFFB-\uDFFD])|\uD83D\uDC69\u200D\uD83D\uDC66\u200D\uD83D\uDC66|\uD83D\uDC69\u200D\uD83D\uDC69\u200D(?:\uD83D[\uDC66\uDC67])|(?:\uD83D\uDC41\uFE0F\u200D\uD83D\uDDE8|\uD83D\uDC69(?:\uD83C\uDFFF\u200D[\u2695\u2696\u2708]|\uD83C\uDFFE\u200D[\u2695\u2696\u2708]|\uD83C\uDFFC\u200D[\u2695\u2696\u2708]|\uD83C\uDFFB\u200D[\u2695\u2696\u2708]|\uD83C\uDFFD\u200D[\u2695\u2696\u2708]|\u200D[\u2695\u2696\u2708])|(?:(?:\u26F9|\uD83C[\uDFCB\uDFCC]|\uD83D\uDD75)\uFE0F|\uD83D\uDC6F|\uD83E[\uDD3C\uDDDE\uDDDF])\u200D[\u2640\u2642]|(?:\u26F9|\uD83C[\uDFCB\uDFCC]|\uD83D\uDD75)(?:\uD83C[\uDFFB-\uDFFF])\u200D[\u2640\u2642]|(?:\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD-\uDDCF\uDDD6-\uDDDD])(?:(?:\uD83C[\uDFFB-\uDFFF])\u200D[\u2640\u2642]|\u200D[\u2640\u2642])|\uD83C\uDFF4\u200D\u2620)\uFE0F|\uD83D\uDC69\u200D\uD83D\uDC67\u200D(?:\uD83D[\uDC66\uDC67])|\uD83C\uDFF3\uFE0F\u200D\uD83C\uDF08|\uD83D\uDC15\u200D\uD83E\uDDBA|\uD83D\uDC69\u200D\uD83D\uDC66|\uD83D\uDC69\u200D\uD83D\uDC67|\uD83C\uDDFD\uD83C\uDDF0|\uD83C\uDDF4\uD83C\uDDF2|\uD83C\uDDF6\uD83C\uDDE6|[#\*0-9]\uFE0F\u20E3|\uD83C\uDDE7(?:\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEF\uDDF1-\uDDF4\uDDF6-\uDDF9\uDDFB\uDDFC\uDDFE\uDDFF])|\uD83C\uDDF9(?:\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDED\uDDEF-\uDDF4\uDDF7\uDDF9\uDDFB\uDDFC\uDDFF])|\uD83C\uDDEA(?:\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDED\uDDF7-\uDDFA])|\uD83E\uDDD1(?:\uD83C[\uDFFB-\uDFFF])|\uD83C\uDDF7(?:\uD83C[\uDDEA\uDDF4\uDDF8\uDDFA\uDDFC])|\uD83D\uDC69(?:\uD83C[\uDFFB-\uDFFF])|\uD83C\uDDF2(?:\uD83C[\uDDE6\uDDE8-\uDDED\uDDF0-\uDDFF])|\uD83C\uDDE6(?:\uD83C[\uDDE8-\uDDEC\uDDEE\uDDF1\uDDF2\uDDF4\uDDF6-\uDDFA\uDDFC\uDDFD\uDDFF])|\uD83C\uDDF0(?:\uD83C[\uDDEA\uDDEC-\uDDEE\uDDF2\uDDF3\uDDF5\uDDF7\uDDFC\uDDFE\uDDFF])|\uD83C\uDDED(?:\uD83C[\uDDF0\uDDF2\uDDF3\uDDF7\uDDF9\uDDFA])|\uD83C\uDDE9(?:\uD83C[\uDDEA\uDDEC\uDDEF\uDDF0\uDDF2\uDDF4\uDDFF])|\uD83C\uDDFE(?:\uD83C[\uDDEA\uDDF9])|\uD83C\uDDEC(?:\uD83C[\uDDE6\uDDE7\uDDE9-\uDDEE\uDDF1-\uDDF3\uDDF5-\uDDFA\uDDFC\uDDFE])|\uD83C\uDDF8(?:\uD83C[\uDDE6-\uDDEA\uDDEC-\uDDF4\uDDF7-\uDDF9\uDDFB\uDDFD-\uDDFF])|\uD83C\uDDEB(?:\uD83C[\uDDEE-\uDDF0\uDDF2\uDDF4\uDDF7])|\uD83C\uDDF5(?:\uD83C[\uDDE6\uDDEA-\uDDED\uDDF0-\uDDF3\uDDF7-\uDDF9\uDDFC\uDDFE])|\uD83C\uDDFB(?:\uD83C[\uDDE6\uDDE8\uDDEA\uDDEC\uDDEE\uDDF3\uDDFA])|\uD83C\uDDF3(?:\uD83C[\uDDE6\uDDE8\uDDEA-\uDDEC\uDDEE\uDDF1\uDDF4\uDDF5\uDDF7\uDDFA\uDDFF])|\uD83C\uDDE8(?:\uD83C[\uDDE6\uDDE8\uDDE9\uDDEB-\uDDEE\uDDF0-\uDDF5\uDDF7\uDDFA-\uDDFF])|\uD83C\uDDF1(?:\uD83C[\uDDE6-\uDDE8\uDDEE\uDDF0\uDDF7-\uDDFB\uDDFE])|\uD83C\uDDFF(?:\uD83C[\uDDE6\uDDF2\uDDFC])|\uD83C\uDDFC(?:\uD83C[\uDDEB\uDDF8])|\uD83C\uDDFA(?:\uD83C[\uDDE6\uDDEC\uDDF2\uDDF3\uDDF8\uDDFE\uDDFF])|\uD83C\uDDEE(?:\uD83C[\uDDE8-\uDDEA\uDDF1-\uDDF4\uDDF6-\uDDF9])|\uD83C\uDDEF(?:\uD83C[\uDDEA\uDDF2\uDDF4\uDDF5])|(?:\uD83C[\uDFC3\uDFC4\uDFCA]|\uD83D[\uDC6E\uDC71\uDC73\uDC77\uDC81\uDC82\uDC86\uDC87\uDE45-\uDE47\uDE4B\uDE4D\uDE4E\uDEA3\uDEB4-\uDEB6]|\uD83E[\uDD26\uDD37-\uDD39\uDD3D\uDD3E\uDDB8\uDDB9\uDDCD-\uDDCF\uDDD6-\uDDDD])(?:\uD83C[\uDFFB-\uDFFF])|(?:\u26F9|\uD83C[\uDFCB\uDFCC]|\uD83D\uDD75)(?:\uD83C[\uDFFB-\uDFFF])|(?:[\u261D\u270A-\u270D]|\uD83C[\uDF85\uDFC2\uDFC7]|\uD83D[\uDC42\uDC43\uDC46-\uDC50\uDC66\uDC67\uDC6B-\uDC6D\uDC70\uDC72\uDC74-\uDC76\uDC78\uDC7C\uDC83\uDC85\uDCAA\uDD74\uDD7A\uDD90\uDD95\uDD96\uDE4C\uDE4F\uDEC0\uDECC]|\uD83E[\uDD0F\uDD18-\uDD1C\uDD1E\uDD1F\uDD30-\uDD36\uDDB5\uDDB6\uDDBB\uDDD2-\uDDD5])(?:\uD83C[\uDFFB-\uDFFF])|(?:[\u231A\u231B\u23E9-\u23EC\u23F0\u23F3\u25FD\u25FE\u2614\u2615\u2648-\u2653\u267F\u2693\u26A1\u26AA\u26AB\u26BD\u26BE\u26C4\u26C5\u26CE\u26D4\u26EA\u26F2\u26F3\u26F5\u26FA\u26FD\u2705\u270A\u270B\u2728\u274C\u274E\u2753-\u2755\u2757\u2795-\u2797\u27B0\u27BF\u2B1B\u2B1C\u2B50\u2B55]|\uD83C[\uDC04\uDCCF\uDD8E\uDD91-\uDD9A\uDDE6-\uDDFF\uDE01\uDE1A\uDE2F\uDE32-\uDE36\uDE38-\uDE3A\uDE50\uDE51\uDF00-\uDF20\uDF2D-\uDF35\uDF37-\uDF7C\uDF7E-\uDF93\uDFA0-\uDFCA\uDFCF-\uDFD3\uDFE0-\uDFF0\uDFF4\uDFF8-\uDFFF]|\uD83D[\uDC00-\uDC3E\uDC40\uDC42-\uDCFC\uDCFF-\uDD3D\uDD4B-\uDD4E\uDD50-\uDD67\uDD7A\uDD95\uDD96\uDDA4\uDDFB-\uDE4F\uDE80-\uDEC5\uDECC\uDED0-\uDED2\uDED5\uDEEB\uDEEC\uDEF4-\uDEFA\uDFE0-\uDFEB]|\uD83E[\uDD0D-\uDD3A\uDD3C-\uDD45\uDD47-\uDD71\uDD73-\uDD76\uDD7A-\uDDA2\uDDA5-\uDDAA\uDDAE-\uDDCA\uDDCD-\uDDFF\uDE70-\uDE73\uDE78-\uDE7A\uDE80-\uDE82\uDE90-\uDE95])|(?:[#\*0-9\xA9\xAE\u203C\u2049\u2122\u2139\u2194-\u2199\u21A9\u21AA\u231A\u231B\u2328\u23CF\u23E9-\u23F3\u23F8-\u23FA\u24C2\u25AA\u25AB\u25B6\u25C0\u25FB-\u25FE\u2600-\u2604\u260E\u2611\u2614\u2615\u2618\u261D\u2620\u2622\u2623\u2626\u262A\u262E\u262F\u2638-\u263A\u2640\u2642\u2648-\u2653\u265F\u2660\u2663\u2665\u2666\u2668\u267B\u267E\u267F\u2692-\u2697\u2699\u269B\u269C\u26A0\u26A1\u26AA\u26AB\u26B0\u26B1\u26BD\u26BE\u26C4\u26C5\u26C8\u26CE\u26CF\u26D1\u26D3\u26D4\u26E9\u26EA\u26F0-\u26F5\u26F7-\u26FA\u26FD\u2702\u2705\u2708-\u270D\u270F\u2712\u2714\u2716\u271D\u2721\u2728\u2733\u2734\u2744\u2747\u274C\u274E\u2753-\u2755\u2757\u2763\u2764\u2795-\u2797\u27A1\u27B0\u27BF\u2934\u2935\u2B05-\u2B07\u2B1B\u2B1C\u2B50\u2B55\u3030\u303D\u3297\u3299]|\uD83C[\uDC04\uDCCF\uDD70\uDD71\uDD7E\uDD7F\uDD8E\uDD91-\uDD9A\uDDE6-\uDDFF\uDE01\uDE02\uDE1A\uDE2F\uDE32-\uDE3A\uDE50\uDE51\uDF00-\uDF21\uDF24-\uDF93\uDF96\uDF97\uDF99-\uDF9B\uDF9E-\uDFF0\uDFF3-\uDFF5\uDFF7-\uDFFF]|\uD83D[\uDC00-\uDCFD\uDCFF-\uDD3D\uDD49-\uDD4E\uDD50-\uDD67\uDD6F\uDD70\uDD73-\uDD7A\uDD87\uDD8A-\uDD8D\uDD90\uDD95\uDD96\uDDA4\uDDA5\uDDA8\uDDB1\uDDB2\uDDBC\uDDC2-\uDDC4\uDDD1-\uDDD3\uDDDC-\uDDDE\uDDE1\uDDE3\uDDE8\uDDEF\uDDF3\uDDFA-\uDE4F\uDE80-\uDEC5\uDECB-\uDED2\uDED5\uDEE0-\uDEE5\uDEE9\uDEEB\uDEEC\uDEF0\uDEF3-\uDEFA\uDFE0-\uDFEB]|\uD83E[\uDD0D-\uDD3A\uDD3C-\uDD45\uDD47-\uDD71\uDD73-\uDD76\uDD7A-\uDDA2\uDDA5-\uDDAA\uDDAE-\uDDCA\uDDCD-\uDDFF\uDE70-\uDE73\uDE78-\uDE7A\uDE80-\uDE82\uDE90-\uDE95])\uFE0F|(?:[\u261D\u26F9\u270A-\u270D]|\uD83C[\uDF85\uDFC2-\uDFC4\uDFC7\uDFCA-\uDFCC]|\uD83D[\uDC42\uDC43\uDC46-\uDC50\uDC66-\uDC78\uDC7C\uDC81-\uDC83\uDC85-\uDC87\uDC8F\uDC91\uDCAA\uDD74\uDD75\uDD7A\uDD90\uDD95\uDD96\uDE45-\uDE47\uDE4B-\uDE4F\uDEA3\uDEB4-\uDEB6\uDEC0\uDECC]|\uD83E[\uDD0F\uDD18-\uDD1F\uDD26\uDD30-\uDD39\uDD3C-\uDD3E\uDDB5\uDDB6\uDDB8\uDDB9\uDDBB\uDDCD-\uDDCF\uDDD1-\uDDDD])/g; | |
| }; | |
| } | |
| }); | |
| // node_modules/.pnpm/string-width@4.2.3/node_modules/string-width/index.js | |
| var require_string_width = __commonJS({ | |
| "node_modules/.pnpm/string-width@4.2.3/node_modules/string-width/index.js"(exports, module2) { | |
| "use strict"; | |
| var stripAnsi = require_strip_ansi(); | |
| var isFullwidthCodePoint = require_is_fullwidth_code_point(); | |
| var emojiRegex = require_emoji_regex(); | |
| var stringWidth = (string) => { | |
| if (typeof string !== "string" || string.length === 0) { | |
| return 0; | |
| } | |
| string = stripAnsi(string); | |
| if (string.length === 0) { | |
| return 0; | |
| } | |
| string = string.replace(emojiRegex(), " "); | |
| let width = 0; | |
| for (let i = 0; i < string.length; i++) { | |
| const code = string.codePointAt(i); | |
| if (code <= 31 || code >= 127 && code <= 159) { | |
| continue; | |
| } | |
| if (code >= 768 && code <= 879) { | |
| continue; | |
| } | |
| if (code > 65535) { | |
| i++; | |
| } | |
| width += isFullwidthCodePoint(code) ? 2 : 1; | |
| } | |
| return width; | |
| }; | |
| module2.exports = stringWidth; | |
| module2.exports.default = stringWidth; | |
| } | |
| }); | |
| // node_modules/.pnpm/cli-progress@3.12.0/node_modules/cli-progress/lib/format-value.js | |
| var require_format_value = __commonJS({ | |
| "node_modules/.pnpm/cli-progress@3.12.0/node_modules/cli-progress/lib/format-value.js"(exports, module2) { | |
| module2.exports = function formatValue(v, options, type) { | |
| if (options.autopadding !== true) { | |
| return v; | |
| } | |
| function autopadding(value, length) { | |
| return (options.autopaddingChar + value).slice(-length); | |
| } | |
| switch (type) { | |
| case "percentage": | |
| return autopadding(v, 3); | |
| default: | |
| return v; | |
| } | |
| }; | |
| } | |
| }); | |
| // node_modules/.pnpm/cli-progress@3.12.0/node_modules/cli-progress/lib/format-bar.js | |
| var require_format_bar = __commonJS({ | |
| "node_modules/.pnpm/cli-progress@3.12.0/node_modules/cli-progress/lib/format-bar.js"(exports, module2) { | |
| module2.exports = function formatBar(progress, options) { | |
| const completeSize = Math.round(progress * options.barsize); | |
| const incompleteSize = options.barsize - completeSize; | |
| return options.barCompleteString.substr(0, completeSize) + options.barGlue + options.barIncompleteString.substr(0, incompleteSize); | |
| }; | |
| } | |
| }); | |
| // node_modules/.pnpm/cli-progress@3.12.0/node_modules/cli-progress/lib/format-time.js | |
| var require_format_time = __commonJS({ | |
| "node_modules/.pnpm/cli-progress@3.12.0/node_modules/cli-progress/lib/format-time.js"(exports, module2) { | |
| module2.exports = function formatTime(t, options, roundToMultipleOf) { | |
| function round(input) { | |
| if (roundToMultipleOf) { | |
| return roundToMultipleOf * Math.round(input / roundToMultipleOf); | |
| } else { | |
| return input; | |
| } | |
| } | |
| function autopadding(v) { | |
| return (options.autopaddingChar + v).slice(-2); | |
| } | |
| if (t > 3600) { | |
| return autopadding(Math.floor(t / 3600)) + "h" + autopadding(round(t % 3600 / 60)) + "m"; | |
| } else if (t > 60) { | |
| return autopadding(Math.floor(t / 60)) + "m" + autopadding(round(t % 60)) + "s"; | |
| } else if (t > 10) { | |
| return autopadding(round(t)) + "s"; | |
| } else { | |
| return autopadding(t) + "s"; | |
| } | |
| }; | |
| } | |
| }); | |
| // node_modules/.pnpm/cli-progress@3.12.0/node_modules/cli-progress/lib/formatter.js | |
| var require_formatter = __commonJS({ | |
| "node_modules/.pnpm/cli-progress@3.12.0/node_modules/cli-progress/lib/formatter.js"(exports, module2) { | |
| var _stringWidth = require_string_width(); | |
| var _defaultFormatValue = require_format_value(); | |
| var _defaultFormatBar = require_format_bar(); | |
| var _defaultFormatTime = require_format_time(); | |
| module2.exports = function defaultFormatter(options, params, payload) { | |
| let s = options.format; | |
| const formatTime = options.formatTime || _defaultFormatTime; | |
| const formatValue = options.formatValue || _defaultFormatValue; | |
| const formatBar = options.formatBar || _defaultFormatBar; | |
| const percentage = Math.floor(params.progress * 100) + ""; | |
| const stopTime = params.stopTime || Date.now(); | |
| const elapsedTime = Math.round((stopTime - params.startTime) / 1e3); | |
| const context = Object.assign({}, payload, { | |
| bar: formatBar(params.progress, options), | |
| percentage: formatValue(percentage, options, "percentage"), | |
| total: formatValue(params.total, options, "total"), | |
| value: formatValue(params.value, options, "value"), | |
| eta: formatValue(params.eta, options, "eta"), | |
| eta_formatted: formatTime(params.eta, options, 5), | |
| duration: formatValue(elapsedTime, options, "duration"), | |
| duration_formatted: formatTime(elapsedTime, options, 1) | |
| }); | |
| s = s.replace(/\{(\w+)\}/g, function(match, key) { | |
| if (typeof context[key] !== "undefined") { | |
| return context[key]; | |
| } | |
| return match; | |
| }); | |
| const fullMargin = Math.max(0, params.maxWidth - _stringWidth(s) - 2); | |
| const halfMargin = Math.floor(fullMargin / 2); | |
| switch (options.align) { | |
| case "right": | |
| s = fullMargin > 0 ? " ".repeat(fullMargin) + s : s; | |
| break; | |
| case "center": | |
| s = halfMargin > 0 ? " ".repeat(halfMargin) + s : s; | |
| break; | |
| case "left": | |
| default: | |
| break; | |
| } | |
| return s; | |
| }; | |
| } | |
| }); | |
| // node_modules/.pnpm/cli-progress@3.12.0/node_modules/cli-progress/lib/options.js | |
| var require_options = __commonJS({ | |
| "node_modules/.pnpm/cli-progress@3.12.0/node_modules/cli-progress/lib/options.js"(exports, module2) { | |
| function mergeOption(v, defaultValue) { | |
| if (typeof v === "undefined" || v === null) { | |
| return defaultValue; | |
| } else { | |
| return v; | |
| } | |
| } | |
| module2.exports = { | |
| // set global options | |
| parse: function parse(rawOptions, preset) { | |
| const options = {}; | |
| const opt = Object.assign({}, preset, rawOptions); | |
| options.throttleTime = 1e3 / mergeOption(opt.fps, 10); | |
| options.stream = mergeOption(opt.stream, process.stderr); | |
| options.terminal = mergeOption(opt.terminal, null); | |
| options.clearOnComplete = mergeOption(opt.clearOnComplete, false); | |
| options.stopOnComplete = mergeOption(opt.stopOnComplete, false); | |
| options.barsize = mergeOption(opt.barsize, 40); | |
| options.align = mergeOption(opt.align, "left"); | |
| options.hideCursor = mergeOption(opt.hideCursor, false); | |
| options.linewrap = mergeOption(opt.linewrap, false); | |
| options.barGlue = mergeOption(opt.barGlue, ""); | |
| options.barCompleteChar = mergeOption(opt.barCompleteChar, "="); | |
| options.barIncompleteChar = mergeOption(opt.barIncompleteChar, "-"); | |
| options.format = mergeOption(opt.format, "progress [{bar}] {percentage}% | ETA: {eta}s | {value}/{total}"); | |
| options.formatTime = mergeOption(opt.formatTime, null); | |
| options.formatValue = mergeOption(opt.formatValue, null); | |
| options.formatBar = mergeOption(opt.formatBar, null); | |
| options.etaBufferLength = mergeOption(opt.etaBuffer, 10); | |
| options.etaAsynchronousUpdate = mergeOption(opt.etaAsynchronousUpdate, false); | |
| options.progressCalculationRelative = mergeOption(opt.progressCalculationRelative, false); | |
| options.synchronousUpdate = mergeOption(opt.synchronousUpdate, true); | |
| options.noTTYOutput = mergeOption(opt.noTTYOutput, false); | |
| options.notTTYSchedule = mergeOption(opt.notTTYSchedule, 2e3); | |
| options.emptyOnZero = mergeOption(opt.emptyOnZero, false); | |
| options.forceRedraw = mergeOption(opt.forceRedraw, false); | |
| options.autopadding = mergeOption(opt.autopadding, false); | |
| options.gracefulExit = mergeOption(opt.gracefulExit, false); | |
| return options; | |
| }, | |
| // derived options: instance specific, has to be created for every bar element | |
| assignDerivedOptions: function assignDerivedOptions(options) { | |
| options.barCompleteString = options.barCompleteChar.repeat(options.barsize + 1); | |
| options.barIncompleteString = options.barIncompleteChar.repeat(options.barsize + 1); | |
| options.autopaddingChar = options.autopadding ? mergeOption(options.autopaddingChar, " ") : ""; | |
| return options; | |
| } | |
| }; | |
| } | |
| }); | |
| // node_modules/.pnpm/cli-progress@3.12.0/node_modules/cli-progress/lib/generic-bar.js | |
| var require_generic_bar = __commonJS({ | |
| "node_modules/.pnpm/cli-progress@3.12.0/node_modules/cli-progress/lib/generic-bar.js"(exports, module2) { | |
| var _ETA = require_eta(); | |
| var _Terminal = require_terminal(); | |
| var _formatter = require_formatter(); | |
| var _options = require_options(); | |
| var _EventEmitter = require("events"); | |
| module2.exports = class GenericBar extends _EventEmitter { | |
| constructor(options) { | |
| super(); | |
| this.options = _options.assignDerivedOptions(options); | |
| this.terminal = this.options.terminal ? this.options.terminal : new _Terminal(this.options.stream); | |
| this.value = 0; | |
| this.startValue = 0; | |
| this.total = 100; | |
| this.lastDrawnString = null; | |
| this.startTime = null; | |
| this.stopTime = null; | |
| this.lastRedraw = Date.now(); | |
| this.eta = new _ETA(this.options.etaBufferLength, 0, 0); | |
| this.payload = {}; | |
| this.isActive = false; | |
| this.formatter = typeof this.options.format === "function" ? this.options.format : _formatter; | |
| } | |
| // internal render function | |
| render(forceRendering = false) { | |
| const params = { | |
| progress: this.getProgress(), | |
| eta: this.eta.getTime(), | |
| startTime: this.startTime, | |
| stopTime: this.stopTime, | |
| total: this.total, | |
| value: this.value, | |
| maxWidth: this.terminal.getWidth() | |
| }; | |
| if (this.options.etaAsynchronousUpdate) { | |
| this.updateETA(); | |
| } | |
| const s = this.formatter(this.options, params, this.payload); | |
| const forceRedraw = forceRendering || this.options.forceRedraw || this.options.noTTYOutput && !this.terminal.isTTY(); | |
| if (forceRedraw || this.lastDrawnString != s) { | |
| this.emit("redraw-pre"); | |
| this.terminal.cursorTo(0, null); | |
| this.terminal.write(s); | |
| this.terminal.clearRight(); | |
| this.lastDrawnString = s; | |
| this.lastRedraw = Date.now(); | |
| this.emit("redraw-post"); | |
| } | |
| } | |
| // start the progress bar | |
| start(total, startValue, payload) { | |
| this.value = startValue || 0; | |
| this.total = typeof total !== "undefined" && total >= 0 ? total : 100; | |
| this.startValue = startValue || 0; | |
| this.payload = payload || {}; | |
| this.startTime = Date.now(); | |
| this.stopTime = null; | |
| this.lastDrawnString = ""; | |
| this.eta = new _ETA(this.options.etaBufferLength, this.startTime, this.value); | |
| this.isActive = true; | |
| this.emit("start", total, startValue); | |
| } | |
| // stop the bar | |
| stop() { | |
| this.isActive = false; | |
| this.stopTime = Date.now(); | |
| this.emit("stop", this.total, this.value); | |
| } | |
| // update the bar value | |
| // update(value, payload) | |
| // update(payload) | |
| update(arg0, arg1 = {}) { | |
| if (typeof arg0 === "number") { | |
| this.value = arg0; | |
| this.eta.update(Date.now(), arg0, this.total); | |
| } | |
| const payloadData = (typeof arg0 === "object" ? arg0 : arg1) || {}; | |
| this.emit("update", this.total, this.value); | |
| for (const key in payloadData) { | |
| this.payload[key] = payloadData[key]; | |
| } | |
| if (this.value >= this.getTotal() && this.options.stopOnComplete) { | |
| this.stop(); | |
| } | |
| } | |
| // calculate the actual progress value | |
| getProgress() { | |
| let progress = this.value / this.total; | |
| if (this.options.progressCalculationRelative) { | |
| progress = (this.value - this.startValue) / (this.total - this.startValue); | |
| } | |
| if (isNaN(progress)) { | |
| progress = this.options && this.options.emptyOnZero ? 0 : 1; | |
| } | |
| progress = Math.min(Math.max(progress, 0), 1); | |
| return progress; | |
| } | |
| // update the bar value | |
| // increment(delta, payload) | |
| // increment(payload) | |
| increment(arg0 = 1, arg1 = {}) { | |
| if (typeof arg0 === "object") { | |
| this.update(this.value + 1, arg0); | |
| } else { | |
| this.update(this.value + arg0, arg1); | |
| } | |
| } | |
| // get the total (limit) value | |
| getTotal() { | |
| return this.total; | |
| } | |
| // set the total (limit) value | |
| setTotal(total) { | |
| if (typeof total !== "undefined" && total >= 0) { | |
| this.total = total; | |
| } | |
| } | |
| // force eta calculation update (long running processes) | |
| updateETA() { | |
| this.eta.update(Date.now(), this.value, this.total); | |
| } | |
| }; | |
| } | |
| }); | |
| // node_modules/.pnpm/cli-progress@3.12.0/node_modules/cli-progress/lib/single-bar.js | |
| var require_single_bar = __commonJS({ | |
| "node_modules/.pnpm/cli-progress@3.12.0/node_modules/cli-progress/lib/single-bar.js"(exports, module2) { | |
| var _GenericBar = require_generic_bar(); | |
| var _options = require_options(); | |
| module2.exports = class SingleBar extends _GenericBar { | |
| constructor(options, preset) { | |
| super(_options.parse(options, preset)); | |
| this.timer = null; | |
| if (this.options.noTTYOutput && this.terminal.isTTY() === false) { | |
| this.options.synchronousUpdate = false; | |
| } | |
| this.schedulingRate = this.terminal.isTTY() ? this.options.throttleTime : this.options.notTTYSchedule; | |
| this.sigintCallback = null; | |
| } | |
| // internal render function | |
| render() { | |
| if (this.timer) { | |
| clearTimeout(this.timer); | |
| this.timer = null; | |
| } | |
| super.render(); | |
| if (this.options.noTTYOutput && this.terminal.isTTY() === false) { | |
| this.terminal.newline(); | |
| } | |
| this.timer = setTimeout(this.render.bind(this), this.schedulingRate); | |
| } | |
| update(current, payload) { | |
| if (!this.timer) { | |
| return; | |
| } | |
| super.update(current, payload); | |
| if (this.options.synchronousUpdate && this.lastRedraw + this.options.throttleTime * 2 < Date.now()) { | |
| this.render(); | |
| } | |
| } | |
| // start the progress bar | |
| start(total, startValue, payload) { | |
| if (this.options.noTTYOutput === false && this.terminal.isTTY() === false) { | |
| return; | |
| } | |
| if (this.sigintCallback === null && this.options.gracefulExit) { | |
| this.sigintCallback = this.stop.bind(this); | |
| process.once("SIGINT", this.sigintCallback); | |
| process.once("SIGTERM", this.sigintCallback); | |
| } | |
| this.terminal.cursorSave(); | |
| if (this.options.hideCursor === true) { | |
| this.terminal.cursor(false); | |
| } | |
| if (this.options.linewrap === false) { | |
| this.terminal.lineWrapping(false); | |
| } | |
| super.start(total, startValue, payload); | |
| this.render(); | |
| } | |
| // stop the bar | |
| stop() { | |
| if (!this.timer) { | |
| return; | |
| } | |
| if (this.sigintCallback) { | |
| process.removeListener("SIGINT", this.sigintCallback); | |
| process.removeListener("SIGTERM", this.sigintCallback); | |
| this.sigintCallback = null; | |
| } | |
| this.render(); | |
| super.stop(); | |
| clearTimeout(this.timer); | |
| this.timer = null; | |
| if (this.options.hideCursor === true) { | |
| this.terminal.cursor(true); | |
| } | |
| if (this.options.linewrap === false) { | |
| this.terminal.lineWrapping(true); | |
| } | |
| this.terminal.cursorRestore(); | |
| if (this.options.clearOnComplete) { | |
| this.terminal.cursorTo(0, null); | |
| this.terminal.clearLine(); | |
| } else { | |
| this.terminal.newline(); | |
| } | |
| } | |
| }; | |
| } | |
| }); | |
| // node_modules/.pnpm/cli-progress@3.12.0/node_modules/cli-progress/lib/multi-bar.js | |
| var require_multi_bar = __commonJS({ | |
| "node_modules/.pnpm/cli-progress@3.12.0/node_modules/cli-progress/lib/multi-bar.js"(exports, module2) { | |
| var _Terminal = require_terminal(); | |
| var _BarElement = require_generic_bar(); | |
| var _options = require_options(); | |
| var _EventEmitter = require("events"); | |
| module2.exports = class MultiBar extends _EventEmitter { | |
| constructor(options, preset) { | |
| super(); | |
| this.bars = []; | |
| this.options = _options.parse(options, preset); | |
| this.options.synchronousUpdate = false; | |
| this.terminal = this.options.terminal ? this.options.terminal : new _Terminal(this.options.stream); | |
| this.timer = null; | |
| this.isActive = false; | |
| this.schedulingRate = this.terminal.isTTY() ? this.options.throttleTime : this.options.notTTYSchedule; | |
| this.loggingBuffer = []; | |
| this.sigintCallback = null; | |
| } | |
| // add a new bar to the stack | |
| create(total, startValue, payload, barOptions = {}) { | |
| const bar = new _BarElement(Object.assign( | |
| {}, | |
| // global options | |
| this.options, | |
| // terminal instance | |
| { | |
| terminal: this.terminal | |
| }, | |
| // overrides | |
| barOptions | |
| )); | |
| this.bars.push(bar); | |
| if (this.options.noTTYOutput === false && this.terminal.isTTY() === false) { | |
| return bar; | |
| } | |
| if (this.sigintCallback === null && this.options.gracefulExit) { | |
| this.sigintCallback = this.stop.bind(this); | |
| process.once("SIGINT", this.sigintCallback); | |
| process.once("SIGTERM", this.sigintCallback); | |
| } | |
| if (!this.isActive) { | |
| if (this.options.hideCursor === true) { | |
| this.terminal.cursor(false); | |
| } | |
| if (this.options.linewrap === false) { | |
| this.terminal.lineWrapping(false); | |
| } | |
| this.timer = setTimeout(this.update.bind(this), this.schedulingRate); | |
| } | |
| this.isActive = true; | |
| bar.start(total, startValue, payload); | |
| this.emit("start"); | |
| return bar; | |
| } | |
| // remove a bar from the stack | |
| remove(bar) { | |
| const index = this.bars.indexOf(bar); | |
| if (index < 0) { | |
| return false; | |
| } | |
| this.bars.splice(index, 1); | |
| this.update(); | |
| this.terminal.newline(); | |
| this.terminal.clearBottom(); | |
| return true; | |
| } | |
| // internal update routine | |
| update() { | |
| if (this.timer) { | |
| clearTimeout(this.timer); | |
| this.timer = null; | |
| } | |
| this.emit("update-pre"); | |
| this.terminal.cursorRelativeReset(); | |
| this.emit("redraw-pre"); | |
| if (this.loggingBuffer.length > 0) { | |
| this.terminal.clearLine(); | |
| while (this.loggingBuffer.length > 0) { | |
| this.terminal.write(this.loggingBuffer.shift(), true); | |
| } | |
| } | |
| for (let i = 0; i < this.bars.length; i++) { | |
| if (i > 0) { | |
| this.terminal.newline(); | |
| } | |
| this.bars[i].render(); | |
| } | |
| this.emit("redraw-post"); | |
| if (this.options.noTTYOutput && this.terminal.isTTY() === false) { | |
| this.terminal.newline(); | |
| this.terminal.newline(); | |
| } | |
| this.timer = setTimeout(this.update.bind(this), this.schedulingRate); | |
| this.emit("update-post"); | |
| if (this.options.stopOnComplete && !this.bars.find((bar) => bar.isActive)) { | |
| this.stop(); | |
| } | |
| } | |
| stop() { | |
| clearTimeout(this.timer); | |
| this.timer = null; | |
| if (this.sigintCallback) { | |
| process.removeListener("SIGINT", this.sigintCallback); | |
| process.removeListener("SIGTERM", this.sigintCallback); | |
| this.sigintCallback = null; | |
| } | |
| this.isActive = false; | |
| if (this.options.hideCursor === true) { | |
| this.terminal.cursor(true); | |
| } | |
| if (this.options.linewrap === false) { | |
| this.terminal.lineWrapping(true); | |
| } | |
| this.terminal.cursorRelativeReset(); | |
| this.emit("stop-pre-clear"); | |
| if (this.options.clearOnComplete) { | |
| this.terminal.clearBottom(); | |
| } else { | |
| for (let i = 0; i < this.bars.length; i++) { | |
| if (i > 0) { | |
| this.terminal.newline(); | |
| } | |
| this.bars[i].render(); | |
| this.bars[i].stop(); | |
| } | |
| this.terminal.newline(); | |
| } | |
| this.emit("stop"); | |
| } | |
| log(s) { | |
| this.loggingBuffer.push(s); | |
| } | |
| }; | |
| } | |
| }); | |
| // node_modules/.pnpm/cli-progress@3.12.0/node_modules/cli-progress/presets/legacy.js | |
| var require_legacy = __commonJS({ | |
| "node_modules/.pnpm/cli-progress@3.12.0/node_modules/cli-progress/presets/legacy.js"(exports, module2) { | |
| module2.exports = { | |
| format: "progress [{bar}] {percentage}% | ETA: {eta}s | {value}/{total}", | |
| barCompleteChar: "=", | |
| barIncompleteChar: "-" | |
| }; | |
| } | |
| }); | |
| // node_modules/.pnpm/cli-progress@3.12.0/node_modules/cli-progress/presets/shades-classic.js | |
| var require_shades_classic = __commonJS({ | |
| "node_modules/.pnpm/cli-progress@3.12.0/node_modules/cli-progress/presets/shades-classic.js"(exports, module2) { | |
| module2.exports = { | |
| format: " {bar} {percentage}% | ETA: {eta}s | {value}/{total}", | |
| barCompleteChar: "\u2588", | |
| barIncompleteChar: "\u2591" | |
| }; | |
| } | |
| }); | |
| // node_modules/.pnpm/cli-progress@3.12.0/node_modules/cli-progress/presets/shades-grey.js | |
| var require_shades_grey = __commonJS({ | |
| "node_modules/.pnpm/cli-progress@3.12.0/node_modules/cli-progress/presets/shades-grey.js"(exports, module2) { | |
| module2.exports = { | |
| format: " \x1B[90m{bar}\x1B[0m {percentage}% | ETA: {eta}s | {value}/{total}", | |
| barCompleteChar: "\u2588", | |
| barIncompleteChar: "\u2591" | |
| }; | |
| } | |
| }); | |
| // node_modules/.pnpm/cli-progress@3.12.0/node_modules/cli-progress/presets/rect.js | |
| var require_rect = __commonJS({ | |
| "node_modules/.pnpm/cli-progress@3.12.0/node_modules/cli-progress/presets/rect.js"(exports, module2) { | |
| module2.exports = { | |
| format: " {bar}\u25A0 {percentage}% | ETA: {eta}s | {value}/{total}", | |
| barCompleteChar: "\u25A0", | |
| barIncompleteChar: " " | |
| }; | |
| } | |
| }); | |
| // node_modules/.pnpm/cli-progress@3.12.0/node_modules/cli-progress/presets/index.js | |
| var require_presets = __commonJS({ | |
| "node_modules/.pnpm/cli-progress@3.12.0/node_modules/cli-progress/presets/index.js"(exports, module2) { | |
| var _legacy = require_legacy(); | |
| var _shades_classic = require_shades_classic(); | |
| var _shades_grey = require_shades_grey(); | |
| var _rect = require_rect(); | |
| module2.exports = { | |
| legacy: _legacy, | |
| shades_classic: _shades_classic, | |
| shades_grey: _shades_grey, | |
| rect: _rect | |
| }; | |
| } | |
| }); | |
| // node_modules/.pnpm/cli-progress@3.12.0/node_modules/cli-progress/cli-progress.js | |
| var require_cli_progress = __commonJS({ | |
| "node_modules/.pnpm/cli-progress@3.12.0/node_modules/cli-progress/cli-progress.js"(exports, module2) { | |
| var _SingleBar = require_single_bar(); | |
| var _MultiBar = require_multi_bar(); | |
| var _Presets = require_presets(); | |
| var _Formatter = require_formatter(); | |
| var _defaultFormatValue = require_format_value(); | |
| var _defaultFormatBar = require_format_bar(); | |
| var _defaultFormatTime = require_format_time(); | |
| module2.exports = { | |
| Bar: _SingleBar, | |
| SingleBar: _SingleBar, | |
| MultiBar: _MultiBar, | |
| Presets: _Presets, | |
| Format: { | |
| Formatter: _Formatter, | |
| BarFormat: _defaultFormatBar, | |
| ValueFormat: _defaultFormatValue, | |
| TimeFormat: _defaultFormatTime | |
| } | |
| }; | |
| } | |
| }); | |
| // cli.ts | |
| var import_node_util = require("util"); | |
| // src/utils/typedEntries.ts | |
| function typedEntries(obj) { | |
| return Object.entries(obj); | |
| } | |
| // src/lib/cache-management.ts | |
| var import_node_os = require("os"); | |
| var import_node_path = require("path"); | |
| var import_promises = require("fs/promises"); | |
| // src/consts.ts | |
| var HUB_URL = "https://huggingface.co"; | |
| // src/error.ts | |
| async function createApiError(response, opts) { | |
| const error = new HubApiError(response.url, response.status, response.headers.get("X-Request-Id") ?? opts?.requestId); | |
| error.message = `Api error with status ${error.statusCode}${opts?.message ? `. ${opts.message}` : ""}`; | |
| const trailer = [`URL: ${error.url}`, error.requestId ? `Request ID: ${error.requestId}` : void 0].filter(Boolean).join(". "); | |
| if (response.headers.get("Content-Type")?.startsWith("application/json")) { | |
| const json = await response.json(); | |
| error.message = json.error || json.message || error.message; | |
| if (json.error_description) { | |
| error.message = error.message ? error.message + `: ${json.error_description}` : json.error_description; | |
| } | |
| error.data = json; | |
| } else { | |
| error.data = { message: await response.text() }; | |
| } | |
| error.message += `. ${trailer}`; | |
| throw error; | |
| } | |
| var HubApiError = class extends Error { | |
| statusCode; | |
| url; | |
| requestId; | |
| data; | |
| constructor(url, statusCode, requestId, message) { | |
| super(message); | |
| this.statusCode = statusCode; | |
| this.requestId = requestId; | |
| this.url = url; | |
| } | |
| }; | |
| var InvalidApiResponseFormatError = class extends Error { | |
| }; | |
| // src/utils/checkCredentials.ts | |
| function checkAccessToken(accessToken) { | |
| if (!accessToken.startsWith("hf_")) { | |
| throw new TypeError("Your access token must start with 'hf_'"); | |
| } | |
| } | |
| function checkCredentials(params) { | |
| if (params.accessToken) { | |
| checkAccessToken(params.accessToken); | |
| return params.accessToken; | |
| } | |
| if (params.credentials?.accessToken) { | |
| checkAccessToken(params.credentials.accessToken); | |
| return params.credentials.accessToken; | |
| } | |
| } | |
| // src/utils/toRepoId.ts | |
| function toRepoId(repo) { | |
| if (typeof repo !== "string") { | |
| return repo; | |
| } | |
| if (repo.startsWith("model/") || repo.startsWith("models/")) { | |
| throw new TypeError( | |
| "A repo designation for a model should not start with 'models/', directly specify the model namespace / name" | |
| ); | |
| } | |
| if (repo.startsWith("space/")) { | |
| throw new TypeError("Spaces should start with 'spaces/', plural, not 'space/'"); | |
| } | |
| if (repo.startsWith("dataset/")) { | |
| throw new TypeError("Datasets should start with 'datasets/', plural, not 'dataset/'"); | |
| } | |
| if (repo.startsWith("bucket/")) { | |
| throw new TypeError("Buckets should start with 'buckets/', plural, not 'bucket/'"); | |
| } | |
| if (repo.startsWith("kernel/")) { | |
| throw new TypeError("Kernels should start with 'kernels/', plural, not 'kernel/'"); | |
| } | |
| const slashes = repo.split("/").length - 1; | |
| if (repo.startsWith("spaces/")) { | |
| if (slashes !== 2) { | |
| throw new TypeError("Space Id must include namespace and name of the space"); | |
| } | |
| return { | |
| type: "space", | |
| name: repo.slice("spaces/".length) | |
| }; | |
| } | |
| if (repo.startsWith("datasets/")) { | |
| if (slashes > 2) { | |
| throw new TypeError("Too many slashes in repo designation: " + repo); | |
| } | |
| return { | |
| type: "dataset", | |
| name: repo.slice("datasets/".length) | |
| }; | |
| } | |
| if (repo.startsWith("buckets/")) { | |
| if (slashes !== 2) { | |
| throw new TypeError("Bucket Id must include namespace and name of the bucket"); | |
| } | |
| return { | |
| type: "bucket", | |
| name: repo.slice("buckets/".length) | |
| }; | |
| } | |
| if (repo.startsWith("kernels/")) { | |
| if (slashes !== 2) { | |
| throw new TypeError("Kernel Id must include namespace and name of the kernel"); | |
| } | |
| return { | |
| type: "kernel", | |
| name: repo.slice("kernels/".length) | |
| }; | |
| } | |
| if (slashes > 1) { | |
| throw new TypeError("Too many slashes in repo designation: " + repo); | |
| } | |
| return { | |
| type: "model", | |
| name: repo | |
| }; | |
| } | |
| // src/utils/range.ts | |
| function range(n, b) { | |
| return b ? Array(b - n).fill(0).map((_, i) => n + i) : Array(n).fill(0).map((_, i) => i); | |
| } | |
| // src/utils/chunk.ts | |
| function chunk(arr, chunkSize) { | |
| if (isNaN(chunkSize) || chunkSize < 1) { | |
| throw new RangeError("Invalid chunk size: " + chunkSize); | |
| } | |
| if (!arr.length) { | |
| return []; | |
| } | |
| if (arr.length <= chunkSize) { | |
| return [arr]; | |
| } | |
| return range(Math.ceil(arr.length / chunkSize)).map((i) => { | |
| return arr.slice(i * chunkSize, (i + 1) * chunkSize); | |
| }); | |
| } | |
| // src/utils/promisesQueue.ts | |
| async function promisesQueue(factories, concurrency) { | |
| const results = []; | |
| const executing = /* @__PURE__ */ new Set(); | |
| let index = 0; | |
| for (const factory of factories) { | |
| const closureIndex = index++; | |
| const e = factory().then((r) => { | |
| results[closureIndex] = r; | |
| executing.delete(e); | |
| }); | |
| executing.add(e); | |
| if (executing.size >= concurrency) { | |
| await Promise.race(executing); | |
| } | |
| } | |
| await Promise.all(executing); | |
| return results; | |
| } | |
| // src/utils/promisesQueueStreaming.ts | |
| async function promisesQueueStreaming(factories, concurrency) { | |
| const executing = []; | |
| for await (const factory of factories) { | |
| const e = factory().then(() => { | |
| executing.splice(executing.indexOf(e), 1); | |
| }); | |
| executing.push(e); | |
| if (executing.length >= concurrency) { | |
| await Promise.race(executing); | |
| } | |
| } | |
| await Promise.all(executing); | |
| } | |
| // src/utils/eventToGenerator.ts | |
| async function* eventToGenerator(cb) { | |
| const promises = []; | |
| function addPromise() { | |
| let resolve3; | |
| let reject; | |
| const p = new Promise((res, rej) => { | |
| resolve3 = res; | |
| reject = rej; | |
| }); | |
| promises.push({ p, resolve: resolve3, reject }); | |
| } | |
| addPromise(); | |
| const callbackRes = Promise.resolve().then( | |
| () => cb( | |
| (y) => { | |
| addPromise(); | |
| promises.at(-2)?.resolve({ done: false, value: y }); | |
| }, | |
| (r) => { | |
| addPromise(); | |
| promises.at(-2)?.resolve({ done: true, value: r }); | |
| }, | |
| (err) => promises.shift()?.reject(err) | |
| ) | |
| ).catch((err) => promises.shift()?.reject(err)); | |
| while (1) { | |
| const p = promises[0]; | |
| if (!p) { | |
| throw new Error("Logic error in eventGenerator, promises should never be empty"); | |
| } | |
| const result = await p.p; | |
| promises.shift(); | |
| if (result.done) { | |
| await callbackRes; | |
| return result.value; | |
| } | |
| yield result.value; | |
| } | |
| throw new Error("Unreachable"); | |
| } | |
| // src/utils/hexFromBytes.ts | |
| function hexFromBytes(arr) { | |
| if (globalThis.Buffer) { | |
| return globalThis.Buffer.from(arr).toString("hex"); | |
| } else { | |
| const bin = []; | |
| arr.forEach((byte) => { | |
| bin.push(byte.toString(16).padStart(2, "0")); | |
| }); | |
| return bin.join(""); | |
| } | |
| } | |
| // 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/sha256.ts | |
| async function getWebWorkerCode() { | |
| const sha256Module = await Promise.resolve().then(() => (init_sha256_wrapper(), sha256_wrapper_exports)); | |
| return URL.createObjectURL(new Blob([sha256Module.createSHA256WorkerCode()])); | |
| } | |
| var pendingWorkers = []; | |
| var runningWorkers = /* @__PURE__ */ new Set(); | |
| var resolve; | |
| var waitPromise = new Promise((r) => { | |
| resolve = r; | |
| }); | |
| async function getWorker(poolSize) { | |
| { | |
| const worker2 = pendingWorkers.pop(); | |
| if (worker2) { | |
| runningWorkers.add(worker2); | |
| return worker2; | |
| } | |
| } | |
| if (!poolSize) { | |
| const worker2 = new Worker(await getWebWorkerCode()); | |
| runningWorkers.add(worker2); | |
| return worker2; | |
| } | |
| if (poolSize <= 0) { | |
| throw new TypeError("Invalid webworker pool size: " + poolSize); | |
| } | |
| while (runningWorkers.size >= poolSize) { | |
| await waitPromise; | |
| } | |
| const worker = new Worker(await getWebWorkerCode()); | |
| runningWorkers.add(worker); | |
| return worker; | |
| } | |
| async function freeWorker(worker, poolSize) { | |
| if (!poolSize) { | |
| return destroyWorker(worker); | |
| } | |
| runningWorkers.delete(worker); | |
| pendingWorkers.push(worker); | |
| const r = resolve; | |
| waitPromise = new Promise((r2) => { | |
| resolve = r2; | |
| }); | |
| r(); | |
| } | |
| function destroyWorker(worker) { | |
| runningWorkers.delete(worker); | |
| worker.terminate(); | |
| const r = resolve; | |
| waitPromise = new Promise((r2) => { | |
| resolve = r2; | |
| }); | |
| r(); | |
| } | |
| async function* sha256(buffer, opts) { | |
| yield 0; | |
| const maxCryptoSize = typeof opts?.useWebWorker === "object" && opts?.useWebWorker.minSize !== void 0 ? opts.useWebWorker.minSize : 1e7; | |
| if (buffer.size < maxCryptoSize && globalThis.crypto?.subtle) { | |
| const res = hexFromBytes( | |
| new Uint8Array( | |
| await globalThis.crypto.subtle.digest("SHA-256", buffer instanceof Blob ? await buffer.arrayBuffer() : buffer) | |
| ) | |
| ); | |
| yield 1; | |
| return res; | |
| } | |
| if (isFrontend) { | |
| if (opts?.useWebWorker) { | |
| try { | |
| const poolSize = typeof opts?.useWebWorker === "object" ? opts.useWebWorker.poolSize : void 0; | |
| const worker = await getWorker(poolSize); | |
| let messageHandler; | |
| let errorHandler; | |
| const cleanup = () => { | |
| worker.removeEventListener("message", messageHandler); | |
| worker.removeEventListener("error", errorHandler); | |
| }; | |
| return yield* eventToGenerator((yieldCallback, returnCallback, rejectCallback) => { | |
| messageHandler = (event) => { | |
| if (event.data.sha256) { | |
| cleanup(); | |
| freeWorker(worker, poolSize); | |
| returnCallback(event.data.sha256); | |
| } else if (event.data.progress) { | |
| yieldCallback(event.data.progress); | |
| try { | |
| opts.abortSignal?.throwIfAborted(); | |
| } catch (err) { | |
| cleanup(); | |
| destroyWorker(worker); | |
| rejectCallback(err); | |
| } | |
| } else { | |
| cleanup(); | |
| destroyWorker(worker); | |
| rejectCallback(event); | |
| } | |
| }; | |
| errorHandler = (event) => { | |
| cleanup(); | |
| destroyWorker(worker); | |
| rejectCallback(event.error); | |
| }; | |
| if (opts?.abortSignal) { | |
| try { | |
| opts.abortSignal?.throwIfAborted(); | |
| } catch (err) { | |
| cleanup(); | |
| destroyWorker(worker); | |
| rejectCallback(opts.abortSignal.reason ?? new DOMException("Aborted", "AbortError")); | |
| return; | |
| } | |
| const abortListener = () => { | |
| cleanup(); | |
| destroyWorker(worker); | |
| rejectCallback(opts.abortSignal?.reason ?? new DOMException("Aborted", "AbortError")); | |
| opts.abortSignal?.removeEventListener("abort", abortListener); | |
| }; | |
| opts.abortSignal.addEventListener("abort", abortListener); | |
| } | |
| worker.addEventListener("message", messageHandler); | |
| worker.addEventListener("error", errorHandler); | |
| worker.postMessage({ file: buffer }); | |
| }); | |
| } catch (err) { | |
| console.warn("Failed to use web worker for sha256", err); | |
| } | |
| } | |
| if (!wasmModule) { | |
| wasmModule = await Promise.resolve().then(() => (init_sha256_wrapper(), sha256_wrapper_exports)); | |
| } | |
| const sha2562 = await wasmModule.createSHA256(); | |
| sha2562.init(); | |
| const reader = buffer.stream().getReader(); | |
| const total = buffer.size; | |
| let bytesDone = 0; | |
| while (true) { | |
| const { done, value } = await reader.read(); | |
| if (done) { | |
| break; | |
| } | |
| sha2562.update(value); | |
| bytesDone += value.length; | |
| yield bytesDone / total; | |
| opts?.abortSignal?.throwIfAborted(); | |
| } | |
| return sha2562.digest("hex"); | |
| } | |
| if (!cryptoModule) { | |
| cryptoModule = await Promise.resolve().then(() => (init_sha256_node(), sha256_node_exports)); | |
| } | |
| return yield* cryptoModule.sha256Node(buffer, { abortSignal: opts?.abortSignal }); | |
| } | |
| var cryptoModule; | |
| var wasmModule; | |
| // src/utils/WebBlob.ts | |
| var WebBlob = class extends Blob { | |
| static async create(url, opts) { | |
| const customFetch = opts?.fetch ?? fetch; | |
| const probe = await customFetch(url, { | |
| headers: { | |
| Range: "bytes=0-0", | |
| ...opts?.accessToken && { Authorization: `Bearer ${opts.accessToken}` } | |
| } | |
| }); | |
| if (!probe.ok) { | |
| throw await createApiError(probe); | |
| } | |
| const contentType = probe.headers.get("content-type") || ""; | |
| if (probe.status === 206) { | |
| const totalSize = Number(probe.headers.get("content-range")?.split("/").pop()); | |
| await probe.body?.cancel(); | |
| if (Number.isFinite(totalSize) && totalSize >= (opts?.cacheBelow ?? 1e6)) { | |
| return new WebBlob(url, 0, totalSize, contentType, true, customFetch, opts?.accessToken); | |
| } | |
| const full = await customFetch(url, { | |
| ...opts?.accessToken && { headers: { Authorization: `Bearer ${opts.accessToken}` } } | |
| }); | |
| if (!full.ok) { | |
| throw await createApiError(full); | |
| } | |
| return full.blob(); | |
| } | |
| return probe.blob(); | |
| } | |
| url; | |
| start; | |
| end; | |
| contentType; | |
| full; | |
| fetch; | |
| accessToken; | |
| constructor(url, start, end, contentType, full, customFetch, accessToken) { | |
| super([]); | |
| this.url = url; | |
| this.start = start; | |
| this.end = end; | |
| this.contentType = contentType; | |
| this.full = full; | |
| this.fetch = customFetch; | |
| this.accessToken = accessToken; | |
| } | |
| 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 WebBlob.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, | |
| this.accessToken | |
| ); | |
| 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, { | |
| ...this.accessToken && { | |
| headers: { | |
| Authorization: `Bearer ${this.accessToken}` | |
| } | |
| } | |
| }).then((resp) => resp.ok ? resp : createApiError(resp)); | |
| } | |
| return fetch2(this.url, { | |
| headers: { | |
| Range: `bytes=${this.start}-${this.end - 1}`, | |
| ...this.accessToken && { Authorization: `Bearer ${this.accessToken}` } | |
| } | |
| }).then((resp) => resp.ok ? resp : createApiError(resp)); | |
| } | |
| }; | |
| // src/utils/base64FromBytes.ts | |
| function base64FromBytes(arr) { | |
| if (globalThis.Buffer) { | |
| return globalThis.Buffer.from(arr).toString("base64"); | |
| } else { | |
| const bin = []; | |
| arr.forEach((byte) => { | |
| bin.push(String.fromCharCode(byte)); | |
| }); | |
| return globalThis.btoa(bin.join("")); | |
| } | |
| } | |
| // src/utils/createBlobs.ts | |
| async function createBlobs(url, destPath, opts) { | |
| if (url.protocol === "http:" || url.protocol === "https:") { | |
| const blob = await WebBlob.create(url, { fetch: opts?.fetch, accessToken: opts?.accessToken }); | |
| return [{ path: destPath, blob }]; | |
| } | |
| 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)); | |
| const { subPaths: subPaths2 } = await Promise.resolve().then(() => (init_sub_paths(), sub_paths_exports)); | |
| const paths = await subPaths2(url, opts?.maxFolderDepth); | |
| if (paths.length === 1 && paths[0].relativePath === ".") { | |
| const blob = await FileBlob2.create(url); | |
| return [{ path: destPath, blob }]; | |
| } | |
| return Promise.all( | |
| paths.map(async (path2) => ({ | |
| path: `${destPath}/${path2.relativePath}`.replace(/\/[.]$/, "").replaceAll("//", "/").replace(/^[.]?\//, ""), | |
| blob: await FileBlob2.create(new URL(path2.path)) | |
| })) | |
| ); | |
| } | |
| throw new TypeError(`Unsupported URL protocol "${url.protocol}"`); | |
| } | |
| // src/vendor/lz4js/util.ts | |
| function hashU32(a) { | |
| a = a | 0; | |
| a = a + 2127912214 + (a << 12) | 0; | |
| a = a ^ -949894596 ^ a >>> 19; | |
| a = a + 374761393 + (a << 5) | 0; | |
| a = a + -744332180 ^ a << 9; | |
| a = a + -42973499 + (a << 3) | 0; | |
| return a ^ -1252372727 ^ a >>> 16 | 0; | |
| } | |
| function readU32(b, n) { | |
| let x = 0; | |
| x |= b[n++] << 0; | |
| x |= b[n++] << 8; | |
| x |= b[n++] << 16; | |
| x |= b[n++] << 24; | |
| return x; | |
| } | |
| function writeU32(b, n, x) { | |
| b[n++] = x >> 0 & 255; | |
| b[n++] = x >> 8 & 255; | |
| b[n++] = x >> 16 & 255; | |
| b[n++] = x >> 24 & 255; | |
| } | |
| function imul(a, b) { | |
| const ah = a >>> 16; | |
| const al = a & 65535; | |
| const bh = b >>> 16; | |
| const bl = b & 65535; | |
| return al * bl + (ah * bl + al * bh << 16) | 0; | |
| } | |
| // src/vendor/lz4js/xxh32.ts | |
| var prime1 = 2654435761; | |
| var prime2 = 2246822519; | |
| var prime3 = 3266489917; | |
| var prime4 = 668265263; | |
| var prime5 = 374761393; | |
| function rotl32(x, r) { | |
| x = x | 0; | |
| r = r | 0; | |
| return x >>> (32 - r | 0) | x << r | 0; | |
| } | |
| function rotmul32(h, r, m) { | |
| h = h | 0; | |
| r = r | 0; | |
| m = m | 0; | |
| return imul(h >>> (32 - r | 0) | h << r, m) | 0; | |
| } | |
| function shiftxor32(h, s) { | |
| h = h | 0; | |
| s = s | 0; | |
| return h >>> s ^ h | 0; | |
| } | |
| function xxhapply(h, src, m0, s, m1) { | |
| return rotmul32(imul(src, m0) + h, s, m1); | |
| } | |
| function xxh1(h, src, index) { | |
| return rotmul32(h + imul(src[index], prime5), 11, prime1); | |
| } | |
| function xxh4(h, src, index) { | |
| return xxhapply(h, readU32(src, index), prime3, 17, prime4); | |
| } | |
| function xxh16(h, src, index) { | |
| return [ | |
| xxhapply(h[0], readU32(src, index + 0), prime2, 13, prime1), | |
| xxhapply(h[1], readU32(src, index + 4), prime2, 13, prime1), | |
| xxhapply(h[2], readU32(src, index + 8), prime2, 13, prime1), | |
| xxhapply(h[3], readU32(src, index + 12), prime2, 13, prime1) | |
| ]; | |
| } | |
| function xxh32(seed, src, index, len) { | |
| let h; | |
| const l = len; | |
| if (len >= 16) { | |
| h = [seed + prime1 + prime2, seed + prime2, seed, seed - prime1]; | |
| while (len >= 16) { | |
| h = xxh16(h, src, index); | |
| index += 16; | |
| len -= 16; | |
| } | |
| h = rotl32(h[0], 1) + rotl32(h[1], 7) + rotl32(h[2], 12) + rotl32(h[3], 18) + l; | |
| } else { | |
| h = seed + prime5 + len >>> 0; | |
| } | |
| while (len >= 4) { | |
| h = xxh4(h, src, index); | |
| index += 4; | |
| len -= 4; | |
| } | |
| while (len > 0) { | |
| h = xxh1(h, src, index); | |
| index++; | |
| len--; | |
| } | |
| h = shiftxor32(imul(shiftxor32(imul(shiftxor32(h, 15), prime2), 13), prime3), 16); | |
| return h >>> 0; | |
| } | |
| var hash = xxh32; | |
| // src/vendor/lz4js/index.ts | |
| var minMatch = 4; | |
| var matchSearchLimit = 12; | |
| var minTrailingLitterals = 5; | |
| var skipTrigger = 6; | |
| var hashSize = 1 << 16; | |
| var mlBits = 4; | |
| var mlMask = (1 << mlBits) - 1; | |
| var runBits = 4; | |
| var runMask = (1 << runBits) - 1; | |
| var blockBuf = makeBuffer(5 << 20); | |
| var hashTable = makeHashTable(); | |
| var magicNum = 407708164; | |
| var fdVersion = 64; | |
| var bsDefault = 7; | |
| var bsShift = 4; | |
| var bsMap = { | |
| 4: 65536, | |
| 5: 262144, | |
| 6: 1048576, | |
| 7: 4194304 | |
| }; | |
| function makeHashTable() { | |
| try { | |
| return new Uint32Array(hashSize); | |
| } catch (error) { | |
| const hashTable2 = new Array(hashSize); | |
| for (let i = 0; i < hashSize; i++) { | |
| hashTable2[i] = 0; | |
| } | |
| return hashTable2; | |
| } | |
| } | |
| function clearHashTable(table) { | |
| for (let i = 0; i < hashSize; i++) { | |
| table[i] = 0; | |
| } | |
| } | |
| function makeBuffer(size) { | |
| return new Uint8Array(size); | |
| } | |
| function sliceArray(array, start, end) { | |
| return array.slice(start, end); | |
| } | |
| function compressBound(n) { | |
| return n + n / 255 + 16 | 0; | |
| } | |
| function compressBlock(src, dst, sIndex, sLength, hashTable2) { | |
| let mIndex, mAnchor, mLength, mOffset, mStep; | |
| let literalCount, dIndex, sEnd, n; | |
| dIndex = 0; | |
| sEnd = sLength + sIndex; | |
| mAnchor = sIndex; | |
| let searchMatchCount = (1 << skipTrigger) + 3; | |
| while (sIndex <= sEnd - matchSearchLimit) { | |
| const seq = readU32(src, sIndex); | |
| let hash2 = hashU32(seq) >>> 0; | |
| hash2 = (hash2 >> 16 ^ hash2) >>> 0 & 65535; | |
| mIndex = hashTable2[hash2] - 1; | |
| hashTable2[hash2] = sIndex + 1; | |
| if (mIndex < 0 || sIndex - mIndex >>> 16 > 0 || readU32(src, mIndex) !== seq) { | |
| mStep = searchMatchCount++ >> skipTrigger; | |
| sIndex += mStep; | |
| continue; | |
| } | |
| searchMatchCount = (1 << skipTrigger) + 3; | |
| literalCount = sIndex - mAnchor; | |
| mOffset = sIndex - mIndex; | |
| sIndex += minMatch; | |
| mIndex += minMatch; | |
| mLength = sIndex; | |
| while (sIndex < sEnd - minTrailingLitterals && src[sIndex] === src[mIndex]) { | |
| sIndex++; | |
| mIndex++; | |
| } | |
| mLength = sIndex - mLength; | |
| const token = mLength < mlMask ? mLength : mlMask; | |
| if (literalCount >= runMask) { | |
| dst[dIndex++] = (runMask << mlBits) + token; | |
| for (n = literalCount - runMask; n >= 255; n -= 255) { | |
| dst[dIndex++] = 255; | |
| } | |
| dst[dIndex++] = n; | |
| } else { | |
| dst[dIndex++] = (literalCount << mlBits) + token; | |
| } | |
| for (let i = 0; i < literalCount; i++) { | |
| dst[dIndex++] = src[mAnchor + i]; | |
| } | |
| dst[dIndex++] = mOffset; | |
| dst[dIndex++] = mOffset >> 8; | |
| if (mLength >= mlMask) { | |
| for (n = mLength - mlMask; n >= 255; n -= 255) { | |
| dst[dIndex++] = 255; | |
| } | |
| dst[dIndex++] = n; | |
| } | |
| mAnchor = sIndex; | |
| } | |
| if (mAnchor === 0) { | |
| return 0; | |
| } | |
| literalCount = sEnd - mAnchor; | |
| if (literalCount >= runMask) { | |
| dst[dIndex++] = runMask << mlBits; | |
| for (n = literalCount - runMask; n >= 255; n -= 255) { | |
| dst[dIndex++] = 255; | |
| } | |
| dst[dIndex++] = n; | |
| } else { | |
| dst[dIndex++] = literalCount << mlBits; | |
| } | |
| sIndex = mAnchor; | |
| while (sIndex < sEnd) { | |
| dst[dIndex++] = src[sIndex++]; | |
| } | |
| return dIndex; | |
| } | |
| function compressFrame(src, dst) { | |
| let dIndex = 0; | |
| writeU32(dst, dIndex, magicNum); | |
| dIndex += 4; | |
| dst[dIndex++] = fdVersion; | |
| dst[dIndex++] = bsDefault << bsShift; | |
| dst[dIndex] = hash(0, dst, 4, dIndex - 4) >> 8; | |
| dIndex++; | |
| const maxBlockSize = bsMap[bsDefault]; | |
| let remaining = src.length; | |
| let sIndex = 0; | |
| clearHashTable(hashTable); | |
| while (remaining > 0) { | |
| let compSize = 0; | |
| const blockSize = remaining > maxBlockSize ? maxBlockSize : remaining; | |
| compSize = compressBlock(src, blockBuf, sIndex, blockSize, hashTable); | |
| if (compSize > blockSize || compSize === 0) { | |
| writeU32(dst, dIndex, 2147483648 | blockSize); | |
| dIndex += 4; | |
| for (let z = sIndex + blockSize; sIndex < z; ) { | |
| dst[dIndex++] = src[sIndex++]; | |
| } | |
| remaining -= blockSize; | |
| } else { | |
| writeU32(dst, dIndex, compSize); | |
| dIndex += 4; | |
| for (let j = 0; j < compSize; ) { | |
| dst[dIndex++] = blockBuf[j++]; | |
| } | |
| sIndex += blockSize; | |
| remaining -= blockSize; | |
| } | |
| } | |
| writeU32(dst, dIndex, 0); | |
| dIndex += 4; | |
| return dIndex; | |
| } | |
| function compress(src, maxSize) { | |
| let dst, size; | |
| if (maxSize === void 0) { | |
| maxSize = compressBound(src.length); | |
| } | |
| dst = makeBuffer(maxSize); | |
| size = compressFrame(src, dst); | |
| if (size !== maxSize) { | |
| dst = sliceArray(dst, 0, size); | |
| } | |
| return dst; | |
| } | |
| // src/utils/XetBlob.ts | |
| var XET_CHUNK_HEADER_BYTES = 8; | |
| function bg4_split_bytes(bytes) { | |
| const ret = new Uint8Array(bytes.byteLength); | |
| const split = Math.floor(bytes.byteLength / 4); | |
| const rem = bytes.byteLength % 4; | |
| const g1_pos = split + (rem >= 1 ? 1 : 0); | |
| const g2_pos = g1_pos + split + (rem >= 2 ? 1 : 0); | |
| const g3_pos = g2_pos + split + (rem == 3 ? 1 : 0); | |
| for (let i = 0, j = 0; i < bytes.byteLength; i += 4, j++) { | |
| ret[j] = bytes[i]; | |
| } | |
| for (let i = 1, j = g1_pos; i < bytes.byteLength; i += 4, j++) { | |
| ret[j] = bytes[i]; | |
| } | |
| for (let i = 2, j = g2_pos; i < bytes.byteLength; i += 4, j++) { | |
| ret[j] = bytes[i]; | |
| } | |
| for (let i = 3, j = g3_pos; i < bytes.byteLength; i += 4, j++) { | |
| ret[j] = bytes[i]; | |
| } | |
| return ret; | |
| } | |
| // src/utils/ChunkCache.ts | |
| var CHUNK_CACHE_INITIAL_SIZE = 1e4; | |
| var CHUNK_CACHE_GROW_FACTOR = 1.5; | |
| var CHUNK_CACHE_MAX_SIZE = 1e6; | |
| var ChunkCache = class { | |
| index = 0; | |
| // Index >= 0 means local xorb, < 0 means remote xorb | |
| xorbIndices; | |
| // Max 8K chunks per xorb, less than 64K uint16_t | |
| chunkIndices; | |
| map = /* @__PURE__ */ new Map(); | |
| // hash -> chunkCacheIndex. Less overhead that way, empty object is 60+B and empty array is 40+B | |
| hmacs = /* @__PURE__ */ new Set(); | |
| // todo : remove old hmacs | |
| maxSize; | |
| constructor(maxSize = CHUNK_CACHE_MAX_SIZE) { | |
| if (maxSize < 1) { | |
| throw new Error("maxSize must be at least 1"); | |
| } | |
| this.maxSize = maxSize; | |
| this.xorbIndices = new Int32Array(Math.min(CHUNK_CACHE_INITIAL_SIZE, maxSize)); | |
| this.chunkIndices = new Uint16Array(Math.min(CHUNK_CACHE_INITIAL_SIZE, maxSize)); | |
| } | |
| addChunkToCache(hash2, xorbIndex, chunkIndex, hmac2) { | |
| if (this.map.has(hash2)) { | |
| return; | |
| } | |
| if (this.map.values().next().value === this.index) { | |
| this.map.delete(this.map.keys().next().value); | |
| } | |
| this.map.set(hash2, this.index); | |
| if (hmac2 !== null) { | |
| this.hmacs.add(hmac2); | |
| } | |
| if (this.index >= this.xorbIndices.length) { | |
| const oldXorbIndices = this.xorbIndices; | |
| const oldChunkIndices = this.chunkIndices; | |
| this.xorbIndices = new Int32Array(Math.min(this.xorbIndices.length * CHUNK_CACHE_GROW_FACTOR, this.maxSize)); | |
| this.chunkIndices = new Uint16Array(Math.min(this.chunkIndices.length * CHUNK_CACHE_GROW_FACTOR, this.maxSize)); | |
| this.xorbIndices.set(oldXorbIndices); | |
| this.chunkIndices.set(oldChunkIndices); | |
| } | |
| this.xorbIndices[this.index] = xorbIndex; | |
| this.chunkIndices[this.index] = chunkIndex; | |
| this.index = (this.index + 1) % this.maxSize; | |
| } | |
| getChunk(hash2, hmacFunction) { | |
| let index = this.map.get(hash2); | |
| if (index === void 0 && hmacFunction !== null) { | |
| for (const hmac2 of this.hmacs) { | |
| index = this.map.get(hmacFunction(hash2, hmac2)); | |
| if (index !== void 0) { | |
| break; | |
| } | |
| } | |
| } | |
| if (index === void 0) { | |
| return void 0; | |
| } | |
| return { | |
| xorbIndex: this.xorbIndices[index], | |
| chunkIndex: this.chunkIndices[index] | |
| }; | |
| } | |
| updateChunkIndex(hash2, chunkIndex) { | |
| const index = this.map.get(hash2); | |
| if (index === void 0) { | |
| throw new Error(`Chunk not found in cache: ${hash2}`); | |
| } | |
| this.chunkIndices[index] = chunkIndex; | |
| } | |
| removeChunkFromCache(hash2) { | |
| this.map.delete(hash2); | |
| } | |
| }; | |
| // src/utils/xetWriteToken.ts | |
| var JWT_SAFETY_PERIOD = 6e4; | |
| var JWT_CACHE_SIZE = 1e3; | |
| var jwtPromises = /* @__PURE__ */ new Map(); | |
| var jwts = /* @__PURE__ */ new Map(); | |
| async function xetWriteToken(params) { | |
| if (params.xetParams.expiresAt && params.xetParams.casUrl && params.xetParams.accessToken && params.xetParams.expiresAt > new Date(Date.now() + JWT_SAFETY_PERIOD)) { | |
| return { accessToken: params.xetParams.accessToken, casUrl: params.xetParams.casUrl }; | |
| } | |
| const key = params.xetParams.refreshWriteTokenUrl; | |
| const jwt = jwts.get(key); | |
| if (jwt && jwt.expiresAt > new Date(Date.now() + JWT_SAFETY_PERIOD)) { | |
| return { accessToken: jwt.accessToken, casUrl: jwt.casUrl }; | |
| } | |
| const existingPromise = jwtPromises.get(key); | |
| if (existingPromise) { | |
| return existingPromise; | |
| } | |
| const promise = (async () => { | |
| const resp = await (params.fetch ?? fetch)(params.xetParams.refreshWriteTokenUrl, { | |
| headers: { | |
| ...params.accessToken ? { | |
| Authorization: `Bearer ${params.accessToken}` | |
| } : {}, | |
| ...params.xetParams.sessionId ? { "X-Xet-Session-Id": params.xetParams.sessionId } : {} | |
| } | |
| }); | |
| if (!resp.ok) { | |
| throw await createApiError(resp); | |
| } | |
| const json = await resp.json(); | |
| const jwt2 = { | |
| accessToken: json.accessToken, | |
| expiresAt: new Date(json.exp * 1e3), | |
| casUrl: json.casUrl | |
| }; | |
| jwtPromises.delete(key); | |
| for (const [key2, value] of jwts.entries()) { | |
| if (value.expiresAt < new Date(Date.now() + JWT_SAFETY_PERIOD)) { | |
| jwts.delete(key2); | |
| } else { | |
| break; | |
| } | |
| } | |
| if (jwts.size >= JWT_CACHE_SIZE) { | |
| const keyToDelete = jwts.keys().next().value; | |
| if (keyToDelete) { | |
| jwts.delete(keyToDelete); | |
| } | |
| } | |
| jwts.set(key, jwt2); | |
| return { | |
| accessToken: json.accessToken, | |
| casUrl: json.casUrl | |
| }; | |
| })(); | |
| jwtPromises.set(key, promise); | |
| return promise; | |
| } | |
| // src/utils/shardParser.ts | |
| var HASH_LENGTH = 32; | |
| var XORB_HASH_BOOKEND = "ff".repeat(HASH_LENGTH); | |
| function readHashFromArray(array, offset) { | |
| let hash2 = ""; | |
| for (let i = 0; i < HASH_LENGTH; i += 8) { | |
| hash2 += `${array[offset + i + 7].toString(16).padStart(2, "0")}${array[offset + i + 6].toString(16).padStart(2, "0")}${array[offset + i + 5].toString(16).padStart(2, "0")}${array[offset + i + 4].toString(16).padStart(2, "0")}${array[offset + i + 3].toString(16).padStart(2, "0")}${array[offset + i + 2].toString(16).padStart(2, "0")}${array[offset + i + 1].toString(16).padStart(2, "0")}${array[offset + i].toString(16).padStart(2, "0")}`; | |
| } | |
| return hash2; | |
| } | |
| async function parseShardData(shardBlob) { | |
| const shard = new Uint8Array(await shardBlob.arrayBuffer()); | |
| const shardView = new DataView(shard.buffer); | |
| const magicTag = shard.slice(0, SHARD_MAGIC_TAG.length); | |
| if (!magicTag.every((byte, i) => byte === SHARD_MAGIC_TAG[i])) { | |
| throw new Error("Invalid shard magic tag"); | |
| } | |
| const version2 = shardView.getBigUint64(SHARD_MAGIC_TAG.length, true); | |
| if (version2 !== SHARD_HEADER_VERSION) { | |
| throw new Error(`Invalid shard version: ${version2}`); | |
| } | |
| const footerSize = Number(shardView.getBigUint64(SHARD_MAGIC_TAG.length + 8, true)); | |
| const footerStart = shard.length - footerSize; | |
| const footerVersion = shardView.getBigUint64(footerStart, true); | |
| if (footerVersion !== SHARD_FOOTER_VERSION) { | |
| throw new Error(`Invalid shard footer version: ${footerVersion}`); | |
| } | |
| const xorbInfoStart = Number(shardView.getBigUint64(footerStart + 16, true)); | |
| const fileLookupStart = Number(shardView.getBigUint64(footerStart + 24, true)); | |
| const hmacKey = readHashFromArray(shard, footerStart + 72); | |
| const xorbs = []; | |
| let offset = xorbInfoStart; | |
| while (offset < fileLookupStart) { | |
| const xorbHash2 = readHashFromArray(shard, offset); | |
| offset += HASH_LENGTH; | |
| if (xorbHash2 === XORB_HASH_BOOKEND) { | |
| break; | |
| } | |
| offset += 4; | |
| const chunkCount = shardView.getUint32(offset, true); | |
| offset += 4; | |
| offset += 4; | |
| offset += 4; | |
| const chunks = []; | |
| for (let i = 0; i < chunkCount; i++) { | |
| const chunkHash = readHashFromArray(shard, offset); | |
| offset += HASH_LENGTH; | |
| const startOffset = shardView.getUint32(offset, true); | |
| offset += 4; | |
| const length = shardView.getUint32(offset, true); | |
| offset += 4; | |
| offset += 8; | |
| chunks.push({ | |
| hash: chunkHash, | |
| startOffset, | |
| unpackedLength: length | |
| }); | |
| } | |
| xorbs.push({ | |
| hash: xorbHash2, | |
| chunks | |
| }); | |
| } | |
| return { | |
| hmacKey, | |
| xorbs | |
| }; | |
| } | |
| // src/utils/sum.ts | |
| function sum(arr) { | |
| return arr.reduce((a, b) => a + b, 0); | |
| } | |
| // src/utils/SplicedBlob.ts | |
| var SplicedBlob = class extends Blob { | |
| originalBlob; | |
| spliceOperations; | |
| constructor(originalBlob, spliceOperations) { | |
| super(); | |
| this.originalBlob = originalBlob; | |
| this.spliceOperations = spliceOperations; | |
| } | |
| static create(originalBlob, operations) { | |
| for (const op of operations) { | |
| if (op.start < 0 || op.end < 0) { | |
| throw new Error("Invalid start/end positions for SplicedBlob"); | |
| } | |
| if (op.start > originalBlob.size || op.end > originalBlob.size) { | |
| throw new Error("Invalid start/end positions for SplicedBlob"); | |
| } | |
| if (op.start > op.end) { | |
| throw new Error("Invalid start/end positions for SplicedBlob"); | |
| } | |
| } | |
| const sortedOps = [...operations].sort((a, b) => a.start - b.start); | |
| for (let i = 0; i < sortedOps.length - 1; i++) { | |
| if (sortedOps[i].end > sortedOps[i + 1].start) { | |
| throw new Error("Overlapping splice operations are not supported"); | |
| } | |
| } | |
| return new SplicedBlob(originalBlob, sortedOps); | |
| } | |
| /** | |
| * Returns the size of the spliced blob. | |
| * Size = original size - total replaced size + total insert size | |
| */ | |
| get size() { | |
| let totalReplacedSize = 0; | |
| let totalInsertSize = 0; | |
| for (const op of this.spliceOperations) { | |
| totalReplacedSize += op.end - op.start; | |
| totalInsertSize += op.insert.size; | |
| } | |
| return this.originalBlob.size - totalReplacedSize + totalInsertSize; | |
| } | |
| /** | |
| * Returns the MIME type of the original blob. | |
| */ | |
| get type() { | |
| return this.originalBlob.type; | |
| } | |
| /** | |
| * Returns a new instance of SplicedBlob 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 support 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) { | |
| throw new TypeError("Unsupported negative start/end on SplicedBlob.slice"); | |
| } | |
| start = Math.min(start, this.size); | |
| end = Math.min(end, this.size); | |
| if (start >= end) { | |
| return new Blob([]); | |
| } | |
| const segments = this.segments; | |
| const segmentBoundaries = [0]; | |
| let cumulativeSize = 0; | |
| for (const segment of segments) { | |
| cumulativeSize += segment.size; | |
| segmentBoundaries.push(cumulativeSize); | |
| } | |
| const resultSegments = []; | |
| for (let i = 0; i < segments.length; i++) { | |
| const segmentStart = segmentBoundaries[i]; | |
| const segmentEnd = segmentBoundaries[i + 1]; | |
| if (segmentEnd <= start) { | |
| continue; | |
| } | |
| if (segmentStart >= end) { | |
| break; | |
| } | |
| const sliceStart = Math.max(0, start - segmentStart); | |
| const sliceEnd = Math.min(segments[i].size, end - segmentStart); | |
| if (sliceStart < sliceEnd) { | |
| resultSegments.push(segments[i].slice(sliceStart, sliceEnd)); | |
| } | |
| } | |
| return new Blob(resultSegments); | |
| } | |
| get firstSpliceIndex() { | |
| return this.spliceOperations[0]?.start ?? Infinity; | |
| } | |
| /** | |
| * Read the spliced blob content and returns it as an ArrayBuffer. | |
| */ | |
| async arrayBuffer() { | |
| const segments = this.segments; | |
| const buffers = await Promise.all(segments.map((segment) => segment.arrayBuffer())); | |
| const totalSize = sum(buffers.map((buffer) => buffer.byteLength)); | |
| const result = new Uint8Array(totalSize); | |
| let offset = 0; | |
| for (const buffer of buffers) { | |
| result.set(new Uint8Array(buffer), offset); | |
| offset += buffer.byteLength; | |
| } | |
| return result.buffer; | |
| } | |
| /** | |
| * Read the spliced blob content and returns it as a string. | |
| */ | |
| async text() { | |
| const buffer = await this.arrayBuffer(); | |
| return new TextDecoder().decode(buffer); | |
| } | |
| /** | |
| * Returns a stream around the spliced blob content. | |
| */ | |
| stream() { | |
| const readable = new ReadableStream({ | |
| start: async (controller) => { | |
| try { | |
| const segments = this.segments; | |
| for (const segment of segments) { | |
| const reader = segment.stream().getReader(); | |
| try { | |
| while (true) { | |
| const { done, value } = await reader.read(); | |
| if (done) { | |
| break; | |
| } | |
| controller.enqueue(value); | |
| } | |
| } finally { | |
| reader.releaseLock(); | |
| } | |
| } | |
| controller.close(); | |
| } catch (error) { | |
| controller.error(error); | |
| } | |
| } | |
| }); | |
| return readable; | |
| } | |
| /** | |
| * Get all segments that make up the spliced blob. | |
| * This includes original blob segments between splice operations and insert blobs. | |
| */ | |
| get segments() { | |
| const segments = []; | |
| let currentPosition = 0; | |
| const sortedOps = [...this.spliceOperations].sort((a, b) => a.start - b.start); | |
| for (const op of sortedOps) { | |
| if (currentPosition < op.start) { | |
| segments.push(this.originalBlob.slice(currentPosition, op.start)); | |
| } | |
| if (op.insert.size > 0) { | |
| segments.push(op.insert); | |
| } | |
| currentPosition = op.end; | |
| } | |
| if (currentPosition < this.originalBlob.size) { | |
| segments.push(this.originalBlob.slice(currentPosition)); | |
| } | |
| return segments; | |
| } | |
| }; | |
| // src/utils/createXorbs.ts | |
| var import_xetchunk_wasm = require("@huggingface/xetchunk-wasm"); | |
| var TARGET_CHUNK_SIZE = 64 * 1024; | |
| var MAX_CHUNK_SIZE = 2 * TARGET_CHUNK_SIZE; | |
| var XORB_SIZE = 64 * 1024 * 1024; | |
| var MAX_XORB_CHUNKS = 8 * 1024; | |
| var INTERVAL_BETWEEN_REMOTE_DEDUP = 4e6; | |
| var PROCESSING_PROGRESS_RATIO = 0.1; | |
| var UPLOADING_PROGRESS_RATIO = 1 - PROCESSING_PROGRESS_RATIO; | |
| function computeXorbHashHex(chunks) { | |
| const chunkObjs = chunks.map((c) => ({ hash: (0, import_xetchunk_wasm.hexToBytes)(c.hash), length: c.length })); | |
| return (0, import_xetchunk_wasm.hashToHex)((0, import_xetchunk_wasm.xorbHash)(chunkObjs)); | |
| } | |
| function computeHmacHex(hash2, key) { | |
| return (0, import_xetchunk_wasm.hashToHex)((0, import_xetchunk_wasm.hmac)((0, import_xetchunk_wasm.hexToBytes)(hash2), (0, import_xetchunk_wasm.hexToBytes)(key))); | |
| } | |
| function computeVerificationHashHex(hashes) { | |
| return (0, import_xetchunk_wasm.hashToHex)((0, import_xetchunk_wasm.verificationHash)(hashes.map(import_xetchunk_wasm.hexToBytes))); | |
| } | |
| function computeFileHashHex(chunks) { | |
| const chunkObjs = chunks.map((c) => ({ hash: (0, import_xetchunk_wasm.hexToBytes)(c.hash), length: c.length })); | |
| return (0, import_xetchunk_wasm.hashToHex)((0, import_xetchunk_wasm.fileHash)(chunkObjs)); | |
| } | |
| function addDataToChunker(data, chunker) { | |
| return (0, import_xetchunk_wasm.nextBlock)(chunker, data).map((c) => ({ hash: (0, import_xetchunk_wasm.hashToHex)(c.hash), length: c.length, dedup: false })); | |
| } | |
| function finalizeChunker(chunker) { | |
| const last = (0, import_xetchunk_wasm.finalize)(chunker); | |
| if (!last) { | |
| return []; | |
| } | |
| return [{ hash: (0, import_xetchunk_wasm.hashToHex)(last.hash), length: last.length, dedup: false }]; | |
| } | |
| var CurrentXorbInfo = class { | |
| id; | |
| offset; | |
| chunks; | |
| fileProcessedBytes; | |
| fileUploadedBytes; | |
| fileSize; | |
| data; | |
| immutableData; | |
| constructor() { | |
| this.id = 0; | |
| this.offset = 0; | |
| this.chunks = []; | |
| this.fileProcessedBytes = {}; | |
| this.fileUploadedBytes = {}; | |
| this.fileSize = {}; | |
| this.data = new Uint8Array(XORB_SIZE); | |
| this.immutableData = null; | |
| } | |
| event(computeXorbHash) { | |
| const xorbChunksCleaned = this.chunks.map((chunk2) => ({ | |
| hash: chunk2.hash, | |
| length: chunk2.length | |
| })); | |
| return { | |
| event: "xorb", | |
| xorb: this.data.subarray(0, this.offset), | |
| hash: computeXorbHash(xorbChunksCleaned), | |
| chunks: xorbChunksCleaned, | |
| id: this.id, | |
| files: Object.entries(this.fileProcessedBytes).map(([path2, processedBytes]) => ({ | |
| path: path2, | |
| progress: processedBytes / this.fileSize[path2], | |
| lastSentProgress: ((this.fileUploadedBytes[path2] ?? 0) + (processedBytes - (this.fileUploadedBytes[path2] ?? 0)) * PROCESSING_PROGRESS_RATIO) / this.fileSize[path2] | |
| })) | |
| }; | |
| } | |
| }; | |
| async function* createXorbs(fileSources, params) { | |
| const alreadyDoneFileSha256s = /* @__PURE__ */ new Set(); | |
| let xorbId = 0; | |
| const chunkCache = new ChunkCache(); | |
| let xorb = new CurrentXorbInfo(); | |
| const nextXorb = (currentFile) => { | |
| const event = xorb.event(computeXorbHashHex); | |
| xorbId++; | |
| xorb = new CurrentXorbInfo(); | |
| xorb.id = xorbId; | |
| xorb.fileUploadedBytes = { | |
| [currentFile.path]: currentFile.uploadedBytes | |
| }; | |
| xorb.fileSize[currentFile.path] = currentFile.size; | |
| return event; | |
| }; | |
| const pendingFileEvents = []; | |
| const remoteXorbHashes = [""]; | |
| for await (const fileSource of fileSources) { | |
| params.yieldCallback?.({ | |
| event: "fileProgress", | |
| path: fileSource.path, | |
| progress: 0 | |
| }); | |
| if (fileSource.sha256 && alreadyDoneFileSha256s.has(fileSource.sha256)) { | |
| params.yieldCallback?.({ | |
| event: "fileProgress", | |
| path: fileSource.path, | |
| progress: 1 | |
| }); | |
| continue; | |
| } | |
| if (fileSource.sha256) { | |
| alreadyDoneFileSha256s.add(fileSource.sha256); | |
| } | |
| const chunker = (0, import_xetchunk_wasm.createChunker)(TARGET_CHUNK_SIZE); | |
| { | |
| xorb.fileSize[fileSource.path] = fileSource.content.size; | |
| if (fileSource.content instanceof SplicedBlob && fileSource.content.firstSpliceIndex < MAX_CHUNK_SIZE) { | |
| await loadDedupInfoToCache( | |
| fileSource.content.originalBlob.slice(0, MAX_CHUNK_SIZE), | |
| remoteXorbHashes, | |
| params, | |
| chunkCache, | |
| computeHmacHex, | |
| { | |
| maxChunks: 1, | |
| isAtBeginning: true | |
| } | |
| ); | |
| } | |
| let bytesSinceRemoteDedup = Infinity; | |
| let bytesSinceLastProgressEvent = 0; | |
| let isFirstFileChunk = true; | |
| const sourceChunks = []; | |
| const reader = fileSource.content.stream().getReader(); | |
| let processedBytes = 0; | |
| let dedupedBytes = 0; | |
| const fileChunks = []; | |
| const chunkMetadata = []; | |
| const addChunks = async function* (chunks) { | |
| for (const chunk2 of chunks) { | |
| if (isFirstFileChunk) { | |
| chunk2.dedup = true; | |
| isFirstFileChunk = false; | |
| } | |
| let chunkIndex = xorb.chunks.length; | |
| let chunkXorbId = xorbId; | |
| const chunkToCopy = removeChunkFromSourceData(sourceChunks, chunk2.length); | |
| let cacheData = chunkCache.getChunk(chunk2.hash, computeHmacHex); | |
| if (cacheData === void 0 && chunk2.dedup && bytesSinceRemoteDedup >= INTERVAL_BETWEEN_REMOTE_DEDUP) { | |
| const token = await xetWriteToken(params); | |
| bytesSinceRemoteDedup = 0; | |
| const shardResp = await (params.fetch ?? fetch)(token.casUrl + "/v1/chunks/default/" + chunk2.hash, { | |
| headers: { | |
| Authorization: `Bearer ${token.accessToken}` | |
| } | |
| }); | |
| if (shardResp.ok) { | |
| const shard = await shardResp.blob(); | |
| const shardData = await parseShardData(shard); | |
| for (const xorb2 of shardData.xorbs) { | |
| const remoteXorbId = -remoteXorbHashes.length; | |
| remoteXorbHashes.push(xorb2.hash); | |
| let i = 0; | |
| for (const chunk3 of xorb2.chunks) { | |
| chunkCache.addChunkToCache(chunk3.hash, remoteXorbId, i++, shardData.hmacKey); | |
| } | |
| } | |
| cacheData = chunkCache.getChunk(chunk2.hash, computeHmacHex); | |
| const oldDedupedBytes = dedupedBytes; | |
| dedupedBytes = backtrackDedup(xorb, computeHmacHex, shardData, chunkCache, chunkMetadata, dedupedBytes); | |
| if (dedupedBytes > oldDedupedBytes) { | |
| xorb.fileUploadedBytes[fileSource.path] ??= 0; | |
| xorb.fileUploadedBytes[fileSource.path] += dedupedBytes - oldDedupedBytes; | |
| } | |
| } | |
| } | |
| if (cacheData === void 0) { | |
| if (!writeChunk(xorb, chunkToCopy, chunk2.hash)) { | |
| yield nextXorb({ path: fileSource.path, uploadedBytes: processedBytes, size: fileSource.content.size }); | |
| chunkIndex = 0; | |
| chunkXorbId = xorbId; | |
| for (const event of pendingFileEvents) { | |
| event.representation = event.representation.map((rep) => ({ | |
| ...rep, | |
| xorbId: rep.xorbId >= 0 ? rep.xorbId : remoteXorbHashes[-rep.xorbId] | |
| })); | |
| yield event; | |
| } | |
| pendingFileEvents.length = 0; | |
| if (!writeChunk(xorb, chunkToCopy, chunk2.hash)) { | |
| throw new Error("Failed to write chunk into xorb"); | |
| } | |
| } | |
| chunkCache.addChunkToCache(chunk2.hash, xorbId, chunkIndex, null); | |
| } else { | |
| chunkXorbId = cacheData.xorbIndex; | |
| chunkIndex = cacheData.chunkIndex; | |
| dedupedBytes += chunk2.length; | |
| xorb.fileUploadedBytes[fileSource.path] ??= 0; | |
| xorb.fileUploadedBytes[fileSource.path] += chunk2.length; | |
| } | |
| bytesSinceRemoteDedup += chunk2.length; | |
| bytesSinceLastProgressEvent += chunk2.length; | |
| fileChunks.push({ hash: chunk2.hash, length: chunk2.length }); | |
| chunkMetadata.push({ | |
| xorbId: chunkXorbId, | |
| chunkIndex, | |
| length: chunk2.length | |
| }); | |
| xorb.fileProcessedBytes[fileSource.path] = processedBytes; | |
| if (bytesSinceLastProgressEvent >= 1e6) { | |
| bytesSinceLastProgressEvent = 0; | |
| params.yieldCallback?.({ | |
| event: "fileProgress", | |
| path: fileSource.path, | |
| progress: ((xorb.fileUploadedBytes[fileSource.path] ?? 0) + (xorb.fileProcessedBytes[fileSource.path] - (xorb.fileUploadedBytes[fileSource.path] ?? 0)) * PROCESSING_PROGRESS_RATIO) / fileSource.content.size | |
| }); | |
| } | |
| if (xorb.chunks.length >= MAX_XORB_CHUNKS) { | |
| yield nextXorb({ path: fileSource.path, uploadedBytes: processedBytes, size: fileSource.content.size }); | |
| for (const event of pendingFileEvents) { | |
| event.representation = event.representation.map((rep) => ({ | |
| ...rep, | |
| xorbId: rep.xorbId >= 0 ? rep.xorbId : remoteXorbHashes[-rep.xorbId] | |
| })); | |
| yield event; | |
| } | |
| pendingFileEvents.length = 0; | |
| } | |
| } | |
| }; | |
| while (true) { | |
| const { done, value } = await reader.read(); | |
| if (done) { | |
| yield* addChunks(finalizeChunker(chunker)); | |
| break; | |
| } | |
| processedBytes += value.length; | |
| sourceChunks.push(value); | |
| yield* addChunks(addDataToChunker(value, chunker)); | |
| } | |
| const fileRepresentation = buildFileRepresentation(chunkMetadata, fileChunks, computeVerificationHashHex); | |
| xorb.immutableData = { | |
| chunkIndex: xorb.chunks.length, | |
| offset: xorb.offset | |
| }; | |
| const dedupRatio = fileSource.content.size > 0 ? dedupedBytes / fileSource.content.size : 0; | |
| pendingFileEvents.push({ | |
| event: "file", | |
| path: fileSource.path, | |
| hash: computeFileHashHex(fileChunks), | |
| sha256: fileSource.sha256, | |
| dedupRatio, | |
| representation: fileRepresentation | |
| }); | |
| } | |
| } | |
| if (xorb.offset > 0) { | |
| yield xorb.event(computeXorbHashHex); | |
| } | |
| for (const event of pendingFileEvents) { | |
| event.representation = event.representation.map((rep) => ({ | |
| ...rep, | |
| xorbId: rep.xorbId >= 0 ? rep.xorbId : remoteXorbHashes[-rep.xorbId] | |
| })); | |
| yield event; | |
| } | |
| } | |
| function backtrackDedup(xorb, computeHmac, shardData, chunkCache, chunkMetadata, dedupedBytes) { | |
| const chunkIndexesToBacktrackFor = /* @__PURE__ */ new Map(); | |
| for (let chunkToRecheckIndex = xorb.immutableData?.chunkIndex ?? 0; chunkToRecheckIndex < xorb.chunks.length; chunkToRecheckIndex++) { | |
| const chunk2 = xorb.chunks[chunkToRecheckIndex]; | |
| const hmacHash = computeHmac(chunk2.hash, shardData.hmacKey); | |
| const cacheData = chunkCache.getChunk(hmacHash, null); | |
| if (cacheData !== void 0) { | |
| chunkIndexesToBacktrackFor.set(chunkToRecheckIndex, { | |
| xorbId: cacheData.xorbIndex, | |
| chunkIndex: cacheData.chunkIndex | |
| }); | |
| chunkCache.removeChunkFromCache(chunk2.hash); | |
| } | |
| } | |
| for (const metadata of chunkMetadata) { | |
| if (metadata.xorbId === xorb.id && chunkIndexesToBacktrackFor.has(metadata.chunkIndex)) { | |
| const backtrackData = chunkIndexesToBacktrackFor.get(metadata.chunkIndex); | |
| if (backtrackData !== void 0) { | |
| metadata.xorbId = backtrackData.xorbId; | |
| metadata.chunkIndex = backtrackData.chunkIndex; | |
| dedupedBytes += metadata.length; | |
| } | |
| } | |
| } | |
| const xorbRangesToErase = []; | |
| for (let i = 0; i < xorb.chunks.length; i++) { | |
| const chunk2 = xorb.chunks[i]; | |
| if (chunkIndexesToBacktrackFor.has(i)) { | |
| xorbRangesToErase.push({ | |
| start: chunk2.offset, | |
| end: i < xorb.chunks.length - 1 ? xorb.chunks[i + 1].offset : xorb.offset | |
| }); | |
| } | |
| } | |
| const xorbRangesToKeep = []; | |
| let currentStart = 0; | |
| for (let i = 0; i < xorbRangesToErase.length; i++) { | |
| const range2 = xorbRangesToErase[i]; | |
| if (currentStart !== range2.start) { | |
| xorbRangesToKeep.push({ start: currentStart, end: range2.start }); | |
| } | |
| currentStart = range2.end; | |
| } | |
| if (currentStart !== xorb.offset) { | |
| xorbRangesToKeep.push({ start: currentStart, end: xorb.offset }); | |
| } | |
| let currentOffset = 0; | |
| for (const range2 of xorbRangesToKeep) { | |
| if (range2.start !== currentOffset) { | |
| xorb.data.set(xorb.data.subarray(range2.start, range2.end), currentOffset); | |
| } | |
| currentOffset += range2.end - range2.start; | |
| } | |
| const newXorbChunks = []; | |
| const oldIndexToNewIndex = /* @__PURE__ */ new Map(); | |
| let erasedOffset = 0; | |
| for (let i = 0; i < xorb.chunks.length; i++) { | |
| const chunk2 = xorb.chunks[i]; | |
| if (chunkIndexesToBacktrackFor.has(i)) { | |
| if (i < xorb.chunks.length - 1) { | |
| erasedOffset += xorb.chunks[i + 1].offset - chunk2.offset; | |
| } | |
| } else { | |
| newXorbChunks.push({ | |
| hash: chunk2.hash, | |
| length: chunk2.length, | |
| offset: chunk2.offset - erasedOffset | |
| }); | |
| if (erasedOffset > 0) { | |
| oldIndexToNewIndex.set(i, newXorbChunks.length - 1); | |
| } | |
| } | |
| } | |
| xorb.chunks = newXorbChunks; | |
| xorb.offset = currentOffset; | |
| for (const chunk2 of chunkMetadata) { | |
| if (chunk2.xorbId === xorb.id) { | |
| const newIndex = oldIndexToNewIndex.get(chunk2.chunkIndex); | |
| if (newIndex !== void 0) { | |
| const cached = chunkCache.getChunk(xorb.chunks[newIndex].hash, null); | |
| if (cached !== void 0 && cached.xorbIndex === chunk2.xorbId && cached.chunkIndex === chunk2.chunkIndex) { | |
| chunkCache.updateChunkIndex(xorb.chunks[newIndex].hash, newIndex); | |
| } | |
| chunk2.chunkIndex = newIndex; | |
| } | |
| } | |
| } | |
| return dedupedBytes; | |
| } | |
| function removeChunkFromSourceData(sourceChunks, chunkLength) { | |
| if (chunkLength === sourceChunks[0].length) { | |
| const chunkToCopy = sourceChunks[0]; | |
| sourceChunks.shift(); | |
| return chunkToCopy; | |
| } else if (chunkLength < sourceChunks[0].length) { | |
| const chunkToCopy = sourceChunks[0].subarray(0, chunkLength); | |
| sourceChunks[0] = sourceChunks[0].subarray(chunkLength); | |
| return chunkToCopy; | |
| } else { | |
| const chunkToCopy = new Uint8Array(chunkLength); | |
| let copyOffset = 0; | |
| let index = 0; | |
| let toSlice = -1; | |
| while (copyOffset < chunkLength) { | |
| const nToCopy = Math.min(sourceChunks[index].length, chunkLength - copyOffset); | |
| chunkToCopy.set(sourceChunks[index].subarray(0, nToCopy), copyOffset); | |
| copyOffset += nToCopy; | |
| if (nToCopy === sourceChunks[index].length) { | |
| index++; | |
| } else { | |
| toSlice = nToCopy; | |
| } | |
| } | |
| sourceChunks.splice(0, index); | |
| if (toSlice !== -1) { | |
| sourceChunks[0] = sourceChunks[0].subarray(toSlice); | |
| } | |
| return chunkToCopy; | |
| } | |
| } | |
| function writeChunk(xorb, chunk2, hash2) { | |
| const regularCompressedChunk = compress(chunk2); | |
| const bgCompressedChunk = compress(bg4_split_bytes(chunk2)); | |
| const compressedChunk = bgCompressedChunk.length < regularCompressedChunk.length ? bgCompressedChunk : regularCompressedChunk; | |
| const chunkToWrite = compressedChunk.length < chunk2.length ? compressedChunk : chunk2; | |
| if (xorb.offset + XET_CHUNK_HEADER_BYTES + chunkToWrite.length > XORB_SIZE) { | |
| return false; | |
| } | |
| xorb.data[xorb.offset] = 0; | |
| xorb.data[xorb.offset + 1] = chunkToWrite.length & 255; | |
| xorb.data[xorb.offset + 2] = chunkToWrite.length >> 8 & 255; | |
| xorb.data[xorb.offset + 3] = chunkToWrite.length >> 16 & 255; | |
| xorb.data[xorb.offset + 4] = chunkToWrite.length < chunk2.length ? bgCompressedChunk.length < regularCompressedChunk.length ? 2 /* ByteGroupingLZ4 */ : 1 /* LZ4 */ : 0 /* None */; | |
| xorb.data[xorb.offset + 5] = chunk2.length & 255; | |
| xorb.data[xorb.offset + 6] = chunk2.length >> 8 & 255; | |
| xorb.data[xorb.offset + 7] = chunk2.length >> 16 & 255; | |
| xorb.data.set(chunkToWrite, xorb.offset + XET_CHUNK_HEADER_BYTES); | |
| xorb.chunks.push({ hash: hash2, length: chunk2.length, offset: xorb.offset }); | |
| xorb.offset += XET_CHUNK_HEADER_BYTES + chunkToWrite.length; | |
| return true; | |
| } | |
| var buildFileRepresentation = (metadata, chunks, computeVerificationHash) => { | |
| if (metadata.length === 0) { | |
| return []; | |
| } | |
| const representation = []; | |
| let currentRange = { | |
| xorbId: metadata[0].xorbId, | |
| indexStart: metadata[0].chunkIndex, | |
| indexEnd: metadata[0].chunkIndex + 1, | |
| length: metadata[0].length, | |
| chunkHashStart: 0 | |
| }; | |
| for (let i = 1; i < metadata.length; i++) { | |
| const chunk2 = metadata[i]; | |
| if (currentRange.xorbId === chunk2.xorbId && currentRange.indexEnd === chunk2.chunkIndex) { | |
| currentRange.indexEnd = chunk2.chunkIndex + 1; | |
| currentRange.length += chunk2.length; | |
| } else { | |
| const rangeHash2 = computeVerificationHash(chunks.slice(currentRange.chunkHashStart, i).map((x) => x.hash)); | |
| representation.push({ | |
| xorbId: currentRange.xorbId, | |
| indexStart: currentRange.indexStart, | |
| indexEnd: currentRange.indexEnd, | |
| length: currentRange.length, | |
| rangeHash: rangeHash2 | |
| }); | |
| currentRange = { | |
| xorbId: chunk2.xorbId, | |
| indexStart: chunk2.chunkIndex, | |
| indexEnd: chunk2.chunkIndex + 1, | |
| length: chunk2.length, | |
| chunkHashStart: i | |
| }; | |
| } | |
| } | |
| const rangeHash = computeVerificationHash(chunks.slice(currentRange.chunkHashStart).map((x) => x.hash)); | |
| representation.push({ | |
| xorbId: currentRange.xorbId, | |
| indexStart: currentRange.indexStart, | |
| indexEnd: currentRange.indexEnd, | |
| length: currentRange.length, | |
| rangeHash | |
| }); | |
| return representation; | |
| }; | |
| async function loadDedupInfoToCache(content, remoteXorbHashes, params, chunkCache, computeHmacHex2, opts) { | |
| const chunker = (0, import_xetchunk_wasm.createChunker)(TARGET_CHUNK_SIZE); | |
| const cache = chunkCache; | |
| let dedupedBytes = 0; | |
| let chunksProcessed = 0; | |
| let totalBytes = 0; | |
| let bytesSinceRemoteDedup = Infinity; | |
| const sourceChunks = []; | |
| const reader = content.stream().getReader(); | |
| const processChunks = async (chunks) => { | |
| for (const chunk2 of chunks) { | |
| chunksProcessed++; | |
| if (opts?.isAtBeginning && chunksProcessed === 1) { | |
| chunk2.dedup = true; | |
| } | |
| totalBytes += chunk2.length; | |
| removeChunkFromSourceData(sourceChunks, chunk2.length); | |
| let cacheData = cache.getChunk(chunk2.hash, computeHmacHex2); | |
| if (cacheData !== void 0) { | |
| dedupedBytes += chunk2.length; | |
| bytesSinceRemoteDedup += chunk2.length; | |
| continue; | |
| } | |
| if (chunk2.dedup && bytesSinceRemoteDedup >= INTERVAL_BETWEEN_REMOTE_DEDUP) { | |
| const token = await xetWriteToken(params); | |
| bytesSinceRemoteDedup = 0; | |
| const shardResp = await (params.fetch ?? fetch)(token.casUrl + "/v1/chunks/default/" + chunk2.hash, { | |
| headers: { | |
| Authorization: `Bearer ${token.accessToken}` | |
| } | |
| }); | |
| if (shardResp.ok) { | |
| const shard = await shardResp.blob(); | |
| const shardData = await parseShardData(shard); | |
| for (const xorb of shardData.xorbs) { | |
| const remoteXorbId = -remoteXorbHashes.length; | |
| remoteXorbHashes.push(xorb.hash); | |
| let i = 0; | |
| for (const xorbChunk of xorb.chunks) { | |
| cache.addChunkToCache(xorbChunk.hash, remoteXorbId, i++, shardData.hmacKey); | |
| } | |
| } | |
| cacheData = cache.getChunk(chunk2.hash, computeHmacHex2); | |
| } | |
| } | |
| if (cacheData !== void 0) { | |
| dedupedBytes += chunk2.length; | |
| } | |
| bytesSinceRemoteDedup += chunk2.length; | |
| } | |
| }; | |
| while (true) { | |
| if (opts?.end !== void 0 && totalBytes >= opts.end) { | |
| break; | |
| } | |
| if (opts?.maxChunks !== void 0 && chunksProcessed >= opts.maxChunks) { | |
| break; | |
| } | |
| const { done, value } = await reader.read(); | |
| if (done) { | |
| await processChunks(finalizeChunker(chunker)); | |
| break; | |
| } | |
| sourceChunks.push(value); | |
| await processChunks(addDataToChunker(value, chunker)); | |
| } | |
| } | |
| // src/utils/uploadShards.ts | |
| var SHARD_MAX_SIZE = 64 * 1024 * 1024; | |
| var SHARD_HEADER_SIZE = 48; | |
| var SHARD_FOOTER_SIZE = 200; | |
| var HASH_LENGTH2 = 32; | |
| var XORB_FOOTER_LENGTH = 48; | |
| var FILE_FOOTER_LENGTH = 48; | |
| var SHARD_HEADER_VERSION = 2n; | |
| var SHARD_FOOTER_VERSION = 1n; | |
| var MDB_FILE_FLAG_WITH_VERIFICATION = 2147483648; | |
| var MDB_FILE_FLAG_WITH_METADATA_EXT = 1073741824; | |
| var SHARD_MAGIC_TAG = new Uint8Array([ | |
| "H".charCodeAt(0), | |
| "F".charCodeAt(0), | |
| "R".charCodeAt(0), | |
| "e".charCodeAt(0), | |
| "p".charCodeAt(0), | |
| "o".charCodeAt(0), | |
| "M".charCodeAt(0), | |
| "e".charCodeAt(0), | |
| "t".charCodeAt(0), | |
| "a".charCodeAt(0), | |
| "D".charCodeAt(0), | |
| "a".charCodeAt(0), | |
| "t".charCodeAt(0), | |
| "a".charCodeAt(0), | |
| 0, | |
| 85, | |
| 105, | |
| 103, | |
| 69, | |
| 106, | |
| 123, | |
| 129, | |
| 87, | |
| 131, | |
| 165, | |
| 189, | |
| 217, | |
| 92, | |
| 205, | |
| 209, | |
| 74, | |
| 169 | |
| ]); | |
| async function* uploadShards(source, params) { | |
| const xorbHashes = []; | |
| const seenFileXetHashes = /* @__PURE__ */ new Set(); | |
| const fileInfoSection = new Uint8Array(Math.floor(SHARD_MAX_SIZE - SHARD_HEADER_SIZE - SHARD_FOOTER_SIZE) * 0.25); | |
| const xorbInfoSection = new Uint8Array(Math.floor(SHARD_MAX_SIZE - SHARD_HEADER_SIZE - SHARD_FOOTER_SIZE) * 0.75); | |
| const xorbView = new DataView(xorbInfoSection.buffer); | |
| let xorbViewOffset = 0; | |
| const fileInfoView = new DataView(fileInfoSection.buffer); | |
| let fileViewOffset = 0; | |
| let xorbTotalSize = 0n; | |
| let fileTotalSize = 0n; | |
| let xorbTotalUnpackedSize = 0n; | |
| for await (const output of createXorbs(source, params)) { | |
| switch (output.event) { | |
| case "xorb": { | |
| xorbHashes.push(output.hash); | |
| const xorbEntrySize = HASH_LENGTH2 + 4 + 4 + 4 + 4; | |
| const chunksSize = output.chunks.length * (HASH_LENGTH2 + 4 + 4 + 8); | |
| const totalXorbSize = xorbEntrySize + chunksSize; | |
| if (xorbViewOffset + totalXorbSize > xorbInfoSection.length) { | |
| if (xorbViewOffset > 0 || fileViewOffset > 0) { | |
| await uploadShard(createShard(), params); | |
| } | |
| } | |
| writeHashToArray(output.hash, xorbInfoSection, xorbViewOffset); | |
| xorbViewOffset += HASH_LENGTH2; | |
| xorbView.setUint32(xorbViewOffset, 0, true); | |
| xorbViewOffset += 4; | |
| xorbView.setUint32(xorbViewOffset, output.chunks.length, true); | |
| xorbViewOffset += 4; | |
| const xorbUnpackedSize = sum(output.chunks.map((x) => x.length)); | |
| xorbView.setUint32(xorbViewOffset, xorbUnpackedSize, true); | |
| xorbTotalUnpackedSize += BigInt(xorbUnpackedSize); | |
| xorbTotalSize += BigInt(output.xorb.byteLength); | |
| xorbViewOffset += 4; | |
| xorbView.setUint32(xorbViewOffset, output.xorb.byteLength, true); | |
| xorbViewOffset += 4; | |
| let chunkBytes = 0; | |
| for (const chunk2 of output.chunks) { | |
| writeHashToArray(chunk2.hash, xorbInfoSection, xorbViewOffset); | |
| xorbViewOffset += HASH_LENGTH2; | |
| xorbView.setUint32(xorbViewOffset, chunkBytes, true); | |
| xorbViewOffset += 4; | |
| xorbView.setUint32(xorbViewOffset, chunk2.length, true); | |
| xorbViewOffset += 4; | |
| xorbView.setBigUint64(xorbViewOffset, 0n, true); | |
| xorbViewOffset += 8; | |
| chunkBytes += chunk2.length; | |
| } | |
| for (const file of output.files) { | |
| yield { | |
| event: "fileProgress", | |
| path: file.path, | |
| progress: file.lastSentProgress | |
| }; | |
| } | |
| await uploadXorb(output, params); | |
| for (const file of output.files) { | |
| yield { event: "fileProgress", path: file.path, progress: file.progress }; | |
| } | |
| break; | |
| } | |
| case "file": { | |
| yield { | |
| event: "file", | |
| path: output.path, | |
| xetHash: output.hash, | |
| sha256: output.sha256, | |
| dedupRatio: output.dedupRatio | |
| }; | |
| if (seenFileXetHashes.has(output.hash)) { | |
| break; | |
| } | |
| seenFileXetHashes.add(output.hash); | |
| const fileHeaderSize = HASH_LENGTH2 + 4 + 4 + 8; | |
| const representationSize = output.representation.length * (HASH_LENGTH2 + 4 + 4 + 4 + 4); | |
| const verificationSize = output.representation.length * (HASH_LENGTH2 + 16); | |
| const fileSha256 = output.sha256; | |
| const hasMetadataExt = fileSha256 !== void 0; | |
| const metadataSize = hasMetadataExt ? HASH_LENGTH2 + 16 : 0; | |
| const totalFileSize = fileHeaderSize + representationSize + verificationSize + metadataSize; | |
| if (fileViewOffset + totalFileSize > fileInfoSection.length) { | |
| if (xorbViewOffset > 0 || fileViewOffset > 0) { | |
| await uploadShard(createShard(), params); | |
| } | |
| } | |
| writeHashToArray(output.hash, fileInfoSection, fileViewOffset); | |
| fileViewOffset += HASH_LENGTH2; | |
| fileInfoView.setUint32( | |
| fileViewOffset, | |
| MDB_FILE_FLAG_WITH_VERIFICATION + (hasMetadataExt ? MDB_FILE_FLAG_WITH_METADATA_EXT : 0), | |
| true | |
| ); | |
| fileViewOffset += 4; | |
| fileInfoView.setUint32(fileViewOffset, output.representation.length, true); | |
| fileViewOffset += 4; | |
| fileInfoView.setBigUint64(fileViewOffset, 0n, true); | |
| fileViewOffset += 8; | |
| for (const repItem of output.representation) { | |
| writeHashToArray( | |
| typeof repItem.xorbId === "number" ? xorbHashes[repItem.xorbId] : repItem.xorbId, | |
| fileInfoSection, | |
| fileViewOffset | |
| ); | |
| fileViewOffset += HASH_LENGTH2; | |
| fileInfoView.setUint32(fileViewOffset, 0, true); | |
| fileViewOffset += 4; | |
| fileInfoView.setUint32(fileViewOffset, repItem.length, true); | |
| fileViewOffset += 4; | |
| fileInfoView.setUint32(fileViewOffset, repItem.indexStart, true); | |
| fileViewOffset += 4; | |
| fileInfoView.setUint32(fileViewOffset, repItem.indexEnd, true); | |
| fileViewOffset += 4; | |
| } | |
| for (const repItem of output.representation) { | |
| writeHashToArray(repItem.rangeHash, fileInfoSection, fileViewOffset); | |
| fileViewOffset += HASH_LENGTH2; | |
| for (let i = 0; i < 16; i++) { | |
| fileInfoSection[fileViewOffset + i] = 0; | |
| } | |
| fileViewOffset += 16; | |
| } | |
| if (hasMetadataExt) { | |
| writeHashToArray(fileSha256, fileInfoSection, fileViewOffset); | |
| fileViewOffset += HASH_LENGTH2; | |
| for (let i = 0; i < 16; i++) { | |
| fileInfoSection[fileViewOffset + i] = 0; | |
| } | |
| fileViewOffset += 16; | |
| } | |
| break; | |
| } | |
| } | |
| } | |
| function createShard() { | |
| const shard = new Uint8Array( | |
| SHARD_HEADER_SIZE + SHARD_FOOTER_SIZE + xorbViewOffset + XORB_FOOTER_LENGTH + fileViewOffset + FILE_FOOTER_LENGTH | |
| ); | |
| const shardView = new DataView(shard.buffer); | |
| let shardOffset = 0; | |
| shard.set(SHARD_MAGIC_TAG, shardOffset); | |
| shardOffset += SHARD_MAGIC_TAG.length; | |
| shardView.setBigUint64(shardOffset, SHARD_HEADER_VERSION, true); | |
| shardOffset += 8; | |
| shardView.setBigUint64(shardOffset, BigInt(SHARD_FOOTER_SIZE), true); | |
| shardOffset += 8; | |
| shard.set(fileInfoSection.slice(0, fileViewOffset), shardOffset); | |
| shardOffset += fileViewOffset; | |
| for (let i = 0; i < 32; i++) { | |
| shard[shardOffset + i] = 255; | |
| } | |
| shardOffset += 32; | |
| for (let i = 0; i < 16; i++) { | |
| shard[shardOffset + i] = 0; | |
| } | |
| shardOffset += 16; | |
| const xorbInfoOffset = shardOffset; | |
| shard.set(xorbInfoSection.slice(0, xorbViewOffset), shardOffset); | |
| shardOffset += xorbViewOffset; | |
| for (let i = 0; i < 32; i++) { | |
| shard[shardOffset + i] = 255; | |
| } | |
| shardOffset += 32; | |
| for (let i = 0; i < 16; i++) { | |
| shard[shardOffset + i] = 0; | |
| } | |
| shardOffset += 16; | |
| const footerOffset = shardOffset; | |
| shardView.setBigUint64(shardOffset, SHARD_FOOTER_VERSION, true); | |
| shardOffset += 8; | |
| shardView.setBigUint64(shardOffset, BigInt(SHARD_HEADER_SIZE), true); | |
| shardOffset += 8; | |
| shardView.setBigUint64(shardOffset, BigInt(xorbInfoOffset), true); | |
| shardOffset += 8; | |
| for (let i = 0; i < 48; i++) { | |
| shardView.setUint8(shardOffset + i, 0); | |
| } | |
| shardOffset += 48; | |
| for (let i = 0; i < 32; i++) { | |
| shardView.setUint8(shardOffset + i, 0); | |
| } | |
| shardOffset += 32; | |
| shardView.setBigUint64(shardOffset, BigInt(Math.floor(Date.now() / 1e3)), true); | |
| shardOffset += 8; | |
| shardView.setBigUint64(shardOffset, 0n, true); | |
| shardOffset += 8; | |
| for (let i = 0; i < 48; i++) { | |
| shardView.setUint8(shardOffset + i, 0); | |
| } | |
| shardOffset += 48; | |
| shardView.setBigUint64(shardOffset, xorbTotalSize, true); | |
| shardOffset += 8; | |
| shardView.setBigUint64(shardOffset, fileTotalSize, true); | |
| shardOffset += 8; | |
| shardView.setBigUint64(shardOffset, xorbTotalUnpackedSize, true); | |
| shardOffset += 8; | |
| shardView.setBigUint64(shardOffset, BigInt(footerOffset), true); | |
| xorbViewOffset = 0; | |
| fileViewOffset = 0; | |
| xorbTotalSize = 0n; | |
| xorbTotalUnpackedSize = 0n; | |
| fileTotalSize = 0n; | |
| return shard; | |
| } | |
| if (xorbViewOffset || fileViewOffset) { | |
| await uploadShard(createShard(), params); | |
| } | |
| } | |
| function writeHashToArray(hash2, array, offset) { | |
| for (let i = 0; i < hash2.length; i += 16) { | |
| array[offset + i / 2] = parseInt(hash2.substring(i + 2 * 7, i + 2 * 8), 16); | |
| array[offset + i / 2 + 1] = parseInt(hash2.substring(i + 2 * 6, i + 2 * 7), 16); | |
| array[offset + i / 2 + 2] = parseInt(hash2.substring(i + 2 * 5, i + 2 * 6), 16); | |
| array[offset + i / 2 + 3] = parseInt(hash2.substring(i + 2 * 4, i + 2 * 5), 16); | |
| array[offset + i / 2 + 4] = parseInt(hash2.substring(i + 2 * 3, i + 2 * 4), 16); | |
| array[offset + i / 2 + 5] = parseInt(hash2.substring(i + 2 * 2, i + 2 * 3), 16); | |
| array[offset + i / 2 + 6] = parseInt(hash2.substring(i + 2 * 1, i + 2 * 2), 16); | |
| array[offset + i / 2 + 7] = parseInt(hash2.substring(i + 2 * 0, i + 2 * 1), 16); | |
| } | |
| } | |
| async function uploadXorb(xorb, params) { | |
| const token = await xetWriteToken(params); | |
| const resp = await (params.fetch ?? fetch)(`${token.casUrl}/v1/xorbs/default/${xorb.hash}`, { | |
| method: "POST", | |
| body: xorb.xorb, | |
| headers: { | |
| Authorization: `Bearer ${token.accessToken}`, | |
| ...params.xetParams.sessionId ? { "X-Xet-Session-Id": params.xetParams.sessionId } : {} | |
| }, | |
| ...{ | |
| progressHint: { | |
| progressCallback: (progress) => { | |
| for (const file of xorb.files) { | |
| params.yieldCallback?.({ | |
| event: "fileProgress", | |
| path: file.path, | |
| progress: file.lastSentProgress + (file.progress - file.lastSentProgress) * progress | |
| }); | |
| } | |
| } | |
| } | |
| } | |
| }); | |
| if (!resp.ok) { | |
| throw await createApiError(resp); | |
| } | |
| } | |
| async function uploadShard(shard, params) { | |
| const token = await xetWriteToken(params); | |
| const resp = await (params.fetch ?? fetch)(`${token.casUrl}/v1/shards`, { | |
| method: "POST", | |
| body: shard, | |
| headers: { | |
| Authorization: `Bearer ${token.accessToken}`, | |
| ...params.xetParams.sessionId ? { "X-Xet-Session-Id": params.xetParams.sessionId } : {} | |
| } | |
| }); | |
| if (!resp.ok) { | |
| throw await createApiError(resp); | |
| } | |
| } | |
| // src/utils/splitAsyncGenerator.ts | |
| function splitAsyncGenerator(source, n) { | |
| if (n <= 0) { | |
| return []; | |
| } | |
| const sleep = (ms) => new Promise((resolve3) => setTimeout(resolve3, ms)); | |
| let takenIndex = null; | |
| const generators = []; | |
| let remaining = n; | |
| for (let i = 0; i < n; i++) { | |
| generators.push({ | |
| next: async () => { | |
| while (takenIndex !== null) { | |
| await sleep(1); | |
| } | |
| takenIndex = i; | |
| return source.next().then((r) => { | |
| takenIndex = null; | |
| return r; | |
| }); | |
| }, | |
| return: async () => { | |
| remaining--; | |
| if (remaining === 0) { | |
| return source.return(void 0); | |
| } | |
| return { | |
| done: true, | |
| value: void 0 | |
| }; | |
| }, | |
| throw: async (error) => { | |
| return source.throw(error); | |
| }, | |
| [Symbol.asyncIterator]: () => generators[i] | |
| }); | |
| } | |
| return generators; | |
| } | |
| // src/lib/commit.ts | |
| var CONCURRENT_SHAS = 5; | |
| var CONCURRENT_LFS_UPLOADS = 5; | |
| var MULTIPART_PARALLEL_UPLOAD = 5; | |
| function isFileOperation(op) { | |
| const ret = op.operation === "addOrUpdate"; | |
| if (ret && !(op.content instanceof Blob)) { | |
| throw new TypeError("Precondition failed: op.content should be a Blob"); | |
| } | |
| return ret; | |
| } | |
| async function* commitIter(params) { | |
| const accessToken = checkCredentials(params); | |
| const repoId = toRepoId(params.repo); | |
| if (repoId.type === "bucket") { | |
| return yield* commitIterBucket(params); | |
| } | |
| if (params.operations.some((op) => op.operation === "copy")) { | |
| throw new Error("'copy' operations are only supported when the destination repo is a bucket"); | |
| } | |
| yield { event: "phase", phase: "preuploading" }; | |
| let useXet = params.useXet ?? true; | |
| const lfsShas = /* @__PURE__ */ new Map(); | |
| const abortController = new AbortController(); | |
| const abortSignal = abortController.signal; | |
| if (!abortSignal.throwIfAborted) { | |
| abortSignal.throwIfAborted = () => { | |
| if (abortSignal.aborted) { | |
| throw new DOMException("Aborted", "AbortError"); | |
| } | |
| }; | |
| } | |
| if (params.abortSignal) { | |
| params.abortSignal.addEventListener("abort", () => abortController.abort()); | |
| } | |
| try { | |
| const allOperations = (await Promise.all( | |
| params.operations.map(async (operation) => { | |
| if (operation.operation === "edit") { | |
| const splicedBlob = SplicedBlob.create( | |
| operation.originalContent, | |
| operation.edits.map((splice) => ({ insert: splice.content, start: splice.start, end: splice.end })) | |
| ); | |
| return { | |
| operation: "addOrUpdate", | |
| path: operation.path, | |
| content: splicedBlob | |
| }; | |
| } | |
| if (operation.operation !== "addOrUpdate") { | |
| return operation; | |
| } | |
| if (!(operation.content instanceof URL)) { | |
| return { ...operation, content: operation.content }; | |
| } | |
| const lazyBlobs = await createBlobs(operation.content, operation.path, { | |
| fetch: params.fetch, | |
| maxFolderDepth: params.maxFolderDepth | |
| }); | |
| abortSignal?.throwIfAborted(); | |
| return lazyBlobs.map((blob) => ({ | |
| ...operation, | |
| content: blob.blob, | |
| path: blob.path | |
| })); | |
| }) | |
| )).flat(1); | |
| const gitAttributes = allOperations.filter(isFileOperation).find((op) => op.path === ".gitattributes")?.content; | |
| for (const operations of chunk(allOperations.filter(isFileOperation), 100)) { | |
| const payload = { | |
| gitAttributes: gitAttributes && await gitAttributes.text(), | |
| files: await Promise.all( | |
| operations.map(async (operation) => ({ | |
| path: operation.path, | |
| size: operation.content.size, | |
| sample: base64FromBytes(new Uint8Array(await operation.content.slice(0, 512).arrayBuffer())) | |
| })) | |
| ) | |
| }; | |
| abortSignal?.throwIfAborted(); | |
| const res = await (params.fetch ?? fetch)( | |
| `${params.hubUrl ?? HUB_URL}/api/${repoId.type}s/${repoId.name}/preupload/${encodeURIComponent( | |
| params.branch ?? "main" | |
| )}` + (params.isPullRequest ? "?create_pr=1" : ""), | |
| { | |
| method: "POST", | |
| headers: { | |
| ...accessToken && { Authorization: `Bearer ${accessToken}` }, | |
| "Content-Type": "application/json" | |
| }, | |
| body: JSON.stringify(payload), | |
| signal: abortSignal | |
| } | |
| ); | |
| if (!res.ok) { | |
| throw await createApiError(res); | |
| } | |
| const json = await res.json(); | |
| for (const file of json.files) { | |
| if (file.uploadMode === "lfs") { | |
| lfsShas.set(file.path, null); | |
| } | |
| } | |
| } | |
| yield { event: "phase", phase: "uploadingLargeFiles" }; | |
| for (const operations of chunk( | |
| allOperations.filter(isFileOperation).filter((op) => lfsShas.has(op.path)), | |
| 100 | |
| )) { | |
| const shas = yield* eventToGenerator((yieldCallback, returnCallback, rejectCallack) => { | |
| return promisesQueue( | |
| operations.map((op) => async () => { | |
| const iterator = sha256(op.content, { useWebWorker: params.useWebWorkers, abortSignal }); | |
| let res2; | |
| do { | |
| res2 = await iterator.next(); | |
| if (!res2.done) { | |
| yieldCallback({ event: "fileProgress", path: op.path, progress: res2.value, state: "hashing" }); | |
| } | |
| } while (!res2.done); | |
| const sha = res2.value; | |
| lfsShas.set(op.path, res2.value); | |
| return sha; | |
| }), | |
| CONCURRENT_SHAS | |
| ).then(returnCallback, rejectCallack); | |
| }); | |
| abortSignal?.throwIfAborted(); | |
| const payload = { | |
| operation: "upload", | |
| // multipart is a custom protocol for HF | |
| transfers: ["basic", "multipart", ...useXet ? ["xet"] : []], | |
| hash_algo: "sha_256", | |
| ...!params.isPullRequest && { | |
| ref: { | |
| name: params.branch ?? "main" | |
| } | |
| }, | |
| objects: operations.map((op, i) => ({ | |
| oid: shas[i], | |
| size: op.content.size | |
| })) | |
| }; | |
| const res = await (params.fetch ?? fetch)( | |
| `${params.hubUrl ?? HUB_URL}/${repoId.type === "model" ? "" : repoId.type + "s/"}${repoId.name}.git/info/lfs/objects/batch`, | |
| { | |
| method: "POST", | |
| headers: { | |
| ...accessToken && { Authorization: `Bearer ${accessToken}` }, | |
| Accept: "application/vnd.git-lfs+json", | |
| "Content-Type": "application/vnd.git-lfs+json" | |
| }, | |
| body: JSON.stringify(payload), | |
| signal: abortSignal | |
| } | |
| ); | |
| if (!res.ok) { | |
| throw await createApiError(res); | |
| } | |
| const json = await res.json(); | |
| const batchRequestId = res.headers.get("X-Request-Id") || void 0; | |
| const shaToOperation = new Map(operations.map((op, i) => [shas[i], op])); | |
| if (useXet && json.transfer !== "xet") { | |
| useXet = false; | |
| } | |
| let xetParams = null; | |
| if (useXet) { | |
| for (const obj of json.objects) { | |
| const op = shaToOperation.get(obj.oid); | |
| if (!op) { | |
| throw new InvalidApiResponseFormatError("Unrequested object ID in response"); | |
| } | |
| if (obj.error) { | |
| const errorMessage = `Error while doing LFS batch call for ${operations[shas.indexOf(obj.oid)].path}: ${obj.error.message}${batchRequestId ? ` - Request ID: ${batchRequestId}` : ""}`; | |
| throw new HubApiError(res.url, obj.error.code, batchRequestId, errorMessage); | |
| } | |
| if (!obj.actions?.upload) { | |
| yield { | |
| event: "fileProgress", | |
| path: op.path, | |
| progress: 1, | |
| state: "uploading" | |
| }; | |
| } else { | |
| const headers = new Headers(obj.actions.upload.header); | |
| xetParams = { | |
| sessionId: headers.get("X-Xet-Session-Id") ?? void 0, | |
| casUrl: headers.get("X-Xet-Cas-Url") ?? void 0, | |
| accessToken: headers.get("X-Xet-Access-Token") ?? void 0, | |
| expiresAt: headers.get("X-Xet-Token-Expiration") ? new Date(parseInt(headers.get("X-Xet-Token-Expiration") ?? "0") * 1e3) : void 0, | |
| refreshWriteTokenUrl: obj.actions.upload.href | |
| }; | |
| } | |
| } | |
| const source = async function* () { | |
| for (const obj of json.objects) { | |
| const op = shaToOperation.get(obj.oid); | |
| if (!op || !obj.actions?.upload) { | |
| continue; | |
| } | |
| abortSignal?.throwIfAborted(); | |
| yield { content: op.content, path: op.path, sha256: obj.oid }; | |
| } | |
| }(); | |
| if (xetParams) { | |
| const fixedXetParams = xetParams; | |
| const sources = splitAsyncGenerator(source, 5); | |
| yield* eventToGenerator( | |
| (yieldCallback, returnCallback, rejectCallback) => Promise.all( | |
| sources.map(async function(source2) { | |
| for await (const event of uploadShards(source2, { | |
| fetch: params.fetch, | |
| accessToken, | |
| hubUrl: params.hubUrl ?? HUB_URL, | |
| repo: repoId, | |
| xetParams: fixedXetParams, | |
| // todo: maybe leave empty if PR? | |
| rev: params.branch ?? "main", | |
| isPullRequest: params.isPullRequest, | |
| yieldCallback: (event2) => yieldCallback({ ...event2, state: "uploading" }) | |
| })) { | |
| if (event.event === "file") { | |
| yieldCallback({ | |
| event: "fileProgress", | |
| path: event.path, | |
| progress: 1, | |
| state: "uploading" | |
| }); | |
| } else if (event.event === "fileProgress") { | |
| yieldCallback({ | |
| event: "fileProgress", | |
| path: event.path, | |
| progress: event.progress, | |
| state: "uploading" | |
| }); | |
| } | |
| } | |
| }) | |
| ).then(() => returnCallback(void 0), rejectCallback) | |
| ); | |
| } else { | |
| } | |
| } else { | |
| yield* eventToGenerator((yieldCallback, returnCallback, rejectCallback) => { | |
| return promisesQueueStreaming( | |
| json.objects.map((obj) => async () => { | |
| const op = shaToOperation.get(obj.oid); | |
| if (!op) { | |
| throw new InvalidApiResponseFormatError("Unrequested object ID in response"); | |
| } | |
| abortSignal?.throwIfAborted(); | |
| if (obj.error) { | |
| const errorMessage = `Error while doing LFS batch call for ${operations[shas.indexOf(obj.oid)].path}: ${obj.error.message}${batchRequestId ? ` - Request ID: ${batchRequestId}` : ""}`; | |
| throw new HubApiError(res.url, obj.error.code, batchRequestId, errorMessage); | |
| } | |
| if (!obj.actions?.upload) { | |
| yieldCallback({ | |
| event: "fileProgress", | |
| path: op.path, | |
| progress: 1, | |
| state: "uploading" | |
| }); | |
| return; | |
| } | |
| yieldCallback({ | |
| event: "fileProgress", | |
| path: op.path, | |
| progress: 0, | |
| state: "uploading" | |
| }); | |
| const content = op.content; | |
| const header = obj.actions.upload.header; | |
| if (header?.chunk_size) { | |
| const chunkSize = parseInt(header.chunk_size); | |
| const completionUrl = obj.actions.upload.href; | |
| const parts = Object.keys(header).filter((key) => /^[0-9]+$/.test(key)); | |
| if (parts.length !== Math.ceil(content.size / chunkSize)) { | |
| throw new Error("Invalid server response to upload large LFS file, wrong number of parts"); | |
| } | |
| const completeReq = { | |
| oid: obj.oid, | |
| parts: parts.map((part) => ({ | |
| partNumber: +part, | |
| etag: "" | |
| })) | |
| }; | |
| const progressCallback = (progress) => yieldCallback({ event: "fileProgress", path: op.path, progress, state: "uploading" }); | |
| await promisesQueueStreaming( | |
| parts.map((part) => async () => { | |
| abortSignal?.throwIfAborted(); | |
| const index = parseInt(part) - 1; | |
| const slice = content.slice(index * chunkSize, (index + 1) * chunkSize); | |
| const res3 = await (params.fetch ?? fetch)(header[part], { | |
| method: "PUT", | |
| /** Unfortunately, browsers don't support our inherited version of Blob in fetch calls */ | |
| body: slice instanceof WebBlob && isFrontend ? await slice.arrayBuffer() : slice, | |
| signal: abortSignal, | |
| ...{ | |
| progressHint: { | |
| path: op.path, | |
| part: index, | |
| numParts: parts.length, | |
| progressCallback | |
| } | |
| // eslint-disable-next-line @typescript-eslint/no-explicit-any | |
| } | |
| }); | |
| if (!res3.ok) { | |
| throw await createApiError(res3, { | |
| requestId: batchRequestId, | |
| message: `Error while uploading part ${part} of ${operations[shas.indexOf(obj.oid)].path} to LFS storage` | |
| }); | |
| } | |
| const eTag = res3.headers.get("ETag"); | |
| if (!eTag) { | |
| throw new Error("Cannot get ETag of part during multipart upload"); | |
| } | |
| completeReq.parts[Number(part) - 1].etag = eTag; | |
| }), | |
| MULTIPART_PARALLEL_UPLOAD | |
| ); | |
| abortSignal?.throwIfAborted(); | |
| const res2 = await (params.fetch ?? fetch)(completionUrl, { | |
| method: "POST", | |
| body: JSON.stringify(completeReq), | |
| headers: { | |
| Accept: "application/vnd.git-lfs+json", | |
| "Content-Type": "application/vnd.git-lfs+json" | |
| }, | |
| signal: abortSignal | |
| }); | |
| if (!res2.ok) { | |
| throw await createApiError(res2, { | |
| requestId: batchRequestId, | |
| message: `Error completing multipart upload of ${operations[shas.indexOf(obj.oid)].path} to LFS storage` | |
| }); | |
| } | |
| yieldCallback({ | |
| event: "fileProgress", | |
| path: op.path, | |
| progress: 1, | |
| state: "uploading" | |
| }); | |
| } else { | |
| const res2 = await (params.fetch ?? fetch)(obj.actions.upload.href, { | |
| method: "PUT", | |
| headers: { | |
| ...batchRequestId ? { "X-Request-Id": batchRequestId } : void 0 | |
| }, | |
| /** Unfortunately, browsers don't support our inherited version of Blob in fetch calls */ | |
| body: content instanceof WebBlob && isFrontend ? await content.arrayBuffer() : content, | |
| signal: abortSignal, | |
| ...{ | |
| progressHint: { | |
| path: op.path, | |
| progressCallback: (progress) => yieldCallback({ | |
| event: "fileProgress", | |
| path: op.path, | |
| progress, | |
| state: "uploading" | |
| }) | |
| } | |
| // eslint-disable-next-line @typescript-eslint/no-explicit-any | |
| } | |
| }); | |
| if (!res2.ok) { | |
| throw await createApiError(res2, { | |
| requestId: batchRequestId, | |
| message: `Error while uploading ${operations[shas.indexOf(obj.oid)].path} to LFS storage` | |
| }); | |
| } | |
| yieldCallback({ | |
| event: "fileProgress", | |
| path: op.path, | |
| progress: 1, | |
| state: "uploading" | |
| }); | |
| } | |
| }), | |
| CONCURRENT_LFS_UPLOADS | |
| ).then(returnCallback, rejectCallback); | |
| }); | |
| } | |
| } | |
| abortSignal?.throwIfAborted(); | |
| yield { event: "phase", phase: "committing" }; | |
| return yield* eventToGenerator( | |
| async (yieldCallback, returnCallback, rejectCallback) => (params.fetch ?? fetch)( | |
| `${params.hubUrl ?? HUB_URL}/api/${repoId.type}s/${repoId.name}/commit/${encodeURIComponent( | |
| params.branch ?? "main" | |
| )}` + (params.isPullRequest ? "?create_pr=1" : ""), | |
| { | |
| method: "POST", | |
| headers: { | |
| ...accessToken && { Authorization: `Bearer ${accessToken}` }, | |
| "Content-Type": "application/x-ndjson" | |
| }, | |
| body: [ | |
| { | |
| key: "header", | |
| value: { | |
| summary: params.title, | |
| description: params.description, | |
| parentCommit: params.parentCommit | |
| } | |
| }, | |
| ...await Promise.all( | |
| allOperations.map((operation) => { | |
| if (isFileOperation(operation)) { | |
| const sha = lfsShas.get(operation.path); | |
| if (sha) { | |
| return { | |
| key: "lfsFile", | |
| value: { | |
| path: operation.path, | |
| algo: "sha256", | |
| size: operation.content.size, | |
| oid: sha | |
| } | |
| }; | |
| } | |
| } | |
| return convertOperationToNdJson(operation); | |
| }) | |
| ) | |
| ].map((x) => JSON.stringify(x)).join("\n"), | |
| signal: abortSignal, | |
| ...{ | |
| progressHint: { | |
| progressCallback: (progress) => { | |
| for (const op of allOperations) { | |
| if (isFileOperation(op) && !lfsShas.has(op.path)) { | |
| yieldCallback({ | |
| event: "fileProgress", | |
| path: op.path, | |
| progress, | |
| state: "uploading" | |
| }); | |
| } | |
| } | |
| } | |
| } | |
| // eslint-disable-next-line @typescript-eslint/no-explicit-any | |
| } | |
| } | |
| ).then(async (res) => { | |
| if (!res.ok) { | |
| throw await createApiError(res); | |
| } | |
| const json = await res.json(); | |
| returnCallback({ | |
| pullRequestUrl: json.pullRequestUrl, | |
| commit: { | |
| oid: json.commitOid, | |
| url: json.commitUrl | |
| }, | |
| hookOutput: json.hookOutput | |
| }); | |
| }).catch(rejectCallback) | |
| ); | |
| } catch (err) { | |
| abortController.abort(); | |
| throw err; | |
| } | |
| } | |
| async function* commitIterBucket(params) { | |
| const accessToken = checkCredentials(params); | |
| const repoId = toRepoId(params.repo); | |
| if (params.useXet === false) { | |
| throw new Error("useXet must be true or undefined for buckets"); | |
| } | |
| const abortController = new AbortController(); | |
| const abortSignal = abortController.signal; | |
| if (!abortSignal.throwIfAborted) { | |
| abortSignal.throwIfAborted = () => { | |
| if (abortSignal.aborted) { | |
| throw new DOMException("Aborted", "AbortError"); | |
| } | |
| }; | |
| } | |
| if (params.abortSignal) { | |
| params.abortSignal.addEventListener("abort", () => abortController.abort()); | |
| } | |
| try { | |
| const allOperations = (await Promise.all( | |
| params.operations.map(async (operation) => { | |
| if (operation.operation === "edit") { | |
| const splicedBlob = SplicedBlob.create( | |
| operation.originalContent, | |
| operation.edits.map((splice) => ({ insert: splice.content, start: splice.start, end: splice.end })) | |
| ); | |
| return { | |
| operation: "addOrUpdate", | |
| path: operation.path, | |
| content: splicedBlob | |
| }; | |
| } | |
| if (operation.operation !== "addOrUpdate") { | |
| return operation; | |
| } | |
| if (!(operation.content instanceof URL)) { | |
| return { ...operation, content: operation.content }; | |
| } | |
| const lazyBlobs = await createBlobs(operation.content, operation.path, { | |
| fetch: params.fetch, | |
| maxFolderDepth: params.maxFolderDepth | |
| }); | |
| abortSignal?.throwIfAborted(); | |
| return lazyBlobs.map((blob) => ({ | |
| ...operation, | |
| content: blob.blob, | |
| path: blob.path | |
| })); | |
| }) | |
| )).flat(1); | |
| yield { event: "phase", phase: "uploadingLargeFiles" }; | |
| for (const operations of chunk(allOperations.filter(isFileOperation), 100)) { | |
| const xetHashes = /* @__PURE__ */ new Map(); | |
| abortSignal?.throwIfAborted(); | |
| const source = async function* () { | |
| for (const operation of operations) { | |
| abortSignal?.throwIfAborted(); | |
| yield { content: operation.content, path: operation.path }; | |
| } | |
| }(); | |
| const xetParams = { | |
| sessionId: crypto.randomUUID(), | |
| refreshWriteTokenUrl: `${params.hubUrl ?? HUB_URL}/api/${repoId.type}s/${repoId.name}/xet-write-token` | |
| }; | |
| const sources = splitAsyncGenerator(source, 5); | |
| yield* eventToGenerator( | |
| (yieldCallback, returnCallback, rejectCallback) => Promise.all( | |
| sources.map(async function(source2) { | |
| for await (const event of uploadShards(source2, { | |
| fetch: params.fetch, | |
| accessToken, | |
| hubUrl: params.hubUrl ?? HUB_URL, | |
| repo: repoId, | |
| xetParams, | |
| rev: params.branch ?? "main", | |
| yieldCallback: (event2) => yieldCallback({ ...event2, state: "uploading" }) | |
| })) { | |
| if (event.event === "file") { | |
| yieldCallback({ | |
| event: "fileProgress", | |
| path: event.path, | |
| progress: 1, | |
| state: "uploading" | |
| }); | |
| xetHashes.set(event.path, event.xetHash); | |
| } else if (event.event === "fileProgress") { | |
| yieldCallback({ | |
| event: "fileProgress", | |
| path: event.path, | |
| progress: event.progress, | |
| state: "uploading" | |
| }); | |
| } | |
| } | |
| }) | |
| ).then(() => returnCallback(void 0), rejectCallback) | |
| ); | |
| const resp = await (params.fetch ?? fetch)( | |
| `${params.hubUrl ?? HUB_URL}/api/${repoId.type}s/${repoId.name}/batch`, | |
| { | |
| method: "POST", | |
| headers: { | |
| ...accessToken && { Authorization: `Bearer ${accessToken}` }, | |
| "Content-Type": "application/x-ndjson" | |
| }, | |
| body: [...xetHashes.entries()].map( | |
| ([path2, xetHash]) => JSON.stringify({ | |
| type: "addFile", | |
| path: path2, | |
| xetHash | |
| }) | |
| ).join("\n"), | |
| signal: abortSignal | |
| } | |
| ); | |
| if (!resp.ok && resp.status !== 422) { | |
| throw await createApiError(resp); | |
| } | |
| const json = await resp.json(); | |
| for (const failed of json.failed) { | |
| yield { | |
| event: "fileProgress", | |
| path: failed.path, | |
| progress: 0, | |
| state: "error" | |
| }; | |
| } | |
| } | |
| abortSignal?.throwIfAborted(); | |
| const copyOperations = allOperations.filter( | |
| (operation) => operation.operation === "copy" | |
| ); | |
| for (const copyChunk of chunk(copyOperations, 100)) { | |
| abortSignal?.throwIfAborted(); | |
| const resp = await (params.fetch ?? fetch)( | |
| `${params.hubUrl ?? HUB_URL}/api/${repoId.type}s/${repoId.name}/batch`, | |
| { | |
| method: "POST", | |
| headers: { | |
| ...accessToken && { Authorization: `Bearer ${accessToken}` }, | |
| "Content-Type": "application/x-ndjson" | |
| }, | |
| body: copyChunk.map((op) => { | |
| const sourceRepoId = toRepoId(op.sourceRepo); | |
| return JSON.stringify({ | |
| type: "copyFile", | |
| path: op.path, | |
| xetHash: op.sourceXetHash, | |
| sourceRepoType: sourceRepoId.type, | |
| sourceRepoId: sourceRepoId.name | |
| }); | |
| }).join("\n"), | |
| signal: abortSignal | |
| } | |
| ); | |
| if (!resp.ok && resp.status !== 422) { | |
| throw await createApiError(resp); | |
| } | |
| const json = await resp.json(); | |
| for (const failed of json.failed) { | |
| yield { | |
| event: "fileProgress", | |
| path: failed.path, | |
| progress: 0, | |
| state: "error" | |
| }; | |
| } | |
| } | |
| abortSignal?.throwIfAborted(); | |
| const deletedOperations = allOperations.filter((operation) => operation.operation === "delete"); | |
| if (deletedOperations.length > 0) { | |
| const resp = await (params.fetch ?? fetch)( | |
| `${params.hubUrl ?? HUB_URL}/api/${repoId.type}s/${repoId.name}/batch`, | |
| { | |
| method: "POST", | |
| headers: { | |
| ...accessToken && { Authorization: `Bearer ${accessToken}` }, | |
| "Content-Type": "application/x-ndjson" | |
| }, | |
| body: deletedOperations.map( | |
| (operation) => JSON.stringify({ | |
| type: "deleteFile", | |
| path: operation.path | |
| }) | |
| ).join("\n"), | |
| signal: abortSignal | |
| } | |
| ); | |
| if (!resp.ok) { | |
| throw await createApiError(resp); | |
| } | |
| const json = await resp.json(); | |
| if (json.failed.length > 0) { | |
| const failedPaths = json.failed.slice(0, 5).map((f) => f.path); | |
| throw new Error( | |
| `Failed to delete ${json.failed.length} file(s): ${failedPaths.join(", ")}${json.failed.length > 5 ? "..." : ""}, request ID: ${resp.headers.get("X-Request-Id")}` | |
| ); | |
| } | |
| } | |
| abortSignal?.throwIfAborted(); | |
| } catch (err) { | |
| abortController.abort(); | |
| throw err; | |
| } | |
| } | |
| async function convertOperationToNdJson(operation) { | |
| switch (operation.operation) { | |
| case "addOrUpdate": { | |
| return { | |
| key: "file", | |
| value: { | |
| content: base64FromBytes(new Uint8Array(await operation.content.arrayBuffer())), | |
| path: operation.path, | |
| encoding: "base64" | |
| } | |
| }; | |
| } | |
| case "delete": { | |
| return { | |
| key: "deletedFile", | |
| value: { | |
| path: operation.path | |
| } | |
| }; | |
| } | |
| case "edit": { | |
| throw new Error( | |
| "Edit operations should be converted to addOrUpdate operations before reaching convertOperationToNdJson" | |
| ); | |
| } | |
| default: | |
| throw new TypeError("Unknown operation: " + operation.operation); | |
| } | |
| } | |
| // src/utils/parseLinkHeader.ts | |
| function parseLinkHeader(header) { | |
| const regex = /<(https?:[/][/][^>]+)>;\s+rel="([^"]+)"/g; | |
| return Object.fromEntries([...header.matchAll(regex)].map(([, url, rel]) => [rel, url])); | |
| } | |
| // src/lib/create-repo.ts | |
| async function createRepo(params) { | |
| const accessToken = checkCredentials(params); | |
| const repoId = toRepoId(params.repo); | |
| const [namespace, repoName] = repoId.name.split("/"); | |
| const visibility = params.visibility ?? (params.private !== void 0 ? params.private ? "private" : "public" : void 0); | |
| if (!namespace || !repoName) { | |
| throw new TypeError( | |
| `"${repoId.name}" is not a fully qualified repo name. It should be of the form "{namespace}/{repoName}".` | |
| ); | |
| } | |
| const res = repoId.type === "bucket" ? await (params.fetch ?? fetch)(`${params.hubUrl ?? HUB_URL}/api/buckets/${namespace}/${repoName}`, { | |
| method: "POST", | |
| body: JSON.stringify({ | |
| visibility, | |
| resourceGroupId: params.resourceGroupId | |
| }), | |
| headers: { | |
| Authorization: `Bearer ${accessToken}`, | |
| "Content-Type": "application/json" | |
| } | |
| }) : await (params.fetch ?? fetch)(`${params.hubUrl ?? HUB_URL}/api/repos/create`, { | |
| method: "POST", | |
| body: JSON.stringify({ | |
| name: repoName, | |
| visibility, | |
| organization: namespace, | |
| resourceGroupId: params.resourceGroupId, | |
| license: params.license, | |
| ...repoId.type === "space" ? { | |
| type: "space", | |
| sdk: params.sdk ?? "static" | |
| } : { | |
| type: repoId.type | |
| }, | |
| files: params.files ? await Promise.all( | |
| params.files.map(async (file) => ({ | |
| encoding: "base64", | |
| path: file.path, | |
| content: base64FromBytes( | |
| new Uint8Array(file.content instanceof Blob ? await file.content.arrayBuffer() : file.content) | |
| ) | |
| })) | |
| ) : void 0 | |
| }), | |
| headers: { | |
| Authorization: `Bearer ${accessToken}`, | |
| "Content-Type": "application/json" | |
| } | |
| }); | |
| if (!res.ok) { | |
| throw await createApiError(res); | |
| } | |
| const output = await res.json(); | |
| return { repoUrl: output.url, id: output.id }; | |
| } | |
| // src/lib/create-branch.ts | |
| async function createBranch(params) { | |
| const repoId = toRepoId(params.repo); | |
| const res = await (params.fetch ?? fetch)( | |
| `${params.hubUrl ?? HUB_URL}/api/${repoId.type}s/${repoId.name}/branch/${encodeURIComponent(params.branch)}`, | |
| { | |
| method: "POST", | |
| headers: { | |
| "Content-Type": "application/json", | |
| ...params.accessToken && { | |
| Authorization: `Bearer ${params.accessToken}` | |
| } | |
| }, | |
| body: JSON.stringify({ | |
| startingPoint: params.revision, | |
| ...params.empty && { emptyBranch: true }, | |
| overwrite: params.overwrite | |
| }) | |
| } | |
| ); | |
| if (!res.ok) { | |
| throw await createApiError(res); | |
| } | |
| } | |
| // src/lib/delete-branch.ts | |
| async function deleteBranch(params) { | |
| const repoId = toRepoId(params.repo); | |
| const res = await (params.fetch ?? fetch)( | |
| `${params.hubUrl ?? HUB_URL}/api/${repoId.type}s/${repoId.name}/branch/${encodeURIComponent(params.branch)}`, | |
| { | |
| method: "DELETE", | |
| headers: { | |
| ...params.accessToken && { | |
| Authorization: `Bearer ${params.accessToken}` | |
| } | |
| } | |
| } | |
| ); | |
| if (!res.ok) { | |
| throw await createApiError(res); | |
| } | |
| } | |
| // src/lib/delete-repo.ts | |
| async function deleteRepo(params) { | |
| const accessToken = checkCredentials(params); | |
| const repoId = toRepoId(params.repo); | |
| const [namespace, repoName] = repoId.name.split("/"); | |
| const res = repoId.type === "bucket" ? await (params.fetch ?? fetch)(`${params.hubUrl ?? HUB_URL}/api/buckets/${namespace}/${repoName}`, { | |
| method: "DELETE", | |
| headers: { | |
| Authorization: `Bearer ${accessToken}`, | |
| "Content-Type": "application/json" | |
| } | |
| }) : await (params.fetch ?? fetch)(`${params.hubUrl ?? HUB_URL}/api/repos/delete`, { | |
| method: "DELETE", | |
| body: JSON.stringify({ | |
| name: repoName, | |
| organization: namespace, | |
| type: repoId.type | |
| }), | |
| headers: { | |
| Authorization: `Bearer ${accessToken}`, | |
| "Content-Type": "application/json" | |
| } | |
| }); | |
| if (!res.ok) { | |
| throw await createApiError(res); | |
| } | |
| } | |
| // src/lib/download-file-to-cache-dir.ts | |
| var import_node_path2 = require("path"); | |
| var import_promises4 = require("fs/promises"); | |
| // src/utils/symlink.ts | |
| var fs = __toESM(require("fs/promises")); | |
| var path = __toESM(require("path")); | |
| var os = __toESM(require("os")); | |
| // src/lib/download-file-to-cache-dir.ts | |
| var import_node_stream3 = require("stream"); | |
| var import_promises5 = require("stream/promises"); | |
| var import_node_fs2 = require("fs"); | |
| var REGEX_COMMIT_HASH = new RegExp("^[0-9a-f]{40}$"); | |
| // src/lib/jobs/get-job.ts | |
| async function getJob(params) { | |
| const accessToken = checkCredentials(params); | |
| const response = await (params.fetch || fetch)( | |
| `${params.hubUrl || HUB_URL}/api/jobs/${params.namespace}/${params.jobId}`, | |
| { | |
| headers: { | |
| ...accessToken ? { Authorization: `Bearer ${accessToken}` } : {} | |
| } | |
| } | |
| ); | |
| if (!response.ok) { | |
| throw await createApiError(response); | |
| } | |
| return await response.json(); | |
| } | |
| // src/lib/jobs/list-job-hardware.ts | |
| async function listJobHardware(params) { | |
| const accessToken = checkCredentials(params ?? {}); | |
| const headers = {}; | |
| if (accessToken) { | |
| headers.Authorization = `Bearer ${accessToken}`; | |
| } | |
| const response = await (params?.fetch || fetch)(`${params?.hubUrl || HUB_URL}/api/jobs/hardware`, { | |
| headers | |
| }); | |
| if (!response.ok) { | |
| throw await createApiError(response); | |
| } | |
| return await response.json(); | |
| } | |
| // src/lib/jobs/list-jobs.ts | |
| async function listJobs(params) { | |
| const accessToken = checkCredentials(params); | |
| const response = await (params.fetch || fetch)(`${params.hubUrl || HUB_URL}/api/jobs/${params.namespace}`, { | |
| headers: { | |
| ...accessToken ? { Authorization: `Bearer ${accessToken}` } : {} | |
| } | |
| }); | |
| if (!response.ok) { | |
| throw await createApiError(response); | |
| } | |
| return await response.json(); | |
| } | |
| // src/lib/jobs/run-job.ts | |
| async function runJob(params) { | |
| const accessToken = checkCredentials(params); | |
| if (!params.dockerImage && !params.spaceId) { | |
| throw new Error("Either dockerImage or spaceId must be provided"); | |
| } | |
| if (params.dockerImage && params.spaceId) { | |
| throw new Error("Cannot provide both dockerImage and spaceId"); | |
| } | |
| const body = { | |
| flavor: params.flavor, | |
| environment: params.environment || {} | |
| }; | |
| if (params.dockerImage) { | |
| body.dockerImage = params.dockerImage; | |
| } | |
| if (params.spaceId) { | |
| body.spaceId = params.spaceId; | |
| } | |
| if (params.command) { | |
| body.command = params.command; | |
| } | |
| if (params.arguments) { | |
| body.arguments = params.arguments; | |
| } | |
| if (params.secrets) { | |
| body.secrets = params.secrets; | |
| } | |
| if (params.arch) { | |
| body.arch = params.arch; | |
| } | |
| if (params.timeoutSeconds !== void 0) { | |
| body.timeoutSeconds = params.timeoutSeconds; | |
| } | |
| if (params.attempts !== void 0) { | |
| body.attempts = params.attempts; | |
| } | |
| if (params.labels) { | |
| body.labels = params.labels; | |
| } | |
| if (params.volumes?.length) { | |
| body.volumes = params.volumes.map(({ source, ...rest }) => { | |
| const repoId = toRepoId(source); | |
| return { type: repoId.type, source: repoId.name, ...rest }; | |
| }); | |
| } | |
| const response = await (params.fetch || fetch)(`${params.hubUrl || HUB_URL}/api/jobs/${params.namespace}`, { | |
| method: "POST", | |
| headers: { | |
| "Content-Type": "application/json", | |
| ...accessToken ? { Authorization: `Bearer ${accessToken}` } : {} | |
| }, | |
| body: JSON.stringify(body) | |
| }); | |
| if (!response.ok) { | |
| throw await createApiError(response); | |
| } | |
| return await response.json(); | |
| } | |
| // src/lib/jobs/stream-job-logs.ts | |
| async function* streamJobLogs(params) { | |
| const accessToken = checkCredentials(params); | |
| const response = await (params.fetch || fetch)( | |
| `${params.hubUrl || HUB_URL}/api/jobs/${params.namespace}/${params.jobId}/logs`, | |
| { | |
| headers: { | |
| Accept: "text/event-stream", | |
| ...accessToken ? { Authorization: `Bearer ${accessToken}` } : {} | |
| } | |
| } | |
| ); | |
| if (!response.ok) { | |
| throw await createApiError(response); | |
| } | |
| if (!response.body) { | |
| return; | |
| } | |
| const reader = response.body.getReader(); | |
| const decoder = new TextDecoder(); | |
| let buffer = ""; | |
| try { | |
| while (true) { | |
| const { done, value } = await reader.read(); | |
| if (done) { | |
| break; | |
| } | |
| buffer += decoder.decode(value, { stream: true }); | |
| const lines = buffer.split("\n"); | |
| buffer = lines.pop() || ""; | |
| for (const line of lines) { | |
| if (line.startsWith("data: ")) { | |
| try { | |
| const data = JSON.parse(line.slice(6)); | |
| yield { message: data.data, timestamp: new Date(data.timestamp) }; | |
| } catch { | |
| yield { message: line.slice(6), timestamp: /* @__PURE__ */ new Date() }; | |
| } | |
| } | |
| } | |
| } | |
| if (buffer) { | |
| const lines = buffer.split("\n"); | |
| for (const line of lines) { | |
| if (line.startsWith("data: ")) { | |
| try { | |
| const data = JSON.parse(line.slice(6)); | |
| yield { message: data.data, timestamp: new Date(data.timestamp) }; | |
| } catch { | |
| yield { message: line.slice(6), timestamp: /* @__PURE__ */ new Date() }; | |
| } | |
| } | |
| } | |
| } | |
| } finally { | |
| reader.releaseLock(); | |
| } | |
| } | |
| // src/utils/normalizeInferenceProviderMapping.ts | |
| function normalizeInferenceProviderMapping(hfModelId, inferenceProviderMapping) { | |
| if (!inferenceProviderMapping) { | |
| return []; | |
| } | |
| if (Array.isArray(inferenceProviderMapping)) { | |
| return inferenceProviderMapping.map((entry) => ({ | |
| ...entry, | |
| hfModelId | |
| })); | |
| } | |
| return Object.entries(inferenceProviderMapping).map(([provider, mapping]) => ({ | |
| provider, | |
| hfModelId, | |
| providerId: mapping.providerId, | |
| status: mapping.status, | |
| task: mapping.task | |
| })); | |
| } | |
| // src/lib/list-models.ts | |
| var MODEL_EXPAND_KEYS = [ | |
| "pipeline_tag", | |
| "private", | |
| "gated", | |
| "downloads", | |
| "likes", | |
| "lastModified" | |
| ]; | |
| var MODEL_DERIVED_FIELD_TO_API_KEY = { | |
| filePaths: "siblings" | |
| }; | |
| async function* listModels(params) { | |
| const accessToken = params && checkCredentials(params); | |
| let totalToFetch = params?.limit ?? Infinity; | |
| const additionalExpandKeys = params?.additionalFields?.map( | |
| (field) => MODEL_DERIVED_FIELD_TO_API_KEY[field] ?? field | |
| ) ?? []; | |
| const search = new URLSearchParams([ | |
| ...Object.entries({ | |
| limit: String(Math.min(totalToFetch, 500)), | |
| ...params?.search?.owner ? { author: params.search.owner } : void 0, | |
| ...params?.search?.task ? { pipeline_tag: params.search.task } : void 0, | |
| ...params?.search?.query ? { search: params.search.query } : void 0, | |
| ...params?.search?.inferenceProviders ? { inference_provider: params.search.inferenceProviders.join(",") } : void 0, | |
| ...params?.search?.apps ? { apps: params.search.apps.join(",") } : void 0, | |
| ...params?.sort ? { sort: params.sort } : void 0 | |
| }), | |
| ...params?.search?.tags?.map((tag) => ["filter", tag]) ?? [], | |
| ...MODEL_EXPAND_KEYS.map((val) => ["expand", val]), | |
| ...additionalExpandKeys.map((val) => ["expand", val]) | |
| ]).toString(); | |
| let url = `${params?.hubUrl || HUB_URL}/api/models?${search}`; | |
| while (url) { | |
| const res = await (params?.fetch ?? fetch)(url, { | |
| headers: { | |
| accept: "application/json", | |
| ...accessToken ? { Authorization: `Bearer ${accessToken}` } : void 0 | |
| } | |
| }); | |
| if (!res.ok) { | |
| throw await createApiError(res); | |
| } | |
| const items = await res.json(); | |
| for (const item of items) { | |
| const additional = {}; | |
| if (params?.additionalFields) { | |
| for (const field of params.additionalFields) { | |
| if (field === "filePaths") { | |
| additional.filePaths = (item.siblings ?? []).map((s) => s.rfilename); | |
| } else if (field === "inferenceProviderMapping" && item.inferenceProviderMapping) { | |
| additional.inferenceProviderMapping = normalizeInferenceProviderMapping( | |
| item.id, | |
| item.inferenceProviderMapping | |
| ); | |
| } else { | |
| additional[field] = item[field]; | |
| } | |
| } | |
| } | |
| yield { | |
| ...additional, | |
| id: item._id, | |
| name: item.id, | |
| private: item.private, | |
| task: item.pipeline_tag, | |
| downloads: item.downloads, | |
| gated: item.gated, | |
| likes: item.likes, | |
| updatedAt: new Date(item.lastModified) | |
| }; | |
| totalToFetch--; | |
| if (totalToFetch <= 0) { | |
| return; | |
| } | |
| } | |
| const linkHeader = res.headers.get("Link"); | |
| url = linkHeader ? parseLinkHeader(linkHeader).next : void 0; | |
| } | |
| } | |
| // src/utils/typedInclude.ts | |
| function typedInclude(arr, v) { | |
| return arr.includes(v); | |
| } | |
| // src/lib/repo-exists.ts | |
| async function repoExists(params) { | |
| const repoId = toRepoId(params.repo); | |
| const res = await (params.fetch ?? fetch)( | |
| `${params.hubUrl ?? HUB_URL}/api/${repoId.type}s/${repoId.name}?expand[]=likes`, | |
| { | |
| method: "GET", | |
| headers: { | |
| ...params.accessToken && { | |
| Authorization: `Bearer ${params.accessToken}` | |
| } | |
| } | |
| } | |
| ); | |
| if (res.status === 404 || res.status === 401) { | |
| return false; | |
| } | |
| if (!res.ok) { | |
| throw await createApiError(res); | |
| } | |
| return true; | |
| } | |
| // src/lib/snapshot-download.ts | |
| var import_node_path3 = require("path"); | |
| var import_promises6 = require("fs/promises"); | |
| // src/lib/upload-files-with-progress.ts | |
| var multipartUploadTracking = /* @__PURE__ */ new WeakMap(); | |
| async function* uploadFilesWithProgress(params) { | |
| return yield* commitIter({ | |
| ...params.accessToken ? { accessToken: params.accessToken } : { credentials: params.credentials }, | |
| repo: params.repo, | |
| operations: params.files.map((file) => ({ | |
| operation: "addOrUpdate", | |
| path: file instanceof URL ? file.pathname.split("/").at(-1) ?? "file" : "path" in file ? file.path : file.name, | |
| content: "content" in file ? file.content : file | |
| })), | |
| title: params.commitTitle ?? `Add ${params.files.length} files`, | |
| description: params.commitDescription, | |
| hubUrl: params.hubUrl, | |
| branch: params.branch, | |
| isPullRequest: params.isPullRequest, | |
| parentCommit: params.parentCommit, | |
| useWebWorkers: params.useWebWorkers, | |
| abortSignal: params.abortSignal, | |
| useXet: params.useXet, | |
| fetch: async (input, init) => { | |
| if (!init) { | |
| return fetch(input); | |
| } | |
| if (!typedInclude(["PUT", "POST"], init.method) || !("progressHint" in init) || !init.progressHint || typeof XMLHttpRequest === "undefined" || typeof input !== "string" || !(init.body instanceof ArrayBuffer) && !(init.body instanceof Blob) && !(init.body instanceof File) && typeof init.body !== "string") { | |
| return fetch(input, init); | |
| } | |
| const progressHint = init.progressHint; | |
| const progressCallback = progressHint.progressCallback; | |
| const xhr = new XMLHttpRequest(); | |
| xhr.upload.addEventListener("progress", (event) => { | |
| if (event.lengthComputable) { | |
| if (progressHint.part !== void 0) { | |
| let tracking = multipartUploadTracking.get(progressCallback); | |
| if (!tracking) { | |
| tracking = { numParts: progressHint.numParts, partsProgress: {} }; | |
| multipartUploadTracking.set(progressCallback, tracking); | |
| } | |
| tracking.partsProgress[progressHint.part] = event.loaded / event.total; | |
| let totalProgress = 0; | |
| for (const partProgress of Object.values(tracking.partsProgress)) { | |
| totalProgress += partProgress; | |
| } | |
| if (totalProgress === tracking.numParts) { | |
| progressCallback(0.9999999999); | |
| } else { | |
| progressCallback(totalProgress / tracking.numParts); | |
| } | |
| } else { | |
| if (event.loaded === event.total) { | |
| progressCallback(0.9999999999); | |
| } else { | |
| progressCallback(event.loaded / event.total); | |
| } | |
| } | |
| } | |
| }); | |
| xhr.open(init.method, input, true); | |
| if (init.headers) { | |
| const headers = new Headers(init.headers); | |
| headers.forEach((value, key) => { | |
| xhr.setRequestHeader(key, value); | |
| }); | |
| } | |
| init.signal?.throwIfAborted(); | |
| xhr.send(init.body); | |
| return new Promise((resolve3, reject) => { | |
| xhr.addEventListener("load", () => { | |
| resolve3( | |
| new Response(xhr.responseText, { | |
| status: xhr.status, | |
| statusText: xhr.statusText, | |
| headers: Object.fromEntries( | |
| xhr.getAllResponseHeaders().trim().split("\n").map((header) => [ | |
| header.slice(0, header.indexOf(":")), | |
| header.slice(header.indexOf(":") + 1).trim() | |
| ]) | |
| ) | |
| }) | |
| ); | |
| }); | |
| xhr.addEventListener("error", () => { | |
| reject(new Error(xhr.statusText)); | |
| }); | |
| if (init.signal) { | |
| init.signal.addEventListener("abort", () => { | |
| xhr.abort(); | |
| try { | |
| init.signal?.throwIfAborted(); | |
| } catch (err) { | |
| reject(err); | |
| } | |
| }); | |
| } | |
| }); | |
| } | |
| }); | |
| } | |
| // src/lib/who-am-i.ts | |
| async function whoAmI(params) { | |
| const accessToken = checkCredentials(params); | |
| const res = await (params.fetch ?? fetch)(`${params.hubUrl ?? HUB_URL}/api/whoami-v2`, { | |
| headers: { | |
| Authorization: `Bearer ${accessToken}` | |
| } | |
| }); | |
| if (!res.ok) { | |
| throw await createApiError(res); | |
| } | |
| const response = await res.json(); | |
| if (typeof response.auth.accessToken?.createdAt === "string") { | |
| response.auth.accessToken.createdAt = new Date(response.auth.accessToken.createdAt); | |
| } | |
| return response; | |
| } | |
| // cli.ts | |
| var import_node_url3 = require("url"); | |
| var import_promises7 = require("fs/promises"); | |
| var import_node_path4 = require("path"); | |
| // package.json | |
| var version = "2.13.2"; | |
| // cli.ts | |
| var UploadProgressManager = class { | |
| multibar = null; | |
| fileBars = /* @__PURE__ */ new Map(); | |
| isQuiet; | |
| cliProgressAvailable = false; | |
| constructor(isQuiet = false) { | |
| this.isQuiet = isQuiet; | |
| } | |
| async initialize() { | |
| if (this.isQuiet) { | |
| return; | |
| } | |
| try { | |
| const cliProgress = await Promise.resolve().then(() => __toESM(require_cli_progress())); | |
| this.cliProgressAvailable = true; | |
| this.multibar = new cliProgress.MultiBar( | |
| { | |
| clearOnComplete: false, | |
| hideCursor: true, | |
| format: " {bar} | {filename} | {percentage}% | {state}", | |
| barCompleteChar: "\u2588", | |
| barIncompleteChar: "\u2591" | |
| }, | |
| cliProgress.Presets.shades_grey | |
| ); | |
| } catch (error) { | |
| this.cliProgressAvailable = false; | |
| } | |
| } | |
| handleEvent(event) { | |
| if (this.isQuiet) { | |
| return; | |
| } | |
| if (event.event === "phase") { | |
| this.logPhase(event.phase); | |
| } else if (event.event === "fileProgress") { | |
| this.updateFileProgress(event.path, event.progress, event.state); | |
| } | |
| } | |
| logPhase(phase) { | |
| if (this.isQuiet) { | |
| return; | |
| } | |
| const phaseMessages = { | |
| preuploading: "\u{1F4CB} Preparing files for upload...", | |
| uploadingLargeFiles: "\u2B06\uFE0F Uploading files...", | |
| committing: "\u2728 Finalizing commit..." | |
| }; | |
| console.log(` | |
| ${phaseMessages[phase] || phase}`); | |
| } | |
| updateFileProgress(path2, progress, state) { | |
| if (this.isQuiet) { | |
| return; | |
| } | |
| if (this.cliProgressAvailable && this.multibar) { | |
| let bar = this.fileBars.get(path2); | |
| if (!bar) { | |
| bar = this.multibar.create(100, 0, { | |
| filename: this.truncateFilename(path2, 100), | |
| state | |
| }); | |
| this.fileBars.set(path2, bar); | |
| } | |
| if (state === "error") { | |
| bar.update(0, { state: "\u2717 error" }); | |
| } else if (progress >= 1) { | |
| bar.update(100, { state: state === "hashing" ? "\u2713 hashed" : "\u2713 uploaded" }); | |
| } else { | |
| const percentage = Math.round(progress * 100); | |
| bar.update(percentage, { state }); | |
| } | |
| } else { | |
| const percentage = Math.round(progress * 100); | |
| const truncatedPath = this.truncateFilename(path2, 100); | |
| if (state === "error") { | |
| console.error(`\u2717 error: ${truncatedPath}`); | |
| } else if (progress >= 1) { | |
| const statusIcon = state === "hashing" ? "\u2713 hashed" : "\u2713 uploaded"; | |
| console.log(`${statusIcon}: ${truncatedPath}`); | |
| } else if (percentage % 25 === 0) { | |
| console.log(`${state}: ${truncatedPath} (${percentage}%)`); | |
| } | |
| } | |
| } | |
| truncateFilename(filename, maxLength) { | |
| if (filename.length <= maxLength) { | |
| return filename; | |
| } | |
| return "..." + filename.slice(-(maxLength - 3)); | |
| } | |
| stop() { | |
| if (!this.isQuiet && this.cliProgressAvailable && this.multibar) { | |
| this.multibar.stop(); | |
| } | |
| } | |
| }; | |
| var commands = { | |
| upload: { | |
| description: "Upload a folder to a repo on the Hub", | |
| args: [ | |
| { | |
| name: "repo-name", | |
| description: "The name of the repo to upload to", | |
| positional: true, | |
| required: true | |
| }, | |
| { | |
| name: "local-folder", | |
| description: "The local folder to upload. Defaults to the current working directory", | |
| positional: true, | |
| default: () => process.cwd() | |
| }, | |
| { | |
| name: "path-in-repo", | |
| description: "The path in the repo to upload the folder to. Defaults to the root of the repo", | |
| positional: true, | |
| default: "." | |
| }, | |
| { | |
| name: "quiet", | |
| short: "q", | |
| description: "Suppress all output", | |
| boolean: true | |
| }, | |
| { | |
| name: "repo-type", | |
| enum: ["dataset", "model", "space", "bucket"], | |
| description: "The type of repo to upload to. Defaults to model. You can also prefix the repo name with the type, e.g. datasets/username/repo-name or buckets/username/repo-name" | |
| }, | |
| { | |
| name: "revision", | |
| description: "The revision to upload to. Defaults to the main branch", | |
| default: "main" | |
| }, | |
| { | |
| name: "commit-message", | |
| description: "The commit message to use. Defaults to 'Upload files using @huggingface/hub'", | |
| default: "Upload files using @huggingface/hub" | |
| }, | |
| { | |
| name: "private", | |
| description: "If creating a new repo, make it private", | |
| boolean: true | |
| }, | |
| { | |
| name: "token", | |
| description: "The access token to use for authentication. If not provided, the HF_TOKEN environment variable will be used.", | |
| default: process.env.HF_TOKEN | |
| } | |
| ] | |
| }, | |
| branch: { | |
| description: "Manage repository branches", | |
| subcommands: { | |
| create: { | |
| description: "Create a new branch in a repo, or update an existing one", | |
| args: [ | |
| { | |
| name: "repo-name", | |
| description: "The name of the repo to create the branch in", | |
| positional: true, | |
| required: true | |
| }, | |
| { | |
| name: "branch", | |
| description: "The name of the branch to create", | |
| positional: true, | |
| required: true | |
| }, | |
| { | |
| name: "repo-type", | |
| enum: ["dataset", "model", "space"], | |
| description: "The type of the repo to create the branch into. Defaults to model. You can also prefix the repo name with the type, e.g. datasets/username/repo-name" | |
| }, | |
| { | |
| name: "revision", | |
| description: "The revision to create the branch from. Defaults to the main branch, or existing branch if it exists." | |
| }, | |
| { | |
| name: "empty", | |
| boolean: true, | |
| description: "Create an empty branch. This will erase all previous commits on the branch if it exists." | |
| }, | |
| { | |
| name: "force", | |
| short: "f", | |
| boolean: true, | |
| description: "Overwrite the branch if it already exists. Otherwise, throws an error if the branch already exists. No-ops if no revision is provided and the branch exists." | |
| }, | |
| { | |
| name: "token", | |
| description: "The access token to use for authentication. If not provided, the HF_TOKEN environment variable will be used.", | |
| default: process.env.HF_TOKEN | |
| } | |
| ] | |
| }, | |
| delete: { | |
| description: "Delete a branch in a repo", | |
| args: [ | |
| { | |
| name: "repo-name", | |
| description: "The name of the repo to delete the branch from", | |
| positional: true, | |
| required: true | |
| }, | |
| { | |
| name: "branch", | |
| description: "The name of the branch to delete", | |
| positional: true, | |
| required: true | |
| }, | |
| { | |
| name: "repo-type", | |
| enum: ["dataset", "model", "space"], | |
| description: "The type of repo to delete the branch from. Defaults to model. You can also prefix the repo name with the type, e.g. datasets/username/repo-name" | |
| }, | |
| { | |
| name: "token", | |
| description: "The access token to use for authentication. If not provided, the HF_TOKEN environment variable will be used.", | |
| default: process.env.HF_TOKEN | |
| } | |
| ] | |
| } | |
| } | |
| }, | |
| repo: { | |
| description: "Manage repositories on the Hub", | |
| subcommands: { | |
| delete: { | |
| description: "Delete a repository from the Hub", | |
| args: [ | |
| { | |
| name: "repo-name", | |
| description: "The name of the repo to delete. You can also prefix the repo name with the type, e.g. datasets/username/repo-name", | |
| positional: true, | |
| required: true | |
| }, | |
| { | |
| name: "repo-type", | |
| enum: ["dataset", "model", "space"], | |
| description: "The type of the repo to delete. Defaults to model. You can also prefix the repo name with the type, e.g. datasets/username/repo-name" | |
| }, | |
| { | |
| name: "token", | |
| description: "The access token to use for authentication. If not provided, the HF_TOKEN environment variable will be used.", | |
| default: process.env.HF_TOKEN | |
| } | |
| ] | |
| } | |
| } | |
| }, | |
| models: { | |
| description: "Manage models on the Hub", | |
| subcommands: { | |
| list: { | |
| description: "List models on the Hub (first page)", | |
| args: [ | |
| { | |
| name: "search", | |
| description: "Search query to filter models by name", | |
| positional: true | |
| }, | |
| { | |
| name: "sort", | |
| enum: [ | |
| "createdAt", | |
| "downloads", | |
| "likes", | |
| "lastModified", | |
| "likes30d", | |
| "trendingScore", | |
| "num_parameters" | |
| // "mainSize", | |
| // "id", | |
| ], | |
| description: "Sort models by a specific field" | |
| }, | |
| { | |
| name: "token", | |
| description: "The access token to use for authentication. If not provided, the HF_TOKEN environment variable will be used.", | |
| default: process.env.HF_TOKEN | |
| } | |
| ] | |
| } | |
| } | |
| }, | |
| version: { | |
| description: "Print the version of the CLI", | |
| args: [] | |
| }, | |
| jobs: { | |
| description: "Manage jobs on the Hub", | |
| subcommands: { | |
| run: { | |
| description: "Run a new job", | |
| args: [ | |
| { | |
| name: "docker-image-or-space", | |
| description: "The Docker image to run (e.g., python:3.12) or Space ID (e.g., hf.co/spaces/username/space-name or username/space-name)", | |
| positional: true, | |
| required: true | |
| }, | |
| { | |
| name: "command", | |
| description: `The command to run (can be multiple arguments preceded by --, e.g., -- python -c 'import os; print(os.environ["FOO"])')`, | |
| positional: true, | |
| multiple: true | |
| }, | |
| { | |
| name: "env", | |
| short: "e", | |
| multiple: true, | |
| description: "Environment variable in the format KEY=VALUE (can be specified multiple times)" | |
| }, | |
| { | |
| name: "secret", | |
| short: "s", | |
| multiple: true, | |
| description: "Secret in the format KEY=VALUE (will be encrypted server-side, can be specified multiple times)" | |
| }, | |
| { | |
| name: "label", | |
| short: "l", | |
| multiple: true, | |
| description: "Label in the format KEY=VALUE or KEY alone (in this case VALUE defaults to empty string). Can be specified multiple times." | |
| }, | |
| { | |
| name: "volume", | |
| short: "v", | |
| multiple: true, | |
| description: "Volume to mount in the format SOURCE:MOUNTPATH[:OPTIONS]. SOURCE uses HuggingFace prefixes (datasets/user/repo, spaces/user/repo, buckets/user/bucket) or bare user/repo for models. OPTIONS are comma-separated: ro, revision=REV, path=SUBPATH. Can be specified multiple times." | |
| }, | |
| { | |
| name: "flavor", | |
| description: "Hardware flavor to use (defaults to cpu-basic)", | |
| default: "cpu-basic" | |
| }, | |
| { | |
| name: "attempts", | |
| description: "Maximum number of attempts (defaults to 1)" | |
| }, | |
| { | |
| name: "namespace", | |
| description: "The namespace (username or organization name). Defaults to the current user's username." | |
| }, | |
| { | |
| name: "token", | |
| description: "The access token to use for authentication. If not provided, the HF_TOKEN environment variable will be used.", | |
| default: process.env.HF_TOKEN | |
| }, | |
| { | |
| name: "detach", | |
| short: "d", | |
| description: "Don't stream logs after creating the job", | |
| boolean: true | |
| } | |
| ] | |
| }, | |
| ps: { | |
| description: "List jobs", | |
| args: [ | |
| { | |
| name: "all", | |
| short: "a", | |
| description: "List all jobs (not just running ones)", | |
| boolean: true | |
| }, | |
| { | |
| name: "namespace", | |
| description: "The namespace (username or organization name). Defaults to the current user's username." | |
| }, | |
| { | |
| name: "token", | |
| description: "The access token to use for authentication. If not provided, the HF_TOKEN environment variable will be used.", | |
| default: process.env.HF_TOKEN | |
| } | |
| ] | |
| }, | |
| hardware: { | |
| description: "List available hardware options for jobs", | |
| args: [ | |
| { | |
| name: "token", | |
| description: "The access token to use for authentication. If not provided, the HF_TOKEN environment variable will be used.", | |
| default: process.env.HF_TOKEN | |
| } | |
| ] | |
| }, | |
| logs: { | |
| description: "Show logs for a job", | |
| args: [ | |
| { | |
| name: "job-id", | |
| description: "The job ID", | |
| positional: true, | |
| required: true | |
| }, | |
| { | |
| name: "namespace", | |
| description: "The namespace (username or organization name). Defaults to the current user's username." | |
| }, | |
| { | |
| name: "token", | |
| description: "The access token to use for authentication. If not provided, the HF_TOKEN environment variable will be used.", | |
| default: process.env.HF_TOKEN | |
| } | |
| ] | |
| } | |
| } | |
| } | |
| }; | |
| var mainCommandName = process.argv[2]; | |
| var subCommandName; | |
| var cliArgs; | |
| if (mainCommandName && mainCommandName in commands && commands[mainCommandName] && "subcommands" in commands[mainCommandName]) { | |
| subCommandName = process.argv[3]; | |
| cliArgs = process.argv.slice(4); | |
| } else { | |
| cliArgs = process.argv.slice(3); | |
| } | |
| async function run() { | |
| switch (mainCommandName) { | |
| case void 0: | |
| case "--help": | |
| case "help": { | |
| const helpArgs = mainCommandName === "help" ? process.argv.slice(3) : []; | |
| if (helpArgs.length > 0) { | |
| const cmdName = helpArgs[0]; | |
| if (cmdName && commands[cmdName]) { | |
| const cmdDef = commands[cmdName]; | |
| if ("subcommands" in cmdDef) { | |
| if (helpArgs.length > 1) { | |
| const subCmdName = helpArgs[1]; | |
| if (subCmdName in cmdDef.subcommands && cmdDef.subcommands[subCmdName]) { | |
| console.log(detailedUsageForSubcommand(cmdName, subCmdName)); | |
| break; | |
| } else { | |
| console.error(`Error: Unknown subcommand '${subCmdName}' for command '${cmdName}'.`); | |
| console.log(listSubcommands(cmdName, cmdDef)); | |
| process.exitCode = 1; | |
| break; | |
| } | |
| } else { | |
| console.log(listSubcommands(cmdName, cmdDef)); | |
| break; | |
| } | |
| } else { | |
| console.log(detailedUsageForCommand(cmdName)); | |
| break; | |
| } | |
| } else { | |
| console.error(`Error: Unknown command '${cmdName}' for help.`); | |
| process.exitCode = 1; | |
| } | |
| } else { | |
| console.log( | |
| `Hugging Face CLI Tools (hfjs) | |
| Available commands: | |
| ` + typedEntries(commands).map(([name, def]) => ` ${usage(name)}: ${def.description}`).join("\n") | |
| ); | |
| console.log("\nTo get help on a specific command, run `hfjs help <command>` or `hfjs <command> --help`"); | |
| console.log( | |
| "For commands with subcommands (like 'branch'), run `hfjs help <command> <subcommand>` or `hfjs <command> <subcommand> --help`" | |
| ); | |
| if (mainCommandName === void 0) { | |
| process.exitCode = 1; | |
| } | |
| } | |
| break; | |
| } | |
| case "upload": { | |
| const cmdDef = commands.upload; | |
| if (cliArgs[0] === "--help" || cliArgs[0] === "-h") { | |
| console.log(detailedUsageForCommand("upload")); | |
| break; | |
| } | |
| const parsedArgs = advParseArgs(cliArgs, cmdDef.args, "upload"); | |
| const { | |
| repoName, | |
| localFolder, | |
| repoType, | |
| revision, | |
| token, | |
| quiet, | |
| commitMessage, | |
| pathInRepo, | |
| private: isPrivate | |
| } = parsedArgs; | |
| const repoId = repoType ? { type: repoType, name: repoName } : repoName; | |
| if (!await repoExists({ repo: repoId, revision, accessToken: token, hubUrl: process.env.HF_ENDPOINT ?? HUB_URL })) { | |
| if (!quiet) { | |
| console.log(`Repo ${repoName} does not exist. Creating it...`); | |
| } | |
| await createRepo({ | |
| repo: repoId, | |
| accessToken: token, | |
| private: !!isPrivate, | |
| hubUrl: process.env.HF_ENDPOINT ?? HUB_URL | |
| }); | |
| } | |
| const isFile = (await (0, import_promises7.stat)(localFolder)).isFile(); | |
| const files = isFile ? [ | |
| { | |
| content: (0, import_node_url3.pathToFileURL)(localFolder), | |
| path: (0, import_node_path4.join)(pathInRepo, `${(0, import_node_path4.basename)(localFolder)}`).replace(/^[.]?\//, "") | |
| } | |
| ] : [{ content: (0, import_node_url3.pathToFileURL)(localFolder), path: pathInRepo.replace(/^[.]?\//, "") }]; | |
| const progressManager = new UploadProgressManager(!!quiet); | |
| await progressManager.initialize(); | |
| try { | |
| for await (const event of uploadFilesWithProgress({ | |
| repo: repoId, | |
| files, | |
| branch: revision, | |
| accessToken: token, | |
| commitTitle: commitMessage?.trim().split("\n")[0], | |
| commitDescription: commitMessage?.trim().split("\n").slice(1).join("\n").trim(), | |
| hubUrl: process.env.HF_ENDPOINT ?? HUB_URL, | |
| useXet: true | |
| })) { | |
| progressManager.handleEvent(event); | |
| } | |
| if (!quiet) { | |
| console.log("\n\u2705 Upload completed successfully!"); | |
| } | |
| } catch (error) { | |
| progressManager.stop(); | |
| throw error; | |
| } finally { | |
| progressManager.stop(); | |
| } | |
| break; | |
| } | |
| case "branch": { | |
| const branchCommandGroup = commands.branch; | |
| const currentSubCommandName = subCommandName; | |
| if (subCommandName === "--help" || subCommandName === "-h") { | |
| console.log(listSubcommands("branch", branchCommandGroup)); | |
| break; | |
| } | |
| if (cliArgs[0] === "--help" || cliArgs[0] === "-h") { | |
| if (currentSubCommandName && branchCommandGroup.subcommands[currentSubCommandName]) { | |
| console.log(detailedUsageForSubcommand("branch", currentSubCommandName)); | |
| } else { | |
| console.log(listSubcommands("branch", branchCommandGroup)); | |
| } | |
| break; | |
| } | |
| if (!currentSubCommandName || !branchCommandGroup.subcommands[currentSubCommandName]) { | |
| console.error(`Error: Missing or invalid subcommand for 'branch'.`); | |
| console.log(listSubcommands("branch", branchCommandGroup)); | |
| process.exitCode = 1; | |
| break; | |
| } | |
| const subCmdDef = branchCommandGroup.subcommands[currentSubCommandName]; | |
| switch (currentSubCommandName) { | |
| case "create": { | |
| const parsedArgs = advParseArgs(cliArgs, subCmdDef.args, "branch create"); | |
| const { repoName, branch, revision, empty, repoType, token, force } = parsedArgs; | |
| await createBranch({ | |
| repo: repoType ? { type: repoType, name: repoName } : repoName, | |
| branch, | |
| accessToken: token, | |
| revision, | |
| empty: empty ?? void 0, | |
| overwrite: force ?? void 0, | |
| hubUrl: process.env.HF_ENDPOINT ?? HUB_URL | |
| }); | |
| console.log(`Branch '${branch}' created successfully in repo '${repoName}'.`); | |
| break; | |
| } | |
| case "delete": { | |
| const parsedArgs = advParseArgs(cliArgs, subCmdDef.args, "branch delete"); | |
| const { repoName, branch, repoType, token } = parsedArgs; | |
| await deleteBranch({ | |
| repo: repoType ? { type: repoType, name: repoName } : repoName, | |
| branch, | |
| accessToken: token, | |
| hubUrl: process.env.HF_ENDPOINT ?? HUB_URL | |
| }); | |
| console.log(`Branch '${branch}' deleted successfully from repo '${repoName}'.`); | |
| break; | |
| } | |
| default: | |
| console.error(`Error: Unknown subcommand '${currentSubCommandName}' for 'branch'.`); | |
| console.log(listSubcommands("branch", branchCommandGroup)); | |
| process.exitCode = 1; | |
| break; | |
| } | |
| break; | |
| } | |
| case "repo": { | |
| const repoCommandGroup = commands.repo; | |
| const currentSubCommandName = subCommandName; | |
| if (subCommandName === "--help" || subCommandName === "-h") { | |
| console.log(listSubcommands("repo", repoCommandGroup)); | |
| break; | |
| } | |
| if (cliArgs[0] === "--help" || cliArgs[0] === "-h") { | |
| if (currentSubCommandName && repoCommandGroup.subcommands[currentSubCommandName]) { | |
| console.log(detailedUsageForSubcommand("repo", currentSubCommandName)); | |
| } else { | |
| console.log(listSubcommands("repo", repoCommandGroup)); | |
| } | |
| break; | |
| } | |
| if (!currentSubCommandName || !repoCommandGroup.subcommands[currentSubCommandName]) { | |
| console.error(`Error: Missing or invalid subcommand for 'repo'.`); | |
| console.log(listSubcommands("repo", repoCommandGroup)); | |
| process.exitCode = 1; | |
| break; | |
| } | |
| const subCmdDef = repoCommandGroup.subcommands[currentSubCommandName]; | |
| switch (currentSubCommandName) { | |
| case "delete": { | |
| const parsedArgs = advParseArgs(cliArgs, subCmdDef.args, `repo ${currentSubCommandName}`); | |
| const { repoName, repoType, token } = parsedArgs; | |
| const repoDesignation = repoType ? { type: repoType, name: repoName } : repoName; | |
| await deleteRepo({ | |
| repo: repoDesignation, | |
| accessToken: token, | |
| hubUrl: process.env.HF_ENDPOINT ?? HUB_URL | |
| }); | |
| console.log(`Repository '${repoName}' deleted successfully.`); | |
| break; | |
| } | |
| default: | |
| console.error(`Error: Unknown subcommand '${currentSubCommandName}' for 'repo'.`); | |
| console.log(listSubcommands("repo", repoCommandGroup)); | |
| process.exitCode = 1; | |
| break; | |
| } | |
| break; | |
| } | |
| case "models": { | |
| const modelCommandGroup = commands.models; | |
| const currentSubCommandName = subCommandName; | |
| if (subCommandName === "--help" || subCommandName === "-h") { | |
| console.log(listSubcommands("models", modelCommandGroup)); | |
| break; | |
| } | |
| if (cliArgs[0] === "--help" || cliArgs[0] === "-h") { | |
| if (currentSubCommandName && modelCommandGroup.subcommands[currentSubCommandName]) { | |
| console.log(detailedUsageForSubcommand("models", currentSubCommandName)); | |
| } else { | |
| console.log(listSubcommands("models", modelCommandGroup)); | |
| } | |
| break; | |
| } | |
| if (!currentSubCommandName || !modelCommandGroup.subcommands[currentSubCommandName]) { | |
| console.error(`Error: Missing or invalid subcommand for 'models'.`); | |
| console.log(listSubcommands("models", modelCommandGroup)); | |
| process.exitCode = 1; | |
| break; | |
| } | |
| const subCmdDef = modelCommandGroup.subcommands[currentSubCommandName]; | |
| switch (currentSubCommandName) { | |
| case "list": { | |
| const parsedArgs = advParseArgs(cliArgs, subCmdDef.args, "models list"); | |
| const { search, sort, token } = parsedArgs; | |
| const models = []; | |
| for await (const model of listModels({ | |
| search: search ? { query: search } : void 0, | |
| sort, | |
| limit: 20, | |
| accessToken: token, | |
| hubUrl: process.env.HF_ENDPOINT ?? HUB_URL | |
| })) { | |
| models.push(model); | |
| } | |
| if (models.length === 0) { | |
| console.log("No models found."); | |
| break; | |
| } | |
| console.log( | |
| `${"MODEL".padEnd(45)} ${"TASK".padEnd(25)} ${"DOWNLOADS".padStart(10)} ${"LIKES".padStart(7)} ${"UPDATED"}` | |
| ); | |
| console.log("-".repeat(110)); | |
| for (const model of models) { | |
| const task = model.task || "N/A"; | |
| const updatedAt = model.updatedAt.toLocaleDateString(); | |
| console.log( | |
| `${model.name.padEnd(45)} ${task.padEnd(25)} ${String(model.downloads).padStart(10)} ${String(model.likes).padStart(7)} ${updatedAt}` | |
| ); | |
| } | |
| break; | |
| } | |
| default: | |
| console.error(`Error: Unknown subcommand '${currentSubCommandName}' for 'models'.`); | |
| console.log(listSubcommands("models", modelCommandGroup)); | |
| process.exitCode = 1; | |
| break; | |
| } | |
| break; | |
| } | |
| case "version": { | |
| if (cliArgs[0] === "--help" || cliArgs[0] === "-h") { | |
| console.log(detailedUsageForCommand("version")); | |
| break; | |
| } | |
| console.log(`hfjs version: ${version}`); | |
| break; | |
| } | |
| case "jobs": { | |
| const jobsCommandGroup = commands.jobs; | |
| const currentSubCommandName = subCommandName; | |
| if (subCommandName === "--help" || subCommandName === "-h") { | |
| console.log(listSubcommands("jobs", jobsCommandGroup)); | |
| break; | |
| } | |
| if (cliArgs[0] === "--help" || cliArgs[0] === "-h") { | |
| if (currentSubCommandName && jobsCommandGroup.subcommands[currentSubCommandName]) { | |
| console.log(detailedUsageForSubcommand("jobs", currentSubCommandName)); | |
| } else { | |
| console.log(listSubcommands("jobs", jobsCommandGroup)); | |
| } | |
| break; | |
| } | |
| if (!currentSubCommandName || !jobsCommandGroup.subcommands[currentSubCommandName]) { | |
| console.error(`Error: Missing or invalid subcommand for 'jobs'.`); | |
| console.log(listSubcommands("jobs", jobsCommandGroup)); | |
| process.exitCode = 1; | |
| break; | |
| } | |
| const subCmdDef = jobsCommandGroup.subcommands[currentSubCommandName]; | |
| switch (currentSubCommandName) { | |
| case "run": { | |
| const parsedArgs = advParseArgs(cliArgs, subCmdDef.args, "jobs run"); | |
| const { | |
| dockerImageOrSpace: firstArg, | |
| command: commandArray, | |
| env, | |
| secret, | |
| label, | |
| volume: volumeArgs, | |
| flavor, | |
| attempts: attemptsStr, | |
| namespace, | |
| token, | |
| detach | |
| } = parsedArgs; | |
| const envVars = env; | |
| const secretVars = secret; | |
| const labelVars = label; | |
| let attempts; | |
| if (attemptsStr) { | |
| const parsed = parseInt(attemptsStr, 10); | |
| if (isNaN(parsed) || parsed < 1) { | |
| throw new Error("Attempts must be a positive integer"); | |
| } | |
| attempts = parsed; | |
| } | |
| let dockerImage; | |
| let spaceId; | |
| const hfCoSpacesMatch = firstArg.match(/^hf\.co\/spaces\/(.+)$/); | |
| if (hfCoSpacesMatch) { | |
| spaceId = hfCoSpacesMatch[1]; | |
| } else { | |
| dockerImage = firstArg; | |
| } | |
| let finalNamespace = namespace; | |
| if (!finalNamespace) { | |
| if (!token) { | |
| throw new Error( | |
| "Cannot determine namespace without authentication. Please provide --namespace or --token." | |
| ); | |
| } | |
| const userInfo = await whoAmI({ | |
| accessToken: token, | |
| hubUrl: process.env.HF_ENDPOINT ?? HUB_URL | |
| }); | |
| if (userInfo.type !== "user") { | |
| throw new Error("Cannot determine namespace. Please provide --namespace explicitly."); | |
| } | |
| finalNamespace = userInfo.name; | |
| } | |
| const environment = {}; | |
| if (envVars) { | |
| for (const envVar of envVars) { | |
| const equalIndex = envVar.indexOf("="); | |
| if (equalIndex === -1) { | |
| throw new Error(`Invalid environment variable format: ${envVar}. Expected KEY=VALUE`); | |
| } | |
| const key = envVar.slice(0, equalIndex); | |
| const value = envVar.slice(equalIndex + 1); | |
| environment[key] = value; | |
| } | |
| } | |
| const secrets = {}; | |
| if (secretVars) { | |
| for (const secretVar of secretVars) { | |
| const equalIndex = secretVar.indexOf("="); | |
| if (equalIndex === -1) { | |
| throw new Error(`Invalid secret format: ${secretVar}. Expected KEY=VALUE`); | |
| } | |
| const key = secretVar.slice(0, equalIndex); | |
| const value = secretVar.slice(equalIndex + 1); | |
| secrets[key] = value; | |
| } | |
| } | |
| const labels = {}; | |
| if (labelVars) { | |
| for (const labelVar of labelVars) { | |
| const equalIndex = labelVar.indexOf("="); | |
| const [key, value] = equalIndex > -1 ? [labelVar.slice(0, equalIndex), labelVar.slice(equalIndex + 1)] : [labelVar, ""]; | |
| labels[key] = value; | |
| } | |
| } | |
| const volumes = []; | |
| if (volumeArgs) { | |
| for (const volumeArg of volumeArgs) { | |
| const colonIdx = volumeArg.indexOf(":"); | |
| if (colonIdx === -1) { | |
| throw new Error(`Invalid volume format: ${volumeArg}. Expected SOURCE:MOUNTPATH[:OPTIONS]`); | |
| } | |
| const source = volumeArg.slice(0, colonIdx); | |
| const rest = volumeArg.slice(colonIdx + 1); | |
| const secondColon = rest.indexOf(":"); | |
| const mountPath = secondColon === -1 ? rest : rest.slice(0, secondColon); | |
| const optionsStr = secondColon === -1 ? "" : rest.slice(secondColon + 1); | |
| if (!mountPath.startsWith("/")) { | |
| throw new Error(`Volume mountPath must start with "/": ${mountPath}`); | |
| } | |
| let readOnly; | |
| let revision; | |
| let subPath; | |
| if (optionsStr) { | |
| for (const opt of optionsStr.split(",")) { | |
| if (opt === "ro") { | |
| readOnly = true; | |
| } else if (opt.startsWith("revision=")) { | |
| revision = opt.slice("revision=".length); | |
| } else if (opt.startsWith("path=")) { | |
| subPath = opt.slice("path=".length); | |
| } else { | |
| throw new Error(`Unknown volume option: ${opt}`); | |
| } | |
| } | |
| } | |
| volumes.push({ | |
| source, | |
| mountPath, | |
| ...revision ? { revision } : {}, | |
| ...readOnly ? { readOnly } : {}, | |
| ...subPath ? { path: subPath } : {} | |
| }); | |
| } | |
| } | |
| const jobParams = { | |
| namespace: finalNamespace, | |
| ...dockerImage ? { dockerImage } : {}, | |
| ...spaceId ? { spaceId } : {}, | |
| flavor, | |
| command: commandArray.length > 0 ? commandArray : void 0, | |
| environment, | |
| secrets, | |
| ...attempts !== void 0 ? { attempts } : {}, | |
| ...Object.keys(labels).length > 0 ? { labels } : {}, | |
| ...volumes.length > 0 ? { volumes } : {}, | |
| hubUrl: process.env.HF_ENDPOINT ?? HUB_URL, | |
| ...token ? { accessToken: token } : {} | |
| }; | |
| const job = await runJob(jobParams); | |
| console.log(`Job created: ${job.id}`); | |
| console.log(`Status: ${job.status.stage}`); | |
| if (!detach) { | |
| const logsParams = { | |
| namespace: finalNamespace, | |
| jobId: job.id, | |
| hubUrl: process.env.HF_ENDPOINT ?? HUB_URL, | |
| ...token ? { accessToken: token } : {} | |
| }; | |
| for await (const logChunk of streamJobLogs(logsParams)) { | |
| console.log(logChunk.message); | |
| } | |
| } | |
| break; | |
| } | |
| case "ps": { | |
| const parsedArgs = advParseArgs(cliArgs, subCmdDef.args, "jobs ps"); | |
| const { all, namespace, token } = parsedArgs; | |
| let finalNamespace = namespace; | |
| if (!finalNamespace) { | |
| if (!token) { | |
| throw new Error( | |
| "Cannot determine namespace without authentication. Please provide --namespace or --token." | |
| ); | |
| } | |
| const userInfo = await whoAmI({ | |
| accessToken: token, | |
| hubUrl: process.env.HF_ENDPOINT ?? HUB_URL | |
| }); | |
| if (userInfo.type !== "user") { | |
| throw new Error("Cannot determine namespace. Please provide --namespace explicitly."); | |
| } | |
| finalNamespace = userInfo.name; | |
| } | |
| const jobs = await listJobs({ | |
| namespace: finalNamespace, | |
| accessToken: token, | |
| hubUrl: process.env.HF_ENDPOINT ?? HUB_URL | |
| }); | |
| const filteredJobs = all ? jobs : jobs.filter((job) => job.status.stage === "RUNNING"); | |
| if (filteredJobs.length === 0) { | |
| console.log(all ? "No jobs found." : "No running jobs found."); | |
| break; | |
| } | |
| console.log(`${"ID".padEnd(40)} ${"STATUS".padEnd(12)} ${"CREATED".padEnd(20)} ${"DOCKER IMAGE"}`); | |
| console.log("-".repeat(100)); | |
| for (const job of filteredJobs) { | |
| const createdAt = new Date(job.createdAt).toLocaleString(); | |
| const dockerImage = job.dockerImage || job.spaceId || "N/A"; | |
| const status = job.status.stage; | |
| console.log(`${job.id.padEnd(40)} ${status.padEnd(12)} ${createdAt.padEnd(20)} ${dockerImage}`); | |
| } | |
| break; | |
| } | |
| case "hardware": { | |
| const parsedArgs = advParseArgs(cliArgs, subCmdDef.args, "jobs hardware"); | |
| const { token } = parsedArgs; | |
| const hardwareParams = { | |
| hubUrl: process.env.HF_ENDPOINT ?? HUB_URL | |
| }; | |
| if (token) { | |
| hardwareParams.accessToken = token; | |
| } | |
| const hardware = await listJobHardware(hardwareParams); | |
| console.log( | |
| `${"NAME".padEnd(15)} ${"PRETTY NAME".padEnd(22)} ${"CPU".padEnd(8)} ${"RAM".padEnd(7)} ${"ACCELERATOR".padEnd(16)} ${"COST/MIN".padEnd(9)} ${"COST/HOUR"}` | |
| ); | |
| console.log("-".repeat(100)); | |
| for (const hw of hardware) { | |
| let accelerator = "N/A"; | |
| if (hw.accelerator) { | |
| accelerator = `${hw.accelerator.quantity}x ${hw.accelerator.model} (${hw.accelerator.vram})`; | |
| } | |
| const costPerMin = (hw.unitCostMicroUSD / 1e6).toFixed(4); | |
| const costPerHour = (hw.unitCostMicroUSD / 1e6 * 60).toFixed(2); | |
| console.log( | |
| `${hw.name.padEnd(15)} ${hw.prettyName.padEnd(22)} ${hw.cpu.padEnd(8)} ${hw.ram.padEnd(7)} ${accelerator.padEnd(16)} $${costPerMin.padStart(8)} $${costPerHour.padStart(9)}` | |
| ); | |
| } | |
| break; | |
| } | |
| case "logs": { | |
| const parsedArgs = advParseArgs(cliArgs, subCmdDef.args, "jobs logs"); | |
| const { jobId, namespace, token } = parsedArgs; | |
| let finalNamespace = namespace; | |
| if (!finalNamespace) { | |
| if (!token) { | |
| throw new Error( | |
| "Cannot determine namespace without authentication. Please provide --namespace or --token." | |
| ); | |
| } | |
| const userInfo = await whoAmI({ | |
| accessToken: token, | |
| hubUrl: process.env.HF_ENDPOINT ?? HUB_URL | |
| }); | |
| if (userInfo.type !== "user") { | |
| throw new Error("Cannot determine namespace. Please provide --namespace explicitly."); | |
| } | |
| finalNamespace = userInfo.name; | |
| } | |
| const logsParams = { | |
| namespace: finalNamespace, | |
| jobId, | |
| hubUrl: process.env.HF_ENDPOINT ?? HUB_URL, | |
| ...token ? { accessToken: token } : {} | |
| }; | |
| const jobInfoParams = { | |
| namespace: finalNamespace, | |
| jobId, | |
| hubUrl: process.env.HF_ENDPOINT ?? HUB_URL, | |
| ...token ? { accessToken: token } : {} | |
| }; | |
| const jobInfo = await getJob(jobInfoParams); | |
| if (jobInfo.status.stage === "ERROR" && jobInfo.status.message) { | |
| console.error(` | |
| \u274C Job failed: ${jobInfo.status.message} | |
| `); | |
| } | |
| for await (const logChunk of streamJobLogs(logsParams)) { | |
| console.log(logChunk.message); | |
| } | |
| break; | |
| } | |
| default: | |
| console.error(`Error: Unknown subcommand '${currentSubCommandName}' for 'jobs'.`); | |
| console.log(listSubcommands("jobs", jobsCommandGroup)); | |
| process.exitCode = 1; | |
| break; | |
| } | |
| break; | |
| } | |
| default: | |
| console.error("Command not found: " + mainCommandName); | |
| console.log( | |
| ` | |
| Available commands: | |
| ` + typedEntries(commands).map(([name, def]) => ` ${usage(name)}: ${def.description}`).join("\n") | |
| ); | |
| console.log("\nTo get help on a specific command, run `hfjs help <command>` or `hfjs <command> --help`"); | |
| process.exitCode = 1; | |
| break; | |
| } | |
| } | |
| run().catch((err) => { | |
| console.error("\x1B[31mError:\x1B[0m", err.message); | |
| console.error(err); | |
| process.exitCode = 1; | |
| }); | |
| function usage(commandName, subCommandName2) { | |
| const commandEntry = commands[commandName]; | |
| let cmdArgs; | |
| let fullCommandName = commandName; | |
| if ("subcommands" in commandEntry) { | |
| if (subCommandName2 && subCommandName2 in commandEntry.subcommands) { | |
| const subCmd = commandEntry.subcommands[subCommandName2]; | |
| cmdArgs = subCmd.args; | |
| fullCommandName = `${commandName} ${subCommandName2}`; | |
| } else { | |
| return `${commandName} <subcommand>`; | |
| } | |
| } else { | |
| cmdArgs = commandEntry.args; | |
| } | |
| return `${fullCommandName} ${(cmdArgs || []).map((arg) => { | |
| if (arg.positional) { | |
| return arg.required ? `<${arg.name}>` : `[${arg.name}]`; | |
| } | |
| return `[--${arg.name}${arg.short ? `|-${arg.short}` : ""}${arg.enum ? ` {${arg.enum.join("|")}}` : arg.boolean ? "" : ` <${arg.name.toUpperCase().replace(/-/g, "_")}>`}]`; | |
| }).join(" ")}`.trim(); | |
| } | |
| function _detailedUsage(args, usageLine, commandDescription) { | |
| let ret = `usage: hfjs ${usageLine} | |
| `; | |
| if (commandDescription) { | |
| ret += ` | |
| ${commandDescription} | |
| `; | |
| } | |
| const positionals = args.filter((p) => p.positional); | |
| const options = args.filter((p) => !p.positional); | |
| if (positionals.length > 0) { | |
| ret += ` | |
| Positional arguments: | |
| `; | |
| for (const arg of positionals) { | |
| ret += ` ${arg.name} ${arg.description}${arg.default ? ` (default: ${typeof arg.default === "function" ? arg.default() : arg.default})` : ""} | |
| `; | |
| } | |
| } | |
| if (options.length > 0) { | |
| ret += ` | |
| Options: | |
| `; | |
| for (const arg of options) { | |
| const nameAndAlias = `--${arg.name}${arg.short ? `, -${arg.short}` : ""}`; | |
| const valueHint = arg.enum ? `{${arg.enum.join("|")}}` : arg.boolean ? "" : `<${arg.name.toUpperCase().replace(/-/g, "_")}>`; | |
| ret += ` ${nameAndAlias}${valueHint ? " " + valueHint : ""} ${arg.description}${arg.default !== void 0 ? ` (default: ${typeof arg.default === "function" ? arg.default() : arg.default})` : ""} | |
| `; | |
| } | |
| } | |
| ret += ` | |
| `; | |
| return ret; | |
| } | |
| function detailedUsageForCommand(commandName) { | |
| const commandDef = commands[commandName]; | |
| if ("subcommands" in commandDef) { | |
| return listSubcommands(commandName, commandDef); | |
| } | |
| return _detailedUsage(commandDef.args, usage(commandName), commandDef.description); | |
| } | |
| function detailedUsageForSubcommand(commandName, subCommandName2) { | |
| const commandGroup = commands[commandName]; | |
| if (!("subcommands" in commandGroup)) { | |
| throw new Error(`Command ${commandName} does not have subcommands`); | |
| } | |
| if (!(subCommandName2 in commandGroup.subcommands)) { | |
| throw new Error(`Subcommand ${subCommandName2} not found for ${commandName}`); | |
| } | |
| const subCommandDef = commandGroup.subcommands[subCommandName2]; | |
| return _detailedUsage(subCommandDef.args, usage(commandName, subCommandName2), subCommandDef.description); | |
| } | |
| function listSubcommands(commandName, commandGroup) { | |
| let ret = `usage: hfjs ${commandName} <subcommand> [options] | |
| `; | |
| ret += `${commandGroup.description} | |
| `; | |
| ret += `Available subcommands for '${commandName}': | |
| `; | |
| ret += typedEntries(commandGroup.subcommands).map(([subName, subDef]) => ` ${subName} ${subDef.description}`).join("\n"); | |
| if (commandName === "jobs") { | |
| ret += ` | |
| Example: | |
| hfjs jobs run -e FOO=foo -e BAR=bar python:3.12 -- python -c 'import os; print(os.environ["FOO"], os.environ["BAR"])'`; | |
| } | |
| ret += ` | |
| Run \`hfjs help ${commandName} <subcommand>\` for more information on a specific subcommand.`; | |
| return ret; | |
| } | |
| function advParseArgs(args, argDefs, commandNameForError) { | |
| const hasMultiplePositional = argDefs.some((arg) => arg.multiple && arg.positional); | |
| const { tokens } = (0, import_node_util.parseArgs)({ | |
| options: Object.fromEntries( | |
| argDefs.filter((arg) => !arg.positional).map((arg) => { | |
| const optionConfig = { | |
| type: arg.boolean ? "boolean" : "string", | |
| ...arg.short && { short: arg.short }, | |
| ...arg.multiple && { multiple: true }, | |
| ...arg.default !== void 0 && { | |
| default: typeof arg.default === "function" ? arg.default() : arg.default | |
| } | |
| }; | |
| return [arg.name, optionConfig]; | |
| }) | |
| ), | |
| args, | |
| allowPositionals: true, | |
| strict: false, | |
| // We do custom validation based on tokens and argDefs | |
| tokens: true | |
| }); | |
| const expectedPositionals = argDefs.filter((arg) => arg.positional); | |
| const providedPositionalTokens = tokens.filter((token) => token.kind === "positional"); | |
| if (providedPositionalTokens.length < expectedPositionals.filter((arg) => arg.required).length) { | |
| throw new Error( | |
| `Command '${commandNameForError}': Missing required positional arguments. Usage: hfjs ${usage( | |
| commandNameForError.split(" ")[0], | |
| commandNameForError.split(" ")[1] | |
| )}` | |
| ); | |
| } | |
| if (providedPositionalTokens.length > expectedPositionals.length && !hasMultiplePositional) { | |
| throw new Error( | |
| `Command '${commandNameForError}': Too many positional arguments. Usage: hfjs ${usage( | |
| commandNameForError.split(" ")[0], | |
| commandNameForError.split(" ")[1] | |
| )}` | |
| ); | |
| } | |
| const result = {}; | |
| for (const argDef of argDefs) { | |
| if (argDef.default !== void 0) { | |
| result[argDef.name] = typeof argDef.default === "function" ? argDef.default() : argDef.default; | |
| } else if (argDef.boolean) { | |
| result[argDef.name] = false; | |
| } | |
| } | |
| expectedPositionals.forEach((argDef, i) => { | |
| if (argDef.multiple) { | |
| result[argDef.name] = providedPositionalTokens.slice(i).map((token) => token.value); | |
| } else if (providedPositionalTokens[i]) { | |
| result[argDef.name] = providedPositionalTokens[i].value; | |
| } | |
| }); | |
| tokens.filter((token) => token.kind === "option").forEach((token) => { | |
| const argDef = argDefs.find((def) => def.name === token.name || def.short === token.name); | |
| if (!argDef) { | |
| throw new Error(`Command '${commandNameForError}': Unknown option: ${token.rawName}`); | |
| } | |
| if (argDef.boolean) { | |
| result[argDef.name] = true; | |
| } else { | |
| if (token.value === void 0) { | |
| throw new Error(`Command '${commandNameForError}': Missing value for option: ${token.rawName}`); | |
| } | |
| if (argDef.enum && !argDef.enum.includes(token.value)) { | |
| throw new Error( | |
| `Command '${commandNameForError}': Invalid value '${token.value}' for option ${token.rawName}. Expected one of: ${argDef.enum.join(", ")}` | |
| ); | |
| } | |
| if (argDef.multiple) { | |
| const existing = result[argDef.name] || []; | |
| existing.push(token.value); | |
| result[argDef.name] = existing; | |
| } else { | |
| result[argDef.name] = token.value; | |
| } | |
| } | |
| }); | |
| for (const argDef of argDefs) { | |
| if (argDef.required && result[argDef.name] === void 0) { | |
| throw new Error(`Command '${commandNameForError}': Missing required argument: ${argDef.name}`); | |
| } | |
| } | |
| return Object.fromEntries( | |
| Object.entries(result).map(([name, val]) => [kebabToCamelCase(name), val]) | |
| ); | |
| } | |
| function kebabToCamelCase(str) { | |
| return str.replace(/-./g, (match) => match[1].toUpperCase()); | |
| } | |