@hot-updater/cli-tools 0.30.7 → 0.30.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +58 -2
- package/dist/index.mjs +244 -36
- package/package.json +3 -3
package/dist/index.d.mts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Readable } from "stream";
|
|
2
2
|
import { Key as Key$1 } from "node:readline";
|
|
3
3
|
import { Readable as Readable$1, Writable } from "node:stream";
|
|
4
|
-
import { ConfigInput, Platform, RequiredDeep } from "@hot-updater/plugin-core";
|
|
4
|
+
import { Bundle, ConfigInput, DatabasePlugin, Platform, RequiredDeep, StoragePlugin } from "@hot-updater/plugin-core";
|
|
5
5
|
|
|
6
6
|
//#region src/BuildLogger.d.ts
|
|
7
7
|
type LinePattern = string | RegExp;
|
|
@@ -366,6 +366,62 @@ declare const makeEnv: (newEnvVars: Record<string, EnvVarValue>, filePath?: stri
|
|
|
366
366
|
preserveKeys?: string[];
|
|
367
367
|
}) => Promise<string>;
|
|
368
368
|
//#endregion
|
|
369
|
+
//#region ../core/dist/index.d.mts
|
|
370
|
+
//#endregion
|
|
371
|
+
//#region src/types.d.ts
|
|
372
|
+
type Platform$1 = "ios" | "android";
|
|
373
|
+
type BundleMetadata = {
|
|
374
|
+
app_version?: string;
|
|
375
|
+
};
|
|
376
|
+
//#endregion
|
|
377
|
+
//#region src/promoteBundle.d.ts
|
|
378
|
+
declare const LEGACY_BUNDLE_ERROR = "This OTA bundle was created by a version that does not support manifest.json. Copy bundle is not available.";
|
|
379
|
+
interface PromoteBundleInput {
|
|
380
|
+
action: "copy" | "move";
|
|
381
|
+
bundleId: string;
|
|
382
|
+
nextBundleId?: string;
|
|
383
|
+
targetChannel: string;
|
|
384
|
+
}
|
|
385
|
+
interface PromoteBundleDependencies {
|
|
386
|
+
config: ConfigResponse;
|
|
387
|
+
databasePlugin: DatabasePlugin;
|
|
388
|
+
storagePlugin: StoragePlugin | null;
|
|
389
|
+
}
|
|
390
|
+
declare function createCopiedBundleArchive({
|
|
391
|
+
bundle,
|
|
392
|
+
config,
|
|
393
|
+
nextBundleId,
|
|
394
|
+
storagePlugin,
|
|
395
|
+
targetChannel
|
|
396
|
+
}: {
|
|
397
|
+
bundle: Bundle;
|
|
398
|
+
config: ConfigResponse;
|
|
399
|
+
nextBundleId: string;
|
|
400
|
+
storagePlugin: StoragePlugin;
|
|
401
|
+
targetChannel: string;
|
|
402
|
+
}): Promise<{
|
|
403
|
+
id: string;
|
|
404
|
+
channel: string;
|
|
405
|
+
storageUri: string;
|
|
406
|
+
fileHash: string;
|
|
407
|
+
platform: Platform$1;
|
|
408
|
+
shouldForceUpdate: boolean;
|
|
409
|
+
enabled: boolean;
|
|
410
|
+
gitCommitHash: string | null;
|
|
411
|
+
message: string | null;
|
|
412
|
+
targetAppVersion: string | null;
|
|
413
|
+
fingerprintHash: string | null;
|
|
414
|
+
metadata?: BundleMetadata;
|
|
415
|
+
rolloutCohortCount?: number | null;
|
|
416
|
+
targetCohorts?: string[] | null;
|
|
417
|
+
}>;
|
|
418
|
+
declare function promoteBundle({
|
|
419
|
+
action,
|
|
420
|
+
bundleId,
|
|
421
|
+
nextBundleId,
|
|
422
|
+
targetChannel
|
|
423
|
+
}: PromoteBundleInput, deps: PromoteBundleDependencies): Promise<Bundle>;
|
|
424
|
+
//#endregion
|
|
369
425
|
//#region ../../node_modules/.pnpm/@clack+core@1.0.1/node_modules/@clack/core/dist/index.d.mts
|
|
370
426
|
declare const actions: readonly ["up", "down", "left", "right", "space", "enter", "cancel"];
|
|
371
427
|
type Action = (typeof actions)[number];
|
|
@@ -919,4 +975,4 @@ type TransformTemplateArgs<T extends string> = { [Key in ExtractPlaceholders<T>]
|
|
|
919
975
|
*/
|
|
920
976
|
declare function transformTemplate<T extends string>(templateString: T, values: TransformTemplateArgs<T>): string;
|
|
921
977
|
//#endregion
|
|
922
|
-
export { BuildLogger, BuildLoggerConfig, BuildType, ConfigBuilder, ConfigBuilderScaffold, ConfigResponse, CreateHotUpdaterConfigScaffoldFromBuilderOptions, CreateHotUpdaterConfigScaffoldOptions, HOT_UPDATER_SERVER_PACKAGE_VERSION_ENV, HotUpdateDirUtil, HotUpdaterConfigOptions, HotUpdaterConfigScaffold, HotUpdaterLogWriter, IConfigBuilder, ImportInfo, ManagedHelperStatement, ManagedHelperStrategy, PromptProgress, PromptSpinner, ProviderConfig, ReactNativeMetadata, WriteHotUpdaterConfigResult, banner, picocolors as colors, copyDirToTmp, createHotUpdaterConfigScaffold, createHotUpdaterConfigScaffoldFromBuilder, createLogWriter, createTarBr, createTarBrTargetFiles, createTarGz, createTarGzTargetFiles, createZip, createZipTargetFiles, decryptJson, encryptJson, ensureInstallPackages, getAndroidSdkPath, getCwd, getPackageManager, getReactNativeMetadatas, link, loadConfig, log, makeEnv, index_d_exports as p, printBanner, renderImportStatements, resolveHotUpdaterServerVersion, resolvePackageVersion, stripAnsi, transformEnv, transformTemplate, writeHotUpdaterConfig };
|
|
978
|
+
export { BuildLogger, BuildLoggerConfig, BuildType, ConfigBuilder, ConfigBuilderScaffold, ConfigResponse, CreateHotUpdaterConfigScaffoldFromBuilderOptions, CreateHotUpdaterConfigScaffoldOptions, HOT_UPDATER_SERVER_PACKAGE_VERSION_ENV, HotUpdateDirUtil, HotUpdaterConfigOptions, HotUpdaterConfigScaffold, HotUpdaterLogWriter, IConfigBuilder, ImportInfo, LEGACY_BUNDLE_ERROR, ManagedHelperStatement, ManagedHelperStrategy, PromoteBundleDependencies, PromoteBundleInput, PromptProgress, PromptSpinner, ProviderConfig, ReactNativeMetadata, WriteHotUpdaterConfigResult, banner, picocolors as colors, copyDirToTmp, createCopiedBundleArchive, createHotUpdaterConfigScaffold, createHotUpdaterConfigScaffoldFromBuilder, createLogWriter, createTarBr, createTarBrTargetFiles, createTarGz, createTarGzTargetFiles, createZip, createZipTargetFiles, decryptJson, encryptJson, ensureInstallPackages, getAndroidSdkPath, getCwd, getPackageManager, getReactNativeMetadatas, link, loadConfig, log, makeEnv, index_d_exports as p, printBanner, promoteBundle, renderImportStatements, resolveHotUpdaterServerVersion, resolvePackageVersion, stripAnsi, transformEnv, transformTemplate, writeHotUpdaterConfig };
|
package/dist/index.mjs
CHANGED
|
@@ -23,8 +23,8 @@ import { EventEmitter as EventEmitter$1, addAbortListener, on, once, setMaxListe
|
|
|
23
23
|
import Stream, { Duplex, PassThrough as PassThrough$1, Readable as Readable$1, Transform, Writable, getDefaultHighWaterMark } from "node:stream";
|
|
24
24
|
import { StringDecoder } from "node:string_decoder";
|
|
25
25
|
import assert$1 from "node:assert";
|
|
26
|
-
import { randomBytes } from "node:crypto";
|
|
27
|
-
import
|
|
26
|
+
import crypto$1, { randomBytes } from "node:crypto";
|
|
27
|
+
import fs$3 from "node:fs/promises";
|
|
28
28
|
import { fileURLToPath } from "node:url";
|
|
29
29
|
import { ChildProcess, execFile, spawn, spawnSync } from "node:child_process";
|
|
30
30
|
import { scheduler, setImmediate as setImmediate$1, setTimeout as setTimeout$1 } from "node:timers/promises";
|
|
@@ -33,6 +33,8 @@ import { finished } from "node:stream/promises";
|
|
|
33
33
|
import { Buffer as Buffer$2 } from "node:buffer";
|
|
34
34
|
import ts from "typescript";
|
|
35
35
|
import { loadConfig as loadConfig$1 } from "unconfig";
|
|
36
|
+
import { brotliDecompressSync } from "node:zlib";
|
|
37
|
+
import { createUUIDv7, detectCompressionFormat } from "@hot-updater/plugin-core";
|
|
36
38
|
import { transformSync } from "oxc-transform";
|
|
37
39
|
//#region ../../node_modules/.pnpm/picocolors@1.1.1/node_modules/picocolors/picocolors.js
|
|
38
40
|
var require_picocolors = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
@@ -5408,12 +5410,12 @@ var require_sync$5 = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
5408
5410
|
var require_fs$2 = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
5409
5411
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5410
5412
|
exports.createFileSystemAdapter = exports.FILE_SYSTEM_ADAPTER = void 0;
|
|
5411
|
-
const fs$
|
|
5413
|
+
const fs$9 = __require("fs");
|
|
5412
5414
|
exports.FILE_SYSTEM_ADAPTER = {
|
|
5413
|
-
lstat: fs$
|
|
5414
|
-
stat: fs$
|
|
5415
|
-
lstatSync: fs$
|
|
5416
|
-
statSync: fs$
|
|
5415
|
+
lstat: fs$9.lstat,
|
|
5416
|
+
stat: fs$9.stat,
|
|
5417
|
+
lstatSync: fs$9.lstatSync,
|
|
5418
|
+
statSync: fs$9.statSync
|
|
5417
5419
|
};
|
|
5418
5420
|
function createFileSystemAdapter(fsMethods) {
|
|
5419
5421
|
if (fsMethods === void 0) return exports.FILE_SYSTEM_ADAPTER;
|
|
@@ -5731,14 +5733,14 @@ var require_sync$4 = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
5731
5733
|
var require_fs = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
5732
5734
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
5733
5735
|
exports.createFileSystemAdapter = exports.FILE_SYSTEM_ADAPTER = void 0;
|
|
5734
|
-
const fs$
|
|
5736
|
+
const fs$8 = __require("fs");
|
|
5735
5737
|
exports.FILE_SYSTEM_ADAPTER = {
|
|
5736
|
-
lstat: fs$
|
|
5737
|
-
stat: fs$
|
|
5738
|
-
lstatSync: fs$
|
|
5739
|
-
statSync: fs$
|
|
5740
|
-
readdir: fs$
|
|
5741
|
-
readdirSync: fs$
|
|
5738
|
+
lstat: fs$8.lstat,
|
|
5739
|
+
stat: fs$8.stat,
|
|
5740
|
+
lstatSync: fs$8.lstatSync,
|
|
5741
|
+
statSync: fs$8.statSync,
|
|
5742
|
+
readdir: fs$8.readdir,
|
|
5743
|
+
readdirSync: fs$8.readdirSync
|
|
5742
5744
|
};
|
|
5743
5745
|
function createFileSystemAdapter(fsMethods) {
|
|
5744
5746
|
if (fsMethods === void 0) return exports.FILE_SYSTEM_ADAPTER;
|
|
@@ -6908,7 +6910,7 @@ var require_sync = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
6908
6910
|
var require_settings = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
6909
6911
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6910
6912
|
exports.DEFAULT_FILE_SYSTEM_ADAPTER = void 0;
|
|
6911
|
-
const fs$
|
|
6913
|
+
const fs$7 = __require("fs");
|
|
6912
6914
|
const os$1 = __require("os");
|
|
6913
6915
|
/**
|
|
6914
6916
|
* The `os.cpus` method can return zero. We expect the number of cores to be greater than zero.
|
|
@@ -6916,12 +6918,12 @@ var require_settings = /* @__PURE__ */ __commonJSMin(((exports) => {
|
|
|
6916
6918
|
*/
|
|
6917
6919
|
const CPU_COUNT = Math.max(os$1.cpus().length, 1);
|
|
6918
6920
|
exports.DEFAULT_FILE_SYSTEM_ADAPTER = {
|
|
6919
|
-
lstat: fs$
|
|
6920
|
-
lstatSync: fs$
|
|
6921
|
-
stat: fs$
|
|
6922
|
-
statSync: fs$
|
|
6923
|
-
readdir: fs$
|
|
6924
|
-
readdirSync: fs$
|
|
6921
|
+
lstat: fs$7.lstat,
|
|
6922
|
+
lstatSync: fs$7.lstatSync,
|
|
6923
|
+
stat: fs$7.stat,
|
|
6924
|
+
statSync: fs$7.statSync,
|
|
6925
|
+
readdir: fs$7.readdir,
|
|
6926
|
+
readdirSync: fs$7.readdirSync
|
|
6925
6927
|
};
|
|
6926
6928
|
var Settings = class {
|
|
6927
6929
|
constructor(_options = {}) {
|
|
@@ -25988,7 +25990,7 @@ const mkdir = (dir, opt, cb) => {
|
|
|
25988
25990
|
else cb();
|
|
25989
25991
|
};
|
|
25990
25992
|
if (dir === cwd) return checkCwd(dir, done);
|
|
25991
|
-
if (preserve) return
|
|
25993
|
+
if (preserve) return fs$3.mkdir(dir, {
|
|
25992
25994
|
mode,
|
|
25993
25995
|
recursive: true
|
|
25994
25996
|
}).then((made) => done(null, made ?? void 0), done);
|
|
@@ -26799,7 +26801,7 @@ const extractFile = (opt, _) => {
|
|
|
26799
26801
|
});
|
|
26800
26802
|
});
|
|
26801
26803
|
};
|
|
26802
|
-
makeCommand(extractFileSync, extractFile, (opt) => new UnpackSync(opt), (opt) => new Unpack(opt), (opt, files) => {
|
|
26804
|
+
const extract = makeCommand(extractFileSync, extractFile, (opt) => new UnpackSync(opt), (opt) => new Unpack(opt), (opt, files) => {
|
|
26803
26805
|
if (files?.length) filesFilter(opt, files);
|
|
26804
26806
|
});
|
|
26805
26807
|
//#endregion
|
|
@@ -36656,7 +36658,7 @@ const handleCommand = (filePath, rawArguments, rawOptions) => {
|
|
|
36656
36658
|
var require_windows = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
36657
36659
|
module.exports = isexe;
|
|
36658
36660
|
isexe.sync = sync;
|
|
36659
|
-
var fs$
|
|
36661
|
+
var fs$6 = __require("fs");
|
|
36660
36662
|
function checkPathExt(path, options) {
|
|
36661
36663
|
var pathext = options.pathExt !== void 0 ? options.pathExt : process.env.PATHEXT;
|
|
36662
36664
|
if (!pathext) return true;
|
|
@@ -36673,12 +36675,12 @@ var require_windows = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
36673
36675
|
return checkPathExt(path, options);
|
|
36674
36676
|
}
|
|
36675
36677
|
function isexe(path, options, cb) {
|
|
36676
|
-
fs$
|
|
36678
|
+
fs$6.stat(path, function(er, stat) {
|
|
36677
36679
|
cb(er, er ? false : checkStat(stat, path, options));
|
|
36678
36680
|
});
|
|
36679
36681
|
}
|
|
36680
36682
|
function sync(path, options) {
|
|
36681
|
-
return checkStat(fs$
|
|
36683
|
+
return checkStat(fs$6.statSync(path), path, options);
|
|
36682
36684
|
}
|
|
36683
36685
|
}));
|
|
36684
36686
|
//#endregion
|
|
@@ -36686,14 +36688,14 @@ var require_windows = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
|
36686
36688
|
var require_mode = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
36687
36689
|
module.exports = isexe;
|
|
36688
36690
|
isexe.sync = sync;
|
|
36689
|
-
var fs$
|
|
36691
|
+
var fs$5 = __require("fs");
|
|
36690
36692
|
function isexe(path, options, cb) {
|
|
36691
|
-
fs$
|
|
36693
|
+
fs$5.stat(path, function(er, stat) {
|
|
36692
36694
|
cb(er, er ? false : checkStat(stat, options));
|
|
36693
36695
|
});
|
|
36694
36696
|
}
|
|
36695
36697
|
function sync(path, options) {
|
|
36696
|
-
return checkStat(fs$
|
|
36698
|
+
return checkStat(fs$5.statSync(path), options);
|
|
36697
36699
|
}
|
|
36698
36700
|
function checkStat(stat, options) {
|
|
36699
36701
|
return stat.isFile() && checkMode(stat, options);
|
|
@@ -36908,16 +36910,16 @@ var require_shebang_command = /* @__PURE__ */ __commonJSMin(((exports, module) =
|
|
|
36908
36910
|
//#endregion
|
|
36909
36911
|
//#region ../../node_modules/.pnpm/cross-spawn@7.0.6/node_modules/cross-spawn/lib/util/readShebang.js
|
|
36910
36912
|
var require_readShebang = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
36911
|
-
const fs$
|
|
36913
|
+
const fs$4 = __require("fs");
|
|
36912
36914
|
const shebangCommand = require_shebang_command();
|
|
36913
36915
|
function readShebang(command) {
|
|
36914
36916
|
const size = 150;
|
|
36915
36917
|
const buffer = Buffer.alloc(size);
|
|
36916
36918
|
let fd;
|
|
36917
36919
|
try {
|
|
36918
|
-
fd = fs$
|
|
36919
|
-
fs$
|
|
36920
|
-
fs$
|
|
36920
|
+
fd = fs$4.openSync(command, "r");
|
|
36921
|
+
fs$4.readSync(fd, buffer, 0, size, 0);
|
|
36922
|
+
fs$4.closeSync(fd);
|
|
36921
36923
|
} catch (e) {}
|
|
36922
36924
|
return shebangCommand(buffer.toString());
|
|
36923
36925
|
}
|
|
@@ -42055,7 +42057,7 @@ async function findUp(name, { cwd = process$1.cwd(), type = "file", stopAt } = {
|
|
|
42055
42057
|
while (directory) {
|
|
42056
42058
|
const filePath = isAbsoluteName ? name : path$1.join(directory, name);
|
|
42057
42059
|
try {
|
|
42058
|
-
const stats = await
|
|
42060
|
+
const stats = await fs$3.stat(filePath);
|
|
42059
42061
|
if (type === "file" && stats.isFile() || type === "directory" && stats.isDirectory()) return filePath;
|
|
42060
42062
|
} catch {}
|
|
42061
42063
|
if (directory === stopAt || directory === root) break;
|
|
@@ -47124,7 +47126,7 @@ const _readPackage = (file, normalize) => {
|
|
|
47124
47126
|
return json;
|
|
47125
47127
|
};
|
|
47126
47128
|
async function readPackage({ cwd, normalize = true } = {}) {
|
|
47127
|
-
return _readPackage(await
|
|
47129
|
+
return _readPackage(await fs$3.readFile(getPackagePath(cwd), "utf8"), normalize);
|
|
47128
47130
|
}
|
|
47129
47131
|
//#endregion
|
|
47130
47132
|
//#region ../../node_modules/.pnpm/read-package-up@11.0.0/node_modules/read-package-up/index.js
|
|
@@ -48116,6 +48118,212 @@ const makeEnv = async (newEnvVars, filePath = ".env.hotupdater", options) => {
|
|
|
48116
48118
|
}
|
|
48117
48119
|
};
|
|
48118
48120
|
//#endregion
|
|
48121
|
+
//#region src/promoteBundle.ts
|
|
48122
|
+
const LEGACY_BUNDLE_ERROR = "This OTA bundle was created by a version that does not support manifest.json. Copy bundle is not available.";
|
|
48123
|
+
const SIGNED_HASH_PREFIX = "sig:";
|
|
48124
|
+
function isSignedFileHash(fileHash) {
|
|
48125
|
+
return fileHash.startsWith(SIGNED_HASH_PREFIX);
|
|
48126
|
+
}
|
|
48127
|
+
async function getFileHash(filepath) {
|
|
48128
|
+
const file = await fs$3.readFile(filepath);
|
|
48129
|
+
return crypto$1.createHash("sha256").update(file).digest("hex");
|
|
48130
|
+
}
|
|
48131
|
+
async function signFileHash(fileHash, privateKeyPath) {
|
|
48132
|
+
const privateKeyPEM = await fs$3.readFile(privateKeyPath, "utf8");
|
|
48133
|
+
const sign = crypto$1.createSign("RSA-SHA256");
|
|
48134
|
+
sign.update(Buffer.from(fileHash, "hex"));
|
|
48135
|
+
sign.end();
|
|
48136
|
+
return `${SIGNED_HASH_PREFIX}${sign.sign(privateKeyPEM).toString("base64")}`;
|
|
48137
|
+
}
|
|
48138
|
+
function getArchiveFilename(storageUri) {
|
|
48139
|
+
const { pathname } = new URL(storageUri);
|
|
48140
|
+
return path$1.basename(pathname) || "bundle.zip";
|
|
48141
|
+
}
|
|
48142
|
+
function resolveExtractedPath(rootDir, entryName) {
|
|
48143
|
+
const normalizedEntryName = entryName.replaceAll("\\", "/");
|
|
48144
|
+
const entryPath = path$1.resolve(rootDir, normalizedEntryName);
|
|
48145
|
+
const relativePath = path$1.relative(rootDir, entryPath);
|
|
48146
|
+
if (relativePath.startsWith("..") || path$1.isAbsolute(relativePath) || normalizedEntryName.startsWith("/")) throw new Error(`Invalid archive entry path: ${entryName}`);
|
|
48147
|
+
return entryPath;
|
|
48148
|
+
}
|
|
48149
|
+
async function downloadArchive(fileUrl, archivePath) {
|
|
48150
|
+
const response = await fetch(fileUrl);
|
|
48151
|
+
if (!response.ok) throw new Error(`Failed to download bundle archive: ${response.statusText}`);
|
|
48152
|
+
const archiveBuffer = Buffer.from(await response.arrayBuffer());
|
|
48153
|
+
await fs$3.writeFile(archivePath, archiveBuffer);
|
|
48154
|
+
}
|
|
48155
|
+
async function extractZipArchive(archivePath, extractDir) {
|
|
48156
|
+
const zip = await import_lib$1.default.loadAsync(await fs$3.readFile(archivePath));
|
|
48157
|
+
const entries = Object.values(zip.files).sort((left, right) => left.name.localeCompare(right.name));
|
|
48158
|
+
for (const entry of entries) {
|
|
48159
|
+
const outputPath = resolveExtractedPath(extractDir, entry.name);
|
|
48160
|
+
if (entry.dir) {
|
|
48161
|
+
await fs$3.mkdir(outputPath, { recursive: true });
|
|
48162
|
+
continue;
|
|
48163
|
+
}
|
|
48164
|
+
await fs$3.mkdir(path$1.dirname(outputPath), { recursive: true });
|
|
48165
|
+
await fs$3.writeFile(outputPath, await entry.async("nodebuffer"));
|
|
48166
|
+
}
|
|
48167
|
+
}
|
|
48168
|
+
async function extractTarBrArchive(archivePath, extractDir) {
|
|
48169
|
+
const tarPath = path$1.join(extractDir, "bundle.tar");
|
|
48170
|
+
const tarBuffer = brotliDecompressSync(await fs$3.readFile(archivePath));
|
|
48171
|
+
await fs$3.writeFile(tarPath, tarBuffer);
|
|
48172
|
+
try {
|
|
48173
|
+
await extract({
|
|
48174
|
+
file: tarPath,
|
|
48175
|
+
cwd: extractDir,
|
|
48176
|
+
gzip: false,
|
|
48177
|
+
strict: true
|
|
48178
|
+
});
|
|
48179
|
+
} finally {
|
|
48180
|
+
await fs$3.rm(tarPath, { force: true });
|
|
48181
|
+
}
|
|
48182
|
+
}
|
|
48183
|
+
async function extractArchive(archivePath, extractDir) {
|
|
48184
|
+
const { format } = detectCompressionFormat(path$1.basename(archivePath));
|
|
48185
|
+
switch (format) {
|
|
48186
|
+
case "zip":
|
|
48187
|
+
await extractZipArchive(archivePath, extractDir);
|
|
48188
|
+
return format;
|
|
48189
|
+
case "tar.gz":
|
|
48190
|
+
await extract({
|
|
48191
|
+
file: archivePath,
|
|
48192
|
+
cwd: extractDir,
|
|
48193
|
+
gzip: true,
|
|
48194
|
+
strict: true
|
|
48195
|
+
});
|
|
48196
|
+
return format;
|
|
48197
|
+
case "tar.br":
|
|
48198
|
+
await extractTarBrArchive(archivePath, extractDir);
|
|
48199
|
+
return format;
|
|
48200
|
+
}
|
|
48201
|
+
}
|
|
48202
|
+
async function getArchiveTargetFiles(bundleDir) {
|
|
48203
|
+
const entries = await fs$3.readdir(bundleDir, { withFileTypes: true });
|
|
48204
|
+
entries.sort((left, right) => left.name.localeCompare(right.name));
|
|
48205
|
+
return entries.map((entry) => ({
|
|
48206
|
+
path: path$1.join(bundleDir, entry.name),
|
|
48207
|
+
name: entry.name
|
|
48208
|
+
}));
|
|
48209
|
+
}
|
|
48210
|
+
async function createArchiveFromDirectory(sourceDir, archivePath, format) {
|
|
48211
|
+
const targetFiles = await getArchiveTargetFiles(sourceDir);
|
|
48212
|
+
switch (format) {
|
|
48213
|
+
case "zip":
|
|
48214
|
+
await createZipTargetFiles({
|
|
48215
|
+
outfile: archivePath,
|
|
48216
|
+
targetFiles
|
|
48217
|
+
});
|
|
48218
|
+
return;
|
|
48219
|
+
case "tar.gz":
|
|
48220
|
+
await createTarGzTargetFiles({
|
|
48221
|
+
outfile: archivePath,
|
|
48222
|
+
targetFiles
|
|
48223
|
+
});
|
|
48224
|
+
return;
|
|
48225
|
+
case "tar.br":
|
|
48226
|
+
await createTarBrTargetFiles({
|
|
48227
|
+
outfile: archivePath,
|
|
48228
|
+
targetFiles
|
|
48229
|
+
});
|
|
48230
|
+
return;
|
|
48231
|
+
}
|
|
48232
|
+
}
|
|
48233
|
+
async function rewriteManifestBundleId(extractDir, nextBundleId) {
|
|
48234
|
+
const manifestPath = path$1.join(extractDir, "manifest.json");
|
|
48235
|
+
try {
|
|
48236
|
+
await fs$3.access(manifestPath);
|
|
48237
|
+
} catch {
|
|
48238
|
+
throw new Error(LEGACY_BUNDLE_ERROR);
|
|
48239
|
+
}
|
|
48240
|
+
const manifest = JSON.parse(await fs$3.readFile(manifestPath, "utf8"));
|
|
48241
|
+
manifest.bundleId = nextBundleId;
|
|
48242
|
+
await fs$3.writeFile(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`);
|
|
48243
|
+
}
|
|
48244
|
+
async function resolveBundleDownloadUrl(storageUri, storagePlugin) {
|
|
48245
|
+
const protocol = new URL(storageUri).protocol.replace(":", "");
|
|
48246
|
+
if (protocol === "http" || protocol === "https") return storageUri;
|
|
48247
|
+
if (!storagePlugin) throw new Error("Storage plugin is not configured");
|
|
48248
|
+
if (storagePlugin.supportedProtocol !== protocol) throw new Error(`No storage plugin for protocol: ${protocol}`);
|
|
48249
|
+
const { fileUrl } = await storagePlugin.getDownloadUrl(storageUri);
|
|
48250
|
+
if (!fileUrl) throw new Error("Storage plugin returned empty fileUrl");
|
|
48251
|
+
return fileUrl;
|
|
48252
|
+
}
|
|
48253
|
+
async function createCopiedBundleArchive({ bundle, config, nextBundleId, storagePlugin, targetChannel }) {
|
|
48254
|
+
const downloadUrl = await resolveBundleDownloadUrl(bundle.storageUri, storagePlugin);
|
|
48255
|
+
const archiveFilename = getArchiveFilename(bundle.storageUri);
|
|
48256
|
+
const workDir = await fs$3.mkdtemp(path$1.join(os.tmpdir(), "hot-updater-console-promote-"));
|
|
48257
|
+
const sourceArchivePath = path$1.join(workDir, archiveFilename);
|
|
48258
|
+
const extractDir = path$1.join(workDir, "bundle");
|
|
48259
|
+
const outputArchivePath = path$1.join(workDir, archiveFilename);
|
|
48260
|
+
await fs$3.mkdir(extractDir, { recursive: true });
|
|
48261
|
+
try {
|
|
48262
|
+
await downloadArchive(downloadUrl, sourceArchivePath);
|
|
48263
|
+
const format = await extractArchive(sourceArchivePath, extractDir);
|
|
48264
|
+
await rewriteManifestBundleId(extractDir, nextBundleId);
|
|
48265
|
+
await fs$3.rm(sourceArchivePath, { force: true });
|
|
48266
|
+
await createArchiveFromDirectory(extractDir, outputArchivePath, format);
|
|
48267
|
+
const fileHash = await getFileHash(outputArchivePath);
|
|
48268
|
+
if (isSignedFileHash(bundle.fileHash) && !config.signing?.enabled) throw new Error("Cannot copy a signed bundle without signing.privateKeyPath in hot-updater.config.ts");
|
|
48269
|
+
const nextFileHash = config.signing?.enabled && config.signing.privateKeyPath ? await signFileHash(fileHash, config.signing.privateKeyPath) : fileHash;
|
|
48270
|
+
const { storageUri } = await storagePlugin.upload(nextBundleId, outputArchivePath);
|
|
48271
|
+
return {
|
|
48272
|
+
...bundle,
|
|
48273
|
+
id: nextBundleId,
|
|
48274
|
+
channel: targetChannel,
|
|
48275
|
+
storageUri,
|
|
48276
|
+
fileHash: nextFileHash
|
|
48277
|
+
};
|
|
48278
|
+
} finally {
|
|
48279
|
+
await fs$3.rm(workDir, {
|
|
48280
|
+
recursive: true,
|
|
48281
|
+
force: true
|
|
48282
|
+
});
|
|
48283
|
+
}
|
|
48284
|
+
}
|
|
48285
|
+
async function deleteUploadedCopy(storagePlugin, storageUri) {
|
|
48286
|
+
if (!storageUri) return;
|
|
48287
|
+
try {
|
|
48288
|
+
await storagePlugin.delete(storageUri);
|
|
48289
|
+
} catch (error) {
|
|
48290
|
+
console.error("Failed to delete uploaded bundle copy:", error);
|
|
48291
|
+
}
|
|
48292
|
+
}
|
|
48293
|
+
async function promoteBundle({ action, bundleId, nextBundleId, targetChannel }, deps) {
|
|
48294
|
+
const normalizedTargetChannel = targetChannel.trim();
|
|
48295
|
+
if (!normalizedTargetChannel) throw new Error("Target channel is required");
|
|
48296
|
+
const bundle = await deps.databasePlugin.getBundleById(bundleId);
|
|
48297
|
+
if (!bundle) throw new Error("Bundle not found");
|
|
48298
|
+
if (bundle.channel === normalizedTargetChannel) throw new Error("Target channel must be different from the current channel");
|
|
48299
|
+
if (action === "move") {
|
|
48300
|
+
await deps.databasePlugin.updateBundle(bundleId, { channel: normalizedTargetChannel });
|
|
48301
|
+
await deps.databasePlugin.commitBundle();
|
|
48302
|
+
const updatedBundle = await deps.databasePlugin.getBundleById(bundleId);
|
|
48303
|
+
if (!updatedBundle) throw new Error("Promoted bundle not found");
|
|
48304
|
+
return updatedBundle;
|
|
48305
|
+
}
|
|
48306
|
+
if (!deps.storagePlugin) throw new Error("Storage plugin is not configured");
|
|
48307
|
+
const resolvedNextBundleId = nextBundleId?.trim() || createUUIDv7();
|
|
48308
|
+
const copiedBundle = await createCopiedBundleArchive({
|
|
48309
|
+
bundle,
|
|
48310
|
+
config: deps.config,
|
|
48311
|
+
nextBundleId: resolvedNextBundleId,
|
|
48312
|
+
storagePlugin: deps.storagePlugin,
|
|
48313
|
+
targetChannel: normalizedTargetChannel
|
|
48314
|
+
});
|
|
48315
|
+
let uploadedStorageUri = copiedBundle.storageUri;
|
|
48316
|
+
try {
|
|
48317
|
+
await deps.databasePlugin.appendBundle(copiedBundle);
|
|
48318
|
+
await deps.databasePlugin.commitBundle();
|
|
48319
|
+
uploadedStorageUri = null;
|
|
48320
|
+
return copiedBundle;
|
|
48321
|
+
} catch (error) {
|
|
48322
|
+
await deleteUploadedCopy(deps.storagePlugin, uploadedStorageUri);
|
|
48323
|
+
throw error;
|
|
48324
|
+
}
|
|
48325
|
+
}
|
|
48326
|
+
//#endregion
|
|
48119
48327
|
//#region src/resolvePackageVersion.ts
|
|
48120
48328
|
const require$1 = createRequire(import.meta.url);
|
|
48121
48329
|
const HOT_UPDATER_SERVER_PACKAGE_VERSION_ENV = "HOT_UPDATER_SERVER_PACKAGE_VERSION";
|
|
@@ -48182,4 +48390,4 @@ function transformTemplate(templateString, values) {
|
|
|
48182
48390
|
}
|
|
48183
48391
|
//#endregion
|
|
48184
48392
|
var colors = import_picocolors.default;
|
|
48185
|
-
export { BuildLogger, ConfigBuilder, HOT_UPDATER_SERVER_PACKAGE_VERSION_ENV, HotUpdateDirUtil, banner, colors, copyDirToTmp, createHotUpdaterConfigScaffold, createHotUpdaterConfigScaffoldFromBuilder, createLogWriter, createTarBr, createTarBrTargetFiles, createTarGz, createTarGzTargetFiles, createZip, createZipTargetFiles, decryptJson, encryptJson, ensureInstallPackages, getAndroidSdkPath, getCwd, getPackageManager, getReactNativeMetadatas, link, loadConfig, log, makeEnv, dist_exports as p, printBanner, renderImportStatements, resolveHotUpdaterServerVersion, resolvePackageVersion, stripAnsi, transformEnv, transformTemplate, writeHotUpdaterConfig };
|
|
48393
|
+
export { BuildLogger, ConfigBuilder, HOT_UPDATER_SERVER_PACKAGE_VERSION_ENV, HotUpdateDirUtil, LEGACY_BUNDLE_ERROR, banner, colors, copyDirToTmp, createCopiedBundleArchive, createHotUpdaterConfigScaffold, createHotUpdaterConfigScaffoldFromBuilder, createLogWriter, createTarBr, createTarBrTargetFiles, createTarGz, createTarGzTargetFiles, createZip, createZipTargetFiles, decryptJson, encryptJson, ensureInstallPackages, getAndroidSdkPath, getCwd, getPackageManager, getReactNativeMetadatas, link, loadConfig, log, makeEnv, dist_exports as p, printBanner, promoteBundle, renderImportStatements, resolveHotUpdaterServerVersion, resolvePackageVersion, stripAnsi, transformEnv, transformTemplate, writeHotUpdaterConfig };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hot-updater/cli-tools",
|
|
3
|
-
"version": "0.30.
|
|
3
|
+
"version": "0.30.9",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=20.19.0"
|
|
@@ -46,7 +46,7 @@
|
|
|
46
46
|
"oxc-transform": "0.121.0",
|
|
47
47
|
"typescript": "6.0.2",
|
|
48
48
|
"unconfig": "7.5.0",
|
|
49
|
-
"@hot-updater/plugin-core": "0.30.
|
|
49
|
+
"@hot-updater/plugin-core": "0.30.9"
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
|
52
52
|
"@clack/prompts": "1.0.1",
|
|
@@ -62,7 +62,7 @@
|
|
|
62
62
|
"semver": "^7.6.3",
|
|
63
63
|
"tar": "^7.5.1",
|
|
64
64
|
"workspace-tools": "^0.36.4",
|
|
65
|
-
"@hot-updater/test-utils": "0.30.
|
|
65
|
+
"@hot-updater/test-utils": "0.30.9"
|
|
66
66
|
},
|
|
67
67
|
"inlinedDependencies": {
|
|
68
68
|
"@babel/code-frame": "7.29.0",
|