UNPKG

@arkts/sdk-downloader

Version:
515 lines (508 loc) 20.1 kB
//#region rolldown:runtime 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 __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) { key = keys[i]; if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: ((k) => from[k]).bind(null, key), enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod)); //#endregion const node_fs = __toESM(require("node:fs")); const node_path = __toESM(require("node:path")); const node_process = __toESM(require("node:process")); const node_crypto = __toESM(require("node:crypto")); const alien_signals = __toESM(require("alien-signals")); const fast_glob = __toESM(require("fast-glob")); const mitt = __toESM(require("mitt")); const progress_stream = __toESM(require("progress-stream")); const tar = __toESM(require("tar")); const unzipper = __toESM(require("unzipper")); const node_http = __toESM(require("node:http")); const node_https = __toESM(require("node:https")); const node_buffer = __toESM(require("node:buffer")); //#region src/errors/download.ts var DownloadError = class extends Error { constructor(code, options) { super(options?.message); this.code = code; this.cause = options?.cause; } }; (function(_DownloadError) { let Code = /* @__PURE__ */ function(Code$1) { Code$1["DownloadFailed"] = "DOWNLOAD_FAILED"; Code$1["ZipExtractionFailed"] = "ZIP_EXTRACTION_FAILED"; Code$1["InvalidUrl"] = "INVALID_URL"; Code$1["Sha256Mismatch"] = "SHA256_MISMATCH"; Code$1["FileNotFound"] = "FILE_NOT_FOUND"; Code$1["InvalidSha256"] = "INVALID_SHA256"; Code$1["FileReadError"] = "FILE_READ_ERROR"; return Code$1; }({}); _DownloadError.Code = Code; })(DownloadError || (DownloadError = {})); //#endregion //#region src/enums/sdk.ts let SdkVersion = /* @__PURE__ */ function(SdkVersion$1) { SdkVersion$1["API10"] = "4.0.0"; SdkVersion$1["API11"] = "4.1.0"; SdkVersion$1["API12"] = "5.0.0"; SdkVersion$1["API13"] = "5.0.1"; SdkVersion$1["API14"] = "5.0.2"; SdkVersion$1["API15"] = "5.0.3"; SdkVersion$1["API18"] = "5.1.0"; SdkVersion$1["API20"] = "6.0.0-Beta1"; return SdkVersion$1; }({}); let SdkArch = /* @__PURE__ */ function(SdkArch$1) { SdkArch$1[SdkArch$1["X86"] = 0] = "X86"; SdkArch$1[SdkArch$1["ARM"] = 1] = "ARM"; return SdkArch$1; }({}); let SdkOS = /* @__PURE__ */ function(SdkOS$1) { SdkOS$1[SdkOS$1["MacOS"] = 0] = "MacOS"; SdkOS$1[SdkOS$1["Windows"] = 1] = "Windows"; SdkOS$1[SdkOS$1["Linux"] = 2] = "Linux"; return SdkOS$1; }({}); const urls = { [SdkVersion.API10]: { [SdkArch.X86]: { [SdkOS.MacOS]: "https://mirrors.huaweicloud.com/harmonyos/os/4.0-Release/ohos-sdk-mac-public.tar.gz", [SdkOS.Windows]: "https://mirrors.huaweicloud.com/harmonyos/os/4.0-Release/ohos-sdk-windows_linux-public.tar.gz", [SdkOS.Linux]: "https://mirrors.huaweicloud.com/harmonyos/os/4.0-Release/ohos-sdk-windows_linux-public.tar.gz" }, [SdkArch.ARM]: { [SdkOS.MacOS]: "https://mirrors.huaweicloud.com/harmonyos/os/4.0-Release/L2-SDK-MAC-M1-PUBLIC.tar.gz", [SdkOS.Windows]: "https://mirrors.huaweicloud.com/harmonyos/os/4.0-Release/ohos-sdk-windows_linux-public.tar.gz", [SdkOS.Linux]: null } }, [SdkVersion.API11]: { [SdkArch.X86]: { [SdkOS.MacOS]: "https://mirrors.huaweicloud.com/harmonyos/os/4.1-Release/ohos-sdk-mac-public-signed.tar.gz", [SdkOS.Windows]: "https://mirrors.huaweicloud.com/harmonyos/os/4.1-Release/ohos-sdk-windows_linux-public.tar.gz", [SdkOS.Linux]: "https://mirrors.huaweicloud.com/harmonyos/os/4.1-Release/ohos-sdk-windows_linux-public.tar.gz" }, [SdkArch.ARM]: { [SdkOS.MacOS]: "https://mirrors.huaweicloud.com/harmonyos/os/4.1-Release/L2-SDK-MAC-M1-PUBLIC.tar.gz", [SdkOS.Windows]: "https://mirrors.huaweicloud.com/harmonyos/os/4.1-Release/ohos-sdk-windows_linux-public.tar.gz", [SdkOS.Linux]: null } }, [SdkVersion.API12]: { [SdkArch.X86]: { [SdkOS.MacOS]: "https://mirrors.huaweicloud.com/harmonyos/os/5.0.0-Release/ohos-sdk-mac-public.tar.gz", [SdkOS.Windows]: "https://mirrors.huaweicloud.com/harmonyos/os/5.0.0-Release/ohos-sdk-windows_linux-public.tar.gz", [SdkOS.Linux]: "https://mirrors.huaweicloud.com/harmonyos/os/5.0.0-Release/ohos-sdk-windows_linux-public.tar.gz" }, [SdkArch.ARM]: { [SdkOS.MacOS]: "https://mirrors.huaweicloud.com/harmonyos/os/5.0.0-Release/L2-SDK-MAC-M1-PUBLIC.tar.gz", [SdkOS.Windows]: "https://mirrors.huaweicloud.com/harmonyos/os/5.0.0-Release/ohos-sdk-windows_linux-public.tar.gz", [SdkOS.Linux]: null } }, [SdkVersion.API13]: { [SdkArch.X86]: { [SdkOS.MacOS]: "https://mirrors.huaweicloud.com/harmonyos/os/5.0.1-Release/ohos-sdk-mac-public.tar.gz", [SdkOS.Windows]: "https://mirrors.huaweicloud.com/harmonyos/os/5.0.1-Release/ohos-sdk-windows_linux-public.tar.gz", [SdkOS.Linux]: "https://mirrors.huaweicloud.com/harmonyos/os/5.0.1-Release/ohos-sdk-windows_linux-public.tar.gz" }, [SdkArch.ARM]: { [SdkOS.MacOS]: "https://mirrors.huaweicloud.com/harmonyos/os/5.0.1-Release/L2-SDK-MAC-M1-PUBLIC.tar.gz", [SdkOS.Windows]: "https://mirrors.huaweicloud.com/harmonyos/os/5.0.1-Release/ohos-sdk-windows_linux-public.tar.gz", [SdkOS.Linux]: null } }, [SdkVersion.API14]: { [SdkArch.X86]: { [SdkOS.MacOS]: "https://mirrors.huaweicloud.com/harmonyos/os/5.0.2-Release/ohos-sdk-mac-public.tar.gz", [SdkOS.Windows]: "https://mirrors.huaweicloud.com/harmonyos/os/5.0.2-Release/ohos-sdk-windows_linux-public.tar.gz", [SdkOS.Linux]: "https://mirrors.huaweicloud.com/harmonyos/os/5.0.2-Release/ohos-sdk-windows_linux-public.tar.gz" }, [SdkArch.ARM]: { [SdkOS.MacOS]: "https://mirrors.huaweicloud.com/harmonyos/os/5.0.2-Release/L2-SDK-MAC-M1-PUBLIC.tar.gz", [SdkOS.Windows]: "https://mirrors.huaweicloud.com/harmonyos/os/5.0.2-Release/ohos-sdk-windows_linux-public.tar.gz", [SdkOS.Linux]: null } }, [SdkVersion.API15]: { [SdkArch.X86]: { [SdkOS.MacOS]: "https://mirrors.huaweicloud.com/harmonyos/os/5.0.3-Release/ohos-sdk-mac-public.tar.gz", [SdkOS.Windows]: "https://mirrors.huaweicloud.com/harmonyos/os/5.0.3-Release/ohos-sdk-windows_linux-public.tar.gz", [SdkOS.Linux]: "https://mirrors.huaweicloud.com/harmonyos/os/5.0.3-Release/ohos-sdk-windows_linux-public.tar.gz" }, [SdkArch.ARM]: { [SdkOS.MacOS]: "https://mirrors.huaweicloud.com/harmonyos/os/5.0.3-Release/L2-SDK-MAC-M1-PUBLIC.tar.gz", [SdkOS.Windows]: "https://mirrors.huaweicloud.com/harmonyos/os/5.0.3-Release/ohos-sdk-windows_linux-public.tar.gz", [SdkOS.Linux]: null } }, [SdkVersion.API18]: { [SdkArch.X86]: { [SdkOS.MacOS]: "https://mirrors.huaweicloud.com/harmonyos/os/5.1.0-Release/ohos-sdk-mac-public.tar.gz", [SdkOS.Windows]: "https://mirrors.huaweicloud.com/harmonyos/os/5.1.0-Release/ohos-sdk-windows_linux-public.tar.gz", [SdkOS.Linux]: "https://mirrors.huaweicloud.com/harmonyos/os/5.1.0-Release/ohos-sdk-windows_linux-public.tar.gz" }, [SdkArch.ARM]: { [SdkOS.MacOS]: "https://mirrors.huaweicloud.com/harmonyos/os/5.1.0-Release/L2-SDK-MAC-M1-PUBLIC.tar.gz", [SdkOS.Windows]: "https://mirrors.huaweicloud.com/harmonyos/os/5.1.0-Release/ohos-sdk-windows_linux-public.tar.gz", [SdkOS.Linux]: null } }, [SdkVersion.API20]: { [SdkArch.X86]: { [SdkOS.MacOS]: "https://mirrors.huaweicloud.com/harmonyos/os/6.0-Beta1/ohos-sdk-mac-public.tar.gz", [SdkOS.Windows]: "https://mirrors.huaweicloud.com/harmonyos/os/6.0-Beta1/ohos-sdk-windows_linux-public.tar.gz", [SdkOS.Linux]: "https://mirrors.huaweicloud.com/harmonyos/os/6.0-Beta1/ohos-sdk-windows_linux-public.tar.gz" }, [SdkArch.ARM]: { [SdkOS.MacOS]: "https://mirrors.huaweicloud.com/harmonyos/os/6.0-Beta1/L2-SDK-MAC-M1-PUBLIC.tar.gz", [SdkOS.Windows]: "https://mirrors.huaweicloud.com/harmonyos/os/6.0-Beta1/ohos-sdk-windows_linux-public.tar.gz", [SdkOS.Linux]: null } } }; /** * Get the SDK URL for a given version, architecture, and operating system. * @param version - The version of the SDK. * @param arch - The architecture of the SDK. * @param os - The operating system of the SDK. * @returns The URL of the SDK. */ function getSdkUrl(version, arch, os) { return urls?.[version]?.[arch]?.[os] ?? null; } /** * Get all the SDK URLs. * @returns The SDK URLs. */ function getSdkUrls() { return urls; } //#endregion //#region src/options.ts function resolveDownloadOptions(options) { const url = typeof options.url === "string" ? options.url : getSdkUrl(options.url.version, options.url.arch, options.url.os); if (!url) throw new DownloadError(DownloadError.Code.InvalidUrl); if (!node_fs.default.existsSync(options.cacheDir)) node_fs.default.mkdirSync(options.cacheDir, { recursive: true }); options.tempFilePath = options.tempFilePath ? node_path.default.resolve(options.tempFilePath) : node_path.default.resolve(node_path.default.join(options.cacheDir, "download.tmp.tar.gz")); if (!node_fs.default.existsSync(node_path.default.dirname(options.tempFilePath))) node_fs.default.mkdirSync(node_path.default.dirname(options.tempFilePath), { recursive: true }); return { ...options, url, requester: options.requestType === "http" ? node_http.default : node_https.default, tempFilePath: options.tempFilePath, targetDir: node_path.default.resolve(options.targetDir), resumeDownload: typeof options.resumeDownload === "boolean" ? options.resumeDownload : true }; } //#endregion //#region src/request.ts function makeRequest(resolvedOptions, startByte, extraOptions) { return new Promise((resolve, reject) => { resolvedOptions.requester.get(resolvedOptions.url, { method: "GET", headers: startByte ? { Range: `bytes=${startByte}-` } : void 0, ...extraOptions }, (res) => { if (res.statusCode === 416 || res.statusCode === 206) resolve(res); else if (res.statusCode !== 200) reject(new DownloadError(DownloadError.Code.DownloadFailed, { cause: res })); else resolve(res); }).on("error", (err) => reject(err)); }); } function makeSha256Request(resolvedOptions) { return new Promise((resolve, reject) => { resolvedOptions.requester.get(`${resolvedOptions.url}.sha256`, (res) => { if (res.statusCode !== 200 && res.statusCode !== 201) reject(new DownloadError(DownloadError.Code.DownloadFailed, { cause: res.statusCode })); const chunks = []; res.on("data", (chunk) => { chunks.push(chunk); }); res.on("end", () => { resolve(node_buffer.Buffer.concat(chunks).toString("utf-8")); }); }); }); } //#endregion //#region src/download.ts function typeAssert(_value) {} function useDownloadProgress() { let lastTime = Date.now(); let lastTransferred = 0; let lastPercentage = 0; const speedHistory = []; const maxHistorySize = 5; const minTimeInterval = 100; return (progress$1) => { const currentTime = Date.now(); const timeDifference = currentTime - lastTime; const transferredDifference = progress$1.transferred - lastTransferred; const increment = progress$1.percentage - lastPercentage; let network; let unit; if (timeDifference >= minTimeInterval && transferredDifference > 0) { const currentSpeed = transferredDifference / timeDifference * 1e3; speedHistory.push(currentSpeed); if (speedHistory.length > maxHistorySize) speedHistory.shift(); lastTime = currentTime; lastTransferred = progress$1.transferred; } const avgSpeedBytesPerSecond = speedHistory.length > 0 ? speedHistory.reduce((sum, speed) => sum + speed, 0) / speedHistory.length : 0; if (avgSpeedBytesPerSecond >= 1024 * 1024) { network = Math.round(avgSpeedBytesPerSecond / (1024 * 1024) * 100) / 100; unit = "MB"; } else { network = Math.round(avgSpeedBytesPerSecond / 1024 * 100) / 100; unit = "KB"; } lastPercentage = progress$1.percentage; return { network, unit, increment }; }; } async function onDownloaded(writeStream, res) { return new Promise((resolve, reject) => { let isResolved = false; function cleanup() { isResolved = true; if (!res.destroyed) res.destroy(); if (!writeStream.destroyed) writeStream.destroy(); } function handleError(error) { if (!isResolved) { cleanup(); const errorMessage = error instanceof Error ? error.message : String(error); reject(new DownloadError(DownloadError.Code.DownloadFailed, { message: `Download failed: ${errorMessage}`, cause: error })); } } writeStream.on("error", handleError); writeStream.on("finish", () => { if (!isResolved) { isResolved = true; if (!res.destroyed) res.destroy(); resolve(); } }); res.on("error", handleError); }); } async function _checkSha256(filePath, sha256) { if (!node_fs.default.existsSync(filePath)) throw new DownloadError(DownloadError.Code.FileNotFound, { message: `File not found: ${filePath}` }); if (!sha256 || typeof sha256 !== "string" || !/^[a-f0-9]{64}$/i.test(sha256.trim())) throw new DownloadError(DownloadError.Code.InvalidSha256, { message: "Invalid SHA256 format" }); return new Promise((resolve, reject) => { const hash = node_crypto.default.createHash("sha256"); const stream = node_fs.default.createReadStream(filePath); stream.on("error", (error) => { reject(new DownloadError(DownloadError.Code.FileReadError, { message: `Failed to read file: ${error.message}` })); }); stream.on("data", (chunk) => { hash.update(chunk); }); stream.on("end", () => { const calculatedHash = hash.digest("hex").trim(); const expectedHash = sha256.trim(); if (calculatedHash !== expectedHash) { const error = new DownloadError(DownloadError.Code.Sha256Mismatch, { message: `SHA256 checksum mismatch, expected: ${expectedHash}, actual: ${calculatedHash}` }); reject(error); } else resolve(); }); }); } async function _extractTar(resolvedOptions, extractedDir, emitter) { await tar.extract({ file: resolvedOptions.tempFilePath, cwd: extractedDir, onReadEntry: (entry) => { resolvedOptions.onTarExtracted?.(entry); emitter.emit("tar-extracted", entry); } }); } async function _extractZip(resolvedOptions, extractedDir, emitter) { const currentOS = node_process.default.platform === "win32" ? "windows" : node_process.default.platform === "linux" ? "linux" : void 0; let files = fast_glob.default.sync(node_path.default.join(extractedDir, "**", "*.zip"), { onlyFiles: true, absolute: true }).filter((file) => file.endsWith(".zip")); if (currentOS === "linux" || currentOS === "windows") files = files.filter((filePath) => filePath.includes(currentOS)); async function extractSingleZip(filePath) { const fileReadStream = node_fs.default.createReadStream(filePath).pipe(unzipper.Parse({ forceStream: true })); const writePromises = []; for await (const entry of fileReadStream) { typeAssert(entry); const currentFilePath = node_path.default.join(resolvedOptions.targetDir, entry.path); if (entry.type === "File") { if (!node_fs.default.existsSync(node_path.default.dirname(currentFilePath))) node_fs.default.mkdirSync(node_path.default.dirname(currentFilePath), { recursive: true }); const writePromise = new Promise((resolve, reject) => { const writeStream = node_fs.default.createWriteStream(currentFilePath); writeStream.on("error", reject); writeStream.on("finish", resolve); entry.pipe(writeStream); }); writePromises.push(writePromise); await resolvedOptions.onZipExtracted?.(entry); emitter.emit("zip-extracted", entry); } else if (entry.type === "Directory") { if (!node_fs.default.existsSync(currentFilePath)) node_fs.default.mkdirSync(currentFilePath, { recursive: true }); } } await Promise.all(writePromises); } if (!node_fs.default.existsSync(resolvedOptions.targetDir)) node_fs.default.mkdirSync(resolvedOptions.targetDir, { recursive: true }); await Promise.all(files.map(extractSingleZip)); } /** * Download the ArkTS SDK. * * @param options - The options for the download. */ async function createDownloader(options) { const resolvedOptions = resolveDownloadOptions(options); const emitter = (0, mitt.default)(); async function startDownload(requestOptions) { const startByte = (0, alien_signals.computed)(() => node_fs.default.existsSync(resolvedOptions.tempFilePath) ? node_fs.default.statSync(resolvedOptions.tempFilePath).size : 0); const res = await makeRequest(resolvedOptions, startByte(), { signal: resolvedOptions.signal, ...resolvedOptions.requestOptions, ...requestOptions }); const totalLength = (0, alien_signals.computed)(() => (Number(res.headers["content-length"]) || 0) + startByte()); const downloadProgressStream = (0, progress_stream.default)({ length: totalLength(), transferred: startByte() }); const progressHandler = useDownloadProgress(); downloadProgressStream.on("progress", (progress$1) => { const progressEvent = { ...progress$1, ...progressHandler(progress$1) }; options.onDownloadProgress?.(progressEvent); emitter.emit("download-progress", progressEvent); }); if (res.statusCode === 200 || res.statusCode === 206) { const writeStream = node_fs.default.createWriteStream(resolvedOptions.tempFilePath, { flags: startByte() > 0 ? "a" : "w", start: startByte() }); res.pipe(downloadProgressStream).pipe(writeStream); await onDownloaded(writeStream, res); } } async function checkSha256() { const sha256 = await makeSha256Request(resolvedOptions); await _checkSha256(resolvedOptions.tempFilePath, sha256); } const extractedDir = node_path.default.join(resolvedOptions.cacheDir, ".tar-extracted"); async function extractTar() { if (!node_fs.default.existsSync(extractedDir)) node_fs.default.mkdirSync(extractedDir, { recursive: true }); await _extractTar(resolvedOptions, extractedDir, emitter); } async function extractZip() { await _extractZip(resolvedOptions, extractedDir, emitter); } async function clean() { if (resolvedOptions.clean !== false) { node_fs.default.rmSync(resolvedOptions.tempFilePath, { recursive: true }); node_fs.default.rmSync(resolvedOptions.cacheDir, { recursive: true }); } } return { startDownload, checkSha256, extractTar, extractZip, clean, emit: emitter.emit, on: emitter.on, off: emitter.off, all: emitter.all }; } /** * Download the ArkTS SDK. * * @deprecated Deprecate this entry in newer version. * @param options - The options for the download. */ async function download(options) { return await createDownloader(options); } //#endregion Object.defineProperty(exports, 'DownloadError', { enumerable: true, get: function () { return DownloadError; } }); Object.defineProperty(exports, 'SdkArch', { enumerable: true, get: function () { return SdkArch; } }); Object.defineProperty(exports, 'SdkOS', { enumerable: true, get: function () { return SdkOS; } }); Object.defineProperty(exports, 'SdkVersion', { enumerable: true, get: function () { return SdkVersion; } }); Object.defineProperty(exports, '__toESM', { enumerable: true, get: function () { return __toESM; } }); Object.defineProperty(exports, 'createDownloader', { enumerable: true, get: function () { return createDownloader; } }); Object.defineProperty(exports, 'download', { enumerable: true, get: function () { return download; } }); Object.defineProperty(exports, 'getSdkUrl', { enumerable: true, get: function () { return getSdkUrl; } }); Object.defineProperty(exports, 'getSdkUrls', { enumerable: true, get: function () { return getSdkUrls; } }); //# sourceMappingURL=download-CUyFpN2j.cjs.map