@hot-updater/cli-tools 1.0.0-rc.14 → 1.0.0-rc.16
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 +33 -33
- package/dist/index.mjs +204 -407
- package/package.json +5 -5
package/dist/index.d.mts
CHANGED
|
@@ -2,6 +2,7 @@ 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
4
|
import { Bundle, BundleSigningPlugin, ConfigInput, LocalSigningConfig, Platform, RequiredDeep, SigningConfig, StoragePluginWith, StoragePutResult } from "@hot-updater/plugin-core";
|
|
5
|
+
import { ManifestArchive } from "@hot-updater/core";
|
|
5
6
|
//#region src/BuildLogger.d.ts
|
|
6
7
|
type LinePattern = string | RegExp;
|
|
7
8
|
interface BuildLoggerConfig {
|
|
@@ -163,41 +164,16 @@ declare const copyDirToTmp: (dir: string, childDirname?: string) => Promise<{
|
|
|
163
164
|
}>;
|
|
164
165
|
//#endregion
|
|
165
166
|
//#region src/createTarBr.d.ts
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
path: string;
|
|
169
|
-
name: string;
|
|
170
|
-
}[];
|
|
171
|
-
outfile: string;
|
|
172
|
-
}) => Promise<string>;
|
|
173
|
-
declare const createTarBr: ({ outfile, targetDir, excludeExts }: {
|
|
174
|
-
targetDir: string;
|
|
167
|
+
/** Build the one supported bulk transport from the exact manifest file set. */
|
|
168
|
+
declare function createTarBrTargetFiles({ outfile, targetFiles }: {
|
|
175
169
|
outfile: string;
|
|
176
|
-
excludeExts?: string[];
|
|
177
|
-
}) => Promise<string>;
|
|
178
|
-
//#endregion
|
|
179
|
-
//#region src/createTarGz.d.ts
|
|
180
|
-
declare const createTarGzTargetFiles: ({ outfile, targetFiles }: {
|
|
181
170
|
targetFiles: {
|
|
182
171
|
path: string;
|
|
183
172
|
name: string;
|
|
184
173
|
}[];
|
|
185
|
-
|
|
186
|
-
}) => Promise<string>;
|
|
187
|
-
declare const createTarGz: ({ outfile, targetDir, excludeExts }: {
|
|
188
|
-
targetDir: string;
|
|
189
|
-
outfile: string;
|
|
190
|
-
excludeExts?: string[];
|
|
191
|
-
}) => Promise<string>;
|
|
174
|
+
}): Promise<ManifestArchive>;
|
|
192
175
|
//#endregion
|
|
193
176
|
//#region src/createZip.d.ts
|
|
194
|
-
declare const createZipTargetFiles: ({ outfile, targetFiles }: {
|
|
195
|
-
targetFiles: {
|
|
196
|
-
path: string;
|
|
197
|
-
name: string;
|
|
198
|
-
}[];
|
|
199
|
-
outfile: string;
|
|
200
|
-
}) => Promise<string>;
|
|
201
177
|
declare const createZip: ({ outfile, targetDir, excludeExts }: {
|
|
202
178
|
targetDir: string;
|
|
203
179
|
outfile: string;
|
|
@@ -295,6 +271,33 @@ declare const readHotUpdaterInitEnv: (cwd: string, envFile?: string) => Promise<
|
|
|
295
271
|
declare const readHotUpdaterEnv: (cwd: string) => Promise<Readonly<Record<string, string>>>;
|
|
296
272
|
declare const getHotUpdaterEnvValue: (env: Readonly<Record<string, string>>, key: string) => string | undefined;
|
|
297
273
|
//#endregion
|
|
274
|
+
//#region src/hotUpdaterPlugins.d.ts
|
|
275
|
+
/** Where `hot-updater init` writes a managed server's plugin list. */
|
|
276
|
+
declare const HOT_UPDATER_PLUGINS_PATH = "hotUpdater.plugins.ts";
|
|
277
|
+
/**
|
|
278
|
+
* The plugins file for a managed provider: a re-export of the fixed list its
|
|
279
|
+
* package ships, which its prebuilt server runs too.
|
|
280
|
+
*/
|
|
281
|
+
declare const renderHotUpdaterPlugins: (pkg: string) => string;
|
|
282
|
+
type WriteHotUpdaterPluginsResult = {
|
|
283
|
+
readonly status: "created" | "unchanged";
|
|
284
|
+
readonly path: string;
|
|
285
|
+
} | {
|
|
286
|
+
readonly status: "skipped";
|
|
287
|
+
readonly path: string;
|
|
288
|
+
readonly reason: string;
|
|
289
|
+
};
|
|
290
|
+
/** Writes the plugins file; an existing file that differs is kept. */
|
|
291
|
+
declare const writeHotUpdaterPlugins: (pkg: string, filePath?: string) => Promise<WriteHotUpdaterPluginsResult>;
|
|
292
|
+
/** Writes the plugins file for `pkg` and reports what happened. */
|
|
293
|
+
declare const generateHotUpdaterPlugins: (pkg: string, filePath?: string) => Promise<WriteHotUpdaterPluginsResult>;
|
|
294
|
+
/**
|
|
295
|
+
* The plugins a project's `hotUpdater.plugins.ts` exports, which its server
|
|
296
|
+
* runs; undefined when the project has no such file. The console assembles
|
|
297
|
+
* them in process to read Insights and API keys as the server would.
|
|
298
|
+
*/
|
|
299
|
+
declare const loadHotUpdaterPlugins: (cwd?: string) => Promise<readonly unknown[] | undefined>;
|
|
300
|
+
//#endregion
|
|
298
301
|
//#region src/HotUpdateDirUtil.d.ts
|
|
299
302
|
declare const HotUpdateDirUtil: {
|
|
300
303
|
readonly dirName: ".hot-updater";
|
|
@@ -467,7 +470,7 @@ declare const makeEnv: (newEnvVars: Record<string, EnvVarValue>, filePath?: stri
|
|
|
467
470
|
//#region src/promoteBundle.d.ts
|
|
468
471
|
type PromoteStoragePlugin = StoragePluginWith<"get" | "put" | "exists" | "delete">;
|
|
469
472
|
declare const LEGACY_BUNDLE_ERROR = "This OTA bundle was created by a version that does not support manifest.json. Copy bundle is not available.";
|
|
470
|
-
declare function
|
|
473
|
+
declare function createCopiedBundleArtifacts({ bundle, config, nextBundleId, storagePlugin }: {
|
|
471
474
|
bundle: Bundle;
|
|
472
475
|
config: ConfigResponse;
|
|
473
476
|
nextBundleId: string;
|
|
@@ -475,9 +478,6 @@ declare function createCopiedBundleArchive({ bundle, config, nextBundleId, stora
|
|
|
475
478
|
}): Promise<{
|
|
476
479
|
bundle: {
|
|
477
480
|
id: string;
|
|
478
|
-
archiveByteSize: number;
|
|
479
|
-
storageUri: string;
|
|
480
|
-
fileHash: string;
|
|
481
481
|
metadata: import("@hot-updater/core").BundleMetadata | undefined;
|
|
482
482
|
assetBaseStorageUri: string;
|
|
483
483
|
patches: never[];
|
|
@@ -1733,4 +1733,4 @@ type TransformTemplateArgs<T extends string> = { [Key in ExtractPlaceholders<T>]
|
|
|
1733
1733
|
*/
|
|
1734
1734
|
declare function transformTemplate<T extends string>(templateString: T, values: TransformTemplateArgs<T>): string;
|
|
1735
1735
|
//#endregion
|
|
1736
|
-
export { BuildLogger, BuildLoggerConfig, BuildType, BundleSigningSession, ConfigBuilder, ConfigBuilderScaffold, ConfigResponse, CreateHotUpdaterConfigScaffoldFromBuilderOptions, CreateHotUpdaterConfigScaffoldOptions, HOT_UPDATER_SERVER_PACKAGE_VERSION_ENV, HotUpdateDirUtil, HotUpdaterConfigOptions, HotUpdaterConfigScaffold, HotUpdaterInitEnv, HotUpdaterLogWriter, IConfigBuilder, ImportInfo, InitEnvFileError, InitError, InitProviderDefinition, InitProviderInputDefinition, InitProviderInputPersistence, LEGACY_BUNDLE_ERROR, LegacyInfrastructureError, ManagedHelperStatement, ManagedHelperStrategy, MissingInitInputsError, PromptProgress, PromptSpinner, ProviderConfig, ReactNativeMetadata, ReadPackageUpResult, RunInitOptions, WriteHotUpdaterConfigResult, assertInfrastructureGenerationAtUrl, assertInfrastructureGenerationPayload, assertInitInputs, assertInitProviderInputs, banner, typedColors as colors, confirmInitInputPersistence, copyDirToTmp,
|
|
1736
|
+
export { BuildLogger, BuildLoggerConfig, BuildType, BundleSigningSession, ConfigBuilder, ConfigBuilderScaffold, ConfigResponse, CreateHotUpdaterConfigScaffoldFromBuilderOptions, CreateHotUpdaterConfigScaffoldOptions, HOT_UPDATER_PLUGINS_PATH, HOT_UPDATER_SERVER_PACKAGE_VERSION_ENV, HotUpdateDirUtil, HotUpdaterConfigOptions, HotUpdaterConfigScaffold, HotUpdaterInitEnv, HotUpdaterLogWriter, IConfigBuilder, ImportInfo, InitEnvFileError, InitError, InitProviderDefinition, InitProviderInputDefinition, InitProviderInputPersistence, LEGACY_BUNDLE_ERROR, LegacyInfrastructureError, ManagedHelperStatement, ManagedHelperStrategy, MissingInitInputsError, PromptProgress, PromptSpinner, ProviderConfig, ReactNativeMetadata, ReadPackageUpResult, RunInitOptions, WriteHotUpdaterConfigResult, WriteHotUpdaterPluginsResult, assertInfrastructureGenerationAtUrl, assertInfrastructureGenerationPayload, assertInitInputs, assertInitProviderInputs, banner, typedColors as colors, confirmInitInputPersistence, copyDirToTmp, createCopiedBundleArtifacts, createHotUpdaterConfigScaffold, createHotUpdaterConfigScaffoldFromBuilder, createLogWriter, createTarBrTargetFiles, createZip, decryptJson, defineInitProvider, encryptJson, ensureInstallPackages, formatApiKeyNote, generateHotUpdaterPlugins, getAndroidSdkPath, getBundleSigningPublicKey, getCwd, getHotUpdaterEnvValue, getHotUpdaterInitInputEnv, getInitProviderEnvVars, getInitProviderTextPromptValues, getMissingInitInputs, getMissingInitProviderInputs, getPackageManager, getReactNativeMetadatas, getStorageFileByteSize, link, loadConfig, loadHotUpdaterPlugins, log, makeEnv, p, prepareBundleSigning, printBanner, putStorageFile, readBundleSigningPublicKeyFile, readHotUpdaterEnv, readHotUpdaterInitEnv, readPackageUp, renderHotUpdaterPlugins, renderImportStatements, resolveHotUpdaterServerVersion, resolveInitProviderInput, resolveInitProviderInputs, resolvePackageVersion, shouldAutoSelectOnlyInitResource, stripAnsi, transformEnv, transformTemplate, writeHotUpdaterConfig, writeHotUpdaterPlugins, writeStorageFile, writeStorageResponseFile };
|
package/dist/index.mjs
CHANGED
|
@@ -3,7 +3,7 @@ import { createRequire } from "node:module";
|
|
|
3
3
|
import path, { dirname, parse } from "path";
|
|
4
4
|
import { createInterface } from "readline";
|
|
5
5
|
import { PassThrough } from "stream";
|
|
6
|
-
import fs
|
|
6
|
+
import fs from "fs";
|
|
7
7
|
import fs$1 from "fs/promises";
|
|
8
8
|
import $r, { EventEmitter } from "events";
|
|
9
9
|
import Pi from "assert";
|
|
@@ -14,28 +14,27 @@ import process$1, { execArgv, execPath, hrtime, platform, stdin, stdout } from "
|
|
|
14
14
|
import * as l from "node:readline";
|
|
15
15
|
import l__default from "node:readline";
|
|
16
16
|
import tty, { ReadStream } from "node:tty";
|
|
17
|
-
import Ei, { appendFileSync, createReadStream, createWriteStream
|
|
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
19
|
import os, { constants } from "node:os";
|
|
20
|
-
import crypto$1, { randomBytes, randomUUID } from "node:crypto";
|
|
20
|
+
import crypto$1, { createHash, randomBytes, randomUUID } from "node:crypto";
|
|
21
21
|
import fs$2 from "node:fs/promises";
|
|
22
|
-
import { pipeline } from "stream/promises";
|
|
23
|
-
import * as Ms from "zlib";
|
|
24
|
-
import Jr, { constants as constants$1, createBrotliCompress } from "zlib";
|
|
25
|
-
import { EventEmitter as EventEmitter$1, addAbortListener, on, once, setMaxListeners } from "node:events";
|
|
26
22
|
import As, { Duplex, PassThrough as PassThrough$1, Readable as Readable$1, Transform, Writable, getDefaultHighWaterMark } from "node:stream";
|
|
23
|
+
import { finished, pipeline } from "node:stream/promises";
|
|
24
|
+
import { brotliDecompressSync, constants as constants$1, createBrotliCompress } from "node:zlib";
|
|
25
|
+
import { EventEmitter as EventEmitter$1, addAbortListener, on, once, setMaxListeners } from "node:events";
|
|
27
26
|
import { StringDecoder } from "node:string_decoder";
|
|
27
|
+
import * as Ms from "zlib";
|
|
28
|
+
import Jr from "zlib";
|
|
28
29
|
import no from "node:assert";
|
|
29
30
|
import { fileURLToPath } from "node:url";
|
|
30
31
|
import { ChildProcess, execFile, spawn, spawnSync } from "node:child_process";
|
|
31
32
|
import { scheduler, setImmediate as setImmediate$1, setTimeout as setTimeout$1 } from "node:timers/promises";
|
|
32
33
|
import { serialize } from "node:v8";
|
|
33
|
-
import { finished, pipeline as pipeline$1 } from "node:stream/promises";
|
|
34
34
|
import { Buffer as Buffer$2 } from "node:buffer";
|
|
35
35
|
import { parseSync } from "oxc-parser";
|
|
36
|
-
import { createBundleStorageKey, createDatabasePlugin, createStoragePlugin, createStorageRootUriWithPath, detectCompressionFormat, getContentType, getManifestAssetDownloadPath, getManifestAssetStoragePath, isContentAddressedAssetFileHash, parseStorageUri, resolveManifestAssetStorageUri } from "@hot-updater/plugin-core";
|
|
37
36
|
import { loadConfig as loadConfig$1 } from "unconfig";
|
|
38
|
-
import {
|
|
37
|
+
import { createBundleStorageKey, createStoragePlugin, createStorageRootUriWithPath, getContentType, getManifestAssetDownloadPath, getManifestAssetStoragePath, isContentAddressedAssetFileHash, resolveManifestAssetStorageUri } from "@hot-updater/plugin-core";
|
|
39
38
|
import { getManifestFileHash, stripBundleArtifactMetadata } from "@hot-updater/core";
|
|
40
39
|
import { transformSync } from "oxc-transform";
|
|
41
40
|
//#endregion
|
|
@@ -25043,14 +25042,14 @@ var ConfigBuilder = class {
|
|
|
25043
25042
|
intermediateCode = "";
|
|
25044
25043
|
collectedImports = /* @__PURE__ */ new Map();
|
|
25045
25044
|
constructor() {
|
|
25046
|
-
this.addImport({
|
|
25047
|
-
pkg: "dotenv",
|
|
25048
|
-
named: ["config"]
|
|
25049
|
-
});
|
|
25050
25045
|
this.addImport({
|
|
25051
25046
|
pkg: "hot-updater",
|
|
25052
25047
|
named: ["defineConfig"]
|
|
25053
25048
|
});
|
|
25049
|
+
this.addImport({
|
|
25050
|
+
pkg: "node:fs",
|
|
25051
|
+
named: ["existsSync"]
|
|
25052
|
+
});
|
|
25054
25053
|
}
|
|
25055
25054
|
addImport(info) {
|
|
25056
25055
|
const pkg = info.pkg;
|
|
@@ -25127,7 +25126,9 @@ var ConfigBuilder = class {
|
|
|
25127
25126
|
const text = `
|
|
25128
25127
|
${importStatements}
|
|
25129
25128
|
|
|
25130
|
-
|
|
25129
|
+
if (existsSync(".env.hotupdater")) {
|
|
25130
|
+
process.loadEnvFile(".env.hotupdater");
|
|
25131
|
+
}
|
|
25131
25132
|
|
|
25132
25133
|
${this.intermediateCode ? `${this.intermediateCode}\n` : ""}
|
|
25133
25134
|
export default defineConfig({
|
|
@@ -28325,7 +28326,7 @@ var fo = (s, t) => {
|
|
|
28325
28326
|
});
|
|
28326
28327
|
});
|
|
28327
28328
|
};
|
|
28328
|
-
|
|
28329
|
+
K(co, fo, (s) => new Te(s), (s) => new Xt(s), (s, t) => {
|
|
28329
28330
|
t?.length && Xi(s, t);
|
|
28330
28331
|
});
|
|
28331
28332
|
var mo = (s, t) => {
|
|
@@ -28439,150 +28440,47 @@ var Ro = (s) => {
|
|
|
28439
28440
|
};
|
|
28440
28441
|
//#endregion
|
|
28441
28442
|
//#region src/createTarBr.ts
|
|
28442
|
-
|
|
28443
|
-
|
|
28444
|
-
|
|
28445
|
-
await fs$1.
|
|
28443
|
+
/** Build the one supported bulk transport from the exact manifest file set. */
|
|
28444
|
+
async function createTarBrTargetFiles({ outfile, targetFiles }) {
|
|
28445
|
+
await fs$2.mkdir(path$1.dirname(outfile), { recursive: true });
|
|
28446
|
+
const staging = await fs$2.mkdtemp(path$1.join(path$1.dirname(outfile), ".tar-br-"));
|
|
28446
28447
|
try {
|
|
28448
|
+
const names = /* @__PURE__ */ new Set();
|
|
28447
28449
|
for (const target of targetFiles) {
|
|
28448
|
-
const
|
|
28449
|
-
|
|
28450
|
-
await fs$
|
|
28451
|
-
|
|
28452
|
-
|
|
28453
|
-
|
|
28454
|
-
|
|
28450
|
+
const name = target.name;
|
|
28451
|
+
if (!name || name !== name.trim() || name.includes("\\") || name.includes("\0") || name.startsWith("/") || /^[A-Za-z]:/.test(name) || name.split("/").some((part) => !part || part === "." || part === "..") || name === "manifest.json" || name === "bundle.tar.br" || names.has(name)) throw new Error(`Invalid or duplicate archive asset path: ${name}`);
|
|
28452
|
+
if (!(await fs$2.lstat(target.path)).isFile()) throw new Error(`Archive asset is not a regular file: ${name}`);
|
|
28453
|
+
names.add(name);
|
|
28454
|
+
const destination = path$1.join(staging, name);
|
|
28455
|
+
await fs$2.mkdir(path$1.dirname(destination), { recursive: true });
|
|
28456
|
+
await fs$2.copyFile(target.path, destination);
|
|
28457
|
+
await fs$2.chmod(destination, 420);
|
|
28458
|
+
}
|
|
28459
|
+
let tarByteSize = 0;
|
|
28460
|
+
const countTarBytes = new Transform({ transform(chunk, _encoding, callback) {
|
|
28461
|
+
tarByteSize += chunk.length;
|
|
28462
|
+
callback(null, chunk);
|
|
28463
|
+
} });
|
|
28455
28464
|
await pipeline(Kn({
|
|
28456
|
-
cwd:
|
|
28465
|
+
cwd: staging,
|
|
28457
28466
|
portable: true,
|
|
28458
28467
|
mtime: /* @__PURE__ */ new Date(0),
|
|
28459
28468
|
gzip: false
|
|
28460
|
-
},
|
|
28461
|
-
|
|
28462
|
-
|
|
28463
|
-
|
|
28464
|
-
|
|
28465
|
-
|
|
28466
|
-
|
|
28467
|
-
|
|
28468
|
-
force: true
|
|
28469
|
-
});
|
|
28470
|
-
}
|
|
28471
|
-
};
|
|
28472
|
-
async function copyDir$1(src, dest) {
|
|
28473
|
-
await fs$1.mkdir(dest, { recursive: true });
|
|
28474
|
-
const entries = await fs$1.readdir(src, { withFileTypes: true });
|
|
28475
|
-
for (const entry of entries) {
|
|
28476
|
-
const srcPath = path.join(src, entry.name);
|
|
28477
|
-
const destPath = path.join(dest, entry.name);
|
|
28478
|
-
if (entry.isDirectory()) await copyDir$1(srcPath, destPath);
|
|
28479
|
-
else await fs$1.copyFile(srcPath, destPath);
|
|
28480
|
-
}
|
|
28481
|
-
}
|
|
28482
|
-
const createBrotliTar = async ({ cwd, files, outfile }) => {
|
|
28483
|
-
await fs$1.mkdir(path.dirname(outfile), { recursive: true });
|
|
28484
|
-
await pipeline(Kn({
|
|
28485
|
-
cwd,
|
|
28486
|
-
portable: true,
|
|
28487
|
-
mtime: /* @__PURE__ */ new Date(0),
|
|
28488
|
-
gzip: false
|
|
28489
|
-
}, files), createBrotliCompress({ params: {
|
|
28490
|
-
[constants$1.BROTLI_PARAM_QUALITY]: 11,
|
|
28491
|
-
[constants$1.BROTLI_PARAM_LGWIN]: 24
|
|
28492
|
-
} }), createWriteStream(outfile));
|
|
28493
|
-
};
|
|
28494
|
-
const createTarBr = async ({ outfile, targetDir, excludeExts = [] }) => {
|
|
28495
|
-
await fs$1.rm(outfile, { force: true });
|
|
28496
|
-
async function getFiles(dir, baseDir = "") {
|
|
28497
|
-
const entries = await fs$1.readdir(dir, { withFileTypes: true });
|
|
28498
|
-
const files = [];
|
|
28499
|
-
for (const entry of entries) {
|
|
28500
|
-
if (excludeExts.some((pattern) => entry.name.includes(pattern))) continue;
|
|
28501
|
-
const fullPath = path.join(dir, entry.name);
|
|
28502
|
-
const relativePath = path.join(baseDir, entry.name);
|
|
28503
|
-
if (entry.isDirectory()) {
|
|
28504
|
-
const subFiles = await getFiles(fullPath, relativePath);
|
|
28505
|
-
files.push(...subFiles);
|
|
28506
|
-
} else files.push(relativePath);
|
|
28507
|
-
}
|
|
28508
|
-
return files;
|
|
28509
|
-
}
|
|
28510
|
-
const filesToInclude = await getFiles(targetDir);
|
|
28511
|
-
filesToInclude.sort();
|
|
28512
|
-
await createBrotliTar({
|
|
28513
|
-
cwd: targetDir,
|
|
28514
|
-
files: filesToInclude,
|
|
28515
|
-
outfile
|
|
28516
|
-
});
|
|
28517
|
-
return outfile;
|
|
28518
|
-
};
|
|
28519
|
-
//#endregion
|
|
28520
|
-
//#region src/createTarGz.ts
|
|
28521
|
-
const createTarGzTargetFiles = async ({ outfile, targetFiles }) => {
|
|
28522
|
-
await fs$1.rm(outfile, { force: true });
|
|
28523
|
-
const tmpDir = path.join(path.dirname(outfile), `.tmp-tar-${Date.now()}`);
|
|
28524
|
-
await fs$1.mkdir(tmpDir, { recursive: true });
|
|
28525
|
-
try {
|
|
28526
|
-
for (const target of targetFiles) {
|
|
28527
|
-
const sourcePath = target.path;
|
|
28528
|
-
const destPath = path.join(tmpDir, target.name);
|
|
28529
|
-
await fs$1.mkdir(path.dirname(destPath), { recursive: true });
|
|
28530
|
-
if ((await fs$1.stat(sourcePath)).isDirectory()) await copyDir(sourcePath, destPath);
|
|
28531
|
-
else await fs$1.copyFile(sourcePath, destPath);
|
|
28532
|
-
}
|
|
28533
|
-
await fs$1.mkdir(path.dirname(outfile), { recursive: true });
|
|
28534
|
-
await Kn({
|
|
28535
|
-
file: outfile,
|
|
28536
|
-
cwd: tmpDir,
|
|
28537
|
-
portable: true,
|
|
28538
|
-
mtime: /* @__PURE__ */ new Date(0),
|
|
28539
|
-
gzip: true
|
|
28540
|
-
}, await fs$1.readdir(tmpDir));
|
|
28541
|
-
return outfile;
|
|
28469
|
+
}, [...names].sort()), countTarBytes, createBrotliCompress({ params: { [constants$1.BROTLI_PARAM_QUALITY]: 11 } }), createWriteStream(outfile));
|
|
28470
|
+
const hash = createHash("sha256");
|
|
28471
|
+
for await (const chunk of createReadStream(outfile)) hash.update(chunk);
|
|
28472
|
+
return {
|
|
28473
|
+
downloadFileHash: hash.digest("hex"),
|
|
28474
|
+
downloadByteSize: (await fs$2.stat(outfile)).size,
|
|
28475
|
+
tarByteSize
|
|
28476
|
+
};
|
|
28542
28477
|
} finally {
|
|
28543
|
-
await fs$
|
|
28478
|
+
await fs$2.rm(staging, {
|
|
28544
28479
|
recursive: true,
|
|
28545
28480
|
force: true
|
|
28546
28481
|
});
|
|
28547
28482
|
}
|
|
28548
|
-
};
|
|
28549
|
-
async function copyDir(src, dest) {
|
|
28550
|
-
await fs$1.mkdir(dest, { recursive: true });
|
|
28551
|
-
const entries = await fs$1.readdir(src, { withFileTypes: true });
|
|
28552
|
-
for (const entry of entries) {
|
|
28553
|
-
const srcPath = path.join(src, entry.name);
|
|
28554
|
-
const destPath = path.join(dest, entry.name);
|
|
28555
|
-
if (entry.isDirectory()) await copyDir(srcPath, destPath);
|
|
28556
|
-
else await fs$1.copyFile(srcPath, destPath);
|
|
28557
|
-
}
|
|
28558
28483
|
}
|
|
28559
|
-
const createTarGz = async ({ outfile, targetDir, excludeExts = [] }) => {
|
|
28560
|
-
await fs$1.rm(outfile, { force: true });
|
|
28561
|
-
async function getFiles(dir, baseDir = "") {
|
|
28562
|
-
const entries = await fs$1.readdir(dir, { withFileTypes: true });
|
|
28563
|
-
const files = [];
|
|
28564
|
-
for (const entry of entries) {
|
|
28565
|
-
if (excludeExts.some((pattern) => entry.name.includes(pattern))) continue;
|
|
28566
|
-
const fullPath = path.join(dir, entry.name);
|
|
28567
|
-
const relativePath = path.join(baseDir, entry.name);
|
|
28568
|
-
if (entry.isDirectory()) {
|
|
28569
|
-
const subFiles = await getFiles(fullPath, relativePath);
|
|
28570
|
-
files.push(...subFiles);
|
|
28571
|
-
} else files.push(relativePath);
|
|
28572
|
-
}
|
|
28573
|
-
return files;
|
|
28574
|
-
}
|
|
28575
|
-
const filesToInclude = await getFiles(targetDir);
|
|
28576
|
-
filesToInclude.sort();
|
|
28577
|
-
await Kn({
|
|
28578
|
-
file: outfile,
|
|
28579
|
-
cwd: targetDir,
|
|
28580
|
-
portable: true,
|
|
28581
|
-
mtime: /* @__PURE__ */ new Date(0),
|
|
28582
|
-
gzip: true
|
|
28583
|
-
}, filesToInclude);
|
|
28584
|
-
return outfile;
|
|
28585
|
-
};
|
|
28586
28484
|
//#endregion
|
|
28587
28485
|
//#region ../../node_modules/.pnpm/process-nextick-args@2.0.1/node_modules/process-nextick-args/index.js
|
|
28588
28486
|
var require_process_nextick_args = /* @__PURE__ */ __commonJSMin(((exports, module) => {
|
|
@@ -37664,41 +37562,6 @@ var import_lib = /* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJSMin(((export
|
|
|
37664
37562
|
JSZip.external = require_external();
|
|
37665
37563
|
module.exports = JSZip;
|
|
37666
37564
|
})))(), 1);
|
|
37667
|
-
const createZipTargetFiles = async ({ outfile, targetFiles }) => {
|
|
37668
|
-
const zip = new import_lib.default();
|
|
37669
|
-
await fs$1.rm(outfile, { force: true });
|
|
37670
|
-
async function addFiles(dir, zipFolder) {
|
|
37671
|
-
const files = await fs$1.readdir(dir);
|
|
37672
|
-
files.sort();
|
|
37673
|
-
for (const file of files) {
|
|
37674
|
-
const fullPath = path.join(dir, file);
|
|
37675
|
-
if ((await fs$1.stat(fullPath)).isDirectory()) {
|
|
37676
|
-
const folder = zipFolder.folder(file);
|
|
37677
|
-
if (!folder) continue;
|
|
37678
|
-
await addFiles(fullPath, folder);
|
|
37679
|
-
} else {
|
|
37680
|
-
const data = await fs$1.readFile(fullPath);
|
|
37681
|
-
zipFolder.file(file, data);
|
|
37682
|
-
}
|
|
37683
|
-
}
|
|
37684
|
-
}
|
|
37685
|
-
for (const target of targetFiles) if ((await fs$1.stat(target.path)).isDirectory()) {
|
|
37686
|
-
const folder = zip.folder(target.name);
|
|
37687
|
-
if (folder) await addFiles(target.path, folder);
|
|
37688
|
-
} else {
|
|
37689
|
-
const data = await fs$1.readFile(target.path);
|
|
37690
|
-
zip.file(target.name, data);
|
|
37691
|
-
}
|
|
37692
|
-
const content = await zip.generateAsync({
|
|
37693
|
-
type: "nodebuffer",
|
|
37694
|
-
compression: "DEFLATE",
|
|
37695
|
-
compressionOptions: { level: 9 },
|
|
37696
|
-
platform: "UNIX"
|
|
37697
|
-
});
|
|
37698
|
-
await fs$1.mkdir(path.dirname(outfile), { recursive: true });
|
|
37699
|
-
await fs$1.writeFile(outfile, content);
|
|
37700
|
-
return outfile;
|
|
37701
|
-
};
|
|
37702
37565
|
const createZip = async ({ outfile, targetDir, excludeExts = [] }) => {
|
|
37703
37566
|
const zip = new import_lib.default();
|
|
37704
37567
|
await fs$1.rm(outfile, { force: true });
|
|
@@ -42298,8 +42161,8 @@ const addPropertiesAsync = {
|
|
|
42298
42161
|
},
|
|
42299
42162
|
output: {
|
|
42300
42163
|
...addProperties,
|
|
42301
|
-
fileUrl: ({ value }) => ({ stream: createWriteStream
|
|
42302
|
-
filePath: ({ value: { file, append } }) => ({ stream: createWriteStream
|
|
42164
|
+
fileUrl: ({ value }) => ({ stream: createWriteStream(value) }),
|
|
42165
|
+
filePath: ({ value: { file, append } }) => ({ stream: createWriteStream(file, append ? { flags: "a" } : {}) }),
|
|
42303
42166
|
webStream: ({ value }) => ({ stream: Writable.fromWeb(value) }),
|
|
42304
42167
|
iterable: forbiddenIfAsync,
|
|
42305
42168
|
asyncIterable: forbiddenIfAsync,
|
|
@@ -44175,7 +44038,6 @@ const getReactNativeMetadatas = (cwd) => {
|
|
|
44175
44038
|
const HOT_UPDATER_CONFIG_PATH = "hot-updater.config.ts";
|
|
44176
44039
|
const CONFIG_FILE_NAME = "hot-updater.config.ts";
|
|
44177
44040
|
const MANAGED_IMPORT_PACKAGES = /* @__PURE__ */ new Set([
|
|
44178
|
-
"dotenv",
|
|
44179
44041
|
"firebase-admin",
|
|
44180
44042
|
"firebase-admin/app",
|
|
44181
44043
|
"hot-updater",
|
|
@@ -44428,7 +44290,6 @@ const updateManagedObject = (existing, next) => {
|
|
|
44428
44290
|
for (const edit of propertyEdits.sort((left, right) => right.start - left.start)) mergedText = mergedText.slice(0, edit.start) + edit.text + mergedText.slice(edit.end);
|
|
44429
44291
|
return appendMissingProperties(mergedText, missingPropertyTexts, existing.objectExpression.properties.length > 0);
|
|
44430
44292
|
};
|
|
44431
|
-
const isConfigCallStatement = (statement) => statement.type === "ExpressionStatement" && statement.expression.type === "CallExpression" && statement.expression.callee.type === "Identifier" && statement.expression.callee.name === "config";
|
|
44432
44293
|
const getManagedHelperName = (statement) => {
|
|
44433
44294
|
if (statement.type !== "VariableDeclaration") return null;
|
|
44434
44295
|
const declaration = statement.declarations[0];
|
|
@@ -44436,16 +44297,20 @@ const getManagedHelperName = (statement) => {
|
|
|
44436
44297
|
return declaration.id.name;
|
|
44437
44298
|
};
|
|
44438
44299
|
const rebuildImportBlock = (source, scaffold) => {
|
|
44300
|
+
const imports = scaffold.imports.map((info) => info.pkg === "node:fs" ? {
|
|
44301
|
+
...info,
|
|
44302
|
+
named: info.named?.filter((name) => name !== "existsSync")
|
|
44303
|
+
} : info);
|
|
44439
44304
|
const importDeclarations = source.program.body.filter((statement) => statement.type === "ImportDeclaration");
|
|
44440
44305
|
const firstImport = importDeclarations[0];
|
|
44441
44306
|
const lastImport = importDeclarations.at(-1);
|
|
44442
44307
|
if (!firstImport || !lastImport) return {
|
|
44443
44308
|
start: 0,
|
|
44444
44309
|
end: 0,
|
|
44445
|
-
text: `${renderImportStatements(
|
|
44310
|
+
text: `${renderImportStatements(imports)}\n\n`
|
|
44446
44311
|
};
|
|
44447
44312
|
const preservedImportTexts = importDeclarations.filter((declaration) => !MANAGED_IMPORT_PACKAGES.has(declaration.source.value)).map((declaration) => source.text.slice(getTopLevelFullStart(source, declaration), declaration.end).trim());
|
|
44448
|
-
const managedImportText = renderImportStatements(
|
|
44313
|
+
const managedImportText = renderImportStatements(imports);
|
|
44449
44314
|
const nextImportBlock = [...preservedImportTexts, managedImportText].filter(Boolean).join("\n");
|
|
44450
44315
|
return {
|
|
44451
44316
|
start: getTopLevelFullStart(source, firstImport),
|
|
@@ -44458,12 +44323,7 @@ const rebuildManagedBody = (source, exportStart, scaffold) => {
|
|
|
44458
44323
|
const managedHelpers = new Map(scaffold.helperStatements.map((statement) => [statement.name, statement]));
|
|
44459
44324
|
const emittedHelpers = /* @__PURE__ */ new Set();
|
|
44460
44325
|
const bodyStatements = [];
|
|
44461
|
-
const configStatements = [];
|
|
44462
44326
|
for (const statement of statementsBeforeExport) {
|
|
44463
|
-
if (isConfigCallStatement(statement)) {
|
|
44464
|
-
configStatements.push(getStatementText(source, statement));
|
|
44465
|
-
continue;
|
|
44466
|
-
}
|
|
44467
44327
|
const helperName = getManagedHelperName(statement);
|
|
44468
44328
|
if (!helperName || !MANAGED_HELPER_NAMES.has(helperName)) {
|
|
44469
44329
|
bodyStatements.push(getStatementText(source, statement));
|
|
@@ -44478,8 +44338,7 @@ const rebuildManagedBody = (source, exportStart, scaffold) => {
|
|
|
44478
44338
|
}
|
|
44479
44339
|
for (const helper of scaffold.helperStatements) if (!emittedHelpers.has(helper.name)) bodyStatements.push(helper.code.trim());
|
|
44480
44340
|
const bodyText = bodyStatements.filter(Boolean).join("\n\n");
|
|
44481
|
-
const
|
|
44482
|
-
const managedBody = bodyText ? `\n\n${configStatement}\n\n${bodyText}\n\n` : `\n\n${configStatement}\n\n`;
|
|
44341
|
+
const managedBody = bodyText ? `\n\n${bodyText}\n\n` : "\n\n";
|
|
44483
44342
|
return {
|
|
44484
44343
|
start: source.program.body.filter((statement) => statement.type === "ImportDeclaration").at(-1)?.end ?? 0,
|
|
44485
44344
|
end: exportStart,
|
|
@@ -44678,6 +44537,77 @@ const getHotUpdaterEnvValue = (env, key) => {
|
|
|
44678
44537
|
return env[key]?.trim() || void 0;
|
|
44679
44538
|
};
|
|
44680
44539
|
//#endregion
|
|
44540
|
+
//#region src/hotUpdaterPlugins.ts
|
|
44541
|
+
/** Where `hot-updater init` writes a managed server's plugin list. */
|
|
44542
|
+
const HOT_UPDATER_PLUGINS_PATH = "hotUpdater.plugins.ts";
|
|
44543
|
+
/**
|
|
44544
|
+
* The plugins file for a managed provider: a re-export of the fixed list its
|
|
44545
|
+
* package ships, which its prebuilt server runs too.
|
|
44546
|
+
*/
|
|
44547
|
+
const renderHotUpdaterPlugins = (pkg) => [
|
|
44548
|
+
"// Generated by `hot-updater init`. The managed server runs these plugins,",
|
|
44549
|
+
`// and ${pkg} fixes the list, so the server, CLI, and console agree.`,
|
|
44550
|
+
`export { plugins } from "${pkg}";`,
|
|
44551
|
+
""
|
|
44552
|
+
].join("\n");
|
|
44553
|
+
/** Writes the plugins file; an existing file that differs is kept. */
|
|
44554
|
+
const writeHotUpdaterPlugins = async (pkg, filePath = HOT_UPDATER_PLUGINS_PATH) => {
|
|
44555
|
+
const text = renderHotUpdaterPlugins(pkg);
|
|
44556
|
+
const existingText = await fs$1.readFile(filePath, "utf-8").catch((error) => {
|
|
44557
|
+
if (error instanceof Error && "code" in error && error.code === "ENOENT") return null;
|
|
44558
|
+
throw error;
|
|
44559
|
+
});
|
|
44560
|
+
if (existingText === null) {
|
|
44561
|
+
await fs$1.writeFile(filePath, text, "utf-8");
|
|
44562
|
+
return {
|
|
44563
|
+
status: "created",
|
|
44564
|
+
path: filePath
|
|
44565
|
+
};
|
|
44566
|
+
}
|
|
44567
|
+
if (existingText === text) return {
|
|
44568
|
+
status: "unchanged",
|
|
44569
|
+
path: filePath
|
|
44570
|
+
};
|
|
44571
|
+
return {
|
|
44572
|
+
status: "skipped",
|
|
44573
|
+
path: filePath,
|
|
44574
|
+
reason: `it does not re-export the plugins ${pkg} runs; replace it with \`export { plugins } from "${pkg}";\``
|
|
44575
|
+
};
|
|
44576
|
+
};
|
|
44577
|
+
/** Writes the plugins file for `pkg` and reports what happened. */
|
|
44578
|
+
const generateHotUpdaterPlugins = async (pkg, filePath = HOT_UPDATER_PLUGINS_PATH) => {
|
|
44579
|
+
const result = await writeHotUpdaterPlugins(pkg, filePath);
|
|
44580
|
+
if (result.status === "created") p.log.success(`Generated '${filePath}' with the plugins the server runs.`);
|
|
44581
|
+
else if (result.status === "skipped") p.log.warn(`Kept existing '${filePath}' unchanged: ${result.reason}`);
|
|
44582
|
+
return result;
|
|
44583
|
+
};
|
|
44584
|
+
/**
|
|
44585
|
+
* The plugins a project's `hotUpdater.plugins.ts` exports, which its server
|
|
44586
|
+
* runs; undefined when the project has no such file. The console assembles
|
|
44587
|
+
* them in process to read Insights and API keys as the server would.
|
|
44588
|
+
*/
|
|
44589
|
+
const loadHotUpdaterPlugins = async (cwd = getCwd()) => {
|
|
44590
|
+
const { config, sources } = await loadConfig$1({
|
|
44591
|
+
cwd,
|
|
44592
|
+
stopAt: path.dirname(cwd),
|
|
44593
|
+
merge: false,
|
|
44594
|
+
sources: [{
|
|
44595
|
+
files: "hotUpdater.plugins",
|
|
44596
|
+
extensions: [
|
|
44597
|
+
"ts",
|
|
44598
|
+
"mts",
|
|
44599
|
+
"cts",
|
|
44600
|
+
"js",
|
|
44601
|
+
"mjs",
|
|
44602
|
+
"cjs"
|
|
44603
|
+
]
|
|
44604
|
+
}]
|
|
44605
|
+
});
|
|
44606
|
+
if (sources.length === 0) return void 0;
|
|
44607
|
+
if (!Array.isArray(config?.plugins)) throw new Error(`${path.basename(sources[0])} must export plugins, an array of plugins.`);
|
|
44608
|
+
return config.plugins;
|
|
44609
|
+
};
|
|
44610
|
+
//#endregion
|
|
44681
44611
|
//#region src/infrastructureGeneration.ts
|
|
44682
44612
|
const assertInfrastructureGenerationPayload = ({ payload, provider, resource }) => {
|
|
44683
44613
|
if (typeof payload !== "object" || payload === null || !("infrastructureGeneration" in payload) || payload.infrastructureGeneration !== 1) throw new LegacyInfrastructureError(provider, resource);
|
|
@@ -44873,89 +44803,20 @@ function isMergeableValue(value) {
|
|
|
44873
44803
|
//#endregion
|
|
44874
44804
|
//#region src/loadConfig.ts
|
|
44875
44805
|
var import_out = /* @__PURE__ */ __toESM(require_out(), 1);
|
|
44876
|
-
const
|
|
44806
|
+
const missingDatabaseError = async () => {
|
|
44807
|
+
throw new Error("database is required");
|
|
44808
|
+
};
|
|
44809
|
+
/** The default until the config names a database: every read and write refuses. */
|
|
44810
|
+
const missingDatabase = {
|
|
44877
44811
|
name: "missingDatabase",
|
|
44878
|
-
|
|
44879
|
-
|
|
44880
|
-
|
|
44881
|
-
|
|
44882
|
-
|
|
44883
|
-
|
|
44884
|
-
throw new Error("database plugin is required");
|
|
44885
|
-
},
|
|
44886
|
-
count: async () => {
|
|
44887
|
-
throw new Error("database plugin is required");
|
|
44888
|
-
}
|
|
44889
|
-
},
|
|
44890
|
-
bundlePatches: { findByBundleIds: async () => {
|
|
44891
|
-
throw new Error("database plugin is required");
|
|
44892
|
-
} },
|
|
44893
|
-
releases: {
|
|
44894
|
-
findById: async () => {
|
|
44895
|
-
throw new Error("database plugin is required");
|
|
44896
|
-
},
|
|
44897
|
-
findMany: async () => {
|
|
44898
|
-
throw new Error("database plugin is required");
|
|
44899
|
-
},
|
|
44900
|
-
findManyByScope: async () => {
|
|
44901
|
-
throw new Error("database plugin is required");
|
|
44902
|
-
}
|
|
44903
|
-
},
|
|
44904
|
-
releaseCatalogs: {
|
|
44905
|
-
findByScopeKey: async () => {
|
|
44906
|
-
throw new Error("database plugin is required");
|
|
44907
|
-
},
|
|
44908
|
-
findMany: async () => {
|
|
44909
|
-
throw new Error("database plugin is required");
|
|
44910
|
-
}
|
|
44911
|
-
},
|
|
44912
|
-
channels: {
|
|
44913
|
-
insert: async () => {
|
|
44914
|
-
throw new Error("database plugin is required");
|
|
44915
|
-
},
|
|
44916
|
-
list: async () => {
|
|
44917
|
-
throw new Error("database plugin is required");
|
|
44918
|
-
},
|
|
44919
|
-
delete: async () => {
|
|
44920
|
-
throw new Error("database plugin is required");
|
|
44921
|
-
}
|
|
44922
|
-
},
|
|
44923
|
-
insights: {
|
|
44924
|
-
recordEvent: async () => {
|
|
44925
|
-
throw new Error("database plugin is required");
|
|
44926
|
-
},
|
|
44927
|
-
listEvents: async () => {
|
|
44928
|
-
throw new Error("database plugin is required");
|
|
44929
|
-
},
|
|
44930
|
-
findLatestEvents: async () => {
|
|
44931
|
-
throw new Error("database plugin is required");
|
|
44932
|
-
},
|
|
44933
|
-
countLatestEvents: async () => {
|
|
44934
|
-
throw new Error("database plugin is required");
|
|
44935
|
-
},
|
|
44936
|
-
countEvents: async () => {
|
|
44937
|
-
throw new Error("database plugin is required");
|
|
44938
|
-
}
|
|
44939
|
-
},
|
|
44940
|
-
apiKeys: {
|
|
44941
|
-
create: async () => {
|
|
44942
|
-
throw new Error("database plugin is required");
|
|
44943
|
-
},
|
|
44944
|
-
findByHash: async () => {
|
|
44945
|
-
throw new Error("database plugin is required");
|
|
44946
|
-
},
|
|
44947
|
-
list: async () => {
|
|
44948
|
-
throw new Error("database plugin is required");
|
|
44949
|
-
},
|
|
44950
|
-
revoke: async () => {
|
|
44951
|
-
throw new Error("database plugin is required");
|
|
44952
|
-
}
|
|
44953
|
-
}
|
|
44954
|
-
},
|
|
44955
|
-
commit: async () => {
|
|
44956
|
-
throw new Error("database plugin is required");
|
|
44812
|
+
adapter: {
|
|
44813
|
+
id: "missing",
|
|
44814
|
+
fits: () => true,
|
|
44815
|
+
get: missingDatabaseError,
|
|
44816
|
+
query: missingDatabaseError,
|
|
44817
|
+
write: missingDatabaseError
|
|
44957
44818
|
}
|
|
44958
|
-
}
|
|
44819
|
+
};
|
|
44959
44820
|
const missingStorageError = async () => {
|
|
44960
44821
|
throw new Error("storage plugin is required");
|
|
44961
44822
|
};
|
|
@@ -45003,7 +44864,6 @@ const getDefaultConfig = () => {
|
|
|
45003
44864
|
return {
|
|
45004
44865
|
cacheDir: path.join("node_modules", ".hot-updater"),
|
|
45005
44866
|
updateStrategy: "appVersion",
|
|
45006
|
-
compressStrategy: "zip",
|
|
45007
44867
|
fingerprint: {},
|
|
45008
44868
|
patch: {
|
|
45009
44869
|
enabled: true,
|
|
@@ -45059,6 +44919,7 @@ const getConfigLoaderOptions = (options) => {
|
|
|
45059
44919
|
const loadConfig = async (options) => {
|
|
45060
44920
|
const { config } = await loadConfig$1(getConfigLoaderOptions(options));
|
|
45061
44921
|
for (const key of ["authorityId", "catalogId"]) if (config && Object.hasOwn(config, key)) throw new Error(`Remove ${key} from hot-updater.config. Catalog identity is managed internally.`);
|
|
44922
|
+
if (config && Object.hasOwn(config, "compressStrategy")) throw new Error("Remove compressStrategy from hot-updater.config. OTA artifacts use manifest files with per-file Brotli compression.");
|
|
45062
44923
|
const mergedConfig = mergeConfigSources(config, getDefaultConfig());
|
|
45063
44924
|
const signing = normalizeSigningConfig(mergedConfig.signing);
|
|
45064
44925
|
return {
|
|
@@ -45216,7 +45077,7 @@ const writeStorageResponseFile = async (response, filePath) => {
|
|
|
45216
45077
|
return;
|
|
45217
45078
|
}
|
|
45218
45079
|
try {
|
|
45219
|
-
await pipeline
|
|
45080
|
+
await pipeline(Readable$1.fromWeb(response.body), createWriteStream(filePath));
|
|
45220
45081
|
} catch (error) {
|
|
45221
45082
|
await fs$2.rm(filePath, { force: true });
|
|
45222
45083
|
throw error;
|
|
@@ -45252,11 +45113,6 @@ function verifySignedFileHash({ actualFileHash, publicKey, signedFileHash }) {
|
|
|
45252
45113
|
return false;
|
|
45253
45114
|
}
|
|
45254
45115
|
}
|
|
45255
|
-
function getArchiveFilename(storageUri) {
|
|
45256
|
-
const protocol = new URL(storageUri).protocol.replace(":", "");
|
|
45257
|
-
const { key } = parseStorageUri(storageUri, protocol);
|
|
45258
|
-
return path$1.posix.basename(key) || "bundle.zip";
|
|
45259
|
-
}
|
|
45260
45116
|
const getRelativeStorageDir = (relativePath) => {
|
|
45261
45117
|
const normalized = relativePath.replace(/\\/g, "/");
|
|
45262
45118
|
const dirname = path$1.posix.dirname(normalized);
|
|
@@ -45273,7 +45129,7 @@ async function prepareManifestAssetUploadFile({ assetPath, sourcePath, workDir }
|
|
|
45273
45129
|
if (getManifestAssetDownloadPath(assetPath) === assetPath) return sourcePath;
|
|
45274
45130
|
const uploadPath = resolvePreparedUploadPath(workDir, assetPath);
|
|
45275
45131
|
await fs$2.mkdir(path$1.dirname(uploadPath), { recursive: true });
|
|
45276
|
-
await pipeline
|
|
45132
|
+
await pipeline(createReadStream(sourcePath), createBrotliCompress({ params: { [constants$1.BROTLI_PARAM_QUALITY]: 11 } }), createWriteStream(uploadPath));
|
|
45277
45133
|
return uploadPath;
|
|
45278
45134
|
}
|
|
45279
45135
|
async function prepareContentAddressedUploadFile({ sourcePath, storagePath, workDir }) {
|
|
@@ -45290,9 +45146,10 @@ async function prepareManifestAssetUploadTargets({ extractDir, manifest, workDir
|
|
|
45290
45146
|
for (const assetPath of assetPaths) {
|
|
45291
45147
|
const asset = manifest.assets?.[assetPath];
|
|
45292
45148
|
if (!asset?.fileHash) throw new Error(`Manifest file hash not found for ${assetPath}`);
|
|
45149
|
+
const sourcePath = resolveExtractedPath(extractDir, assetPath);
|
|
45293
45150
|
const uploadSourcePath = await prepareManifestAssetUploadFile({
|
|
45294
45151
|
assetPath,
|
|
45295
|
-
sourcePath
|
|
45152
|
+
sourcePath,
|
|
45296
45153
|
workDir
|
|
45297
45154
|
});
|
|
45298
45155
|
const downloadByteSize = await getStorageFileByteSize(uploadSourcePath);
|
|
@@ -45301,6 +45158,7 @@ async function prepareManifestAssetUploadTargets({ extractDir, manifest, workDir
|
|
|
45301
45158
|
if (downloadFileHash !== void 0 && !isContentAddressedAssetFileHash(downloadFileHash)) throw new Error(`Prepared asset hash must be a lowercase SHA-256 hash: ${assetPath}`);
|
|
45302
45159
|
const nextAsset = {
|
|
45303
45160
|
...asset,
|
|
45161
|
+
byteSize: (await fs$2.stat(sourcePath)).size,
|
|
45304
45162
|
downloadByteSize
|
|
45305
45163
|
};
|
|
45306
45164
|
delete nextAsset.downloadFileHash;
|
|
@@ -45330,143 +45188,81 @@ function resolveExtractedPath(rootDir, entryName) {
|
|
|
45330
45188
|
const normalizedEntryName = entryName.replaceAll("\\", "/");
|
|
45331
45189
|
const entryPath = path$1.resolve(rootDir, normalizedEntryName);
|
|
45332
45190
|
const relativePath = path$1.relative(rootDir, entryPath);
|
|
45333
|
-
if (relativePath.startsWith("..") || path$1.isAbsolute(relativePath) || normalizedEntryName.startsWith("/")) throw new Error(`Invalid
|
|
45191
|
+
if (relativePath.startsWith("..") || path$1.isAbsolute(relativePath) || normalizedEntryName.startsWith("/")) throw new Error(`Invalid manifest asset path: ${entryName}`);
|
|
45334
45192
|
return entryPath;
|
|
45335
45193
|
}
|
|
45336
|
-
async function
|
|
45194
|
+
async function downloadStorageObject(storageUri, storagePlugin, outputPath) {
|
|
45337
45195
|
const protocol = new URL(storageUri).protocol.replace(":", "");
|
|
45338
45196
|
if (storagePlugin?.protocol === protocol) {
|
|
45339
|
-
await writeStorageFile(storagePlugin, storageUri,
|
|
45197
|
+
await writeStorageFile(storagePlugin, storageUri, outputPath);
|
|
45340
45198
|
return;
|
|
45341
45199
|
}
|
|
45342
45200
|
if (protocol === "http" || protocol === "https") {
|
|
45343
|
-
await downloadFromUrl(storageUri,
|
|
45201
|
+
await downloadFromUrl(storageUri, outputPath);
|
|
45344
45202
|
return;
|
|
45345
45203
|
}
|
|
45346
45204
|
throw new Error(`No storage plugin for protocol: ${protocol}`);
|
|
45347
45205
|
}
|
|
45348
45206
|
async function downloadFromUrl(fileUrl, filePath) {
|
|
45349
45207
|
const response = await fetch(fileUrl);
|
|
45350
|
-
if (!response.ok) throw new Error(`Failed to download
|
|
45208
|
+
if (!response.ok) throw new Error(`Failed to download storage object: ${response.statusText}`);
|
|
45351
45209
|
await writeStorageResponseFile(response, filePath);
|
|
45352
45210
|
}
|
|
45353
|
-
async function
|
|
45354
|
-
|
|
45355
|
-
|
|
45356
|
-
|
|
45357
|
-
const
|
|
45358
|
-
|
|
45359
|
-
|
|
45360
|
-
|
|
45211
|
+
async function downloadManifestAssets({ bundle, manifest, outputDir, storagePlugin, workDir }) {
|
|
45212
|
+
await runWithConcurrency(Object.keys(manifest.assets ?? {}).sort((left, right) => left.localeCompare(right)), PROMOTE_ASSET_CONCURRENCY, async (assetPath) => {
|
|
45213
|
+
const asset = manifest.assets?.[assetPath];
|
|
45214
|
+
if (!asset?.fileHash) throw new Error(`Manifest file hash not found for ${assetPath}`);
|
|
45215
|
+
const downloadPath = getManifestAssetDownloadPath(assetPath);
|
|
45216
|
+
const storageUri = resolveManifestAssetStorageUri({
|
|
45217
|
+
assetBaseStorageUri: bundle.assetBaseStorageUri,
|
|
45218
|
+
assetPath: downloadPath,
|
|
45219
|
+
downloadFileHash: asset.downloadFileHash,
|
|
45220
|
+
fileHash: asset.fileHash
|
|
45221
|
+
});
|
|
45222
|
+
const transferPath = resolveExtractedPath(workDir, `downloads/${downloadPath}`);
|
|
45223
|
+
await fs$2.mkdir(path$1.dirname(transferPath), { recursive: true });
|
|
45224
|
+
await downloadStorageObject(storageUri, storagePlugin, transferPath);
|
|
45225
|
+
if (asset.downloadFileHash) {
|
|
45226
|
+
if (await getFileHash(transferPath) !== asset.downloadFileHash.toLowerCase()) throw new Error(`Manifest download hash mismatch for ${assetPath}`);
|
|
45361
45227
|
}
|
|
45228
|
+
const outputPath = resolveExtractedPath(outputDir, assetPath);
|
|
45362
45229
|
await fs$2.mkdir(path$1.dirname(outputPath), { recursive: true });
|
|
45363
|
-
await fs$2.
|
|
45364
|
-
|
|
45365
|
-
}
|
|
45366
|
-
|
|
45367
|
-
const tarPath = path$1.join(extractDir, "bundle.tar");
|
|
45368
|
-
const compressedBuffer = await fs$2.readFile(archivePath);
|
|
45369
|
-
const tarBuffer = brotliDecompressSync(compressedBuffer);
|
|
45370
|
-
await fs$2.writeFile(tarPath, tarBuffer);
|
|
45371
|
-
try {
|
|
45372
|
-
await uo({
|
|
45373
|
-
file: tarPath,
|
|
45374
|
-
cwd: extractDir,
|
|
45375
|
-
gzip: false,
|
|
45376
|
-
strict: true
|
|
45377
|
-
});
|
|
45378
|
-
} finally {
|
|
45379
|
-
await fs$2.rm(tarPath, { force: true });
|
|
45380
|
-
}
|
|
45381
|
-
}
|
|
45382
|
-
async function extractArchive(archivePath, extractDir) {
|
|
45383
|
-
const { format } = detectCompressionFormat(path$1.basename(archivePath));
|
|
45384
|
-
switch (format) {
|
|
45385
|
-
case "zip":
|
|
45386
|
-
await extractZipArchive(archivePath, extractDir);
|
|
45387
|
-
return format;
|
|
45388
|
-
case "tar.gz":
|
|
45389
|
-
await uo({
|
|
45390
|
-
file: archivePath,
|
|
45391
|
-
cwd: extractDir,
|
|
45392
|
-
gzip: true,
|
|
45393
|
-
strict: true
|
|
45394
|
-
});
|
|
45395
|
-
return format;
|
|
45396
|
-
case "tar.br":
|
|
45397
|
-
await extractTarBrArchive(archivePath, extractDir);
|
|
45398
|
-
return format;
|
|
45399
|
-
}
|
|
45400
|
-
}
|
|
45401
|
-
async function getArchiveTargetFiles(bundleDir) {
|
|
45402
|
-
const entries = await fs$2.readdir(bundleDir, { withFileTypes: true });
|
|
45403
|
-
entries.sort((left, right) => left.name.localeCompare(right.name));
|
|
45404
|
-
return entries.map((entry) => ({
|
|
45405
|
-
path: path$1.join(bundleDir, entry.name),
|
|
45406
|
-
name: entry.name
|
|
45407
|
-
}));
|
|
45408
|
-
}
|
|
45409
|
-
async function createArchiveFromDirectory(sourceDir, archivePath, format) {
|
|
45410
|
-
const targetFiles = await getArchiveTargetFiles(sourceDir);
|
|
45411
|
-
switch (format) {
|
|
45412
|
-
case "zip":
|
|
45413
|
-
await createZipTargetFiles({
|
|
45414
|
-
outfile: archivePath,
|
|
45415
|
-
targetFiles
|
|
45416
|
-
});
|
|
45417
|
-
return;
|
|
45418
|
-
case "tar.gz":
|
|
45419
|
-
await createTarGzTargetFiles({
|
|
45420
|
-
outfile: archivePath,
|
|
45421
|
-
targetFiles
|
|
45422
|
-
});
|
|
45423
|
-
return;
|
|
45424
|
-
case "tar.br":
|
|
45425
|
-
await createTarBrTargetFiles({
|
|
45426
|
-
outfile: archivePath,
|
|
45427
|
-
targetFiles
|
|
45428
|
-
});
|
|
45429
|
-
return;
|
|
45430
|
-
}
|
|
45431
|
-
}
|
|
45432
|
-
async function readCopiedBundleManifest(extractDir, nextBundleId) {
|
|
45433
|
-
const manifestPath = path$1.join(extractDir, "manifest.json");
|
|
45434
|
-
try {
|
|
45435
|
-
await fs$2.access(manifestPath);
|
|
45436
|
-
} catch {
|
|
45437
|
-
throw new Error(LEGACY_BUNDLE_ERROR);
|
|
45438
|
-
}
|
|
45439
|
-
const manifest = JSON.parse(await fs$2.readFile(manifestPath, "utf8"));
|
|
45440
|
-
manifest.bundleId = nextBundleId;
|
|
45441
|
-
return {
|
|
45442
|
-
manifest,
|
|
45443
|
-
manifestPath
|
|
45444
|
-
};
|
|
45230
|
+
if (downloadPath === assetPath) await fs$2.copyFile(transferPath, outputPath);
|
|
45231
|
+
else await fs$2.writeFile(outputPath, brotliDecompressSync(await fs$2.readFile(transferPath)));
|
|
45232
|
+
if (await getFileHash(outputPath) !== asset.fileHash.toLowerCase()) throw new Error(`Manifest file hash mismatch for ${assetPath}`);
|
|
45233
|
+
});
|
|
45445
45234
|
}
|
|
45446
|
-
async function
|
|
45447
|
-
const archiveFilename = getArchiveFilename(bundle.storageUri);
|
|
45235
|
+
async function createCopiedBundleArtifacts({ bundle, config, nextBundleId, storagePlugin }) {
|
|
45448
45236
|
const workDir = await fs$2.mkdtemp(path$1.join(os.tmpdir(), "hot-updater-console-promote-"));
|
|
45449
|
-
const sourceArchivePath = path$1.join(workDir, archiveFilename);
|
|
45450
45237
|
const extractDir = path$1.join(workDir, "bundle");
|
|
45451
|
-
const
|
|
45238
|
+
const sourceManifestPath = path$1.join(workDir, "source-manifest.json");
|
|
45239
|
+
const manifestPath = path$1.join(extractDir, "manifest.json");
|
|
45452
45240
|
const uploadedStorageUris = [];
|
|
45453
45241
|
await fs$2.mkdir(extractDir, { recursive: true });
|
|
45454
45242
|
try {
|
|
45455
|
-
await
|
|
45456
|
-
const
|
|
45243
|
+
await downloadStorageObject(bundle.manifestStorageUri, storagePlugin, sourceManifestPath);
|
|
45244
|
+
const actualManifestHash = await getFileHash(sourceManifestPath);
|
|
45457
45245
|
const signingSession = await prepareBundleSigning(config.signing);
|
|
45458
|
-
if (isSignedFileHash(bundle.
|
|
45246
|
+
if (isSignedFileHash(bundle.manifestFileHash)) {
|
|
45459
45247
|
if (!signingSession) throw new Error("Cannot copy a signed bundle without enabled bundle signing configuration.");
|
|
45460
45248
|
if (!verifySignedFileHash({
|
|
45461
|
-
actualFileHash:
|
|
45249
|
+
actualFileHash: actualManifestHash,
|
|
45462
45250
|
publicKey: signingSession.publicKey,
|
|
45463
|
-
signedFileHash: bundle.
|
|
45464
|
-
})) throw new Error("Source
|
|
45465
|
-
} else if (
|
|
45466
|
-
const
|
|
45467
|
-
|
|
45251
|
+
signedFileHash: bundle.manifestFileHash
|
|
45252
|
+
})) throw new Error("Source manifest signature verification failed.");
|
|
45253
|
+
} else if (actualManifestHash !== bundle.manifestFileHash.toLowerCase()) throw new Error("Source manifest file hash verification failed.");
|
|
45254
|
+
const manifest = JSON.parse(await fs$2.readFile(sourceManifestPath, "utf8"));
|
|
45255
|
+
if (!manifest.assets || typeof manifest.assets !== "object") throw new Error(LEGACY_BUNDLE_ERROR);
|
|
45256
|
+
await downloadManifestAssets({
|
|
45257
|
+
bundle,
|
|
45258
|
+
manifest,
|
|
45259
|
+
outputDir: extractDir,
|
|
45260
|
+
storagePlugin,
|
|
45261
|
+
workDir
|
|
45262
|
+
});
|
|
45263
|
+
manifest.bundleId = nextBundleId;
|
|
45468
45264
|
const assetPaths = Object.keys(manifest.assets ?? {}).sort((left, right) => left.localeCompare(right));
|
|
45469
|
-
const sourceIsSigned =
|
|
45265
|
+
const sourceIsSigned = isSignedFileHash(getManifestFileHash(bundle));
|
|
45470
45266
|
const manifestHasSignatures = assetPaths.some((assetPath) => Boolean(manifest.assets?.[assetPath]?.signature));
|
|
45471
45267
|
if (!signingSession && (sourceIsSigned || manifestHasSignatures)) throw new Error("Cannot copy a signed bundle without enabled bundle signing configuration.");
|
|
45472
45268
|
if (signingSession) {
|
|
@@ -45486,16 +45282,22 @@ async function createCopiedBundleArchive({ bundle, config, nextBundleId, storage
|
|
|
45486
45282
|
manifest,
|
|
45487
45283
|
workDir
|
|
45488
45284
|
});
|
|
45285
|
+
const archivePath = path$1.join(workDir, "bundle.tar.br");
|
|
45286
|
+
manifest.archive = await createTarBrTargetFiles({
|
|
45287
|
+
outfile: archivePath,
|
|
45288
|
+
targetFiles: assetPaths.map((name) => ({
|
|
45289
|
+
name,
|
|
45290
|
+
path: resolveExtractedPath(extractDir, name)
|
|
45291
|
+
}))
|
|
45292
|
+
});
|
|
45489
45293
|
await fs$2.writeFile(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`);
|
|
45490
|
-
await fs$2.rm(sourceArchivePath, { force: true });
|
|
45491
|
-
await createArchiveFromDirectory(extractDir, outputArchivePath, format);
|
|
45492
|
-
const fileHash = await getFileHash(outputArchivePath);
|
|
45493
45294
|
const manifestHash = await getFileHash(manifestPath);
|
|
45494
|
-
const nextFileHash = signingSession ? `${SIGNED_HASH_PREFIX}${await signingSession.signFileHash(fileHash)}` : fileHash;
|
|
45495
45295
|
const nextManifestFileHash = signingSession ? `${SIGNED_HASH_PREFIX}${await signingSession.signFileHash(manifestHash)}` : manifestHash;
|
|
45496
|
-
const archiveUpload = await putStorageFile(storagePlugin, createBundleStorageKey(nextBundleId),
|
|
45296
|
+
const archiveUpload = await putStorageFile(storagePlugin, createBundleStorageKey(nextBundleId), archivePath);
|
|
45497
45297
|
uploadedStorageUris.push(archiveUpload.storageUri);
|
|
45498
|
-
const
|
|
45298
|
+
const manifestUpload = await putStorageFile(storagePlugin, createBundleStorageKey(nextBundleId), manifestPath);
|
|
45299
|
+
uploadedStorageUris.push(manifestUpload.storageUri);
|
|
45300
|
+
const assetBaseStorageUri = createStorageRootUriWithPath(manifestUpload.storageUri, nextBundleId, "assets");
|
|
45499
45301
|
for (const assetUploadTarget of assetUploadTargets) {
|
|
45500
45302
|
const storageUri = resolveManifestAssetStorageUri({
|
|
45501
45303
|
assetBaseStorageUri,
|
|
@@ -45506,15 +45308,10 @@ async function createCopiedBundleArchive({ bundle, config, nextBundleId, storage
|
|
|
45506
45308
|
const { exists } = await storagePlugin.exists({ storageUri });
|
|
45507
45309
|
if (!exists) await putStorageFile(storagePlugin, getRelativeStorageDir(assetUploadTarget.storagePath) ? `assets/${getRelativeStorageDir(assetUploadTarget.storagePath)}` : "assets", assetUploadTarget.uploadSourcePath);
|
|
45508
45310
|
}
|
|
45509
|
-
const manifestUpload = await putStorageFile(storagePlugin, createBundleStorageKey(nextBundleId), manifestPath);
|
|
45510
|
-
uploadedStorageUris.push(manifestUpload.storageUri);
|
|
45511
45311
|
return {
|
|
45512
45312
|
bundle: {
|
|
45513
45313
|
...bundle,
|
|
45514
45314
|
id: nextBundleId,
|
|
45515
|
-
archiveByteSize: archiveUpload.byteSize,
|
|
45516
|
-
storageUri: archiveUpload.storageUri,
|
|
45517
|
-
fileHash: nextFileHash,
|
|
45518
45315
|
metadata: stripBundleArtifactMetadata(bundle.metadata),
|
|
45519
45316
|
assetBaseStorageUri,
|
|
45520
45317
|
patches: [],
|
|
@@ -45611,4 +45408,4 @@ function transformTemplate(templateString, values) {
|
|
|
45611
45408
|
return result;
|
|
45612
45409
|
}
|
|
45613
45410
|
//#endregion
|
|
45614
|
-
export { BuildLogger, ConfigBuilder, HOT_UPDATER_SERVER_PACKAGE_VERSION_ENV, HotUpdateDirUtil, InitEnvFileError, InitError, LEGACY_BUNDLE_ERROR, LegacyInfrastructureError, MissingInitInputsError, assertInfrastructureGenerationAtUrl, assertInfrastructureGenerationPayload, assertInitInputs, assertInitProviderInputs, banner, typedColors as colors, confirmInitInputPersistence, copyDirToTmp,
|
|
45411
|
+
export { BuildLogger, ConfigBuilder, HOT_UPDATER_PLUGINS_PATH, HOT_UPDATER_SERVER_PACKAGE_VERSION_ENV, HotUpdateDirUtil, InitEnvFileError, InitError, LEGACY_BUNDLE_ERROR, LegacyInfrastructureError, MissingInitInputsError, assertInfrastructureGenerationAtUrl, assertInfrastructureGenerationPayload, assertInitInputs, assertInitProviderInputs, banner, typedColors as colors, confirmInitInputPersistence, copyDirToTmp, createCopiedBundleArtifacts, createHotUpdaterConfigScaffold, createHotUpdaterConfigScaffoldFromBuilder, createLogWriter, createTarBrTargetFiles, createZip, decryptJson, defineInitProvider, encryptJson, ensureInstallPackages, formatApiKeyNote, generateHotUpdaterPlugins, getAndroidSdkPath, getBundleSigningPublicKey, getCwd, getHotUpdaterEnvValue, getHotUpdaterInitInputEnv, getInitProviderEnvVars, getInitProviderTextPromptValues, getMissingInitInputs, getMissingInitProviderInputs, getPackageManager, getReactNativeMetadatas, getStorageFileByteSize, link, loadConfig, loadHotUpdaterPlugins, log, makeEnv, p, prepareBundleSigning, printBanner, putStorageFile, readBundleSigningPublicKeyFile, readHotUpdaterEnv, readHotUpdaterInitEnv, readPackageUp, renderHotUpdaterPlugins, renderImportStatements, resolveHotUpdaterServerVersion, resolveInitProviderInput, resolveInitProviderInputs, resolvePackageVersion, shouldAutoSelectOnlyInitResource, stripAnsi, transformEnv, transformTemplate, writeHotUpdaterConfig, writeHotUpdaterPlugins, writeStorageFile, writeStorageResponseFile };
|
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.16",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=20.19.0"
|
|
@@ -49,8 +49,8 @@
|
|
|
49
49
|
"oxc-parser": "0.141.0",
|
|
50
50
|
"oxc-transform": "0.141.0",
|
|
51
51
|
"unconfig": "7.5.0",
|
|
52
|
-
"@hot-updater/core": "1.0.0-rc.
|
|
53
|
-
"@hot-updater/plugin-core": "1.0.0-rc.
|
|
52
|
+
"@hot-updater/core": "1.0.0-rc.15",
|
|
53
|
+
"@hot-updater/plugin-core": "1.0.0-rc.16"
|
|
54
54
|
},
|
|
55
55
|
"devDependencies": {
|
|
56
56
|
"@clack/prompts": "1.7.0",
|
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
"tar": "^7.5.16",
|
|
65
65
|
"verkit": "0.4.0",
|
|
66
66
|
"workspace-tools": "^0.41.7",
|
|
67
|
-
"@hot-updater/test-utils": "1.0.0-rc.
|
|
67
|
+
"@hot-updater/test-utils": "1.0.0-rc.16"
|
|
68
68
|
},
|
|
69
69
|
"inlinedDependencies": {
|
|
70
70
|
"@babel/code-frame": "7.29.0",
|
|
@@ -174,7 +174,7 @@
|
|
|
174
174
|
"7.1.0"
|
|
175
175
|
],
|
|
176
176
|
"strip-final-newline": "4.0.0",
|
|
177
|
-
"tar": "7.5.
|
|
177
|
+
"tar": "7.5.16",
|
|
178
178
|
"to-regex-range": "5.0.1",
|
|
179
179
|
"unicorn-magic": [
|
|
180
180
|
"0.1.0",
|