@arkts/sdk-downloader
Version:
Download and extract the ArkTS SDK.
515 lines (508 loc) • 20.1 kB
JavaScript
//#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