@rudderhq/cli 0.7.19 → 0.7.20
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/README.md +11 -1
- package/dist/index.js +1490 -696
- package/dist/index.js.map +4 -4
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -22345,6 +22345,256 @@ var init_native_payload = __esm({
|
|
|
22345
22345
|
}
|
|
22346
22346
|
});
|
|
22347
22347
|
|
|
22348
|
+
// src/runtime/platform-dependencies.ts
|
|
22349
|
+
import { mkdir, readFile, rm } from "node:fs/promises";
|
|
22350
|
+
import path10 from "node:path";
|
|
22351
|
+
function runtimePackageJsonPath(cacheDir, packageName) {
|
|
22352
|
+
return path10.join(cacheDir, "node_modules", ...packageName.split("/"), "package.json");
|
|
22353
|
+
}
|
|
22354
|
+
async function readRuntimePackageJson(cacheDir, packageName) {
|
|
22355
|
+
try {
|
|
22356
|
+
return JSON.parse(await readFile(runtimePackageJsonPath(cacheDir, packageName), "utf8"));
|
|
22357
|
+
} catch {
|
|
22358
|
+
return null;
|
|
22359
|
+
}
|
|
22360
|
+
}
|
|
22361
|
+
async function canResolveRuntimePackage(cacheDir, packageName) {
|
|
22362
|
+
try {
|
|
22363
|
+
await readFile(runtimePackageJsonPath(cacheDir, packageName), "utf8");
|
|
22364
|
+
return true;
|
|
22365
|
+
} catch {
|
|
22366
|
+
return false;
|
|
22367
|
+
}
|
|
22368
|
+
}
|
|
22369
|
+
async function removeRuntimeInstallLocks(cacheDir) {
|
|
22370
|
+
await Promise.all([
|
|
22371
|
+
rm(path10.join(cacheDir, "package-lock.json"), { force: true }),
|
|
22372
|
+
rm(path10.join(cacheDir, "node_modules", ".package-lock.json"), { force: true })
|
|
22373
|
+
]);
|
|
22374
|
+
}
|
|
22375
|
+
function packageNameFromSpec(packageSpec) {
|
|
22376
|
+
if (!packageSpec.startsWith("@")) {
|
|
22377
|
+
const versionSeparator2 = packageSpec.indexOf("@");
|
|
22378
|
+
return versionSeparator2 === -1 ? packageSpec : packageSpec.slice(0, versionSeparator2);
|
|
22379
|
+
}
|
|
22380
|
+
const versionSeparator = packageSpec.indexOf("@", 1);
|
|
22381
|
+
return versionSeparator === -1 ? packageSpec : packageSpec.slice(0, versionSeparator);
|
|
22382
|
+
}
|
|
22383
|
+
function normalizeOptionalDependencyVersion(versionRange) {
|
|
22384
|
+
const trimmed = versionRange?.trim();
|
|
22385
|
+
if (!trimmed) return null;
|
|
22386
|
+
const exactVersion = /^[~^]\s*([0-9]+\.[0-9]+\.[0-9]+(?:-[0-9A-Za-z.-]+)?)$/.exec(trimmed);
|
|
22387
|
+
return exactVersion?.[1] ?? trimmed;
|
|
22388
|
+
}
|
|
22389
|
+
async function installRuntimePackageInStaging(spawnSyncImpl, cacheDir, packageSpec, packageName, options) {
|
|
22390
|
+
const stagingDir = path10.join(cacheDir, `.platform-repair-${process.pid}-${Date.now()}`);
|
|
22391
|
+
await mkdir(stagingDir, { recursive: true });
|
|
22392
|
+
try {
|
|
22393
|
+
const packResult = runNpmPack(spawnSyncImpl, packageSpec, stagingDir, options);
|
|
22394
|
+
if (packResult.status !== 0) return packResult;
|
|
22395
|
+
const packFilename = parseNpmPackFilename(packResult.stdout);
|
|
22396
|
+
if (!packFilename) {
|
|
22397
|
+
return createSyntheticSpawnResult(1, "", `Unable to parse npm pack output for ${packageSpec}.`);
|
|
22398
|
+
}
|
|
22399
|
+
const archivePath = path10.join(stagingDir, packFilename);
|
|
22400
|
+
const targetDir = path10.dirname(runtimePackageJsonPath(cacheDir, packageName));
|
|
22401
|
+
await mkdir(path10.dirname(targetDir), { recursive: true });
|
|
22402
|
+
await rm(targetDir, { recursive: true, force: true });
|
|
22403
|
+
await mkdir(targetDir, { recursive: true });
|
|
22404
|
+
const extractResult = runTarExtract(spawnSyncImpl, archivePath, targetDir, options);
|
|
22405
|
+
return combineSpawnResults(packResult, extractResult);
|
|
22406
|
+
} finally {
|
|
22407
|
+
await rm(stagingDir, { recursive: true, force: true });
|
|
22408
|
+
}
|
|
22409
|
+
}
|
|
22410
|
+
function runNpmPack(spawnSyncImpl, packageSpec, destinationDir, options) {
|
|
22411
|
+
const timeout = options.remainingMs(options.deadline, options.cacheDir, `npm pack ${packageSpec}`);
|
|
22412
|
+
const npm = resolveNpmCommandInvocation();
|
|
22413
|
+
return spawnSyncImpl(
|
|
22414
|
+
npm.command,
|
|
22415
|
+
[
|
|
22416
|
+
...npm.args,
|
|
22417
|
+
"pack",
|
|
22418
|
+
packageSpec,
|
|
22419
|
+
"--pack-destination",
|
|
22420
|
+
destinationDir,
|
|
22421
|
+
"--registry",
|
|
22422
|
+
NPM_PUBLIC_REGISTRY_URL,
|
|
22423
|
+
"--silent"
|
|
22424
|
+
],
|
|
22425
|
+
{
|
|
22426
|
+
encoding: "utf8",
|
|
22427
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
22428
|
+
env: { ...process.env, ...NPM_PLATFORM_REPAIR_ENV },
|
|
22429
|
+
...timeout === void 0 ? {} : { timeout },
|
|
22430
|
+
...process.platform === "win32" ? { windowsHide: true } : {}
|
|
22431
|
+
}
|
|
22432
|
+
);
|
|
22433
|
+
}
|
|
22434
|
+
function runTarExtract(spawnSyncImpl, archivePath, targetDir, options) {
|
|
22435
|
+
const timeout = options.remainingMs(options.deadline, options.cacheDir, "extract runtime platform package");
|
|
22436
|
+
return spawnSyncImpl(
|
|
22437
|
+
"tar",
|
|
22438
|
+
["-xzf", archivePath, "-C", targetDir, "--strip-components", "1"],
|
|
22439
|
+
{
|
|
22440
|
+
encoding: "utf8",
|
|
22441
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
22442
|
+
...timeout === void 0 ? {} : { timeout },
|
|
22443
|
+
...process.platform === "win32" ? { windowsHide: true } : {}
|
|
22444
|
+
}
|
|
22445
|
+
);
|
|
22446
|
+
}
|
|
22447
|
+
function parseNpmPackFilename(stdout) {
|
|
22448
|
+
if (typeof stdout !== "string") return null;
|
|
22449
|
+
const filename = stdout.trim().split(/\r?\n/).filter(Boolean).at(-1);
|
|
22450
|
+
return filename?.endsWith(".tgz") ? filename : null;
|
|
22451
|
+
}
|
|
22452
|
+
function createSyntheticSpawnResult(status, stdout, stderr) {
|
|
22453
|
+
return { status, stdout, stderr };
|
|
22454
|
+
}
|
|
22455
|
+
function combineSpawnResults(...results) {
|
|
22456
|
+
const last = results.at(-1);
|
|
22457
|
+
return {
|
|
22458
|
+
status: last?.status ?? 0,
|
|
22459
|
+
stdout: results.map((result) => result.stdout).filter(Boolean).join("\n"),
|
|
22460
|
+
stderr: results.map((result) => result.stderr).filter(Boolean).join("\n"),
|
|
22461
|
+
error: results.find((result) => result.error)?.error
|
|
22462
|
+
};
|
|
22463
|
+
}
|
|
22464
|
+
function isLinuxGlibcRuntime() {
|
|
22465
|
+
try {
|
|
22466
|
+
const report = process.report?.getReport();
|
|
22467
|
+
return typeof report.header?.glibcVersionRuntime === "string";
|
|
22468
|
+
} catch {
|
|
22469
|
+
return true;
|
|
22470
|
+
}
|
|
22471
|
+
}
|
|
22472
|
+
function resolveSharpPlatformPackageName(sharpPackage) {
|
|
22473
|
+
const platformPrefixes = process.platform === "linux" ? [
|
|
22474
|
+
isLinuxGlibcRuntime() ? "linux" : "linuxmusl",
|
|
22475
|
+
"linux",
|
|
22476
|
+
"linuxmusl"
|
|
22477
|
+
] : [process.platform];
|
|
22478
|
+
for (const platformPrefix of platformPrefixes) {
|
|
22479
|
+
const packageName = `@img/sharp-${platformPrefix}-${process.arch}`;
|
|
22480
|
+
if (sharpPackage.optionalDependencies?.[packageName]) return packageName;
|
|
22481
|
+
}
|
|
22482
|
+
return null;
|
|
22483
|
+
}
|
|
22484
|
+
async function hasRequiredRuntimeNativeDependencies(cacheDir) {
|
|
22485
|
+
const sharpPackage = await readRuntimePackageJson(cacheDir, "sharp");
|
|
22486
|
+
if (!sharpPackage) return true;
|
|
22487
|
+
const platformPackageName = resolveSharpPlatformPackageName(sharpPackage);
|
|
22488
|
+
if (!platformPackageName) return true;
|
|
22489
|
+
const requiredPackages = [{
|
|
22490
|
+
name: platformPackageName,
|
|
22491
|
+
version: normalizeOptionalDependencyVersion(sharpPackage.optionalDependencies?.[platformPackageName])
|
|
22492
|
+
}];
|
|
22493
|
+
for (let index = 0; index < requiredPackages.length; index += 1) {
|
|
22494
|
+
const requiredPackage = requiredPackages[index];
|
|
22495
|
+
const packageJson = await readRuntimePackageJson(cacheDir, requiredPackage.name);
|
|
22496
|
+
if (!packageJson || requiredPackage.version !== null && packageJson.version !== requiredPackage.version) return false;
|
|
22497
|
+
for (const [dependencyName, versionRange] of Object.entries(packageJson.optionalDependencies ?? {})) {
|
|
22498
|
+
if (!requiredPackages.some(({ name }) => name === dependencyName)) {
|
|
22499
|
+
requiredPackages.push({
|
|
22500
|
+
name: dependencyName,
|
|
22501
|
+
version: normalizeOptionalDependencyVersion(versionRange)
|
|
22502
|
+
});
|
|
22503
|
+
}
|
|
22504
|
+
}
|
|
22505
|
+
}
|
|
22506
|
+
return true;
|
|
22507
|
+
}
|
|
22508
|
+
async function ensureRuntimeNativeDependencies(options) {
|
|
22509
|
+
if (process.env.RUDDER_RUNTIME_INSTALL_OMIT_OPTIONAL !== "true") return "";
|
|
22510
|
+
const sharpPackage = await readRuntimePackageJson(options.cacheDir, "sharp");
|
|
22511
|
+
if (!sharpPackage) return "";
|
|
22512
|
+
const platformPackageName = resolveSharpPlatformPackageName(sharpPackage);
|
|
22513
|
+
if (!platformPackageName) return "";
|
|
22514
|
+
const installOptions = {
|
|
22515
|
+
deadline: options.deadline,
|
|
22516
|
+
cacheDir: options.cacheDir,
|
|
22517
|
+
remainingMs: options.remainingMs
|
|
22518
|
+
};
|
|
22519
|
+
const requiredPackageVersions = /* @__PURE__ */ new Map([
|
|
22520
|
+
[platformPackageName, normalizeOptionalDependencyVersion(sharpPackage.optionalDependencies?.[platformPackageName])]
|
|
22521
|
+
]);
|
|
22522
|
+
const requiredPackages = /* @__PURE__ */ new Set([platformPackageName]);
|
|
22523
|
+
let output = "";
|
|
22524
|
+
for (let pass = 0; pass < 8; pass += 1) {
|
|
22525
|
+
const missingSpecs = [];
|
|
22526
|
+
for (const packageName of requiredPackages) {
|
|
22527
|
+
const version = requiredPackageVersions.get(packageName) ?? null;
|
|
22528
|
+
const packageJson = await readRuntimePackageJson(options.cacheDir, packageName);
|
|
22529
|
+
if (packageJson && (version === null || packageJson.version === version)) continue;
|
|
22530
|
+
missingSpecs.push(version ? `${packageName}@${version}` : packageName);
|
|
22531
|
+
}
|
|
22532
|
+
if (missingSpecs.length > 0) {
|
|
22533
|
+
await removeRuntimeInstallLocks(options.cacheDir);
|
|
22534
|
+
for (const packageSpec of missingSpecs) {
|
|
22535
|
+
const packageName = packageNameFromSpec(packageSpec);
|
|
22536
|
+
const result = await installRuntimePackageInStaging(
|
|
22537
|
+
options.spawnSyncImpl,
|
|
22538
|
+
options.cacheDir,
|
|
22539
|
+
packageSpec,
|
|
22540
|
+
packageName,
|
|
22541
|
+
installOptions
|
|
22542
|
+
);
|
|
22543
|
+
output = collectOutputParts(output, collectSpawnOutput(result));
|
|
22544
|
+
if (result.status === 0 && await canResolveRuntimePackage(options.cacheDir, packageName)) continue;
|
|
22545
|
+
const command2 = formatRuntimePlatformRepairCommand(options.cacheDir, packageSpec);
|
|
22546
|
+
throw options.createError(
|
|
22547
|
+
`Rudder runtime installation is missing required native package ${packageName}. Re-run manually: ${command2}`,
|
|
22548
|
+
command2,
|
|
22549
|
+
output
|
|
22550
|
+
);
|
|
22551
|
+
}
|
|
22552
|
+
}
|
|
22553
|
+
let discoveredNewPackage = false;
|
|
22554
|
+
for (const packageName of [...requiredPackages]) {
|
|
22555
|
+
const packageJson = await readRuntimePackageJson(options.cacheDir, packageName);
|
|
22556
|
+
for (const [dependencyName, versionRange] of Object.entries(packageJson?.optionalDependencies ?? {})) {
|
|
22557
|
+
if (requiredPackages.has(dependencyName)) continue;
|
|
22558
|
+
requiredPackages.add(dependencyName);
|
|
22559
|
+
requiredPackageVersions.set(dependencyName, normalizeOptionalDependencyVersion(versionRange));
|
|
22560
|
+
discoveredNewPackage = true;
|
|
22561
|
+
}
|
|
22562
|
+
}
|
|
22563
|
+
if (!discoveredNewPackage && await hasRequiredRuntimeNativeDependencies(options.cacheDir)) return output;
|
|
22564
|
+
}
|
|
22565
|
+
const command = [...requiredPackages].map((packageName) => formatRuntimePlatformRepairCommand(
|
|
22566
|
+
options.cacheDir,
|
|
22567
|
+
requiredPackageVersions.get(packageName) ? `${packageName}@${requiredPackageVersions.get(packageName)}` : packageName
|
|
22568
|
+
)).join("; ");
|
|
22569
|
+
throw options.createError(
|
|
22570
|
+
"Rudder runtime native dependency preparation did not converge. Re-run manually: " + command,
|
|
22571
|
+
command,
|
|
22572
|
+
output
|
|
22573
|
+
);
|
|
22574
|
+
}
|
|
22575
|
+
function formatRuntimePlatformRepairCommand(cacheDir, packageSpec) {
|
|
22576
|
+
return `npm pack ${packageSpec} --registry=${NPM_PUBLIC_REGISTRY_URL} --silent, then extract it into ${path10.join(cacheDir, "node_modules")}`;
|
|
22577
|
+
}
|
|
22578
|
+
function collectSpawnOutput(result) {
|
|
22579
|
+
return [result.stdout, result.stderr, result.error instanceof Error ? result.error.message : null].filter((value) => typeof value === "string" && value.trim().length > 0).join("\n").trim();
|
|
22580
|
+
}
|
|
22581
|
+
function collectOutputParts(...parts) {
|
|
22582
|
+
return parts.filter((part) => part.trim().length > 0).join("\n").trim();
|
|
22583
|
+
}
|
|
22584
|
+
var NPM_PUBLIC_REGISTRY_URL, NPM_PLATFORM_REPAIR_ENV;
|
|
22585
|
+
var init_platform_dependencies = __esm({
|
|
22586
|
+
"src/runtime/platform-dependencies.ts"() {
|
|
22587
|
+
"use strict";
|
|
22588
|
+
init_npm_command();
|
|
22589
|
+
NPM_PUBLIC_REGISTRY_URL = "https://registry.npmjs.org";
|
|
22590
|
+
NPM_PLATFORM_REPAIR_ENV = {
|
|
22591
|
+
npm_config_registry: NPM_PUBLIC_REGISTRY_URL,
|
|
22592
|
+
npm_config_update_notifier: "false",
|
|
22593
|
+
NO_UPDATE_NOTIFIER: "1"
|
|
22594
|
+
};
|
|
22595
|
+
}
|
|
22596
|
+
});
|
|
22597
|
+
|
|
22348
22598
|
// src/runtime/postgres-runtime-download.ts
|
|
22349
22599
|
import { createHash as createHash3 } from "node:crypto";
|
|
22350
22600
|
import { createReadStream, createWriteStream } from "node:fs";
|
|
@@ -22466,12 +22716,22 @@ var init_postgres_runtime_source = __esm({
|
|
|
22466
22716
|
// src/runtime/install.ts
|
|
22467
22717
|
import { execFileSync, spawnSync as spawnSync2 } from "node:child_process";
|
|
22468
22718
|
import { createReadStream as createReadStream2, createWriteStream as createWriteStream2 } from "node:fs";
|
|
22469
|
-
import { chmod, mkdir, mkdtemp, readFile, readdir, realpath, rename, rm, stat, symlink, writeFile } from "node:fs/promises";
|
|
22719
|
+
import { chmod, mkdir as mkdir2, mkdtemp, readFile as readFile2, readdir, realpath, rename, rm as rm2, stat, symlink, writeFile } from "node:fs/promises";
|
|
22470
22720
|
import { createRequire } from "node:module";
|
|
22471
|
-
import
|
|
22721
|
+
import path11 from "node:path";
|
|
22472
22722
|
import { performance as performance2 } from "node:perf_hooks";
|
|
22473
22723
|
import { pipeline as pipeline2 } from "node:stream/promises";
|
|
22474
22724
|
import { pathToFileURL } from "node:url";
|
|
22725
|
+
function omitOptionalRuntimeDependencies() {
|
|
22726
|
+
return process.env.RUDDER_RUNTIME_INSTALL_OMIT_OPTIONAL === "true";
|
|
22727
|
+
}
|
|
22728
|
+
function runtimeNpmInstallFlags() {
|
|
22729
|
+
return [
|
|
22730
|
+
...RUNTIME_NPM_INSTALL_BASE_FLAGS,
|
|
22731
|
+
...omitOptionalRuntimeDependencies() ? ["--omit=optional"] : RUNTIME_NPM_INSTALL_OPTIONAL_FLAGS,
|
|
22732
|
+
...RUNTIME_NPM_INSTALL_SUFFIX_FLAGS
|
|
22733
|
+
];
|
|
22734
|
+
}
|
|
22475
22735
|
function createRuntimeInstallDeadline(options) {
|
|
22476
22736
|
if (options.timeoutMs === void 0) return void 0;
|
|
22477
22737
|
if (!Number.isFinite(options.timeoutMs) || options.timeoutMs <= 0) {
|
|
@@ -22512,7 +22772,7 @@ function resolveRuntimePackageVersion(version) {
|
|
|
22512
22772
|
return normalized.length > 0 ? normalized : "latest";
|
|
22513
22773
|
}
|
|
22514
22774
|
function resolveRuntimeCacheDir(version, homeDir = resolveRudderHomeDir()) {
|
|
22515
|
-
return
|
|
22775
|
+
return path11.join(homeDir, "runtimes", sanitizeRuntimeCacheSegment(resolveRuntimePackageVersion(version)));
|
|
22516
22776
|
}
|
|
22517
22777
|
function resolveRuntimePackageSpec(version, packageName = RUNTIME_NPM_PACKAGE_NAME) {
|
|
22518
22778
|
const packageVersion = resolveRuntimePackageVersion(version);
|
|
@@ -22520,7 +22780,7 @@ function resolveRuntimePackageSpec(version, packageName = RUNTIME_NPM_PACKAGE_NA
|
|
|
22520
22780
|
}
|
|
22521
22781
|
async function readRuntimeInstallMetadata(cacheDir) {
|
|
22522
22782
|
try {
|
|
22523
|
-
const raw = await
|
|
22783
|
+
const raw = await readFile2(path11.join(cacheDir, RUNTIME_METADATA_FILE), "utf8");
|
|
22524
22784
|
const parsed = JSON.parse(raw);
|
|
22525
22785
|
if (parsed.version !== 1) return null;
|
|
22526
22786
|
if (typeof parsed.packageName !== "string" || typeof parsed.packageVersion !== "string") return null;
|
|
@@ -22535,7 +22795,7 @@ async function readRuntimeInstallMetadata(cacheDir) {
|
|
|
22535
22795
|
}
|
|
22536
22796
|
}
|
|
22537
22797
|
async function writeRuntimeInstallMetadata(cacheDir, metadata) {
|
|
22538
|
-
await writeFile(
|
|
22798
|
+
await writeFile(path11.join(cacheDir, RUNTIME_METADATA_FILE), `${JSON.stringify(metadata, null, 2)}
|
|
22539
22799
|
`, "utf8");
|
|
22540
22800
|
}
|
|
22541
22801
|
async function touchRuntimeInstallMetadata(cacheDir, postgresRuntime) {
|
|
@@ -22561,23 +22821,16 @@ function resolveEmbeddedPostgresPlatformPackage(platform = process.platform, arc
|
|
|
22561
22821
|
if (platform === "win32" && arch === "x64") return "@embedded-postgres/windows-x64";
|
|
22562
22822
|
return null;
|
|
22563
22823
|
}
|
|
22564
|
-
async function canResolveRuntimePackage(cacheDir, packageName) {
|
|
22565
|
-
try {
|
|
22566
|
-
await readFile(path10.join(cacheDir, "node_modules", ...packageName.split("/"), "package.json"), "utf8");
|
|
22567
|
-
return true;
|
|
22568
|
-
} catch {
|
|
22569
|
-
return false;
|
|
22570
|
-
}
|
|
22571
|
-
}
|
|
22572
22824
|
async function hasRequiredRuntimePlatformDependencies(cacheDir, metadata, postgresVersionProbe, deadline) {
|
|
22825
|
+
if (omitOptionalRuntimeDependencies()) return hasRequiredRuntimeNativeDependencies(cacheDir);
|
|
22573
22826
|
if (!await canResolveRuntimePackage(cacheDir, EMBEDDED_POSTGRES_PACKAGE_NAME)) return true;
|
|
22574
22827
|
const platformPackage = resolveEmbeddedPostgresPlatformPackage();
|
|
22575
22828
|
if (!platformPackage) return true;
|
|
22576
22829
|
if (await canResolveRuntimePackage(cacheDir, platformPackage)) return true;
|
|
22577
22830
|
const expectedSharedBinDir = resolveSharedRuntimePostgresPayloadBinDir(
|
|
22578
|
-
|
|
22831
|
+
path11.dirname(path11.dirname(cacheDir))
|
|
22579
22832
|
);
|
|
22580
|
-
return metadata.postgresRuntime?.scope === "shared" && metadata.postgresRuntime.platform === process.platform && metadata.postgresRuntime.arch === process.arch &&
|
|
22833
|
+
return metadata.postgresRuntime?.scope === "shared" && metadata.postgresRuntime.platform === process.platform && metadata.postgresRuntime.arch === process.arch && path11.resolve(metadata.postgresRuntime.binDir) === path11.resolve(expectedSharedBinDir) && await isRuntimePostgresPayloadUsable(
|
|
22581
22834
|
cacheDir,
|
|
22582
22835
|
metadata.postgresRuntime.binDir,
|
|
22583
22836
|
postgresVersionProbe,
|
|
@@ -22592,8 +22845,8 @@ async function isRuntimeCacheHitWithinDeadline(options, deadline) {
|
|
|
22592
22845
|
return false;
|
|
22593
22846
|
}
|
|
22594
22847
|
try {
|
|
22595
|
-
const packageJsonPath =
|
|
22596
|
-
const packageJson = JSON.parse(await
|
|
22848
|
+
const packageJsonPath = path11.join(options.cacheDir, "node_modules", ...packageName.split("/"), "package.json");
|
|
22849
|
+
const packageJson = JSON.parse(await readFile2(packageJsonPath, "utf8"));
|
|
22597
22850
|
const packageVersionMatches = packageVersion === "latest" || packageJson.version === packageVersion;
|
|
22598
22851
|
return packageVersionMatches && await hasRequiredRuntimePlatformDependencies(
|
|
22599
22852
|
options.cacheDir,
|
|
@@ -22612,7 +22865,7 @@ async function ensureRuntimeInstalled(options) {
|
|
|
22612
22865
|
const cacheDir = resolveRuntimeCacheDir(packageVersion, homeDir);
|
|
22613
22866
|
const deadline = createRuntimeInstallDeadline(options);
|
|
22614
22867
|
return withRuntimeFilesystemLock(
|
|
22615
|
-
|
|
22868
|
+
path11.join(homeDir, "runtime-payloads", ".postgres-runtime.lifecycle.lock"),
|
|
22616
22869
|
async () => withRuntimeFilesystemLock(
|
|
22617
22870
|
`${cacheDir}.install.lock`,
|
|
22618
22871
|
async () => {
|
|
@@ -22635,7 +22888,7 @@ async function ensureRuntimeInstalled(options) {
|
|
|
22635
22888
|
);
|
|
22636
22889
|
}
|
|
22637
22890
|
function scheduleIncompleteRuntimeCacheCleanup(options) {
|
|
22638
|
-
const remove = options.remove ?? ((cacheDir) =>
|
|
22891
|
+
const remove = options.remove ?? ((cacheDir) => rm2(cacheDir, { recursive: true, force: true }));
|
|
22639
22892
|
void withRuntimeFilesystemLock(
|
|
22640
22893
|
`${options.cacheDir}.install.lock`,
|
|
22641
22894
|
async () => {
|
|
@@ -22733,12 +22986,12 @@ async function ensureRuntimeInstalledUnlocked(options, deadline) {
|
|
|
22733
22986
|
postgresPayload2
|
|
22734
22987
|
);
|
|
22735
22988
|
}
|
|
22736
|
-
await
|
|
22737
|
-
await
|
|
22738
|
-
await writeFile(
|
|
22989
|
+
await rm2(cacheDir, { recursive: true, force: true });
|
|
22990
|
+
await mkdir2(cacheDir, { recursive: true });
|
|
22991
|
+
await writeFile(path11.join(cacheDir, "package.json"), `${JSON.stringify(RUNTIME_CACHE_PACKAGE_JSON, null, 2)}
|
|
22739
22992
|
`, "utf8");
|
|
22740
22993
|
const result = runNpmRuntimeInstall(spawnSyncImpl, cacheDir, packageSpec, deadline);
|
|
22741
|
-
let output =
|
|
22994
|
+
let output = collectSpawnOutput2(result);
|
|
22742
22995
|
if (result.status !== 0 && packageVersion !== "latest" && options.allowLatestFallback !== false && isVersionNotFoundError(output)) {
|
|
22743
22996
|
const fallbackVersion = "latest";
|
|
22744
22997
|
const fallbackCacheDir = resolveRuntimeCacheDir(fallbackVersion, options.homeDir);
|
|
@@ -22773,16 +23026,17 @@ async function ensureRuntimeInstalledUnlocked(options, deadline) {
|
|
|
22773
23026
|
fallbackPostgresPayload
|
|
22774
23027
|
);
|
|
22775
23028
|
}
|
|
22776
|
-
await
|
|
22777
|
-
await
|
|
22778
|
-
await writeFile(
|
|
23029
|
+
await rm2(fallbackCacheDir, { recursive: true, force: true });
|
|
23030
|
+
await mkdir2(fallbackCacheDir, { recursive: true });
|
|
23031
|
+
await writeFile(path11.join(fallbackCacheDir, "package.json"), `${JSON.stringify(RUNTIME_CACHE_PACKAGE_JSON, null, 2)}
|
|
22779
23032
|
`, "utf8");
|
|
22780
23033
|
const fallbackResult = runNpmRuntimeInstall(spawnSyncImpl, fallbackCacheDir, fallbackSpec, deadline);
|
|
22781
|
-
let fallbackOutput =
|
|
23034
|
+
let fallbackOutput = collectSpawnOutput2(fallbackResult);
|
|
22782
23035
|
if (fallbackResult.status !== 0) return null;
|
|
22783
|
-
fallbackOutput =
|
|
23036
|
+
fallbackOutput = collectOutputParts2(
|
|
22784
23037
|
fallbackOutput,
|
|
22785
|
-
await ensureRequiredEmbeddedPostgresPlatformPackage(spawnSyncImpl, fallbackCacheDir, deadline)
|
|
23038
|
+
await ensureRequiredEmbeddedPostgresPlatformPackage(spawnSyncImpl, fallbackCacheDir, deadline),
|
|
23039
|
+
await ensureRuntimeNativeDependenciesForCache(spawnSyncImpl, fallbackCacheDir, deadline)
|
|
22786
23040
|
);
|
|
22787
23041
|
const postgresPayload2 = await stageRuntimePostgresPayload(
|
|
22788
23042
|
fallbackCacheDir,
|
|
@@ -22823,9 +23077,10 @@ async function ensureRuntimeInstalledUnlocked(options, deadline) {
|
|
|
22823
23077
|
{ cacheDir, command, output }
|
|
22824
23078
|
);
|
|
22825
23079
|
}
|
|
22826
|
-
output =
|
|
23080
|
+
output = collectOutputParts2(
|
|
22827
23081
|
output,
|
|
22828
|
-
await ensureRequiredEmbeddedPostgresPlatformPackage(spawnSyncImpl, cacheDir, deadline)
|
|
23082
|
+
await ensureRequiredEmbeddedPostgresPlatformPackage(spawnSyncImpl, cacheDir, deadline),
|
|
23083
|
+
await ensureRuntimeNativeDependenciesForCache(spawnSyncImpl, cacheDir, deadline)
|
|
22829
23084
|
);
|
|
22830
23085
|
const postgresPayload = await stageRuntimePostgresPayload(
|
|
22831
23086
|
cacheDir,
|
|
@@ -22857,10 +23112,10 @@ async function ensureRuntimeInstalledUnlocked(options, deadline) {
|
|
|
22857
23112
|
);
|
|
22858
23113
|
}
|
|
22859
23114
|
function resolveRuntimePostgresPayloadBinDir(cacheDir, platform = process.platform, arch = process.arch) {
|
|
22860
|
-
return
|
|
23115
|
+
return path11.join(cacheDir, RUNTIME_POSTGRES_PAYLOAD_DIR, runtimePostgresPlatformSegment(platform, arch), "bin");
|
|
22861
23116
|
}
|
|
22862
23117
|
function resolveSharedRuntimePostgresPayloadBinDir(homeDir = resolveRudderHomeDir(), platform = process.platform, arch = process.arch) {
|
|
22863
|
-
return
|
|
23118
|
+
return path11.join(
|
|
22864
23119
|
homeDir,
|
|
22865
23120
|
"runtime-payloads",
|
|
22866
23121
|
RUNTIME_POSTGRES_PAYLOAD_DIR,
|
|
@@ -22869,7 +23124,7 @@ function resolveSharedRuntimePostgresPayloadBinDir(homeDir = resolveRudderHomeDi
|
|
|
22869
23124
|
);
|
|
22870
23125
|
}
|
|
22871
23126
|
function resolveRuntimeServerEntrypoint(cacheDir, packageName = RUNTIME_NPM_PACKAGE_NAME) {
|
|
22872
|
-
return createRequire(
|
|
23127
|
+
return createRequire(path11.join(cacheDir, "package.json")).resolve(packageName);
|
|
22873
23128
|
}
|
|
22874
23129
|
async function importRuntimeServerModule(cacheDir, packageName = RUNTIME_NPM_PACKAGE_NAME) {
|
|
22875
23130
|
const entrypoint = resolveRuntimeServerEntrypoint(cacheDir, packageName);
|
|
@@ -22880,7 +23135,7 @@ function runNpmRuntimeInstall(spawnSyncImpl, cacheDir, packageSpec, deadline) {
|
|
|
22880
23135
|
const npm = resolveNpmCommandInvocation();
|
|
22881
23136
|
return spawnSyncImpl(
|
|
22882
23137
|
npm.command,
|
|
22883
|
-
[...npm.args, "install", "--prefix", cacheDir, ...
|
|
23138
|
+
[...npm.args, "install", "--prefix", cacheDir, ...runtimeNpmInstallFlags(), packageSpec],
|
|
22884
23139
|
{
|
|
22885
23140
|
encoding: "utf8",
|
|
22886
23141
|
stdio: ["ignore", "pipe", "pipe"],
|
|
@@ -22890,35 +23145,25 @@ function runNpmRuntimeInstall(spawnSyncImpl, cacheDir, packageSpec, deadline) {
|
|
|
22890
23145
|
);
|
|
22891
23146
|
}
|
|
22892
23147
|
function formatRuntimeInstallCommand(cacheDir, packageSpec) {
|
|
22893
|
-
return `npm install --prefix ${cacheDir} ${
|
|
23148
|
+
return `npm install --prefix ${cacheDir} ${runtimeNpmInstallFlags().join(" ")} ${packageSpec}`;
|
|
22894
23149
|
}
|
|
22895
|
-
function
|
|
22896
|
-
return `npm pack ${packageSpec} --registry=${
|
|
23150
|
+
function formatRuntimePlatformRepairCommand2(cacheDir, packageSpec) {
|
|
23151
|
+
return `npm pack ${packageSpec} --registry=${NPM_PUBLIC_REGISTRY_URL2} --silent, then extract it into ${path11.join(cacheDir, "node_modules")}`;
|
|
22897
23152
|
}
|
|
22898
|
-
function
|
|
23153
|
+
function collectSpawnOutput2(result) {
|
|
22899
23154
|
return [result.stdout, result.stderr, result.error instanceof Error ? result.error.message : null].filter((value) => typeof value === "string" && value.trim().length > 0).join("\n").trim();
|
|
22900
23155
|
}
|
|
22901
|
-
function
|
|
23156
|
+
function collectOutputParts2(...parts) {
|
|
22902
23157
|
return parts.filter((part) => part.trim().length > 0).join("\n").trim();
|
|
22903
23158
|
}
|
|
22904
23159
|
function withPostgresPayload(result, postgresPayload) {
|
|
22905
23160
|
return {
|
|
22906
23161
|
...result,
|
|
22907
|
-
output:
|
|
23162
|
+
output: collectOutputParts2(result.output, postgresPayload.output),
|
|
22908
23163
|
...postgresPayload.binDir ? { postgresPayloadBinDir: postgresPayload.binDir } : {},
|
|
22909
23164
|
...postgresPayload.metadata ? { postgresRuntime: postgresPayload.metadata } : {}
|
|
22910
23165
|
};
|
|
22911
23166
|
}
|
|
22912
|
-
function runtimePackageJsonPath(cacheDir, packageName) {
|
|
22913
|
-
return path10.join(cacheDir, "node_modules", ...packageName.split("/"), "package.json");
|
|
22914
|
-
}
|
|
22915
|
-
async function readRuntimePackageJson(cacheDir, packageName) {
|
|
22916
|
-
try {
|
|
22917
|
-
return JSON.parse(await readFile(runtimePackageJsonPath(cacheDir, packageName), "utf8"));
|
|
22918
|
-
} catch {
|
|
22919
|
-
return null;
|
|
22920
|
-
}
|
|
22921
|
-
}
|
|
22922
23167
|
async function tryRepairExistingRuntimePackage(options) {
|
|
22923
23168
|
const runtimePackage = await readRuntimePackageJson(options.cacheDir, options.packageName);
|
|
22924
23169
|
if (!runtimePackage) return null;
|
|
@@ -22928,9 +23173,24 @@ async function tryRepairExistingRuntimePackage(options) {
|
|
|
22928
23173
|
options.cacheDir,
|
|
22929
23174
|
options.deadline
|
|
22930
23175
|
);
|
|
22931
|
-
|
|
23176
|
+
const nativeOutput = await ensureRuntimeNativeDependenciesForCache(
|
|
23177
|
+
options.spawnSyncImpl,
|
|
23178
|
+
options.cacheDir,
|
|
23179
|
+
options.deadline
|
|
23180
|
+
);
|
|
23181
|
+
const combinedOutput = collectOutputParts2(output, nativeOutput);
|
|
23182
|
+
if (!await canResolveRuntimePackage(options.cacheDir, EMBEDDED_POSTGRES_PACKAGE_NAME)) return combinedOutput;
|
|
22932
23183
|
const platformPackage = resolveEmbeddedPostgresPlatformPackage();
|
|
22933
|
-
return !platformPackage || await canResolveRuntimePackage(options.cacheDir, platformPackage) ?
|
|
23184
|
+
return !platformPackage || await canResolveRuntimePackage(options.cacheDir, platformPackage) ? combinedOutput : null;
|
|
23185
|
+
}
|
|
23186
|
+
async function ensureRuntimeNativeDependenciesForCache(spawnSyncImpl, cacheDir, deadline) {
|
|
23187
|
+
return ensureRuntimeNativeDependencies({
|
|
23188
|
+
spawnSyncImpl,
|
|
23189
|
+
cacheDir,
|
|
23190
|
+
deadline,
|
|
23191
|
+
remainingMs: remainingRuntimeInstallMs,
|
|
23192
|
+
createError: (message, command, output) => new RuntimeInstallError(message, { cacheDir, command, output })
|
|
23193
|
+
});
|
|
22934
23194
|
}
|
|
22935
23195
|
async function resolveEmbeddedPostgresPlatformPackageSpec(cacheDir) {
|
|
22936
23196
|
if (!await canResolveRuntimePackage(cacheDir, EMBEDDED_POSTGRES_PACKAGE_NAME)) return null;
|
|
@@ -22942,6 +23202,7 @@ async function resolveEmbeddedPostgresPlatformPackageSpec(cacheDir) {
|
|
|
22942
23202
|
return packageVersion ? `${packageName}@${packageVersion}` : packageName;
|
|
22943
23203
|
}
|
|
22944
23204
|
async function ensureRequiredEmbeddedPostgresPlatformPackage(spawnSyncImpl, cacheDir, deadline) {
|
|
23205
|
+
if (omitOptionalRuntimeDependencies()) return "";
|
|
22945
23206
|
const packageSpec = await resolveEmbeddedPostgresPlatformPackageSpec(cacheDir);
|
|
22946
23207
|
if (!packageSpec) return "";
|
|
22947
23208
|
const packageName = packageNameFromSpec(packageSpec);
|
|
@@ -22952,104 +23213,18 @@ async function ensureRequiredEmbeddedPostgresPlatformPackage(spawnSyncImpl, cach
|
|
|
22952
23213
|
cacheDir,
|
|
22953
23214
|
packageSpec,
|
|
22954
23215
|
packageName,
|
|
22955
|
-
deadline
|
|
23216
|
+
{ cacheDir, deadline, remainingMs: remainingRuntimeInstallMs }
|
|
22956
23217
|
);
|
|
22957
|
-
const output =
|
|
23218
|
+
const output = collectSpawnOutput2(result);
|
|
22958
23219
|
if (result.status === 0 && packageName && await canResolveRuntimePackage(cacheDir, packageName)) {
|
|
22959
23220
|
return output;
|
|
22960
23221
|
}
|
|
22961
|
-
const command =
|
|
23222
|
+
const command = formatRuntimePlatformRepairCommand2(cacheDir, packageSpec);
|
|
22962
23223
|
throw new RuntimeInstallError(
|
|
22963
23224
|
`Rudder runtime installation is missing required platform package ${packageName || packageSpec}. Re-run manually: ${command}`,
|
|
22964
23225
|
{ cacheDir, command, output }
|
|
22965
23226
|
);
|
|
22966
23227
|
}
|
|
22967
|
-
async function installRuntimePackageInStaging(spawnSyncImpl, cacheDir, packageSpec, packageName, deadline) {
|
|
22968
|
-
const stagingDir = path10.join(cacheDir, `.platform-repair-${process.pid}-${Date.now()}`);
|
|
22969
|
-
await mkdir(stagingDir, { recursive: true });
|
|
22970
|
-
try {
|
|
22971
|
-
const packResult = runNpmPack(spawnSyncImpl, packageSpec, stagingDir, cacheDir, deadline);
|
|
22972
|
-
if (packResult.status !== 0) return packResult;
|
|
22973
|
-
const packFilename = parseNpmPackFilename(packResult.stdout);
|
|
22974
|
-
if (!packFilename) {
|
|
22975
|
-
return createSyntheticSpawnResult(1, "", `Unable to parse npm pack output for ${packageSpec}.`);
|
|
22976
|
-
}
|
|
22977
|
-
const archivePath = path10.join(stagingDir, packFilename);
|
|
22978
|
-
const targetDir = path10.dirname(runtimePackageJsonPath(cacheDir, packageName));
|
|
22979
|
-
await mkdir(path10.dirname(targetDir), { recursive: true });
|
|
22980
|
-
await rm(targetDir, { recursive: true, force: true });
|
|
22981
|
-
await mkdir(targetDir, { recursive: true });
|
|
22982
|
-
const extractResult = runTarExtract(spawnSyncImpl, archivePath, targetDir, cacheDir, deadline);
|
|
22983
|
-
return combineSpawnResults(packResult, extractResult);
|
|
22984
|
-
} finally {
|
|
22985
|
-
await rm(stagingDir, { recursive: true, force: true });
|
|
22986
|
-
}
|
|
22987
|
-
}
|
|
22988
|
-
function runNpmPack(spawnSyncImpl, packageSpec, destinationDir, cacheDir, deadline) {
|
|
22989
|
-
const timeout = remainingRuntimeInstallMs(deadline, cacheDir, `npm pack ${packageSpec}`);
|
|
22990
|
-
const npm = resolveNpmCommandInvocation();
|
|
22991
|
-
return spawnSyncImpl(
|
|
22992
|
-
npm.command,
|
|
22993
|
-
[...npm.args, "pack", packageSpec, "--pack-destination", destinationDir, ...RUNTIME_NPM_PACK_FLAGS],
|
|
22994
|
-
{
|
|
22995
|
-
encoding: "utf8",
|
|
22996
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
22997
|
-
env: { ...process.env, ...NPM_PLATFORM_REPAIR_ENV },
|
|
22998
|
-
...timeout === void 0 ? {} : { timeout },
|
|
22999
|
-
...process.platform === "win32" ? { windowsHide: true } : {}
|
|
23000
|
-
}
|
|
23001
|
-
);
|
|
23002
|
-
}
|
|
23003
|
-
function runTarExtract(spawnSyncImpl, archivePath, targetDir, cacheDir, deadline) {
|
|
23004
|
-
const timeout = remainingRuntimeInstallMs(deadline, cacheDir, "extract runtime platform package");
|
|
23005
|
-
return spawnSyncImpl(
|
|
23006
|
-
"tar",
|
|
23007
|
-
["-xzf", archivePath, "-C", targetDir, "--strip-components", "1"],
|
|
23008
|
-
{
|
|
23009
|
-
encoding: "utf8",
|
|
23010
|
-
stdio: ["ignore", "pipe", "pipe"],
|
|
23011
|
-
...timeout === void 0 ? {} : { timeout },
|
|
23012
|
-
...process.platform === "win32" ? { windowsHide: true } : {}
|
|
23013
|
-
}
|
|
23014
|
-
);
|
|
23015
|
-
}
|
|
23016
|
-
function parseNpmPackFilename(stdout) {
|
|
23017
|
-
if (typeof stdout !== "string") return null;
|
|
23018
|
-
const filename = stdout.trim().split(/\r?\n/).filter(Boolean).at(-1);
|
|
23019
|
-
return filename?.endsWith(".tgz") ? filename : null;
|
|
23020
|
-
}
|
|
23021
|
-
function createSyntheticSpawnResult(status, stdout, stderr) {
|
|
23022
|
-
return { status, stdout, stderr };
|
|
23023
|
-
}
|
|
23024
|
-
function combineSpawnResults(...results) {
|
|
23025
|
-
const last = results.at(-1);
|
|
23026
|
-
return {
|
|
23027
|
-
status: last?.status ?? 0,
|
|
23028
|
-
stdout: results.map((result) => result.stdout).filter(Boolean).join("\n"),
|
|
23029
|
-
stderr: results.map((result) => result.stderr).filter(Boolean).join("\n"),
|
|
23030
|
-
error: results.find((result) => result.error)?.error
|
|
23031
|
-
};
|
|
23032
|
-
}
|
|
23033
|
-
async function removeRuntimeInstallLocks(cacheDir) {
|
|
23034
|
-
await Promise.all([
|
|
23035
|
-
rm(path10.join(cacheDir, "package-lock.json"), { force: true }),
|
|
23036
|
-
rm(path10.join(cacheDir, "node_modules", ".package-lock.json"), { force: true })
|
|
23037
|
-
]);
|
|
23038
|
-
}
|
|
23039
|
-
function packageNameFromSpec(packageSpec) {
|
|
23040
|
-
if (!packageSpec.startsWith("@")) {
|
|
23041
|
-
const versionSeparator2 = packageSpec.indexOf("@");
|
|
23042
|
-
return versionSeparator2 === -1 ? packageSpec : packageSpec.slice(0, versionSeparator2);
|
|
23043
|
-
}
|
|
23044
|
-
const versionSeparator = packageSpec.indexOf("@", 1);
|
|
23045
|
-
return versionSeparator === -1 ? packageSpec : packageSpec.slice(0, versionSeparator);
|
|
23046
|
-
}
|
|
23047
|
-
function normalizeOptionalDependencyVersion(versionRange) {
|
|
23048
|
-
const trimmed = versionRange?.trim();
|
|
23049
|
-
if (!trimmed) return null;
|
|
23050
|
-
const exactVersion = /^[~^]\s*([0-9]+\.[0-9]+\.[0-9]+(?:-[0-9A-Za-z.-]+)?)$/.exec(trimmed);
|
|
23051
|
-
return exactVersion?.[1] ?? trimmed;
|
|
23052
|
-
}
|
|
23053
23228
|
function runtimePostgresPlatformSegment(platform = process.platform, arch = process.arch) {
|
|
23054
23229
|
return `${platform}-${arch}`;
|
|
23055
23230
|
}
|
|
@@ -23057,25 +23232,25 @@ function runtimePostgresExecutableName(baseName) {
|
|
|
23057
23232
|
return process.platform === "win32" ? `${baseName}.exe` : baseName;
|
|
23058
23233
|
}
|
|
23059
23234
|
function debianSharedirCandidate(binDir) {
|
|
23060
|
-
const normalized =
|
|
23061
|
-
const parts = normalized.split(
|
|
23235
|
+
const normalized = path11.resolve(binDir);
|
|
23236
|
+
const parts = normalized.split(path11.sep);
|
|
23062
23237
|
const libIndex = parts.lastIndexOf("lib");
|
|
23063
23238
|
if (libIndex < 0) return null;
|
|
23064
23239
|
if (parts[libIndex + 1] !== "postgresql") return null;
|
|
23065
23240
|
const version = parts[libIndex + 2];
|
|
23066
23241
|
if (!version || parts[libIndex + 3] !== "bin") return null;
|
|
23067
|
-
const prefix = parts.slice(0, libIndex).join(
|
|
23068
|
-
return
|
|
23242
|
+
const prefix = parts.slice(0, libIndex).join(path11.sep) || path11.sep;
|
|
23243
|
+
return path11.join(prefix, "share", "postgresql", version);
|
|
23069
23244
|
}
|
|
23070
23245
|
async function resolveRuntimePostgresTemplateDir(binDir, cacheDir = binDir, deadline) {
|
|
23071
23246
|
for (const candidatePath of [
|
|
23072
|
-
|
|
23073
|
-
|
|
23247
|
+
path11.join(binDir, "..", "share", "postgresql", "postgres.bki"),
|
|
23248
|
+
path11.join(binDir, "..", "share", "postgres.bki")
|
|
23074
23249
|
]) {
|
|
23075
23250
|
remainingRuntimeInstallMs(deadline, cacheDir, "discover PostgreSQL runtime templates");
|
|
23076
23251
|
try {
|
|
23077
23252
|
await stat(candidatePath);
|
|
23078
|
-
return
|
|
23253
|
+
return path11.dirname(candidatePath);
|
|
23079
23254
|
} catch {
|
|
23080
23255
|
}
|
|
23081
23256
|
}
|
|
@@ -23083,12 +23258,12 @@ async function resolveRuntimePostgresTemplateDir(binDir, cacheDir = binDir, dead
|
|
|
23083
23258
|
if (debianSharedir) {
|
|
23084
23259
|
remainingRuntimeInstallMs(deadline, cacheDir, "discover PostgreSQL runtime templates");
|
|
23085
23260
|
try {
|
|
23086
|
-
await stat(
|
|
23261
|
+
await stat(path11.join(debianSharedir, "postgres.bki"));
|
|
23087
23262
|
return debianSharedir;
|
|
23088
23263
|
} catch {
|
|
23089
23264
|
}
|
|
23090
23265
|
}
|
|
23091
|
-
const pgConfigPath =
|
|
23266
|
+
const pgConfigPath = path11.join(binDir, process.platform === "win32" ? "pg_config.exe" : "pg_config");
|
|
23092
23267
|
try {
|
|
23093
23268
|
remainingRuntimeInstallMs(deadline, cacheDir, "discover PostgreSQL runtime templates");
|
|
23094
23269
|
await stat(pgConfigPath);
|
|
@@ -23107,7 +23282,7 @@ async function resolveRuntimePostgresTemplateDir(binDir, cacheDir = binDir, dead
|
|
|
23107
23282
|
}
|
|
23108
23283
|
if (!sharedir) return null;
|
|
23109
23284
|
remainingRuntimeInstallMs(deadline, cacheDir, "validate PostgreSQL runtime templates");
|
|
23110
|
-
const candidatePath =
|
|
23285
|
+
const candidatePath = path11.join(sharedir, "postgres.bki");
|
|
23111
23286
|
await stat(candidatePath);
|
|
23112
23287
|
return sharedir;
|
|
23113
23288
|
} catch (error) {
|
|
@@ -23116,7 +23291,7 @@ async function resolveRuntimePostgresTemplateDir(binDir, cacheDir = binDir, dead
|
|
|
23116
23291
|
}
|
|
23117
23292
|
}
|
|
23118
23293
|
function resolveRuntimePostgresShareDir(binDir, templateDir) {
|
|
23119
|
-
const adjacentShareDir =
|
|
23294
|
+
const adjacentShareDir = path11.resolve(binDir, "..", "share");
|
|
23120
23295
|
return pathIsInside(templateDir, adjacentShareDir) ? adjacentShareDir : templateDir;
|
|
23121
23296
|
}
|
|
23122
23297
|
async function assertRuntimePostgresBinDirComplete(cacheDir, binDir, deadline) {
|
|
@@ -23124,7 +23299,7 @@ async function assertRuntimePostgresBinDirComplete(cacheDir, binDir, deadline) {
|
|
|
23124
23299
|
const missing = [];
|
|
23125
23300
|
for (const binary of requiredBinaries) {
|
|
23126
23301
|
remainingRuntimeInstallMs(deadline, cacheDir, "validate PostgreSQL runtime binaries");
|
|
23127
|
-
const binaryPath =
|
|
23302
|
+
const binaryPath = path11.join(binDir, runtimePostgresExecutableName(binary));
|
|
23128
23303
|
try {
|
|
23129
23304
|
await stat(binaryPath);
|
|
23130
23305
|
} catch {
|
|
@@ -23133,19 +23308,19 @@ async function assertRuntimePostgresBinDirComplete(cacheDir, binDir, deadline) {
|
|
|
23133
23308
|
}
|
|
23134
23309
|
const templateDir = await resolveRuntimePostgresTemplateDir(binDir, cacheDir, deadline);
|
|
23135
23310
|
if (!templateDir) {
|
|
23136
|
-
missing.push(
|
|
23311
|
+
missing.push(path11.join(binDir, "..", "share", "postgresql", "postgres.bki"));
|
|
23137
23312
|
} else {
|
|
23138
23313
|
try {
|
|
23139
|
-
await stat(
|
|
23314
|
+
await stat(path11.join(templateDir, "postgresql.conf.sample"));
|
|
23140
23315
|
} catch {
|
|
23141
|
-
missing.push(
|
|
23316
|
+
missing.push(path11.join(templateDir, "postgresql.conf.sample"));
|
|
23142
23317
|
}
|
|
23143
23318
|
const shareDir = resolveRuntimePostgresShareDir(binDir, templateDir);
|
|
23144
23319
|
const hasTimezoneDir = (await Promise.all([
|
|
23145
|
-
|
|
23146
|
-
|
|
23320
|
+
path11.join(templateDir, "timezone"),
|
|
23321
|
+
path11.join(shareDir, "timezone")
|
|
23147
23322
|
].map((candidate) => stat(candidate).catch(() => null)))).some((candidate) => candidate?.isDirectory());
|
|
23148
|
-
if (!hasTimezoneDir) missing.push(
|
|
23323
|
+
if (!hasTimezoneDir) missing.push(path11.join(shareDir, "timezone"));
|
|
23149
23324
|
}
|
|
23150
23325
|
if (missing.length > 0) {
|
|
23151
23326
|
throw new RuntimeInstallError(
|
|
@@ -23170,8 +23345,8 @@ async function isRuntimePostgresPayloadUsable(cacheDir, binDir, postgresVersionP
|
|
|
23170
23345
|
}
|
|
23171
23346
|
}
|
|
23172
23347
|
function pathIsInside(candidatePath, rootPath) {
|
|
23173
|
-
const relative =
|
|
23174
|
-
return relative === "" || relative !== ".." && !relative.startsWith(`..${
|
|
23348
|
+
const relative = path11.relative(path11.resolve(rootPath), path11.resolve(candidatePath));
|
|
23349
|
+
return relative === "" || relative !== ".." && !relative.startsWith(`..${path11.sep}`) && !path11.isAbsolute(relative);
|
|
23175
23350
|
}
|
|
23176
23351
|
async function copyRuntimePayloadEntry(sourcePath, targetPath, cacheDir, deadline, signal, command) {
|
|
23177
23352
|
if (signal.aborted) throw runtimeInstallDeadlineError(cacheDir, command);
|
|
@@ -23180,12 +23355,12 @@ async function copyRuntimePayloadEntry(sourcePath, targetPath, cacheDir, deadlin
|
|
|
23180
23355
|
if (signal.aborted) throw runtimeInstallDeadlineError(cacheDir, command);
|
|
23181
23356
|
remainingRuntimeInstallMs(deadline, cacheDir, command);
|
|
23182
23357
|
if (sourceStats.isDirectory()) {
|
|
23183
|
-
await
|
|
23358
|
+
await mkdir2(targetPath, { recursive: true });
|
|
23184
23359
|
const entries = await readdir(sourcePath);
|
|
23185
23360
|
for (const entry of entries) {
|
|
23186
23361
|
await copyRuntimePayloadEntry(
|
|
23187
|
-
|
|
23188
|
-
|
|
23362
|
+
path11.join(sourcePath, entry),
|
|
23363
|
+
path11.join(targetPath, entry),
|
|
23189
23364
|
cacheDir,
|
|
23190
23365
|
deadline,
|
|
23191
23366
|
signal,
|
|
@@ -23195,7 +23370,7 @@ async function copyRuntimePayloadEntry(sourcePath, targetPath, cacheDir, deadlin
|
|
|
23195
23370
|
return;
|
|
23196
23371
|
}
|
|
23197
23372
|
if (!sourceStats.isFile()) return;
|
|
23198
|
-
await
|
|
23373
|
+
await mkdir2(path11.dirname(targetPath), { recursive: true });
|
|
23199
23374
|
try {
|
|
23200
23375
|
await pipeline2(
|
|
23201
23376
|
createReadStream2(sourcePath),
|
|
@@ -23205,7 +23380,7 @@ async function copyRuntimePayloadEntry(sourcePath, targetPath, cacheDir, deadlin
|
|
|
23205
23380
|
await chmod(targetPath, sourceStats.mode);
|
|
23206
23381
|
remainingRuntimeInstallMs(deadline, cacheDir, command);
|
|
23207
23382
|
} catch (error) {
|
|
23208
|
-
await
|
|
23383
|
+
await rm2(targetPath, { force: true });
|
|
23209
23384
|
if (signal.aborted || isRuntimeInstallDeadlineError(error)) {
|
|
23210
23385
|
throw runtimeInstallDeadlineError(cacheDir, command);
|
|
23211
23386
|
}
|
|
@@ -23227,13 +23402,13 @@ async function copyRuntimePostgresPayloadWithinDeadline(sourceRuntimeDir, target
|
|
|
23227
23402
|
}, timeoutMs);
|
|
23228
23403
|
});
|
|
23229
23404
|
const copyPromise = (async () => {
|
|
23230
|
-
await
|
|
23405
|
+
await mkdir2(targetRuntimeDir, { recursive: true });
|
|
23231
23406
|
for (const directoryName of ["bin", "lib"]) {
|
|
23232
|
-
const sourceDirectory =
|
|
23407
|
+
const sourceDirectory = path11.join(sourceRuntimeDir, directoryName);
|
|
23233
23408
|
if (!await stat(sourceDirectory).catch(() => null)) continue;
|
|
23234
23409
|
await copyRuntimePayloadEntry(
|
|
23235
23410
|
sourceDirectory,
|
|
23236
|
-
|
|
23411
|
+
path11.join(targetRuntimeDir, directoryName),
|
|
23237
23412
|
cacheDir,
|
|
23238
23413
|
deadline,
|
|
23239
23414
|
controller.signal,
|
|
@@ -23242,7 +23417,7 @@ async function copyRuntimePostgresPayloadWithinDeadline(sourceRuntimeDir, target
|
|
|
23242
23417
|
}
|
|
23243
23418
|
await copyRuntimePayloadEntry(
|
|
23244
23419
|
sourceShareDir,
|
|
23245
|
-
|
|
23420
|
+
path11.join(targetRuntimeDir, "share"),
|
|
23246
23421
|
cacheDir,
|
|
23247
23422
|
deadline,
|
|
23248
23423
|
controller.signal,
|
|
@@ -23260,18 +23435,18 @@ async function copyRuntimePostgresPayloadWithinDeadline(sourceRuntimeDir, target
|
|
|
23260
23435
|
async function withRuntimeFilesystemLock(lockPath, task, options = {}) {
|
|
23261
23436
|
const deadlineTimeout = remainingRuntimeInstallMs(
|
|
23262
23437
|
options.deadline,
|
|
23263
|
-
options.cacheDir ??
|
|
23438
|
+
options.cacheDir ?? path11.dirname(lockPath),
|
|
23264
23439
|
options.command ?? `wait for runtime lock ${lockPath}`
|
|
23265
23440
|
);
|
|
23266
23441
|
const timeoutMs = Math.min(options.timeoutMs ?? 3e4, deadlineTimeout ?? Number.POSITIVE_INFINITY);
|
|
23267
23442
|
const pollMs = options.pollMs ?? 50;
|
|
23268
23443
|
const startedAt = Date.now();
|
|
23269
23444
|
const lockId = `${process.pid}-${startedAt}-${Math.random().toString(16).slice(2)}`;
|
|
23270
|
-
const ownerPath =
|
|
23271
|
-
await
|
|
23445
|
+
const ownerPath = path11.join(lockPath, "owner.json");
|
|
23446
|
+
await mkdir2(path11.dirname(lockPath), { recursive: true });
|
|
23272
23447
|
while (true) {
|
|
23273
23448
|
try {
|
|
23274
|
-
await
|
|
23449
|
+
await mkdir2(lockPath);
|
|
23275
23450
|
await writeFile(
|
|
23276
23451
|
ownerPath,
|
|
23277
23452
|
`${JSON.stringify({ pid: process.pid, lockId, createdAt: (/* @__PURE__ */ new Date()).toISOString() })}
|
|
@@ -23282,27 +23457,27 @@ async function withRuntimeFilesystemLock(lockPath, task, options = {}) {
|
|
|
23282
23457
|
} catch (error) {
|
|
23283
23458
|
if (error.code !== "EEXIST") throw error;
|
|
23284
23459
|
try {
|
|
23285
|
-
const existing = JSON.parse(await
|
|
23460
|
+
const existing = JSON.parse(await readFile2(ownerPath, "utf8"));
|
|
23286
23461
|
if (typeof existing.pid !== "number" || !isPidRunning(existing.pid)) {
|
|
23287
|
-
await
|
|
23462
|
+
await rm2(lockPath, { recursive: true, force: true });
|
|
23288
23463
|
continue;
|
|
23289
23464
|
}
|
|
23290
23465
|
} catch {
|
|
23291
23466
|
const lockStats = await stat(lockPath).catch(() => null);
|
|
23292
23467
|
if (lockStats && Date.now() - lockStats.mtimeMs > 5e3) {
|
|
23293
|
-
await
|
|
23468
|
+
await rm2(lockPath, { recursive: true, force: true });
|
|
23294
23469
|
continue;
|
|
23295
23470
|
}
|
|
23296
23471
|
}
|
|
23297
23472
|
if (Date.now() - startedAt >= timeoutMs) {
|
|
23298
23473
|
throw new RuntimeInstallError(
|
|
23299
23474
|
`Timed out waiting for PostgreSQL runtime install lock ${lockPath}`,
|
|
23300
|
-
{ cacheDir:
|
|
23475
|
+
{ cacheDir: path11.dirname(lockPath), command: "prepare shared PostgreSQL runtime", output: "" }
|
|
23301
23476
|
);
|
|
23302
23477
|
}
|
|
23303
23478
|
remainingRuntimeInstallMs(
|
|
23304
23479
|
options.deadline,
|
|
23305
|
-
options.cacheDir ??
|
|
23480
|
+
options.cacheDir ?? path11.dirname(lockPath),
|
|
23306
23481
|
options.command ?? `wait for runtime lock ${lockPath}`
|
|
23307
23482
|
);
|
|
23308
23483
|
await new Promise((resolve) => setTimeout(resolve, pollMs));
|
|
@@ -23312,9 +23487,9 @@ async function withRuntimeFilesystemLock(lockPath, task, options = {}) {
|
|
|
23312
23487
|
return await task();
|
|
23313
23488
|
} finally {
|
|
23314
23489
|
try {
|
|
23315
|
-
const existing = JSON.parse(await
|
|
23490
|
+
const existing = JSON.parse(await readFile2(ownerPath, "utf8"));
|
|
23316
23491
|
if (existing.lockId === lockId) {
|
|
23317
|
-
await
|
|
23492
|
+
await rm2(lockPath, { recursive: true, force: true });
|
|
23318
23493
|
}
|
|
23319
23494
|
} catch {
|
|
23320
23495
|
}
|
|
@@ -23322,29 +23497,29 @@ async function withRuntimeFilesystemLock(lockPath, task, options = {}) {
|
|
|
23322
23497
|
}
|
|
23323
23498
|
function isManagedRuntimePostgresBinDir(binDir, homeDir) {
|
|
23324
23499
|
const managedBinDir = process.env[RUDDER_DESKTOP_MANAGED_POSTGRES_BIN_DIR_ENV]?.trim();
|
|
23325
|
-
if (managedBinDir &&
|
|
23326
|
-
const runtimesRelative =
|
|
23327
|
-
|
|
23328
|
-
|
|
23500
|
+
if (managedBinDir && path11.resolve(managedBinDir) === path11.resolve(binDir)) return true;
|
|
23501
|
+
const runtimesRelative = path11.relative(
|
|
23502
|
+
path11.join(homeDir, "runtimes"),
|
|
23503
|
+
path11.resolve(binDir)
|
|
23329
23504
|
);
|
|
23330
|
-
const runtimeSegments = runtimesRelative.split(
|
|
23331
|
-
if (runtimesRelative !== "" && runtimesRelative !== ".." && !runtimesRelative.startsWith(`..${
|
|
23505
|
+
const runtimeSegments = runtimesRelative.split(path11.sep);
|
|
23506
|
+
if (runtimesRelative !== "" && runtimesRelative !== ".." && !runtimesRelative.startsWith(`..${path11.sep}`) && !path11.isAbsolute(runtimesRelative) && runtimeSegments.length === 4 && runtimeSegments[0]?.length > 0 && runtimeSegments[1] === RUNTIME_POSTGRES_PAYLOAD_DIR && runtimeSegments[2] === `${process.platform}-${process.arch}` && runtimeSegments[3] === "bin") {
|
|
23332
23507
|
return true;
|
|
23333
23508
|
}
|
|
23334
|
-
const payloadsRelative =
|
|
23335
|
-
|
|
23336
|
-
|
|
23509
|
+
const payloadsRelative = path11.relative(
|
|
23510
|
+
path11.join(homeDir, "runtime-payloads"),
|
|
23511
|
+
path11.resolve(binDir)
|
|
23337
23512
|
);
|
|
23338
|
-
const payloadSegments = payloadsRelative.split(
|
|
23339
|
-
return payloadsRelative !== "" && payloadsRelative !== ".." && !payloadsRelative.startsWith(`..${
|
|
23513
|
+
const payloadSegments = payloadsRelative.split(path11.sep);
|
|
23514
|
+
return payloadsRelative !== "" && payloadsRelative !== ".." && !payloadsRelative.startsWith(`..${path11.sep}`) && !path11.isAbsolute(payloadsRelative) && payloadSegments.length === 3 && payloadSegments[0] === RUNTIME_POSTGRES_PAYLOAD_DIR && payloadSegments[1] === `${process.platform}-${process.arch}` && payloadSegments[2] === "bin";
|
|
23340
23515
|
}
|
|
23341
23516
|
async function findLegacyRuntimePostgresBinDir(cacheDir, homeDir, postgresVersionProbe, deadline) {
|
|
23342
|
-
const runtimesRoot =
|
|
23517
|
+
const runtimesRoot = path11.join(homeDir, "runtimes");
|
|
23343
23518
|
const entries = await readdir(runtimesRoot, { withFileTypes: true }).catch(() => []);
|
|
23344
23519
|
for (const entry of entries) {
|
|
23345
23520
|
if (!entry.isDirectory() && !entry.isSymbolicLink()) continue;
|
|
23346
|
-
const candidateCacheDir =
|
|
23347
|
-
if (
|
|
23521
|
+
const candidateCacheDir = path11.join(runtimesRoot, entry.name);
|
|
23522
|
+
if (path11.resolve(candidateCacheDir) === path11.resolve(cacheDir)) continue;
|
|
23348
23523
|
const candidateBinDir = resolveRuntimePostgresPayloadBinDir(candidateCacheDir);
|
|
23349
23524
|
remainingRuntimeInstallMs(deadline, cacheDir, "find cached PostgreSQL runtime payload");
|
|
23350
23525
|
if (await isRuntimePostgresPayloadUsable(cacheDir, candidateBinDir, postgresVersionProbe, deadline)) {
|
|
@@ -23354,13 +23529,13 @@ async function findLegacyRuntimePostgresBinDir(cacheDir, homeDir, postgresVersio
|
|
|
23354
23529
|
return null;
|
|
23355
23530
|
}
|
|
23356
23531
|
async function readLiveRuntimeDescriptors(homeDir) {
|
|
23357
|
-
const instancesRoot =
|
|
23532
|
+
const instancesRoot = path11.join(homeDir, "instances");
|
|
23358
23533
|
const entries = await readdir(instancesRoot, { withFileTypes: true }).catch(() => []);
|
|
23359
23534
|
const descriptors = [];
|
|
23360
23535
|
for (const entry of entries) {
|
|
23361
23536
|
if (!entry.isDirectory()) continue;
|
|
23362
23537
|
try {
|
|
23363
|
-
const raw = JSON.parse(await
|
|
23538
|
+
const raw = JSON.parse(await readFile2(path11.join(instancesRoot, entry.name, "runtime", "server.json"), "utf8"));
|
|
23364
23539
|
if (typeof raw.pid !== "number" || !Number.isInteger(raw.pid) || !isPidRunning(raw.pid) || typeof raw.version !== "string") {
|
|
23365
23540
|
continue;
|
|
23366
23541
|
}
|
|
@@ -23378,13 +23553,13 @@ async function assertSharedPostgresPayloadNotLive(cacheDir, homeDir, sharedBinDi
|
|
|
23378
23553
|
const sharedPhysicalBinDir = await realpath(sharedBinDir).catch(() => null);
|
|
23379
23554
|
const mayReferenceSharedPayload = await Promise.all(liveDescriptors.map(async (descriptor) => {
|
|
23380
23555
|
if (descriptor.postgresBinDir === void 0) return true;
|
|
23381
|
-
if (
|
|
23556
|
+
if (path11.resolve(descriptor.postgresBinDir) === path11.resolve(sharedBinDir)) return true;
|
|
23382
23557
|
const descriptorPhysicalBinDir = await realpath(descriptor.postgresBinDir).catch(() => null);
|
|
23383
|
-
if (descriptorPhysicalBinDir && sharedPhysicalBinDir &&
|
|
23558
|
+
if (descriptorPhysicalBinDir && sharedPhysicalBinDir && path11.resolve(descriptorPhysicalBinDir) === path11.resolve(sharedPhysicalBinDir)) {
|
|
23384
23559
|
return true;
|
|
23385
23560
|
}
|
|
23386
23561
|
if (!descriptorPhysicalBinDir) {
|
|
23387
|
-
return pathIsInside(descriptor.postgresBinDir,
|
|
23562
|
+
return pathIsInside(descriptor.postgresBinDir, path11.join(homeDir, "runtimes")) || pathIsInside(descriptor.postgresBinDir, path11.join(homeDir, "runtime-payloads"));
|
|
23388
23563
|
}
|
|
23389
23564
|
return false;
|
|
23390
23565
|
}));
|
|
@@ -23399,7 +23574,7 @@ async function validateRuntimePostgresVersion(cacheDir, binDir, postgresVersionP
|
|
|
23399
23574
|
await assertRuntimePostgresBinDirComplete(cacheDir, binDir, deadline);
|
|
23400
23575
|
for (const binary of ["initdb", "pg_ctl", "postgres"]) {
|
|
23401
23576
|
remainingRuntimeInstallMs(deadline, cacheDir, "validate PostgreSQL runtime version");
|
|
23402
|
-
const binaryPath =
|
|
23577
|
+
const binaryPath = path11.join(binDir, runtimePostgresExecutableName(binary));
|
|
23403
23578
|
const result = postgresVersionProbe(binaryPath);
|
|
23404
23579
|
if (!/\bPostgreSQL\)?\s+18\.4\b/i.test(result)) {
|
|
23405
23580
|
throw new RuntimeInstallError(
|
|
@@ -23439,24 +23614,24 @@ async function findRuntimePostgresBinDir(rootDir, cacheDir, postgresVersionProbe
|
|
|
23439
23614
|
if (await isRuntimePostgresPayloadUsable(cacheDir, current, postgresVersionProbe, deadline)) return current;
|
|
23440
23615
|
const entries = await readdir(current, { withFileTypes: true }).catch(() => []);
|
|
23441
23616
|
for (const entry of entries) {
|
|
23442
|
-
if (entry.isDirectory()) queue.push(
|
|
23617
|
+
if (entry.isDirectory()) queue.push(path11.join(current, entry.name));
|
|
23443
23618
|
}
|
|
23444
23619
|
}
|
|
23445
23620
|
return null;
|
|
23446
23621
|
}
|
|
23447
23622
|
async function reconcileSharedPostgresPayloadGenerations(cacheDir, sharedPlatformRoot, postgresVersionProbe, cleanupDownloads = false, deadline) {
|
|
23448
23623
|
remainingRuntimeInstallMs(deadline, cacheDir, "reconcile shared PostgreSQL payload");
|
|
23449
|
-
const parentDir =
|
|
23450
|
-
const baseName =
|
|
23624
|
+
const parentDir = path11.dirname(sharedPlatformRoot);
|
|
23625
|
+
const baseName = path11.basename(sharedPlatformRoot);
|
|
23451
23626
|
const entries = await readdir(parentDir, { withFileTypes: true }).catch(() => []);
|
|
23452
|
-
const temporaryRoots = entries.filter((entry) => entry.name.startsWith(`${baseName}.tmp-`)).map((entry) =>
|
|
23453
|
-
const previousRoots = entries.filter((entry) => entry.name.startsWith(`${baseName}.previous-`)).map((entry) =>
|
|
23454
|
-
const downloadsRoot =
|
|
23455
|
-
|
|
23627
|
+
const temporaryRoots = entries.filter((entry) => entry.name.startsWith(`${baseName}.tmp-`)).map((entry) => path11.join(parentDir, entry.name));
|
|
23628
|
+
const previousRoots = entries.filter((entry) => entry.name.startsWith(`${baseName}.previous-`)).map((entry) => path11.join(parentDir, entry.name)).sort().reverse();
|
|
23629
|
+
const downloadsRoot = path11.join(
|
|
23630
|
+
path11.dirname(path11.dirname(sharedPlatformRoot)),
|
|
23456
23631
|
".downloads"
|
|
23457
23632
|
);
|
|
23458
|
-
const staleDownloadRoots = cleanupDownloads ? (await readdir(downloadsRoot, { withFileTypes: true }).catch(() => [])).filter((entry) => entry.name.startsWith("postgres-18.4-")).map((entry) =>
|
|
23459
|
-
const canonicalBinDir =
|
|
23633
|
+
const staleDownloadRoots = cleanupDownloads ? (await readdir(downloadsRoot, { withFileTypes: true }).catch(() => [])).filter((entry) => entry.name.startsWith("postgres-18.4-")).map((entry) => path11.join(downloadsRoot, entry.name)) : [];
|
|
23634
|
+
const canonicalBinDir = path11.join(sharedPlatformRoot, "bin");
|
|
23460
23635
|
if (!await isRuntimePostgresPayloadUsable(
|
|
23461
23636
|
cacheDir,
|
|
23462
23637
|
canonicalBinDir,
|
|
@@ -23466,28 +23641,28 @@ async function reconcileSharedPostgresPayloadGenerations(cacheDir, sharedPlatfor
|
|
|
23466
23641
|
for (const previousRoot of previousRoots) {
|
|
23467
23642
|
if (!await isRuntimePostgresPayloadUsable(
|
|
23468
23643
|
cacheDir,
|
|
23469
|
-
|
|
23644
|
+
path11.join(previousRoot, "bin"),
|
|
23470
23645
|
postgresVersionProbe,
|
|
23471
23646
|
deadline
|
|
23472
23647
|
)) {
|
|
23473
23648
|
continue;
|
|
23474
23649
|
}
|
|
23475
|
-
await
|
|
23650
|
+
await rm2(sharedPlatformRoot, { recursive: true, force: true });
|
|
23476
23651
|
await rename(previousRoot, sharedPlatformRoot);
|
|
23477
23652
|
break;
|
|
23478
23653
|
}
|
|
23479
23654
|
}
|
|
23480
23655
|
await Promise.all([
|
|
23481
|
-
...temporaryRoots.map((candidate) =>
|
|
23482
|
-
...previousRoots.map((candidate) =>
|
|
23483
|
-
...staleDownloadRoots.map((candidate) =>
|
|
23656
|
+
...temporaryRoots.map((candidate) => rm2(candidate, { recursive: true, force: true })),
|
|
23657
|
+
...previousRoots.map((candidate) => rm2(candidate, { recursive: true, force: true })),
|
|
23658
|
+
...staleDownloadRoots.map((candidate) => rm2(candidate, { recursive: true, force: true }))
|
|
23484
23659
|
]);
|
|
23485
23660
|
}
|
|
23486
23661
|
async function installSharedRuntimePostgresPayload(cacheDir, homeDir, sourceBinDir, postgresVersionProbe, deadline) {
|
|
23487
23662
|
const sharedBinDir = resolveSharedRuntimePostgresPayloadBinDir(homeDir);
|
|
23488
|
-
const sharedRuntimeDir =
|
|
23663
|
+
const sharedRuntimeDir = path11.dirname(sharedBinDir);
|
|
23489
23664
|
const sharedPlatformRoot = sharedRuntimeDir;
|
|
23490
|
-
const sourceRuntimeDir =
|
|
23665
|
+
const sourceRuntimeDir = path11.dirname(sourceBinDir);
|
|
23491
23666
|
const sourceTemplateDir = await resolveRuntimePostgresTemplateDir(sourceBinDir, cacheDir, deadline);
|
|
23492
23667
|
if (!sourceTemplateDir) {
|
|
23493
23668
|
throw new RuntimeInstallError(
|
|
@@ -23508,13 +23683,13 @@ async function installSharedRuntimePostgresPayload(cacheDir, homeDir, sourceBinD
|
|
|
23508
23683
|
return sharedBinDir;
|
|
23509
23684
|
}
|
|
23510
23685
|
await assertSharedPostgresPayloadNotLive(cacheDir, homeDir, sharedBinDir);
|
|
23511
|
-
await
|
|
23686
|
+
await mkdir2(path11.dirname(sharedPlatformRoot), { recursive: true });
|
|
23512
23687
|
const temporaryPlatformRoot = `${sharedPlatformRoot}.tmp-${process.pid}-${Date.now()}`;
|
|
23513
23688
|
const previousPlatformRoot = `${sharedPlatformRoot}.previous-${process.pid}-${Date.now()}`;
|
|
23514
23689
|
let previousMoved = false;
|
|
23515
23690
|
let published = false;
|
|
23516
|
-
await
|
|
23517
|
-
await
|
|
23691
|
+
await rm2(temporaryPlatformRoot, { recursive: true, force: true });
|
|
23692
|
+
await rm2(previousPlatformRoot, { recursive: true, force: true });
|
|
23518
23693
|
try {
|
|
23519
23694
|
const temporaryRuntimeDir = temporaryPlatformRoot;
|
|
23520
23695
|
const sourceShareDir = resolveRuntimePostgresShareDir(sourceBinDir, sourceTemplateDir);
|
|
@@ -23525,7 +23700,7 @@ async function installSharedRuntimePostgresPayload(cacheDir, homeDir, sourceBinD
|
|
|
23525
23700
|
cacheDir,
|
|
23526
23701
|
deadline
|
|
23527
23702
|
);
|
|
23528
|
-
const temporaryBinDir =
|
|
23703
|
+
const temporaryBinDir = path11.join(temporaryRuntimeDir, "bin");
|
|
23529
23704
|
await validateRuntimePostgresVersion(cacheDir, temporaryBinDir, postgresVersionProbe, deadline);
|
|
23530
23705
|
try {
|
|
23531
23706
|
await rename(sharedPlatformRoot, previousPlatformRoot);
|
|
@@ -23544,13 +23719,13 @@ async function installSharedRuntimePostgresPayload(cacheDir, homeDir, sourceBinD
|
|
|
23544
23719
|
throw error;
|
|
23545
23720
|
}
|
|
23546
23721
|
if (previousMoved) {
|
|
23547
|
-
await
|
|
23722
|
+
await rm2(previousPlatformRoot, { recursive: true, force: true });
|
|
23548
23723
|
previousMoved = false;
|
|
23549
23724
|
}
|
|
23550
23725
|
} finally {
|
|
23551
|
-
await
|
|
23726
|
+
await rm2(temporaryPlatformRoot, { recursive: true, force: true });
|
|
23552
23727
|
if (published || !previousMoved) {
|
|
23553
|
-
await
|
|
23728
|
+
await rm2(previousPlatformRoot, { recursive: true, force: true });
|
|
23554
23729
|
}
|
|
23555
23730
|
}
|
|
23556
23731
|
return sharedBinDir;
|
|
@@ -23561,17 +23736,17 @@ async function downloadSharedRuntimePostgresPayload(cacheDir, homeDir, postgresV
|
|
|
23561
23736
|
const archiveUrl = archiveSource?.url ?? null;
|
|
23562
23737
|
if (!archiveUrl) return null;
|
|
23563
23738
|
const sharedBinDir = resolveSharedRuntimePostgresPayloadBinDir(homeDir);
|
|
23564
|
-
const sharedPlatformRoot =
|
|
23739
|
+
const sharedPlatformRoot = path11.dirname(sharedBinDir);
|
|
23565
23740
|
const downloadLockPath = `${sharedPlatformRoot}.download.lock`;
|
|
23566
23741
|
return withRuntimeFilesystemLock(downloadLockPath, async () => {
|
|
23567
23742
|
if (await isRuntimePostgresPayloadUsable(cacheDir, sharedBinDir, postgresVersionProbe, deadline)) {
|
|
23568
23743
|
return sharedBinDir;
|
|
23569
23744
|
}
|
|
23570
|
-
const workRoot =
|
|
23571
|
-
await
|
|
23572
|
-
const workDir = await mkdtemp(
|
|
23573
|
-
const archivePath =
|
|
23574
|
-
const extractDir =
|
|
23745
|
+
const workRoot = path11.join(homeDir, "runtime-payloads", ".downloads");
|
|
23746
|
+
await mkdir2(workRoot, { recursive: true });
|
|
23747
|
+
const workDir = await mkdtemp(path11.join(workRoot, "postgres-18.4-"));
|
|
23748
|
+
const archivePath = path11.join(workDir, "postgresql-18.4.zip");
|
|
23749
|
+
const extractDir = path11.join(workDir, "extract");
|
|
23575
23750
|
try {
|
|
23576
23751
|
await downloadRuntimePostgresArchive(
|
|
23577
23752
|
archiveUrl,
|
|
@@ -23582,7 +23757,7 @@ async function downloadSharedRuntimePostgresPayload(cacheDir, homeDir, postgresV
|
|
|
23582
23757
|
const configuredMaxBytes = Number.parseInt(process.env[RUDDER_POSTGRES_RUNTIME_ARCHIVE_MAX_BYTES_ENV2] ?? "", 10);
|
|
23583
23758
|
const maxArchiveBytes = Number.isSafeInteger(configuredMaxBytes) && configuredMaxBytes > 0 ? configuredMaxBytes : DEFAULT_RUNTIME_POSTGRES_ARCHIVE_MAX_BYTES2;
|
|
23584
23759
|
const nativePublishStaging = `${sharedPlatformRoot}.tmp-native-${process.pid}-${Date.now()}`;
|
|
23585
|
-
await
|
|
23760
|
+
await mkdir2(path11.dirname(sharedPlatformRoot), { recursive: true });
|
|
23586
23761
|
const nativeInstall = await tryInstallNativePayload({
|
|
23587
23762
|
archivePath,
|
|
23588
23763
|
extractPath: extractDir,
|
|
@@ -23614,22 +23789,22 @@ async function downloadSharedRuntimePostgresPayload(cacheDir, homeDir, postgresV
|
|
|
23614
23789
|
);
|
|
23615
23790
|
}
|
|
23616
23791
|
await copyRuntimePostgresPayloadWithinDeadline(
|
|
23617
|
-
|
|
23792
|
+
path11.dirname(extractedBinDir2),
|
|
23618
23793
|
publishStagingPath,
|
|
23619
23794
|
resolveRuntimePostgresShareDir(extractedBinDir2, templateDir),
|
|
23620
23795
|
cacheDir,
|
|
23621
23796
|
deadline,
|
|
23622
23797
|
context.signal
|
|
23623
23798
|
);
|
|
23624
|
-
return
|
|
23799
|
+
return path11.relative(
|
|
23625
23800
|
publishStagingPath,
|
|
23626
|
-
|
|
23801
|
+
path11.join(publishStagingPath, "bin", runtimePostgresExecutableName("postgres"))
|
|
23627
23802
|
);
|
|
23628
23803
|
},
|
|
23629
23804
|
validatePublished: async (destinationPath) => {
|
|
23630
23805
|
await validateRuntimePostgresVersion(
|
|
23631
23806
|
cacheDir,
|
|
23632
|
-
|
|
23807
|
+
path11.join(destinationPath, "bin"),
|
|
23633
23808
|
postgresVersionProbe,
|
|
23634
23809
|
deadline
|
|
23635
23810
|
);
|
|
@@ -23638,7 +23813,7 @@ async function downloadSharedRuntimePostgresPayload(cacheDir, homeDir, postgresV
|
|
|
23638
23813
|
if (nativeInstall.installed) {
|
|
23639
23814
|
return sharedBinDir;
|
|
23640
23815
|
}
|
|
23641
|
-
await
|
|
23816
|
+
await mkdir2(extractDir, { recursive: true });
|
|
23642
23817
|
extractRuntimePostgresArchive(archivePath, extractDir, cacheDir, deadline);
|
|
23643
23818
|
const extractedBinDir = await findRuntimePostgresBinDir(
|
|
23644
23819
|
extractDir,
|
|
@@ -23660,27 +23835,27 @@ async function downloadSharedRuntimePostgresPayload(cacheDir, homeDir, postgresV
|
|
|
23660
23835
|
deadline
|
|
23661
23836
|
);
|
|
23662
23837
|
} finally {
|
|
23663
|
-
const cleanup = cleanupWorkDir ?? ((candidate) =>
|
|
23838
|
+
const cleanup = cleanupWorkDir ?? ((candidate) => rm2(candidate, { recursive: true, force: true }));
|
|
23664
23839
|
void cleanup(workDir).catch(() => {
|
|
23665
23840
|
});
|
|
23666
23841
|
}
|
|
23667
23842
|
}, { deadline, cacheDir, command: "acquire shared PostgreSQL download lock" });
|
|
23668
23843
|
}
|
|
23669
23844
|
async function ensureRuntimePostgresCompatibilityLink(cacheDir, homeDir, packageVersion) {
|
|
23670
|
-
const compatibilityRoot =
|
|
23671
|
-
const sharedPayloadRoot =
|
|
23845
|
+
const compatibilityRoot = path11.join(cacheDir, RUNTIME_POSTGRES_PAYLOAD_DIR);
|
|
23846
|
+
const sharedPayloadRoot = path11.join(homeDir, "runtime-payloads", RUNTIME_POSTGRES_PAYLOAD_DIR);
|
|
23672
23847
|
const runtimeMetadata = await readRuntimeInstallMetadata(cacheDir);
|
|
23673
23848
|
const liveDescriptors = await readLiveRuntimeDescriptors(homeDir);
|
|
23674
23849
|
const compatibilityBinDir = resolveRuntimePostgresPayloadBinDir(cacheDir);
|
|
23675
23850
|
const isProtected = liveDescriptors.some((descriptor) => descriptor.postgresBinDir && pathIsInside(descriptor.postgresBinDir, compatibilityRoot) || !descriptor.postgresBinDir && descriptor.version === (runtimeMetadata?.packageVersion ?? packageVersion));
|
|
23676
23851
|
if (isProtected) return;
|
|
23677
|
-
await
|
|
23852
|
+
await mkdir2(path11.dirname(compatibilityRoot), { recursive: true });
|
|
23678
23853
|
const temporaryRoot = `${compatibilityRoot}.next-${process.pid}-${Date.now()}`;
|
|
23679
23854
|
const previousRoot = `${compatibilityRoot}.previous-${process.pid}-${Date.now()}`;
|
|
23680
|
-
await
|
|
23681
|
-
await
|
|
23855
|
+
await rm2(temporaryRoot, { recursive: true, force: true });
|
|
23856
|
+
await rm2(previousRoot, { recursive: true, force: true });
|
|
23682
23857
|
await symlink(
|
|
23683
|
-
process.platform === "win32" ? sharedPayloadRoot :
|
|
23858
|
+
process.platform === "win32" ? sharedPayloadRoot : path11.relative(path11.dirname(compatibilityRoot), sharedPayloadRoot),
|
|
23684
23859
|
temporaryRoot,
|
|
23685
23860
|
process.platform === "win32" ? "junction" : "dir"
|
|
23686
23861
|
);
|
|
@@ -23702,18 +23877,18 @@ async function ensureRuntimePostgresCompatibilityLink(cacheDir, homeDir, package
|
|
|
23702
23877
|
throw error;
|
|
23703
23878
|
}
|
|
23704
23879
|
if (previousMoved) {
|
|
23705
|
-
await
|
|
23880
|
+
await rm2(previousRoot, { recursive: true, force: true });
|
|
23706
23881
|
previousMoved = false;
|
|
23707
23882
|
}
|
|
23708
23883
|
} finally {
|
|
23709
|
-
await
|
|
23710
|
-
if (!previousMoved) await
|
|
23884
|
+
await rm2(temporaryRoot, { recursive: true, force: true });
|
|
23885
|
+
if (!previousMoved) await rm2(previousRoot, { recursive: true, force: true });
|
|
23711
23886
|
}
|
|
23712
23887
|
}
|
|
23713
23888
|
async function stageRuntimePostgresPayload(cacheDir, homeDir, packageVersion, enabled, postgresVersionProbe, deadline, cleanupDownloadWorkDir) {
|
|
23714
23889
|
if (!enabled) return { output: "" };
|
|
23715
23890
|
const explicitSourceBinDir = process.env[RUDDER_POSTGRES_BIN_DIR_ENV]?.trim();
|
|
23716
|
-
const resolvedExplicitSourceBinDir = explicitSourceBinDir ?
|
|
23891
|
+
const resolvedExplicitSourceBinDir = explicitSourceBinDir ? path11.resolve(explicitSourceBinDir) : null;
|
|
23717
23892
|
if (resolvedExplicitSourceBinDir && !isManagedRuntimePostgresBinDir(resolvedExplicitSourceBinDir, homeDir)) {
|
|
23718
23893
|
await validateRuntimePostgresVersion(
|
|
23719
23894
|
cacheDir,
|
|
@@ -23734,7 +23909,7 @@ async function stageRuntimePostgresPayload(cacheDir, homeDir, packageVersion, en
|
|
|
23734
23909
|
};
|
|
23735
23910
|
}
|
|
23736
23911
|
const sharedBinDir = resolveSharedRuntimePostgresPayloadBinDir(homeDir);
|
|
23737
|
-
const sharedPlatformRoot =
|
|
23912
|
+
const sharedPlatformRoot = path11.dirname(sharedBinDir);
|
|
23738
23913
|
await withRuntimeFilesystemLock(
|
|
23739
23914
|
`${sharedPlatformRoot}.install.lock`,
|
|
23740
23915
|
async () => reconcileSharedPostgresPayloadGenerations(
|
|
@@ -23825,7 +24000,7 @@ async function pruneRuntimeCache(options = {}) {
|
|
|
23825
24000
|
const warnings = [];
|
|
23826
24001
|
for (const entry of deletions) {
|
|
23827
24002
|
try {
|
|
23828
|
-
await
|
|
24003
|
+
await rm2(entry.cacheDir, { recursive: true, force: true });
|
|
23829
24004
|
deleted.push({
|
|
23830
24005
|
cacheDir: entry.cacheDir,
|
|
23831
24006
|
packageVersion: entry.packageVersion,
|
|
@@ -23846,13 +24021,13 @@ async function pruneRuntimeCache(options = {}) {
|
|
|
23846
24021
|
};
|
|
23847
24022
|
}
|
|
23848
24023
|
async function scanRuntimeCacheEntries(homeDir) {
|
|
23849
|
-
const runtimesDir =
|
|
24024
|
+
const runtimesDir = path11.join(homeDir, "runtimes");
|
|
23850
24025
|
const dirents = await readdir(runtimesDir, { withFileTypes: true }).catch(() => null);
|
|
23851
24026
|
if (!dirents) return [];
|
|
23852
24027
|
const entries = [];
|
|
23853
24028
|
for (const dirent of dirents) {
|
|
23854
24029
|
if (!dirent.isDirectory()) continue;
|
|
23855
|
-
const cacheDir =
|
|
24030
|
+
const cacheDir = path11.join(runtimesDir, dirent.name);
|
|
23856
24031
|
const metadata = await readRuntimeInstallMetadata(cacheDir);
|
|
23857
24032
|
if (!metadata) continue;
|
|
23858
24033
|
const fallbackStat = await safeStat(cacheDir);
|
|
@@ -23885,7 +24060,7 @@ async function directorySizeBytes(targetPath) {
|
|
|
23885
24060
|
if (!dirents) return 0;
|
|
23886
24061
|
let total = 0;
|
|
23887
24062
|
for (const dirent of dirents) {
|
|
23888
|
-
const entryPath =
|
|
24063
|
+
const entryPath = path11.join(targetPath, dirent.name);
|
|
23889
24064
|
if (dirent.isSymbolicLink()) continue;
|
|
23890
24065
|
if (dirent.isDirectory()) {
|
|
23891
24066
|
total += await directorySizeBytes(entryPath);
|
|
@@ -23897,15 +24072,15 @@ async function directorySizeBytes(targetPath) {
|
|
|
23897
24072
|
return total;
|
|
23898
24073
|
}
|
|
23899
24074
|
async function readActiveRuntimeVersions(homeDir) {
|
|
23900
|
-
const instancesDir =
|
|
24075
|
+
const instancesDir = path11.join(homeDir, "instances");
|
|
23901
24076
|
const dirents = await readdir(instancesDir, { withFileTypes: true }).catch(() => null);
|
|
23902
24077
|
if (!dirents) return [];
|
|
23903
24078
|
const versions = /* @__PURE__ */ new Set();
|
|
23904
24079
|
for (const dirent of dirents) {
|
|
23905
24080
|
if (!dirent.isDirectory()) continue;
|
|
23906
24081
|
try {
|
|
23907
|
-
const descriptorPath =
|
|
23908
|
-
const parsed = JSON.parse(await
|
|
24082
|
+
const descriptorPath = path11.join(instancesDir, dirent.name, "runtime", "server.json");
|
|
24083
|
+
const parsed = JSON.parse(await readFile2(descriptorPath, "utf8"));
|
|
23909
24084
|
if (typeof parsed.version !== "string") continue;
|
|
23910
24085
|
if (typeof parsed.pid === "number" && Number.isInteger(parsed.pid) && parsed.pid > 0 && isPidRunning(parsed.pid)) {
|
|
23911
24086
|
versions.add(parsed.version);
|
|
@@ -24013,25 +24188,27 @@ function parseRuntimeVersion(version) {
|
|
|
24013
24188
|
canaryNumber: canaryMatch ? Number(canaryMatch[1]) : null
|
|
24014
24189
|
};
|
|
24015
24190
|
}
|
|
24016
|
-
var RUNTIME_NPM_PACKAGE_NAME,
|
|
24191
|
+
var RUNTIME_NPM_PACKAGE_NAME, NPM_PUBLIC_REGISTRY_URL2, RUNTIME_METADATA_FILE, RUNTIME_POSTGRES_PAYLOAD_DIR, DEFAULT_RUNTIME_CACHE_MAX_ENTRIES, DEFAULT_RUNTIME_CACHE_MAX_AGE_MS, DEFAULT_RUNTIME_CACHE_MAX_BYTES, DEFAULT_RUNTIME_CACHE_KEEP_PREVIOUS, RUNTIME_NPM_INSTALL_BASE_FLAGS, RUNTIME_NPM_INSTALL_OPTIONAL_FLAGS, RUNTIME_NPM_INSTALL_SUFFIX_FLAGS, EMBEDDED_POSTGRES_PACKAGE_NAME, RUDDER_DESKTOP_MANAGED_POSTGRES_BIN_DIR_ENV, RUDDER_POSTGRES_BIN_DIR_ENV, RUDDER_POSTGRES_RUNTIME_ARCHIVE_MAX_BYTES_ENV2, DEFAULT_RUNTIME_POSTGRES_ARCHIVE_MAX_BYTES2, RUNTIME_CACHE_PACKAGE_JSON, RuntimeInstallError;
|
|
24017
24192
|
var init_install = __esm({
|
|
24018
24193
|
"src/runtime/install.ts"() {
|
|
24019
24194
|
"use strict";
|
|
24020
24195
|
init_home();
|
|
24021
24196
|
init_npm_command();
|
|
24022
24197
|
init_native_payload();
|
|
24198
|
+
init_platform_dependencies();
|
|
24023
24199
|
init_postgres_runtime_download();
|
|
24024
24200
|
init_postgres_runtime_source();
|
|
24025
24201
|
RUNTIME_NPM_PACKAGE_NAME = "@rudderhq/server";
|
|
24026
|
-
|
|
24202
|
+
NPM_PUBLIC_REGISTRY_URL2 = "https://registry.npmjs.org";
|
|
24027
24203
|
RUNTIME_METADATA_FILE = "runtime.json";
|
|
24028
24204
|
RUNTIME_POSTGRES_PAYLOAD_DIR = "postgres-18.4";
|
|
24029
24205
|
DEFAULT_RUNTIME_CACHE_MAX_ENTRIES = 2;
|
|
24030
24206
|
DEFAULT_RUNTIME_CACHE_MAX_AGE_MS = 14 * 24 * 60 * 60 * 1e3;
|
|
24031
24207
|
DEFAULT_RUNTIME_CACHE_MAX_BYTES = 2 * 1024 * 1024 * 1024;
|
|
24032
24208
|
DEFAULT_RUNTIME_CACHE_KEEP_PREVIOUS = 0;
|
|
24033
|
-
|
|
24034
|
-
|
|
24209
|
+
RUNTIME_NPM_INSTALL_BASE_FLAGS = ["--omit=dev"];
|
|
24210
|
+
RUNTIME_NPM_INSTALL_OPTIONAL_FLAGS = ["--include=optional"];
|
|
24211
|
+
RUNTIME_NPM_INSTALL_SUFFIX_FLAGS = ["--no-audit", "--no-fund"];
|
|
24035
24212
|
EMBEDDED_POSTGRES_PACKAGE_NAME = "embedded-postgres";
|
|
24036
24213
|
RUDDER_DESKTOP_MANAGED_POSTGRES_BIN_DIR_ENV = "RUDDER_DESKTOP_MANAGED_POSTGRES_BIN_DIR";
|
|
24037
24214
|
RUDDER_POSTGRES_BIN_DIR_ENV = "RUDDER_POSTGRES_BIN_DIR";
|
|
@@ -24043,11 +24220,6 @@ var init_install = __esm({
|
|
|
24043
24220
|
private: true,
|
|
24044
24221
|
type: "module"
|
|
24045
24222
|
};
|
|
24046
|
-
NPM_PLATFORM_REPAIR_ENV = {
|
|
24047
|
-
npm_config_registry: NPM_PUBLIC_REGISTRY_URL,
|
|
24048
|
-
npm_config_update_notifier: "false",
|
|
24049
|
-
NO_UPDATE_NOTIFIER: "1"
|
|
24050
|
-
};
|
|
24051
24223
|
RuntimeInstallError = class extends Error {
|
|
24052
24224
|
cacheDir;
|
|
24053
24225
|
command;
|
|
@@ -24065,7 +24237,7 @@ var init_install = __esm({
|
|
|
24065
24237
|
|
|
24066
24238
|
// src/runtime/server-entry.ts
|
|
24067
24239
|
import fs8 from "node:fs";
|
|
24068
|
-
import
|
|
24240
|
+
import path12 from "node:path";
|
|
24069
24241
|
import { fileURLToPath as fileURLToPath5, pathToFileURL as pathToFileURL2 } from "node:url";
|
|
24070
24242
|
function formatError(err) {
|
|
24071
24243
|
if (err instanceof Error) {
|
|
@@ -24087,10 +24259,14 @@ function maybeEnableUiDevMiddleware(entrypoint) {
|
|
|
24087
24259
|
}
|
|
24088
24260
|
}
|
|
24089
24261
|
function resolveDevServerEntry() {
|
|
24090
|
-
const projectRoot =
|
|
24091
|
-
return
|
|
24262
|
+
const projectRoot = path12.resolve(path12.dirname(fileURLToPath5(import.meta.url)), "../../..");
|
|
24263
|
+
return path12.resolve(projectRoot, "server/src/index.ts");
|
|
24092
24264
|
}
|
|
24093
24265
|
async function loadServerRuntimeModule(options) {
|
|
24266
|
+
const runtimePackageDir = options.runtimePackageDir?.trim();
|
|
24267
|
+
if (runtimePackageDir) {
|
|
24268
|
+
return await importRuntimeServerModule(path12.resolve(runtimePackageDir));
|
|
24269
|
+
}
|
|
24094
24270
|
const devEntry = resolveDevServerEntry();
|
|
24095
24271
|
if (fs8.existsSync(devEntry)) {
|
|
24096
24272
|
maybeEnableUiDevMiddleware(devEntry);
|
|
@@ -24113,20 +24289,20 @@ async function loadServerRuntimeModule(options) {
|
|
|
24113
24289
|
async function startManagedServerFromRuntime(options) {
|
|
24114
24290
|
try {
|
|
24115
24291
|
const mod = await loadServerRuntimeModule(options);
|
|
24116
|
-
return await startServerFromModule(mod);
|
|
24292
|
+
return await startServerFromModule(mod, options);
|
|
24117
24293
|
} catch (err) {
|
|
24118
24294
|
throw new Error(`Rudder server failed to start.
|
|
24119
24295
|
${formatError(err)}`);
|
|
24120
24296
|
}
|
|
24121
24297
|
}
|
|
24122
|
-
async function startServerFromModule(mod) {
|
|
24298
|
+
async function startServerFromModule(mod, options = {}) {
|
|
24123
24299
|
const startManagedLocalServer = mod.startManagedLocalServer;
|
|
24124
24300
|
if (typeof startManagedLocalServer !== "function") {
|
|
24125
24301
|
throw new Error("Rudder server runtime did not export startManagedLocalServer().");
|
|
24126
24302
|
}
|
|
24127
24303
|
return await startManagedLocalServer({
|
|
24128
24304
|
ownerKind: "cli",
|
|
24129
|
-
takeoverOnVersionMismatch: true
|
|
24305
|
+
takeoverOnVersionMismatch: options.takeoverOnVersionMismatch ?? true
|
|
24130
24306
|
});
|
|
24131
24307
|
}
|
|
24132
24308
|
var RUDDER_POSTGRES_BIN_DIR_ENV2;
|
|
@@ -24226,23 +24402,85 @@ var init_auth_bootstrap_ceo = __esm({
|
|
|
24226
24402
|
}
|
|
24227
24403
|
});
|
|
24228
24404
|
|
|
24405
|
+
// src/config/local-env.ts
|
|
24406
|
+
function parseLocalEnvName(value) {
|
|
24407
|
+
if (!value) return null;
|
|
24408
|
+
const normalized = value.trim().toLowerCase().replace(/-/g, "_");
|
|
24409
|
+
return LOCAL_ENV_NAMES.includes(normalized) ? normalized : null;
|
|
24410
|
+
}
|
|
24411
|
+
function resolveLocalEnvProfile(value) {
|
|
24412
|
+
const name = parseLocalEnvName(value);
|
|
24413
|
+
return name ? LOCAL_ENV_PROFILES[name] : null;
|
|
24414
|
+
}
|
|
24415
|
+
function resolveActiveLocalEnvProfile() {
|
|
24416
|
+
return resolveLocalEnvProfile(process.env.RUDDER_LOCAL_ENV);
|
|
24417
|
+
}
|
|
24418
|
+
function applyLocalEnvProfile(input) {
|
|
24419
|
+
const profile = resolveLocalEnvProfile(input.localEnv ?? process.env.RUDDER_LOCAL_ENV);
|
|
24420
|
+
if (!profile) return null;
|
|
24421
|
+
process.env.RUDDER_LOCAL_ENV = profile.name;
|
|
24422
|
+
if (!input.instance?.trim()) {
|
|
24423
|
+
process.env.RUDDER_INSTANCE_ID = profile.instanceId;
|
|
24424
|
+
}
|
|
24425
|
+
if (!process.env.PORT?.trim()) {
|
|
24426
|
+
process.env.PORT = String(profile.port);
|
|
24427
|
+
}
|
|
24428
|
+
if (!process.env.RUDDER_EMBEDDED_POSTGRES_PORT?.trim()) {
|
|
24429
|
+
process.env.RUDDER_EMBEDDED_POSTGRES_PORT = String(profile.embeddedPostgresPort);
|
|
24430
|
+
}
|
|
24431
|
+
return profile;
|
|
24432
|
+
}
|
|
24433
|
+
var LOCAL_ENV_NAMES, LOCAL_ENV_PROFILES;
|
|
24434
|
+
var init_local_env = __esm({
|
|
24435
|
+
"src/config/local-env.ts"() {
|
|
24436
|
+
"use strict";
|
|
24437
|
+
LOCAL_ENV_NAMES = ["dev", "prod_local", "e2e"];
|
|
24438
|
+
LOCAL_ENV_PROFILES = {
|
|
24439
|
+
dev: {
|
|
24440
|
+
name: "dev",
|
|
24441
|
+
instanceId: "dev",
|
|
24442
|
+
port: 3100,
|
|
24443
|
+
embeddedPostgresPort: 54329,
|
|
24444
|
+
resettable: true,
|
|
24445
|
+
description: "Disposable local development instance"
|
|
24446
|
+
},
|
|
24447
|
+
prod_local: {
|
|
24448
|
+
name: "prod_local",
|
|
24449
|
+
instanceId: "default",
|
|
24450
|
+
port: 3200,
|
|
24451
|
+
embeddedPostgresPort: 54339,
|
|
24452
|
+
resettable: false,
|
|
24453
|
+
description: "Persistent local instance"
|
|
24454
|
+
},
|
|
24455
|
+
e2e: {
|
|
24456
|
+
name: "e2e",
|
|
24457
|
+
instanceId: "e2e",
|
|
24458
|
+
port: 3300,
|
|
24459
|
+
embeddedPostgresPort: 54349,
|
|
24460
|
+
resettable: true,
|
|
24461
|
+
description: "Isolated end-to-end test instance"
|
|
24462
|
+
}
|
|
24463
|
+
};
|
|
24464
|
+
}
|
|
24465
|
+
});
|
|
24466
|
+
|
|
24229
24467
|
// src/utils/path-resolver.ts
|
|
24230
24468
|
import fs11 from "node:fs";
|
|
24231
|
-
import
|
|
24469
|
+
import path22 from "node:path";
|
|
24232
24470
|
function unique(items) {
|
|
24233
24471
|
return Array.from(new Set(items));
|
|
24234
24472
|
}
|
|
24235
24473
|
function resolveRuntimeLikePath(value, configPath) {
|
|
24236
24474
|
const expanded = expandHomePrefix(value);
|
|
24237
|
-
if (
|
|
24475
|
+
if (path22.isAbsolute(expanded)) return path22.resolve(expanded);
|
|
24238
24476
|
const cwd = process.cwd();
|
|
24239
|
-
const configDir = configPath ?
|
|
24240
|
-
const workspaceRoot = configDir ?
|
|
24477
|
+
const configDir = configPath ? path22.dirname(configPath) : null;
|
|
24478
|
+
const workspaceRoot = configDir ? path22.resolve(configDir, "..") : cwd;
|
|
24241
24479
|
const candidates = unique([
|
|
24242
|
-
...configDir ? [
|
|
24243
|
-
|
|
24244
|
-
|
|
24245
|
-
|
|
24480
|
+
...configDir ? [path22.resolve(configDir, expanded)] : [],
|
|
24481
|
+
path22.resolve(workspaceRoot, "server", expanded),
|
|
24482
|
+
path22.resolve(workspaceRoot, expanded),
|
|
24483
|
+
path22.resolve(cwd, expanded)
|
|
24246
24484
|
]);
|
|
24247
24485
|
return candidates.find((candidate) => fs11.existsSync(candidate)) ?? candidates[0];
|
|
24248
24486
|
}
|
|
@@ -24256,7 +24494,7 @@ var init_path_resolver = __esm({
|
|
|
24256
24494
|
// src/config/secrets-key.ts
|
|
24257
24495
|
import { randomBytes as randomBytes2 } from "node:crypto";
|
|
24258
24496
|
import fs12 from "node:fs";
|
|
24259
|
-
import
|
|
24497
|
+
import path23 from "node:path";
|
|
24260
24498
|
function ensureLocalSecretsKeyFile(config, configPath) {
|
|
24261
24499
|
if (config.secrets.provider !== "local_encrypted") {
|
|
24262
24500
|
return { status: "skipped_provider", path: null };
|
|
@@ -24271,7 +24509,7 @@ function ensureLocalSecretsKeyFile(config, configPath) {
|
|
|
24271
24509
|
if (fs12.existsSync(keyFilePath)) {
|
|
24272
24510
|
return { status: "existing", path: keyFilePath };
|
|
24273
24511
|
}
|
|
24274
|
-
fs12.mkdirSync(
|
|
24512
|
+
fs12.mkdirSync(path23.dirname(keyFilePath), { recursive: true });
|
|
24275
24513
|
fs12.writeFileSync(keyFilePath, randomBytes2(32).toString("base64"), {
|
|
24276
24514
|
encoding: "utf8",
|
|
24277
24515
|
mode: 384
|
|
@@ -25357,7 +25595,7 @@ var init_port_check = __esm({
|
|
|
25357
25595
|
// src/checks/secrets-check.ts
|
|
25358
25596
|
import { randomBytes as randomBytes3 } from "node:crypto";
|
|
25359
25597
|
import fs15 from "node:fs";
|
|
25360
|
-
import
|
|
25598
|
+
import path24 from "node:path";
|
|
25361
25599
|
function decodeMasterKey(raw) {
|
|
25362
25600
|
const trimmed = raw.trim();
|
|
25363
25601
|
if (!trimmed) return null;
|
|
@@ -25427,7 +25665,7 @@ function secretsCheck(config, configPath) {
|
|
|
25427
25665
|
message: `Secrets key file does not exist yet: ${keyFilePath}`,
|
|
25428
25666
|
canRepair: true,
|
|
25429
25667
|
repair: () => {
|
|
25430
|
-
fs15.mkdirSync(
|
|
25668
|
+
fs15.mkdirSync(path24.dirname(keyFilePath), { recursive: true });
|
|
25431
25669
|
fs15.writeFileSync(keyFilePath, randomBytes3(32).toString("base64"), {
|
|
25432
25670
|
encoding: "utf8",
|
|
25433
25671
|
mode: 384
|
|
@@ -25697,7 +25935,8 @@ var init_doctor = __esm({
|
|
|
25697
25935
|
});
|
|
25698
25936
|
|
|
25699
25937
|
// src/install.ts
|
|
25700
|
-
import { execFileSync as execFileSync2, spawnSync as
|
|
25938
|
+
import { execFileSync as execFileSync2, spawnSync as spawnSync4 } from "node:child_process";
|
|
25939
|
+
import path25 from "node:path";
|
|
25701
25940
|
function normalizePath(value) {
|
|
25702
25941
|
return (value ?? "").replaceAll("\\", "/").toLowerCase();
|
|
25703
25942
|
}
|
|
@@ -25746,6 +25985,26 @@ function getGlobalInstalledPackageVersion(packageName, execFileSyncImpl = execFi
|
|
|
25746
25985
|
return null;
|
|
25747
25986
|
}
|
|
25748
25987
|
}
|
|
25988
|
+
function resolveGlobalInstalledCliEntry(execFileSyncImpl = execFileSync2) {
|
|
25989
|
+
let globalRoot;
|
|
25990
|
+
try {
|
|
25991
|
+
const npm = resolveNpmCommandInvocation();
|
|
25992
|
+
globalRoot = execFileSyncImpl(
|
|
25993
|
+
npm.command,
|
|
25994
|
+
[...npm.args, "root", "--global"],
|
|
25995
|
+
{
|
|
25996
|
+
encoding: "utf8",
|
|
25997
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
25998
|
+
}
|
|
25999
|
+
).trim();
|
|
26000
|
+
} catch {
|
|
26001
|
+
throw new Error("Could not resolve the global npm package directory for the Rudder browser app.");
|
|
26002
|
+
}
|
|
26003
|
+
if (!globalRoot) {
|
|
26004
|
+
throw new Error("npm returned an empty global package directory for the Rudder browser app.");
|
|
26005
|
+
}
|
|
26006
|
+
return path25.join(globalRoot, "@rudderhq", "cli", "dist", "index.js");
|
|
26007
|
+
}
|
|
25749
26008
|
function hasPersistentBinaryOnPath(execFileSyncImpl = execFileSync2) {
|
|
25750
26009
|
const { command, args } = resolveCommandLookupExecutable();
|
|
25751
26010
|
try {
|
|
@@ -25781,10 +26040,10 @@ function detectPersistentCliState(options = {}) {
|
|
|
25781
26040
|
};
|
|
25782
26041
|
}
|
|
25783
26042
|
function installPersistentCli(options) {
|
|
25784
|
-
const spawnSyncImpl = options.spawnSyncImpl ??
|
|
26043
|
+
const spawnSyncImpl = options.spawnSyncImpl ?? spawnSync4;
|
|
25785
26044
|
const command = `npm install --global ${options.installSpec}`;
|
|
25786
26045
|
const initialResult = runNpmGlobalInstall(spawnSyncImpl, ["install", "--global", options.installSpec]);
|
|
25787
|
-
const initialOutput =
|
|
26046
|
+
const initialOutput = collectSpawnOutput3(initialResult);
|
|
25788
26047
|
if (initialResult.status === 0 || !isRudderBinConflict(initialOutput)) {
|
|
25789
26048
|
return {
|
|
25790
26049
|
ok: initialResult.status === 0,
|
|
@@ -25794,7 +26053,7 @@ function installPersistentCli(options) {
|
|
|
25794
26053
|
}
|
|
25795
26054
|
const forcedCommand = `npm install --global --force ${options.installSpec}`;
|
|
25796
26055
|
const forcedResult = runNpmGlobalInstall(spawnSyncImpl, ["install", "--global", "--force", options.installSpec]);
|
|
25797
|
-
const forcedOutput =
|
|
26056
|
+
const forcedOutput = collectSpawnOutput3(forcedResult);
|
|
25798
26057
|
return {
|
|
25799
26058
|
ok: forcedResult.status === 0,
|
|
25800
26059
|
command: forcedCommand,
|
|
@@ -25806,85 +26065,23 @@ function runNpmGlobalInstall(spawnSyncImpl, args) {
|
|
|
25806
26065
|
return spawnSyncImpl(npm.command, [...npm.args, ...args], {
|
|
25807
26066
|
encoding: "utf8",
|
|
25808
26067
|
stdio: ["inherit", "pipe", "pipe"],
|
|
25809
|
-
...process.platform === "win32" ? { windowsHide: true } : {}
|
|
25810
|
-
});
|
|
25811
|
-
}
|
|
25812
|
-
function collectSpawnOutput2(result) {
|
|
25813
|
-
return [result.stdout, result.stderr, result.error instanceof Error ? result.error.message : null].filter((value) => typeof value === "string" && value.trim().length > 0).join("\n").trim();
|
|
25814
|
-
}
|
|
25815
|
-
function isRudderBinConflict(output) {
|
|
25816
|
-
const normalized = output.toLowerCase().replaceAll("\\", "/");
|
|
25817
|
-
return normalized.includes("eexist") && (normalized.includes(`/${CLI_BIN_NAME}`) || normalized.includes(`/${CLI_BIN_NAME}.cmd`) || normalized.includes(`/${CLI_BIN_NAME}.ps1`));
|
|
25818
|
-
}
|
|
25819
|
-
var CLI_NPM_PACKAGE_NAME, CLI_BIN_NAME;
|
|
25820
|
-
var init_install2 = __esm({
|
|
25821
|
-
"src/install.ts"() {
|
|
25822
|
-
"use strict";
|
|
25823
|
-
init_npm_command();
|
|
25824
|
-
CLI_NPM_PACKAGE_NAME = "@rudderhq/cli";
|
|
25825
|
-
CLI_BIN_NAME = "rudder";
|
|
25826
|
-
}
|
|
25827
|
-
});
|
|
25828
|
-
|
|
25829
|
-
// src/config/local-env.ts
|
|
25830
|
-
function parseLocalEnvName(value) {
|
|
25831
|
-
if (!value) return null;
|
|
25832
|
-
const normalized = value.trim().toLowerCase().replace(/-/g, "_");
|
|
25833
|
-
return LOCAL_ENV_NAMES.includes(normalized) ? normalized : null;
|
|
25834
|
-
}
|
|
25835
|
-
function resolveLocalEnvProfile(value) {
|
|
25836
|
-
const name = parseLocalEnvName(value);
|
|
25837
|
-
return name ? LOCAL_ENV_PROFILES[name] : null;
|
|
26068
|
+
...process.platform === "win32" ? { windowsHide: true } : {}
|
|
26069
|
+
});
|
|
25838
26070
|
}
|
|
25839
|
-
function
|
|
25840
|
-
return
|
|
26071
|
+
function collectSpawnOutput3(result) {
|
|
26072
|
+
return [result.stdout, result.stderr, result.error instanceof Error ? result.error.message : null].filter((value) => typeof value === "string" && value.trim().length > 0).join("\n").trim();
|
|
25841
26073
|
}
|
|
25842
|
-
function
|
|
25843
|
-
const
|
|
25844
|
-
|
|
25845
|
-
process.env.RUDDER_LOCAL_ENV = profile.name;
|
|
25846
|
-
if (!input.instance?.trim()) {
|
|
25847
|
-
process.env.RUDDER_INSTANCE_ID = profile.instanceId;
|
|
25848
|
-
}
|
|
25849
|
-
if (!process.env.PORT?.trim()) {
|
|
25850
|
-
process.env.PORT = String(profile.port);
|
|
25851
|
-
}
|
|
25852
|
-
if (!process.env.RUDDER_EMBEDDED_POSTGRES_PORT?.trim()) {
|
|
25853
|
-
process.env.RUDDER_EMBEDDED_POSTGRES_PORT = String(profile.embeddedPostgresPort);
|
|
25854
|
-
}
|
|
25855
|
-
return profile;
|
|
26074
|
+
function isRudderBinConflict(output) {
|
|
26075
|
+
const normalized = output.toLowerCase().replaceAll("\\", "/");
|
|
26076
|
+
return normalized.includes("eexist") && (normalized.includes(`/${CLI_BIN_NAME}`) || normalized.includes(`/${CLI_BIN_NAME}.cmd`) || normalized.includes(`/${CLI_BIN_NAME}.ps1`));
|
|
25856
26077
|
}
|
|
25857
|
-
var
|
|
25858
|
-
var
|
|
25859
|
-
"src/
|
|
26078
|
+
var CLI_NPM_PACKAGE_NAME, CLI_BIN_NAME;
|
|
26079
|
+
var init_install2 = __esm({
|
|
26080
|
+
"src/install.ts"() {
|
|
25860
26081
|
"use strict";
|
|
25861
|
-
|
|
25862
|
-
|
|
25863
|
-
|
|
25864
|
-
name: "dev",
|
|
25865
|
-
instanceId: "dev",
|
|
25866
|
-
port: 3100,
|
|
25867
|
-
embeddedPostgresPort: 54329,
|
|
25868
|
-
resettable: true,
|
|
25869
|
-
description: "Disposable local development instance"
|
|
25870
|
-
},
|
|
25871
|
-
prod_local: {
|
|
25872
|
-
name: "prod_local",
|
|
25873
|
-
instanceId: "default",
|
|
25874
|
-
port: 3200,
|
|
25875
|
-
embeddedPostgresPort: 54339,
|
|
25876
|
-
resettable: false,
|
|
25877
|
-
description: "Persistent local instance"
|
|
25878
|
-
},
|
|
25879
|
-
e2e: {
|
|
25880
|
-
name: "e2e",
|
|
25881
|
-
instanceId: "e2e",
|
|
25882
|
-
port: 3300,
|
|
25883
|
-
embeddedPostgresPort: 54349,
|
|
25884
|
-
resettable: true,
|
|
25885
|
-
description: "Isolated end-to-end test instance"
|
|
25886
|
-
}
|
|
25887
|
-
};
|
|
26082
|
+
init_npm_command();
|
|
26083
|
+
CLI_NPM_PACKAGE_NAME = "@rudderhq/cli";
|
|
26084
|
+
CLI_BIN_NAME = "rudder";
|
|
25888
26085
|
}
|
|
25889
26086
|
});
|
|
25890
26087
|
|
|
@@ -26003,7 +26200,7 @@ var init_run = __esm({
|
|
|
26003
26200
|
|
|
26004
26201
|
// src/commands/onboard.ts
|
|
26005
26202
|
import * as p14 from "@clack/prompts";
|
|
26006
|
-
import
|
|
26203
|
+
import path26 from "node:path";
|
|
26007
26204
|
import pc13 from "picocolors";
|
|
26008
26205
|
function parseBooleanFromEnv(rawValue) {
|
|
26009
26206
|
if (rawValue === void 0) return null;
|
|
@@ -26036,7 +26233,7 @@ function parseEnumFromEnv(rawValue, allowedValues) {
|
|
|
26036
26233
|
}
|
|
26037
26234
|
function resolvePathFromEnv(rawValue) {
|
|
26038
26235
|
if (!rawValue || rawValue.trim().length === 0) return null;
|
|
26039
|
-
return
|
|
26236
|
+
return path26.resolve(expandHomePrefix(rawValue.trim()));
|
|
26040
26237
|
}
|
|
26041
26238
|
function quickstartDefaultsFromEnv() {
|
|
26042
26239
|
const instanceId = resolveRudderInstanceId();
|
|
@@ -28823,42 +29020,42 @@ var RudderApiClient = class {
|
|
|
28823
29020
|
now: opts.now
|
|
28824
29021
|
});
|
|
28825
29022
|
}
|
|
28826
|
-
get(
|
|
28827
|
-
return this.request(
|
|
29023
|
+
get(path29, opts) {
|
|
29024
|
+
return this.request(path29, { method: "GET" }, opts);
|
|
28828
29025
|
}
|
|
28829
|
-
post(
|
|
28830
|
-
return this.request(
|
|
29026
|
+
post(path29, body, opts) {
|
|
29027
|
+
return this.request(path29, {
|
|
28831
29028
|
method: "POST",
|
|
28832
29029
|
body: body === void 0 ? void 0 : JSON.stringify(body)
|
|
28833
29030
|
}, opts);
|
|
28834
29031
|
}
|
|
28835
|
-
postForm(
|
|
28836
|
-
return this.request(
|
|
29032
|
+
postForm(path29, form, opts) {
|
|
29033
|
+
return this.request(path29, {
|
|
28837
29034
|
method: "POST",
|
|
28838
29035
|
body: form
|
|
28839
29036
|
}, opts);
|
|
28840
29037
|
}
|
|
28841
|
-
patch(
|
|
28842
|
-
return this.request(
|
|
29038
|
+
patch(path29, body, opts) {
|
|
29039
|
+
return this.request(path29, {
|
|
28843
29040
|
method: "PATCH",
|
|
28844
29041
|
body: body === void 0 ? void 0 : JSON.stringify(body)
|
|
28845
29042
|
}, opts);
|
|
28846
29043
|
}
|
|
28847
|
-
put(
|
|
28848
|
-
return this.request(
|
|
29044
|
+
put(path29, body, opts) {
|
|
29045
|
+
return this.request(path29, {
|
|
28849
29046
|
method: "PUT",
|
|
28850
29047
|
body: body === void 0 ? void 0 : JSON.stringify(body)
|
|
28851
29048
|
}, opts);
|
|
28852
29049
|
}
|
|
28853
|
-
delete(
|
|
28854
|
-
return this.request(
|
|
29050
|
+
delete(path29, opts) {
|
|
29051
|
+
return this.request(path29, { method: "DELETE" }, opts);
|
|
28855
29052
|
}
|
|
28856
29053
|
setApiKey(apiKey) {
|
|
28857
29054
|
this.apiKey = apiKey?.trim() || void 0;
|
|
28858
29055
|
}
|
|
28859
|
-
async request(
|
|
28860
|
-
const url = buildUrl(this.apiBase,
|
|
28861
|
-
const reservation = await this.issueTransportBudget.reserve(init.method,
|
|
29056
|
+
async request(path29, init, opts, hasRetriedAuth = false) {
|
|
29057
|
+
const url = buildUrl(this.apiBase, path29);
|
|
29058
|
+
const reservation = await this.issueTransportBudget.reserve(init.method, path29, init.body);
|
|
28862
29059
|
const headers = {
|
|
28863
29060
|
accept: "application/json",
|
|
28864
29061
|
...toStringRecord(init.headers)
|
|
@@ -28896,14 +29093,14 @@ var RudderApiClient = class {
|
|
|
28896
29093
|
const apiError = await toApiError(response);
|
|
28897
29094
|
if (!hasRetriedAuth && this.recoverAuth) {
|
|
28898
29095
|
const recoveredToken = await this.recoverAuth({
|
|
28899
|
-
path:
|
|
29096
|
+
path: path29,
|
|
28900
29097
|
method: String(init.method ?? "GET").toUpperCase(),
|
|
28901
29098
|
error: apiError
|
|
28902
29099
|
});
|
|
28903
29100
|
if (recoveredToken) {
|
|
28904
29101
|
await this.issueTransportBudget.succeed(reservation);
|
|
28905
29102
|
this.setApiKey(recoveredToken);
|
|
28906
|
-
return this.request(
|
|
29103
|
+
return this.request(path29, init, opts, true);
|
|
28907
29104
|
}
|
|
28908
29105
|
}
|
|
28909
29106
|
await this.issueTransportBudget.fail(reservation, apiError);
|
|
@@ -28924,8 +29121,8 @@ function shouldAttachAgentContext(method) {
|
|
|
28924
29121
|
const normalized = String(method ?? "GET").toUpperCase();
|
|
28925
29122
|
return normalized !== "GET" && normalized !== "HEAD";
|
|
28926
29123
|
}
|
|
28927
|
-
function buildUrl(apiBase,
|
|
28928
|
-
const normalizedPath =
|
|
29124
|
+
function buildUrl(apiBase, path29) {
|
|
29125
|
+
const normalizedPath = path29.startsWith("/") ? path29 : `/${path29}`;
|
|
28929
29126
|
const [pathname, query] = normalizedPath.split("?");
|
|
28930
29127
|
const url = new URL3(apiBase);
|
|
28931
29128
|
url.pathname = `${url.pathname.replace(/\/+$/, "")}${pathname}`;
|
|
@@ -31510,67 +31707,586 @@ function hasRunnableRudderOnPath(env) {
|
|
|
31510
31707
|
function rpcResult(id, result) {
|
|
31511
31708
|
return { jsonrpc: "2.0", id, result };
|
|
31512
31709
|
}
|
|
31513
|
-
function rpcError(id, code, message, data) {
|
|
31514
|
-
return { jsonrpc: "2.0", id, error: { code, message, ...data === void 0 ? {} : { data } } };
|
|
31710
|
+
function rpcError(id, code, message, data) {
|
|
31711
|
+
return { jsonrpc: "2.0", id, error: { code, message, ...data === void 0 ? {} : { data } } };
|
|
31712
|
+
}
|
|
31713
|
+
function errorMessage(err) {
|
|
31714
|
+
return err instanceof Error ? err.message : String(err);
|
|
31715
|
+
}
|
|
31716
|
+
function errorDetails(err) {
|
|
31717
|
+
if (!(err instanceof Error)) return void 0;
|
|
31718
|
+
if (err instanceof ApiRequestError) {
|
|
31719
|
+
const details = isRecord3(err.details) ? err.details : err.details === void 0 ? {} : { upstreamDetails: err.details };
|
|
31720
|
+
return {
|
|
31721
|
+
code: err.code ?? "api_request_error",
|
|
31722
|
+
status: err.status,
|
|
31723
|
+
...details
|
|
31724
|
+
};
|
|
31725
|
+
}
|
|
31726
|
+
const code = err.code;
|
|
31727
|
+
return code ? { code } : void 0;
|
|
31728
|
+
}
|
|
31729
|
+
function isRecord3(value) {
|
|
31730
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
31731
|
+
}
|
|
31732
|
+
|
|
31733
|
+
// src/commands/allowed-hostname.ts
|
|
31734
|
+
init_hostnames();
|
|
31735
|
+
init_store();
|
|
31736
|
+
import * as p from "@clack/prompts";
|
|
31737
|
+
import pc3 from "picocolors";
|
|
31738
|
+
async function addAllowedHostname(host, opts) {
|
|
31739
|
+
const configPath = resolveConfigPath(opts.config);
|
|
31740
|
+
const config = readConfig(opts.config);
|
|
31741
|
+
if (!config) {
|
|
31742
|
+
p.log.error(`No config found at ${configPath}. Run ${pc3.cyan("rudder onboard")} first.`);
|
|
31743
|
+
return;
|
|
31744
|
+
}
|
|
31745
|
+
const normalized = normalizeHostnameInput(host);
|
|
31746
|
+
const current = new Set((config.server.allowedHostnames ?? []).map((value) => value.trim().toLowerCase()).filter(Boolean));
|
|
31747
|
+
const existed = current.has(normalized);
|
|
31748
|
+
current.add(normalized);
|
|
31749
|
+
config.server.allowedHostnames = Array.from(current).sort();
|
|
31750
|
+
config.$meta.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
31751
|
+
config.$meta.source = "configure";
|
|
31752
|
+
writeConfig(config, opts.config);
|
|
31753
|
+
if (existed) {
|
|
31754
|
+
p.log.info(`Hostname ${pc3.cyan(normalized)} is already allowed.`);
|
|
31755
|
+
} else {
|
|
31756
|
+
p.log.success(`Added allowed hostname: ${pc3.cyan(normalized)}`);
|
|
31757
|
+
p.log.message(
|
|
31758
|
+
pc3.dim("Restart the Rudder server for this change to take effect.")
|
|
31759
|
+
);
|
|
31760
|
+
}
|
|
31761
|
+
if (!(config.server.deploymentMode === "authenticated" && config.server.exposure === "private")) {
|
|
31762
|
+
p.log.message(
|
|
31763
|
+
pc3.dim("Note: allowed hostnames are enforced only in authenticated/private mode.")
|
|
31764
|
+
);
|
|
31765
|
+
}
|
|
31766
|
+
}
|
|
31767
|
+
|
|
31768
|
+
// src/program.ts
|
|
31769
|
+
init_auth_bootstrap_ceo();
|
|
31770
|
+
|
|
31771
|
+
// src/commands/browser-app.ts
|
|
31772
|
+
import { spawn as spawn3, spawnSync as spawnSync3 } from "node:child_process";
|
|
31773
|
+
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
31774
|
+
import { closeSync, existsSync as existsSync4, mkdirSync, openSync, readFileSync as readFileSync2, rmdirSync, statSync as statSync2, unlinkSync, writeFileSync } from "node:fs";
|
|
31775
|
+
import { readFile as readFile3, rm as rm3, writeFile as writeFile2 } from "node:fs/promises";
|
|
31776
|
+
import { homedir, tmpdir } from "node:os";
|
|
31777
|
+
import path14 from "node:path";
|
|
31778
|
+
import { setTimeout as delay } from "node:timers/promises";
|
|
31779
|
+
|
|
31780
|
+
// src/config/data-dir.ts
|
|
31781
|
+
init_home();
|
|
31782
|
+
import path13 from "node:path";
|
|
31783
|
+
function applyDataDirOverride(options, support = {}) {
|
|
31784
|
+
const rawDataDir = options.dataDir?.trim();
|
|
31785
|
+
if (!rawDataDir) return null;
|
|
31786
|
+
const resolvedDataDir = path13.resolve(expandHomePrefix(rawDataDir));
|
|
31787
|
+
process.env.RUDDER_HOME = resolvedDataDir;
|
|
31788
|
+
if (support.hasConfigOption) {
|
|
31789
|
+
const hasConfigOverride = Boolean(options.config?.trim()) || Boolean(process.env.RUDDER_CONFIG?.trim());
|
|
31790
|
+
if (!hasConfigOverride) {
|
|
31791
|
+
const instanceId = resolveRudderInstanceId(options.instance);
|
|
31792
|
+
process.env.RUDDER_INSTANCE_ID = instanceId;
|
|
31793
|
+
process.env.RUDDER_CONFIG = resolveDefaultConfigPath(instanceId);
|
|
31794
|
+
}
|
|
31795
|
+
}
|
|
31796
|
+
if (support.hasContextOption) {
|
|
31797
|
+
const hasContextOverride = Boolean(options.context?.trim()) || Boolean(process.env.RUDDER_CONTEXT?.trim());
|
|
31798
|
+
if (!hasContextOverride) {
|
|
31799
|
+
process.env.RUDDER_CONTEXT = resolveDefaultContextPath();
|
|
31800
|
+
}
|
|
31801
|
+
}
|
|
31802
|
+
return resolvedDataDir;
|
|
31803
|
+
}
|
|
31804
|
+
|
|
31805
|
+
// src/commands/browser-app.ts
|
|
31806
|
+
init_home();
|
|
31807
|
+
init_local_env();
|
|
31808
|
+
init_server_entry();
|
|
31809
|
+
init_version();
|
|
31810
|
+
var SMART_APP_CONTROL_REGISTRY_KEY = String.raw`HKLM\SYSTEM\CurrentControlSet\Control\CI\Policy`;
|
|
31811
|
+
var SMART_APP_CONTROL_REGISTRY_VALUE = "VerifiedAndReputablePolicyState";
|
|
31812
|
+
var BROWSER_APP_READY_TIMEOUT_MS = 9e4;
|
|
31813
|
+
var RUNTIME_HEALTH_POLL_MS = 2e3;
|
|
31814
|
+
var DESKTOP_TAKEOVER_LEASE_DIR = "browser-app-desktop-takeover.lock";
|
|
31815
|
+
var DESKTOP_TAKEOVER_PARTIAL_LEASE_GRACE_MS = 3e4;
|
|
31816
|
+
function resolveBrowserAppRuntimeVersion(env = process.env) {
|
|
31817
|
+
const version = resolveCliVersion(import.meta.url, env);
|
|
31818
|
+
return version === "0.0.0" ? "latest" : version;
|
|
31819
|
+
}
|
|
31820
|
+
function parseSmartAppControlState(output) {
|
|
31821
|
+
const line = output.split(/\r?\n/).find((candidate) => candidate.toLowerCase().includes(SMART_APP_CONTROL_REGISTRY_VALUE.toLowerCase()));
|
|
31822
|
+
if (!line) return "unknown";
|
|
31823
|
+
const match = line.match(/REG_DWORD\s+0x([0-9a-f]+)/iu);
|
|
31824
|
+
if (!match) return "unknown";
|
|
31825
|
+
const value = Number.parseInt(match[1], 16);
|
|
31826
|
+
if (value === 0) return "off";
|
|
31827
|
+
if (value === 1) return "on";
|
|
31828
|
+
if (value === 2) return "evaluation";
|
|
31829
|
+
return "unknown";
|
|
31830
|
+
}
|
|
31831
|
+
function detectSmartAppControlState(platform = process.platform, spawnSyncImpl = spawnSync3) {
|
|
31832
|
+
if (platform !== "win32") return "unknown";
|
|
31833
|
+
const result = spawnSyncImpl("reg.exe", [
|
|
31834
|
+
"query",
|
|
31835
|
+
SMART_APP_CONTROL_REGISTRY_KEY,
|
|
31836
|
+
"/v",
|
|
31837
|
+
SMART_APP_CONTROL_REGISTRY_VALUE
|
|
31838
|
+
], {
|
|
31839
|
+
encoding: "utf8",
|
|
31840
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
31841
|
+
windowsHide: true
|
|
31842
|
+
});
|
|
31843
|
+
if (result.status !== 0 || typeof result.stdout !== "string") return "unknown";
|
|
31844
|
+
return parseSmartAppControlState(result.stdout);
|
|
31845
|
+
}
|
|
31846
|
+
function parseDesktopLaunchMode(value) {
|
|
31847
|
+
const normalized = value?.trim().toLowerCase() || "auto";
|
|
31848
|
+
if (normalized === "auto" || normalized === "native" || normalized === "browser") return normalized;
|
|
31849
|
+
throw new Error(`Desktop mode must be auto, native, or browser. Received ${value}.`);
|
|
31850
|
+
}
|
|
31851
|
+
function resolveDesktopLaunchMode(options = {}) {
|
|
31852
|
+
const requested = parseDesktopLaunchMode(options.requested);
|
|
31853
|
+
if (requested !== "auto") return requested;
|
|
31854
|
+
const platform = options.platform ?? process.platform;
|
|
31855
|
+
const state = options.smartAppControlState ?? detectSmartAppControlState(platform);
|
|
31856
|
+
return platform === "win32" && state === "on" ? "browser" : "native";
|
|
31857
|
+
}
|
|
31858
|
+
function resolveEdgeExecutable(env = process.env, pathExists3 = existsSync4) {
|
|
31859
|
+
const candidates = [
|
|
31860
|
+
env["PROGRAMFILES(X86)"] && path14.join(env["PROGRAMFILES(X86)"], "Microsoft", "Edge", "Application", "msedge.exe"),
|
|
31861
|
+
env.ProgramFiles && path14.join(env.ProgramFiles, "Microsoft", "Edge", "Application", "msedge.exe"),
|
|
31862
|
+
env.LOCALAPPDATA && path14.join(env.LOCALAPPDATA, "Microsoft", "Edge", "Application", "msedge.exe")
|
|
31863
|
+
].filter((candidate) => Boolean(candidate));
|
|
31864
|
+
return candidates.find(pathExists3) ?? null;
|
|
31865
|
+
}
|
|
31866
|
+
function buildEdgeBrowserAppArgs(boardUrl) {
|
|
31867
|
+
return [
|
|
31868
|
+
`--app=${boardUrl}`,
|
|
31869
|
+
"--start-maximized",
|
|
31870
|
+
"--no-first-run"
|
|
31871
|
+
];
|
|
31872
|
+
}
|
|
31873
|
+
function quoteWindowsArgument(value) {
|
|
31874
|
+
if (!/[\s"]/u.test(value)) return value;
|
|
31875
|
+
return `"${value.replace(/(\\*)"/gu, '$1$1\\"').replace(/(\\+)$/u, "$1$1")}"`;
|
|
31876
|
+
}
|
|
31877
|
+
function quotePowerShellString(value) {
|
|
31878
|
+
return `'${value.replaceAll("'", "''")}'`;
|
|
31879
|
+
}
|
|
31880
|
+
function buildWindowsBrowserAppShortcutScript(options) {
|
|
31881
|
+
const args = [
|
|
31882
|
+
options.cliEntryPath,
|
|
31883
|
+
"--local-env",
|
|
31884
|
+
options.localEnv,
|
|
31885
|
+
"browser-app",
|
|
31886
|
+
"--data-dir",
|
|
31887
|
+
options.dataDir,
|
|
31888
|
+
"--runtime-version",
|
|
31889
|
+
options.runtimeVersion
|
|
31890
|
+
].map(quoteWindowsArgument).join(" ");
|
|
31891
|
+
return [
|
|
31892
|
+
"$shell = New-Object -ComObject WScript.Shell",
|
|
31893
|
+
`$shortcut = $shell.CreateShortcut(${quotePowerShellString(options.shortcutPath)})`,
|
|
31894
|
+
`$shortcut.TargetPath = ${quotePowerShellString(options.nodePath)}`,
|
|
31895
|
+
`$shortcut.Arguments = ${quotePowerShellString(args)}`,
|
|
31896
|
+
`$shortcut.WorkingDirectory = ${quotePowerShellString(options.workingDirectory)}`,
|
|
31897
|
+
"$shortcut.WindowStyle = 7",
|
|
31898
|
+
...options.iconPath ? [`$shortcut.IconLocation = ${quotePowerShellString(options.iconPath)}`] : [],
|
|
31899
|
+
"$shortcut.Save()"
|
|
31900
|
+
].join("; ");
|
|
31901
|
+
}
|
|
31902
|
+
function createWindowsBrowserAppShortcut(options) {
|
|
31903
|
+
const env = options.env ?? process.env;
|
|
31904
|
+
const appData = env.APPDATA?.trim() || path14.join(homedir(), "AppData", "Roaming");
|
|
31905
|
+
const shortcutPath = path14.join(appData, "Microsoft", "Windows", "Start Menu", "Programs", "Rudder.lnk");
|
|
31906
|
+
mkdirSync(path14.dirname(shortcutPath), { recursive: true });
|
|
31907
|
+
const result = (options.spawnSyncImpl ?? spawnSync3)("powershell.exe", [
|
|
31908
|
+
"-NoProfile",
|
|
31909
|
+
"-Command",
|
|
31910
|
+
buildWindowsBrowserAppShortcutScript({
|
|
31911
|
+
shortcutPath,
|
|
31912
|
+
nodePath: options.nodePath,
|
|
31913
|
+
cliEntryPath: options.cliEntryPath,
|
|
31914
|
+
localEnv: options.localEnv,
|
|
31915
|
+
dataDir: path14.resolve(options.dataDir),
|
|
31916
|
+
runtimeVersion: options.runtimeVersion,
|
|
31917
|
+
workingDirectory: options.workingDirectory,
|
|
31918
|
+
iconPath: options.iconPath
|
|
31919
|
+
})
|
|
31920
|
+
], { stdio: "ignore", windowsHide: true });
|
|
31921
|
+
if (result.status !== 0) throw new Error("Could not create the Windows Rudder browser-app shortcut.");
|
|
31922
|
+
return shortcutPath;
|
|
31923
|
+
}
|
|
31924
|
+
function launchBrowserAppWindow(boardUrl, options = {}) {
|
|
31925
|
+
const env = options.env ?? process.env;
|
|
31926
|
+
const spawnImpl = options.spawnImpl ?? spawn3;
|
|
31927
|
+
const edge = resolveEdgeExecutable(env, options.pathExists);
|
|
31928
|
+
if (edge) {
|
|
31929
|
+
spawnImpl(edge, buildEdgeBrowserAppArgs(boardUrl), {
|
|
31930
|
+
detached: true,
|
|
31931
|
+
stdio: "ignore",
|
|
31932
|
+
windowsHide: false
|
|
31933
|
+
}).unref();
|
|
31934
|
+
return "edge";
|
|
31935
|
+
}
|
|
31936
|
+
spawnImpl("cmd.exe", ["/c", "start", "", boardUrl], {
|
|
31937
|
+
detached: true,
|
|
31938
|
+
stdio: "ignore",
|
|
31939
|
+
windowsHide: true
|
|
31940
|
+
}).unref();
|
|
31941
|
+
return "default";
|
|
31942
|
+
}
|
|
31943
|
+
function terminateDetachedBrowserAppProcess(child, options = {}) {
|
|
31944
|
+
const pid = child.pid;
|
|
31945
|
+
if (!Number.isSafeInteger(pid) || !pid || pid <= 0) {
|
|
31946
|
+
child.kill?.("SIGKILL");
|
|
31947
|
+
return;
|
|
31948
|
+
}
|
|
31949
|
+
if ((options.platform ?? process.platform) === "win32") {
|
|
31950
|
+
(options.spawnSyncImpl ?? spawnSync3)("taskkill.exe", ["/PID", String(pid), "/T", "/F"], {
|
|
31951
|
+
stdio: "ignore",
|
|
31952
|
+
windowsHide: true
|
|
31953
|
+
});
|
|
31954
|
+
return;
|
|
31955
|
+
}
|
|
31956
|
+
const processKill = options.processKill ?? ((targetPid, signal) => {
|
|
31957
|
+
process.kill(targetPid, signal);
|
|
31958
|
+
});
|
|
31959
|
+
try {
|
|
31960
|
+
processKill(-pid, "SIGKILL");
|
|
31961
|
+
} catch {
|
|
31962
|
+
try {
|
|
31963
|
+
processKill(pid, "SIGKILL");
|
|
31964
|
+
} catch {
|
|
31965
|
+
}
|
|
31966
|
+
}
|
|
31967
|
+
child.kill?.("SIGKILL");
|
|
31968
|
+
}
|
|
31969
|
+
function applyBrowserAppEnvironment(options = {}) {
|
|
31970
|
+
applyLocalEnvProfile(options);
|
|
31971
|
+
applyDataDirOverride(options);
|
|
31972
|
+
const profile = resolveActiveLocalEnvProfile() ?? applyLocalEnvProfile({ localEnv: "prod_local" });
|
|
31973
|
+
if (!profile) throw new Error("Rudder browser-app requires a local environment profile.");
|
|
31974
|
+
process.env.RUDDER_LOCAL_ENV = profile.name;
|
|
31975
|
+
process.env.RUDDER_INSTANCE_ID = profile.instanceId;
|
|
31976
|
+
process.env.PORT = String(profile.port);
|
|
31977
|
+
process.env.RUDDER_EMBEDDED_POSTGRES_PORT = String(profile.embeddedPostgresPort);
|
|
31978
|
+
process.env.RUDDER_DEPLOYMENT_MODE = "local_trusted";
|
|
31979
|
+
process.env.RUDDER_DEPLOYMENT_EXPOSURE = "private";
|
|
31980
|
+
process.env.HOST = "127.0.0.1";
|
|
31981
|
+
process.env.SERVE_UI = "true";
|
|
31982
|
+
process.env.RUDDER_UI_DEV_MIDDLEWARE = "false";
|
|
31983
|
+
process.env.RUDDER_OPEN_ON_LISTEN = "false";
|
|
31984
|
+
}
|
|
31985
|
+
async function writeReadyRecord(readyFile, record) {
|
|
31986
|
+
if (!readyFile) return;
|
|
31987
|
+
await writeFile2(readyFile, `${JSON.stringify(record)}
|
|
31988
|
+
`, "utf8");
|
|
31989
|
+
}
|
|
31990
|
+
function boardUrlFromServer(startedServer) {
|
|
31991
|
+
return startedServer.apiUrl.replace(/\/api\/?$/u, "");
|
|
31992
|
+
}
|
|
31993
|
+
async function waitForShutdownSignal() {
|
|
31994
|
+
await new Promise((resolve) => {
|
|
31995
|
+
const finish = () => resolve();
|
|
31996
|
+
process.once("SIGINT", finish);
|
|
31997
|
+
process.once("SIGTERM", finish);
|
|
31998
|
+
});
|
|
31999
|
+
}
|
|
32000
|
+
async function runtimeStillHealthy(apiUrl) {
|
|
32001
|
+
try {
|
|
32002
|
+
const response = await fetch(new URL("/api/health", apiUrl), {
|
|
32003
|
+
signal: AbortSignal.timeout(1e3),
|
|
32004
|
+
headers: { Accept: "application/json" }
|
|
32005
|
+
});
|
|
32006
|
+
return response.ok;
|
|
32007
|
+
} catch {
|
|
32008
|
+
return false;
|
|
32009
|
+
}
|
|
32010
|
+
}
|
|
32011
|
+
function processIsAlive(pid) {
|
|
32012
|
+
if (!Number.isSafeInteger(pid) || pid <= 0) return false;
|
|
32013
|
+
try {
|
|
32014
|
+
process.kill(pid, 0);
|
|
32015
|
+
return true;
|
|
32016
|
+
} catch (error) {
|
|
32017
|
+
return error.code === "EPERM";
|
|
32018
|
+
}
|
|
32019
|
+
}
|
|
32020
|
+
function acquireDesktopTakeoverLease(instanceId) {
|
|
32021
|
+
const instanceRoot = describeLocalInstancePaths(instanceId).instanceRoot;
|
|
32022
|
+
mkdirSync(instanceRoot, { recursive: true });
|
|
32023
|
+
const leaseDir = path14.join(instanceRoot, DESKTOP_TAKEOVER_LEASE_DIR);
|
|
32024
|
+
const leaseRecordPath = path14.join(leaseDir, "owner.json");
|
|
32025
|
+
const token = randomUUID2();
|
|
32026
|
+
const processStartedAt = Math.round(Date.now() - process.uptime() * 1e3);
|
|
32027
|
+
for (let attempt = 0; attempt < 2; attempt += 1) {
|
|
32028
|
+
try {
|
|
32029
|
+
mkdirSync(leaseDir);
|
|
32030
|
+
try {
|
|
32031
|
+
writeFileSync(
|
|
32032
|
+
leaseRecordPath,
|
|
32033
|
+
`${JSON.stringify({ pid: process.pid, processStartedAt, token })}
|
|
32034
|
+
`,
|
|
32035
|
+
{ encoding: "utf8", flag: "wx" }
|
|
32036
|
+
);
|
|
32037
|
+
} catch (error) {
|
|
32038
|
+
try {
|
|
32039
|
+
rmdirSync(leaseDir);
|
|
32040
|
+
} catch {
|
|
32041
|
+
}
|
|
32042
|
+
throw error;
|
|
32043
|
+
}
|
|
32044
|
+
return () => {
|
|
32045
|
+
try {
|
|
32046
|
+
const current = JSON.parse(readFileSync2(leaseRecordPath, "utf8"));
|
|
32047
|
+
if (current.pid !== process.pid || current.token !== token) return;
|
|
32048
|
+
unlinkSync(leaseRecordPath);
|
|
32049
|
+
rmdirSync(leaseDir);
|
|
32050
|
+
} catch {
|
|
32051
|
+
}
|
|
32052
|
+
};
|
|
32053
|
+
} catch (error) {
|
|
32054
|
+
if (error.code !== "EEXIST") throw error;
|
|
32055
|
+
let existingPid = null;
|
|
32056
|
+
let existingProcessStartedAt = null;
|
|
32057
|
+
try {
|
|
32058
|
+
const existing = JSON.parse(readFileSync2(leaseRecordPath, "utf8"));
|
|
32059
|
+
existingPid = typeof existing.pid === "number" ? existing.pid : null;
|
|
32060
|
+
existingProcessStartedAt = typeof existing.processStartedAt === "number" ? existing.processStartedAt : null;
|
|
32061
|
+
} catch {
|
|
32062
|
+
let ageMs;
|
|
32063
|
+
try {
|
|
32064
|
+
ageMs = Date.now() - statSync2(leaseDir).mtimeMs;
|
|
32065
|
+
} catch (statError) {
|
|
32066
|
+
if (statError.code === "ENOENT") continue;
|
|
32067
|
+
throw statError;
|
|
32068
|
+
}
|
|
32069
|
+
if (ageMs < DESKTOP_TAKEOVER_PARTIAL_LEASE_GRACE_MS) return null;
|
|
32070
|
+
}
|
|
32071
|
+
const sameProcess = existingPid === process.pid && existingProcessStartedAt !== null && Math.abs(existingProcessStartedAt - processStartedAt) < 2e3;
|
|
32072
|
+
if (sameProcess || existingPid !== null && existingPid !== process.pid && processIsAlive(existingPid)) {
|
|
32073
|
+
return null;
|
|
32074
|
+
}
|
|
32075
|
+
try {
|
|
32076
|
+
unlinkSync(leaseRecordPath);
|
|
32077
|
+
} catch (unlinkError) {
|
|
32078
|
+
if (unlinkError.code !== "ENOENT") return null;
|
|
32079
|
+
}
|
|
32080
|
+
try {
|
|
32081
|
+
rmdirSync(leaseDir);
|
|
32082
|
+
} catch {
|
|
32083
|
+
return null;
|
|
32084
|
+
}
|
|
32085
|
+
}
|
|
32086
|
+
}
|
|
32087
|
+
return null;
|
|
32088
|
+
}
|
|
32089
|
+
async function runBrowserAppChild(options) {
|
|
32090
|
+
applyBrowserAppEnvironment(options);
|
|
32091
|
+
const runtimeVersion = options.runtimeVersion?.trim() || resolveBrowserAppRuntimeVersion();
|
|
32092
|
+
let startedServer = null;
|
|
32093
|
+
let readyWritten = false;
|
|
32094
|
+
let releaseDesktopTakeoverLease = null;
|
|
32095
|
+
const runtimePackageDir = process.env.RUDDER_BROWSER_APP_RUNTIME_PACKAGE_DIR?.trim();
|
|
32096
|
+
try {
|
|
32097
|
+
while (true) {
|
|
32098
|
+
startedServer = await startManagedServerFromRuntime({
|
|
32099
|
+
version: runtimeVersion,
|
|
32100
|
+
...runtimePackageDir ? { runtimePackageDir } : {},
|
|
32101
|
+
// A native Desktop runtime owns the process while it is alive. Never
|
|
32102
|
+
// terminate it just to replace a mismatched browser-app version.
|
|
32103
|
+
takeoverOnVersionMismatch: false
|
|
32104
|
+
});
|
|
32105
|
+
const boardUrl = boardUrlFromServer(startedServer);
|
|
32106
|
+
if (!readyWritten) {
|
|
32107
|
+
await writeReadyRecord(options.readyFile, {
|
|
32108
|
+
ok: true,
|
|
32109
|
+
apiUrl: startedServer.apiUrl,
|
|
32110
|
+
boardUrl,
|
|
32111
|
+
runtimeMode: startedServer.runtime.mode
|
|
32112
|
+
});
|
|
32113
|
+
readyWritten = true;
|
|
32114
|
+
if (options.open !== false) launchBrowserAppWindow(boardUrl);
|
|
32115
|
+
}
|
|
32116
|
+
if (startedServer.runtime.mode === "owned") {
|
|
32117
|
+
releaseDesktopTakeoverLease?.();
|
|
32118
|
+
releaseDesktopTakeoverLease = null;
|
|
32119
|
+
await waitForShutdownSignal();
|
|
32120
|
+
await startedServer.dispose();
|
|
32121
|
+
return;
|
|
32122
|
+
}
|
|
32123
|
+
if (startedServer.runtime.ownerKind !== "desktop") return;
|
|
32124
|
+
releaseDesktopTakeoverLease ??= acquireDesktopTakeoverLease(startedServer.runtime.instanceId);
|
|
32125
|
+
if (!releaseDesktopTakeoverLease) return;
|
|
32126
|
+
while (await runtimeStillHealthy(startedServer.apiUrl)) {
|
|
32127
|
+
await delay(RUNTIME_HEALTH_POLL_MS);
|
|
32128
|
+
}
|
|
32129
|
+
await delay(500);
|
|
32130
|
+
}
|
|
32131
|
+
} catch (error) {
|
|
32132
|
+
if (!readyWritten) {
|
|
32133
|
+
await writeReadyRecord(options.readyFile, {
|
|
32134
|
+
ok: false,
|
|
32135
|
+
error: error instanceof Error ? error.message : String(error)
|
|
32136
|
+
});
|
|
32137
|
+
}
|
|
32138
|
+
throw error;
|
|
32139
|
+
} finally {
|
|
32140
|
+
releaseDesktopTakeoverLease?.();
|
|
32141
|
+
}
|
|
32142
|
+
}
|
|
32143
|
+
async function readReadyRecord(readyFile) {
|
|
32144
|
+
return JSON.parse(await readFile3(readyFile, "utf8"));
|
|
31515
32145
|
}
|
|
31516
|
-
function
|
|
31517
|
-
|
|
32146
|
+
async function waitForReadyRecord(options) {
|
|
32147
|
+
const timeoutMs = options.timeoutMs ?? BROWSER_APP_READY_TIMEOUT_MS;
|
|
32148
|
+
const startedAt = Date.now();
|
|
32149
|
+
const childState = { stopped: null };
|
|
32150
|
+
const onExit = (code, signal) => {
|
|
32151
|
+
childState.stopped = { code, signal };
|
|
32152
|
+
};
|
|
32153
|
+
const onError = (error) => {
|
|
32154
|
+
childState.stopped = { code: null, signal: null, error };
|
|
32155
|
+
};
|
|
32156
|
+
options.child.once("exit", onExit);
|
|
32157
|
+
options.child.once("error", onError);
|
|
32158
|
+
try {
|
|
32159
|
+
while (Date.now() - startedAt < timeoutMs) {
|
|
32160
|
+
try {
|
|
32161
|
+
return await readReadyRecord(options.readyFile);
|
|
32162
|
+
} catch {
|
|
32163
|
+
const stopped = childState.stopped;
|
|
32164
|
+
if (stopped) {
|
|
32165
|
+
if (stopped.error) {
|
|
32166
|
+
throw new Error(`Rudder browser-app process failed before it was ready. See ${options.logPath}.`, {
|
|
32167
|
+
cause: stopped.error
|
|
32168
|
+
});
|
|
32169
|
+
}
|
|
32170
|
+
const outcome = stopped.signal ? `signal ${stopped.signal}` : `exit code ${stopped.code ?? "unknown"}`;
|
|
32171
|
+
throw new Error(
|
|
32172
|
+
`Rudder browser-app process stopped before it was ready (${outcome}). See ${options.logPath}.`
|
|
32173
|
+
);
|
|
32174
|
+
}
|
|
32175
|
+
await delay(200);
|
|
32176
|
+
}
|
|
32177
|
+
}
|
|
32178
|
+
throw new Error("Rudder browser-app did not become ready in time.");
|
|
32179
|
+
} finally {
|
|
32180
|
+
options.child.off("exit", onExit);
|
|
32181
|
+
options.child.off("error", onError);
|
|
32182
|
+
}
|
|
31518
32183
|
}
|
|
31519
|
-
function
|
|
31520
|
-
|
|
31521
|
-
|
|
31522
|
-
|
|
32184
|
+
async function launchDetachedBrowserApp(options) {
|
|
32185
|
+
applyLocalEnvProfile(options);
|
|
32186
|
+
applyDataDirOverride(options);
|
|
32187
|
+
const localProfile = resolveActiveLocalEnvProfile() ?? applyLocalEnvProfile({ localEnv: "prod_local" });
|
|
32188
|
+
if (!localProfile) throw new Error("Rudder browser-app requires a local environment profile.");
|
|
32189
|
+
const dataDir = resolveRudderHomeDir();
|
|
32190
|
+
const instanceId = resolveRudderInstanceId(localProfile.instanceId);
|
|
32191
|
+
const paths = describeLocalInstancePaths(instanceId);
|
|
32192
|
+
const logDir = path14.join(paths.instanceRoot, "logs");
|
|
32193
|
+
mkdirSync(logDir, { recursive: true });
|
|
32194
|
+
const logPath = path14.join(logDir, "browser-app.log");
|
|
32195
|
+
const readyFile = path14.join(tmpdir(), `rudder-browser-app-${process.pid}-${randomUUID2()}.json`);
|
|
32196
|
+
const logFd = openSync(logPath, "a");
|
|
32197
|
+
const spawnImpl = options.spawnImpl ?? spawn3;
|
|
32198
|
+
let child = null;
|
|
32199
|
+
let launchSucceeded = false;
|
|
32200
|
+
try {
|
|
32201
|
+
const spawnedChild = spawnImpl(options.nodePath ?? process.execPath, [
|
|
32202
|
+
options.cliEntryPath,
|
|
32203
|
+
"--local-env",
|
|
32204
|
+
localProfile.name,
|
|
32205
|
+
"browser-app",
|
|
32206
|
+
"--data-dir",
|
|
32207
|
+
dataDir,
|
|
32208
|
+
"--child",
|
|
32209
|
+
"--no-open",
|
|
32210
|
+
"--ready-file",
|
|
32211
|
+
readyFile,
|
|
32212
|
+
"--runtime-version",
|
|
32213
|
+
options.runtimeVersion
|
|
32214
|
+
], {
|
|
32215
|
+
detached: true,
|
|
32216
|
+
windowsHide: true,
|
|
32217
|
+
stdio: ["ignore", logFd, logFd]
|
|
32218
|
+
});
|
|
32219
|
+
child = spawnedChild;
|
|
32220
|
+
await new Promise((resolve, reject) => {
|
|
32221
|
+
spawnedChild.once("spawn", resolve);
|
|
32222
|
+
spawnedChild.once("error", reject);
|
|
32223
|
+
});
|
|
32224
|
+
spawnedChild.unref();
|
|
32225
|
+
} catch (error) {
|
|
32226
|
+
if (child) {
|
|
32227
|
+
terminateDetachedBrowserAppProcess(child, {
|
|
32228
|
+
platform: options.platform,
|
|
32229
|
+
processKill: options.processKill,
|
|
32230
|
+
spawnSyncImpl: options.spawnSyncImpl
|
|
32231
|
+
});
|
|
32232
|
+
}
|
|
32233
|
+
throw error;
|
|
32234
|
+
} finally {
|
|
32235
|
+
closeSync(logFd);
|
|
32236
|
+
}
|
|
32237
|
+
try {
|
|
32238
|
+
const ready = await waitForReadyRecord({
|
|
32239
|
+
readyFile,
|
|
32240
|
+
child,
|
|
32241
|
+
logPath,
|
|
32242
|
+
timeoutMs: options.readyTimeoutMs
|
|
32243
|
+
});
|
|
32244
|
+
if (!ready.ok || !ready.apiUrl || !ready.boardUrl || !ready.runtimeMode) {
|
|
32245
|
+
throw new Error(ready.error || `Rudder browser-app failed to start. See ${logPath}.`);
|
|
32246
|
+
}
|
|
32247
|
+
const browser = options.open === false ? null : launchBrowserAppWindow(ready.boardUrl);
|
|
32248
|
+
launchSucceeded = true;
|
|
31523
32249
|
return {
|
|
31524
|
-
|
|
31525
|
-
|
|
31526
|
-
|
|
32250
|
+
apiUrl: ready.apiUrl,
|
|
32251
|
+
boardUrl: ready.boardUrl,
|
|
32252
|
+
browser,
|
|
32253
|
+
logPath,
|
|
32254
|
+
runtimeMode: ready.runtimeMode
|
|
31527
32255
|
};
|
|
32256
|
+
} finally {
|
|
32257
|
+
await rm3(readyFile, { force: true });
|
|
32258
|
+
if (!launchSucceeded && child) {
|
|
32259
|
+
terminateDetachedBrowserAppProcess(child, {
|
|
32260
|
+
platform: options.platform,
|
|
32261
|
+
processKill: options.processKill,
|
|
32262
|
+
spawnSyncImpl: options.spawnSyncImpl
|
|
32263
|
+
});
|
|
32264
|
+
}
|
|
31528
32265
|
}
|
|
31529
|
-
const code = err.code;
|
|
31530
|
-
return code ? { code } : void 0;
|
|
31531
|
-
}
|
|
31532
|
-
function isRecord3(value) {
|
|
31533
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
31534
32266
|
}
|
|
31535
|
-
|
|
31536
|
-
|
|
31537
|
-
|
|
31538
|
-
init_store();
|
|
31539
|
-
import * as p from "@clack/prompts";
|
|
31540
|
-
import pc3 from "picocolors";
|
|
31541
|
-
async function addAllowedHostname(host, opts) {
|
|
31542
|
-
const configPath = resolveConfigPath(opts.config);
|
|
31543
|
-
const config = readConfig(opts.config);
|
|
31544
|
-
if (!config) {
|
|
31545
|
-
p.log.error(`No config found at ${configPath}. Run ${pc3.cyan("rudder onboard")} first.`);
|
|
31546
|
-
return;
|
|
31547
|
-
}
|
|
31548
|
-
const normalized = normalizeHostnameInput(host);
|
|
31549
|
-
const current = new Set((config.server.allowedHostnames ?? []).map((value) => value.trim().toLowerCase()).filter(Boolean));
|
|
31550
|
-
const existed = current.has(normalized);
|
|
31551
|
-
current.add(normalized);
|
|
31552
|
-
config.server.allowedHostnames = Array.from(current).sort();
|
|
31553
|
-
config.$meta.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
31554
|
-
config.$meta.source = "configure";
|
|
31555
|
-
writeConfig(config, opts.config);
|
|
31556
|
-
if (existed) {
|
|
31557
|
-
p.log.info(`Hostname ${pc3.cyan(normalized)} is already allowed.`);
|
|
31558
|
-
} else {
|
|
31559
|
-
p.log.success(`Added allowed hostname: ${pc3.cyan(normalized)}`);
|
|
31560
|
-
p.log.message(
|
|
31561
|
-
pc3.dim("Restart the Rudder server for this change to take effect.")
|
|
31562
|
-
);
|
|
32267
|
+
async function browserAppCommand(options) {
|
|
32268
|
+
if (process.platform !== "win32") {
|
|
32269
|
+
throw new Error("Rudder browser-app compatibility mode is currently available on Windows only.");
|
|
31563
32270
|
}
|
|
31564
|
-
|
|
31565
|
-
|
|
31566
|
-
|
|
31567
|
-
|
|
32271
|
+
const runtimeVersion = options.runtimeVersion?.trim() || resolveBrowserAppRuntimeVersion();
|
|
32272
|
+
if (options.child) {
|
|
32273
|
+
await runBrowserAppChild({ ...options, runtimeVersion });
|
|
32274
|
+
return;
|
|
31568
32275
|
}
|
|
32276
|
+
const result = await launchDetachedBrowserApp({
|
|
32277
|
+
cliEntryPath: process.argv[1],
|
|
32278
|
+
localEnv: options.localEnv,
|
|
32279
|
+
dataDir: options.dataDir,
|
|
32280
|
+
runtimeVersion,
|
|
32281
|
+
open: options.open !== false
|
|
32282
|
+
});
|
|
32283
|
+
process.stdout.write(
|
|
32284
|
+
options.open === false ? `Rudder browser-app runtime is ready at ${result.boardUrl} (${result.runtimeMode})
|
|
32285
|
+
` : `Rudder browser app opened at ${result.boardUrl} (${result.runtimeMode})
|
|
32286
|
+
`
|
|
32287
|
+
);
|
|
31569
32288
|
}
|
|
31570
32289
|
|
|
31571
|
-
// src/program.ts
|
|
31572
|
-
init_auth_bootstrap_ceo();
|
|
31573
|
-
|
|
31574
32290
|
// src/commands/client/activity.ts
|
|
31575
32291
|
function registerActivityCommands(program) {
|
|
31576
32292
|
const activity = program.command("activity").description("Activity log operations");
|
|
@@ -31583,8 +32299,8 @@ function registerActivityCommands(program) {
|
|
|
31583
32299
|
if (opts.entityType) params.set("entityType", opts.entityType);
|
|
31584
32300
|
if (opts.entityId) params.set("entityId", opts.entityId);
|
|
31585
32301
|
const query = params.toString();
|
|
31586
|
-
const
|
|
31587
|
-
const rows = await ctx.api.get(
|
|
32302
|
+
const path29 = `/api/orgs/${ctx.orgId}/activity${query ? `?${query}` : ""}`;
|
|
32303
|
+
const rows = await ctx.api.get(path29) ?? [];
|
|
31588
32304
|
if (ctx.json) {
|
|
31589
32305
|
printOutput(rows, { json: true });
|
|
31590
32306
|
return;
|
|
@@ -31616,7 +32332,7 @@ function registerActivityCommands(program) {
|
|
|
31616
32332
|
|
|
31617
32333
|
// ../packages/agent-runtime-utils/dist/server-utils.cli.js
|
|
31618
32334
|
import { promises as fs9 } from "node:fs";
|
|
31619
|
-
import
|
|
32335
|
+
import path15 from "node:path";
|
|
31620
32336
|
|
|
31621
32337
|
// ../packages/agent-runtime-utils/dist/native-process-runner.js
|
|
31622
32338
|
init_dist2();
|
|
@@ -32122,8 +32838,8 @@ var RUDDER_AGENT_HEARTBEAT_INSTRUCTION = [
|
|
|
32122
32838
|
// ../packages/agent-runtime-utils/dist/server-utils.cli.js
|
|
32123
32839
|
async function resolveRudderSkillsDir(moduleDir, additionalCandidates = []) {
|
|
32124
32840
|
const candidates = [
|
|
32125
|
-
...RUDDER_SKILL_ROOT_RELATIVE_CANDIDATES.map((relativePath) =>
|
|
32126
|
-
...additionalCandidates.map((candidate) =>
|
|
32841
|
+
...RUDDER_SKILL_ROOT_RELATIVE_CANDIDATES.map((relativePath) => path15.resolve(moduleDir, relativePath)),
|
|
32842
|
+
...additionalCandidates.map((candidate) => path15.resolve(candidate))
|
|
32127
32843
|
];
|
|
32128
32844
|
const seenRoots = /* @__PURE__ */ new Set();
|
|
32129
32845
|
for (const root of candidates) {
|
|
@@ -32140,26 +32856,26 @@ async function removeMaintainerOnlySkillSymlinks(skillsHome, allowedSkillNames)
|
|
|
32140
32856
|
return removeUnselectedRudderSkillSymlinks(skillsHome, allowedSkillNames);
|
|
32141
32857
|
}
|
|
32142
32858
|
async function readRudderMaterializedSkillSource(target) {
|
|
32143
|
-
const manifestPath =
|
|
32859
|
+
const manifestPath = path15.join(target, ".rudder", "materialized-skill.json");
|
|
32144
32860
|
const raw = await fs9.readFile(manifestPath, "utf8").catch(() => null);
|
|
32145
32861
|
if (!raw)
|
|
32146
32862
|
return null;
|
|
32147
32863
|
try {
|
|
32148
32864
|
const parsed = parseObject(JSON.parse(raw));
|
|
32149
32865
|
const sourcePath = asString(parsed.sourcePath, "").trim();
|
|
32150
|
-
return sourcePath.length > 0 ?
|
|
32866
|
+
return sourcePath.length > 0 ? path15.resolve(sourcePath) : null;
|
|
32151
32867
|
} catch {
|
|
32152
32868
|
return null;
|
|
32153
32869
|
}
|
|
32154
32870
|
}
|
|
32155
32871
|
async function removeUnselectedRudderSkillSymlinks(skillsHome, allowedSkillNames, knownSkillSources = []) {
|
|
32156
32872
|
const allowed = new Set(Array.from(allowedSkillNames));
|
|
32157
|
-
const knownSources = new Set(Array.from(knownSkillSources).map((value) => value.trim()).filter(Boolean).map((value) =>
|
|
32873
|
+
const knownSources = new Set(Array.from(knownSkillSources).map((value) => value.trim()).filter(Boolean).map((value) => path15.resolve(value)));
|
|
32158
32874
|
try {
|
|
32159
32875
|
const entries = await fs9.readdir(skillsHome, { withFileTypes: true });
|
|
32160
32876
|
const removed = [];
|
|
32161
32877
|
for (const entry of entries) {
|
|
32162
|
-
const target =
|
|
32878
|
+
const target = path15.join(skillsHome, entry.name);
|
|
32163
32879
|
const existing = await fs9.lstat(target).catch(() => null);
|
|
32164
32880
|
if (!existing)
|
|
32165
32881
|
continue;
|
|
@@ -32168,8 +32884,8 @@ async function removeUnselectedRudderSkillSymlinks(skillsHome, allowedSkillNames
|
|
|
32168
32884
|
const linkedPath = await fs9.readlink(target).catch(() => null);
|
|
32169
32885
|
if (!linkedPath)
|
|
32170
32886
|
continue;
|
|
32171
|
-
const resolvedLinkedPath =
|
|
32172
|
-
isRudderManagedSkill = knownSources.has(
|
|
32887
|
+
const resolvedLinkedPath = path15.isAbsolute(linkedPath) ? linkedPath : path15.resolve(path15.dirname(target), linkedPath);
|
|
32888
|
+
isRudderManagedSkill = knownSources.has(path15.resolve(resolvedLinkedPath)) || isMaintainerOnlySkillTarget(linkedPath) || isMaintainerOnlySkillTarget(resolvedLinkedPath);
|
|
32173
32889
|
} else if (existing.isDirectory()) {
|
|
32174
32890
|
const materializedSource = await readRudderMaterializedSkillSource(target);
|
|
32175
32891
|
isRudderManagedSkill = materializedSource !== null && knownSources.has(materializedSource);
|
|
@@ -32191,7 +32907,7 @@ async function removeUnselectedRudderSkillSymlinks(skillsHome, allowedSkillNames
|
|
|
32191
32907
|
init_dist2();
|
|
32192
32908
|
import fs10 from "node:fs/promises";
|
|
32193
32909
|
import os4 from "node:os";
|
|
32194
|
-
import
|
|
32910
|
+
import path16 from "node:path";
|
|
32195
32911
|
import { fileURLToPath as fileURLToPath6 } from "node:url";
|
|
32196
32912
|
|
|
32197
32913
|
// src/commands/client/help.ts
|
|
@@ -32215,16 +32931,16 @@ function formatHelpExample(example) {
|
|
|
32215
32931
|
}
|
|
32216
32932
|
|
|
32217
32933
|
// src/commands/client/agent.ts
|
|
32218
|
-
var __moduleDir =
|
|
32934
|
+
var __moduleDir = path16.dirname(fileURLToPath6(import.meta.url));
|
|
32219
32935
|
function codexSkillsHome() {
|
|
32220
32936
|
const fromEnv = process.env.CODEX_HOME?.trim();
|
|
32221
|
-
const base = fromEnv && fromEnv.length > 0 ? fromEnv :
|
|
32222
|
-
return
|
|
32937
|
+
const base = fromEnv && fromEnv.length > 0 ? fromEnv : path16.join(os4.homedir(), ".codex");
|
|
32938
|
+
return path16.join(base, "skills");
|
|
32223
32939
|
}
|
|
32224
32940
|
function claudeSkillsHome() {
|
|
32225
32941
|
const fromEnv = process.env.CLAUDE_HOME?.trim();
|
|
32226
|
-
const base = fromEnv && fromEnv.length > 0 ? fromEnv :
|
|
32227
|
-
return
|
|
32942
|
+
const base = fromEnv && fromEnv.length > 0 ? fromEnv : path16.join(os4.homedir(), ".claude");
|
|
32943
|
+
return path16.join(base, "skills");
|
|
32228
32944
|
}
|
|
32229
32945
|
async function installSkillsForTarget(sourceSkillsDir, targetSkillsDir, tool2) {
|
|
32230
32946
|
const summary = {
|
|
@@ -32243,8 +32959,8 @@ async function installSkillsForTarget(sourceSkillsDir, targetSkillsDir, tool2) {
|
|
|
32243
32959
|
);
|
|
32244
32960
|
for (const entry of entries) {
|
|
32245
32961
|
if (!entry.isDirectory()) continue;
|
|
32246
|
-
const source =
|
|
32247
|
-
const target =
|
|
32962
|
+
const source = path16.join(sourceSkillsDir, entry.name);
|
|
32963
|
+
const target = path16.join(targetSkillsDir, entry.name);
|
|
32248
32964
|
const existing = await fs10.lstat(target).catch(() => null);
|
|
32249
32965
|
if (existing) {
|
|
32250
32966
|
if (existing.isSymbolicLink()) {
|
|
@@ -32265,7 +32981,7 @@ async function installSkillsForTarget(sourceSkillsDir, targetSkillsDir, tool2) {
|
|
|
32265
32981
|
continue;
|
|
32266
32982
|
}
|
|
32267
32983
|
}
|
|
32268
|
-
const resolvedLinkedPath =
|
|
32984
|
+
const resolvedLinkedPath = path16.isAbsolute(linkedPath) ? linkedPath : path16.resolve(path16.dirname(target), linkedPath);
|
|
32269
32985
|
const linkedTargetExists = await fs10.stat(resolvedLinkedPath).then(() => true).catch(() => false);
|
|
32270
32986
|
if (!linkedTargetExists) {
|
|
32271
32987
|
await fs10.unlink(target);
|
|
@@ -32490,7 +33206,7 @@ function registerAgentCommands(program) {
|
|
|
32490
33206
|
if (opts.markdown && opts.markdownFile) {
|
|
32491
33207
|
throw new Error("Pass only one of --markdown or --markdown-file.");
|
|
32492
33208
|
}
|
|
32493
|
-
const markdown = opts.markdownFile ? await fs10.readFile(
|
|
33209
|
+
const markdown = opts.markdownFile ? await fs10.readFile(path16.resolve(opts.markdownFile), "utf8") : opts.markdown;
|
|
32494
33210
|
const payload = organizationSkillCreateSchema.parse({
|
|
32495
33211
|
name: opts.name,
|
|
32496
33212
|
slug: opts.slug?.trim() || null,
|
|
@@ -32669,7 +33385,7 @@ function registerAgentCommands(program) {
|
|
|
32669
33385
|
}
|
|
32670
33386
|
const installSummaries = [];
|
|
32671
33387
|
if (opts.installSkills !== false) {
|
|
32672
|
-
const skillsDir = await resolveRudderSkillsDir(__moduleDir, [
|
|
33388
|
+
const skillsDir = await resolveRudderSkillsDir(__moduleDir, [path16.resolve(process.cwd(), "skills")]);
|
|
32673
33389
|
if (!skillsDir) {
|
|
32674
33390
|
throw new Error(
|
|
32675
33391
|
"Could not locate local Rudder skills directory. Expected ./skills in the repo checkout."
|
|
@@ -32757,10 +33473,10 @@ async function buildAgentUpdatePatch(opts) {
|
|
|
32757
33473
|
if (opts.capabilities !== void 0) rawPatch.capabilities = opts.capabilities;
|
|
32758
33474
|
if (opts.description !== void 0) rawPatch.capabilities = opts.description;
|
|
32759
33475
|
if (opts.capabilitiesFile !== void 0) {
|
|
32760
|
-
rawPatch.capabilities = await fs10.readFile(
|
|
33476
|
+
rawPatch.capabilities = await fs10.readFile(path16.resolve(opts.capabilitiesFile), "utf8");
|
|
32761
33477
|
}
|
|
32762
33478
|
if (opts.descriptionFile !== void 0) {
|
|
32763
|
-
rawPatch.capabilities = await fs10.readFile(
|
|
33479
|
+
rawPatch.capabilities = await fs10.readFile(path16.resolve(opts.descriptionFile), "utf8");
|
|
32764
33480
|
}
|
|
32765
33481
|
if (clearCapabilities) rawPatch.capabilities = null;
|
|
32766
33482
|
return updateAgentSchema.parse(rawPatch);
|
|
@@ -32783,8 +33499,8 @@ function parseJsonObject(value, name) {
|
|
|
32783
33499
|
|
|
32784
33500
|
// src/commands/client/approval.ts
|
|
32785
33501
|
init_dist2();
|
|
32786
|
-
import { readFile as
|
|
32787
|
-
import
|
|
33502
|
+
import { readFile as readFile4 } from "node:fs/promises";
|
|
33503
|
+
import path17 from "node:path";
|
|
32788
33504
|
function registerApprovalCommands(program) {
|
|
32789
33505
|
const approval = program.command("approval").description("Approval operations");
|
|
32790
33506
|
addCommonClientOptions(
|
|
@@ -32975,8 +33691,8 @@ async function readTextInputFile(inputPath, optionName) {
|
|
|
32975
33691
|
if (inputPath === "-") {
|
|
32976
33692
|
return readStdinText();
|
|
32977
33693
|
}
|
|
32978
|
-
const resolvedPath =
|
|
32979
|
-
return
|
|
33694
|
+
const resolvedPath = path17.resolve(process.cwd(), inputPath);
|
|
33695
|
+
return readFile4(resolvedPath, "utf8").catch((err) => {
|
|
32980
33696
|
throw new Error(`Unable to read ${optionName} ${inputPath}: ${err instanceof Error ? err.message : String(err)}`);
|
|
32981
33697
|
});
|
|
32982
33698
|
}
|
|
@@ -33812,12 +34528,12 @@ async function readStdin() {
|
|
|
33812
34528
|
|
|
33813
34529
|
// src/commands/client/company.ts
|
|
33814
34530
|
import * as p3 from "@clack/prompts";
|
|
33815
|
-
import { mkdir as
|
|
33816
|
-
import
|
|
34531
|
+
import { mkdir as mkdir3, readdir as readdir2, readFile as readFile5, stat as stat2, writeFile as writeFile3 } from "node:fs/promises";
|
|
34532
|
+
import path19 from "node:path";
|
|
33817
34533
|
import pc5 from "picocolors";
|
|
33818
34534
|
|
|
33819
34535
|
// src/commands/client/zip.ts
|
|
33820
|
-
import
|
|
34536
|
+
import path18 from "node:path";
|
|
33821
34537
|
import { inflateRawSync } from "node:zlib";
|
|
33822
34538
|
var textDecoder = new TextDecoder();
|
|
33823
34539
|
var binaryContentTypeByExtension = {
|
|
@@ -33845,7 +34561,7 @@ function sharedArchiveRoot(paths) {
|
|
|
33845
34561
|
return firstSegments.every((parts) => parts.length > 1 && parts[0] === candidate) ? candidate : null;
|
|
33846
34562
|
}
|
|
33847
34563
|
function bytesToPortableFileEntry(pathValue, bytes) {
|
|
33848
|
-
const contentType = binaryContentTypeByExtension[
|
|
34564
|
+
const contentType = binaryContentTypeByExtension[path18.extname(pathValue).toLowerCase()];
|
|
33849
34565
|
if (!contentType) return textDecoder.decode(bytes);
|
|
33850
34566
|
return {
|
|
33851
34567
|
encoding: "base64",
|
|
@@ -33933,7 +34649,7 @@ var IMPORT_INCLUDE_OPTIONS = [
|
|
|
33933
34649
|
];
|
|
33934
34650
|
var IMPORT_PREVIEW_SAMPLE_LIMIT = 6;
|
|
33935
34651
|
function readPortableFileEntry(filePath, contents) {
|
|
33936
|
-
const contentType = binaryContentTypeByExtension[
|
|
34652
|
+
const contentType = binaryContentTypeByExtension[path19.extname(filePath).toLowerCase()];
|
|
33937
34653
|
if (!contentType) return contents.toString("utf8");
|
|
33938
34654
|
return {
|
|
33939
34655
|
encoding: "base64",
|
|
@@ -33988,10 +34704,10 @@ function normalizePortablePath(filePath) {
|
|
|
33988
34704
|
return filePath.replace(/\\/g, "/");
|
|
33989
34705
|
}
|
|
33990
34706
|
function shouldIncludePortableFile(filePath) {
|
|
33991
|
-
const baseName =
|
|
34707
|
+
const baseName = path19.basename(filePath);
|
|
33992
34708
|
const isMarkdown = baseName.endsWith(".md");
|
|
33993
34709
|
const isPaperclipYaml = baseName === ".rudder.yaml" || baseName === ".rudder.yml";
|
|
33994
|
-
const contentType = binaryContentTypeByExtension[
|
|
34710
|
+
const contentType = binaryContentTypeByExtension[path19.extname(baseName).toLowerCase()];
|
|
33995
34711
|
return isMarkdown || isPaperclipYaml || Boolean(contentType);
|
|
33996
34712
|
}
|
|
33997
34713
|
function findPortableExtensionPath(files) {
|
|
@@ -34546,7 +35262,7 @@ function normalizeGithubImportSource(input, refOverride) {
|
|
|
34546
35262
|
}
|
|
34547
35263
|
async function pathExists(inputPath) {
|
|
34548
35264
|
try {
|
|
34549
|
-
await stat2(
|
|
35265
|
+
await stat2(path19.resolve(inputPath));
|
|
34550
35266
|
return true;
|
|
34551
35267
|
} catch {
|
|
34552
35268
|
return false;
|
|
@@ -34556,55 +35272,55 @@ async function collectPackageFiles(root, current, files) {
|
|
|
34556
35272
|
const entries = await readdir2(current, { withFileTypes: true });
|
|
34557
35273
|
for (const entry of entries) {
|
|
34558
35274
|
if (entry.name.startsWith(".git")) continue;
|
|
34559
|
-
const absolutePath =
|
|
35275
|
+
const absolutePath = path19.join(current, entry.name);
|
|
34560
35276
|
if (entry.isDirectory()) {
|
|
34561
35277
|
await collectPackageFiles(root, absolutePath, files);
|
|
34562
35278
|
continue;
|
|
34563
35279
|
}
|
|
34564
35280
|
if (!entry.isFile()) continue;
|
|
34565
|
-
const relativePath =
|
|
35281
|
+
const relativePath = path19.relative(root, absolutePath).replace(/\\/g, "/");
|
|
34566
35282
|
if (!shouldIncludePortableFile(relativePath)) continue;
|
|
34567
|
-
files[relativePath] = readPortableFileEntry(relativePath, await
|
|
35283
|
+
files[relativePath] = readPortableFileEntry(relativePath, await readFile5(absolutePath));
|
|
34568
35284
|
}
|
|
34569
35285
|
}
|
|
34570
35286
|
async function resolveInlineSourceFromPath(inputPath) {
|
|
34571
|
-
const resolved =
|
|
35287
|
+
const resolved = path19.resolve(inputPath);
|
|
34572
35288
|
const resolvedStat = await stat2(resolved);
|
|
34573
|
-
if (resolvedStat.isFile() &&
|
|
34574
|
-
const archive = await readZipArchive(await
|
|
35289
|
+
if (resolvedStat.isFile() && path19.extname(resolved).toLowerCase() === ".zip") {
|
|
35290
|
+
const archive = await readZipArchive(await readFile5(resolved));
|
|
34575
35291
|
const filteredFiles = Object.fromEntries(
|
|
34576
35292
|
Object.entries(archive.files).filter(([relativePath]) => shouldIncludePortableFile(relativePath))
|
|
34577
35293
|
);
|
|
34578
35294
|
return {
|
|
34579
|
-
rootPath: archive.rootPath ??
|
|
35295
|
+
rootPath: archive.rootPath ?? path19.basename(resolved, ".zip"),
|
|
34580
35296
|
files: filteredFiles
|
|
34581
35297
|
};
|
|
34582
35298
|
}
|
|
34583
|
-
const rootDir = resolvedStat.isDirectory() ? resolved :
|
|
35299
|
+
const rootDir = resolvedStat.isDirectory() ? resolved : path19.dirname(resolved);
|
|
34584
35300
|
const files = {};
|
|
34585
35301
|
await collectPackageFiles(rootDir, rootDir, files);
|
|
34586
35302
|
return {
|
|
34587
|
-
rootPath:
|
|
35303
|
+
rootPath: path19.basename(rootDir),
|
|
34588
35304
|
files
|
|
34589
35305
|
};
|
|
34590
35306
|
}
|
|
34591
35307
|
async function writeExportToFolder(outDir, exported) {
|
|
34592
|
-
const root =
|
|
34593
|
-
await
|
|
35308
|
+
const root = path19.resolve(outDir);
|
|
35309
|
+
await mkdir3(root, { recursive: true });
|
|
34594
35310
|
for (const [relativePath, content] of Object.entries(exported.files)) {
|
|
34595
35311
|
const normalized = relativePath.replace(/\\/g, "/");
|
|
34596
|
-
const filePath =
|
|
34597
|
-
await
|
|
35312
|
+
const filePath = path19.join(root, normalized);
|
|
35313
|
+
await mkdir3(path19.dirname(filePath), { recursive: true });
|
|
34598
35314
|
const writeValue = portableFileEntryToWriteValue(content);
|
|
34599
35315
|
if (typeof writeValue === "string") {
|
|
34600
|
-
await
|
|
35316
|
+
await writeFile3(filePath, writeValue, "utf8");
|
|
34601
35317
|
} else {
|
|
34602
|
-
await
|
|
35318
|
+
await writeFile3(filePath, writeValue);
|
|
34603
35319
|
}
|
|
34604
35320
|
}
|
|
34605
35321
|
}
|
|
34606
35322
|
async function confirmOverwriteExportDirectory(outDir) {
|
|
34607
|
-
const root =
|
|
35323
|
+
const root = path19.resolve(outDir);
|
|
34608
35324
|
const stats = await stat2(root).catch(() => null);
|
|
34609
35325
|
if (!stats) return;
|
|
34610
35326
|
if (!stats.isDirectory()) {
|
|
@@ -34786,7 +35502,7 @@ function registerCompanyCommands(program) {
|
|
|
34786
35502
|
printOutput(
|
|
34787
35503
|
{
|
|
34788
35504
|
ok: true,
|
|
34789
|
-
out:
|
|
35505
|
+
out: path19.resolve(opts.out),
|
|
34790
35506
|
rootPath: exported.rootPath,
|
|
34791
35507
|
filesWritten: Object.keys(exported.files).length,
|
|
34792
35508
|
rudderExtensionPath: exported.rudderExtensionPath,
|
|
@@ -35284,8 +36000,8 @@ function parseResultValue(value) {
|
|
|
35284
36000
|
|
|
35285
36001
|
// src/commands/client/issue.ts
|
|
35286
36002
|
init_dist2();
|
|
35287
|
-
import { readFile as
|
|
35288
|
-
import
|
|
36003
|
+
import { readFile as readFile6, stat as stat3 } from "node:fs/promises";
|
|
36004
|
+
import path20 from "node:path";
|
|
35289
36005
|
function registerIssueCommands(program) {
|
|
35290
36006
|
const issue = program.command("issue").description("Issue operations");
|
|
35291
36007
|
addCommonClientOptions(
|
|
@@ -35649,8 +36365,8 @@ async function readTextInputFile2(inputPath, optionName) {
|
|
|
35649
36365
|
if (inputPath === "-") {
|
|
35650
36366
|
return readStdinText2();
|
|
35651
36367
|
}
|
|
35652
|
-
const resolvedPath =
|
|
35653
|
-
return
|
|
36368
|
+
const resolvedPath = path20.resolve(process.cwd(), inputPath);
|
|
36369
|
+
return readFile6(resolvedPath, "utf8").catch((err) => {
|
|
35654
36370
|
throw new Error(`Unable to read ${optionName} ${inputPath}: ${err instanceof Error ? err.message : String(err)}`);
|
|
35655
36371
|
});
|
|
35656
36372
|
}
|
|
@@ -35706,16 +36422,16 @@ async function appendUploadedIssueImages(ctx, issueId, body, imagePaths) {
|
|
|
35706
36422
|
${imageBlock}` : imageBlock;
|
|
35707
36423
|
}
|
|
35708
36424
|
async function uploadIssueCommentImage(ctx, issue, imagePath) {
|
|
35709
|
-
const resolvedPath =
|
|
36425
|
+
const resolvedPath = path20.resolve(process.cwd(), imagePath);
|
|
35710
36426
|
const stats = await stat3(resolvedPath).catch((err) => {
|
|
35711
36427
|
throw new Error(`Unable to read image ${imagePath}: ${err instanceof Error ? err.message : String(err)}`);
|
|
35712
36428
|
});
|
|
35713
36429
|
if (!stats.isFile()) {
|
|
35714
36430
|
throw new Error(`Image path must be a file: ${imagePath}`);
|
|
35715
36431
|
}
|
|
35716
|
-
const filename =
|
|
36432
|
+
const filename = path20.basename(resolvedPath);
|
|
35717
36433
|
const contentType = inferCommentImageContentType(filename);
|
|
35718
|
-
const buffer = await
|
|
36434
|
+
const buffer = await readFile6(resolvedPath);
|
|
35719
36435
|
if (buffer.length <= 0) {
|
|
35720
36436
|
throw new Error(`Image is empty: ${imagePath}`);
|
|
35721
36437
|
}
|
|
@@ -35732,7 +36448,7 @@ async function uploadIssueCommentImage(ctx, issue, imagePath) {
|
|
|
35732
36448
|
return attachment;
|
|
35733
36449
|
}
|
|
35734
36450
|
function inferCommentImageContentType(filename) {
|
|
35735
|
-
const ext =
|
|
36451
|
+
const ext = path20.extname(filename).toLowerCase();
|
|
35736
36452
|
switch (ext) {
|
|
35737
36453
|
case ".png":
|
|
35738
36454
|
return "image/png";
|
|
@@ -35835,8 +36551,8 @@ function formatIssueSearchMatch(match) {
|
|
|
35835
36551
|
}
|
|
35836
36552
|
|
|
35837
36553
|
// src/commands/client/library.ts
|
|
35838
|
-
import { readFile as
|
|
35839
|
-
import
|
|
36554
|
+
import { readFile as readFile7 } from "node:fs/promises";
|
|
36555
|
+
import path21 from "node:path";
|
|
35840
36556
|
function toLibraryFileLinkResult(detail) {
|
|
35841
36557
|
return {
|
|
35842
36558
|
filePath: detail.filePath,
|
|
@@ -35981,8 +36697,8 @@ async function resolveBodyFileInput(inputPath) {
|
|
|
35981
36697
|
if (inputPath === "-") {
|
|
35982
36698
|
return readStdinText3();
|
|
35983
36699
|
}
|
|
35984
|
-
const resolvedPath =
|
|
35985
|
-
return
|
|
36700
|
+
const resolvedPath = path21.resolve(process.cwd(), inputPath);
|
|
36701
|
+
return readFile7(resolvedPath, "utf8").catch((err) => {
|
|
35986
36702
|
throw new Error(`Unable to read --body-file ${inputPath}: ${err instanceof Error ? err.message : String(err)}`);
|
|
35987
36703
|
});
|
|
35988
36704
|
}
|
|
@@ -36850,8 +37566,8 @@ function registerUserCommands(program) {
|
|
|
36850
37566
|
appendParam(params, "limit", opts.limit);
|
|
36851
37567
|
appendParam(params, "cursor", opts.cursor);
|
|
36852
37568
|
const query = params.toString();
|
|
36853
|
-
const
|
|
36854
|
-
const result = await ctx.api.get(
|
|
37569
|
+
const path29 = `/api/orgs/${ctx.orgId}/users/${encodeURIComponent(userId)}/activity-ledger${query ? `?${query}` : ""}`;
|
|
37570
|
+
const result = await ctx.api.get(path29);
|
|
36855
37571
|
if (ctx.json) {
|
|
36856
37572
|
printOutput(result, { json: true });
|
|
36857
37573
|
return;
|
|
@@ -37351,7 +38067,7 @@ function quoteShellValue(value) {
|
|
|
37351
38067
|
}
|
|
37352
38068
|
|
|
37353
38069
|
// src/commands/heartbeat-run.ts
|
|
37354
|
-
import { setTimeout as
|
|
38070
|
+
import { setTimeout as delay2 } from "node:timers/promises";
|
|
37355
38071
|
import pc11 from "picocolors";
|
|
37356
38072
|
|
|
37357
38073
|
// src/agent-runtimes/http/format-event.ts
|
|
@@ -37596,7 +38312,7 @@ async function heartbeatRun(opts) {
|
|
|
37596
38312
|
logOffset += Buffer.byteLength(logResult.content, "utf8");
|
|
37597
38313
|
}
|
|
37598
38314
|
}
|
|
37599
|
-
await
|
|
38315
|
+
await delay2(POLL_INTERVAL_MS);
|
|
37600
38316
|
}
|
|
37601
38317
|
if (finalStatus) {
|
|
37602
38318
|
if (!debug && stdoutJsonBuffer.trim()) {
|
|
@@ -37665,14 +38381,14 @@ init_run();
|
|
|
37665
38381
|
|
|
37666
38382
|
// src/commands/start.ts
|
|
37667
38383
|
import * as p15 from "@clack/prompts";
|
|
37668
|
-
import { spawn as
|
|
37669
|
-
import { createHash as createHash5, randomUUID as
|
|
37670
|
-
import { constants as fsConstants, mkdirSync as
|
|
37671
|
-
import { access, chmod as chmod2, copyFile, cp, lstat, mkdir as
|
|
37672
|
-
import { homedir, tmpdir } from "node:os";
|
|
37673
|
-
import
|
|
37674
|
-
import { clearTimeout as
|
|
37675
|
-
import { setTimeout as
|
|
38384
|
+
import { spawn as spawn4, spawnSync as spawnSync5 } from "node:child_process";
|
|
38385
|
+
import { createHash as createHash5, randomUUID as randomUUID3 } from "node:crypto";
|
|
38386
|
+
import { constants as fsConstants, mkdirSync as mkdirSync3, readFileSync as readFileSync3 } from "node:fs";
|
|
38387
|
+
import { access, chmod as chmod2, copyFile, cp, lstat, mkdir as mkdir4, mkdtemp as mkdtemp2, readdir as readdir3, readFile as readFile8, rm as rm5, stat as stat4, utimes, writeFile as writeFile4 } from "node:fs/promises";
|
|
38388
|
+
import { homedir as homedir2, tmpdir as tmpdir2 } from "node:os";
|
|
38389
|
+
import path28 from "node:path";
|
|
38390
|
+
import { clearTimeout as clearTimeout4, setTimeout as setTimeout4 } from "node:timers";
|
|
38391
|
+
import { setTimeout as delay3 } from "node:timers/promises";
|
|
37676
38392
|
import pc14 from "picocolors";
|
|
37677
38393
|
|
|
37678
38394
|
// src/checksum-manifest.ts
|
|
@@ -37696,12 +38412,13 @@ function parseChecksumFile(contents) {
|
|
|
37696
38412
|
|
|
37697
38413
|
// src/commands/start.ts
|
|
37698
38414
|
init_home();
|
|
38415
|
+
init_local_env();
|
|
37699
38416
|
|
|
37700
38417
|
// src/desktop-download.ts
|
|
37701
38418
|
import { createHash as createHash4 } from "node:crypto";
|
|
37702
|
-
import { createWriteStream as createWriteStream3, mkdirSync } from "node:fs";
|
|
37703
|
-
import { rm as
|
|
37704
|
-
import
|
|
38419
|
+
import { createWriteStream as createWriteStream3, mkdirSync as mkdirSync2 } from "node:fs";
|
|
38420
|
+
import { rm as rm4 } from "node:fs/promises";
|
|
38421
|
+
import path27 from "node:path";
|
|
37705
38422
|
import { Readable as Readable2, Transform as Transform2 } from "node:stream";
|
|
37706
38423
|
import { pipeline as pipeline3 } from "node:stream/promises";
|
|
37707
38424
|
import { clearTimeout as clearTimeout2, setTimeout as setTimeout2 } from "node:timers";
|
|
@@ -37940,8 +38657,8 @@ async function resolveDesktopDownloadOrigins(options) {
|
|
|
37940
38657
|
return mirrorElapsed === null ? ["github"] : ["github", "mirror"];
|
|
37941
38658
|
}
|
|
37942
38659
|
async function downloadAsset(asset, outputDir, progressFactory = createByteProgress, expectedChecksum, timeouts = {}) {
|
|
37943
|
-
|
|
37944
|
-
const outputPath =
|
|
38660
|
+
mkdirSync2(outputDir, { recursive: true });
|
|
38661
|
+
const outputPath = path27.join(outputDir, path27.basename(asset.name));
|
|
37945
38662
|
const idleTimeoutMs = timeouts.idleMs ?? DESKTOP_ASSET_IDLE_TIMEOUT_MS;
|
|
37946
38663
|
const responseTimeoutMs = timeouts.responseMs ?? DESKTOP_ASSET_RESPONSE_TIMEOUT_MS;
|
|
37947
38664
|
const failures = [];
|
|
@@ -37988,7 +38705,7 @@ async function downloadAsset(asset, outputDir, progressFactory = createByteProgr
|
|
|
37988
38705
|
if (expectedChecksum && actualChecksum !== expectedChecksum.toLowerCase()) {
|
|
37989
38706
|
progress.fail();
|
|
37990
38707
|
progress = null;
|
|
37991
|
-
await
|
|
38708
|
+
await rm4(outputPath, { force: true });
|
|
37992
38709
|
failures.push(`Checksum mismatch for ${asset.name} from ${url}.`);
|
|
37993
38710
|
continue;
|
|
37994
38711
|
}
|
|
@@ -37997,7 +38714,7 @@ async function downloadAsset(asset, outputDir, progressFactory = createByteProgr
|
|
|
37997
38714
|
} catch (error) {
|
|
37998
38715
|
if (idleTimeout) clearTimeout2(idleTimeout);
|
|
37999
38716
|
progress?.fail();
|
|
38000
|
-
await
|
|
38717
|
+
await rm4(outputPath, { force: true });
|
|
38001
38718
|
failures.push(`Failed to download ${asset.name} from ${url}: ${formatFetchError(error)}.`);
|
|
38002
38719
|
}
|
|
38003
38720
|
}
|
|
@@ -38009,51 +38726,8 @@ init_install2();
|
|
|
38009
38726
|
init_install();
|
|
38010
38727
|
init_version();
|
|
38011
38728
|
|
|
38012
|
-
// src/commands/
|
|
38013
|
-
|
|
38014
|
-
return `'${value.replaceAll("'", "''")}'`;
|
|
38015
|
-
}
|
|
38016
|
-
function buildWindowsZipExtractCommand(zipPath, outputDir) {
|
|
38017
|
-
return {
|
|
38018
|
-
command: "powershell.exe",
|
|
38019
|
-
args: [
|
|
38020
|
-
"-NoProfile",
|
|
38021
|
-
"-NonInteractive",
|
|
38022
|
-
"-ExecutionPolicy",
|
|
38023
|
-
"Bypass",
|
|
38024
|
-
"-Command",
|
|
38025
|
-
`$ErrorActionPreference='Stop'; Expand-Archive -LiteralPath ${powershellQuote(zipPath)} -DestinationPath ${powershellQuote(outputDir)} -Force`
|
|
38026
|
-
]
|
|
38027
|
-
};
|
|
38028
|
-
}
|
|
38029
|
-
|
|
38030
|
-
// src/commands/start.ts
|
|
38031
|
-
var DESKTOP_UPDATE_QUIT_ARG = "--rudder-update-quit";
|
|
38032
|
-
var DESKTOP_UPDATE_FORCE_ARG = "--rudder-update-force";
|
|
38033
|
-
var STABLE_SEMVER_RE = /^[0-9]+\.[0-9]+\.[0-9]+$/;
|
|
38034
|
-
var CANARY_SEMVER_RE = /^[0-9]+\.[0-9]+\.[0-9]+-canary\.[0-9]+$/;
|
|
38035
|
-
var CLI_REGISTRY_LATEST_URL = "https://registry.npmjs.org/@rudderhq%2fcli/latest";
|
|
38036
|
-
var LEGACY_UPDATE_QUIT_GRACE_MS = 1e4;
|
|
38037
|
-
var UPDATE_QUIT_FORCE_DELAY_MS = 1e3;
|
|
38038
|
-
var DESKTOP_APP_NAME = "Rudder";
|
|
38039
|
-
var DESKTOP_METADATA_FILE = ".rudder-desktop-install.json";
|
|
38040
|
-
var DESKTOP_CHECKSUM_ASSET_NAME = "SHASUMS256.txt";
|
|
38041
|
-
var DESKTOP_ASSET_CACHE_DIR = "desktop-assets";
|
|
38042
|
-
var DEFAULT_DESKTOP_ASSET_CACHE_MAX_ENTRIES = 2;
|
|
38043
|
-
var DEFAULT_DESKTOP_ASSET_CACHE_MAX_AGE_MS = 14 * 24 * 60 * 60 * 1e3;
|
|
38044
|
-
var DEFAULT_DESKTOP_ASSET_CACHE_MAX_BYTES = 768 * 1024 * 1024;
|
|
38045
|
-
var DEFAULT_DESKTOP_ASSET_CACHE_KEEP_PREVIOUS = 1;
|
|
38046
|
-
var DESKTOP_INSTALL_LOCK_TIMEOUT_MS = 60 * 60 * 1e3;
|
|
38047
|
-
var DESKTOP_INSTALL_LOCK_POLL_MS = 250;
|
|
38048
|
-
var DESKTOP_RUNTIME_PREPARE_TIMEOUT_MS = 9e4;
|
|
38049
|
-
async function waitForDesktopRuntimeSmokeEvidence(envName) {
|
|
38050
|
-
if (process.env.RUDDER_DESKTOP_SMOKE_AUTO_UPDATE_PUBLIC !== "1") return;
|
|
38051
|
-
const value = Number(process.env[envName]);
|
|
38052
|
-
if (!Number.isFinite(value) || value <= 0) return;
|
|
38053
|
-
await delay2(Math.min(value, 1e4));
|
|
38054
|
-
}
|
|
38055
|
-
var DEFAULT_GITHUB_API_BASE_URL = "https://api.github.com";
|
|
38056
|
-
var DEFAULT_GITHUB_DOWNLOAD_BASE_URL = "https://github.com";
|
|
38729
|
+
// src/commands/desktop-update-progress.ts
|
|
38730
|
+
import { clearTimeout as clearTimeout3, setTimeout as setTimeout3 } from "node:timers";
|
|
38057
38731
|
function normalizeProgressTotal(totalBytes) {
|
|
38058
38732
|
return typeof totalBytes === "number" && Number.isFinite(totalBytes) && totalBytes > 0 ? totalBytes : null;
|
|
38059
38733
|
}
|
|
@@ -38201,6 +38875,52 @@ function createDesktopApplySignalController(input = process.stdin) {
|
|
|
38201
38875
|
close: cleanup
|
|
38202
38876
|
};
|
|
38203
38877
|
}
|
|
38878
|
+
|
|
38879
|
+
// src/commands/start-windows.ts
|
|
38880
|
+
function powershellQuote(value) {
|
|
38881
|
+
return `'${value.replaceAll("'", "''")}'`;
|
|
38882
|
+
}
|
|
38883
|
+
function buildWindowsZipExtractCommand(zipPath, outputDir) {
|
|
38884
|
+
return {
|
|
38885
|
+
command: "powershell.exe",
|
|
38886
|
+
args: [
|
|
38887
|
+
"-NoProfile",
|
|
38888
|
+
"-NonInteractive",
|
|
38889
|
+
"-ExecutionPolicy",
|
|
38890
|
+
"Bypass",
|
|
38891
|
+
"-Command",
|
|
38892
|
+
`$ErrorActionPreference='Stop'; Expand-Archive -LiteralPath ${powershellQuote(zipPath)} -DestinationPath ${powershellQuote(outputDir)} -Force`
|
|
38893
|
+
]
|
|
38894
|
+
};
|
|
38895
|
+
}
|
|
38896
|
+
|
|
38897
|
+
// src/commands/start.ts
|
|
38898
|
+
var DESKTOP_UPDATE_QUIT_ARG = "--rudder-update-quit";
|
|
38899
|
+
var DESKTOP_UPDATE_FORCE_ARG = "--rudder-update-force";
|
|
38900
|
+
var STABLE_SEMVER_RE = /^[0-9]+\.[0-9]+\.[0-9]+$/;
|
|
38901
|
+
var CANARY_SEMVER_RE = /^[0-9]+\.[0-9]+\.[0-9]+-canary\.[0-9]+$/;
|
|
38902
|
+
var CLI_REGISTRY_LATEST_URL = "https://registry.npmjs.org/@rudderhq%2fcli/latest";
|
|
38903
|
+
var LEGACY_UPDATE_QUIT_GRACE_MS = 1e4;
|
|
38904
|
+
var UPDATE_QUIT_FORCE_DELAY_MS = 1e3;
|
|
38905
|
+
var DESKTOP_APP_NAME = "Rudder";
|
|
38906
|
+
var DESKTOP_METADATA_FILE = ".rudder-desktop-install.json";
|
|
38907
|
+
var DESKTOP_CHECKSUM_ASSET_NAME = "SHASUMS256.txt";
|
|
38908
|
+
var DESKTOP_ASSET_CACHE_DIR = "desktop-assets";
|
|
38909
|
+
var DEFAULT_DESKTOP_ASSET_CACHE_MAX_ENTRIES = 2;
|
|
38910
|
+
var DEFAULT_DESKTOP_ASSET_CACHE_MAX_AGE_MS = 14 * 24 * 60 * 60 * 1e3;
|
|
38911
|
+
var DEFAULT_DESKTOP_ASSET_CACHE_MAX_BYTES = 768 * 1024 * 1024;
|
|
38912
|
+
var DEFAULT_DESKTOP_ASSET_CACHE_KEEP_PREVIOUS = 1;
|
|
38913
|
+
var DESKTOP_INSTALL_LOCK_TIMEOUT_MS = 60 * 60 * 1e3;
|
|
38914
|
+
var DESKTOP_INSTALL_LOCK_POLL_MS = 250;
|
|
38915
|
+
var DESKTOP_RUNTIME_PREPARE_TIMEOUT_MS = 9e4;
|
|
38916
|
+
async function waitForDesktopRuntimeSmokeEvidence(envName) {
|
|
38917
|
+
if (process.env.RUDDER_DESKTOP_SMOKE_AUTO_UPDATE_PUBLIC !== "1") return;
|
|
38918
|
+
const value = Number(process.env[envName]);
|
|
38919
|
+
if (!Number.isFinite(value) || value <= 0) return;
|
|
38920
|
+
await delay3(Math.min(value, 1e4));
|
|
38921
|
+
}
|
|
38922
|
+
var DEFAULT_GITHUB_API_BASE_URL = "https://api.github.com";
|
|
38923
|
+
var DEFAULT_GITHUB_DOWNLOAD_BASE_URL = "https://github.com";
|
|
38204
38924
|
function resolveCurrentCliVersion(env = process.env) {
|
|
38205
38925
|
const version = resolveCliVersion(import.meta.url, env);
|
|
38206
38926
|
return version === "0.0.0" ? "latest" : version;
|
|
@@ -38224,7 +38944,7 @@ function compareStableSemver(a, b) {
|
|
|
38224
38944
|
}
|
|
38225
38945
|
async function fetchLatestCliVersion() {
|
|
38226
38946
|
const controller = new AbortController();
|
|
38227
|
-
const timeout =
|
|
38947
|
+
const timeout = setTimeout4(() => controller.abort(), 2e3);
|
|
38228
38948
|
try {
|
|
38229
38949
|
const response = await fetch(CLI_REGISTRY_LATEST_URL, {
|
|
38230
38950
|
signal: controller.signal,
|
|
@@ -38236,7 +38956,7 @@ async function fetchLatestCliVersion() {
|
|
|
38236
38956
|
} catch {
|
|
38237
38957
|
return null;
|
|
38238
38958
|
} finally {
|
|
38239
|
-
|
|
38959
|
+
clearTimeout4(timeout);
|
|
38240
38960
|
}
|
|
38241
38961
|
}
|
|
38242
38962
|
async function getCliUpdateNotice(currentVersion) {
|
|
@@ -38276,39 +38996,39 @@ function resolveDesktopAssetTarget(platform = process.platform, arch = process.a
|
|
|
38276
38996
|
}
|
|
38277
38997
|
throw new Error(`Rudder Desktop does not publish portable assets for ${platform}.`);
|
|
38278
38998
|
}
|
|
38279
|
-
function resolveDefaultDesktopInstallRoot(target, env = process.env, homeDir =
|
|
38280
|
-
if (target.platform === "macos") return
|
|
38999
|
+
function resolveDefaultDesktopInstallRoot(target, env = process.env, homeDir = homedir2()) {
|
|
39000
|
+
if (target.platform === "macos") return path28.join(homeDir, "Applications");
|
|
38281
39001
|
if (target.platform === "windows") {
|
|
38282
|
-
const localAppData = env.LOCALAPPDATA?.trim() ||
|
|
38283
|
-
return
|
|
39002
|
+
const localAppData = env.LOCALAPPDATA?.trim() || path28.join(homeDir, "AppData", "Local");
|
|
39003
|
+
return path28.join(localAppData, "Programs", DESKTOP_APP_NAME);
|
|
38284
39004
|
}
|
|
38285
|
-
return
|
|
39005
|
+
return path28.join(homeDir, ".local", "share", "rudder");
|
|
38286
39006
|
}
|
|
38287
39007
|
function resolveDesktopInstallPaths(target, installRoot) {
|
|
38288
|
-
const root =
|
|
39008
|
+
const root = path28.resolve(installRoot);
|
|
38289
39009
|
if (target.platform === "macos") {
|
|
38290
|
-
const appPath2 =
|
|
39010
|
+
const appPath2 = path28.join(root, `${DESKTOP_APP_NAME}.app`);
|
|
38291
39011
|
return {
|
|
38292
39012
|
installRoot: root,
|
|
38293
39013
|
appPath: appPath2,
|
|
38294
|
-
executablePath:
|
|
38295
|
-
metadataPath:
|
|
39014
|
+
executablePath: path28.join(appPath2, "Contents", "MacOS", DESKTOP_APP_NAME),
|
|
39015
|
+
metadataPath: path28.join(root, DESKTOP_METADATA_FILE)
|
|
38296
39016
|
};
|
|
38297
39017
|
}
|
|
38298
39018
|
if (target.platform === "windows") {
|
|
38299
39019
|
return {
|
|
38300
39020
|
installRoot: root,
|
|
38301
39021
|
appPath: root,
|
|
38302
|
-
executablePath:
|
|
38303
|
-
metadataPath:
|
|
39022
|
+
executablePath: path28.join(root, `${DESKTOP_APP_NAME}.exe`),
|
|
39023
|
+
metadataPath: path28.join(root, DESKTOP_METADATA_FILE)
|
|
38304
39024
|
};
|
|
38305
39025
|
}
|
|
38306
|
-
const appPath =
|
|
39026
|
+
const appPath = path28.join(root, `${DESKTOP_APP_NAME}.AppImage`);
|
|
38307
39027
|
return {
|
|
38308
39028
|
installRoot: root,
|
|
38309
39029
|
appPath,
|
|
38310
39030
|
executablePath: appPath,
|
|
38311
|
-
metadataPath:
|
|
39031
|
+
metadataPath: path28.join(root, DESKTOP_METADATA_FILE)
|
|
38312
39032
|
};
|
|
38313
39033
|
}
|
|
38314
39034
|
function normalizeAssetName(name) {
|
|
@@ -38410,11 +39130,11 @@ function selectChecksumAsset(assets) {
|
|
|
38410
39130
|
}
|
|
38411
39131
|
async function fetchWithTimeout2(url, init, timeoutMs) {
|
|
38412
39132
|
const controller = new AbortController();
|
|
38413
|
-
const timeout =
|
|
39133
|
+
const timeout = setTimeout4(() => controller.abort(), timeoutMs);
|
|
38414
39134
|
try {
|
|
38415
39135
|
return await fetch(url, { ...init, signal: controller.signal });
|
|
38416
39136
|
} finally {
|
|
38417
|
-
|
|
39137
|
+
clearTimeout4(timeout);
|
|
38418
39138
|
}
|
|
38419
39139
|
}
|
|
38420
39140
|
function githubApiHeaders() {
|
|
@@ -38492,20 +39212,20 @@ function buildGithubReleaseAsset(repo, tag, assetName, downloadBaseUrl) {
|
|
|
38492
39212
|
}
|
|
38493
39213
|
function checksumForFile(filePath) {
|
|
38494
39214
|
const hash = createHash5("sha256");
|
|
38495
|
-
hash.update(
|
|
39215
|
+
hash.update(readFileSync3(filePath));
|
|
38496
39216
|
return hash.digest("hex");
|
|
38497
39217
|
}
|
|
38498
39218
|
function resolveAssetChecksum(checksums, assetName) {
|
|
38499
|
-
const expected = checksums.get(
|
|
39219
|
+
const expected = checksums.get(path28.basename(assetName));
|
|
38500
39220
|
if (!expected) {
|
|
38501
|
-
throw new Error(`Desktop release checksums do not include ${
|
|
39221
|
+
throw new Error(`Desktop release checksums do not include ${path28.basename(assetName)}.`);
|
|
38502
39222
|
}
|
|
38503
39223
|
return expected;
|
|
38504
39224
|
}
|
|
38505
39225
|
function assertChecksumMatch(filePath, expected) {
|
|
38506
39226
|
const actual = checksumForFile(filePath);
|
|
38507
39227
|
if (actual !== expected.toLowerCase()) {
|
|
38508
|
-
throw new Error(`Checksum mismatch for ${
|
|
39228
|
+
throw new Error(`Checksum mismatch for ${path28.basename(filePath)}.`);
|
|
38509
39229
|
}
|
|
38510
39230
|
return actual;
|
|
38511
39231
|
}
|
|
@@ -38514,7 +39234,7 @@ async function downloadChecksums(checksumAsset, outputDir, progressFactory = cre
|
|
|
38514
39234
|
throw new Error("Desktop release is missing SHASUMS256.txt.");
|
|
38515
39235
|
}
|
|
38516
39236
|
const checksumPath = await downloadAsset(checksumAsset, outputDir, progressFactory);
|
|
38517
|
-
return parseChecksumFile(
|
|
39237
|
+
return parseChecksumFile(readFileSync3(checksumPath, "utf8"));
|
|
38518
39238
|
}
|
|
38519
39239
|
function normalizeDesktopAssetChecksum(checksum) {
|
|
38520
39240
|
const normalized = checksum.trim().toLowerCase();
|
|
@@ -38524,10 +39244,10 @@ function normalizeDesktopAssetChecksum(checksum) {
|
|
|
38524
39244
|
return normalized;
|
|
38525
39245
|
}
|
|
38526
39246
|
function resolveDesktopAssetCacheDir(assetChecksum, homeDir = resolveRudderHomeDir()) {
|
|
38527
|
-
return
|
|
39247
|
+
return path28.join(homeDir, DESKTOP_ASSET_CACHE_DIR, normalizeDesktopAssetChecksum(assetChecksum));
|
|
38528
39248
|
}
|
|
38529
39249
|
function resolveDesktopCachedAssetPath(assetName, assetChecksum, homeDir = resolveRudderHomeDir()) {
|
|
38530
|
-
return
|
|
39250
|
+
return path28.join(resolveDesktopAssetCacheDir(assetChecksum, homeDir), path28.basename(assetName));
|
|
38531
39251
|
}
|
|
38532
39252
|
async function pruneDesktopAssetCache(options = {}) {
|
|
38533
39253
|
const homeDir = options.homeDir ?? resolveRudderHomeDir();
|
|
@@ -38548,7 +39268,7 @@ async function pruneDesktopAssetCache(options = {}) {
|
|
|
38548
39268
|
const warnings = [];
|
|
38549
39269
|
for (const entry of deletions) {
|
|
38550
39270
|
try {
|
|
38551
|
-
await
|
|
39271
|
+
await rm5(entry.cacheDir, { recursive: true, force: true });
|
|
38552
39272
|
deleted.push({
|
|
38553
39273
|
cacheDir: entry.cacheDir,
|
|
38554
39274
|
checksum: entry.checksum,
|
|
@@ -38573,7 +39293,7 @@ async function maybePruneDesktopAssetCache(options) {
|
|
|
38573
39293
|
return result.deleted.length > 0 || result.warnings.length > 0 ? result : null;
|
|
38574
39294
|
}
|
|
38575
39295
|
async function scanDesktopAssetCacheEntries(homeDir) {
|
|
38576
|
-
const cacheRoot =
|
|
39296
|
+
const cacheRoot = path28.join(homeDir, DESKTOP_ASSET_CACHE_DIR);
|
|
38577
39297
|
const dirents = await readdir3(cacheRoot, { withFileTypes: true }).catch(() => null);
|
|
38578
39298
|
if (!dirents) return [];
|
|
38579
39299
|
const entries = [];
|
|
@@ -38585,7 +39305,7 @@ async function scanDesktopAssetCacheEntries(homeDir) {
|
|
|
38585
39305
|
} catch {
|
|
38586
39306
|
continue;
|
|
38587
39307
|
}
|
|
38588
|
-
const cacheDir =
|
|
39308
|
+
const cacheDir = path28.join(cacheRoot, dirent.name);
|
|
38589
39309
|
const stats = await desktopCacheDirectoryStats(cacheDir);
|
|
38590
39310
|
entries.push({
|
|
38591
39311
|
cacheDir,
|
|
@@ -38609,7 +39329,7 @@ async function desktopCacheDirectoryStats(targetPath) {
|
|
|
38609
39329
|
let lastUsedAtMs = Number(fallbackStat?.mtimeMs ?? 0);
|
|
38610
39330
|
for (const dirent of dirents) {
|
|
38611
39331
|
if (dirent.isSymbolicLink()) continue;
|
|
38612
|
-
const entryPath =
|
|
39332
|
+
const entryPath = path28.join(targetPath, dirent.name);
|
|
38613
39333
|
const entryStat = await stat4(entryPath).catch(() => null);
|
|
38614
39334
|
if (!entryStat) continue;
|
|
38615
39335
|
lastUsedAtMs = Math.max(lastUsedAtMs, Number(entryStat.mtimeMs ?? 0));
|
|
@@ -38683,21 +39403,21 @@ async function downloadDesktopAssetWithCache(asset, expectedChecksum, options =
|
|
|
38683
39403
|
await touchDesktopCachedAsset(cachePath);
|
|
38684
39404
|
return { path: cachePath, checksum, cacheStatus: "hit" };
|
|
38685
39405
|
} catch {
|
|
38686
|
-
await
|
|
39406
|
+
await rm5(cachePath, { force: true });
|
|
38687
39407
|
}
|
|
38688
39408
|
}
|
|
38689
|
-
const outputDir = options.outputDir ?? await mkdtemp2(
|
|
39409
|
+
const outputDir = options.outputDir ?? await mkdtemp2(path28.join(tmpdir2(), "rudder-desktop-installer."));
|
|
38690
39410
|
const removeOutputDir = options.outputDir ? false : true;
|
|
38691
39411
|
try {
|
|
38692
39412
|
const downloadedPath = await downloadAsset(asset, outputDir, options.progressFactory, normalizedChecksum);
|
|
38693
39413
|
const checksum = assertChecksumMatch(downloadedPath, normalizedChecksum);
|
|
38694
|
-
await
|
|
38695
|
-
if (
|
|
39414
|
+
await mkdir4(path28.dirname(cachePath), { recursive: true });
|
|
39415
|
+
if (path28.resolve(downloadedPath) !== path28.resolve(cachePath)) {
|
|
38696
39416
|
await copyFile(downloadedPath, cachePath);
|
|
38697
39417
|
}
|
|
38698
39418
|
return { path: cachePath, checksum, cacheStatus: "miss" };
|
|
38699
39419
|
} finally {
|
|
38700
|
-
if (removeOutputDir) await
|
|
39420
|
+
if (removeOutputDir) await rm5(outputDir, { recursive: true, force: true });
|
|
38701
39421
|
}
|
|
38702
39422
|
}
|
|
38703
39423
|
async function pathExists2(targetPath) {
|
|
@@ -38709,12 +39429,12 @@ async function pathExists2(targetPath) {
|
|
|
38709
39429
|
}
|
|
38710
39430
|
}
|
|
38711
39431
|
function resolveDesktopInstallLockPath(paths) {
|
|
38712
|
-
const installRootHash = createHash5("sha256").update(
|
|
38713
|
-
return
|
|
39432
|
+
const installRootHash = createHash5("sha256").update(path28.resolve(paths.installRoot)).digest("hex").slice(0, 16);
|
|
39433
|
+
return path28.join(path28.dirname(paths.appPath), `.rudder-desktop-install-${installRootHash}.lock`);
|
|
38714
39434
|
}
|
|
38715
39435
|
async function readDesktopInstallLock(lockPath) {
|
|
38716
39436
|
try {
|
|
38717
|
-
const parsed = JSON.parse(await
|
|
39437
|
+
const parsed = JSON.parse(await readFile8(lockPath, "utf8"));
|
|
38718
39438
|
if (typeof parsed.pid !== "number" || !Number.isInteger(parsed.pid) || parsed.pid <= 0 || typeof parsed.lockId !== "string" || typeof parsed.installRoot !== "string" || typeof parsed.createdAt !== "string") {
|
|
38719
39439
|
return null;
|
|
38720
39440
|
}
|
|
@@ -38730,20 +39450,20 @@ async function readDesktopInstallLock(lockPath) {
|
|
|
38730
39450
|
}
|
|
38731
39451
|
async function withDesktopInstallLock(paths, fn, options = {}) {
|
|
38732
39452
|
const lockPath = resolveDesktopInstallLockPath(paths);
|
|
38733
|
-
const lockDir =
|
|
39453
|
+
const lockDir = path28.dirname(lockPath);
|
|
38734
39454
|
const timeoutMs = options.timeoutMs ?? DESKTOP_INSTALL_LOCK_TIMEOUT_MS;
|
|
38735
39455
|
const pollMs = options.pollMs ?? DESKTOP_INSTALL_LOCK_POLL_MS;
|
|
38736
39456
|
const startedAt = Date.now();
|
|
38737
39457
|
const payload = {
|
|
38738
|
-
lockId:
|
|
39458
|
+
lockId: randomUUID3(),
|
|
38739
39459
|
pid: process.pid,
|
|
38740
|
-
installRoot:
|
|
39460
|
+
installRoot: path28.resolve(paths.installRoot),
|
|
38741
39461
|
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
38742
39462
|
};
|
|
38743
|
-
await
|
|
39463
|
+
await mkdir4(lockDir, { recursive: true });
|
|
38744
39464
|
while (true) {
|
|
38745
39465
|
try {
|
|
38746
|
-
await
|
|
39466
|
+
await writeFile4(lockPath, `${JSON.stringify(payload, null, 2)}
|
|
38747
39467
|
`, { encoding: "utf8", flag: "wx" });
|
|
38748
39468
|
break;
|
|
38749
39469
|
} catch (error) {
|
|
@@ -38752,7 +39472,7 @@ async function withDesktopInstallLock(paths, fn, options = {}) {
|
|
|
38752
39472
|
const existing = await readDesktopInstallLock(lockPath);
|
|
38753
39473
|
const stale = !existing || !processExists(existing.pid);
|
|
38754
39474
|
if (stale) {
|
|
38755
|
-
await
|
|
39475
|
+
await rm5(lockPath, { force: true });
|
|
38756
39476
|
continue;
|
|
38757
39477
|
}
|
|
38758
39478
|
if (Date.now() - startedAt >= timeoutMs) {
|
|
@@ -38760,7 +39480,7 @@ async function withDesktopInstallLock(paths, fn, options = {}) {
|
|
|
38760
39480
|
`Timed out waiting for Rudder Desktop install lock for ${paths.appPath}. Held by pid ${existing.pid} for ${existing.installRoot}.`
|
|
38761
39481
|
);
|
|
38762
39482
|
}
|
|
38763
|
-
await
|
|
39483
|
+
await delay3(pollMs);
|
|
38764
39484
|
}
|
|
38765
39485
|
}
|
|
38766
39486
|
try {
|
|
@@ -38768,12 +39488,12 @@ async function withDesktopInstallLock(paths, fn, options = {}) {
|
|
|
38768
39488
|
} finally {
|
|
38769
39489
|
const existing = await readDesktopInstallLock(lockPath);
|
|
38770
39490
|
if (existing?.lockId === payload.lockId) {
|
|
38771
|
-
await
|
|
39491
|
+
await rm5(lockPath, { force: true });
|
|
38772
39492
|
}
|
|
38773
39493
|
}
|
|
38774
39494
|
}
|
|
38775
39495
|
function runChecked(command, args, options = {}) {
|
|
38776
|
-
const result =
|
|
39496
|
+
const result = spawnSync5(command, args, {
|
|
38777
39497
|
encoding: "utf8",
|
|
38778
39498
|
stdio: ["ignore", "pipe", "pipe"],
|
|
38779
39499
|
...options
|
|
@@ -38796,8 +39516,8 @@ function isSuccessfulRobocopyExitCode(status) {
|
|
|
38796
39516
|
return typeof status === "number" && status >= 0 && status <= 7;
|
|
38797
39517
|
}
|
|
38798
39518
|
async function extractZip(zipPath, outputDir, target) {
|
|
38799
|
-
await
|
|
38800
|
-
await
|
|
39519
|
+
await rm5(outputDir, { recursive: true, force: true });
|
|
39520
|
+
await mkdir4(outputDir, { recursive: true });
|
|
38801
39521
|
if (target.platform === "macos") {
|
|
38802
39522
|
runChecked("ditto", ["-x", "-k", zipPath, outputDir]);
|
|
38803
39523
|
return;
|
|
@@ -38813,7 +39533,7 @@ async function findPath(root, predicate, maxDepth = 5) {
|
|
|
38813
39533
|
async function visit(dir, depth) {
|
|
38814
39534
|
const entries = await readdir3(dir, { withFileTypes: true });
|
|
38815
39535
|
for (const entry of entries) {
|
|
38816
|
-
const fullPath =
|
|
39536
|
+
const fullPath = path28.join(dir, entry.name);
|
|
38817
39537
|
if (predicate(fullPath, entry.isDirectory())) return fullPath;
|
|
38818
39538
|
if (entry.isDirectory() && depth < maxDepth) {
|
|
38819
39539
|
const nested = await visit(fullPath, depth + 1);
|
|
@@ -38825,22 +39545,22 @@ async function findPath(root, predicate, maxDepth = 5) {
|
|
|
38825
39545
|
return await visit(root, 0);
|
|
38826
39546
|
}
|
|
38827
39547
|
async function findMacApp(extractDir) {
|
|
38828
|
-
const direct =
|
|
39548
|
+
const direct = path28.join(extractDir, `${DESKTOP_APP_NAME}.app`);
|
|
38829
39549
|
if (await pathExists2(direct)) return direct;
|
|
38830
|
-
const found = await findPath(extractDir, (filePath, isDirectory) => isDirectory &&
|
|
39550
|
+
const found = await findPath(extractDir, (filePath, isDirectory) => isDirectory && path28.basename(filePath) === `${DESKTOP_APP_NAME}.app`);
|
|
38831
39551
|
if (!found) throw new Error(`Portable macOS archive did not contain ${DESKTOP_APP_NAME}.app.`);
|
|
38832
39552
|
return found;
|
|
38833
39553
|
}
|
|
38834
39554
|
async function findWindowsAppDir(extractDir) {
|
|
38835
|
-
const direct =
|
|
39555
|
+
const direct = path28.join(extractDir, `${DESKTOP_APP_NAME}.exe`);
|
|
38836
39556
|
if (await pathExists2(direct)) return extractDir;
|
|
38837
|
-
const executable = await findPath(extractDir, (filePath, isDirectory) => !isDirectory &&
|
|
39557
|
+
const executable = await findPath(extractDir, (filePath, isDirectory) => !isDirectory && path28.basename(filePath).toLowerCase() === `${DESKTOP_APP_NAME.toLowerCase()}.exe`);
|
|
38838
39558
|
if (!executable) throw new Error(`Portable Windows archive did not contain ${DESKTOP_APP_NAME}.exe.`);
|
|
38839
|
-
return
|
|
39559
|
+
return path28.dirname(executable);
|
|
38840
39560
|
}
|
|
38841
39561
|
async function readInstallMetadata(metadataPath) {
|
|
38842
39562
|
try {
|
|
38843
|
-
const parsed = JSON.parse(await
|
|
39563
|
+
const parsed = JSON.parse(await readFile8(metadataPath, "utf8"));
|
|
38844
39564
|
if (parsed.version !== 1) return null;
|
|
38845
39565
|
return parsed;
|
|
38846
39566
|
} catch {
|
|
@@ -38854,7 +39574,7 @@ function isInstalledDesktopCurrent(metadata, releaseTag, assetName, assetChecksu
|
|
|
38854
39574
|
}
|
|
38855
39575
|
function forceQuitDesktopProcess(pid, target) {
|
|
38856
39576
|
if (target.platform === "windows") {
|
|
38857
|
-
|
|
39577
|
+
spawnSync5("taskkill.exe", ["/PID", String(pid), "/T", "/F"], { stdio: "ignore" });
|
|
38858
39578
|
return;
|
|
38859
39579
|
}
|
|
38860
39580
|
try {
|
|
@@ -38862,15 +39582,15 @@ function forceQuitDesktopProcess(pid, target) {
|
|
|
38862
39582
|
} catch {
|
|
38863
39583
|
}
|
|
38864
39584
|
}
|
|
38865
|
-
function
|
|
39585
|
+
function quotePowerShellString2(value) {
|
|
38866
39586
|
return `'${value.replaceAll("'", "''")}'`;
|
|
38867
39587
|
}
|
|
38868
39588
|
function findDesktopExecutablePids(executablePath, target) {
|
|
38869
39589
|
if (target.platform === "windows") {
|
|
38870
|
-
const result2 =
|
|
39590
|
+
const result2 = spawnSync5("powershell.exe", [
|
|
38871
39591
|
"-NoProfile",
|
|
38872
39592
|
"-Command",
|
|
38873
|
-
`Get-CimInstance Win32_Process | Where-Object { $_.ExecutablePath -eq ${
|
|
39593
|
+
`Get-CimInstance Win32_Process | Where-Object { $_.ExecutablePath -eq ${quotePowerShellString2(executablePath)} } | Select-Object -ExpandProperty ProcessId`
|
|
38874
39594
|
], {
|
|
38875
39595
|
encoding: "utf8",
|
|
38876
39596
|
stdio: ["ignore", "pipe", "ignore"]
|
|
@@ -38878,7 +39598,7 @@ function findDesktopExecutablePids(executablePath, target) {
|
|
|
38878
39598
|
if (result2.status !== 0) return [];
|
|
38879
39599
|
return result2.stdout.split(/\r?\n/).map((line) => Number.parseInt(line.trim(), 10)).filter((pid) => Number.isInteger(pid) && pid > 0 && pid !== process.pid);
|
|
38880
39600
|
}
|
|
38881
|
-
const result =
|
|
39601
|
+
const result = spawnSync5("ps", ["-eo", "pid=,args="], {
|
|
38882
39602
|
encoding: "utf8",
|
|
38883
39603
|
stdio: ["ignore", "pipe", "ignore"]
|
|
38884
39604
|
});
|
|
@@ -38901,16 +39621,16 @@ async function waitForUpdateQuitResponse(responsePath, timeoutMs = 8e3) {
|
|
|
38901
39621
|
const startedAt = Date.now();
|
|
38902
39622
|
while (Date.now() - startedAt < timeoutMs) {
|
|
38903
39623
|
if (await pathExists2(responsePath)) {
|
|
38904
|
-
return JSON.parse(await
|
|
39624
|
+
return JSON.parse(await readFile8(responsePath, "utf8"));
|
|
38905
39625
|
}
|
|
38906
|
-
await
|
|
39626
|
+
await delay3(200);
|
|
38907
39627
|
}
|
|
38908
39628
|
return null;
|
|
38909
39629
|
}
|
|
38910
39630
|
async function requestDesktopQuit(executablePath, target, options = {}) {
|
|
38911
39631
|
if (!await pathExists2(executablePath)) return { ok: true, status: "not_running" };
|
|
38912
|
-
const responsePath =
|
|
38913
|
-
const result =
|
|
39632
|
+
const responsePath = path28.join(tmpdir2(), `rudder-update-quit-${process.pid}-${Date.now()}.json`);
|
|
39633
|
+
const result = spawnSync5(executablePath, [
|
|
38914
39634
|
`${DESKTOP_UPDATE_QUIT_ARG}=${responsePath}`,
|
|
38915
39635
|
...options.forceUpdate ? [DESKTOP_UPDATE_FORCE_ARG] : []
|
|
38916
39636
|
], {
|
|
@@ -38924,7 +39644,7 @@ async function requestDesktopQuit(executablePath, target, options = {}) {
|
|
|
38924
39644
|
try {
|
|
38925
39645
|
return await waitForUpdateQuitResponse(responsePath, options.responseTimeoutMs);
|
|
38926
39646
|
} finally {
|
|
38927
|
-
await
|
|
39647
|
+
await rm5(responsePath, { force: true });
|
|
38928
39648
|
}
|
|
38929
39649
|
}
|
|
38930
39650
|
function processExists(pid) {
|
|
@@ -38947,7 +39667,7 @@ async function waitForProcessExit(pid, timeoutMs = 2e4, intervalMs = 250) {
|
|
|
38947
39667
|
const startedAt = Date.now();
|
|
38948
39668
|
while (Date.now() - startedAt < timeoutMs) {
|
|
38949
39669
|
if (!processExists(pid)) return true;
|
|
38950
|
-
await
|
|
39670
|
+
await delay3(intervalMs);
|
|
38951
39671
|
}
|
|
38952
39672
|
return !processExists(pid);
|
|
38953
39673
|
}
|
|
@@ -38960,11 +39680,11 @@ async function waitForProcessesExit(pids, waitForExit) {
|
|
|
38960
39680
|
async function removePathWithRetry(targetPath, attempts = 5) {
|
|
38961
39681
|
for (let attempt = 0; attempt < attempts; attempt += 1) {
|
|
38962
39682
|
try {
|
|
38963
|
-
await
|
|
39683
|
+
await rm5(targetPath, { recursive: true, force: true });
|
|
38964
39684
|
if (!await pathExists2(targetPath)) return true;
|
|
38965
39685
|
} catch {
|
|
38966
39686
|
}
|
|
38967
|
-
await
|
|
39687
|
+
await delay3(500);
|
|
38968
39688
|
}
|
|
38969
39689
|
return false;
|
|
38970
39690
|
}
|
|
@@ -38974,7 +39694,7 @@ async function prepareForDesktopReplace(paths, target, options = {}) {
|
|
|
38974
39694
|
const findPids = options.findDesktopExecutablePids ?? findDesktopExecutablePids;
|
|
38975
39695
|
async function forceQuitPidAndConfirm(pid) {
|
|
38976
39696
|
forceQuitPid(pid, target);
|
|
38977
|
-
await
|
|
39697
|
+
await delay3(options.updateQuitForceDelayMs ?? UPDATE_QUIT_FORCE_DELAY_MS);
|
|
38978
39698
|
if (!await waitForExit(pid)) {
|
|
38979
39699
|
throw new Error(`Rudder Desktop process ${pid} did not exit after force-quit fallback. Close Rudder and rerun start.`);
|
|
38980
39700
|
}
|
|
@@ -38984,7 +39704,7 @@ async function prepareForDesktopReplace(paths, target, options = {}) {
|
|
|
38984
39704
|
for (const pid of uniquePids) {
|
|
38985
39705
|
forceQuitPid(pid, target);
|
|
38986
39706
|
}
|
|
38987
|
-
await
|
|
39707
|
+
await delay3(options.updateQuitForceDelayMs ?? UPDATE_QUIT_FORCE_DELAY_MS);
|
|
38988
39708
|
if (!await waitForProcessesExit(uniquePids, waitForExit)) {
|
|
38989
39709
|
throw new Error(`Rudder Desktop process${uniquePids.length === 1 ? "" : "es"} ${uniquePids.join(", ")} did not exit after force-quit fallback. Close Rudder and rerun start.`);
|
|
38990
39710
|
}
|
|
@@ -39006,7 +39726,7 @@ async function prepareForDesktopReplace(paths, target, options = {}) {
|
|
|
39006
39726
|
);
|
|
39007
39727
|
options.onActiveRunsWaiting?.(quitResponse.totalRuns);
|
|
39008
39728
|
const pollIntervalMs = options.activeRunPollIntervalMs ?? 15e3;
|
|
39009
|
-
forceUpdate = options.waitForForceUpdate ? await options.waitForForceUpdate(pollIntervalMs) : (await
|
|
39729
|
+
forceUpdate = options.waitForForceUpdate ? await options.waitForForceUpdate(pollIntervalMs) : (await delay3(pollIntervalMs), false);
|
|
39010
39730
|
quitResponse = await requestQuit();
|
|
39011
39731
|
}
|
|
39012
39732
|
if (quitResponse && !quitResponse.ok && quitResponse.status === "active_runs") {
|
|
@@ -39034,7 +39754,7 @@ async function prepareForDesktopReplace(paths, target, options = {}) {
|
|
|
39034
39754
|
p15.log.warn(
|
|
39035
39755
|
`Existing Rudder Desktop acknowledged update quit without a process id; waiting ${Math.ceil(graceMs / 1e3)}s before replacement.`
|
|
39036
39756
|
);
|
|
39037
|
-
await
|
|
39757
|
+
await delay3(graceMs);
|
|
39038
39758
|
if (managedExecutablePids.length > 0 && !await waitForProcessesExit(managedExecutablePids, waitForExit)) {
|
|
39039
39759
|
p15.log.warn(
|
|
39040
39760
|
`Existing Rudder Desktop did not exit after acknowledging update quit; attempting path-scoped force-quit for process${managedExecutablePids.length === 1 ? "" : "es"} ${managedExecutablePids.join(", ")}.`
|
|
@@ -39051,7 +39771,7 @@ async function prepareForDesktopReplace(paths, target, options = {}) {
|
|
|
39051
39771
|
throw new Error("Existing Rudder Desktop did not respond to the update quit request. Close Rudder and rerun start.");
|
|
39052
39772
|
}
|
|
39053
39773
|
} else {
|
|
39054
|
-
await
|
|
39774
|
+
await delay3(options.updateQuitForceDelayMs ?? UPDATE_QUIT_FORCE_DELAY_MS);
|
|
39055
39775
|
}
|
|
39056
39776
|
}
|
|
39057
39777
|
const replacePath = target.platform === "windows" ? paths.installRoot : paths.appPath;
|
|
@@ -39068,13 +39788,13 @@ async function prepareForDesktopReplace(paths, target, options = {}) {
|
|
|
39068
39788
|
throw new Error(`Failed to replace existing Rudder Desktop at ${replacePath}. Close Rudder and rerun start.`);
|
|
39069
39789
|
}
|
|
39070
39790
|
async function installPortableDesktop(installerPath, paths, target) {
|
|
39071
|
-
await
|
|
39791
|
+
await mkdir4(paths.installRoot, { recursive: true });
|
|
39072
39792
|
if (target.platform === "linux") {
|
|
39073
39793
|
await copyFile(installerPath, paths.appPath);
|
|
39074
39794
|
await chmod2(paths.appPath, 493);
|
|
39075
39795
|
return;
|
|
39076
39796
|
}
|
|
39077
|
-
const extractDir = await mkdtemp2(
|
|
39797
|
+
const extractDir = await mkdtemp2(path28.join(tmpdir2(), "rudder-desktop-extract."));
|
|
39078
39798
|
try {
|
|
39079
39799
|
await extractZip(installerPath, extractDir, target);
|
|
39080
39800
|
if (target.platform === "macos") {
|
|
@@ -39083,17 +39803,17 @@ async function installPortableDesktop(installerPath, paths, target) {
|
|
|
39083
39803
|
return;
|
|
39084
39804
|
}
|
|
39085
39805
|
const appSource = await findWindowsAppDir(extractDir);
|
|
39086
|
-
await
|
|
39806
|
+
await mkdir4(path28.dirname(paths.installRoot), { recursive: true });
|
|
39087
39807
|
await copyPortableAppBundle(appSource, paths.installRoot);
|
|
39088
39808
|
} finally {
|
|
39089
|
-
await
|
|
39809
|
+
await rm5(extractDir, { recursive: true, force: true });
|
|
39090
39810
|
}
|
|
39091
39811
|
}
|
|
39092
39812
|
async function copyPortableAppBundle(sourcePath, destinationPath) {
|
|
39093
39813
|
if (process.platform === "win32") {
|
|
39094
|
-
await
|
|
39814
|
+
await mkdir4(destinationPath, { recursive: true });
|
|
39095
39815
|
const command = buildWindowsRobocopyMirrorCommand(sourcePath, destinationPath);
|
|
39096
|
-
const result =
|
|
39816
|
+
const result = spawnSync5(command.command, command.args, {
|
|
39097
39817
|
encoding: "utf8",
|
|
39098
39818
|
stdio: ["ignore", "pipe", "pipe"]
|
|
39099
39819
|
});
|
|
@@ -39104,7 +39824,7 @@ async function copyPortableAppBundle(sourcePath, destinationPath) {
|
|
|
39104
39824
|
}
|
|
39105
39825
|
async function removeMacQuarantine(paths, target) {
|
|
39106
39826
|
if (target.platform !== "macos") return;
|
|
39107
|
-
const result =
|
|
39827
|
+
const result = spawnSync5("xattr", ["-dr", "com.apple.quarantine", paths.appPath], { stdio: "ignore" });
|
|
39108
39828
|
if (result.status !== 0) {
|
|
39109
39829
|
p15.log.warn(`Could not remove macOS quarantine attributes from ${paths.appPath}.`);
|
|
39110
39830
|
}
|
|
@@ -39124,26 +39844,26 @@ function buildLinuxDesktopEntry(executablePath) {
|
|
|
39124
39844
|
].join("\n");
|
|
39125
39845
|
}
|
|
39126
39846
|
async function writeLinuxLaunchers(paths) {
|
|
39127
|
-
const desktopDir =
|
|
39128
|
-
await
|
|
39129
|
-
await
|
|
39130
|
-
const binDir =
|
|
39131
|
-
await
|
|
39132
|
-
const wrapperPath =
|
|
39847
|
+
const desktopDir = path28.join(homedir2(), ".local", "share", "applications");
|
|
39848
|
+
await mkdir4(desktopDir, { recursive: true });
|
|
39849
|
+
await writeFile4(path28.join(desktopDir, "rudder.desktop"), buildLinuxDesktopEntry(paths.executablePath), "utf8");
|
|
39850
|
+
const binDir = path28.join(homedir2(), ".local", "bin");
|
|
39851
|
+
await mkdir4(binDir, { recursive: true });
|
|
39852
|
+
const wrapperPath = path28.join(binDir, "rudder-desktop");
|
|
39133
39853
|
const escaped = paths.executablePath.replaceAll("'", `'"'"'`);
|
|
39134
|
-
await
|
|
39854
|
+
await writeFile4(wrapperPath, `#!/bin/sh
|
|
39135
39855
|
exec '${escaped}' "$@"
|
|
39136
39856
|
`, "utf8");
|
|
39137
39857
|
await chmod2(wrapperPath, 493);
|
|
39138
39858
|
}
|
|
39139
39859
|
function buildWindowsShortcutScript(executablePath) {
|
|
39140
|
-
const appData = process.env.APPDATA?.trim() ||
|
|
39141
|
-
const shortcutPath =
|
|
39860
|
+
const appData = process.env.APPDATA?.trim() || path28.join(homedir2(), "AppData", "Roaming");
|
|
39861
|
+
const shortcutPath = path28.join(appData, "Microsoft", "Windows", "Start Menu", "Programs", "Rudder.lnk");
|
|
39142
39862
|
return [
|
|
39143
39863
|
"$shell = New-Object -ComObject WScript.Shell",
|
|
39144
39864
|
`$shortcut = $shell.CreateShortcut(${powershellQuote(shortcutPath)})`,
|
|
39145
39865
|
`$shortcut.TargetPath = ${powershellQuote(executablePath)}`,
|
|
39146
|
-
`$shortcut.WorkingDirectory = ${powershellQuote(
|
|
39866
|
+
`$shortcut.WorkingDirectory = ${powershellQuote(path28.dirname(executablePath))}`,
|
|
39147
39867
|
"$shortcut.Save()"
|
|
39148
39868
|
].join("; ");
|
|
39149
39869
|
}
|
|
@@ -39153,7 +39873,7 @@ async function createPlatformLaunchers(paths, target) {
|
|
|
39153
39873
|
return;
|
|
39154
39874
|
}
|
|
39155
39875
|
if (target.platform === "windows") {
|
|
39156
|
-
const result =
|
|
39876
|
+
const result = spawnSync5("powershell.exe", [
|
|
39157
39877
|
"-NoProfile",
|
|
39158
39878
|
"-ExecutionPolicy",
|
|
39159
39879
|
"Bypass",
|
|
@@ -39165,17 +39885,17 @@ async function createPlatformLaunchers(paths, target) {
|
|
|
39165
39885
|
}
|
|
39166
39886
|
function launchDesktop(paths, target) {
|
|
39167
39887
|
if (target.platform === "macos") {
|
|
39168
|
-
|
|
39888
|
+
spawn4("open", [paths.appPath], { detached: true, stdio: "ignore" }).unref();
|
|
39169
39889
|
return;
|
|
39170
39890
|
}
|
|
39171
39891
|
if (target.platform === "windows") {
|
|
39172
|
-
|
|
39892
|
+
spawn4("cmd.exe", ["/c", "start", "", paths.executablePath], { detached: true, stdio: "ignore" }).unref();
|
|
39173
39893
|
return;
|
|
39174
39894
|
}
|
|
39175
|
-
|
|
39895
|
+
spawn4(paths.executablePath, [], { detached: true, stdio: "ignore" }).unref();
|
|
39176
39896
|
}
|
|
39177
39897
|
async function writeInstallMetadata(paths, releaseTag, assetName, assetChecksum, assetKind = "full") {
|
|
39178
|
-
|
|
39898
|
+
mkdirSync3(path28.dirname(paths.metadataPath), { recursive: true });
|
|
39179
39899
|
const metadata = {
|
|
39180
39900
|
version: 1,
|
|
39181
39901
|
releaseTag,
|
|
@@ -39184,8 +39904,8 @@ async function writeInstallMetadata(paths, releaseTag, assetName, assetChecksum,
|
|
|
39184
39904
|
assetKind,
|
|
39185
39905
|
installedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
39186
39906
|
};
|
|
39187
|
-
|
|
39188
|
-
await
|
|
39907
|
+
mkdirSync3(paths.installRoot, { recursive: true });
|
|
39908
|
+
await writeFile4(paths.metadataPath, `${JSON.stringify(metadata, null, 2)}
|
|
39189
39909
|
`, "utf8");
|
|
39190
39910
|
}
|
|
39191
39911
|
async function runStartPhase(message, successMessage, task, progressPhase) {
|
|
@@ -39214,10 +39934,27 @@ async function runStartPhase(message, successMessage, task, progressPhase) {
|
|
|
39214
39934
|
}
|
|
39215
39935
|
}
|
|
39216
39936
|
async function startCommand(opts) {
|
|
39217
|
-
|
|
39937
|
+
applyLocalEnvProfile(opts);
|
|
39938
|
+
applyDataDirOverride(opts);
|
|
39218
39939
|
const serverOnly = opts.serverOnly === true;
|
|
39219
|
-
const
|
|
39220
|
-
const
|
|
39940
|
+
const installApp = !serverOnly && opts.desktop !== false;
|
|
39941
|
+
const requestedDesktopMode = parseDesktopLaunchMode(opts.desktopMode);
|
|
39942
|
+
const desktopTarget = installApp ? resolveDesktopAssetTarget() : null;
|
|
39943
|
+
const automaticCompatibilityCheck = requestedDesktopMode === "auto" && opts.desktopMode !== void 0;
|
|
39944
|
+
const smartAppControlState = desktopTarget?.platform === "windows" && automaticCompatibilityCheck ? detectSmartAppControlState() : "unknown";
|
|
39945
|
+
const desktopMode = installApp ? resolveDesktopLaunchMode({
|
|
39946
|
+
requested: requestedDesktopMode,
|
|
39947
|
+
platform: process.platform,
|
|
39948
|
+
smartAppControlState
|
|
39949
|
+
}) : "native";
|
|
39950
|
+
if (desktopMode === "browser" && desktopTarget?.platform !== "windows") {
|
|
39951
|
+
throw new Error("Rudder browser-app compatibility mode is currently available only on Windows.");
|
|
39952
|
+
}
|
|
39953
|
+
const installDesktop = installApp && desktopMode === "native";
|
|
39954
|
+
const installBrowserApp = installApp && desktopMode === "browser";
|
|
39955
|
+
const browserLocalProfile = installBrowserApp ? resolveActiveLocalEnvProfile() ?? applyLocalEnvProfile({ localEnv: "prod_local" }) : null;
|
|
39956
|
+
const installCli = opts.cli !== false || installBrowserApp;
|
|
39957
|
+
const installRuntime = opts.runtime !== false || installBrowserApp;
|
|
39221
39958
|
const repo = opts.repo?.trim() || DEFAULT_DESKTOP_RELEASE_REPO;
|
|
39222
39959
|
const version = opts.targetVersion?.trim() || opts.version?.trim() || resolveCurrentCliVersion();
|
|
39223
39960
|
const dryRun = opts.dryRun === true;
|
|
@@ -39231,7 +39968,7 @@ async function startCommand(opts) {
|
|
|
39231
39968
|
if (!exactDesktopAssetPath || !exactDesktopAssetChecksum || !exactDesktopAssetName || !exactDesktopReleaseDigest) {
|
|
39232
39969
|
throw new Error("Exact Desktop asset mode requires path, checksum, asset name, and release digest.");
|
|
39233
39970
|
}
|
|
39234
|
-
if (!
|
|
39971
|
+
if (!path28.isAbsolute(exactDesktopAssetPath) || exactDesktopAssetName.includes("/") || !/^[a-f0-9]{64}$/iu.test(exactDesktopAssetChecksum) || !/^[a-f0-9]{64}$/iu.test(exactDesktopReleaseDigest)) {
|
|
39235
39972
|
throw new Error("Exact Desktop asset mode received invalid candidate identity.");
|
|
39236
39973
|
}
|
|
39237
39974
|
if (opts.desktopAssetKind && opts.desktopAssetKind !== "full" && opts.desktopAssetKind !== "shell") {
|
|
@@ -39244,10 +39981,20 @@ async function startCommand(opts) {
|
|
|
39244
39981
|
if (error.code !== "EPIPE") throw error;
|
|
39245
39982
|
});
|
|
39246
39983
|
}
|
|
39247
|
-
if (!installCli && !
|
|
39984
|
+
if (!installCli && !installApp && !installRuntime) {
|
|
39248
39985
|
throw new Error("Nothing to start. Remove --no-cli, --no-runtime, --no-desktop, or --server-only.");
|
|
39249
39986
|
}
|
|
39250
39987
|
p15.intro(pc14.bgCyan(pc14.black(serverOnly ? " rudder start --server-only " : " rudder start ")));
|
|
39988
|
+
if (installBrowserApp) {
|
|
39989
|
+
p15.log.warn(
|
|
39990
|
+
requestedDesktopMode === "browser" ? "Using the requested Windows browser-app compatibility mode." : "Windows Smart App Control is on, so Rudder will use browser-app compatibility mode instead of the unsigned Desktop executable."
|
|
39991
|
+
);
|
|
39992
|
+
p15.log.message(
|
|
39993
|
+
pc14.dim(
|
|
39994
|
+
"This is a loopback-only local_trusted client without the packaged Desktop Account Gate. Local data stays in place; Electron-only Browser and App Builder bridges are unavailable."
|
|
39995
|
+
)
|
|
39996
|
+
);
|
|
39997
|
+
}
|
|
39251
39998
|
if (opts.versionCheck !== false) {
|
|
39252
39999
|
const updateNotice = await getCliUpdateNotice(version);
|
|
39253
40000
|
if (updateNotice) p15.log.warn(updateNotice);
|
|
@@ -39339,15 +40086,86 @@ async function startCommand(opts) {
|
|
|
39339
40086
|
spinner3.stop(`${pc14.cyan("rudder")} CLI installed.`);
|
|
39340
40087
|
}
|
|
39341
40088
|
}
|
|
40089
|
+
if (installBrowserApp) {
|
|
40090
|
+
const target = desktopTarget;
|
|
40091
|
+
const installRoot = opts.desktopInstallDir ? path28.resolve(opts.desktopInstallDir) : resolveDefaultDesktopInstallRoot(target);
|
|
40092
|
+
const installPaths = resolveDesktopInstallPaths(target, installRoot);
|
|
40093
|
+
const runtimeVersion = version;
|
|
40094
|
+
if (!browserLocalProfile) throw new Error("Rudder browser-app requires a local environment profile.");
|
|
40095
|
+
const dataDir = resolveRudderHomeDir();
|
|
40096
|
+
p15.log.step("Preparing Windows browser app");
|
|
40097
|
+
p15.log.message(`Runtime: ${pc14.cyan(runtimeVersion)}`);
|
|
40098
|
+
p15.log.message(`Workspace: ${pc14.cyan(`${browserLocalProfile.name}/${browserLocalProfile.instanceId}`)}`);
|
|
40099
|
+
if (dryRun) {
|
|
40100
|
+
p15.log.message(
|
|
40101
|
+
`[dry-run] Would create a Rudder Start Menu shortcut backed by Node and open the local workspace in Microsoft Edge app mode.`
|
|
40102
|
+
);
|
|
40103
|
+
p15.outro(pc14.green("Dry run complete."));
|
|
40104
|
+
return;
|
|
40105
|
+
}
|
|
40106
|
+
const cliEntryPath = resolveGlobalInstalledCliEntry();
|
|
40107
|
+
if (!await pathExists2(cliEntryPath)) {
|
|
40108
|
+
throw new Error(`Persistent Rudder CLI entry was not found at ${cliEntryPath}.`);
|
|
40109
|
+
}
|
|
40110
|
+
await mkdir4(installRoot, { recursive: true });
|
|
40111
|
+
const edgePath = resolveEdgeExecutable();
|
|
40112
|
+
const nativeIconPath = await pathExists2(installPaths.executablePath) ? installPaths.executablePath : null;
|
|
40113
|
+
const shortcutPath = createWindowsBrowserAppShortcut({
|
|
40114
|
+
nodePath: process.execPath,
|
|
40115
|
+
cliEntryPath,
|
|
40116
|
+
localEnv: browserLocalProfile.name,
|
|
40117
|
+
dataDir,
|
|
40118
|
+
runtimeVersion,
|
|
40119
|
+
workingDirectory: installRoot,
|
|
40120
|
+
iconPath: nativeIconPath ?? edgePath
|
|
40121
|
+
});
|
|
40122
|
+
p15.log.success(`Rudder browser-app shortcut is ready at ${pc14.cyan(shortcutPath)}.`);
|
|
40123
|
+
let applySignalController = null;
|
|
40124
|
+
if (desktopProgressJson && opts.desktopWaitForApply === true) {
|
|
40125
|
+
writeDesktopProgress({
|
|
40126
|
+
phase: "ready_to_install",
|
|
40127
|
+
message: "Windows browser-app compatibility mode is ready.",
|
|
40128
|
+
percent: 100
|
|
40129
|
+
});
|
|
40130
|
+
applySignalController = createDesktopApplySignalController();
|
|
40131
|
+
await applySignalController.waitForInitialSignal();
|
|
40132
|
+
applySignalController.close();
|
|
40133
|
+
writeDesktopProgress({
|
|
40134
|
+
phase: "preparing_restart",
|
|
40135
|
+
message: "Starting the Windows browser app...",
|
|
40136
|
+
percent: 100
|
|
40137
|
+
});
|
|
40138
|
+
}
|
|
40139
|
+
if (opts.open !== false) {
|
|
40140
|
+
const launch = await launchDetachedBrowserApp({
|
|
40141
|
+
cliEntryPath,
|
|
40142
|
+
localEnv: browserLocalProfile.name,
|
|
40143
|
+
dataDir,
|
|
40144
|
+
runtimeVersion,
|
|
40145
|
+
open: true
|
|
40146
|
+
});
|
|
40147
|
+
p15.log.success(`Rudder browser app opened at ${pc14.cyan(launch.boardUrl)}.`);
|
|
40148
|
+
p15.log.message(pc14.dim(`Background runtime log: ${launch.logPath}`));
|
|
40149
|
+
if (desktopProgressJson) {
|
|
40150
|
+
writeDesktopProgress({
|
|
40151
|
+
phase: "closing",
|
|
40152
|
+
message: "Rudder browser app is ready. You can close the native Desktop window.",
|
|
40153
|
+
percent: 100
|
|
40154
|
+
});
|
|
40155
|
+
}
|
|
40156
|
+
}
|
|
40157
|
+
p15.outro(pc14.green("Rudder start complete."));
|
|
40158
|
+
return;
|
|
40159
|
+
}
|
|
39342
40160
|
if (installDesktop) {
|
|
39343
40161
|
const downloadSource = resolveDesktopDownloadSource(opts.downloadSource);
|
|
39344
40162
|
const mirrorBaseUrl = resolveDesktopReleaseMirrorBaseUrl(repo);
|
|
39345
40163
|
const smokeReleaseBaseUrls = resolveDesktopSmokeReleaseBaseUrls();
|
|
39346
|
-
const target =
|
|
40164
|
+
const target = desktopTarget;
|
|
39347
40165
|
const tag = resolveDesktopReleaseTag(version);
|
|
39348
|
-
const installRoot = opts.desktopInstallDir ?
|
|
40166
|
+
const installRoot = opts.desktopInstallDir ? path28.resolve(opts.desktopInstallDir) : resolveDefaultDesktopInstallRoot(target);
|
|
39349
40167
|
const installPaths = resolveDesktopInstallPaths(target, installRoot);
|
|
39350
|
-
const outputDir = opts.outputDir ?
|
|
40168
|
+
const outputDir = opts.outputDir ? path28.resolve(opts.outputDir) : await mkdtemp2(path28.join(tmpdir2(), "rudder-desktop-installer."));
|
|
39351
40169
|
p15.log.step("Installing desktop app");
|
|
39352
40170
|
p15.log.message(`Release: ${pc14.cyan(`${repo}@${tag}`)}`);
|
|
39353
40171
|
p15.log.message(`Target: ${pc14.cyan(`${target.platform}/${target.arch}`)}`);
|
|
@@ -39393,7 +40211,7 @@ async function startCommand(opts) {
|
|
|
39393
40211
|
if (linkDescriptor.isSymbolicLink()) throw new Error("Exact Desktop asset must not be a symbolic link.");
|
|
39394
40212
|
const checksum = await runStartPhase(
|
|
39395
40213
|
"Verifying staged Desktop checksum...",
|
|
39396
|
-
`Verified ${pc14.cyan(
|
|
40214
|
+
`Verified ${pc14.cyan(path28.basename(exactDesktopAssetPath))}.`,
|
|
39397
40215
|
() => assertChecksumMatch(exactDesktopAssetPath, expectedChecksum),
|
|
39398
40216
|
desktopProgressJson ? "verifying_checksum" : null
|
|
39399
40217
|
);
|
|
@@ -39512,7 +40330,7 @@ async function startCommand(opts) {
|
|
|
39512
40330
|
}
|
|
39513
40331
|
const checksum = await runStartPhase(
|
|
39514
40332
|
"Verifying Desktop checksum...",
|
|
39515
|
-
`Verified ${pc14.cyan(
|
|
40333
|
+
`Verified ${pc14.cyan(path28.basename(verifiedAsset.path))}.`,
|
|
39516
40334
|
() => assertChecksumMatch(verifiedAsset.path, expectedChecksum),
|
|
39517
40335
|
desktopProgressJson ? "verifying_checksum" : null
|
|
39518
40336
|
);
|
|
@@ -39524,7 +40342,7 @@ async function startCommand(opts) {
|
|
|
39524
40342
|
assetName: selectedAsset.name,
|
|
39525
40343
|
assetChecksum: checksum,
|
|
39526
40344
|
assetKind: selectedAssetKind,
|
|
39527
|
-
stagedArtifactPath:
|
|
40345
|
+
stagedArtifactPath: path28.resolve(verifiedAsset.path),
|
|
39528
40346
|
stagedArtifactDigest: checksum,
|
|
39529
40347
|
releaseDigest: createHash5("sha256").update(JSON.stringify({
|
|
39530
40348
|
releaseTag,
|
|
@@ -39615,31 +40433,6 @@ async function startCommand(opts) {
|
|
|
39615
40433
|
p15.outro(pc14.green("Rudder start complete."));
|
|
39616
40434
|
}
|
|
39617
40435
|
|
|
39618
|
-
// src/config/data-dir.ts
|
|
39619
|
-
init_home();
|
|
39620
|
-
import path25 from "node:path";
|
|
39621
|
-
function applyDataDirOverride(options, support = {}) {
|
|
39622
|
-
const rawDataDir = options.dataDir?.trim();
|
|
39623
|
-
if (!rawDataDir) return null;
|
|
39624
|
-
const resolvedDataDir = path25.resolve(expandHomePrefix(rawDataDir));
|
|
39625
|
-
process.env.RUDDER_HOME = resolvedDataDir;
|
|
39626
|
-
if (support.hasConfigOption) {
|
|
39627
|
-
const hasConfigOverride = Boolean(options.config?.trim()) || Boolean(process.env.RUDDER_CONFIG?.trim());
|
|
39628
|
-
if (!hasConfigOverride) {
|
|
39629
|
-
const instanceId = resolveRudderInstanceId(options.instance);
|
|
39630
|
-
process.env.RUDDER_INSTANCE_ID = instanceId;
|
|
39631
|
-
process.env.RUDDER_CONFIG = resolveDefaultConfigPath(instanceId);
|
|
39632
|
-
}
|
|
39633
|
-
}
|
|
39634
|
-
if (support.hasContextOption) {
|
|
39635
|
-
const hasContextOverride = Boolean(options.context?.trim()) || Boolean(process.env.RUDDER_CONTEXT?.trim());
|
|
39636
|
-
if (!hasContextOverride) {
|
|
39637
|
-
process.env.RUDDER_CONTEXT = resolveDefaultContextPath();
|
|
39638
|
-
}
|
|
39639
|
-
}
|
|
39640
|
-
return resolvedDataDir;
|
|
39641
|
-
}
|
|
39642
|
-
|
|
39643
40436
|
// src/program.ts
|
|
39644
40437
|
init_env();
|
|
39645
40438
|
init_local_env();
|
|
@@ -39681,7 +40474,8 @@ function createProgram() {
|
|
|
39681
40474
|
});
|
|
39682
40475
|
loadRudderEnvFile(options.config);
|
|
39683
40476
|
});
|
|
39684
|
-
program.command("start").description("Start Rudder Desktop and prepare the matching persistent CLI").option("--server-only", "Prepare the Rudder server runtime and persistent CLI without installing Desktop").option("--no-cli", "Skip persistent CLI installation").option("--no-runtime", "Skip Rudder runtime installation").option("--no-desktop", "Skip desktop app installation").option("--version <version>", "Rudder version to start (default: current CLI version)").option("--target-version <version>", "Rudder version to start; avoids the root CLI version flag").option("--repo <owner/repo>", "GitHub repository that hosts desktop releases").option("--download-source <source>", "Desktop download source: auto, cn, or global").option("--output-dir <path>", "Directory for downloaded desktop release assets").option("--desktop-install-dir <path>", "Directory for the portable Desktop install").option("--no-open", "Install Desktop without launching it").option("--wait-for-active-runs", "Wait for active Rudder runs to finish before replacing Desktop", false).option("--desktop-progress-json", "Emit newline-delimited Desktop update progress events").option("--desktop-wait-for-apply", "Wait for an apply signal after downloading and verifying the Desktop update", false).option("--desktop-prepare-only", "Download and verify the Desktop update without installing or launching it", false).option("--desktop-asset-path <path>", "Use one previously staged, exact Desktop asset path").option("--desktop-asset-checksum <sha256>", "SHA-256 for the exact staged Desktop asset").option("--desktop-asset-name <name>", "Asset name bound to the exact staged Desktop candidate").option("--desktop-asset-kind <kind>", "Asset kind bound to the exact staged Desktop candidate (full or shell)").option("--desktop-release-digest <sha256>", "Release digest bound to the exact staged Desktop candidate").addOption(new Option("--desktop-runtime-best-effort").hideHelp()).option("--no-version-check", "Skip checking npm for a newer Rudder CLI version").option("--dry-run", "Print the start actions without changing the machine", false).action(startCommand);
|
|
40477
|
+
program.command("start").description("Start Rudder Desktop and prepare the matching persistent CLI").option("--server-only", "Prepare the Rudder server runtime and persistent CLI without installing Desktop").option("--no-cli", "Skip persistent CLI installation").option("--no-runtime", "Skip Rudder runtime installation").option("--no-desktop", "Skip desktop app installation").option("--version <version>", "Rudder version to start (default: current CLI version)").option("--target-version <version>", "Rudder version to start; avoids the root CLI version flag").option("--repo <owner/repo>", "GitHub repository that hosts desktop releases").option("--download-source <source>", "Desktop download source: auto, cn, or global").option("--output-dir <path>", "Directory for downloaded desktop release assets").option("--desktop-install-dir <path>", "Directory for the portable Desktop install").option("--desktop-mode <mode>", "Desktop launch mode: auto, native, or browser", "auto").option("-d, --data-dir <path>", DATA_DIR_OPTION_HELP).option("--no-open", "Install Desktop without launching it").option("--wait-for-active-runs", "Wait for active Rudder runs to finish before replacing Desktop", false).option("--desktop-progress-json", "Emit newline-delimited Desktop update progress events").option("--desktop-wait-for-apply", "Wait for an apply signal after downloading and verifying the Desktop update", false).option("--desktop-prepare-only", "Download and verify the Desktop update without installing or launching it", false).option("--desktop-asset-path <path>", "Use one previously staged, exact Desktop asset path").option("--desktop-asset-checksum <sha256>", "SHA-256 for the exact staged Desktop asset").option("--desktop-asset-name <name>", "Asset name bound to the exact staged Desktop candidate").option("--desktop-asset-kind <kind>", "Asset kind bound to the exact staged Desktop candidate (full or shell)").option("--desktop-release-digest <sha256>", "Release digest bound to the exact staged Desktop candidate").addOption(new Option("--desktop-runtime-best-effort").hideHelp()).option("--no-version-check", "Skip checking npm for a newer Rudder CLI version").option("--dry-run", "Print the start actions without changing the machine", false).action(startCommand);
|
|
40478
|
+
program.command("browser-app").description("Open Rudder in a system browser app window").option("--runtime-version <version>", "Rudder server runtime version").option("-d, --data-dir <path>", DATA_DIR_OPTION_HELP).option("--child", "Run the hidden browser-app server child", false).option("--ready-file <path>", "Internal startup handoff file").option("--no-open", "Start or attach to the local runtime without opening the app window").action(browserAppCommand);
|
|
39685
40479
|
program.command("onboard").description("Interactive first-run setup wizard").option("-c, --config <path>", "Path to config file").option("-d, --data-dir <path>", DATA_DIR_OPTION_HELP).option("-y, --yes", "Accept defaults (quickstart + start immediately)", false).option("--run", "Start Rudder immediately after saving config", false).action(onboard);
|
|
39686
40480
|
program.command("doctor").description("Run diagnostic checks on your Rudder setup").option("-c, --config <path>", "Path to config file").option("-d, --data-dir <path>", DATA_DIR_OPTION_HELP).option("--repair", "Attempt to repair issues automatically").alias("--fix").option("-y, --yes", "Skip repair confirmation prompts").action(async (opts) => {
|
|
39687
40481
|
await doctor(opts);
|