@tapi-dev/sdk 0.1.31 → 0.1.33
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +54 -73
- package/package.json +1 -1
package/dist/cli.d.ts
CHANGED
|
@@ -85,6 +85,7 @@ export declare function trySelectDevSessionInOpenStudio(session: TapiDevSession,
|
|
|
85
85
|
baseUrl?: string;
|
|
86
86
|
reason?: string;
|
|
87
87
|
}>;
|
|
88
|
+
export declare function servicePowerShell(action: string): string;
|
|
88
89
|
export declare function installedServiceVersionFromPathName(pathName: string): string | undefined;
|
|
89
90
|
export declare function serviceNeedsInstall(status: ServiceStatus, manifest: ServiceReleaseManifest): boolean;
|
|
90
91
|
export declare function getDefaultStudioCacheDir(): string;
|
package/dist/cli.js
CHANGED
|
@@ -28,6 +28,8 @@ const DOWNLOAD_PROGRESS_LOG_BYTES = 50 * 1024 * 1024;
|
|
|
28
28
|
const MAX_WIDE_EVENT_PROCESS_ROOTS = 5;
|
|
29
29
|
const MAX_NONCURRENT_MANAGED_DOWNLOADS = 0;
|
|
30
30
|
const MAX_NONCURRENT_MANAGED_RELEASES = 0;
|
|
31
|
+
const WINDOWS_SERVICE_STATUS_TIMEOUT_MS = 8_000;
|
|
32
|
+
const WINDOWS_SERVICE_COMMAND_TIMEOUT_MS = 30_000;
|
|
31
33
|
const MANAGED_RELEASE_MARKER = ".tapi-managed-release";
|
|
32
34
|
const MIN_EXTRACTION_REQUIRED_BYTES = 1024 * 1024 * 1024;
|
|
33
35
|
const EXTRACTION_REQUIRED_MULTIPLIER = 3;
|
|
@@ -1351,7 +1353,7 @@ async function runServiceCommand(action, args = []) {
|
|
|
1351
1353
|
return repairService(parseStudioOptions([]));
|
|
1352
1354
|
}
|
|
1353
1355
|
const command = servicePowerShell(normalized);
|
|
1354
|
-
const output = await withCliSpinner(`Running tapi-service ${normalized}`, () => runProcessCapture("powershell.exe", ["-NoProfile", "-ExecutionPolicy", "Bypass", "-Command", command]));
|
|
1356
|
+
const output = await withCliSpinner(`Running tapi-service ${normalized}`, () => runProcessCapture("powershell.exe", ["-NoProfile", "-ExecutionPolicy", "Bypass", "-Command", command], { timeoutMs: WINDOWS_SERVICE_COMMAND_TIMEOUT_MS }));
|
|
1355
1357
|
if (output.trim()) {
|
|
1356
1358
|
console.log(output.trim());
|
|
1357
1359
|
}
|
|
@@ -1369,9 +1371,9 @@ async function repairService(options) {
|
|
|
1369
1371
|
}
|
|
1370
1372
|
return runServiceCommand("restart");
|
|
1371
1373
|
}
|
|
1372
|
-
function servicePowerShell(action) {
|
|
1374
|
+
export function servicePowerShell(action) {
|
|
1373
1375
|
const serviceName = "tapi-service";
|
|
1374
|
-
const status = `$svc = Get-Service -Name '${serviceName}' -ErrorAction SilentlyContinue; if ($null -eq $svc) { [pscustomobject]@{ installed = $false; name = '${serviceName}'; status = 'not_installed'; pathName = '' } | ConvertTo-Json -Compress; exit 0 }; $
|
|
1376
|
+
const status = `$svc = Get-Service -Name '${serviceName}' -ErrorAction SilentlyContinue; if ($null -eq $svc) { [pscustomobject]@{ installed = $false; name = '${serviceName}'; status = 'not_installed'; pathName = '' } | ConvertTo-Json -Compress; exit 0 }; $pathName = ''; try { $imagePath = (Get-ItemProperty -LiteralPath 'HKLM:\\SYSTEM\\CurrentControlSet\\Services\\${serviceName}' -Name ImagePath -ErrorAction SilentlyContinue).ImagePath; if ($null -ne $imagePath) { $pathName = [string]$imagePath } } catch {}; [pscustomobject]@{ installed = $true; name = $svc.Name; status = $svc.Status.ToString(); pathName = $pathName } | ConvertTo-Json -Compress`;
|
|
1375
1377
|
if (action === "status") {
|
|
1376
1378
|
return status;
|
|
1377
1379
|
}
|
|
@@ -1393,7 +1395,7 @@ async function getServiceStatus() {
|
|
|
1393
1395
|
"Bypass",
|
|
1394
1396
|
"-Command",
|
|
1395
1397
|
servicePowerShell("status"),
|
|
1396
|
-
]);
|
|
1398
|
+
], { timeoutMs: WINDOWS_SERVICE_STATUS_TIMEOUT_MS });
|
|
1397
1399
|
try {
|
|
1398
1400
|
const payload = JSON.parse(output.trim());
|
|
1399
1401
|
return {
|
|
@@ -1436,7 +1438,7 @@ async function ensureServiceReadyForStudio(options) {
|
|
|
1436
1438
|
"Bypass",
|
|
1437
1439
|
"-Command",
|
|
1438
1440
|
servicePowerShell("start"),
|
|
1439
|
-
]));
|
|
1441
|
+
], { timeoutMs: WINDOWS_SERVICE_COMMAND_TIMEOUT_MS }));
|
|
1440
1442
|
if (output.trim()) {
|
|
1441
1443
|
console.log(output.trim());
|
|
1442
1444
|
}
|
|
@@ -2434,54 +2436,9 @@ async function isPortAvailable(port) {
|
|
|
2434
2436
|
});
|
|
2435
2437
|
}
|
|
2436
2438
|
async function reapPortableStudioServersBlockingPorts(preferred, count) {
|
|
2437
|
-
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
const start = Math.max(1, Math.min(65535, Math.trunc(preferred)));
|
|
2441
|
-
const end = Math.max(start, Math.min(65535, start + Math.max(1, Math.trunc(count)) - 1));
|
|
2442
|
-
const script = `
|
|
2443
|
-
$ErrorActionPreference = 'SilentlyContinue'
|
|
2444
|
-
$ports = ${start}..${end}
|
|
2445
|
-
$connections = @(Get-NetTCPConnection -State Listen | Where-Object { $ports -contains $_.LocalPort })
|
|
2446
|
-
$owners = @{}
|
|
2447
|
-
foreach ($conn in $connections) {
|
|
2448
|
-
$pidValue = [int]$conn.OwningProcess
|
|
2449
|
-
if ($pidValue -le 0 -or $owners.ContainsKey($pidValue)) { continue }
|
|
2450
|
-
$proc = Get-CimInstance Win32_Process -Filter "ProcessId=$pidValue"
|
|
2451
|
-
if ($null -eq $proc) { continue }
|
|
2452
|
-
$path = [string]$proc.ExecutablePath
|
|
2453
|
-
$cmd = [string]$proc.CommandLine
|
|
2454
|
-
$isPortableStudio = (
|
|
2455
|
-
$path -match '\\\\Tapi\\\\Studio\\\\server\\\\releases\\\\' -or
|
|
2456
|
-
$cmd -match 'tapi-studio-server'
|
|
2457
|
-
)
|
|
2458
|
-
if ($isPortableStudio) {
|
|
2459
|
-
$owners[$pidValue] = $true
|
|
2460
|
-
}
|
|
2461
|
-
}
|
|
2462
|
-
$stopped = 0
|
|
2463
|
-
foreach ($pidValue in $owners.Keys) {
|
|
2464
|
-
try {
|
|
2465
|
-
Stop-Process -Id $pidValue -Force -ErrorAction Stop
|
|
2466
|
-
$stopped += 1
|
|
2467
|
-
} catch {}
|
|
2468
|
-
}
|
|
2469
|
-
[pscustomobject]@{ stopped = $stopped } | ConvertTo-Json -Compress
|
|
2470
|
-
`;
|
|
2471
|
-
try {
|
|
2472
|
-
const output = await runProcessCapture("powershell.exe", [
|
|
2473
|
-
"-NoProfile",
|
|
2474
|
-
"-ExecutionPolicy",
|
|
2475
|
-
"Bypass",
|
|
2476
|
-
"-Command",
|
|
2477
|
-
script,
|
|
2478
|
-
]);
|
|
2479
|
-
const payload = JSON.parse(output.trim() || "{}");
|
|
2480
|
-
return typeof payload.stopped === "number" ? payload.stopped : 0;
|
|
2481
|
-
}
|
|
2482
|
-
catch {
|
|
2483
|
-
return 0;
|
|
2484
|
-
}
|
|
2439
|
+
void preferred;
|
|
2440
|
+
void count;
|
|
2441
|
+
return 0;
|
|
2485
2442
|
}
|
|
2486
2443
|
async function stopPortableStudioServerProcesses() {
|
|
2487
2444
|
if (process.platform !== "win32") {
|
|
@@ -2490,26 +2447,24 @@ async function stopPortableStudioServerProcesses() {
|
|
|
2490
2447
|
const script = `
|
|
2491
2448
|
$ErrorActionPreference = 'SilentlyContinue'
|
|
2492
2449
|
$currentPid = $PID
|
|
2493
|
-
$processes = @(Get-
|
|
2494
|
-
$pidValue = [int]$_.
|
|
2450
|
+
$processes = @(Get-Process -ErrorAction SilentlyContinue | Where-Object {
|
|
2451
|
+
$pidValue = [int]$_.Id
|
|
2495
2452
|
if ($pidValue -le 0 -or $pidValue -eq $currentPid) {
|
|
2496
2453
|
$false
|
|
2497
2454
|
} else {
|
|
2498
|
-
$path =
|
|
2499
|
-
$
|
|
2500
|
-
$name = [string]$_.
|
|
2455
|
+
$path = ''
|
|
2456
|
+
try { $path = [string]$_.Path } catch {}
|
|
2457
|
+
$name = [string]$_.ProcessName
|
|
2501
2458
|
(
|
|
2502
|
-
$name -ieq 'tapi-studio-server
|
|
2503
|
-
$path -match '\\\\Tapi\\\\Studio\\\\server\\\\releases\\\\'
|
|
2504
|
-
$cmd -match 'tapi-studio-server' -or
|
|
2505
|
-
$cmd -match 'scripts[\\\\/]studio\\.py'
|
|
2459
|
+
$name -ieq 'tapi-studio-server' -or
|
|
2460
|
+
$path -match '\\\\Tapi\\\\Studio\\\\server\\\\releases\\\\'
|
|
2506
2461
|
)
|
|
2507
2462
|
}
|
|
2508
2463
|
})
|
|
2509
2464
|
$stopped = 0
|
|
2510
2465
|
foreach ($process in $processes) {
|
|
2511
2466
|
try {
|
|
2512
|
-
Stop-Process -Id ([int]$process.
|
|
2467
|
+
Stop-Process -Id ([int]$process.Id) -Force -ErrorAction Stop
|
|
2513
2468
|
$stopped += 1
|
|
2514
2469
|
} catch {}
|
|
2515
2470
|
}
|
|
@@ -2522,7 +2477,7 @@ foreach ($process in $processes) {
|
|
|
2522
2477
|
"Bypass",
|
|
2523
2478
|
"-Command",
|
|
2524
2479
|
script,
|
|
2525
|
-
]);
|
|
2480
|
+
], { timeoutMs: WINDOWS_SERVICE_STATUS_TIMEOUT_MS });
|
|
2526
2481
|
const payload = JSON.parse(output.trim() || "{}");
|
|
2527
2482
|
return typeof payload.stopped === "number" ? payload.stopped : 0;
|
|
2528
2483
|
}
|
|
@@ -3086,7 +3041,7 @@ async function runProcess(command, args) {
|
|
|
3086
3041
|
});
|
|
3087
3042
|
});
|
|
3088
3043
|
}
|
|
3089
|
-
async function runProcessCapture(command, args) {
|
|
3044
|
+
async function runProcessCapture(command, args, options = {}) {
|
|
3090
3045
|
return await new Promise((resolvePromise, rejectPromise) => {
|
|
3091
3046
|
const child = spawn(command, args, {
|
|
3092
3047
|
stdio: ["ignore", "pipe", "pipe"],
|
|
@@ -3094,21 +3049,47 @@ async function runProcessCapture(command, args) {
|
|
|
3094
3049
|
});
|
|
3095
3050
|
let stdout = "";
|
|
3096
3051
|
let stderr = "";
|
|
3052
|
+
let timedOut = false;
|
|
3053
|
+
let settled = false;
|
|
3054
|
+
const timeoutMs = Math.max(0, options.timeoutMs ?? 0);
|
|
3055
|
+
const timeout = timeoutMs > 0
|
|
3056
|
+
? setTimeout(() => {
|
|
3057
|
+
timedOut = true;
|
|
3058
|
+
child.kill();
|
|
3059
|
+
}, timeoutMs)
|
|
3060
|
+
: undefined;
|
|
3061
|
+
timeout?.unref?.();
|
|
3062
|
+
const finish = (callback) => {
|
|
3063
|
+
if (settled) {
|
|
3064
|
+
return;
|
|
3065
|
+
}
|
|
3066
|
+
settled = true;
|
|
3067
|
+
if (timeout) {
|
|
3068
|
+
clearTimeout(timeout);
|
|
3069
|
+
}
|
|
3070
|
+
callback();
|
|
3071
|
+
};
|
|
3097
3072
|
child.stdout.on("data", (chunk) => {
|
|
3098
3073
|
stdout += String(chunk);
|
|
3099
3074
|
});
|
|
3100
3075
|
child.stderr.on("data", (chunk) => {
|
|
3101
3076
|
stderr += String(chunk);
|
|
3102
3077
|
});
|
|
3103
|
-
child.once("error", rejectPromise);
|
|
3078
|
+
child.once("error", (error) => finish(() => rejectPromise(error)));
|
|
3104
3079
|
child.once("exit", (code) => {
|
|
3105
|
-
|
|
3106
|
-
|
|
3107
|
-
|
|
3108
|
-
|
|
3109
|
-
|
|
3110
|
-
|
|
3111
|
-
|
|
3080
|
+
finish(() => {
|
|
3081
|
+
const err = stderr.trim();
|
|
3082
|
+
if (timedOut) {
|
|
3083
|
+
rejectPromise(new Error(`Process timed out after ${timeoutMs} ms: ${command} ${args.join(" ")}`));
|
|
3084
|
+
return;
|
|
3085
|
+
}
|
|
3086
|
+
if (code === 0) {
|
|
3087
|
+
resolvePromise(stdout);
|
|
3088
|
+
}
|
|
3089
|
+
else {
|
|
3090
|
+
rejectPromise(new Error(err || `Process exited with code ${code ?? "unknown"}.`));
|
|
3091
|
+
}
|
|
3092
|
+
});
|
|
3112
3093
|
});
|
|
3113
3094
|
});
|
|
3114
3095
|
}
|