@rudderhq/cli 0.2.8-canary.1 → 0.2.8-canary.2
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.js +128 -18
- package/dist/index.js.map +3 -3
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -6449,6 +6449,7 @@ import { homedir, tmpdir } from "node:os";
|
|
|
6449
6449
|
import path11 from "node:path";
|
|
6450
6450
|
import { Readable, Transform } from "node:stream";
|
|
6451
6451
|
import { pipeline } from "node:stream/promises";
|
|
6452
|
+
import { clearTimeout as clearTimeout2, setTimeout as setTimeout2 } from "node:timers";
|
|
6452
6453
|
import { setTimeout as delay } from "node:timers/promises";
|
|
6453
6454
|
import * as p13 from "@clack/prompts";
|
|
6454
6455
|
import pc8 from "picocolors";
|
|
@@ -6693,7 +6694,7 @@ function compareStableSemver(a, b) {
|
|
|
6693
6694
|
}
|
|
6694
6695
|
async function fetchLatestCliVersion() {
|
|
6695
6696
|
const controller = new AbortController();
|
|
6696
|
-
const timeout =
|
|
6697
|
+
const timeout = setTimeout2(() => controller.abort(), 2e3);
|
|
6697
6698
|
try {
|
|
6698
6699
|
const response = await fetch(CLI_REGISTRY_LATEST_URL, {
|
|
6699
6700
|
signal: controller.signal,
|
|
@@ -6705,7 +6706,7 @@ async function fetchLatestCliVersion() {
|
|
|
6705
6706
|
} catch {
|
|
6706
6707
|
return null;
|
|
6707
6708
|
} finally {
|
|
6708
|
-
|
|
6709
|
+
clearTimeout2(timeout);
|
|
6709
6710
|
}
|
|
6710
6711
|
}
|
|
6711
6712
|
async function getCliUpdateNotice(currentVersion) {
|
|
@@ -6723,6 +6724,9 @@ function resolveDesktopReleaseTag(version) {
|
|
|
6723
6724
|
`Desktop release lookup requires a release version like 0.1.0 or 0.1.0-canary.0. Received ${version}.`
|
|
6724
6725
|
);
|
|
6725
6726
|
}
|
|
6727
|
+
function isExactRuntimePackageSpec(version, packageSpec) {
|
|
6728
|
+
return version !== "latest" && packageSpec === resolveRuntimePackageSpec(version);
|
|
6729
|
+
}
|
|
6726
6730
|
function resolveDesktopAssetTarget(platform = process.platform, arch = process.arch) {
|
|
6727
6731
|
if (platform === "darwin") {
|
|
6728
6732
|
if (arch !== "x64" && arch !== "arm64") {
|
|
@@ -6782,6 +6786,7 @@ function scoreDesktopAsset(asset, target) {
|
|
|
6782
6786
|
const expectedExtension = target.extension.toLowerCase();
|
|
6783
6787
|
if (!normalized.endsWith(expectedExtension.toLowerCase())) return -1;
|
|
6784
6788
|
if (normalized.includes("blockmap") || normalized.includes("shasum")) return -1;
|
|
6789
|
+
if (normalized.includes("shell")) return -1;
|
|
6785
6790
|
let score = 1;
|
|
6786
6791
|
if (normalized.includes("rudder")) score += 2;
|
|
6787
6792
|
if (normalized.includes(target.platform)) score += 4;
|
|
@@ -6808,18 +6813,77 @@ function selectDesktopAsset(assets, target) {
|
|
|
6808
6813
|
const exactArch = equallyGood.find((item) => normalizeAssetName(item.asset.name).includes(target.arch));
|
|
6809
6814
|
return exactArch?.asset ?? best.asset;
|
|
6810
6815
|
}
|
|
6816
|
+
function selectDesktopShellAsset(assets, target) {
|
|
6817
|
+
if (!resolveDesktopShellAssetName("", target)) return null;
|
|
6818
|
+
const scored = assets.map((asset) => {
|
|
6819
|
+
const normalized = normalizeAssetName(asset.name);
|
|
6820
|
+
if (!normalized.endsWith(".zip")) return { asset, score: -1 };
|
|
6821
|
+
if (!normalized.includes("shell")) return { asset, score: -1 };
|
|
6822
|
+
if (!normalized.includes("rudder")) return { asset, score: -1 };
|
|
6823
|
+
if (!normalized.includes(target.platform)) return { asset, score: -1 };
|
|
6824
|
+
let score = 1;
|
|
6825
|
+
if (target.arch === "arm64" && normalized.includes("arm64")) score += 4;
|
|
6826
|
+
if (target.arch === "x64" && (normalized.includes("x64") || normalized.includes("amd64"))) score += 4;
|
|
6827
|
+
if (target.platform === "macos" && target.arch === "x64" && normalized.includes("arm64")) score -= 10;
|
|
6828
|
+
if (target.arch === "arm64" && normalized.includes("x64")) score -= 10;
|
|
6829
|
+
return { asset, score };
|
|
6830
|
+
}).filter((item) => item.score >= 0).sort((a, b) => b.score - a.score || a.asset.name.localeCompare(b.asset.name));
|
|
6831
|
+
return scored[0]?.asset ?? null;
|
|
6832
|
+
}
|
|
6833
|
+
function resolveDesktopAssetCandidates(options) {
|
|
6834
|
+
const candidates = [];
|
|
6835
|
+
const deterministicShellName = options.directReleaseVersion ? resolveDesktopShellAssetName(options.directReleaseVersion, options.target) : null;
|
|
6836
|
+
if (options.allowShellAssets !== false) {
|
|
6837
|
+
const shellAsset = selectDesktopShellAsset(options.releaseAssets, options.target) ?? (options.releaseAssets.length === 0 && deterministicShellName ? buildGithubReleaseAsset(options.repo, options.tag, deterministicShellName) : null);
|
|
6838
|
+
if (shellAsset) candidates.push({ asset: shellAsset, kind: "shell" });
|
|
6839
|
+
}
|
|
6840
|
+
const fullAsset = selectDesktopAsset(options.releaseAssets, options.target) ?? (options.directReleaseVersion ? buildGithubReleaseAsset(options.repo, options.tag, resolveDesktopAssetName(options.directReleaseVersion, options.target)) : null);
|
|
6841
|
+
if (fullAsset) candidates.push({ asset: fullAsset, kind: "full" });
|
|
6842
|
+
return candidates;
|
|
6843
|
+
}
|
|
6844
|
+
function selectChecksummedDesktopAssetCandidate(candidates, checksums) {
|
|
6845
|
+
const warnings = [];
|
|
6846
|
+
for (const candidate of candidates) {
|
|
6847
|
+
try {
|
|
6848
|
+
return {
|
|
6849
|
+
...candidate,
|
|
6850
|
+
expectedChecksum: resolveAssetChecksum(checksums, candidate.asset.name),
|
|
6851
|
+
warnings
|
|
6852
|
+
};
|
|
6853
|
+
} catch (error) {
|
|
6854
|
+
if (candidate.kind === "shell") {
|
|
6855
|
+
warnings.push(
|
|
6856
|
+
`Layered Desktop shell asset is missing from ${DESKTOP_CHECKSUM_ASSET_NAME}; falling back to the full portable asset.`
|
|
6857
|
+
);
|
|
6858
|
+
continue;
|
|
6859
|
+
}
|
|
6860
|
+
throw error;
|
|
6861
|
+
}
|
|
6862
|
+
}
|
|
6863
|
+
throw new Error("No checksummed Rudder Desktop asset candidate is available.");
|
|
6864
|
+
}
|
|
6811
6865
|
function selectChecksumAsset(assets) {
|
|
6812
6866
|
return assets.find((asset) => asset.name.toLowerCase() === DESKTOP_CHECKSUM_ASSET_NAME.toLowerCase()) ?? null;
|
|
6813
6867
|
}
|
|
6868
|
+
async function fetchWithTimeout(url, init, timeoutMs) {
|
|
6869
|
+
const controller = new AbortController();
|
|
6870
|
+
const timeout = setTimeout2(() => controller.abort(), timeoutMs);
|
|
6871
|
+
try {
|
|
6872
|
+
return await fetch(url, { ...init, signal: controller.signal });
|
|
6873
|
+
} finally {
|
|
6874
|
+
clearTimeout2(timeout);
|
|
6875
|
+
}
|
|
6876
|
+
}
|
|
6814
6877
|
function githubApiHeaders() {
|
|
6815
6878
|
return {
|
|
6816
6879
|
Accept: "application/vnd.github+json",
|
|
6817
6880
|
"User-Agent": "rudder-cli-installer"
|
|
6818
6881
|
};
|
|
6819
6882
|
}
|
|
6883
|
+
var GITHUB_API_TIMEOUT_MS = 15e3;
|
|
6820
6884
|
async function fetchGithubRelease(repo, tag) {
|
|
6821
6885
|
const endpoint = tag === "latest" ? `https://api.github.com/repos/${repo}/releases/latest` : `https://api.github.com/repos/${repo}/releases/tags/${encodeURIComponent(tag)}`;
|
|
6822
|
-
const response = await
|
|
6886
|
+
const response = await fetchWithTimeout(endpoint, { headers: githubApiHeaders() }, GITHUB_API_TIMEOUT_MS);
|
|
6823
6887
|
if (!response.ok) {
|
|
6824
6888
|
throw new Error(`GitHub Release ${tag} was not found in ${repo} (${response.status}).`);
|
|
6825
6889
|
}
|
|
@@ -6838,6 +6902,11 @@ function resolveDesktopAssetName(version, target) {
|
|
|
6838
6902
|
if (target.platform === "windows") return `${DESKTOP_APP_NAME}-${version}-windows-x64-portable.zip`;
|
|
6839
6903
|
return `${DESKTOP_APP_NAME}-${version}-linux-x64.AppImage`;
|
|
6840
6904
|
}
|
|
6905
|
+
function resolveDesktopShellAssetName(version, target) {
|
|
6906
|
+
if (target.platform === "macos") return `${DESKTOP_APP_NAME}-${version}-macos-${target.arch}-shell.zip`;
|
|
6907
|
+
if (target.platform === "windows") return `${DESKTOP_APP_NAME}-${version}-windows-x64-shell.zip`;
|
|
6908
|
+
return null;
|
|
6909
|
+
}
|
|
6841
6910
|
function encodeReleaseTagForDownloadUrl(tag) {
|
|
6842
6911
|
return tag.split("/").map((segment) => encodeURIComponent(segment)).join("/");
|
|
6843
6912
|
}
|
|
@@ -6852,7 +6921,7 @@ function buildGithubReleaseAsset(repo, tag, assetName) {
|
|
|
6852
6921
|
};
|
|
6853
6922
|
}
|
|
6854
6923
|
function uniqueAssetDownloadUrls(asset) {
|
|
6855
|
-
const urls = [asset.
|
|
6924
|
+
const urls = [asset.browser_download_url, asset.url].filter((url) => Boolean(url));
|
|
6856
6925
|
return Array.from(new Set(urls));
|
|
6857
6926
|
}
|
|
6858
6927
|
function downloadHeadersForAssetUrl(asset, url) {
|
|
@@ -6880,13 +6949,16 @@ function contentLengthFromHeaders(headers) {
|
|
|
6880
6949
|
async function downloadAsset(asset, outputDir, progressFactory = createByteProgress) {
|
|
6881
6950
|
mkdirSync(outputDir, { recursive: true });
|
|
6882
6951
|
const outputPath = path11.join(outputDir, path11.basename(asset.name));
|
|
6952
|
+
const ASSET_DOWNLOAD_TIMEOUT_MS = 6e5;
|
|
6883
6953
|
let response = null;
|
|
6884
6954
|
const failures = [];
|
|
6885
6955
|
for (const url of uniqueAssetDownloadUrls(asset)) {
|
|
6886
6956
|
try {
|
|
6887
|
-
const candidate = await
|
|
6888
|
-
|
|
6889
|
-
|
|
6957
|
+
const candidate = await fetchWithTimeout(
|
|
6958
|
+
url,
|
|
6959
|
+
{ headers: downloadHeadersForAssetUrl(asset, url) },
|
|
6960
|
+
ASSET_DOWNLOAD_TIMEOUT_MS
|
|
6961
|
+
);
|
|
6890
6962
|
if (candidate.ok && candidate.body) {
|
|
6891
6963
|
response = candidate;
|
|
6892
6964
|
break;
|
|
@@ -7323,13 +7395,14 @@ function launchDesktop(paths, target) {
|
|
|
7323
7395
|
}
|
|
7324
7396
|
spawn(paths.executablePath, [], { detached: true, stdio: "ignore" }).unref();
|
|
7325
7397
|
}
|
|
7326
|
-
async function writeInstallMetadata(paths, releaseTag, assetName, assetChecksum) {
|
|
7398
|
+
async function writeInstallMetadata(paths, releaseTag, assetName, assetChecksum, assetKind = "full") {
|
|
7327
7399
|
mkdirSync(path11.dirname(paths.metadataPath), { recursive: true });
|
|
7328
7400
|
const metadata = {
|
|
7329
7401
|
version: 1,
|
|
7330
7402
|
releaseTag,
|
|
7331
7403
|
assetName,
|
|
7332
7404
|
assetChecksum,
|
|
7405
|
+
assetKind,
|
|
7333
7406
|
installedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
7334
7407
|
};
|
|
7335
7408
|
mkdirSync(paths.installRoot, { recursive: true });
|
|
@@ -7369,6 +7442,7 @@ async function startCommand(opts) {
|
|
|
7369
7442
|
const version = opts.targetVersion?.trim() || opts.version?.trim() || resolveCurrentCliVersion();
|
|
7370
7443
|
const dryRun = opts.dryRun === true;
|
|
7371
7444
|
const desktopProgressJson = opts.desktopProgressJson === true;
|
|
7445
|
+
let runtimeSupportsShellAssets = false;
|
|
7372
7446
|
if (desktopProgressJson) {
|
|
7373
7447
|
process.stdout.on("error", (error) => {
|
|
7374
7448
|
if (error.code !== "EPIPE") throw error;
|
|
@@ -7391,9 +7465,13 @@ async function startCommand(opts) {
|
|
|
7391
7465
|
spinner3.start("Installing or reusing Rudder runtime...");
|
|
7392
7466
|
try {
|
|
7393
7467
|
const runtime = await ensureRuntimeInstalled({ version });
|
|
7468
|
+
runtimeSupportsShellAssets = isExactRuntimePackageSpec(version, runtime.packageSpec);
|
|
7394
7469
|
spinner3.stop(
|
|
7395
7470
|
runtime.status === "hit" ? `Rudder runtime cache hit at ${pc8.cyan(runtime.cacheDir)}.` : `Rudder runtime installed at ${pc8.cyan(runtime.cacheDir)}.`
|
|
7396
7471
|
);
|
|
7472
|
+
if (!runtimeSupportsShellAssets && installDesktop) {
|
|
7473
|
+
p13.log.warn("Rudder runtime did not resolve to the exact Desktop version; the full portable Desktop asset will be used.");
|
|
7474
|
+
}
|
|
7397
7475
|
} catch (error) {
|
|
7398
7476
|
spinner3.stop(pc8.red("Rudder runtime installation failed."));
|
|
7399
7477
|
if (error instanceof RuntimeInstallError && error.output) {
|
|
@@ -7466,15 +7544,31 @@ async function startCommand(opts) {
|
|
|
7466
7544
|
if (!releaseTag) {
|
|
7467
7545
|
throw new Error(`Unable to resolve Rudder Desktop release tag for ${repo}@${tag}.`);
|
|
7468
7546
|
}
|
|
7469
|
-
const
|
|
7470
|
-
|
|
7547
|
+
const assetCandidates = resolveDesktopAssetCandidates({
|
|
7548
|
+
releaseAssets: release?.assets ?? [],
|
|
7549
|
+
target,
|
|
7550
|
+
repo,
|
|
7551
|
+
tag,
|
|
7552
|
+
directReleaseVersion,
|
|
7553
|
+
allowShellAssets: runtimeSupportsShellAssets
|
|
7554
|
+
});
|
|
7555
|
+
if (assetCandidates.length === 0) {
|
|
7471
7556
|
throw new Error(`No Rudder Desktop portable asset found for ${target.platform}/${target.arch} in ${repo}@${releaseTag}.`);
|
|
7472
7557
|
}
|
|
7473
7558
|
const checksumAsset = selectChecksumAsset(release?.assets ?? []) ?? (directReleaseVersion ? buildGithubReleaseAsset(repo, tag, DESKTOP_CHECKSUM_ASSET_NAME) : null);
|
|
7474
7559
|
const checksums = await downloadChecksums(checksumAsset, outputDir, progressFactory);
|
|
7475
|
-
|
|
7560
|
+
let selectedCandidate;
|
|
7561
|
+
try {
|
|
7562
|
+
selectedCandidate = selectChecksummedDesktopAssetCandidate(assetCandidates, checksums);
|
|
7563
|
+
} catch (error) {
|
|
7564
|
+
throw new Error(`No checksummed Rudder Desktop asset found for ${target.platform}/${target.arch} in ${repo}@${releaseTag}.`);
|
|
7565
|
+
}
|
|
7566
|
+
for (const warning of selectedCandidate.warnings) p13.log.warn(warning);
|
|
7567
|
+
let selectedAsset = selectedCandidate.asset;
|
|
7568
|
+
let selectedAssetKind = selectedCandidate.kind;
|
|
7569
|
+
let expectedChecksum = selectedCandidate.expectedChecksum;
|
|
7476
7570
|
const metadata = await readInstallMetadata(installPaths.metadataPath);
|
|
7477
|
-
if (isInstalledDesktopCurrent(metadata, releaseTag,
|
|
7571
|
+
if (isInstalledDesktopCurrent(metadata, releaseTag, selectedAsset.name, expectedChecksum) && await pathExists(installPaths.executablePath)) {
|
|
7478
7572
|
p13.log.success(`Rudder Desktop is already installed at ${pc8.cyan(installPaths.appPath)}.`);
|
|
7479
7573
|
await runStartPhase(
|
|
7480
7574
|
"Refreshing Desktop launchers...",
|
|
@@ -7486,16 +7580,32 @@ async function startCommand(opts) {
|
|
|
7486
7580
|
desktopProgressJson ? "preparing_restart" : null
|
|
7487
7581
|
);
|
|
7488
7582
|
} else {
|
|
7489
|
-
|
|
7490
|
-
|
|
7491
|
-
|
|
7492
|
-
|
|
7583
|
+
let cachedAsset;
|
|
7584
|
+
try {
|
|
7585
|
+
cachedAsset = await downloadDesktopAssetWithCache(selectedAsset, expectedChecksum, {
|
|
7586
|
+
outputDir,
|
|
7587
|
+
progressFactory
|
|
7588
|
+
});
|
|
7589
|
+
} catch (error) {
|
|
7590
|
+
const fullCandidate = assetCandidates.find((candidate) => candidate.kind === "full");
|
|
7591
|
+
if (selectedAssetKind !== "shell" || !fullCandidate) throw error;
|
|
7592
|
+
p13.log.warn(
|
|
7593
|
+
`Layered Desktop shell asset download failed; falling back to the full portable asset. ${formatFetchError(error)}`
|
|
7594
|
+
);
|
|
7595
|
+
selectedAsset = fullCandidate.asset;
|
|
7596
|
+
selectedAssetKind = fullCandidate.kind;
|
|
7597
|
+
expectedChecksum = resolveAssetChecksum(checksums, selectedAsset.name);
|
|
7598
|
+
cachedAsset = await downloadDesktopAssetWithCache(selectedAsset, expectedChecksum, {
|
|
7599
|
+
outputDir,
|
|
7600
|
+
progressFactory
|
|
7601
|
+
});
|
|
7602
|
+
}
|
|
7493
7603
|
if (cachedAsset.cacheStatus === "hit") {
|
|
7494
7604
|
p13.log.success(`Desktop asset cache hit at ${pc8.cyan(cachedAsset.path)}.`);
|
|
7495
7605
|
if (desktopProgressJson) {
|
|
7496
7606
|
writeDesktopProgress({
|
|
7497
7607
|
phase: "downloading_asset",
|
|
7498
|
-
message: `Desktop asset cache hit for ${
|
|
7608
|
+
message: `Desktop asset cache hit for ${selectedAsset.name}.`,
|
|
7499
7609
|
percent: 100
|
|
7500
7610
|
});
|
|
7501
7611
|
}
|
|
@@ -7539,7 +7649,7 @@ async function startCommand(opts) {
|
|
|
7539
7649
|
},
|
|
7540
7650
|
desktopProgressJson ? "preparing_restart" : null
|
|
7541
7651
|
);
|
|
7542
|
-
await writeInstallMetadata(installPaths, releaseTag,
|
|
7652
|
+
await writeInstallMetadata(installPaths, releaseTag, selectedAsset.name, checksum, selectedAssetKind);
|
|
7543
7653
|
}
|
|
7544
7654
|
if (opts.open !== false) {
|
|
7545
7655
|
await runStartPhase(
|