Big News: Socket raises $60M Series C at a $1B valuation to secure software supply chains for AI-driven development.Announcement
Sign In

@socketsecurity/lib

Package Overview
Dependencies
Maintainers
2
Versions
130
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@socketsecurity/lib - npm Package Compare versions

Comparing version
4.3.0
to
4.4.0
+22
-0
CHANGELOG.md

@@ -8,2 +8,24 @@ # Changelog

## [4.4.0](https://github.com/SocketDev/socket-lib/releases/tag/v4.4.0) - 2025-11-25
### Added
- **fs**: Exported `normalizeEncoding()` function for robust encoding string normalization
- Handles case-insensitive encoding names (e.g., 'UTF-8', 'utf8', 'UTF8')
- Supports encoding aliases (e.g., 'binary' → 'latin1', 'ucs-2' → 'utf16le')
- Fast-path optimization for common encodings
- Defaults to 'utf8' for invalid or null encodings
- Export: `@socketsecurity/lib/fs`
### Fixed
- **fs**: `safeReadFile()` and `safeReadFileSync()` type signatures and encoding handling
- Corrected type overloads: `encoding: null` → `Buffer | undefined`, no encoding → `string | undefined` (UTF-8 default)
- Fixed implementation to properly handle `encoding: null` for Buffer returns
- **suppress-warnings**: `withSuppressedWarnings()` now properly restores warning state
- Fixed state restoration to only remove warning types that were added by the function
- Prevents accidental removal of warnings that were already suppressed
- Ensures correct cleanup behavior when warning types are nested or reused
## [4.3.0](https://github.com/SocketDev/socket-lib/releases/tag/v4.3.0) - 2025-11-20

@@ -10,0 +32,0 @@

+100
-52

@@ -286,2 +286,9 @@ /**

/**
* Invalidate the cached allowed directories.
* Called automatically by the paths/rewire module when paths are overridden in tests.
*
* @internal Used for test rewiring
*/
export declare function invalidatePathCache(): void;
/**
* Check if a path is a directory asynchronously.

@@ -355,49 +362,33 @@ * Returns `true` for directories, `false` for files or non-existent paths.

/**
* Result of file readability validation.
* Contains lists of valid and invalid file paths.
*/
export interface ValidateFilesResult {
/**
* File paths that passed validation and are readable.
*/
validPaths: string[];
/**
* File paths that failed validation (unreadable, permission denied, or non-existent).
* Common with Yarn Berry PnP virtual filesystem, pnpm symlinks, or filesystem race conditions.
*/
invalidPaths: string[];
}
/**
* Validate that file paths are readable before processing.
* Filters out files from glob results that cannot be accessed (common with
* Yarn Berry PnP virtual filesystem, pnpm content-addressable store symlinks,
* or filesystem race conditions in CI/CD environments).
* Normalize encoding string to canonical form.
* Handles common encodings inline for performance, delegates to slowCases for others.
*
* This defensive pattern prevents ENOENT errors when files exist in glob
* results but are not accessible via standard filesystem operations.
* Based on Node.js internal/util.js normalizeEncoding implementation.
* @see https://github.com/nodejs/node/blob/ae62b36d442b7bf987e85ae6e0df0f02cc1bb17f/lib/internal/util.js#L247-L310
*
* @param filepaths - Array of file paths to validate
* @returns Object with `validPaths` (readable) and `invalidPaths` (unreadable)
* @param enc - Encoding to normalize (can be null/undefined)
* @returns Normalized encoding string, defaults to 'utf8'
*
* @example
* ```ts
* import { validateFiles } from '@socketsecurity/lib/fs'
* normalizeEncoding('UTF-8') // Returns 'utf8'
* normalizeEncoding('binary') // Returns 'latin1'
* normalizeEncoding('ucs-2') // Returns 'utf16le'
* normalizeEncoding(null) // Returns 'utf8'
* ```
*/
/*@__NO_SIDE_EFFECTS__*/
export declare function normalizeEncoding(enc: BufferEncoding | string | null | undefined): BufferEncoding;
/**
* Move the "slow cases" to a separate function to make sure this function gets
* inlined properly. That prioritizes the common case.
*
* const files = ['package.json', '.pnp.cjs/virtual-file.json']
* const { validPaths, invalidPaths } = validateFiles(files)
* Based on Node.js internal/util.js normalizeEncoding implementation.
* @see https://github.com/nodejs/node/blob/ae62b36d442b7bf987e85ae6e0df0f02cc1bb17f/lib/internal/util.js#L247-L310
*
* console.log(`Valid: ${validPaths.length}`)
* console.log(`Invalid: ${invalidPaths.length}`)
* ```
*
* @example
* ```ts
* // Typical usage in Socket CLI commands
* const packagePaths = await getPackageFilesForScan(targets)
* const { validPaths } = validateFiles(packagePaths)
* await sdk.uploadManifestFiles(orgSlug, validPaths)
* ```
* @param enc - Encoding to normalize
* @returns Normalized encoding string, defaults to 'utf8' for unknown encodings
*/
/*@__NO_SIDE_EFFECTS__*/
export declare function validateFiles(filepaths: string[] | readonly string[]): ValidateFilesResult;
export declare function normalizeEncodingSlow(enc: string): BufferEncoding;
/**

@@ -591,9 +582,2 @@ * Read directory names asynchronously with filtering and sorting.

/**
* Invalidate the cached allowed directories.
* Called automatically by the paths/rewire module when paths are overridden in tests.
*
* @internal Used for test rewiring
*/
export declare function invalidatePathCache(): void;
/**
* Safely delete a file or directory asynchronously with built-in protections.

@@ -713,10 +697,11 @@ * Uses `del` for safer deletion that prevents removing cwd and above by default.

* Returns undefined for any error (file not found, permission denied, etc.).
* Defaults to UTF-8 encoding, returning a string unless encoding is explicitly set to null.
*
* @param filepath - Path to file
* @param options - Read options including encoding and default value
* @returns Promise resolving to file contents, or undefined on error
* @returns Promise resolving to file contents (string by default), or undefined on error
*
* @example
* ```ts
* // Try to read a file, get undefined if it doesn't exist
* // Try to read a file as UTF-8 string (default), get undefined if it doesn't exist
* const content = await safeReadFile('./optional-config.txt')

@@ -729,6 +714,13 @@ * if (content) {

* const data = await safeReadFile('./data.txt', { encoding: 'utf8' })
*
* // Read as Buffer by setting encoding to null
* const buffer = await safeReadFile('./binary.dat', { encoding: null })
* ```
*/
/*@__NO_SIDE_EFFECTS__*/
export declare function safeReadFile(filepath: PathLike, options?: SafeReadOptions | undefined): Promise<NonSharedBuffer>;
export declare function safeReadFile(filepath: PathLike, options: SafeReadOptions & {
encoding: null;
}): Promise<Buffer | undefined>;
/*@__NO_SIDE_EFFECTS__*/
export declare function safeReadFile(filepath: PathLike, options?: SafeReadOptions | undefined): Promise<string | undefined>;
/**

@@ -738,10 +730,11 @@ * Safely read a file synchronously, returning undefined on error.

* Returns undefined for any error (file not found, permission denied, etc.).
* Defaults to UTF-8 encoding, returning a string unless encoding is explicitly set to null.
*
* @param filepath - Path to file
* @param options - Read options including encoding and default value
* @returns File contents, or undefined on error
* @returns File contents (string by default), or undefined on error
*
* @example
* ```ts
* // Try to read a config file
* // Try to read a config file as UTF-8 string (default)
* const config = safeReadFileSync('./config.txt')

@@ -752,3 +745,6 @@ * if (config) {

*
* // Read binary file safely
* // Read with explicit encoding
* const data = safeReadFileSync('./data.txt', { encoding: 'utf8' })
*
* // Read binary file by setting encoding to null
* const buffer = safeReadFileSync('./image.png', { encoding: null })

@@ -758,3 +754,7 @@ * ```

/*@__NO_SIDE_EFFECTS__*/
export declare function safeReadFileSync(filepath: PathLike, options?: SafeReadOptions | undefined): string | NonSharedBuffer;
export declare function safeReadFileSync(filepath: PathLike, options: SafeReadOptions & {
encoding: null;
}): Buffer | undefined;
/*@__NO_SIDE_EFFECTS__*/
export declare function safeReadFileSync(filepath: PathLike, options?: SafeReadOptions | undefined): string | undefined;
/**

@@ -824,2 +824,50 @@ * Safely get file stats asynchronously, returning undefined on error.

/**
* Result of file readability validation.
* Contains lists of valid and invalid file paths.
*/
export interface ValidateFilesResult {
/**
* File paths that passed validation and are readable.
*/
validPaths: string[];
/**
* File paths that failed validation (unreadable, permission denied, or non-existent).
* Common with Yarn Berry PnP virtual filesystem, pnpm symlinks, or filesystem race conditions.
*/
invalidPaths: string[];
}
/**
* Validate that file paths are readable before processing.
* Filters out files from glob results that cannot be accessed (common with
* Yarn Berry PnP virtual filesystem, pnpm content-addressable store symlinks,
* or filesystem race conditions in CI/CD environments).
*
* This defensive pattern prevents ENOENT errors when files exist in glob
* results but are not accessible via standard filesystem operations.
*
* @param filepaths - Array of file paths to validate
* @returns Object with `validPaths` (readable) and `invalidPaths` (unreadable)
*
* @example
* ```ts
* import { validateFiles } from '@socketsecurity/lib/fs'
*
* const files = ['package.json', '.pnp.cjs/virtual-file.json']
* const { validPaths, invalidPaths } = validateFiles(files)
*
* console.log(`Valid: ${validPaths.length}`)
* console.log(`Invalid: ${invalidPaths.length}`)
* ```
*
* @example
* ```ts
* // Typical usage in Socket CLI commands
* const packagePaths = await getPackageFilesForScan(targets)
* const { validPaths } = validateFiles(packagePaths)
* await sdk.uploadManifestFiles(orgSlug, validPaths)
* ```
*/
/*@__NO_SIDE_EFFECTS__*/
export declare function validateFiles(filepaths: string[] | readonly string[]): ValidateFilesResult;
/**
* Write JSON content to a file asynchronously with formatting.

@@ -826,0 +874,0 @@ * Stringifies the value with configurable indentation and line endings.

+146
-38

@@ -29,2 +29,4 @@ "use strict";

isSymLinkSync: () => isSymLinkSync,
normalizeEncoding: () => normalizeEncoding,
normalizeEncodingSlow: () => normalizeEncodingSlow,
readDirNames: () => readDirNames,

@@ -70,2 +72,22 @@ readDirNamesSync: () => readDirNamesSync,

});
let _cachedAllowedDirs;
function getAllowedDirectories() {
if (_cachedAllowedDirs === void 0) {
const path = /* @__PURE__ */ getPath();
_cachedAllowedDirs = [
path.resolve((0, import_socket.getOsTmpDir)()),
path.resolve((0, import_socket.getSocketCacacheDir)()),
path.resolve((0, import_socket.getSocketUserDir)())
];
}
return _cachedAllowedDirs;
}
let _buffer;
// @__NO_SIDE_EFFECTS__
function getBuffer() {
if (_buffer === void 0) {
_buffer = require("node:buffer");
}
return _buffer;
}
let _fs;

@@ -206,2 +228,6 @@ // @__NO_SIDE_EFFECTS__

}
function invalidatePathCache() {
_cachedAllowedDirs = void 0;
}
(0, import_rewire.registerCacheInvalidation)(invalidatePathCache);
// @__NO_SIDE_EFFECTS__

@@ -256,16 +282,71 @@ async function isDir(filepath) {

// @__NO_SIDE_EFFECTS__
function validateFiles(filepaths) {
const fs = /* @__PURE__ */ getFs();
const validPaths = [];
const invalidPaths = [];
const { R_OK } = fs.constants;
for (const filepath of filepaths) {
try {
fs.accessSync(filepath, R_OK);
validPaths.push(filepath);
} catch {
invalidPaths.push(filepath);
function normalizeEncoding(enc) {
return enc == null || enc === "utf8" || enc === "utf-8" ? "utf8" : /* @__PURE__ */ normalizeEncodingSlow(enc);
}
// @__NO_SIDE_EFFECTS__
function normalizeEncodingSlow(enc) {
const { length } = enc;
if (length === 4) {
if (enc === "ucs2" || enc === "UCS2") {
return "utf16le";
}
if (enc.toLowerCase() === "ucs2") {
return "utf16le";
}
} else if (length === 3 && enc === "hex" || enc === "HEX" || enc.toLowerCase() === "hex") {
return "hex";
} else if (length === 5) {
if (enc === "ascii") {
return "ascii";
}
if (enc === "ucs-2") {
return "utf16le";
}
if (enc === "ASCII") {
return "ascii";
}
if (enc === "UCS-2") {
return "utf16le";
}
enc = enc.toLowerCase();
if (enc === "ascii") {
return "ascii";
}
if (enc === "ucs-2") {
return "utf16le";
}
} else if (length === 6) {
if (enc === "base64") {
return "base64";
}
if (enc === "latin1" || enc === "binary") {
return "latin1";
}
if (enc === "BASE64") {
return "base64";
}
if (enc === "LATIN1" || enc === "BINARY") {
return "latin1";
}
enc = enc.toLowerCase();
if (enc === "base64") {
return "base64";
}
if (enc === "latin1" || enc === "binary") {
return "latin1";
}
} else if (length === 7) {
if (enc === "utf16le" || enc === "UTF16LE" || enc.toLowerCase() === "utf16le") {
return "utf16le";
}
} else if (length === 8) {
if (enc === "utf-16le" || enc === "UTF-16LE" || enc.toLowerCase() === "utf-16le") {
return "utf16le";
}
} else if (length === 9) {
if (enc === "base64url" || enc === "BASE64URL" || enc.toLowerCase() === "base64url") {
return "base64url";
}
}
return { __proto__: null, validPaths, invalidPaths };
return "utf8";
}

@@ -357,4 +438,4 @@ // @__NO_SIDE_EFFECTS__

__proto__: null,
encoding: "utf8",
...fsOptions
...fsOptions,
encoding: "utf8"
});

@@ -401,4 +482,4 @@ } catch (e) {

__proto__: null,
encoding: "utf8",
...fsOptions
...fsOptions,
encoding: "utf8"
});

@@ -432,18 +513,2 @@ } catch (e) {

}
let _cachedAllowedDirs;
function getAllowedDirectories() {
if (_cachedAllowedDirs === void 0) {
const path = /* @__PURE__ */ getPath();
_cachedAllowedDirs = [
path.resolve((0, import_socket.getOsTmpDir)()),
path.resolve((0, import_socket.getSocketCacacheDir)()),
path.resolve((0, import_socket.getSocketUserDir)())
];
}
return _cachedAllowedDirs;
}
function invalidatePathCache() {
_cachedAllowedDirs = void 0;
}
(0, import_rewire.registerCacheInvalidation)(invalidatePathCache);
async function safeDelete(filepath, options) {

@@ -533,16 +598,33 @@ const opts = { __proto__: null, ...options };

async function safeReadFile(filepath, options) {
const opts = typeof options === "string" ? { encoding: options } : options;
const opts = typeof options === "string" ? { __proto__: null, encoding: options } : { __proto__: null, ...options };
const { defaultValue, ...rawReadOpts } = opts;
const readOpts = { __proto__: null, ...rawReadOpts };
const shouldReturnBuffer = readOpts.encoding === null;
const encoding = shouldReturnBuffer ? null : /* @__PURE__ */ normalizeEncoding(readOpts.encoding);
const fs = /* @__PURE__ */ getFs();
try {
return await fs.promises.readFile(filepath, {
__proto__: null,
signal: abortSignal,
...opts
...readOpts,
encoding
});
} catch {
}
return void 0;
if (defaultValue === void 0) {
return void 0;
}
if (shouldReturnBuffer) {
const { Buffer: Buffer2 } = /* @__PURE__ */ getBuffer();
return Buffer2.isBuffer(defaultValue) ? defaultValue : void 0;
}
return typeof defaultValue === "string" ? defaultValue : String(defaultValue);
}
// @__NO_SIDE_EFFECTS__
function safeReadFileSync(filepath, options) {
const opts = typeof options === "string" ? { encoding: options } : options;
const opts = typeof options === "string" ? { __proto__: null, encoding: options } : { __proto__: null, ...options };
const { defaultValue, ...rawReadOpts } = opts;
const readOpts = { __proto__: null, ...rawReadOpts };
const shouldReturnBuffer = readOpts.encoding === null;
const encoding = shouldReturnBuffer ? null : /* @__PURE__ */ normalizeEncoding(readOpts.encoding);
const fs = /* @__PURE__ */ getFs();

@@ -552,7 +634,15 @@ try {

__proto__: null,
...opts
...readOpts,
encoding
});
} catch {
}
return void 0;
if (defaultValue === void 0) {
return void 0;
}
if (shouldReturnBuffer) {
const { Buffer: Buffer2 } = /* @__PURE__ */ getBuffer();
return Buffer2.isBuffer(defaultValue) ? defaultValue : void 0;
}
return typeof defaultValue === "string" ? defaultValue : String(defaultValue);
}

@@ -601,2 +691,18 @@ // @__NO_SIDE_EFFECTS__

}
// @__NO_SIDE_EFFECTS__
function validateFiles(filepaths) {
const fs = /* @__PURE__ */ getFs();
const validPaths = [];
const invalidPaths = [];
const { R_OK } = fs.constants;
for (const filepath of filepaths) {
try {
fs.accessSync(filepath, R_OK);
validPaths.push(filepath);
} catch {
invalidPaths.push(filepath);
}
}
return { __proto__: null, validPaths, invalidPaths };
}
async function writeJson(filepath, jsonContent, options) {

@@ -651,2 +757,4 @@ const opts = typeof options === "string" ? { encoding: options } : options;

isSymLinkSync,
normalizeEncoding,
normalizeEncodingSlow,
readDirNames,

@@ -653,0 +761,0 @@ readDirNamesSync,

@@ -59,29 +59,2 @@ // Type definitions

/**
* Create a lazy getter function that memoizes its result.
*
* The returned function will only call the getter once, caching the result
* for subsequent calls. This is useful for expensive computations or
* operations that should only happen when needed.
*
* @param name - The property key name for the getter (used for debugging and stats)
* @param getter - Function that computes the value on first access
* @param stats - Optional stats object to track initialization
* @returns A memoized getter function
*
* @example
* ```ts
* const stats = { initialized: new Set() }
* const getLargeData = createLazyGetter('data', () => {
* console.log('Computing expensive data...')
* return { large: 'dataset' }
* }, stats)
*
* getLargeData() // Logs "Computing expensive data..." and returns data
* getLargeData() // Returns cached data without logging
* console.log(stats.initialized.has('data')) // true
* ```
*/
/*@__NO_SIDE_EFFECTS__*/
export declare function createLazyGetter<T>(name: PropertyKey, getter: () => T, stats?: LazyGetterStats | undefined): () => T;
/**
* Create a frozen constants object with lazy getters and internal properties.

@@ -125,2 +98,29 @@ *

/**
* Create a lazy getter function that memoizes its result.
*
* The returned function will only call the getter once, caching the result
* for subsequent calls. This is useful for expensive computations or
* operations that should only happen when needed.
*
* @param name - The property key name for the getter (used for debugging and stats)
* @param getter - Function that computes the value on first access
* @param stats - Optional stats object to track initialization
* @returns A memoized getter function
*
* @example
* ```ts
* const stats = { initialized: new Set() }
* const getLargeData = createLazyGetter('data', () => {
* console.log('Computing expensive data...')
* return { large: 'dataset' }
* }, stats)
*
* getLargeData() // Logs "Computing expensive data..." and returns data
* getLargeData() // Returns cached data without logging
* console.log(stats.initialized.has('data')) // true
* ```
*/
/*@__NO_SIDE_EFFECTS__*/
export declare function createLazyGetter<T>(name: PropertyKey, getter: () => T, stats?: LazyGetterStats | undefined): () => T;
/**
* Define a getter property on an object.

@@ -399,2 +399,36 @@ *

/**
* Deep merge source object into target object.
*
* Recursively merges properties from `source` into `target`. Arrays in source
* completely replace arrays in target (no element-wise merging). Objects are
* merged recursively. Includes infinite loop detection for safety.
*
* @param target - The object to merge into (will be modified)
* @param source - The object to merge from
* @returns The modified target object
*
* @example
* ```ts
* const target = { a: { x: 1 }, b: [1, 2] }
* const source = { a: { y: 2 }, b: [3, 4, 5], c: 3 }
* merge(target, source)
* // { a: { x: 1, y: 2 }, b: [3, 4, 5], c: 3 }
* ```
*
* @example
* ```ts
* // Arrays are replaced, not merged
* merge({ arr: [1, 2] }, { arr: [3] }) // { arr: [3] }
*
* // Deep object merging
* merge(
* { config: { api: 'v1', timeout: 1000 } },
* { config: { api: 'v2', retries: 3 } }
* )
* // { config: { api: 'v2', timeout: 1000, retries: 3 } }
* ```
*/
/*@__NO_SIDE_EFFECTS__*/
export declare function merge<T extends object, U extends object>(target: T, source: U): T & U;
/**
* Get all own property entries (key-value pairs) from an object.

@@ -445,36 +479,2 @@ *

/**
* Deep merge source object into target object.
*
* Recursively merges properties from `source` into `target`. Arrays in source
* completely replace arrays in target (no element-wise merging). Objects are
* merged recursively. Includes infinite loop detection for safety.
*
* @param target - The object to merge into (will be modified)
* @param source - The object to merge from
* @returns The modified target object
*
* @example
* ```ts
* const target = { a: { x: 1 }, b: [1, 2] }
* const source = { a: { y: 2 }, b: [3, 4, 5], c: 3 }
* merge(target, source)
* // { a: { x: 1, y: 2 }, b: [3, 4, 5], c: 3 }
* ```
*
* @example
* ```ts
* // Arrays are replaced, not merged
* merge({ arr: [1, 2] }, { arr: [3] }) // { arr: [3] }
*
* // Deep object merging
* merge(
* { config: { api: 'v1', timeout: 1000 } },
* { config: { api: 'v2', retries: 3 } }
* )
* // { config: { api: 'v2', timeout: 1000, retries: 3 } }
* ```
*/
/*@__NO_SIDE_EFFECTS__*/
export declare function merge<T extends object, U extends object>(target: T, source: U): T & U;
/**
* Convert an object to a new object with sorted keys.

@@ -481,0 +481,0 @@ *

@@ -59,16 +59,2 @@ "use strict";

// @__NO_SIDE_EFFECTS__
function createLazyGetter(name, getter, stats) {
let lazyValue = import_core.UNDEFINED_TOKEN;
const { [name]: lazyGetter } = {
[name]() {
if (lazyValue === import_core.UNDEFINED_TOKEN) {
stats?.initialized?.add(name);
lazyValue = getter();
}
return lazyValue;
}
};
return lazyGetter;
}
// @__NO_SIDE_EFFECTS__
function createConstantsObject(props, options_) {

@@ -127,2 +113,16 @@ const options = { __proto__: null, ...options_ };

}
// @__NO_SIDE_EFFECTS__
function createLazyGetter(name, getter, stats) {
let lazyValue = import_core.UNDEFINED_TOKEN;
const { [name]: lazyGetter } = {
[name]() {
if (lazyValue === import_core.UNDEFINED_TOKEN) {
stats?.initialized?.add(name);
lazyValue = getter();
}
return lazyValue;
}
};
return lazyGetter;
}
function defineGetter(object, propKey, getter) {

@@ -214,18 +214,2 @@ ObjectDefineProperty(object, propKey, {

// @__NO_SIDE_EFFECTS__
function objectEntries(obj) {
if (obj === null || obj === void 0) {
return [];
}
const keys = ReflectOwnKeys(obj);
const { length } = keys;
const entries = Array(length);
const record = obj;
for (let i = 0; i < length; i += 1) {
const key = keys[i];
entries[i] = [key, record[key]];
}
return entries;
}
const objectFreeze = Object.freeze;
// @__NO_SIDE_EFFECTS__
function merge(target, source) {

@@ -272,2 +256,18 @@ if (!/* @__PURE__ */ isObject(target) || !/* @__PURE__ */ isObject(source)) {

// @__NO_SIDE_EFFECTS__
function objectEntries(obj) {
if (obj === null || obj === void 0) {
return [];
}
const keys = ReflectOwnKeys(obj);
const { length } = keys;
const entries = Array(length);
const record = obj;
for (let i = 0; i < length; i += 1) {
const key = keys[i];
entries[i] = [key, record[key]];
}
return entries;
}
const objectFreeze = Object.freeze;
// @__NO_SIDE_EFFECTS__
function toSortedObject(obj) {

@@ -274,0 +274,0 @@ return /* @__PURE__ */ toSortedObjectFromEntries(/* @__PURE__ */ objectEntries(obj));

@@ -212,21 +212,2 @@ /**

/**
* Resolve retry options from various input formats.
*
* Converts shorthand and partial options into a base configuration that can be
* further normalized. This is an internal helper for option processing.
*
* @param options - Retry count as number, or partial options object, or undefined
* @returns Resolved retry options with defaults for basic properties
*
* @example
* resolveRetryOptions(3)
* // => { retries: 3, minTimeout: 200, maxTimeout: 10000, factor: 2 }
*
* @example
* resolveRetryOptions({ retries: 5, maxTimeout: 5000 })
* // => { retries: 5, minTimeout: 200, maxTimeout: 5000, factor: 2 }
*/
/*@__NO_SIDE_EFFECTS__*/
export declare function resolveRetryOptions(options?: number | RetryOptions | undefined): RetryOptions;
/**
* Execute an async function for each array element with concurrency control.

@@ -459,1 +440,20 @@ *

export declare function pRetry<T>(callbackFn: (...args: unknown[]) => Promise<T>, options?: number | RetryOptions | undefined): Promise<T | undefined>;
/**
* Resolve retry options from various input formats.
*
* Converts shorthand and partial options into a base configuration that can be
* further normalized. This is an internal helper for option processing.
*
* @param options - Retry count as number, or partial options object, or undefined
* @returns Resolved retry options with defaults for basic properties
*
* @example
* resolveRetryOptions(3)
* // => { retries: 3, minTimeout: 200, maxTimeout: 10000, factor: 2 }
*
* @example
* resolveRetryOptions({ retries: 5, maxTimeout: 5000 })
* // => { retries: 5, minTimeout: 200, maxTimeout: 5000, factor: 2 }
*/
/*@__NO_SIDE_EFFECTS__*/
export declare function resolveRetryOptions(options?: number | RetryOptions | undefined): RetryOptions;

@@ -104,16 +104,2 @@ "use strict";

// @__NO_SIDE_EFFECTS__
function resolveRetryOptions(options) {
const defaults = {
__proto__: null,
retries: 0,
baseDelayMs: 200,
maxDelayMs: 1e4,
backoffFactor: 2
};
if (typeof options === "number") {
return { ...defaults, retries: options };
}
return options ? { ...defaults, ...options } : defaults;
}
// @__NO_SIDE_EFFECTS__
async function pEach(array, callbackFn, options) {

@@ -263,2 +249,16 @@ const iterOpts = /* @__PURE__ */ normalizeIterationOptions(options);

}
// @__NO_SIDE_EFFECTS__
function resolveRetryOptions(options) {
const defaults = {
__proto__: null,
retries: 0,
baseDelayMs: 200,
maxDelayMs: 1e4,
backoffFactor: 2
};
if (typeof options === "number") {
return { ...defaults, retries: options };
}
return options ? { ...defaults, ...options } : defaults;
}
// Annotate the CommonJS export names for ESM import in node:

@@ -265,0 +265,0 @@ 0 && (module.exports = {

/**
* Compare semantic versions.
*/
/*@__NO_SIDE_EFFECTS__*/
export declare function compareSemver(a: string, b: string): number;
/**
* Simple string comparison.
*/
/*@__NO_SIDE_EFFECTS__*/
export declare function compareStr(a: string, b: string): number;
/**
* Compare two strings using locale-aware comparison.

@@ -18,12 +28,2 @@ */

export declare function naturalSorter<T>(arrayToSort: T[]): ReturnType<FastSortFunction>;
/**
* Simple string comparison.
*/
/*@__NO_SIDE_EFFECTS__*/
export declare function compareStr(a: string, b: string): number;
/**
* Compare semantic versions.
*/
/*@__NO_SIDE_EFFECTS__*/
export declare function compareSemver(a: string, b: string): number;
export {};

@@ -41,2 +41,21 @@ "use strict";

var semver = __toESM(require("./external/semver.js"));
// @__NO_SIDE_EFFECTS__
function compareSemver(a, b) {
const validA = semver.valid(a);
const validB = semver.valid(b);
if (!validA && !validB) {
return 0;
}
if (!validA) {
return -1;
}
if (!validB) {
return 1;
}
return semver.compare(a, b);
}
// @__NO_SIDE_EFFECTS__
function compareStr(a, b) {
return a < b ? -1 : a > b ? 1 : 0;
}
let _localeCompare;

@@ -81,21 +100,2 @@ // @__NO_SIDE_EFFECTS__

}
// @__NO_SIDE_EFFECTS__
function compareStr(a, b) {
return a < b ? -1 : a > b ? 1 : 0;
}
// @__NO_SIDE_EFFECTS__
function compareSemver(a, b) {
const validA = semver.valid(a);
const validB = semver.valid(b);
if (!validA && !validB) {
return 0;
}
if (!validA) {
return -1;
}
if (!validB) {
return 1;
}
return semver.compare(a, b);
}
// Annotate the CommonJS export names for ESM import in node:

@@ -102,0 +102,0 @@ 0 && (module.exports = {

@@ -88,2 +88,37 @@ /**

export declare function camelToKebab(str: string): string;
/**
* Center text within a given width.
*
* Adds spaces before and after the text to center it within the specified width.
* Distributes padding evenly on both sides. When the padding is odd, the extra
* space is added to the right side. Strips ANSI codes before calculating text
* length to ensure accurate centering of colored text.
*
* If the text is already wider than or equal to the target width, returns the
* original text unchanged (no truncation occurs).
*
* @param text - The text to center (may include ANSI codes)
* @param width - The target width in columns
* @returns The centered text with padding
*
* @example
* ```ts
* centerText('hello', 11)
* // Returns: ' hello ' (3 spaces on each side)
*
* centerText('hi', 10)
* // Returns: ' hi ' (4 spaces on each side)
*
* centerText('odd', 8)
* // Returns: ' odd ' (2 left, 3 right)
*
* centerText('\x1b[31mred\x1b[0m', 7)
* // Returns: ' \x1b[31mred\x1b[0m ' (ANSI codes preserved, 'red' centered)
*
* centerText('too long text', 5)
* // Returns: 'too long text' (no truncation, returned as-is)
* ```
*/
/*@__NO_SIDE_EFFECTS__*/
export declare function centerText(text: string, width: number): string;
export interface IndentStringOptions {

@@ -185,2 +220,29 @@ /**

export declare function isNonEmptyString(value: unknown): value is Exclude<string, EmptyString>;
/**
* Repeat a string a specified number of times.
*
* Creates a new string by repeating the input string `count` times.
* Returns an empty string if count is 0 or negative.
*
* @param str - The string to repeat
* @param count - The number of times to repeat the string
* @returns The repeated string, or empty string if count <= 0
*
* @example
* ```ts
* repeatString('hello', 3)
* // Returns: 'hellohellohello'
*
* repeatString('x', 5)
* // Returns: 'xxxxx'
*
* repeatString('hello', 0)
* // Returns: ''
*
* repeatString('hello', -1)
* // Returns: ''
* ```
*/
/*@__NO_SIDE_EFFECTS__*/
export declare function repeatString(str: string, count: number): string;
export interface SearchOptions {

@@ -257,2 +319,3 @@ /**

export declare function stripBom(str: string): string;
/* c8 ignore stop */
/**

@@ -409,64 +472,1 @@ * Get the visual width of a string in terminal columns.

export declare function trimNewlines(str: string): string;
/**
* Repeat a string n times.
*
* Creates a new string by repeating the input string the specified number of times.
* Returns an empty string if count is zero or negative. This is a simple wrapper
* around `String.prototype.repeat()` with guard for non-positive counts.
*
* @param str - The string to repeat
* @param count - The number of times to repeat the string
* @returns The repeated string, or empty string if count <= 0
*
* @example
* ```ts
* repeatString('hello', 3)
* // Returns: 'hellohellohello'
*
* repeatString('x', 5)
* // Returns: 'xxxxx'
*
* repeatString('hello', 0)
* // Returns: ''
*
* repeatString('hello', -1)
* // Returns: ''
* ```
*/
/*@__NO_SIDE_EFFECTS__*/
export declare function repeatString(str: string, count: number): string;
/**
* Center text within a given width.
*
* Adds spaces before and after the text to center it within the specified width.
* Distributes padding evenly on both sides. When the padding is odd, the extra
* space is added to the right side. Strips ANSI codes before calculating text
* length to ensure accurate centering of colored text.
*
* If the text is already wider than or equal to the target width, returns the
* original text unchanged (no truncation occurs).
*
* @param text - The text to center (may include ANSI codes)
* @param width - The target width in columns
* @returns The centered text with padding
*
* @example
* ```ts
* centerText('hello', 11)
* // Returns: ' hello ' (3 spaces on each side)
*
* centerText('hi', 10)
* // Returns: ' hi ' (4 spaces on each side)
*
* centerText('odd', 8)
* // Returns: ' odd ' (2 left, 3 right)
*
* centerText('\x1b[31mred\x1b[0m', 7)
* // Returns: ' \x1b[31mred\x1b[0m ' (ANSI codes preserved, 'red' centered)
*
* centerText('too long text', 5)
* // Returns: 'too long text' (no truncation, returned as-is)
* ```
*/
/*@__NO_SIDE_EFFECTS__*/
export declare function centerText(text: string, width: number): string;

@@ -95,2 +95,13 @@ "use strict";

// @__NO_SIDE_EFFECTS__
function centerText(text, width) {
const textLength = (0, import_ansi.stripAnsi)(text).length;
if (textLength >= width) {
return text;
}
const padding = width - textLength;
const leftPad = Math.floor(padding / 2);
const rightPad = padding - leftPad;
return " ".repeat(leftPad) + text + " ".repeat(rightPad);
}
// @__NO_SIDE_EFFECTS__
function indentString(str, options) {

@@ -109,2 +120,9 @@ const { count = 1 } = { __proto__: null, ...options };

// @__NO_SIDE_EFFECTS__
function repeatString(str, count) {
if (count <= 0) {
return "";
}
return str.repeat(count);
}
// @__NO_SIDE_EFFECTS__
function search(str, regexp, options) {

@@ -220,20 +238,2 @@ const { fromIndex = 0 } = { __proto__: null, ...options };

}
// @__NO_SIDE_EFFECTS__
function repeatString(str, count) {
if (count <= 0) {
return "";
}
return str.repeat(count);
}
// @__NO_SIDE_EFFECTS__
function centerText(text, width) {
const textLength = (0, import_ansi.stripAnsi)(text).length;
if (textLength >= width) {
return text;
}
const padding = width - textLength;
const leftPad = Math.floor(padding / 2);
const rightPad = padding - leftPad;
return " ".repeat(leftPad) + text + " ".repeat(rightPad);
}
// Annotate the CommonJS export names for ESM import in node:

@@ -240,0 +240,0 @@ 0 && (module.exports = {

@@ -85,2 +85,3 @@ "use strict";

async function withSuppressedWarnings(warningType, callback) {
const wasAlreadySuppressed = suppressedWarnings.has(warningType);
const original = process.emitWarning;

@@ -91,2 +92,5 @@ suppressWarningType(warningType);

} finally {
if (!wasAlreadySuppressed) {
suppressedWarnings.delete(warningType);
}
process.emitWarning = original;

@@ -93,0 +97,0 @@ }

{
"name": "@socketsecurity/lib",
"version": "4.3.0",
"version": "4.4.0",
"packageManager": "pnpm@10.22.0",

@@ -693,3 +693,3 @@ "license": "MIT",

"@socketregistry/yocto-spinner": "1.0.25",
"@socketsecurity/lib-stable": "npm:@socketsecurity/lib@4.1.0",
"@socketsecurity/lib-stable": "npm:@socketsecurity/lib@4.3.0",
"@types/node": "24.9.2",

@@ -696,0 +696,0 @@ "@typescript/native-preview": "7.0.0-dev.20250920.1",

@@ -5,3 +5,3 @@ # @socketsecurity/lib

[![CI](https://github.com/SocketDev/socket-lib/actions/workflows/ci.yml/badge.svg)](https://github.com/SocketDev/socket-lib/actions/workflows/ci.yml)
![Coverage](https://img.shields.io/badge/coverage-84.12%25-brightgreen)
![Coverage](https://img.shields.io/badge/coverage-83.78%25-brightgreen)

@@ -8,0 +8,0 @@ [![Follow @SocketSecurity](https://img.shields.io/twitter/follow/SocketSecurity?style=social)](https://twitter.com/SocketSecurity)