@applitools/utils
Advanced tools
| "use strict"; | ||
| // Pure, platform-agnostic helpers for computing the resident memory of a process | ||
| // tree. No Node imports — safe to use from both the Node and browser entry points. | ||
| // The OS-specific data collection (reading /proc, spawning `ps`/PowerShell) lives | ||
| // in `process.ts`; these functions only PARSE that data and sum the tree. | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| exports.sumTreeRss = exports.parseWindowsCimJson = exports.parsePosixPsOutput = exports.parseLinuxStatus = void 0; | ||
| /** Parse a single `/proc/<pid>/status` blob (linux). VmRSS is reported in kB. */ | ||
| function parseLinuxStatus(statusText) { | ||
| const ppidMatch = statusText.match(/^PPid:\s+(\d+)/m); | ||
| const rssMatch = statusText.match(/^VmRSS:\s+(\d+)\s*kB/m); | ||
| if (!ppidMatch) | ||
| return null; | ||
| return { ppid: Number(ppidMatch[1]), rss: rssMatch ? Number(rssMatch[1]) * 1024 : 0 }; | ||
| } | ||
| exports.parseLinuxStatus = parseLinuxStatus; | ||
| /** Parse `ps -A -o pid=,ppid=,rss=` output (macOS / posix). rss is reported in kB. */ | ||
| function parsePosixPsOutput(stdout) { | ||
| const table = new Map(); | ||
| for (const line of stdout.split('\n')) { | ||
| const match = line.trim().match(/^(\d+)\s+(\d+)\s+(\d+)$/); | ||
| if (!match) | ||
| continue; | ||
| table.set(Number(match[1]), { ppid: Number(match[2]), rss: Number(match[3]) * 1024 }); | ||
| } | ||
| return table; | ||
| } | ||
| exports.parsePosixPsOutput = parsePosixPsOutput; | ||
| /** Parse `Get-CimInstance Win32_Process | ConvertTo-Json` output (windows). WorkingSetSize is bytes. */ | ||
| function parseWindowsCimJson(stdout) { | ||
| const parsed = JSON.parse(stdout); | ||
| const rows = Array.isArray(parsed) ? parsed : [parsed]; | ||
| const table = new Map(); | ||
| for (const row of rows) { | ||
| if (!row || row.ProcessId == null) | ||
| continue; | ||
| table.set(Number(row.ProcessId), { | ||
| ppid: Number(row.ParentProcessId), | ||
| rss: Number(row.WorkingSetSize) || 0, | ||
| }); | ||
| } | ||
| return table; | ||
| } | ||
| exports.parseWindowsCimJson = parseWindowsCimJson; | ||
| /** Sum rss (bytes) of `rootPid` and all transitive descendants. Cycle-safe. */ | ||
| function sumTreeRss(table, rootPid) { | ||
| const childrenOf = new Map(); | ||
| for (const [pid, { ppid }] of table) { | ||
| if (!childrenOf.has(ppid)) | ||
| childrenOf.set(ppid, []); | ||
| childrenOf.get(ppid).push(pid); | ||
| } | ||
| let total = 0; | ||
| const seen = new Set(); | ||
| const stack = [rootPid]; | ||
| while (stack.length) { | ||
| const pid = stack.pop(); | ||
| if (seen.has(pid)) | ||
| continue; | ||
| seen.add(pid); | ||
| const info = table.get(pid); | ||
| if (info) | ||
| total += info.rss; | ||
| const kids = childrenOf.get(pid); | ||
| if (kids) | ||
| for (const kid of kids) | ||
| if (!seen.has(kid)) | ||
| stack.push(kid); | ||
| } | ||
| return total; | ||
| } | ||
| exports.sumTreeRss = sumTreeRss; |
| export type ProcessTableEntry = { | ||
| ppid: number; | ||
| rss: number; | ||
| }; | ||
| export type ProcessTable = Map<number, ProcessTableEntry>; | ||
| /** Parse a single `/proc/<pid>/status` blob (linux). VmRSS is reported in kB. */ | ||
| export declare function parseLinuxStatus(statusText: string): ProcessTableEntry | null; | ||
| /** Parse `ps -A -o pid=,ppid=,rss=` output (macOS / posix). rss is reported in kB. */ | ||
| export declare function parsePosixPsOutput(stdout: string): ProcessTable; | ||
| /** Parse `Get-CimInstance Win32_Process | ConvertTo-Json` output (windows). WorkingSetSize is bytes. */ | ||
| export declare function parseWindowsCimJson(stdout: string): ProcessTable; | ||
| /** Sum rss (bytes) of `rootPid` and all transitive descendants. Cycle-safe. */ | ||
| export declare function sumTreeRss(table: ProcessTable, rootPid: number): number; |
+7
-0
| # Changelog | ||
| ## [1.15.0](https://github.com/Applitools-Dev/sdk/compare/js/utils@1.14.5...js/utils@1.15.0) (2026-06-18) | ||
| ### Features | ||
| * one-time per-execution summary logEvent in storybook | AD-14305 ([#3911](https://github.com/Applitools-Dev/sdk/issues/3911)) ([59e3a5d](https://github.com/Applitools-Dev/sdk/commit/59e3a5dccf74aa1ac1158024316bd305e3515afa)) | ||
| ## [1.14.5](https://github.com/Applitools-Dev/sdk/compare/js/utils@1.14.4...js/utils@1.14.5) (2026-05-26) | ||
@@ -4,0 +11,0 @@ |
| "use strict"; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| exports.sh = exports.executeProcess = exports.executeAndControlProcess = exports.execute = void 0; | ||
| exports.sampleProcessTreeMemory = exports.sh = exports.executeProcess = exports.executeAndControlProcess = exports.execute = void 0; | ||
| const executionOutput = { | ||
@@ -32,1 +32,7 @@ stdout: '', | ||
| exports.sh = sh; | ||
| // A browser cannot read OS process trees — always resolves "unknown". | ||
| // eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
| async function sampleProcessTreeMemory(_rootPid, _options = {}) { | ||
| return null; | ||
| } | ||
| exports.sampleProcessTreeMemory = sampleProcessTreeMemory; |
+78
-1
| "use strict"; | ||
| Object.defineProperty(exports, "__esModule", { value: true }); | ||
| exports.execute = exports.sh = exports.executeProcess = exports.executeAndControlProcess = void 0; | ||
| exports.sampleProcessTreeMemory = exports.execute = exports.sh = exports.executeProcess = exports.executeAndControlProcess = void 0; | ||
| const child_process_1 = require("child_process"); | ||
| const fs_1 = require("fs"); | ||
| const util_1 = require("util"); | ||
| const process_tree_1 = require("./process-tree"); | ||
| const execFileAsync = (0, util_1.promisify)(child_process_1.execFile); | ||
| const PROCESS_TABLE_EXEC_OPTS = { timeout: 10000, maxBuffer: 16 * 1024 * 1024, windowsHide: true }; | ||
| function makeError(error, properties) { | ||
@@ -80,1 +84,74 @@ if (typeof error === 'string') { | ||
| exports.execute = execute; | ||
| /** | ||
| * Best-effort resident memory (bytes) of `rootPid` and all of its descendant | ||
| * processes — approximates the real RAM a multi-process app (e.g. a Chromium | ||
| * browser: browser + renderers + GPU) consumes, which the V8 JS heap does NOT. | ||
| * | ||
| * Purely additive observability: resolves to `null` on ANY failure (unsupported | ||
| * platform, parse/permission error, missing tools, root process already gone). | ||
| * Never throws to the caller. Browser builds always resolve `null`. | ||
| */ | ||
| async function sampleProcessTreeMemory(rootPid, options = {}) { | ||
| var _a; | ||
| if (!rootPid || !Number.isInteger(rootPid)) | ||
| return null; | ||
| try { | ||
| const table = await getProcessTable(); | ||
| if (!table || table.size === 0) | ||
| return null; | ||
| // root gone (e.g. browser already closed) → report "unknown", not a misleading 0 | ||
| if (!table.has(rootPid)) | ||
| return null; | ||
| return (0, process_tree_1.sumTreeRss)(table, rootPid); | ||
| } | ||
| catch (err) { | ||
| (_a = options.logger) === null || _a === void 0 ? void 0 : _a.log(`[process-tree-memory] failed to sample: ${err && err.message}`); | ||
| return null; | ||
| } | ||
| } | ||
| exports.sampleProcessTreeMemory = sampleProcessTreeMemory; | ||
| async function getProcessTable() { | ||
| switch (process.platform) { | ||
| case 'linux': | ||
| return getProcessTableLinux(); | ||
| case 'win32': | ||
| return getProcessTableWindows(); | ||
| case 'darwin': | ||
| return getProcessTablePosixPs(); | ||
| default: | ||
| // best-effort: assume a posix-like `ps` on any other platform | ||
| return getProcessTablePosixPs(); | ||
| } | ||
| } | ||
| // Linux: read /proc/<pid>/status for PPid + VmRSS. No subprocess spawn. | ||
| async function getProcessTableLinux() { | ||
| const table = new Map(); | ||
| const entries = await fs_1.promises.readdir('/proc'); | ||
| await Promise.all(entries.map(async (entry) => { | ||
| const pid = Number(entry); | ||
| if (!Number.isInteger(pid) || pid <= 0) | ||
| return; | ||
| try { | ||
| const parsed = (0, process_tree_1.parseLinuxStatus)(await fs_1.promises.readFile(`/proc/${pid}/status`, 'utf8')); | ||
| if (parsed) | ||
| table.set(pid, parsed); | ||
| } | ||
| catch { | ||
| // process may have exited between readdir and readFile — ignore it | ||
| } | ||
| })); | ||
| return table; | ||
| } | ||
| // macOS / other posix: `ps -A -o pid=,ppid=,rss=` (rss in kB). | ||
| async function getProcessTablePosixPs() { | ||
| const { stdout } = await execFileAsync('ps', ['-A', '-o', 'pid=,ppid=,rss='], PROCESS_TABLE_EXEC_OPTS); | ||
| return (0, process_tree_1.parsePosixPsOutput)(stdout); | ||
| } | ||
| // Windows: PowerShell + CIM (WorkingSetSize is bytes). Works where wmic is removed. | ||
| async function getProcessTableWindows() { | ||
| const psCommand = 'Get-CimInstance Win32_Process | ' + | ||
| 'Select-Object ProcessId,ParentProcessId,WorkingSetSize | ' + | ||
| 'ConvertTo-Json -Compress'; | ||
| const { stdout } = await execFileAsync('powershell.exe', ['-NoProfile', '-NonInteractive', '-Command', psCommand], PROCESS_TABLE_EXEC_OPTS); | ||
| return (0, process_tree_1.parseWindowsCimJson)(stdout); | ||
| } |
+1
-1
| { | ||
| "name": "@applitools/utils", | ||
| "version": "1.14.5", | ||
| "version": "1.15.0", | ||
| "keywords": [ | ||
@@ -5,0 +5,0 @@ "applitools", |
@@ -35,1 +35,6 @@ /// <reference types="node" /> | ||
| }>; | ||
| export declare function sampleProcessTreeMemory(_rootPid: number, _options?: { | ||
| logger?: { | ||
| log: (...args: any[]) => void; | ||
| }; | ||
| }): Promise<number | null>; |
+14
-0
@@ -23,1 +23,15 @@ /// <reference types="node" /> | ||
| }>; | ||
| /** | ||
| * Best-effort resident memory (bytes) of `rootPid` and all of its descendant | ||
| * processes — approximates the real RAM a multi-process app (e.g. a Chromium | ||
| * browser: browser + renderers + GPU) consumes, which the V8 JS heap does NOT. | ||
| * | ||
| * Purely additive observability: resolves to `null` on ANY failure (unsupported | ||
| * platform, parse/permission error, missing tools, root process already gone). | ||
| * Never throws to the caller. Browser builds always resolve `null`. | ||
| */ | ||
| export declare function sampleProcessTreeMemory(rootPid: number, options?: { | ||
| logger?: { | ||
| log: (...args: any[]) => void; | ||
| }; | ||
| }): Promise<number | null>; |
AI-detected potential code anomaly
Supply chain riskAI has identified unusual behaviors that may pose a security risk.
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
AI-detected potential code anomaly
Supply chain riskAI has identified unusual behaviors that may pose a security risk.
Found 2 instances
116824
7.87%43
4.88%2130
9.62%12
-7.69%2
-33.33%