@hot-updater/cli-tools 1.0.0-rc.45 → 1.0.0-rc.46
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 +2 -26
- package/dist/index.mjs +28 -307
- package/package.json +5 -5
package/dist/index.d.mts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Readable } from "stream";
|
|
2
2
|
import { Key as Key$1 } from "node:readline";
|
|
3
|
-
import { AnyHotUpdaterPlugin,
|
|
3
|
+
import { AnyHotUpdaterPlugin, BundleSigningAdapter, ConfigInput, ConfiguredDatabase, EngineDatabase, HotUpdaterCoreApi, LocalSigningConfig, Migrator, Platform, PluginClientPlugin, RequiredDeep, SchemaGenerator, SigningConfig, StorageAdapter, StorageAdapterWith, StoragePutResult, ToolingDatabase } from "@hot-updater/plugin-core";
|
|
4
4
|
import { Readable as Readable$1, Writable } from "node:stream";
|
|
5
5
|
import { ManifestArchive } from "@hot-updater/protocol";
|
|
6
6
|
//#region src/BuildLogger.d.ts
|
|
@@ -687,28 +687,6 @@ declare const makeEnv: (newEnvVars: Record<string, EnvVarValue>, filePath?: stri
|
|
|
687
687
|
*/
|
|
688
688
|
declare const moduleSpecifiersOf: (fileName: string, source: string) => string[];
|
|
689
689
|
//#endregion
|
|
690
|
-
//#region src/promoteBundle.d.ts
|
|
691
|
-
type PromoteStorageAdapter = StorageAdapterWith<"get" | "put" | "exists" | "delete">;
|
|
692
|
-
declare const LEGACY_BUNDLE_ERROR = "This OTA bundle was created by a version that does not support manifest.json. Copy bundle is not available.";
|
|
693
|
-
declare function createCopiedBundleArtifacts({ bundle, config, nextBundleId, storageAdapter }: {
|
|
694
|
-
bundle: Bundle;
|
|
695
|
-
config: ConfigResponse;
|
|
696
|
-
nextBundleId: string;
|
|
697
|
-
storageAdapter: PromoteStorageAdapter;
|
|
698
|
-
}): Promise<{
|
|
699
|
-
bundle: {
|
|
700
|
-
id: string;
|
|
701
|
-
metadata: import("@hot-updater/protocol").BundleMetadata | undefined;
|
|
702
|
-
assetBaseStorageUri: string;
|
|
703
|
-
patches: never[];
|
|
704
|
-
manifestFileHash: string;
|
|
705
|
-
manifestStorageUri: string;
|
|
706
|
-
platform: import("@hot-updater/protocol").Platform;
|
|
707
|
-
gitCommitHash: string | null;
|
|
708
|
-
};
|
|
709
|
-
uploadedStorageUris: string[];
|
|
710
|
-
}>;
|
|
711
|
-
//#endregion
|
|
712
690
|
//#region ../../node_modules/.pnpm/@clack+core@1.4.3/node_modules/@clack/core/dist/index.d.mts
|
|
713
691
|
declare const actions: readonly ["up", "down", "left", "right", "space", "enter", "cancel"];
|
|
714
692
|
type Action = (typeof actions)[number];
|
|
@@ -1933,8 +1911,6 @@ declare const getStorageFileByteSize: (filePath: string) => Promise<number>;
|
|
|
1933
1911
|
declare const putStorageFile: (storage: StorageAdapterWith<"put">, key: string, filePath: string) => Promise<StoragePutResult & {
|
|
1934
1912
|
byteSize: number;
|
|
1935
1913
|
}>;
|
|
1936
|
-
declare const writeStorageFile: (storage: StorageAdapterWith<"get">, storageUri: string, filePath: string) => Promise<void>;
|
|
1937
|
-
declare const writeStorageResponseFile: (response: Response, filePath: string) => Promise<void>;
|
|
1938
1914
|
//#endregion
|
|
1939
1915
|
//#region src/transformEnv.d.ts
|
|
1940
1916
|
declare const transformEnv: <T extends Record<string, string>>(filename: string, env: T) => string;
|
|
@@ -1953,4 +1929,4 @@ type TransformTemplateArgs<T extends string> = { [Key in ExtractPlaceholders<T>]
|
|
|
1953
1929
|
*/
|
|
1954
1930
|
declare function transformTemplate<T extends string>(templateString: T, values: TransformTemplateArgs<T>): string;
|
|
1955
1931
|
//#endregion
|
|
1956
|
-
export { AppClientCredential, AppClientPlugin, AssembleServerOptions, AssembledServer, BuildLogger, BuildLoggerConfig, BuildType, BundleSigningSession, ClientAuthSpec, ClientCredentialSpec, ConfigBuilder, ConfigBuilderScaffold, ConfigResponse, CreateHotUpdaterConfigScaffoldFromBuilderOptions, CreateHotUpdaterConfigScaffoldOptions, HOT_UPDATER_SERVER_PACKAGE_VERSION_ENV, HotUpdateDirUtil, HotUpdaterConfigOptions, HotUpdaterConfigScaffold, HotUpdaterInitEnv, HotUpdaterLogWriter, ImportInfo, InitEnvFileError, InitError, InitProviderDefinition, InitProviderInputDefinition, InitProviderInputPersistence,
|
|
1932
|
+
export { AppClientCredential, AppClientPlugin, AssembleServerOptions, AssembledServer, BuildLogger, BuildLoggerConfig, BuildType, BundleSigningSession, ClientAuthSpec, ClientCredentialSpec, ConfigBuilder, ConfigBuilderScaffold, ConfigResponse, CreateHotUpdaterConfigScaffoldFromBuilderOptions, CreateHotUpdaterConfigScaffoldOptions, HOT_UPDATER_SERVER_PACKAGE_VERSION_ENV, HotUpdateDirUtil, HotUpdaterConfigOptions, HotUpdaterConfigScaffold, HotUpdaterInitEnv, HotUpdaterLogWriter, ImportInfo, InitEnvFileError, InitError, InitProviderDefinition, InitProviderInputDefinition, InitProviderInputPersistence, LegacyInfrastructureError, ManagedHelperStatement, ManagedHelperStrategy, MissingInitInputsError, PromptProgress, PromptSpinner, ProviderConfig, ProvisionedClientCredential, ReactNativeMetadata, ReadPackageUpResult, RunInitOptions, ServerClientEndpoint, ServerDefinition, ServerDefinitionError, WriteHotUpdaterConfigResult, assembleServer, assertInfrastructureGenerationAtUrl, assertInfrastructureGenerationPayload, assertInitInputs, assertInitProviderInputs, banner, clientAuthOf, typedColors as colors, confirmInitInputPersistence, copyDirToTmp, createHotUpdaterConfigScaffold, createHotUpdaterConfigScaffoldFromBuilder, createLogWriter, createMigrator, createTarBrTargetFiles, createZip, decryptJson, defineInitProvider, encryptJson, ensureInstallPackages, generateClientCredential, generateSchema, generatesSchema, getAndroidSdkPath, getBundleSigningPublicKey, getCwd, getHotUpdaterEnvValue, getHotUpdaterInitInputEnv, getInitProviderEnvVars, getInitProviderTextPromptValues, getMissingInitInputs, getMissingInitProviderInputs, getPackageManager, getReactNativeMetadatas, getStorageFileByteSize, isServerDefinition, link, loadConfig, loadPlatformConfigs, log, makeEnv, moduleSpecifiersOf, p, prepareBundleSigning, printAppSetup, printBanner, provisionClientCredential, putStorageFile, readBundleSigningPublicKeyFile, readHotUpdaterEnv, readHotUpdaterInitEnv, readPackageUp, renderAppImports, renderAppSetup, renderImportStatements, resolveHotUpdaterServerVersion, resolveInitProviderInput, resolveInitProviderInputs, resolvePackageVersion, serverDefinitionOf, shouldAutoSelectOnlyInitResource, stripAnsi, transformEnv, transformTemplate, writeHotUpdaterConfig, writeHotUpdaterFiles };
|
package/dist/index.mjs
CHANGED
|
@@ -16,14 +16,14 @@ import l__default from "node:readline";
|
|
|
16
16
|
import tty, { ReadStream } from "node:tty";
|
|
17
17
|
import Ei, { appendFileSync, createReadStream, createWriteStream, existsSync, lstatSync, readFileSync, readdirSync, statSync, writeFileSync } from "node:fs";
|
|
18
18
|
import path$1, { basename, dirname as dirname$1, join, posix, win32 } from "node:path";
|
|
19
|
-
import {
|
|
19
|
+
import { createMemoryAdapter, createStorageAdapter, getContentType, isRemoteDatabase, toolingTargetOf } from "@hot-updater/plugin-core";
|
|
20
20
|
import { createHotUpdater } from "@hot-updater/server";
|
|
21
21
|
import os, { constants } from "node:os";
|
|
22
22
|
import crypto$1, { createHash, randomBytes, randomUUID } from "node:crypto";
|
|
23
23
|
import fs$2 from "node:fs/promises";
|
|
24
24
|
import As, { Duplex, PassThrough as PassThrough$1, Readable as Readable$1, Transform, Writable, getDefaultHighWaterMark } from "node:stream";
|
|
25
25
|
import { finished, pipeline } from "node:stream/promises";
|
|
26
|
-
import {
|
|
26
|
+
import { constants as constants$1, createBrotliCompress } from "node:zlib";
|
|
27
27
|
import { EventEmitter as EventEmitter$1, addAbortListener, on, once, setMaxListeners } from "node:events";
|
|
28
28
|
import { StringDecoder } from "node:string_decoder";
|
|
29
29
|
import * as Ms from "zlib";
|
|
@@ -36,7 +36,6 @@ import { serialize } from "node:v8";
|
|
|
36
36
|
import { Buffer as Buffer$2 } from "node:buffer";
|
|
37
37
|
import { Visitor, parseSync } from "oxc-parser";
|
|
38
38
|
import { loadConfig as loadConfig$1 } from "unconfig";
|
|
39
|
-
import { getManifestFileHash, stripBundleArtifactMetadata } from "@hot-updater/protocol";
|
|
40
39
|
import { transformSync } from "oxc-transform";
|
|
41
40
|
//#endregion
|
|
42
41
|
//#region src/colors.ts
|
|
@@ -25107,8 +25106,6 @@ const normalizeImportInfos = (imports) => {
|
|
|
25107
25106
|
return Array.from(collectedImports.entries()).sort(([a], [b]) => {
|
|
25108
25107
|
const isABuild = a.startsWith("@hot-updater/");
|
|
25109
25108
|
if (isABuild !== b.startsWith("@hot-updater/")) return isABuild ? -1 : 1;
|
|
25110
|
-
if (a === "dotenv/config") return -1;
|
|
25111
|
-
if (b === "dotenv/config") return 1;
|
|
25112
25109
|
const isAdminA = a === "firebase-admin";
|
|
25113
25110
|
if (isAdminA !== (b === "firebase-admin")) return isAdminA ? -1 : 1;
|
|
25114
25111
|
return a.localeCompare(b);
|
|
@@ -44141,8 +44138,7 @@ const MANAGED_IMPORT_PACKAGES = /* @__PURE__ */ new Set([
|
|
|
44141
44138
|
const MANAGED_HELPER_NAMES = /* @__PURE__ */ new Set([
|
|
44142
44139
|
"awsOptions",
|
|
44143
44140
|
"commonOptions",
|
|
44144
|
-
"credential"
|
|
44145
|
-
"storageOptions"
|
|
44141
|
+
"credential"
|
|
44146
44142
|
]);
|
|
44147
44143
|
const KNOWN_BUILD_CALLEES = /* @__PURE__ */ new Set([
|
|
44148
44144
|
"bare",
|
|
@@ -45496,305 +45492,6 @@ const moduleSpecifiersOf = (fileName, source) => {
|
|
|
45496
45492
|
])];
|
|
45497
45493
|
};
|
|
45498
45494
|
//#endregion
|
|
45499
|
-
//#region src/storageFiles.ts
|
|
45500
|
-
const getStorageFileByteSize = async (filePath) => {
|
|
45501
|
-
const { size } = await fs$2.stat(filePath, { bigint: true });
|
|
45502
|
-
if (size < 0n || size > BigInt(Number.MAX_SAFE_INTEGER)) throw new Error("Storage file size must be a non-negative safe integer.");
|
|
45503
|
-
return Number(size);
|
|
45504
|
-
};
|
|
45505
|
-
const putStorageFile = async (storage, key, filePath) => {
|
|
45506
|
-
const byteSize = await getStorageFileByteSize(filePath);
|
|
45507
|
-
const source = createReadStream(filePath);
|
|
45508
|
-
try {
|
|
45509
|
-
return {
|
|
45510
|
-
...await storage.put({
|
|
45511
|
-
key: path$1.posix.join(key, path$1.basename(filePath)),
|
|
45512
|
-
body: Readable$1.toWeb(source),
|
|
45513
|
-
contentLength: byteSize,
|
|
45514
|
-
contentType: getContentType(filePath)
|
|
45515
|
-
}),
|
|
45516
|
-
byteSize
|
|
45517
|
-
};
|
|
45518
|
-
} finally {
|
|
45519
|
-
source.destroy();
|
|
45520
|
-
}
|
|
45521
|
-
};
|
|
45522
|
-
const writeStorageFile = async (storage, storageUri, filePath) => {
|
|
45523
|
-
const { response } = await storage.get({ storageUri });
|
|
45524
|
-
if (response === null) throw new Error(`Storage object not found: ${storageUri}`);
|
|
45525
|
-
await writeStorageResponseFile(response, filePath);
|
|
45526
|
-
};
|
|
45527
|
-
const writeStorageResponseFile = async (response, filePath) => {
|
|
45528
|
-
await fs$2.mkdir(path$1.dirname(filePath), { recursive: true });
|
|
45529
|
-
if (response.body === null) {
|
|
45530
|
-
await fs$2.writeFile(filePath, /* @__PURE__ */ new Uint8Array());
|
|
45531
|
-
return;
|
|
45532
|
-
}
|
|
45533
|
-
try {
|
|
45534
|
-
await pipeline(Readable$1.fromWeb(response.body), createWriteStream(filePath));
|
|
45535
|
-
} catch (error) {
|
|
45536
|
-
await fs$2.rm(filePath, { force: true });
|
|
45537
|
-
throw error;
|
|
45538
|
-
}
|
|
45539
|
-
};
|
|
45540
|
-
//#endregion
|
|
45541
|
-
//#region src/promoteBundle.ts
|
|
45542
|
-
const LEGACY_BUNDLE_ERROR = "This OTA bundle was created by a version that does not support manifest.json. Copy bundle is not available.";
|
|
45543
|
-
const SIGNED_HASH_PREFIX = "sig:";
|
|
45544
|
-
const PROMOTE_ASSET_CONCURRENCY = 8;
|
|
45545
|
-
function isSignedFileHash(fileHash) {
|
|
45546
|
-
return fileHash.startsWith(SIGNED_HASH_PREFIX);
|
|
45547
|
-
}
|
|
45548
|
-
async function getFileHash(filepath) {
|
|
45549
|
-
const file = await fs$2.readFile(filepath);
|
|
45550
|
-
return crypto$1.createHash("sha256").update(file).digest("hex");
|
|
45551
|
-
}
|
|
45552
|
-
async function runWithConcurrency(items, concurrency, task) {
|
|
45553
|
-
let nextIndex = 0;
|
|
45554
|
-
const workerCount = Math.min(concurrency, items.length);
|
|
45555
|
-
await Promise.all(Array.from({ length: workerCount }, async () => {
|
|
45556
|
-
while (nextIndex < items.length) {
|
|
45557
|
-
const itemIndex = nextIndex;
|
|
45558
|
-
nextIndex += 1;
|
|
45559
|
-
await task(items[itemIndex]);
|
|
45560
|
-
}
|
|
45561
|
-
}));
|
|
45562
|
-
}
|
|
45563
|
-
function verifySignedFileHash({ actualFileHash, publicKey, signedFileHash }) {
|
|
45564
|
-
try {
|
|
45565
|
-
return crypto$1.verify("RSA-SHA256", Buffer.from(actualFileHash, "hex"), publicKey, Buffer.from(signedFileHash.slice(4), "base64"));
|
|
45566
|
-
} catch {
|
|
45567
|
-
return false;
|
|
45568
|
-
}
|
|
45569
|
-
}
|
|
45570
|
-
const getRelativeStorageDir = (relativePath) => {
|
|
45571
|
-
const normalized = relativePath.replace(/\\/g, "/");
|
|
45572
|
-
const dirname = path$1.posix.dirname(normalized);
|
|
45573
|
-
return dirname === "." ? "" : dirname;
|
|
45574
|
-
};
|
|
45575
|
-
function resolvePreparedUploadPath(rootDir, assetPath) {
|
|
45576
|
-
const normalizedAssetPath = assetPath.replaceAll("\\", "/");
|
|
45577
|
-
const outputPath = path$1.resolve(rootDir, "upload-artifacts", `${normalizedAssetPath}.br`);
|
|
45578
|
-
const relativePath = path$1.relative(rootDir, outputPath);
|
|
45579
|
-
if (relativePath.startsWith("..") || path$1.isAbsolute(relativePath) || normalizedAssetPath.startsWith("/")) throw new Error(`Invalid manifest asset path: ${assetPath}`);
|
|
45580
|
-
return outputPath;
|
|
45581
|
-
}
|
|
45582
|
-
async function prepareManifestAssetUploadFile({ assetPath, sourcePath, workDir }) {
|
|
45583
|
-
if (getManifestAssetDownloadPath(assetPath) === assetPath) return sourcePath;
|
|
45584
|
-
const uploadPath = resolvePreparedUploadPath(workDir, assetPath);
|
|
45585
|
-
await fs$2.mkdir(path$1.dirname(uploadPath), { recursive: true });
|
|
45586
|
-
await pipeline(createReadStream(sourcePath), createBrotliCompress({ params: { [constants$1.BROTLI_PARAM_QUALITY]: 11 } }), createWriteStream(uploadPath));
|
|
45587
|
-
return uploadPath;
|
|
45588
|
-
}
|
|
45589
|
-
async function prepareContentAddressedUploadFile({ sourcePath, storagePath, workDir }) {
|
|
45590
|
-
const filename = path$1.posix.basename(storagePath);
|
|
45591
|
-
if (path$1.basename(sourcePath) === filename) return sourcePath;
|
|
45592
|
-
const uploadPath = path$1.join(workDir, "upload-artifacts", "content-addressed", filename);
|
|
45593
|
-
await fs$2.mkdir(path$1.dirname(uploadPath), { recursive: true });
|
|
45594
|
-
await fs$2.copyFile(sourcePath, uploadPath);
|
|
45595
|
-
return uploadPath;
|
|
45596
|
-
}
|
|
45597
|
-
async function prepareManifestAssetUploadTargets({ extractDir, manifest, workDir }) {
|
|
45598
|
-
const targets = /* @__PURE__ */ new Map();
|
|
45599
|
-
const assetPaths = Object.keys(manifest.assets ?? {}).sort((left, right) => left.localeCompare(right));
|
|
45600
|
-
for (const assetPath of assetPaths) {
|
|
45601
|
-
const asset = manifest.assets?.[assetPath];
|
|
45602
|
-
if (!asset?.fileHash) throw new Error(`Manifest file hash not found for ${assetPath}`);
|
|
45603
|
-
const sourcePath = resolveExtractedPath(extractDir, assetPath);
|
|
45604
|
-
const uploadSourcePath = await prepareManifestAssetUploadFile({
|
|
45605
|
-
assetPath,
|
|
45606
|
-
sourcePath,
|
|
45607
|
-
workDir
|
|
45608
|
-
});
|
|
45609
|
-
const downloadByteSize = await getStorageFileByteSize(uploadSourcePath);
|
|
45610
|
-
const downloadPath = getManifestAssetDownloadPath(assetPath);
|
|
45611
|
-
const downloadFileHash = downloadPath !== assetPath ? await getFileHash(uploadSourcePath) : void 0;
|
|
45612
|
-
if (downloadFileHash !== void 0 && !isContentAddressedAssetFileHash(downloadFileHash)) throw new Error(`Prepared asset hash must be a lowercase SHA-256 hash: ${assetPath}`);
|
|
45613
|
-
const nextAsset = {
|
|
45614
|
-
...asset,
|
|
45615
|
-
byteSize: (await fs$2.stat(sourcePath)).size,
|
|
45616
|
-
downloadByteSize
|
|
45617
|
-
};
|
|
45618
|
-
delete nextAsset.downloadFileHash;
|
|
45619
|
-
if (downloadFileHash !== void 0) nextAsset.downloadFileHash = downloadFileHash;
|
|
45620
|
-
manifest.assets[assetPath] = nextAsset;
|
|
45621
|
-
const storagePath = getManifestAssetStoragePath({
|
|
45622
|
-
assetPath: downloadPath,
|
|
45623
|
-
downloadFileHash,
|
|
45624
|
-
fileHash: asset.fileHash
|
|
45625
|
-
});
|
|
45626
|
-
const contentAddressedUploadPath = await prepareContentAddressedUploadFile({
|
|
45627
|
-
sourcePath: uploadSourcePath,
|
|
45628
|
-
storagePath,
|
|
45629
|
-
workDir
|
|
45630
|
-
});
|
|
45631
|
-
targets.set(storagePath, {
|
|
45632
|
-
assetPath: downloadPath,
|
|
45633
|
-
downloadFileHash,
|
|
45634
|
-
fileHash: asset.fileHash,
|
|
45635
|
-
storagePath,
|
|
45636
|
-
uploadSourcePath: contentAddressedUploadPath
|
|
45637
|
-
});
|
|
45638
|
-
}
|
|
45639
|
-
return [...targets.values()];
|
|
45640
|
-
}
|
|
45641
|
-
function resolveExtractedPath(rootDir, entryName) {
|
|
45642
|
-
const normalizedEntryName = entryName.replaceAll("\\", "/");
|
|
45643
|
-
const entryPath = path$1.resolve(rootDir, normalizedEntryName);
|
|
45644
|
-
const relativePath = path$1.relative(rootDir, entryPath);
|
|
45645
|
-
if (relativePath.startsWith("..") || path$1.isAbsolute(relativePath) || normalizedEntryName.startsWith("/")) throw new Error(`Invalid manifest asset path: ${entryName}`);
|
|
45646
|
-
return entryPath;
|
|
45647
|
-
}
|
|
45648
|
-
async function downloadStorageObject(storageUri, storageAdapter, outputPath) {
|
|
45649
|
-
const protocol = new URL(storageUri).protocol.replace(":", "");
|
|
45650
|
-
if (storageAdapter?.protocol === protocol) {
|
|
45651
|
-
await writeStorageFile(storageAdapter, storageUri, outputPath);
|
|
45652
|
-
return;
|
|
45653
|
-
}
|
|
45654
|
-
if (protocol === "http" || protocol === "https") {
|
|
45655
|
-
await downloadFromUrl(storageUri, outputPath);
|
|
45656
|
-
return;
|
|
45657
|
-
}
|
|
45658
|
-
throw new Error(`No storage adapter for protocol: ${protocol}`);
|
|
45659
|
-
}
|
|
45660
|
-
async function downloadFromUrl(fileUrl, filePath) {
|
|
45661
|
-
const response = await fetch(fileUrl);
|
|
45662
|
-
if (!response.ok) throw new Error(`Failed to download storage object: ${response.statusText}`);
|
|
45663
|
-
await writeStorageResponseFile(response, filePath);
|
|
45664
|
-
}
|
|
45665
|
-
async function downloadManifestAssets({ bundle, manifest, outputDir, storageAdapter, workDir }) {
|
|
45666
|
-
await runWithConcurrency(Object.keys(manifest.assets ?? {}).sort((left, right) => left.localeCompare(right)), PROMOTE_ASSET_CONCURRENCY, async (assetPath) => {
|
|
45667
|
-
const asset = manifest.assets?.[assetPath];
|
|
45668
|
-
if (!asset?.fileHash) throw new Error(`Manifest file hash not found for ${assetPath}`);
|
|
45669
|
-
const downloadPath = getManifestAssetDownloadPath(assetPath);
|
|
45670
|
-
const storageUri = resolveManifestAssetStorageUri({
|
|
45671
|
-
assetBaseStorageUri: bundle.assetBaseStorageUri,
|
|
45672
|
-
assetPath: downloadPath,
|
|
45673
|
-
downloadFileHash: asset.downloadFileHash,
|
|
45674
|
-
fileHash: asset.fileHash
|
|
45675
|
-
});
|
|
45676
|
-
const transferPath = resolveExtractedPath(workDir, `downloads/${downloadPath}`);
|
|
45677
|
-
await fs$2.mkdir(path$1.dirname(transferPath), { recursive: true });
|
|
45678
|
-
await downloadStorageObject(storageUri, storageAdapter, transferPath);
|
|
45679
|
-
if (asset.downloadFileHash) {
|
|
45680
|
-
if (await getFileHash(transferPath) !== asset.downloadFileHash.toLowerCase()) throw new Error(`Manifest download hash mismatch for ${assetPath}`);
|
|
45681
|
-
}
|
|
45682
|
-
const outputPath = resolveExtractedPath(outputDir, assetPath);
|
|
45683
|
-
await fs$2.mkdir(path$1.dirname(outputPath), { recursive: true });
|
|
45684
|
-
if (downloadPath === assetPath) await fs$2.copyFile(transferPath, outputPath);
|
|
45685
|
-
else await fs$2.writeFile(outputPath, brotliDecompressSync(await fs$2.readFile(transferPath)));
|
|
45686
|
-
if (await getFileHash(outputPath) !== asset.fileHash.toLowerCase()) throw new Error(`Manifest file hash mismatch for ${assetPath}`);
|
|
45687
|
-
});
|
|
45688
|
-
}
|
|
45689
|
-
async function createCopiedBundleArtifacts({ bundle, config, nextBundleId, storageAdapter }) {
|
|
45690
|
-
const workDir = await fs$2.mkdtemp(path$1.join(os.tmpdir(), "hot-updater-console-promote-"));
|
|
45691
|
-
const extractDir = path$1.join(workDir, "bundle");
|
|
45692
|
-
const sourceManifestPath = path$1.join(workDir, "source-manifest.json");
|
|
45693
|
-
const manifestPath = path$1.join(extractDir, "manifest.json");
|
|
45694
|
-
const uploadedStorageUris = [];
|
|
45695
|
-
await fs$2.mkdir(extractDir, { recursive: true });
|
|
45696
|
-
try {
|
|
45697
|
-
await downloadStorageObject(bundle.manifestStorageUri, storageAdapter, sourceManifestPath);
|
|
45698
|
-
const actualManifestHash = await getFileHash(sourceManifestPath);
|
|
45699
|
-
const signingSession = await prepareBundleSigning(config.signing);
|
|
45700
|
-
if (isSignedFileHash(bundle.manifestFileHash)) {
|
|
45701
|
-
if (!signingSession) throw new Error("Cannot copy a signed bundle without enabled bundle signing configuration.");
|
|
45702
|
-
if (!verifySignedFileHash({
|
|
45703
|
-
actualFileHash: actualManifestHash,
|
|
45704
|
-
publicKey: signingSession.publicKey,
|
|
45705
|
-
signedFileHash: bundle.manifestFileHash
|
|
45706
|
-
})) throw new Error("Source manifest signature verification failed.");
|
|
45707
|
-
} else if (actualManifestHash !== bundle.manifestFileHash.toLowerCase()) throw new Error("Source manifest file hash verification failed.");
|
|
45708
|
-
const manifest = JSON.parse(await fs$2.readFile(sourceManifestPath, "utf8"));
|
|
45709
|
-
if (!manifest.assets || typeof manifest.assets !== "object") throw new Error(LEGACY_BUNDLE_ERROR);
|
|
45710
|
-
await downloadManifestAssets({
|
|
45711
|
-
bundle,
|
|
45712
|
-
manifest,
|
|
45713
|
-
outputDir: extractDir,
|
|
45714
|
-
storageAdapter,
|
|
45715
|
-
workDir
|
|
45716
|
-
});
|
|
45717
|
-
manifest.bundleId = nextBundleId;
|
|
45718
|
-
const assetPaths = Object.keys(manifest.assets ?? {}).sort((left, right) => left.localeCompare(right));
|
|
45719
|
-
const sourceIsSigned = isSignedFileHash(getManifestFileHash(bundle));
|
|
45720
|
-
const manifestHasSignatures = assetPaths.some((assetPath) => Boolean(manifest.assets?.[assetPath]?.signature));
|
|
45721
|
-
if (!signingSession && (sourceIsSigned || manifestHasSignatures)) throw new Error("Cannot copy a signed bundle without enabled bundle signing configuration.");
|
|
45722
|
-
if (signingSession) {
|
|
45723
|
-
await runWithConcurrency(assetPaths, PROMOTE_ASSET_CONCURRENCY, async (assetPath) => {
|
|
45724
|
-
const asset = manifest.assets?.[assetPath];
|
|
45725
|
-
if (!asset?.fileHash) throw new Error(`Manifest file hash not found for ${assetPath}`);
|
|
45726
|
-
if (await getFileHash(resolveExtractedPath(extractDir, assetPath)) !== asset.fileHash.toLowerCase()) throw new Error(`Manifest file hash mismatch for ${assetPath}`);
|
|
45727
|
-
});
|
|
45728
|
-
await runWithConcurrency(assetPaths, PROMOTE_ASSET_CONCURRENCY, async (assetPath) => {
|
|
45729
|
-
const asset = manifest.assets?.[assetPath];
|
|
45730
|
-
if (!asset?.fileHash) throw new Error(`Manifest file hash not found for ${assetPath}`);
|
|
45731
|
-
asset.signature = await signingSession.signFileHash(asset.fileHash);
|
|
45732
|
-
});
|
|
45733
|
-
}
|
|
45734
|
-
const assetUploadTargets = await prepareManifestAssetUploadTargets({
|
|
45735
|
-
extractDir,
|
|
45736
|
-
manifest,
|
|
45737
|
-
workDir
|
|
45738
|
-
});
|
|
45739
|
-
const archivePath = path$1.join(workDir, "bundle.tar.br");
|
|
45740
|
-
manifest.archive = await createTarBrTargetFiles({
|
|
45741
|
-
outfile: archivePath,
|
|
45742
|
-
targetFiles: assetPaths.map((name) => ({
|
|
45743
|
-
name,
|
|
45744
|
-
path: resolveExtractedPath(extractDir, name)
|
|
45745
|
-
}))
|
|
45746
|
-
});
|
|
45747
|
-
await fs$2.writeFile(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`);
|
|
45748
|
-
const manifestHash = await getFileHash(manifestPath);
|
|
45749
|
-
const nextManifestFileHash = signingSession ? `${SIGNED_HASH_PREFIX}${await signingSession.signFileHash(manifestHash)}` : manifestHash;
|
|
45750
|
-
const archiveUpload = await putStorageFile(storageAdapter, createBundleStorageKey(nextBundleId), archivePath);
|
|
45751
|
-
uploadedStorageUris.push(archiveUpload.storageUri);
|
|
45752
|
-
const manifestUpload = await putStorageFile(storageAdapter, createBundleStorageKey(nextBundleId), manifestPath);
|
|
45753
|
-
uploadedStorageUris.push(manifestUpload.storageUri);
|
|
45754
|
-
const assetBaseStorageUri = createStorageRootUriWithPath(manifestUpload.storageUri, nextBundleId, "assets");
|
|
45755
|
-
for (const assetUploadTarget of assetUploadTargets) {
|
|
45756
|
-
const storageUri = resolveManifestAssetStorageUri({
|
|
45757
|
-
assetBaseStorageUri,
|
|
45758
|
-
assetPath: assetUploadTarget.assetPath,
|
|
45759
|
-
downloadFileHash: assetUploadTarget.downloadFileHash,
|
|
45760
|
-
fileHash: assetUploadTarget.fileHash
|
|
45761
|
-
});
|
|
45762
|
-
const { exists } = await storageAdapter.exists({ storageUri });
|
|
45763
|
-
if (!exists) await putStorageFile(storageAdapter, getRelativeStorageDir(assetUploadTarget.storagePath) ? `assets/${getRelativeStorageDir(assetUploadTarget.storagePath)}` : "assets", assetUploadTarget.uploadSourcePath);
|
|
45764
|
-
}
|
|
45765
|
-
return {
|
|
45766
|
-
bundle: {
|
|
45767
|
-
...bundle,
|
|
45768
|
-
id: nextBundleId,
|
|
45769
|
-
metadata: stripBundleArtifactMetadata(bundle.metadata),
|
|
45770
|
-
assetBaseStorageUri,
|
|
45771
|
-
patches: [],
|
|
45772
|
-
manifestFileHash: nextManifestFileHash,
|
|
45773
|
-
manifestStorageUri: manifestUpload.storageUri
|
|
45774
|
-
},
|
|
45775
|
-
uploadedStorageUris
|
|
45776
|
-
};
|
|
45777
|
-
} catch (error) {
|
|
45778
|
-
await deleteUploadedCopy(storageAdapter, uploadedStorageUris);
|
|
45779
|
-
throw error;
|
|
45780
|
-
} finally {
|
|
45781
|
-
await fs$2.rm(workDir, {
|
|
45782
|
-
recursive: true,
|
|
45783
|
-
force: true
|
|
45784
|
-
});
|
|
45785
|
-
}
|
|
45786
|
-
}
|
|
45787
|
-
async function deleteUploadedCopy(storageAdapter, storageUris) {
|
|
45788
|
-
if (storageUris.length === 0) return;
|
|
45789
|
-
for (const storageUri of new Set(storageUris)) try {
|
|
45790
|
-
const protocol = new URL(storageUri).protocol.replace(":", "");
|
|
45791
|
-
if (storageAdapter.protocol === protocol) await storageAdapter.delete({ storageUri });
|
|
45792
|
-
else if (protocol !== "http" && protocol !== "https") throw new Error(`No storage adapter for protocol: ${protocol}`);
|
|
45793
|
-
} catch (error) {
|
|
45794
|
-
console.error("Failed to delete uploaded bundle copy:", error);
|
|
45795
|
-
}
|
|
45796
|
-
}
|
|
45797
|
-
//#endregion
|
|
45798
45495
|
//#region src/resolvePackageVersion.ts
|
|
45799
45496
|
const require$1 = createRequire(import.meta.url);
|
|
45800
45497
|
const HOT_UPDATER_SERVER_PACKAGE_VERSION_ENV = "HOT_UPDATER_SERVER_PACKAGE_VERSION";
|
|
@@ -45836,6 +45533,30 @@ const resolveHotUpdaterServerVersion = (currentPackageName, options) => {
|
|
|
45836
45533
|
return process.env["HOT_UPDATER_SERVER_PACKAGE_VERSION"]?.trim() || resolvePackageVersion(currentPackageName, options);
|
|
45837
45534
|
};
|
|
45838
45535
|
//#endregion
|
|
45536
|
+
//#region src/storageFiles.ts
|
|
45537
|
+
const getStorageFileByteSize = async (filePath) => {
|
|
45538
|
+
const { size } = await fs$2.stat(filePath, { bigint: true });
|
|
45539
|
+
if (size < 0n || size > BigInt(Number.MAX_SAFE_INTEGER)) throw new Error("Storage file size must be a non-negative safe integer.");
|
|
45540
|
+
return Number(size);
|
|
45541
|
+
};
|
|
45542
|
+
const putStorageFile = async (storage, key, filePath) => {
|
|
45543
|
+
const byteSize = await getStorageFileByteSize(filePath);
|
|
45544
|
+
const source = createReadStream(filePath);
|
|
45545
|
+
try {
|
|
45546
|
+
return {
|
|
45547
|
+
...await storage.put({
|
|
45548
|
+
key: path$1.posix.join(key, path$1.basename(filePath)),
|
|
45549
|
+
body: Readable$1.toWeb(source),
|
|
45550
|
+
contentLength: byteSize,
|
|
45551
|
+
contentType: getContentType(filePath)
|
|
45552
|
+
}),
|
|
45553
|
+
byteSize
|
|
45554
|
+
};
|
|
45555
|
+
} finally {
|
|
45556
|
+
source.destroy();
|
|
45557
|
+
}
|
|
45558
|
+
};
|
|
45559
|
+
//#endregion
|
|
45839
45560
|
//#region src/transformEnv.ts
|
|
45840
45561
|
const transformEnv = (filename, env) => {
|
|
45841
45562
|
const code = fs.readFileSync(filename, "utf-8");
|
|
@@ -45862,4 +45583,4 @@ function transformTemplate(templateString, values) {
|
|
|
45862
45583
|
return result;
|
|
45863
45584
|
}
|
|
45864
45585
|
//#endregion
|
|
45865
|
-
export { BuildLogger, ConfigBuilder, HOT_UPDATER_SERVER_PACKAGE_VERSION_ENV, HotUpdateDirUtil, InitEnvFileError, InitError,
|
|
45586
|
+
export { BuildLogger, ConfigBuilder, HOT_UPDATER_SERVER_PACKAGE_VERSION_ENV, HotUpdateDirUtil, InitEnvFileError, InitError, LegacyInfrastructureError, MissingInitInputsError, ServerDefinitionError, assembleServer, assertInfrastructureGenerationAtUrl, assertInfrastructureGenerationPayload, assertInitInputs, assertInitProviderInputs, banner, clientAuthOf, typedColors as colors, confirmInitInputPersistence, copyDirToTmp, createHotUpdaterConfigScaffold, createHotUpdaterConfigScaffoldFromBuilder, createLogWriter, createMigrator, createTarBrTargetFiles, createZip, decryptJson, defineInitProvider, encryptJson, ensureInstallPackages, generateClientCredential, generateSchema, generatesSchema, getAndroidSdkPath, getBundleSigningPublicKey, getCwd, getHotUpdaterEnvValue, getHotUpdaterInitInputEnv, getInitProviderEnvVars, getInitProviderTextPromptValues, getMissingInitInputs, getMissingInitProviderInputs, getPackageManager, getReactNativeMetadatas, getStorageFileByteSize, isServerDefinition, link, loadConfig, loadPlatformConfigs, log, makeEnv, moduleSpecifiersOf, p, prepareBundleSigning, printAppSetup, printBanner, provisionClientCredential, putStorageFile, readBundleSigningPublicKeyFile, readHotUpdaterEnv, readHotUpdaterInitEnv, readPackageUp, renderAppImports, renderAppSetup, renderImportStatements, resolveHotUpdaterServerVersion, resolveInitProviderInput, resolveInitProviderInputs, resolvePackageVersion, serverDefinitionOf, shouldAutoSelectOnlyInitResource, stripAnsi, transformEnv, transformTemplate, writeHotUpdaterConfig, writeHotUpdaterFiles };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hot-updater/cli-tools",
|
|
3
|
-
"version": "1.0.0-rc.
|
|
3
|
+
"version": "1.0.0-rc.46",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=20.19.0"
|
|
@@ -49,9 +49,9 @@
|
|
|
49
49
|
"oxc-parser": "0.141.0",
|
|
50
50
|
"oxc-transform": "0.141.0",
|
|
51
51
|
"unconfig": "7.5.0",
|
|
52
|
-
"@hot-updater/protocol": "1.0.0-rc.
|
|
53
|
-
"@hot-updater/plugin-core": "1.0.0-rc.
|
|
54
|
-
"@hot-updater/server": "1.0.0-rc.
|
|
52
|
+
"@hot-updater/protocol": "1.0.0-rc.46",
|
|
53
|
+
"@hot-updater/plugin-core": "1.0.0-rc.46",
|
|
54
|
+
"@hot-updater/server": "1.0.0-rc.46"
|
|
55
55
|
},
|
|
56
56
|
"devDependencies": {
|
|
57
57
|
"@clack/prompts": "1.7.0",
|
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
"tar": "^7.5.16",
|
|
66
66
|
"verkit": "0.4.0",
|
|
67
67
|
"workspace-tools": "^0.41.7",
|
|
68
|
-
"@hot-updater/test-utils": "1.0.0-rc.
|
|
68
|
+
"@hot-updater/test-utils": "1.0.0-rc.46"
|
|
69
69
|
},
|
|
70
70
|
"inlinedDependencies": {
|
|
71
71
|
"@babel/code-frame": "7.29.0",
|