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.4.0
to
5.0.0
+8
dist/constants/lifecycle-script-names.d.ts
/**
* @fileoverview NPM lifecycle script names.
*
* Standard npm lifecycle hooks that can be defined in package.json scripts.
* https://docs.npmjs.com/cli/v10/using-npm/scripts#life-cycle-scripts
*/
declare const lifecycleScriptNames: Set<string>;
export { lifecycleScriptNames };
"use strict";
/* Socket Lib - Built with esbuild */
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var lifecycle_script_names_exports = {};
__export(lifecycle_script_names_exports, {
lifecycleScriptNames: () => lifecycleScriptNames
});
module.exports = __toCommonJS(lifecycle_script_names_exports);
const lifecycleScriptNames = new Set(
[
"dependencies",
"prepublishOnly",
...[
"install",
"pack",
"prepare",
"publish",
"restart",
"start",
"stop",
"version"
].map((n) => [`pre${n}`, n, `post${n}`])
].flat()
);
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
lifecycleScriptNames
});
declare const maintainedNodeVersions: readonly string[] & {
current: string;
last: string;
next: string;
previous: string;
};
export { maintainedNodeVersions };
"use strict";
/* Socket Lib - Built with esbuild */
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var maintained_node_versions_exports = {};
__export(maintained_node_versions_exports, {
maintainedNodeVersions: () => maintainedNodeVersions
});
module.exports = __toCommonJS(maintained_node_versions_exports);
const ObjectFreeze = Object.freeze;
const next = "25.0.0";
const current = "22.20.0";
const previous = "20.19.5";
const last = "18.20.8";
const maintainedNodeVersions = ObjectFreeze(
Object.assign([last, previous, current, next], {
current,
last,
next,
previous
})
);
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
maintainedNodeVersions
});
/* c8 ignore next - External semver call */
declare const packageDefaultNodeRange: string;
export { packageDefaultNodeRange };
"use strict";
/* Socket Lib - Built with esbuild */
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var package_default_node_range_exports = {};
__export(package_default_node_range_exports, {
packageDefaultNodeRange: () => packageDefaultNodeRange
});
module.exports = __toCommonJS(package_default_node_range_exports);
var import_maintained_node_versions = require("./maintained-node-versions");
var semver = __toESM(require("../external/semver.js"));
const packageDefaultNodeRange = `>=${semver.parse(import_maintained_node_versions.maintainedNodeVersions.last).major}`;
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
packageDefaultNodeRange
});
/**
* @fileoverview Default Socket security categories for packages.
*/
// Default category for new packages
declare const packageDefaultSocketCategories: readonly string[];
export { packageDefaultSocketCategories };
"use strict";
/* Socket Lib - Built with esbuild */
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var package_default_socket_categories_exports = {};
__export(package_default_socket_categories_exports, {
packageDefaultSocketCategories: () => packageDefaultSocketCategories
});
module.exports = __toCommonJS(package_default_socket_categories_exports);
const packageDefaultSocketCategories = Object.freeze(["cleanup"]);
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
packageDefaultSocketCategories
});
import type { SpawnExtra, SpawnOptions } from '../spawn';
import { spawn } from '../spawn';
export interface DlxBinaryOptions {
/**
* URL to download the binary from.
*/
url: string;
/**
* Optional name for the cached binary (defaults to URL hash).
*/
name?: string | undefined;
/**
* Expected checksum (sha256) for verification.
*/
checksum?: string | undefined;
/**
* Cache TTL in milliseconds (default: 7 days).
*/
cacheTtl?: number | undefined;
/**
* Force re-download even if cached.
* Aligns with npm/npx --force flag.
*/
force?: boolean | undefined;
/**
* Skip confirmation prompts (auto-approve).
* Aligns with npx --yes/-y flag.
*/
yes?: boolean | undefined;
/**
* Suppress output (quiet mode).
* Aligns with npx --quiet/-q and pnpm --silent/-s flags.
*/
quiet?: boolean | undefined;
/**
* Additional spawn options.
*/
spawnOptions?: SpawnOptions | undefined;
}
export interface DlxBinaryResult {
/** Path to the cached binary. */
binaryPath: string;
/** Whether the binary was newly downloaded. */
downloaded: boolean;
/** The spawn promise for the running process. */
spawnPromise: ReturnType<typeof spawn>;
}
/**
* Metadata structure for cached binaries (.dlx-metadata.json).
* Unified schema shared across TypeScript (dlxBinary) and C++ (socket_macho_decompress).
*
* Core Fields (present in all implementations):
* - version: Schema version (currently "1.0.0")
* - cache_key: First 16 chars of SHA-512 hash (matches directory name)
* - timestamp: Unix timestamp in milliseconds
* - checksum: Full hash of cached binary (SHA-512 for C++, SHA-256 for TypeScript)
* - checksum_algorithm: "sha512" or "sha256"
* - platform: "darwin" | "linux" | "win32"
* - arch: "x64" | "arm64"
* - size: Size of cached binary in bytes
* - source: Origin information
* - type: "download" (from URL) or "decompression" (from embedded binary)
* - url: Download URL (if type is "download")
* - path: Source binary path (if type is "decompression")
*
* Extra Fields (implementation-specific):
* - For C++ decompression:
* - compressed_size: Size of compressed data in bytes
* - compression_algorithm: Brotli level (numeric)
* - compression_ratio: original_size / compressed_size
*
* Example (TypeScript download):
* ```json
* {
* "version": "1.0.0",
* "cache_key": "a1b2c3d4e5f67890",
* "timestamp": 1730332800000,
* "checksum": "sha256-abc123...",
* "checksum_algorithm": "sha256",
* "platform": "darwin",
* "arch": "arm64",
* "size": 15000000,
* "source": {
* "type": "download",
* "url": "https://example.com/binary"
* }
* }
* ```
*
* Example (C++ decompression):
* ```json
* {
* "version": "1.0.0",
* "cache_key": "0123456789abcdef",
* "timestamp": 1730332800000,
* "checksum": "sha512-def456...",
* "checksum_algorithm": "sha512",
* "platform": "darwin",
* "arch": "arm64",
* "size": 13000000,
* "source": {
* "type": "decompression",
* "path": "/usr/local/bin/socket"
* },
* "extra": {
* "compressed_size": 1700000,
* "compression_algorithm": 3,
* "compression_ratio": 7.647
* }
* }
* ```
*
* @internal This interface documents the metadata file format.
*/
export interface DlxMetadata {
version: string;
cache_key: string;
timestamp: number;
checksum: string;
checksum_algorithm: string;
platform: string;
arch: string;
size: number;
source?: {
type: 'download' | 'decompression';
url?: string;
path?: string;
};
extra?: Record<string, unknown>;
}
/**
* Clean expired entries from the DLX cache.
*/
export declare function cleanDlxCache(maxAge?: number): Promise<number>;
/**
* Download and execute a binary from a URL with caching.
*/
export declare function dlxBinary(args: readonly string[] | string[], options?: DlxBinaryOptions | undefined, spawnExtra?: SpawnExtra | undefined): Promise<DlxBinaryResult>;
/**
* Download a binary from a URL with caching (without execution).
* Similar to downloadPackage from dlx-package.
*
* @returns Object containing the path to the cached binary and whether it was downloaded
*/
export declare function downloadBinary(options: Omit<DlxBinaryOptions, 'spawnOptions'>): Promise<{
binaryPath: string;
downloaded: boolean;
}>;
/**
* Execute a cached binary without re-downloading.
* Similar to executePackage from dlx-package.
* Binary must have been previously downloaded via downloadBinary or dlxBinary.
*
* @param binaryPath Path to the cached binary (from downloadBinary result)
* @param args Arguments to pass to the binary
* @param spawnOptions Spawn options for execution
* @param spawnExtra Extra spawn configuration
* @returns The spawn promise for the running process
*/
export declare function executeBinary(binaryPath: string, args: readonly string[] | string[], spawnOptions?: SpawnOptions | undefined, spawnExtra?: SpawnExtra | undefined): ReturnType<typeof spawn>;
/**
* Get the DLX binary cache directory path.
* Returns normalized path for cross-platform compatibility.
* Uses same directory as dlx-package for unified DLX storage.
*/
export declare function getDlxCachePath(): string;
/**
* Get information about cached binaries.
*/
export declare function listDlxCache(): Promise<Array<{
age: number;
arch: string;
checksum: string;
name: string;
platform: string;
size: number;
url: string;
}>>;
"use strict";
/* Socket Lib - Built with esbuild */
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var binary_exports = {};
__export(binary_exports, {
cleanDlxCache: () => cleanDlxCache,
dlxBinary: () => dlxBinary,
downloadBinary: () => downloadBinary,
executeBinary: () => executeBinary,
getDlxCachePath: () => getDlxCachePath,
listDlxCache: () => listDlxCache
});
module.exports = __toCommonJS(binary_exports);
var import_crypto = require("crypto");
var import_os = __toESM(require("os"));
var import_path = __toESM(require("path"));
var import_platform = require("../constants/platform");
var import_time = require("../constants/time");
var import_cache = require("./cache");
var import_manifest = require("./manifest");
var import_http_request = require("../http-request");
var import_fs = require("../fs");
var import_objects = require("../objects");
var import_normalize = require("../paths/normalize");
var import_socket = require("../paths/socket");
var import_process_lock = require("../process-lock");
var import_spawn = require("../spawn");
let _fs;
// @__NO_SIDE_EFFECTS__
function getFs() {
if (_fs === void 0) {
_fs = require("node:fs");
}
return _fs;
}
function getMetadataPath(cacheEntryPath) {
return import_path.default.join(cacheEntryPath, ".dlx-metadata.json");
}
async function isCacheValid(cacheEntryPath, cacheTtl) {
const fs = /* @__PURE__ */ getFs();
try {
const metaPath = getMetadataPath(cacheEntryPath);
if (!fs.existsSync(metaPath)) {
return false;
}
const metadata = await (0, import_fs.readJson)(metaPath, { throws: false });
if (!(0, import_objects.isObjectObject)(metadata)) {
return false;
}
const now = Date.now();
const timestamp = metadata["timestamp"];
if (typeof timestamp !== "number" || timestamp <= 0) {
return false;
}
const age = now - timestamp;
return age < cacheTtl;
} catch {
return false;
}
}
async function downloadBinaryFile(url, destPath, checksum) {
const cacheEntryDir = import_path.default.dirname(destPath);
const lockPath = import_path.default.join(cacheEntryDir, "concurrency.lock");
return await import_process_lock.processLock.withLock(
lockPath,
async () => {
const fs = /* @__PURE__ */ getFs();
if (fs.existsSync(destPath)) {
const stats = await fs.promises.stat(destPath);
if (stats.size > 0) {
const fileBuffer2 = await fs.promises.readFile(destPath);
const hasher2 = (0, import_crypto.createHash)("sha256");
hasher2.update(fileBuffer2);
return hasher2.digest("hex");
}
}
try {
await (0, import_http_request.httpDownload)(url, destPath);
} catch (e) {
throw new Error(
`Failed to download binary from ${url}
Destination: ${destPath}
Check your internet connection or verify the URL is accessible.`,
{ cause: e }
);
}
const fileBuffer = await fs.promises.readFile(destPath);
const hasher = (0, import_crypto.createHash)("sha256");
hasher.update(fileBuffer);
const actualChecksum = hasher.digest("hex");
if (checksum && actualChecksum !== checksum) {
await (0, import_fs.safeDelete)(destPath);
throw new Error(
`Checksum mismatch: expected ${checksum}, got ${actualChecksum}`
);
}
if (!import_platform.WIN32) {
await fs.promises.chmod(destPath, 493);
}
return actualChecksum;
},
{
// Align with npm npx locking strategy.
staleMs: 5e3,
touchIntervalMs: 2e3
}
);
}
async function writeMetadata(cacheEntryPath, cacheKey, url, binaryName, checksum, size) {
const metaPath = getMetadataPath(cacheEntryPath);
const metadata = {
version: "1.0.0",
cache_key: cacheKey,
timestamp: Date.now(),
checksum,
checksum_algorithm: "sha256",
platform: import_os.default.platform(),
arch: import_os.default.arch(),
size,
source: {
type: "download",
url
}
};
const fs = /* @__PURE__ */ getFs();
await fs.promises.writeFile(metaPath, JSON.stringify(metadata, null, 2));
try {
const spec = `${url}:${binaryName}`;
await import_manifest.dlxManifest.setBinaryEntry(spec, cacheKey, {
checksum,
checksum_algorithm: "sha256",
platform: import_os.default.platform(),
arch: import_os.default.arch(),
size,
source: {
type: "download",
url
}
});
} catch {
}
}
async function cleanDlxCache(maxAge = import_time.DLX_BINARY_CACHE_TTL) {
const cacheDir = getDlxCachePath();
const fs = /* @__PURE__ */ getFs();
if (!fs.existsSync(cacheDir)) {
return 0;
}
let cleaned = 0;
const now = Date.now();
const entries = await fs.promises.readdir(cacheDir);
for (const entry of entries) {
const entryPath = import_path.default.join(cacheDir, entry);
const metaPath = getMetadataPath(entryPath);
try {
if (!await (0, import_fs.isDir)(entryPath)) {
continue;
}
const metadata = await (0, import_fs.readJson)(metaPath, { throws: false });
if (!metadata || typeof metadata !== "object" || Array.isArray(metadata)) {
continue;
}
const timestamp = metadata["timestamp"];
const age = typeof timestamp === "number" && timestamp > 0 ? now - timestamp : Number.POSITIVE_INFINITY;
if (age > maxAge) {
await (0, import_fs.safeDelete)(entryPath, { force: true, recursive: true });
cleaned += 1;
}
} catch {
try {
const contents = await fs.promises.readdir(entryPath);
if (!contents.length) {
await (0, import_fs.safeDelete)(entryPath);
cleaned += 1;
}
} catch {
}
}
}
return cleaned;
}
async function dlxBinary(args, options, spawnExtra) {
const {
cacheTtl = import_time.DLX_BINARY_CACHE_TTL,
checksum,
force: userForce = false,
name,
spawnOptions,
url,
yes
} = { __proto__: null, ...options };
const force = yes === true ? true : userForce;
const cacheDir = getDlxCachePath();
const binaryName = name || `binary-${process.platform}-${import_os.default.arch()}`;
const spec = `${url}:${binaryName}`;
const cacheKey = (0, import_cache.generateCacheKey)(spec);
const cacheEntryDir = import_path.default.join(cacheDir, cacheKey);
const binaryPath = (0, import_normalize.normalizePath)(import_path.default.join(cacheEntryDir, binaryName));
const fs = /* @__PURE__ */ getFs();
let downloaded = false;
let computedChecksum = checksum;
if (!force && fs.existsSync(cacheEntryDir) && await isCacheValid(cacheEntryDir, cacheTtl)) {
try {
const metaPath = getMetadataPath(cacheEntryDir);
const metadata = await (0, import_fs.readJson)(metaPath, { throws: false });
if (metadata && typeof metadata === "object" && !Array.isArray(metadata) && typeof metadata["checksum"] === "string") {
computedChecksum = metadata["checksum"];
} else {
downloaded = true;
}
} catch {
downloaded = true;
}
} else {
downloaded = true;
}
if (downloaded) {
try {
await (0, import_fs.safeMkdir)(cacheEntryDir);
} catch (e) {
const code = e.code;
if (code === "EACCES" || code === "EPERM") {
throw new Error(
`Permission denied creating binary cache directory: ${cacheEntryDir}
Please check directory permissions or run with appropriate access.`,
{ cause: e }
);
}
if (code === "EROFS") {
throw new Error(
`Cannot create binary cache directory on read-only filesystem: ${cacheEntryDir}
Ensure the filesystem is writable or set SOCKET_DLX_DIR to a writable location.`,
{ cause: e }
);
}
throw new Error(
`Failed to create binary cache directory: ${cacheEntryDir}`,
{ cause: e }
);
}
computedChecksum = await downloadBinaryFile(url, binaryPath, checksum);
const stats = await fs.promises.stat(binaryPath);
await writeMetadata(
cacheEntryDir,
cacheKey,
url,
binaryName,
computedChecksum || "",
stats.size
);
}
const needsShell = import_platform.WIN32 && /\.(?:bat|cmd|ps1)$/i.test(binaryPath);
const finalSpawnOptions = needsShell ? {
...spawnOptions,
env: {
...spawnOptions?.env,
PATH: `${cacheEntryDir}${import_path.default.delimiter}${process.env["PATH"] || ""}`
},
shell: true
} : spawnOptions;
const spawnPromise = (0, import_spawn.spawn)(binaryPath, args, finalSpawnOptions, spawnExtra);
return {
binaryPath,
downloaded,
spawnPromise
};
}
async function downloadBinary(options) {
const {
cacheTtl = import_time.DLX_BINARY_CACHE_TTL,
checksum,
force = false,
name,
url
} = { __proto__: null, ...options };
const cacheDir = getDlxCachePath();
const binaryName = name || `binary-${process.platform}-${import_os.default.arch()}`;
const spec = `${url}:${binaryName}`;
const cacheKey = (0, import_cache.generateCacheKey)(spec);
const cacheEntryDir = import_path.default.join(cacheDir, cacheKey);
const binaryPath = (0, import_normalize.normalizePath)(import_path.default.join(cacheEntryDir, binaryName));
const fs = /* @__PURE__ */ getFs();
let downloaded = false;
if (!force && fs.existsSync(cacheEntryDir) && await isCacheValid(cacheEntryDir, cacheTtl)) {
downloaded = false;
} else {
try {
await (0, import_fs.safeMkdir)(cacheEntryDir);
} catch (e) {
const code = e.code;
if (code === "EACCES" || code === "EPERM") {
throw new Error(
`Permission denied creating binary cache directory: ${cacheEntryDir}
Please check directory permissions or run with appropriate access.`,
{ cause: e }
);
}
if (code === "EROFS") {
throw new Error(
`Cannot create binary cache directory on read-only filesystem: ${cacheEntryDir}
Ensure the filesystem is writable or set SOCKET_DLX_DIR to a writable location.`,
{ cause: e }
);
}
throw new Error(
`Failed to create binary cache directory: ${cacheEntryDir}`,
{ cause: e }
);
}
const computedChecksum = await downloadBinaryFile(url, binaryPath, checksum);
const stats = await fs.promises.stat(binaryPath);
await writeMetadata(
cacheEntryDir,
cacheKey,
url,
binaryName,
computedChecksum || "",
stats.size
);
downloaded = true;
}
return {
binaryPath,
downloaded
};
}
function executeBinary(binaryPath, args, spawnOptions, spawnExtra) {
const needsShell = import_platform.WIN32 && /\.(?:bat|cmd|ps1)$/i.test(binaryPath);
const cacheEntryDir = import_path.default.dirname(binaryPath);
const finalSpawnOptions = needsShell ? {
...spawnOptions,
env: {
...spawnOptions?.env,
PATH: `${cacheEntryDir}${import_path.default.delimiter}${process.env["PATH"] || ""}`
},
shell: true
} : spawnOptions;
return (0, import_spawn.spawn)(binaryPath, args, finalSpawnOptions, spawnExtra);
}
function getDlxCachePath() {
return (0, import_socket.getSocketDlxDir)();
}
async function listDlxCache() {
const cacheDir = getDlxCachePath();
const fs = /* @__PURE__ */ getFs();
if (!fs.existsSync(cacheDir)) {
return [];
}
const results = [];
const now = Date.now();
const entries = await fs.promises.readdir(cacheDir);
for (const entry of entries) {
const entryPath = import_path.default.join(cacheDir, entry);
try {
if (!await (0, import_fs.isDir)(entryPath)) {
continue;
}
const metaPath = getMetadataPath(entryPath);
const metadata = await (0, import_fs.readJson)(metaPath, { throws: false });
if (!metadata || typeof metadata !== "object" || Array.isArray(metadata)) {
continue;
}
const metaObj = metadata;
const source = metaObj["source"];
const url = source?.["url"] || metaObj["url"] || "";
const files = await fs.promises.readdir(entryPath);
const binaryFile = files.find((f) => !f.startsWith("."));
if (binaryFile) {
const binaryPath = import_path.default.join(entryPath, binaryFile);
const binaryStats = await fs.promises.stat(binaryPath);
results.push({
age: now - (metaObj["timestamp"] || 0),
arch: metaObj["arch"] || "unknown",
checksum: metaObj["checksum"] || "",
name: binaryFile,
platform: metaObj["platform"] || "unknown",
size: binaryStats.size,
url
});
}
} catch {
}
}
return results;
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
cleanDlxCache,
dlxBinary,
downloadBinary,
executeBinary,
getDlxCachePath,
listDlxCache
});
/**
* Generate a cache directory name using npm/npx approach.
* Uses first 16 characters of SHA-512 hash (like npm/npx).
*
* Rationale for SHA-512 truncated (vs full SHA-256):
* - Matches npm/npx ecosystem behavior
* - Shorter paths for Windows MAX_PATH compatibility (260 chars)
* - 16 hex chars = 64 bits = acceptable collision risk for local cache
* - Collision probability ~1 in 18 quintillion with 1000 entries
*
* Input strategy (aligned with npx):
* - npx uses package spec strings (e.g., '@scope/pkg@1.0.0', 'prettier@3.0.0')
* - Caller provides complete spec string with version for accurate cache keying
* - For package installs: Use PURL-style spec with version
* Examples: 'npm:prettier@3.0.0', 'pypi:requests@2.31.0', 'gem:rails@7.0.0'
* Note: Socket uses shorthand format without 'pkg:' prefix
* (handled by @socketregistry/packageurl-js)
* - For binary downloads: Use URL:name for uniqueness
*
* Reference: npm/cli v11.6.2 libnpmexec/lib/index.js#L233-L244
* https://github.com/npm/cli/blob/v11.6.2/workspaces/libnpmexec/lib/index.js#L233-L244
* Implementation: packages.map().sort().join('\n') → SHA-512 → slice(0,16)
* npx hashes the package spec (name@version), not just name
*/
export declare function generateCacheKey(spec: string): string;
"use strict";
/* Socket Lib - Built with esbuild */
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var cache_exports = {};
__export(cache_exports, {
generateCacheKey: () => generateCacheKey
});
module.exports = __toCommonJS(cache_exports);
var import_node_crypto = require("node:crypto");
function generateCacheKey(spec) {
return (0, import_node_crypto.createHash)("sha512").update(spec).digest("hex").substring(0, 16);
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
generateCacheKey
});
/**
* Clear all DLX package installations.
*/
export declare function clearDlx(): Promise<void>;
/**
* Clear all DLX package installations synchronously.
*/
export declare function clearDlxSync(): void;
/**
* Check if the DLX directory exists.
*/
export declare function dlxDirExists(): boolean;
/**
* Check if the DLX directory exists asynchronously.
*/
export declare function dlxDirExistsAsync(): Promise<boolean>;
/**
* Ensure the DLX directory exists, creating it if necessary.
*/
export declare function ensureDlxDir(): Promise<void>;
/**
* Ensure the DLX directory exists synchronously, creating it if necessary.
*/
export declare function ensureDlxDirSync(): void;
"use strict";
/* Socket Lib - Built with esbuild */
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var dir_exports = {};
__export(dir_exports, {
clearDlx: () => clearDlx,
clearDlxSync: () => clearDlxSync,
dlxDirExists: () => dlxDirExists,
dlxDirExistsAsync: () => dlxDirExistsAsync,
ensureDlxDir: () => ensureDlxDir,
ensureDlxDirSync: () => ensureDlxDirSync
});
module.exports = __toCommonJS(dir_exports);
var import_fs = require("../fs");
var import_socket = require("../paths/socket");
var import_promises = require("../promises");
var import_packages = require("./packages");
let _fs;
// @__NO_SIDE_EFFECTS__
function getFs() {
if (_fs === void 0) {
_fs = require("node:fs");
}
return _fs;
}
async function clearDlx() {
const packages = await (0, import_packages.listDlxPackagesAsync)();
await (0, import_promises.pEach)(packages, (pkg) => (0, import_packages.removeDlxPackage)(pkg));
}
function clearDlxSync() {
const packages = (0, import_packages.listDlxPackages)();
for (const pkg of packages) {
(0, import_packages.removeDlxPackageSync)(pkg);
}
}
function dlxDirExists() {
const fs = /* @__PURE__ */ getFs();
return fs.existsSync((0, import_socket.getSocketDlxDir)());
}
async function dlxDirExistsAsync() {
const fs = /* @__PURE__ */ getFs();
try {
await fs.promises.access((0, import_socket.getSocketDlxDir)());
return true;
} catch {
return false;
}
}
async function ensureDlxDir() {
await (0, import_fs.safeMkdir)((0, import_socket.getSocketDlxDir)());
}
function ensureDlxDirSync() {
(0, import_fs.safeMkdirSync)((0, import_socket.getSocketDlxDir)());
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
clearDlx,
clearDlxSync,
dlxDirExists,
dlxDirExistsAsync,
ensureDlxDir,
ensureDlxDirSync
});
/**
* Details for npm package entries.
*/
export interface PackageDetails {
installed_version: string;
size?: number;
update_check?: {
last_check: number;
last_notification: number;
latest_known: string;
};
}
/**
* Details for binary download entries.
*/
export interface BinaryDetails {
checksum: string;
checksum_algorithm: 'sha256' | 'sha512';
platform: string;
arch: string;
size: number;
source: {
type: 'download';
url: string;
};
}
/**
* Unified manifest entry for all cached items (packages and binaries).
* Shared fields at root, type-specific fields in details.
*/
export interface ManifestEntry {
type: 'package' | 'binary';
cache_key: string;
timestamp: number;
details: PackageDetails | BinaryDetails;
}
/**
* Type guard for package entries.
*/
export declare function isPackageEntry(entry: ManifestEntry): entry is ManifestEntry & {
details: PackageDetails;
};
/**
* Type guard for binary entries.
*/
export declare function isBinaryEntry(entry: ManifestEntry): entry is ManifestEntry & {
details: BinaryDetails;
};
/**
* Legacy store record format (deprecated, for migration).
*/
export interface StoreRecord {
timestampFetch: number;
timestampNotification: number;
version: string;
}
export interface DlxManifestOptions {
/**
* Custom manifest file path (defaults to ~/.socket/_dlx/.dlx-manifest.json).
*/
manifestPath?: string;
}
/**
* DLX manifest storage manager with atomic operations.
* Supports both legacy format (package name keys) and new unified manifest format (spec keys).
*/
export declare class DlxManifest {
private readonly manifestPath;
private readonly lockPath;
constructor(options?: DlxManifestOptions);
/**
* Read the entire manifest file.
*/
private readManifest;
/**
* Get a manifest entry by spec (e.g., "@socketsecurity/cli@^2.0.11").
*/
getManifestEntry(spec: string): ManifestEntry | undefined;
/**
* Get cached update information for a package (legacy format).
* @deprecated Use getManifestEntry() for new code.
*/
get(name: string): StoreRecord | undefined;
/**
* Set a package manifest entry.
*/
setPackageEntry(spec: string, cacheKey: string, details: PackageDetails): Promise<void>;
/**
* Set a binary manifest entry.
*/
setBinaryEntry(spec: string, cacheKey: string, details: BinaryDetails): Promise<void>;
private writeManifest;
/**
* Store update information for a package (legacy format).
* @deprecated Use setPackageEntry() for new code.
*/
set(name: string, record: StoreRecord): Promise<void>;
/**
* Clear cached data for a specific entry.
*/
clear(name: string): Promise<void>;
/**
* Clear all cached data.
*/
clearAll(): Promise<void>;
/**
* Check if cached data is fresh based on TTL.
*/
isFresh(record: StoreRecord | undefined, ttlMs: number): boolean;
/**
* Get all cached package names.
*/
getAllPackages(): string[];
}
// Export singleton instance using default manifest location.
export declare const dlxManifest: DlxManifest;
"use strict";
/* Socket Lib - Built with esbuild */
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var manifest_exports = {};
__export(manifest_exports, {
DlxManifest: () => DlxManifest,
dlxManifest: () => dlxManifest,
isBinaryEntry: () => isBinaryEntry,
isPackageEntry: () => isPackageEntry
});
module.exports = __toCommonJS(manifest_exports);
var import_fs = require("fs");
var import_path = __toESM(require("path"));
var import_fs2 = require("../fs");
var import_logger = require("../logger");
var import_socket = require("../paths/socket");
var import_process_lock = require("../process-lock");
const logger = (0, import_logger.getDefaultLogger)();
const MANIFEST_FILE_NAME = ".dlx-manifest.json";
function isPackageEntry(entry) {
return entry.type === "package";
}
function isBinaryEntry(entry) {
return entry.type === "binary";
}
class DlxManifest {
manifestPath;
lockPath;
constructor(options = {}) {
this.manifestPath = options.manifestPath ?? import_path.default.join((0, import_socket.getSocketDlxDir)(), MANIFEST_FILE_NAME);
this.lockPath = `${this.manifestPath}.lock`;
}
/**
* Read the entire manifest file.
*/
readManifest() {
try {
if (!(0, import_fs.existsSync)(this.manifestPath)) {
return /* @__PURE__ */ Object.create(null);
}
const rawContent = (0, import_fs2.readFileUtf8Sync)(this.manifestPath);
const content = (typeof rawContent === "string" ? rawContent : rawContent.toString("utf8")).trim();
if (!content) {
return /* @__PURE__ */ Object.create(null);
}
return JSON.parse(content);
} catch (error) {
logger.warn(
`Failed to read manifest: ${error instanceof Error ? error.message : String(error)}`
);
return /* @__PURE__ */ Object.create(null);
}
}
/**
* Get a manifest entry by spec (e.g., "@socketsecurity/cli@^2.0.11").
*/
getManifestEntry(spec) {
const data = this.readManifest();
const entry = data[spec];
if (entry && "type" in entry) {
return entry;
}
return void 0;
}
/**
* Get cached update information for a package (legacy format).
* @deprecated Use getManifestEntry() for new code.
*/
get(name) {
const data = this.readManifest();
const entry = data[name];
if (entry && !("type" in entry)) {
return entry;
}
return void 0;
}
/**
* Set a package manifest entry.
*/
async setPackageEntry(spec, cacheKey, details) {
await import_process_lock.processLock.withLock(this.lockPath, async () => {
const data = this.readManifest();
data[spec] = {
type: "package",
cache_key: cacheKey,
timestamp: Date.now(),
details
};
await this.writeManifest(data);
});
}
/**
* Set a binary manifest entry.
*/
async setBinaryEntry(spec, cacheKey, details) {
await import_process_lock.processLock.withLock(this.lockPath, async () => {
const data = this.readManifest();
data[spec] = {
type: "binary",
cache_key: cacheKey,
timestamp: Date.now(),
details
};
await this.writeManifest(data);
});
}
/**
* Write the manifest file atomically.
*/
async writeManifest(data) {
const manifestDir = import_path.default.dirname(this.manifestPath);
try {
(0, import_fs2.safeMkdirSync)(manifestDir, { recursive: true });
} catch (error) {
logger.warn(
`Failed to create manifest directory: ${error instanceof Error ? error.message : String(error)}`
);
}
const content = JSON.stringify(data, null, 2);
const tempPath = `${this.manifestPath}.tmp`;
try {
(0, import_fs.writeFileSync)(tempPath, content, "utf8");
(0, import_fs.writeFileSync)(this.manifestPath, content, "utf8");
try {
if ((0, import_fs.existsSync)(tempPath)) {
(0, import_fs.unlinkSync)(tempPath);
}
} catch {
}
} catch (error) {
try {
if ((0, import_fs.existsSync)(tempPath)) {
(0, import_fs.unlinkSync)(tempPath);
}
} catch {
}
throw error;
}
}
/**
* Store update information for a package (legacy format).
* @deprecated Use setPackageEntry() for new code.
*/
async set(name, record) {
await import_process_lock.processLock.withLock(this.lockPath, async () => {
let data = /* @__PURE__ */ Object.create(null);
try {
if ((0, import_fs.existsSync)(this.manifestPath)) {
const content2 = (0, import_fs.readFileSync)(this.manifestPath, "utf8");
if (content2.trim()) {
data = JSON.parse(content2);
}
}
} catch (error) {
logger.warn(
`Failed to read existing manifest: ${error instanceof Error ? error.message : String(error)}`
);
}
data[name] = record;
const manifestDir = import_path.default.dirname(this.manifestPath);
try {
(0, import_fs2.safeMkdirSync)(manifestDir, { recursive: true });
} catch (error) {
logger.warn(
`Failed to create manifest directory: ${error instanceof Error ? error.message : String(error)}`
);
}
const content = JSON.stringify(data, null, 2);
const tempPath = `${this.manifestPath}.tmp`;
try {
(0, import_fs.writeFileSync)(tempPath, content, "utf8");
(0, import_fs.writeFileSync)(this.manifestPath, content, "utf8");
try {
if ((0, import_fs.existsSync)(tempPath)) {
(0, import_fs.unlinkSync)(tempPath);
}
} catch {
}
} catch (error) {
try {
if ((0, import_fs.existsSync)(tempPath)) {
(0, import_fs.unlinkSync)(tempPath);
}
} catch {
}
throw error;
}
});
}
/**
* Clear cached data for a specific entry.
*/
async clear(name) {
await import_process_lock.processLock.withLock(this.lockPath, async () => {
try {
if (!(0, import_fs.existsSync)(this.manifestPath)) {
return;
}
const content = (0, import_fs.readFileSync)(this.manifestPath, "utf8");
if (!content.trim()) {
return;
}
const data = JSON.parse(content);
delete data[name];
const updatedContent = JSON.stringify(data, null, 2);
(0, import_fs.writeFileSync)(this.manifestPath, updatedContent, "utf8");
} catch (error) {
logger.warn(
`Failed to clear cache for ${name}: ${error instanceof Error ? error.message : String(error)}`
);
}
});
}
/**
* Clear all cached data.
*/
async clearAll() {
await import_process_lock.processLock.withLock(this.lockPath, async () => {
try {
if ((0, import_fs.existsSync)(this.manifestPath)) {
(0, import_fs.unlinkSync)(this.manifestPath);
}
} catch (error) {
logger.warn(
`Failed to clear all cache: ${error instanceof Error ? error.message : String(error)}`
);
}
});
}
/**
* Check if cached data is fresh based on TTL.
*/
isFresh(record, ttlMs) {
if (!record) {
return false;
}
const age = Date.now() - record.timestampFetch;
return age < ttlMs;
}
/**
* Get all cached package names.
*/
getAllPackages() {
try {
if (!(0, import_fs.existsSync)(this.manifestPath)) {
return [];
}
const rawContent = (0, import_fs2.readFileUtf8Sync)(this.manifestPath);
const content = (typeof rawContent === "string" ? rawContent : rawContent.toString("utf8")).trim();
if (!content) {
return [];
}
const data = JSON.parse(content);
return Object.keys(data);
} catch (error) {
logger.warn(
`Failed to get package list: ${error instanceof Error ? error.message : String(error)}`
);
return [];
}
}
}
const dlxManifest = new DlxManifest();
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
DlxManifest,
dlxManifest,
isBinaryEntry,
isPackageEntry
});
import type { SpawnExtra, SpawnOptions } from '../spawn';
import { spawn } from '../spawn';
export interface DownloadPackageResult {
/** Path to the installed package directory. */
packageDir: string;
/** Path to the binary. */
binaryPath: string;
/** Whether the package was newly installed. */
installed: boolean;
}
export interface DlxPackageOptions {
/**
* Package to install (e.g., '@cyclonedx/cdxgen@10.0.0').
* Aligns with npx --package flag.
*/
package: string;
/**
* Binary name to execute (optional - auto-detected in most cases).
*
* Auto-detection logic:
* 1. If package has only one binary, uses it automatically
* 2. Tries user-provided binaryName
* 3. Tries last segment of package name (e.g., 'cli' from '@socketsecurity/cli')
* 4. Falls back to first binary
*
* Only needed when package has multiple binaries and auto-detection fails.
*
* @example
* // Auto-detected (single binary)
* { package: '@socketsecurity/cli' } // Finds 'socket' binary automatically
*
* // Explicit (multiple binaries)
* { package: 'some-tool', binaryName: 'specific-tool' }
*/
binaryName?: string | undefined;
/**
* Force reinstallation even if package exists.
* Aligns with npx --yes/-y flag behavior.
*/
force?: boolean | undefined;
/**
* Skip confirmation prompts (auto-approve).
* Aligns with npx --yes/-y flag.
*/
yes?: boolean | undefined;
/**
* Suppress output (quiet mode).
* Aligns with npx --quiet/-q and pnpm --silent/-s flags.
*/
quiet?: boolean | undefined;
/**
* Additional spawn options for the execution.
*/
spawnOptions?: SpawnOptions | undefined;
}
export interface DlxPackageResult {
/** Path to the installed package directory. */
packageDir: string;
/** Path to the binary that was executed. */
binaryPath: string;
/** Whether the package was newly installed. */
installed: boolean;
/** The spawn promise for the running process. */
spawnPromise: ReturnType<typeof spawn>;
}
/**
* Execute a package via DLX - install if needed and run its binary.
*
* This is the Socket equivalent of npx/pnpm dlx/yarn dlx, but using
* our own cache directory (~/.socket/_dlx) and installation logic.
*
* Auto-forces reinstall for version ranges to get latest within range.
*
* @example
* ```typescript
* // Download and execute cdxgen
* const result = await dlxPackage(
* ['--version'],
* { package: '@cyclonedx/cdxgen@10.0.0' }
* )
* await result.spawnPromise
* ```
*/
export declare function dlxPackage(args: readonly string[] | string[], options?: DlxPackageOptions | undefined, spawnExtra?: SpawnExtra | undefined): Promise<DlxPackageResult>;
/**
* Download and install a package without executing it.
* This is useful for self-update or when you need the package files
* but don't want to run the binary immediately.
*
* @example
* ```typescript
* // Install @socketsecurity/cli without running it
* const result = await downloadPackage({
* package: '@socketsecurity/cli@1.2.0',
* force: true
* })
* console.log('Installed to:', result.packageDir)
* console.log('Binary at:', result.binaryPath)
* ```
*/
export declare function downloadPackage(options: DlxPackageOptions): Promise<DownloadPackageResult>;
/**
* Execute a package's binary with cross-platform shell handling.
* The package must already be installed (use downloadPackage first).
*
* On Windows, script files (.bat, .cmd, .ps1) require shell: true.
* Matches npm/npx execution behavior.
*
* @example
* ```typescript
* // Execute an already-installed package
* const downloaded = await downloadPackage({ package: 'cowsay@1.5.0' })
* const result = await executePackage(
* downloaded.binaryPath,
* ['Hello World'],
* { stdio: 'inherit' }
* )
* ```
*/
export declare function executePackage(binaryPath: string, args: readonly string[] | string[], spawnOptions?: SpawnOptions | undefined, spawnExtra?: SpawnExtra | undefined): ReturnType<typeof spawn>;
"use strict";
/* Socket Lib - Built with esbuild */
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var package_exports = {};
__export(package_exports, {
dlxPackage: () => dlxPackage,
downloadPackage: () => downloadPackage,
executePackage: () => executePackage
});
module.exports = __toCommonJS(package_exports);
var import_node_fs = __toESM(require("node:fs"));
var import_path = __toESM(require("path"));
var import_platform = require("../constants/platform");
var import_packages = require("../constants/packages");
var import_cache = require("./cache");
var import_arborist = __toESM(require("../external/@npmcli/arborist"));
var import_libnpmexec = __toESM(require("../external/libnpmexec"));
var import_npm_package_arg = __toESM(require("../external/npm-package-arg"));
var import_pacote = __toESM(require("../external/pacote"));
var import_fs = require("../fs");
var import_normalize = require("../paths/normalize");
var import_socket = require("../paths/socket");
var import_process_lock = require("../process-lock");
var import_spawn = require("../spawn");
const rangeOperatorsRegExp = /[~^><=xX* ]|\|\|/;
function parsePackageSpec(spec) {
try {
const parsed = (0, import_npm_package_arg.default)(spec);
const version = parsed.type === "tag" ? parsed.fetchSpec : parsed.type === "version" || parsed.type === "range" ? parsed.fetchSpec : void 0;
return {
name: parsed.name || spec,
version
};
} catch {
const atIndex = spec.lastIndexOf("@");
if (atIndex === -1 || spec.startsWith("@")) {
return { name: spec, version: void 0 };
}
return {
name: spec.slice(0, atIndex),
version: spec.slice(atIndex + 1)
};
}
}
async function ensurePackageInstalled(packageName, packageSpec, force) {
const cacheKey = (0, import_cache.generateCacheKey)(packageSpec);
const packageDir = (0, import_normalize.normalizePath)(import_path.default.join((0, import_socket.getSocketDlxDir)(), cacheKey));
const installedDir = (0, import_normalize.normalizePath)(
import_path.default.join(packageDir, "node_modules", packageName)
);
try {
await (0, import_fs.safeMkdir)(packageDir);
} catch (e) {
const code = e.code;
if (code === "EACCES" || code === "EPERM") {
throw new Error(
`Permission denied creating package directory: ${packageDir}
Please check directory permissions or run with appropriate access.`,
{ cause: e }
);
}
if (code === "EROFS") {
throw new Error(
`Cannot create package directory on read-only filesystem: ${packageDir}
Ensure the filesystem is writable or set SOCKET_DLX_DIR to a writable location.`,
{ cause: e }
);
}
throw new Error(`Failed to create package directory: ${packageDir}`, {
cause: e
});
}
const lockPath = import_path.default.join(packageDir, "concurrency.lock");
return await import_process_lock.processLock.withLock(
lockPath,
async () => {
if (!force && import_node_fs.default.existsSync(installedDir)) {
const pkgJsonPath = import_path.default.join(installedDir, "package.json");
if (import_node_fs.default.existsSync(pkgJsonPath)) {
return { installed: false, packageDir };
}
}
const pacoteCachePath = (0, import_packages.getPacoteCachePath)();
try {
await import_pacote.default.extract(packageSpec, installedDir, {
// Use consistent pacote cache path (respects npm cache locations when available).
cache: pacoteCachePath || import_path.default.join(packageDir, ".cache")
});
const arb = new import_arborist.default({
path: installedDir,
cache: pacoteCachePath || import_path.default.join(packageDir, ".cache"),
// Skip devDependencies (production-only like npx).
omit: ["dev"],
// Security: Skip install/preinstall/postinstall scripts to prevent arbitrary code execution.
ignoreScripts: true,
// Security: Enable binary links (needed for dlx to execute the package binary).
binLinks: true,
// Suppress funding messages (unneeded for ephemeral dlx installs).
fund: false,
// Skip audit (unneeded for ephemeral dlx installs).
audit: false,
// Suppress output (unneeded for ephemeral dlx installs).
silent: true
});
await arb.buildIdealTree();
await arb.reify({ save: false });
} catch (e) {
const code = e.code;
if (code === "E404" || code === "ETARGET") {
throw new Error(
`Package not found: ${packageSpec}
Verify the package exists on npm registry and check the version.
Visit https://www.npmjs.com/package/${packageName} to see available versions.`,
{ cause: e }
);
}
if (code === "ENOTFOUND" || code === "ETIMEDOUT" || code === "EAI_AGAIN") {
throw new Error(
`Network error installing ${packageSpec}
Check your internet connection and try again.`,
{ cause: e }
);
}
throw new Error(
`Failed to install package: ${packageSpec}
Destination: ${installedDir}
Check npm registry connectivity or package name.`,
{ cause: e }
);
}
return { installed: true, packageDir };
},
{
// Align with npm npx locking strategy.
staleMs: 5e3,
touchIntervalMs: 2e3
}
);
}
function resolveBinaryPath(basePath) {
if (!import_platform.WIN32) {
return basePath;
}
const extensions = [".cmd", ".bat", ".ps1", ".exe", ""];
for (const ext of extensions) {
const testPath = basePath + ext;
if (import_node_fs.default.existsSync(testPath)) {
return testPath;
}
}
return basePath;
}
function findBinaryPath(packageDir, packageName, binaryName) {
const installedDir = (0, import_normalize.normalizePath)(
import_path.default.join(packageDir, "node_modules", packageName)
);
const pkgJsonPath = import_path.default.join(installedDir, "package.json");
const pkgJson = (0, import_fs.readJsonSync)(pkgJsonPath);
const bin = pkgJson["bin"];
let binName;
let binPath;
if (typeof bin === "string") {
binPath = bin;
} else if (typeof bin === "object" && bin !== null) {
const binObj = bin;
const binKeys = Object.keys(binObj);
if (binKeys.length === 1) {
binName = binKeys[0];
binPath = binObj[binName];
} else {
try {
const { getBinFromManifest } = import_libnpmexec.default;
binName = getBinFromManifest({
name: packageName,
bin: binObj,
_id: `${packageName}@${pkgJson.version || "unknown"}`
});
binPath = binObj[binName];
} catch {
const lastSegment = packageName.split("/").pop();
const candidates = [
binaryName,
lastSegment,
packageName.replace(/^@[^/]+\//, "")
].filter(Boolean);
for (const candidate of candidates) {
if (candidate && binObj[candidate]) {
binName = candidate;
binPath = binObj[candidate];
break;
}
}
if (!binPath && binKeys.length > 0) {
binName = binKeys[0];
binPath = binObj[binName];
}
}
}
}
if (!binPath) {
throw new Error(`No binary found for package "${packageName}"`);
}
const rawPath = (0, import_normalize.normalizePath)(import_path.default.join(installedDir, binPath));
return resolveBinaryPath(rawPath);
}
async function dlxPackage(args, options, spawnExtra) {
const downloadResult = await downloadPackage(options);
const spawnPromise = executePackage(
downloadResult.binaryPath,
args,
options?.spawnOptions,
spawnExtra
);
return {
...downloadResult,
spawnPromise
};
}
function makePackageBinsExecutable(packageDir, packageName) {
if (import_platform.WIN32) {
return;
}
const installedDir = (0, import_normalize.normalizePath)(
import_path.default.join(packageDir, "node_modules", packageName)
);
const pkgJsonPath = import_path.default.join(installedDir, "package.json");
try {
const pkgJson = (0, import_fs.readJsonSync)(pkgJsonPath);
const bin = pkgJson["bin"];
if (!bin) {
return;
}
const binPaths = [];
if (typeof bin === "string") {
binPaths.push(bin);
} else if (typeof bin === "object" && bin !== null) {
const binObj = bin;
binPaths.push(...Object.values(binObj));
}
for (const binPath of binPaths) {
const fullPath = (0, import_normalize.normalizePath)(import_path.default.join(installedDir, binPath));
if (import_node_fs.default.existsSync(fullPath)) {
try {
import_node_fs.default.chmodSync(fullPath, 493);
} catch {
}
}
}
} catch {
}
}
async function downloadPackage(options) {
const {
binaryName,
force: userForce,
package: packageSpec,
yes
} = {
__proto__: null,
...options
};
const { name: packageName, version: packageVersion } = parsePackageSpec(packageSpec);
const isVersionRange = packageVersion !== void 0 && rangeOperatorsRegExp.test(packageVersion);
const force = userForce !== void 0 ? userForce : yes === true ? true : isVersionRange;
const fullPackageSpec = packageVersion ? `${packageName}@${packageVersion}` : packageName;
const { installed, packageDir } = await ensurePackageInstalled(
packageName,
fullPackageSpec,
force
);
const binaryPath = findBinaryPath(packageDir, packageName, binaryName);
makePackageBinsExecutable(packageDir, packageName);
return {
binaryPath,
installed,
packageDir
};
}
function executePackage(binaryPath, args, spawnOptions, spawnExtra) {
const needsShell = import_platform.WIN32 && /\.(?:bat|cmd|ps1)$/i.test(binaryPath);
const finalOptions = needsShell ? {
...spawnOptions,
shell: true
} : spawnOptions;
return (0, import_spawn.spawn)(binaryPath, args, finalOptions, spawnExtra);
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
dlxPackage,
downloadPackage,
executePackage
});
/**
* Check if a package is installed in DLX.
*/
export declare function isDlxPackageInstalled(packageName: string): boolean;
/**
* Check if a package is installed in DLX asynchronously.
*/
export declare function isDlxPackageInstalledAsync(packageName: string): Promise<boolean>;
/**
* List all packages installed in DLX.
*/
export declare function listDlxPackages(): string[];
/**
* List all packages installed in DLX asynchronously.
*/
export declare function listDlxPackagesAsync(): Promise<string[]>;
/**
* Remove a DLX package installation.
*/
export declare function removeDlxPackage(packageName: string): Promise<void>;
/**
* Remove a DLX package installation synchronously.
*/
export declare function removeDlxPackageSync(packageName: string): void;
"use strict";
/* Socket Lib - Built with esbuild */
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var packages_exports = {};
__export(packages_exports, {
isDlxPackageInstalled: () => isDlxPackageInstalled,
isDlxPackageInstalledAsync: () => isDlxPackageInstalledAsync,
listDlxPackages: () => listDlxPackages,
listDlxPackagesAsync: () => listDlxPackagesAsync,
removeDlxPackage: () => removeDlxPackage,
removeDlxPackageSync: () => removeDlxPackageSync
});
module.exports = __toCommonJS(packages_exports);
var import_fs = require("../fs");
var import_socket = require("../paths/socket");
var import_paths = require("./paths");
let _fs;
// @__NO_SIDE_EFFECTS__
function getFs() {
if (_fs === void 0) {
_fs = require("node:fs");
}
return _fs;
}
function isDlxPackageInstalled(packageName) {
const fs = /* @__PURE__ */ getFs();
return fs.existsSync((0, import_paths.getDlxInstalledPackageDir)(packageName));
}
async function isDlxPackageInstalledAsync(packageName) {
const fs = /* @__PURE__ */ getFs();
try {
await fs.promises.access((0, import_paths.getDlxInstalledPackageDir)(packageName));
return true;
} catch {
return false;
}
}
function listDlxPackages() {
try {
return (0, import_fs.readDirNamesSync)((0, import_socket.getSocketDlxDir)(), { sort: true });
} catch {
return [];
}
}
async function listDlxPackagesAsync() {
const fs = /* @__PURE__ */ getFs();
try {
const entries = await fs.promises.readdir((0, import_socket.getSocketDlxDir)(), {
withFileTypes: true
});
return entries.filter((e) => e.isDirectory()).map((e) => e.name).sort();
} catch {
return [];
}
}
async function removeDlxPackage(packageName) {
const packageDir = (0, import_paths.getDlxPackageDir)(packageName);
try {
await (0, import_fs.safeDelete)(packageDir, { recursive: true, force: true });
} catch (e) {
throw new Error(`Failed to remove DLX package "${packageName}"`, {
cause: e
});
}
}
function removeDlxPackageSync(packageName) {
const fs = /* @__PURE__ */ getFs();
const packageDir = (0, import_paths.getDlxPackageDir)(packageName);
try {
fs.rmSync(packageDir, { recursive: true, force: true });
} catch (e) {
const code = e.code;
if (code === "EACCES" || code === "EPERM") {
throw new Error(
`Permission denied removing DLX package "${packageName}"
Directory: ${packageDir}
To resolve:
1. Check file/directory permissions
2. Close any programs using files in this directory
3. Try running with elevated privileges if necessary
4. Manually remove: rm -rf "${packageDir}"`,
{ cause: e }
);
}
if (code === "EROFS") {
throw new Error(
`Cannot remove DLX package "${packageName}" from read-only filesystem
Directory: ${packageDir}
The filesystem is mounted read-only.`,
{ cause: e }
);
}
throw new Error(
`Failed to remove DLX package "${packageName}"
Directory: ${packageDir}
Check permissions and ensure no programs are using this directory.`,
{ cause: e }
);
}
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
isDlxPackageInstalled,
isDlxPackageInstalledAsync,
listDlxPackages,
listDlxPackagesAsync,
removeDlxPackage,
removeDlxPackageSync
});
/**
* Get the installed package directory within DLX node_modules.
*/
export declare function getDlxInstalledPackageDir(packageName: string): string;
/**
* Get the DLX installation directory for a specific package.
*/
export declare function getDlxPackageDir(packageName: string): string;
/**
* Get the package.json path for a DLX installed package.
*/
export declare function getDlxPackageJsonPath(packageName: string): string;
/**
* Get the node_modules directory for a DLX package installation.
*/
export declare function getDlxPackageNodeModulesDir(packageName: string): string;
/**
* Check if a file path is within the Socket DLX directory.
* This is useful for determining if a binary or file is managed by Socket's DLX system.
*
* @param filePath - Absolute or relative path to check
* @returns true if the path is within ~/.socket/_dlx/, false otherwise
*
* @example
* ```typescript
* isInSocketDlx('/home/user/.socket/_dlx/abc123/bin/socket') // true
* isInSocketDlx('/usr/local/bin/socket') // false
* isInSocketDlx(process.argv[0]) // Check if current binary is in DLX
* ```
*/
export declare function isInSocketDlx(filePath: string): boolean;
"use strict";
/* Socket Lib - Built with esbuild */
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var paths_exports = {};
__export(paths_exports, {
getDlxInstalledPackageDir: () => getDlxInstalledPackageDir,
getDlxPackageDir: () => getDlxPackageDir,
getDlxPackageJsonPath: () => getDlxPackageJsonPath,
getDlxPackageNodeModulesDir: () => getDlxPackageNodeModulesDir,
isInSocketDlx: () => isInSocketDlx
});
module.exports = __toCommonJS(paths_exports);
var import_normalize = require("../paths/normalize");
var import_socket = require("../paths/socket");
let _path;
// @__NO_SIDE_EFFECTS__
function getPath() {
if (_path === void 0) {
_path = require("node:path");
}
return _path;
}
function getDlxInstalledPackageDir(packageName) {
const path = /* @__PURE__ */ getPath();
return (0, import_normalize.normalizePath)(
path.join(getDlxPackageNodeModulesDir(packageName), packageName)
);
}
function getDlxPackageDir(packageName) {
const path = /* @__PURE__ */ getPath();
return (0, import_normalize.normalizePath)(path.join((0, import_socket.getSocketDlxDir)(), packageName));
}
function getDlxPackageJsonPath(packageName) {
const path = /* @__PURE__ */ getPath();
return (0, import_normalize.normalizePath)(
path.join(getDlxInstalledPackageDir(packageName), "package.json")
);
}
function getDlxPackageNodeModulesDir(packageName) {
const path = /* @__PURE__ */ getPath();
return (0, import_normalize.normalizePath)(path.join(getDlxPackageDir(packageName), "node_modules"));
}
function isInSocketDlx(filePath) {
if (!filePath) {
return false;
}
const path = /* @__PURE__ */ getPath();
const dlxDir = (0, import_socket.getSocketDlxDir)();
const absolutePath = (0, import_normalize.normalizePath)(path.resolve(filePath));
return absolutePath.startsWith(`${dlxDir}/`);
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
getDlxInstalledPackageDir,
getDlxPackageDir,
getDlxPackageJsonPath,
getDlxPackageNodeModulesDir,
isInSocketDlx
});
import type { EditableJsonConstructor } from './types';
/**
* Get the EditableJson class for JSON file manipulation.
*
* @example
* ```ts
* import { getEditableJsonClass } from '@socketsecurity/lib/json'
*
* const EditableJson = getEditableJsonClass<MyConfigType>()
* const config = await EditableJson.load('./config.json')
* config.update({ someField: 'newValue' })
* await config.save({ sort: true })
* ```
*/
/*@__NO_SIDE_EFFECTS__*/
export declare function getEditableJsonClass<T = Record<string, unknown>>(): EditableJsonConstructor<T>;
"use strict";
/* Socket Lib - Built with esbuild */
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var edit_exports = {};
__export(edit_exports, {
getEditableJsonClass: () => getEditableJsonClass
});
module.exports = __toCommonJS(edit_exports);
var import_format = require("./format");
const identSymbol = import_format.INDENT_SYMBOL;
const newlineSymbol = import_format.NEWLINE_SYMBOL;
const JSONParse = JSON.parse;
let _EditableJsonClass;
let _fs;
// @__NO_SIDE_EFFECTS__
function getFs() {
if (_fs === void 0) {
_fs = require("node:fs");
}
return _fs;
}
async function retryWrite(filepath, content, retries = 3, baseDelay = 10) {
const { promises: fsPromises } = /* @__PURE__ */ getFs();
for (let attempt = 0; attempt <= retries; attempt++) {
try {
await fsPromises.writeFile(filepath, content);
return;
} catch (err) {
const isLastAttempt = attempt === retries;
const isEperm = err instanceof Error && "code" in err && (err.code === "EPERM" || err.code === "EBUSY");
if (!isEperm || isLastAttempt) {
throw err;
}
const delay = baseDelay * 2 ** attempt;
await new Promise((resolve) => setTimeout(resolve, delay));
}
}
}
function parseJson(content) {
return JSONParse(content);
}
async function readFile(filepath) {
const { promises: fsPromises } = /* @__PURE__ */ getFs();
return await fsPromises.readFile(filepath, "utf8");
}
// @__NO_SIDE_EFFECTS__
function getEditableJsonClass() {
if (_EditableJsonClass === void 0) {
_EditableJsonClass = class EditableJson {
_canSave = true;
_content = {};
_path = void 0;
_readFileContent = "";
_readFileJson = void 0;
get content() {
return this._content;
}
get filename() {
const path = this._path;
if (!path) {
return "";
}
return path;
}
get path() {
return this._path;
}
static async create(path, opts = {}) {
const instance = new EditableJson();
instance.create(path);
return opts.data ? instance.update(opts.data) : instance;
}
static async load(path, opts = {}) {
const instance = new EditableJson();
if (!opts.create) {
return await instance.load(path);
}
try {
return await instance.load(path);
} catch (err) {
if (!err.message.includes("ENOENT") && !err.message.includes("no such file")) {
throw err;
}
return instance.create(path);
}
}
create(path) {
this._path = path;
this._content = {};
this._canSave = true;
return this;
}
fromContent(data) {
this._content = data;
this._canSave = false;
return this;
}
fromJSON(data) {
const parsed = parseJson(data);
const indent = (0, import_format.detectIndent)(data);
const newline = (0, import_format.detectNewline)(data);
parsed[identSymbol] = indent;
parsed[newlineSymbol] = newline;
this._content = parsed;
return this;
}
async load(path, create) {
this._path = path;
let parseErr;
try {
this._readFileContent = await readFile(this.filename);
} catch (err) {
if (!create) {
throw err;
}
parseErr = err;
}
if (parseErr) {
throw parseErr;
}
this.fromJSON(this._readFileContent);
this._readFileJson = parseJson(this._readFileContent);
return this;
}
update(content) {
this._content = {
...this._content,
...content
};
return this;
}
async save(options) {
if (!this._canSave || this.content === void 0) {
throw new Error("No file path to save to");
}
if (!(0, import_format.shouldSave)(
this.content,
this._readFileJson,
this._readFileContent,
options
)) {
return false;
}
const content = (0, import_format.stripFormattingSymbols)(
this.content
);
const sortedContent = options?.sort ? (0, import_format.sortKeys)(content) : content;
const formatting = (0, import_format.getFormattingFromContent)(
this.content
);
const fileContent = (0, import_format.stringifyWithFormatting)(sortedContent, formatting);
await retryWrite(this.filename, fileContent);
this._readFileContent = fileContent;
this._readFileJson = parseJson(fileContent);
return true;
}
saveSync(options) {
if (!this._canSave || this.content === void 0) {
throw new Error("No file path to save to");
}
if (!(0, import_format.shouldSave)(
this.content,
this._readFileJson,
this._readFileContent,
options
)) {
return false;
}
const content = (0, import_format.stripFormattingSymbols)(
this.content
);
const sortedContent = options?.sort ? (0, import_format.sortKeys)(content) : content;
const formatting = (0, import_format.getFormattingFromContent)(
this.content
);
const fileContent = (0, import_format.stringifyWithFormatting)(sortedContent, formatting);
const fs = /* @__PURE__ */ getFs();
fs.writeFileSync(this.filename, fileContent);
this._readFileContent = fileContent;
this._readFileJson = parseJson(fileContent);
return true;
}
willSave(options) {
if (!this._canSave || this.content === void 0) {
return false;
}
return (0, import_format.shouldSave)(
this.content,
this._readFileJson,
this._readFileContent,
options
);
}
};
}
return _EditableJsonClass;
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
getEditableJsonClass
});
/**
* @fileoverview Shared utilities for JSON formatting preservation and manipulation.
* Provides functions for detecting and preserving indentation, line endings, and
* determining when JSON files should be saved based on content changes.
*/
/**
* Symbols used to store formatting metadata in JSON objects.
*/
export declare const INDENT_SYMBOL: unique symbol;
export declare const NEWLINE_SYMBOL: unique symbol;
/**
* Formatting metadata for JSON files.
*/
export interface JsonFormatting {
indent: string | number;
newline: string;
}
/**
* Options for determining if a save should occur.
*/
export interface ShouldSaveOptions {
ignoreWhitespace?: boolean;
sort?: boolean;
sortFn?: (obj: Record<string, unknown>) => Record<string, unknown>;
}
/**
* Detect indentation from a JSON string.
* Supports space-based indentation (returns count) or mixed indentation (returns string).
*
* @param json - JSON string to analyze
* @returns Number of spaces or indentation string, defaults to 2 if not detected
*
* @example
* ```ts
* detectIndent('{\n "key": "value"\n}') // => 2
* detectIndent('{\n "key": "value"\n}') // => 4
* detectIndent('{\n\t"key": "value"\n}') // => '\t'
* ```
*/
export declare function detectIndent(json: string): string | number;
/**
* Detect newline character(s) from a JSON string.
* Supports LF (\n) and CRLF (\r\n) line endings.
*
* @param json - JSON string to analyze
* @returns Line ending string ('\n' or '\r\n'), defaults to '\n' if not detected
*
* @example
* ```ts
* detectNewline('{\n "key": "value"\n}') // => '\n'
* detectNewline('{\r\n "key": "value"\r\n}') // => '\r\n'
* ```
*/
export declare function detectNewline(json: string): string;
/**
* Extract formatting metadata from a JSON string.
*
* @param json - JSON string to analyze
* @returns Object containing indent and newline formatting
*
* @example
* ```ts
* const formatting = extractFormatting('{\n "key": "value"\n}')
* // => { indent: 2, newline: '\n' }
* ```
*/
export declare function extractFormatting(json: string): JsonFormatting;
/**
* Get default formatting for JSON files.
*
* @returns Default formatting (2 spaces, LF line endings)
*/
export declare function getDefaultFormatting(): JsonFormatting;
/**
* Sort object keys alphabetically.
* Creates a new object with sorted keys (does not mutate input).
*
* @param obj - Object to sort
* @returns New object with alphabetically sorted keys
*
* @example
* ```ts
* sortKeys({ z: 3, a: 1, m: 2 })
* // => { a: 1, m: 2, z: 3 }
* ```
*/
export declare function sortKeys(obj: Record<string, unknown>): Record<string, unknown>;
/**
* Stringify JSON with specific formatting.
* Applies indentation and line ending preferences.
*
* @param content - Object to stringify
* @param formatting - Formatting preferences (indent and newline)
* @returns Formatted JSON string with trailing newline
*
* @example
* ```ts
* stringifyWithFormatting(
* { key: 'value' },
* { indent: 4, newline: '\r\n' }
* )
* // => '{\r\n "key": "value"\r\n}\r\n'
* ```
*/
export declare function stringifyWithFormatting(content: Record<string, unknown>, formatting: JsonFormatting): string;
/**
* Strip formatting symbols from content object.
* Removes Symbol.for('indent') and Symbol.for('newline') from the object.
*
* @param content - Content object with potential symbol properties
* @returns Object with symbols removed
*/
export declare function stripFormattingSymbols(content: Record<string | symbol, unknown>): Record<string, unknown>;
/**
* Extract formatting from content object that has symbol-based metadata.
*
* @param content - Content object with Symbol.for('indent') and Symbol.for('newline')
* @returns Formatting metadata, or defaults if symbols not present
*/
export declare function getFormattingFromContent(content: Record<string | symbol, unknown>): JsonFormatting;
/**
* Determine if content should be saved based on changes and options.
* Compares current content with original content and respects options like
* ignoreWhitespace and sort.
*
* @param currentContent - Current content object (may include formatting symbols)
* @param originalContent - Original content for comparison (may include formatting symbols)
* @param originalFileContent - Original file content as string (for whitespace comparison)
* @param options - Options controlling save behavior
* @returns true if content should be saved, false otherwise
*
* @example
* ```ts
* const current = { key: 'new-value', [Symbol.for('indent')]: 2 }
* const original = { key: 'old-value', [Symbol.for('indent')]: 2 }
* shouldSave(current, original, '{\n "key": "old-value"\n}\n')
* // => true
* ```
*/
export declare function shouldSave(currentContent: Record<string | symbol, unknown>, originalContent: Record<string | symbol, unknown> | undefined, originalFileContent: string, options?: ShouldSaveOptions): boolean;
"use strict";
/* Socket Lib - Built with esbuild */
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var format_exports = {};
__export(format_exports, {
INDENT_SYMBOL: () => INDENT_SYMBOL,
NEWLINE_SYMBOL: () => NEWLINE_SYMBOL,
detectIndent: () => detectIndent,
detectNewline: () => detectNewline,
extractFormatting: () => extractFormatting,
getDefaultFormatting: () => getDefaultFormatting,
getFormattingFromContent: () => getFormattingFromContent,
shouldSave: () => shouldSave,
sortKeys: () => sortKeys,
stringifyWithFormatting: () => stringifyWithFormatting,
stripFormattingSymbols: () => stripFormattingSymbols
});
module.exports = __toCommonJS(format_exports);
const INDENT_SYMBOL = Symbol.for("indent");
const NEWLINE_SYMBOL = Symbol.for("newline");
function detectIndent(json) {
const match = json.match(/^[{[][\r\n]+(\s+)/m);
if (!match) {
return 2;
}
const indent = match[1];
if (/^ +$/.test(indent)) {
return indent.length;
}
return indent;
}
function detectNewline(json) {
const match = json.match(/\r?\n/);
return match ? match[0] : "\n";
}
function extractFormatting(json) {
return {
indent: detectIndent(json),
newline: detectNewline(json)
};
}
function getDefaultFormatting() {
return {
indent: 2,
newline: "\n"
};
}
function sortKeys(obj) {
const sorted = { __proto__: null };
const keys = Object.keys(obj).sort();
for (const key of keys) {
sorted[key] = obj[key];
}
return sorted;
}
function stringifyWithFormatting(content, formatting) {
const { indent, newline } = formatting;
const format = indent === void 0 || indent === null ? " " : indent;
const eol = newline === void 0 || newline === null ? "\n" : newline;
return `${JSON.stringify(content, void 0, format)}
`.replace(/\n/g, eol);
}
function stripFormattingSymbols(content) {
const {
[INDENT_SYMBOL]: _indent,
[NEWLINE_SYMBOL]: _newline,
...rest
} = content;
return rest;
}
function getFormattingFromContent(content) {
const indent = content[INDENT_SYMBOL];
const newline = content[NEWLINE_SYMBOL];
return {
indent: indent === void 0 || indent === null ? 2 : indent,
newline: newline === void 0 || newline === null ? "\n" : newline
};
}
function shouldSave(currentContent, originalContent, originalFileContent, options = {}) {
const { ignoreWhitespace = false, sort = false, sortFn } = options;
const content = stripFormattingSymbols(currentContent);
const sortedContent = sortFn ? sortFn(content) : sort ? sortKeys(content) : content;
const origContent = originalContent ? stripFormattingSymbols(originalContent) : {};
if (ignoreWhitespace) {
const util = require("node:util");
return !util.isDeepStrictEqual(sortedContent, origContent);
}
const formatting = getFormattingFromContent(currentContent);
const newFileContent = stringifyWithFormatting(sortedContent, formatting);
return newFileContent.trim() !== originalFileContent.trim();
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
INDENT_SYMBOL,
NEWLINE_SYMBOL,
detectIndent,
detectNewline,
extractFormatting,
getDefaultFormatting,
getFormattingFromContent,
shouldSave,
sortKeys,
stringifyWithFormatting,
stripFormattingSymbols
});
import type { JsonParseOptions, JsonPrimitive, JsonValue } from './types';
/**
* Check if a value is a JSON primitive type.
* JSON primitives are: `null`, `boolean`, `number`, or `string`.
*
* @param value - Value to check
* @returns `true` if value is a JSON primitive, `false` otherwise
*
* @example
* ```ts
* isJsonPrimitive(null) // => true
* isJsonPrimitive(true) // => true
* isJsonPrimitive(42) // => true
* isJsonPrimitive('hello') // => true
* isJsonPrimitive({}) // => false
* isJsonPrimitive([]) // => false
* isJsonPrimitive(undefined) // => false
* ```
*/
/*@__NO_SIDE_EFFECTS__*/
export declare function isJsonPrimitive(value: unknown): value is JsonPrimitive;
/**
* Parse JSON content with automatic Buffer handling and BOM stripping.
* Provides safer JSON parsing with helpful error messages and optional error suppression.
*
* Features:
* - Automatic UTF-8 Buffer conversion
* - BOM (Byte Order Mark) stripping for cross-platform compatibility
* - Enhanced error messages with filepath context
* - Optional error suppression (returns `undefined` instead of throwing)
* - Optional reviver for transforming parsed values
*
* @param content - JSON string or Buffer to parse
* @param options - Optional parsing configuration
* @returns Parsed JSON value, or `undefined` if parsing fails and `throws` is `false`
*
* @throws {SyntaxError} When JSON is invalid and `throws` is `true` (default)
*
* @example
* ```ts
* // Basic usage
* const data = jsonParse('{"name":"example"}')
* console.log(data.name) // => 'example'
*
* // Parse Buffer with UTF-8 BOM
* const buffer = Buffer.from('\uFEFF{"value":42}')
* const data = jsonParse(buffer)
* console.log(data.value) // => 42
*
* // Enhanced error messages with filepath
* try {
* jsonParse('invalid', { filepath: 'config.json' })
* } catch (err) {
* console.error(err.message)
* // => "config.json: Unexpected token i in JSON at position 0"
* }
*
* // Suppress errors
* const result = jsonParse('invalid', { throws: false })
* console.log(result) // => undefined
*
* // Transform values with reviver
* const json = '{"created":"2024-01-15T10:30:00Z"}'
* const data = jsonParse(json, {
* reviver: (key, value) => {
* if (key === 'created' && typeof value === 'string') {
* return new Date(value)
* }
* return value
* }
* })
* console.log(data.created instanceof Date) // => true
* ```
*/
/*@__NO_SIDE_EFFECTS__*/
export declare function jsonParse(content: string | Buffer, options?: JsonParseOptions | undefined): JsonValue | undefined;
"use strict";
/* Socket Lib - Built with esbuild */
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var parse_exports = {};
__export(parse_exports, {
isJsonPrimitive: () => isJsonPrimitive,
jsonParse: () => jsonParse
});
module.exports = __toCommonJS(parse_exports);
var import_strings = require("../strings");
const JSONParse = JSON.parse;
// @__NO_SIDE_EFFECTS__
function isBuffer(x) {
if (!x || typeof x !== "object") {
return false;
}
const obj = x;
if (typeof obj["length"] !== "number") {
return false;
}
if (typeof obj["copy"] !== "function" || typeof obj["slice"] !== "function") {
return false;
}
if (typeof obj["length"] === "number" && obj["length"] > 0 && typeof obj[0] !== "number") {
return false;
}
const Ctor = x.constructor;
return !!(typeof Ctor?.isBuffer === "function" && Ctor.isBuffer(x));
}
// @__NO_SIDE_EFFECTS__
function isJsonPrimitive(value) {
return value === null || typeof value === "boolean" || typeof value === "number" || typeof value === "string";
}
// @__NO_SIDE_EFFECTS__
function jsonParse(content, options) {
const { filepath, reviver, throws } = {
__proto__: null,
...options
};
const shouldThrow = throws === void 0 || !!throws;
const jsonStr = /* @__PURE__ */ isBuffer(content) ? content.toString("utf8") : content;
try {
return JSONParse((0, import_strings.stripBom)(jsonStr), reviver);
} catch (e) {
if (shouldThrow) {
const error = e;
if (error && typeof filepath === "string") {
error.message = `${filepath}: ${error.message}`;
}
throw error;
}
}
return void 0;
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
isJsonPrimitive,
jsonParse
});
/**
* @fileoverview JSON type definitions and interfaces.
*/
/**
* JSON primitive types: `null`, `boolean`, `number`, or `string`.
*
* @example
* ```ts
* const primitives: JsonPrimitive[] = [null, true, 42, 'hello']
* ```
*/
export type JsonPrimitive = null | boolean | number | string;
/**
* A JSON array containing JSON values.
*
* @example
* ```ts
* const arr: JsonArray = [1, 'two', { three: 3 }, [4, 5]]
* ```
*/
export interface JsonArray extends Array<JsonValue> {
}
/**
* A JSON object with string keys and JSON values.
*
* @example
* ```ts
* const obj: JsonObject = {
* name: 'example',
* count: 42,
* active: true,
* nested: { key: 'value' }
* }
* ```
*/
export interface JsonObject {
[key: string]: JsonValue;
}
/**
* Any valid JSON value: primitive, object, or array.
*
* @example
* ```ts
* const values: JsonValue[] = [
* null,
* true,
* 42,
* 'hello',
* { key: 'value' },
* [1, 2, 3]
* ]
* ```
*/
export type JsonValue = JsonPrimitive | JsonObject | JsonArray;
/**
* Reviver function for transforming parsed JSON values.
* Called for each key-value pair during parsing.
*
* @param key - The object key or array index being parsed
* @param value - The parsed value
* @returns The transformed value (or original if no transform needed)
*
* @example
* ```ts
* // Convert date strings to Date objects
* const reviver: JsonReviver = (key, value) => {
* if (typeof value === 'string' && /^\d{4}-\d{2}-\d{2}/.test(value)) {
* return new Date(value)
* }
* return value
* }
* ```
*/
export type JsonReviver = (key: string, value: unknown) => unknown;
/**
* Options for JSON parsing operations.
*/
export interface JsonParseOptions {
/**
* Optional filepath for improved error messages.
* When provided, errors will be prefixed with the filepath.
*
* @example
* ```ts
* // Error message will be: "config.json: Unexpected token } in JSON"
* jsonParse('invalid', { filepath: 'config.json' })
* ```
*/
filepath?: string | undefined;
/**
* Optional reviver function to transform parsed values.
* Called for each key-value pair during parsing.
*
* @example
* ```ts
* // Convert ISO date strings to Date objects
* const options = {
* reviver: (key, value) => {
* if (typeof value === 'string' && /^\d{4}-\d{2}-\d{2}/.test(value)) {
* return new Date(value)
* }
* return value
* }
* }
* ```
*/
reviver?: JsonReviver | undefined;
/**
* Whether to throw on parse errors.
* When `false`, returns `undefined` instead of throwing.
*
* @default true
*
* @example
* ```ts
* // Throws error
* jsonParse('invalid', { throws: true })
*
* // Returns undefined
* const result = jsonParse('invalid', { throws: false })
* ```
*/
throws?: boolean | undefined;
}
/**
* Options for saving editable JSON files.
*/
export interface EditableJsonSaveOptions {
/**
* Whether to ignore whitespace-only changes when determining if save is needed.
* @default false
*/
ignoreWhitespace?: boolean | undefined;
/**
* Whether to sort object keys alphabetically before saving.
* @default false
*/
sort?: boolean | undefined;
}
/**
* Options for creating or loading editable JSON instances.
*/
export interface EditableJsonOptions<T = Record<string, unknown>> {
/**
* File path for the JSON file (optional for in-memory instances).
*/
path?: string | undefined;
/**
* Whether to create the file if it doesn't exist during load.
* @default false
*/
create?: boolean | undefined;
/**
* Initial data to populate the instance with.
*/
data?: T | undefined;
}
/**
* EditableJson instance interface for JSON file manipulation.
* Provides core functionality for loading, editing, and saving JSON files
* while preserving formatting (indentation and line endings).
*/
export interface EditableJsonInstance<T = Record<string, unknown>> {
/**
* The parsed JSON content as a readonly object.
* @readonly
*/
content: Readonly<T>;
/**
* Create a new JSON file at the specified path.
* @param path - The file path where JSON will be created
*/
create(path: string): this;
/**
* Initialize the instance from a content object.
* Note: Disables saving when used (no file path associated).
* @param content - The JSON content object
*/
fromContent(content: unknown): this;
/**
* Initialize the instance from a JSON string.
* @param json - The JSON content as a string
*/
fromJSON(json: string): this;
/**
* Load a JSON file from the specified path.
* @param path - The file path to load
* @param create - Whether to create the file if it doesn't exist
*/
load(path: string, create?: boolean): Promise<this>;
/**
* Update the JSON content with new values.
* @param content - Partial object with fields to update
*/
update(content: Partial<T>): this;
/**
* Save the JSON file to disk.
* @param options - Save options for formatting and sorting
*/
save(options?: EditableJsonSaveOptions): Promise<boolean>;
/**
* Synchronously save the JSON file to disk.
* @param options - Save options for formatting and sorting
*/
saveSync(options?: EditableJsonSaveOptions): boolean;
/**
* Check if the JSON will be saved based on current changes.
* @param options - Save options to evaluate
*/
willSave(options?: EditableJsonSaveOptions): boolean;
/**
* The full path to the JSON file.
* @readonly
*/
readonly filename: string;
/**
* The directory path containing the JSON file.
* @readonly
*/
readonly path: string | undefined;
}
/**
* EditableJson constructor interface.
*/
export interface EditableJsonConstructor<T = Record<string, unknown>> {
new (): EditableJsonInstance<T>;
create(path: string, opts?: EditableJsonOptions<T>): Promise<EditableJsonInstance<T>>;
load(path: string, opts?: EditableJsonOptions<T>): Promise<EditableJsonInstance<T>>;
}
"use strict";
/* Socket Lib - Built with esbuild */
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var types_exports = {};
module.exports = __toCommonJS(types_exports);
import type { EditablePackageJsonOptions, NormalizeOptions, PackageJson, SaveOptions } from '../packages';
// Define the interface for the dynamic class
interface EditablePackageJsonConstructor {
new (): EditablePackageJsonInstance;
fixSteps: unknown[];
normalizeSteps: unknown[];
prepareSteps: unknown[];
create(path: string, opts?: EditablePackageJsonOptions): Promise<EditablePackageJsonInstance>;
fix(path: string, opts?: unknown): Promise<EditablePackageJsonInstance>;
load(path: string, opts?: EditablePackageJsonOptions): Promise<EditablePackageJsonInstance>;
normalize(path: string, opts?: NormalizeOptions): Promise<EditablePackageJsonInstance>;
prepare(path: string, opts?: unknown): Promise<EditablePackageJsonInstance>;
}
/**
* EditablePackageJson instance interface extending NPMCliPackageJson functionality.
* Provides enhanced package.json manipulation with Socket-specific features.
* @extends NPMCliPackageJson (from @npmcli/package-json)
*/
export interface EditablePackageJsonInstance {
/**
* The parsed package.json content as a readonly object.
* @readonly
*/
content: Readonly<PackageJson>;
/**
* Create a new package.json file at the specified path.
* @param path - The directory path where package.json will be created
*/
create(path: string): this;
/**
* Apply automatic fixes to the package.json based on npm standards.
* @param opts - Optional fix configuration
*/
fix(opts?: unknown | undefined): Promise<this>;
/**
* Initialize the instance from a content object.
* @param content - The package.json content object
*/
fromContent(content: unknown): this;
/**
* Initialize the instance from a JSON string.
* @param json - The package.json content as a JSON string
*/
fromJSON(json: string): this;
/**
* Load a package.json file from the specified path.
* @param path - The directory containing the package.json
* @param create - Whether to create the file if it doesn't exist
*/
load(path: string, create?: boolean): Promise<this>;
/**
* Normalize the package.json content according to npm standards.
* @param opts - Normalization options
*/
normalize(opts?: NormalizeOptions): Promise<this>;
/**
* Prepare the package.json for publishing.
* @param opts - Preparation options
*/
prepare(opts?: unknown): Promise<this>;
/**
* Update the package.json content with new values.
* @param content - Partial package.json object with fields to update
* @override from NPMCliPackageJson
*/
update(content: Partial<PackageJson>): this;
/**
* Save the package.json file to disk.
* @param options - Save options for formatting and sorting
* @override from NPMCliPackageJson
*/
save(options?: SaveOptions | undefined): Promise<boolean>;
/**
* Synchronously save the package.json file to disk.
* @param options - Save options for formatting and sorting
*/
saveSync(options?: SaveOptions | undefined): boolean;
/**
* Check if the package.json will be saved based on current changes.
* @param options - Save options to evaluate
*/
willSave(options?: SaveOptions | undefined): boolean;
}
/**
* Get the EditablePackageJson class for package.json manipulation.
*/
/*@__NO_SIDE_EFFECTS__*/
export declare function getEditablePackageJsonClass(): EditablePackageJsonConstructor;
/**
* Convert a package.json object to an editable instance.
*/
/*@__NO_SIDE_EFFECTS__*/
export declare function pkgJsonToEditable(pkgJson: PackageJson, options?: EditablePackageJsonOptions): unknown;
/**
* Convert package.json to editable instance with file persistence.
*/
/*@__NO_SIDE_EFFECTS__*/
export declare function toEditablePackageJson(pkgJson: PackageJson, options?: EditablePackageJsonOptions): Promise<unknown>;
/**
* Convert package.json to editable instance with file persistence synchronously.
*/
/*@__NO_SIDE_EFFECTS__*/
export declare function toEditablePackageJsonSync(pkgJson: PackageJson, options?: EditablePackageJsonOptions): unknown;
export {};
"use strict";
/* Socket Lib - Built with esbuild */
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var edit_exports = {};
__export(edit_exports, {
getEditablePackageJsonClass: () => getEditablePackageJsonClass,
pkgJsonToEditable: () => pkgJsonToEditable,
toEditablePackageJson: () => toEditablePackageJson,
toEditablePackageJsonSync: () => toEditablePackageJsonSync
});
module.exports = __toCommonJS(edit_exports);
var import_package_json = __toESM(require("../external/@npmcli/package-json"));
var import_read_package = require("../external/@npmcli/package-json/lib/read-package");
var import_sort = require("../external/@npmcli/package-json/lib/sort");
var import_format = require("../json/format");
var import_normalize = require("../paths/normalize");
var import_normalize2 = require("./normalize");
var import_packages = require("../paths/packages");
let _EditablePackageJsonClass;
let _fs;
// @__NO_SIDE_EFFECTS__
function getFs() {
if (_fs === void 0) {
_fs = require("node:fs");
}
return _fs;
}
let _path;
// @__NO_SIDE_EFFECTS__
function getPath() {
if (_path === void 0) {
_path = require("node:path");
}
return _path;
}
let _util;
// @__NO_SIDE_EFFECTS__
function getUtil() {
if (_util === void 0) {
_util = require("node:util");
}
return _util;
}
// @__NO_SIDE_EFFECTS__
function getEditablePackageJsonClass() {
if (_EditablePackageJsonClass === void 0) {
_EditablePackageJsonClass = class EditablePackageJson extends import_package_json.default {
static fixSteps = import_package_json.default.fixSteps;
static normalizeSteps = import_package_json.default.normalizeSteps;
static prepareSteps = import_package_json.default.prepareSteps;
_canSave = true;
_path = void 0;
_readFileContent = "";
_readFileJson = void 0;
get content() {
return super.content;
}
get filename() {
const path = this._path;
if (!path) {
return "";
}
if (path.endsWith("package.json")) {
return path;
}
const nodePath = /* @__PURE__ */ getPath();
return nodePath.join(path, "package.json");
}
static async create(path, opts = {}) {
const p = new _EditablePackageJsonClass();
await p.create(path);
return opts.data ? p.update(opts.data) : p;
}
static async fix(path, opts) {
const p = new _EditablePackageJsonClass();
await p.load(path, true);
return await p.fix(opts);
}
static async load(path, opts = {}) {
const p = new _EditablePackageJsonClass();
if (!opts.create) {
return await p.load(path);
}
try {
return await p.load(path);
} catch (err) {
if (!err.message.startsWith("Could not read package.json")) {
throw err;
}
return p.create(path);
}
}
static async normalize(path, opts) {
const p = new _EditablePackageJsonClass();
await p.load(path);
return await p.normalize(opts);
}
static async prepare(path, opts) {
const p = new _EditablePackageJsonClass();
await p.load(path, true);
return await p.prepare(opts);
}
create(path) {
super.create(path);
this._path = path;
return this;
}
async fix(opts = {}) {
await super.fix(opts);
return this;
}
fromContent(data) {
super.fromContent(data);
this._canSave = false;
return this;
}
fromJSON(data) {
super.fromJSON(data);
return this;
}
async load(path, create) {
this._path = path;
const { promises: fsPromises } = /* @__PURE__ */ getFs();
let parseErr;
try {
this._readFileContent = await (0, import_read_package.read)(this.filename);
} catch (err) {
if (!create) {
throw err;
}
parseErr = err;
}
if (parseErr) {
const nodePath = /* @__PURE__ */ getPath();
const indexFile = nodePath.resolve(this.path || "", "index.js");
let indexFileContent;
try {
indexFileContent = await fsPromises.readFile(indexFile, "utf8");
} catch {
throw parseErr;
}
try {
this.fromContent(indexFileContent);
} catch {
throw parseErr;
}
this._canSave = false;
return this;
}
this.fromJSON(this._readFileContent);
this._readFileJson = (0, import_read_package.parse)(this._readFileContent);
return this;
}
async normalize(opts = {}) {
await super.normalize(opts);
return this;
}
get path() {
return this._path;
}
async prepare(opts = {}) {
await super.prepare(opts);
return this;
}
async save(options) {
if (!this._canSave || this.content === void 0) {
throw new Error("No package.json to save to");
}
if (!(0, import_format.shouldSave)(
this.content,
this._readFileJson,
this._readFileContent,
{ ...options, sortFn: options?.sort ? import_sort.packageSort : void 0 }
)) {
return false;
}
const content = (0, import_format.stripFormattingSymbols)(
this.content
);
const sortedContent = options?.sort ? (0, import_sort.packageSort)(content) : content;
const formatting = (0, import_format.getFormattingFromContent)(
this.content
);
const fileContent = (0, import_format.stringifyWithFormatting)(sortedContent, formatting);
const { promises: fsPromises } = /* @__PURE__ */ getFs();
await fsPromises.writeFile(this.filename, fileContent);
this._readFileContent = fileContent;
this._readFileJson = (0, import_read_package.parse)(fileContent);
return true;
}
saveSync(options) {
if (!this._canSave || this.content === void 0) {
throw new Error("No package.json to save to");
}
const { ignoreWhitespace = false, sort = false } = {
__proto__: null,
...options
};
const {
[Symbol.for("indent")]: indent,
[Symbol.for("newline")]: newline,
...rest
} = this.content;
const content = sort ? (0, import_sort.packageSort)(rest) : rest;
if (ignoreWhitespace && (/* @__PURE__ */ getUtil()).isDeepStrictEqual(content, this._readFileJson)) {
return false;
}
const format = indent === void 0 || indent === null ? " " : indent;
const eol = newline === void 0 || newline === null ? "\n" : newline;
const fileContent = `${JSON.stringify(
content,
void 0,
format
)}
`.replace(/\n/g, eol);
if (!ignoreWhitespace && fileContent.trim() === this._readFileContent.trim()) {
return false;
}
const fs = /* @__PURE__ */ getFs();
fs.writeFileSync(this.filename, fileContent);
this._readFileContent = fileContent;
this._readFileJson = (0, import_read_package.parse)(fileContent);
return true;
}
update(content) {
super.update(content);
return this;
}
willSave(options) {
const { ignoreWhitespace = false, sort = false } = {
__proto__: null,
...options
};
if (!this._canSave || this.content === void 0) {
return false;
}
const {
[Symbol.for("indent")]: indent,
[Symbol.for("newline")]: newline,
...rest
} = this.content;
const content = sort ? (0, import_sort.packageSort)(rest) : rest;
if (ignoreWhitespace && (/* @__PURE__ */ getUtil()).isDeepStrictEqual(content, this._readFileJson)) {
return false;
}
const format = indent === void 0 || indent === null ? " " : indent;
const eol = newline === void 0 || newline === null ? "\n" : newline;
const fileContent = `${JSON.stringify(
content,
void 0,
format
)}
`.replace(/\n/g, eol);
if (!ignoreWhitespace && fileContent.trim() === this._readFileContent.trim()) {
return false;
}
return true;
}
};
}
return _EditablePackageJsonClass;
}
// @__NO_SIDE_EFFECTS__
function pkgJsonToEditable(pkgJson, options) {
const { normalize, ...normalizeOptions } = {
__proto__: null,
...options
};
const EditablePackageJson = /* @__PURE__ */ getEditablePackageJsonClass();
return new EditablePackageJson().fromContent(
normalize ? (0, import_normalize2.normalizePackageJson)(pkgJson, normalizeOptions) : pkgJson
);
}
// @__NO_SIDE_EFFECTS__
async function toEditablePackageJson(pkgJson, options) {
const { path: filepath, ...pkgJsonToEditableOptions } = {
__proto__: null,
...options
};
const { normalize, ...normalizeOptions } = pkgJsonToEditableOptions;
if (typeof filepath !== "string") {
return /* @__PURE__ */ pkgJsonToEditable(pkgJson, pkgJsonToEditableOptions);
}
const EditablePackageJson = /* @__PURE__ */ getEditablePackageJsonClass();
const pkgJsonPath = (0, import_packages.resolvePackageJsonDirname)(filepath);
return (await EditablePackageJson.load(pkgJsonPath, { create: true })).fromJSON(
`${JSON.stringify(
normalize ? (0, import_normalize2.normalizePackageJson)(pkgJson, {
...(0, import_normalize.isNodeModules)(pkgJsonPath) ? {} : { preserve: ["repository"] },
...normalizeOptions
}) : pkgJson,
null,
2
)}
`
);
}
// @__NO_SIDE_EFFECTS__
function toEditablePackageJsonSync(pkgJson, options) {
const { path: filepath, ...pkgJsonToEditableOptions } = {
__proto__: null,
...options
};
const { normalize, ...normalizeOptions } = pkgJsonToEditableOptions;
if (typeof filepath !== "string") {
return /* @__PURE__ */ pkgJsonToEditable(pkgJson, pkgJsonToEditableOptions);
}
const EditablePackageJson = /* @__PURE__ */ getEditablePackageJsonClass();
const pkgJsonPath = (0, import_packages.resolvePackageJsonDirname)(filepath);
return new EditablePackageJson().create(pkgJsonPath).fromJSON(
`${JSON.stringify(
normalize ? (0, import_normalize2.normalizePackageJson)(pkgJson, {
...(0, import_normalize.isNodeModules)(pkgJsonPath) ? {} : { preserve: ["repository"] },
...normalizeOptions
}) : pkgJson,
null,
2
)}
`
);
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
getEditablePackageJsonClass,
pkgJsonToEditable,
toEditablePackageJson,
toEditablePackageJsonSync
});
+67
-0

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

## [5.0.0](https://github.com/SocketDev/socket-lib/releases/tag/v5.0.0) - 2025-12-04
### Added
- **json/edit**: New `EditableJson` base class for generic JSON file manipulation with formatting preservation
- Extracted from `EditablePackageJson` to enable code reuse via composition pattern
- Supports reading, modifying, and writing JSON files while preserving formatting
- Export: `@socketsecurity/lib/json/edit`
- **json/format**: New JSON formatting utilities for consistent JSON manipulation
- Functions for analyzing and preserving JSON formatting patterns
- Export: `@socketsecurity/lib/json/format`
- **json/parse**: New JSON parsing utilities
- `isJsonPrimitive()`: Check if value is a JSON primitive type
- `jsonParse()`: Parse JSON with error handling
- Export: `@socketsecurity/lib/json/parse`
- **json/types**: New JSON type definitions and interfaces
- Export: `@socketsecurity/lib/json/types`
- **dlx/cache**: New DLX cache utilities
- `generateCacheKey()`: Generate cache keys for DLX packages
- Export: `@socketsecurity/lib/dlx/cache`
- **dlx/dir**: New DLX directory management utilities
- `clearDlx()`, `clearDlxSync()`: Clear DLX directory
- `dlxDirExists()`, `dlxDirExistsAsync()`: Check if DLX directory exists
- `ensureDlxDir()`, `ensureDlxDirSync()`: Ensure DLX directory exists
- Export: `@socketsecurity/lib/dlx/dir`
- **dlx/packages**: New DLX package management utilities
- `isDlxPackageInstalled()`, `isDlxPackageInstalledAsync()`: Check if package is installed
- `listDlxPackages()`, `listDlxPackagesAsync()`: List installed packages
- `removeDlxPackage()`, `removeDlxPackageSync()`: Remove installed packages
- Export: `@socketsecurity/lib/dlx/packages`
- **dlx/paths**: New DLX path utilities
- `getDlxPackageDir()`: Get package directory path
- `getDlxInstalledPackageDir()`: Get installed package directory path
- `getDlxPackageJsonPath()`: Get package.json path
- `getDlxPackageNodeModulesDir()`: Get node_modules directory path
- `isInSocketDlx()`: Check if path is in DLX directory
- Export: `@socketsecurity/lib/dlx/paths`
### Changed
- **BREAKING**: Reorganized module paths for better structure and discoverability
- `@socketsecurity/lib/json/editable` → `@socketsecurity/lib/json/edit`
- `@socketsecurity/lib/packages/editable` → `@socketsecurity/lib/packages/edit`
- `@socketsecurity/lib/maintained-node-versions` → `@socketsecurity/lib/constants/maintained-node-versions`
- `@socketsecurity/lib/package-default-node-range` → `@socketsecurity/lib/constants/package-default-node-range`
- `@socketsecurity/lib/package-default-socket-categories` → `@socketsecurity/lib/constants/package-default-socket-categories`
- `@socketsecurity/lib/lifecycle-script-names` → `@socketsecurity/lib/constants/lifecycle-script-names`
- `@socketsecurity/lib/dlx` → Split into `@socketsecurity/lib/dlx/cache`, `@socketsecurity/lib/dlx/dir`, `@socketsecurity/lib/dlx/packages`, `@socketsecurity/lib/dlx/paths`
- `@socketsecurity/lib/dlx-binary` → `@socketsecurity/lib/dlx/binary`
- `@socketsecurity/lib/dlx-manifest` → `@socketsecurity/lib/dlx/manifest`
- `@socketsecurity/lib/dlx-package` → `@socketsecurity/lib/dlx/package`
- **json**: Reorganized JSON utilities into modular submodules (json/edit, json/format, json/parse, json/types)
- Removed barrel index file in favor of direct submodule imports
- Better separation of concerns and tree-shaking
- **dlx**: Split monolithic DLX module into focused submodules (cache, dir, packages, paths)
- Improved modularity and maintainability
- Better code organization and discoverability
## [4.4.0](https://github.com/SocketDev/socket-lib/releases/tag/v4.4.0) - 2025-11-25

@@ -10,0 +77,0 @@

+1
-1

@@ -44,3 +44,3 @@ "use strict";

module.exports = __toCommonJS(node_exports);
var import_maintained_node_versions = require("../maintained-node-versions");
var import_maintained_node_versions = require("./maintained-node-versions");
const NODE_VERSION = process.version;

@@ -47,0 +47,0 @@ function getNodeVersion() {

@@ -46,5 +46,5 @@ "use strict";

var import_npm = require("../env/npm");
var import_lifecycle_script_names = require("../lifecycle-script-names");
var import_package_default_node_range = require("../package-default-node-range");
var import_package_default_socket_categories = require("../package-default-socket-categories");
var import_lifecycle_script_names = require("./lifecycle-script-names");
var import_package_default_node_range = require("./package-default-node-range");
var import_package_default_socket_categories = require("./package-default-socket-categories");
var import_package_extensions = require("../package-extensions");

@@ -51,0 +51,0 @@ var import_pacote = __toESM(require("../external/pacote"));

@@ -7,3 +7,3 @@ /**

import type { MakeDirectoryOptions, ObjectEncodingOptions, OpenMode, PathLike } from 'fs';
import type { JsonReviver } from './json';
import type { JsonReviver } from './json/types';
import { type Remap } from './objects';

@@ -549,3 +549,3 @@ /**

/*@__NO_SIDE_EFFECTS__*/
export declare function readJson(filepath: PathLike, options?: ReadJsonOptions | string | undefined): Promise<import("./json").JsonValue>;
export declare function readJson(filepath: PathLike, options?: ReadJsonOptions | string | undefined): Promise<import("./json/types").JsonValue>;
/**

@@ -580,3 +580,3 @@ * Read and parse a JSON file synchronously.

/*@__NO_SIDE_EFFECTS__*/
export declare function readJsonSync(filepath: PathLike, options?: ReadJsonOptions | string | undefined): import("./json").JsonValue;
export declare function readJsonSync(filepath: PathLike, options?: ReadJsonOptions | string | undefined): import("./json/types").JsonValue;
/**

@@ -583,0 +583,0 @@ * Safely delete a file or directory asynchronously with built-in protections.

@@ -57,3 +57,3 @@ "use strict";

var import_globs = require("./globs");
var import_json = require("./json");
var import_parse = require("./json/parse");
var import_objects = require("./objects");

@@ -459,3 +459,3 @@ var import_normalize = require("./paths/normalize");

}
return (0, import_json.jsonParse)(content, {
return (0, import_parse.jsonParse)(content, {
filepath: String(filepath),

@@ -503,3 +503,3 @@ reviver,

}
return (0, import_json.jsonParse)(content, {
return (0, import_parse.jsonParse)(content, {
filepath: String(filepath),

@@ -506,0 +506,0 @@ reviver,

@@ -6,3 +6,3 @@ /**

import type { CategoryString } from './types';
import { getEditablePackageJsonClass, pkgJsonToEditable, toEditablePackageJson, toEditablePackageJsonSync } from './packages/editable';
import { getEditablePackageJsonClass, pkgJsonToEditable, toEditablePackageJson, toEditablePackageJsonSync } from './packages/edit';
import { findTypesForSubpath, getExportFilePaths, getSubpaths, isConditionalExports, isSubpathExports, resolvePackageJsonEntryExports } from './packages/exports';

@@ -23,3 +23,3 @@ import { isolatePackage } from './packages/isolation';

// Re-export the EditablePackageJson instance type for convenient access
export type EditablePackageJson = import('./packages/editable').EditablePackageJsonInstance;
export type EditablePackageJson = import('./packages/edit').EditablePackageJsonInstance;
/**

@@ -26,0 +26,0 @@ * Extended PackageJson type based on NPMCliPackageJson.Content with Socket-specific additions.

@@ -34,3 +34,3 @@ "use strict";

findTypesForSubpath: () => import_exports.findTypesForSubpath,
getEditablePackageJsonClass: () => import_editable.getEditablePackageJsonClass,
getEditablePackageJsonClass: () => import_edit.getEditablePackageJsonClass,
getExportFilePaths: () => import_exports.getExportFilePaths,

@@ -54,3 +54,3 @@ getProvenanceDetails: () => import_provenance.getProvenanceDetails,

parseSpdxExp: () => import_licenses.parseSpdxExp,
pkgJsonToEditable: () => import_editable.pkgJsonToEditable,
pkgJsonToEditable: () => import_edit.pkgJsonToEditable,
readPackageJson: () => import_operations.readPackageJson,

@@ -67,4 +67,4 @@ readPackageJsonSync: () => import_operations.readPackageJsonSync,

resolveRegistryPackageName: () => import_operations.resolveRegistryPackageName,
toEditablePackageJson: () => import_editable.toEditablePackageJson,
toEditablePackageJsonSync: () => import_editable.toEditablePackageJsonSync,
toEditablePackageJson: () => import_edit.toEditablePackageJson,
toEditablePackageJsonSync: () => import_edit.toEditablePackageJsonSync,
unescapeScope: () => import_normalize.unescapeScope,

@@ -74,3 +74,3 @@ visitLicenses: () => import_licenses.visitLicenses

module.exports = __toCommonJS(packages_exports);
var import_editable = require("./packages/editable");
var import_edit = require("./packages/edit");
var import_exports = require("./packages/exports");

@@ -77,0 +77,0 @@ var import_isolation = require("./packages/isolation");

@@ -58,3 +58,3 @@ "use strict";

var import_specs = require("./specs");
var import_editable = require("./editable");
var import_edit = require("./edit");
const abortSignal = (0, import_process.getAbortSignal)();

@@ -165,3 +165,3 @@ const packageExtensions = (0, import_packages.getPackageExtensions)();

if (editable) {
return await (0, import_editable.toEditablePackageJson)(pkgJson, {
return await (0, import_edit.toEditablePackageJson)(pkgJson, {
path: filepath,

@@ -185,3 +185,3 @@ normalize,

if (editable) {
return (0, import_editable.toEditablePackageJsonSync)(pkgJson, {
return (0, import_edit.toEditablePackageJsonSync)(pkgJson, {
path: filepath,

@@ -188,0 +188,0 @@ normalize,

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

@@ -154,2 +154,10 @@ "license": "MIT",

},
"./constants/lifecycle-script-names": {
"types": "./dist/constants/lifecycle-script-names.d.ts",
"default": "./dist/constants/lifecycle-script-names.js"
},
"./constants/maintained-node-versions": {
"types": "./dist/constants/maintained-node-versions.d.ts",
"default": "./dist/constants/maintained-node-versions.js"
},
"./constants/node": {

@@ -159,2 +167,10 @@ "types": "./dist/constants/node.d.ts",

},
"./constants/package-default-node-range": {
"types": "./dist/constants/package-default-node-range.d.ts",
"default": "./dist/constants/package-default-node-range.js"
},
"./constants/package-default-socket-categories": {
"types": "./dist/constants/package-default-socket-categories.d.ts",
"default": "./dist/constants/package-default-socket-categories.js"
},
"./constants/packages": {

@@ -208,18 +224,30 @@ "types": "./dist/constants/packages.d.ts",

},
"./dlx": {
"types": "./dist/dlx.d.ts",
"default": "./dist/dlx.js"
"./dlx/binary": {
"types": "./dist/dlx/binary.d.ts",
"default": "./dist/dlx/binary.js"
},
"./dlx-binary": {
"types": "./dist/dlx-binary.d.ts",
"default": "./dist/dlx-binary.js"
"./dlx/cache": {
"types": "./dist/dlx/cache.d.ts",
"default": "./dist/dlx/cache.js"
},
"./dlx-manifest": {
"types": "./dist/dlx-manifest.d.ts",
"default": "./dist/dlx-manifest.js"
"./dlx/dir": {
"types": "./dist/dlx/dir.d.ts",
"default": "./dist/dlx/dir.js"
},
"./dlx-package": {
"types": "./dist/dlx-package.d.ts",
"default": "./dist/dlx-package.js"
"./dlx/manifest": {
"types": "./dist/dlx/manifest.d.ts",
"default": "./dist/dlx/manifest.js"
},
"./dlx/package": {
"types": "./dist/dlx/package.d.ts",
"default": "./dist/dlx/package.js"
},
"./dlx/packages": {
"types": "./dist/dlx/packages.d.ts",
"default": "./dist/dlx/packages.js"
},
"./dlx/paths": {
"types": "./dist/dlx/paths.d.ts",
"default": "./dist/dlx/paths.js"
},
"./effects/pulse-frames": {

@@ -361,10 +389,18 @@ "types": "./dist/effects/pulse-frames.d.ts",

},
"./json": {
"types": "./dist/json.d.ts",
"default": "./dist/json.js"
"./json/edit": {
"types": "./dist/json/edit.d.ts",
"default": "./dist/json/edit.js"
},
"./lifecycle-script-names": {
"types": "./dist/lifecycle-script-names.d.ts",
"default": "./dist/lifecycle-script-names.js"
"./json/format": {
"types": "./dist/json/format.d.ts",
"default": "./dist/json/format.js"
},
"./json/parse": {
"types": "./dist/json/parse.d.ts",
"default": "./dist/json/parse.js"
},
"./json/types": {
"types": "./dist/json/types.d.ts",
"default": "./dist/json/types.js"
},
"./links": {

@@ -382,6 +418,2 @@ "types": "./dist/links/index.d.ts",

},
"./maintained-node-versions": {
"types": "./dist/maintained-node-versions.d.ts",
"default": "./dist/maintained-node-versions.js"
},
"./memoization": {

@@ -395,10 +427,2 @@ "types": "./dist/memoization.d.ts",

},
"./package-default-node-range": {
"types": "./dist/package-default-node-range.d.ts",
"default": "./dist/package-default-node-range.js"
},
"./package-default-socket-categories": {
"types": "./dist/package-default-socket-categories.d.ts",
"default": "./dist/package-default-socket-categories.js"
},
"./package-extensions": {

@@ -412,5 +436,5 @@ "types": "./dist/package-extensions.d.ts",

},
"./packages/editable": {
"types": "./dist/packages/editable.d.ts",
"default": "./dist/packages/editable.js"
"./packages/edit": {
"types": "./dist/packages/edit.d.ts",
"default": "./dist/packages/edit.js"
},

@@ -417,0 +441,0 @@ "./packages/exports": {

import type { SpawnExtra, SpawnOptions } from './spawn';
import { spawn } from './spawn';
export interface DlxBinaryOptions {
/**
* URL to download the binary from.
*/
url: string;
/**
* Optional name for the cached binary (defaults to URL hash).
*/
name?: string | undefined;
/**
* Expected checksum (sha256) for verification.
*/
checksum?: string | undefined;
/**
* Cache TTL in milliseconds (default: 7 days).
*/
cacheTtl?: number | undefined;
/**
* Force re-download even if cached.
* Aligns with npm/npx --force flag.
*/
force?: boolean | undefined;
/**
* Skip confirmation prompts (auto-approve).
* Aligns with npx --yes/-y flag.
*/
yes?: boolean | undefined;
/**
* Suppress output (quiet mode).
* Aligns with npx --quiet/-q and pnpm --silent/-s flags.
*/
quiet?: boolean | undefined;
/**
* Additional spawn options.
*/
spawnOptions?: SpawnOptions | undefined;
}
export interface DlxBinaryResult {
/** Path to the cached binary. */
binaryPath: string;
/** Whether the binary was newly downloaded. */
downloaded: boolean;
/** The spawn promise for the running process. */
spawnPromise: ReturnType<typeof spawn>;
}
/**
* Metadata structure for cached binaries (.dlx-metadata.json).
* Unified schema shared across TypeScript (dlxBinary) and C++ (socket_macho_decompress).
*
* Core Fields (present in all implementations):
* - version: Schema version (currently "1.0.0")
* - cache_key: First 16 chars of SHA-512 hash (matches directory name)
* - timestamp: Unix timestamp in milliseconds
* - checksum: Full hash of cached binary (SHA-512 for C++, SHA-256 for TypeScript)
* - checksum_algorithm: "sha512" or "sha256"
* - platform: "darwin" | "linux" | "win32"
* - arch: "x64" | "arm64"
* - size: Size of cached binary in bytes
* - source: Origin information
* - type: "download" (from URL) or "decompression" (from embedded binary)
* - url: Download URL (if type is "download")
* - path: Source binary path (if type is "decompression")
*
* Extra Fields (implementation-specific):
* - For C++ decompression:
* - compressed_size: Size of compressed data in bytes
* - compression_algorithm: Brotli level (numeric)
* - compression_ratio: original_size / compressed_size
*
* Example (TypeScript download):
* ```json
* {
* "version": "1.0.0",
* "cache_key": "a1b2c3d4e5f67890",
* "timestamp": 1730332800000,
* "checksum": "sha256-abc123...",
* "checksum_algorithm": "sha256",
* "platform": "darwin",
* "arch": "arm64",
* "size": 15000000,
* "source": {
* "type": "download",
* "url": "https://example.com/binary"
* }
* }
* ```
*
* Example (C++ decompression):
* ```json
* {
* "version": "1.0.0",
* "cache_key": "0123456789abcdef",
* "timestamp": 1730332800000,
* "checksum": "sha512-def456...",
* "checksum_algorithm": "sha512",
* "platform": "darwin",
* "arch": "arm64",
* "size": 13000000,
* "source": {
* "type": "decompression",
* "path": "/usr/local/bin/socket"
* },
* "extra": {
* "compressed_size": 1700000,
* "compression_algorithm": 3,
* "compression_ratio": 7.647
* }
* }
* ```
*
* @internal This interface documents the metadata file format.
*/
export interface DlxMetadata {
version: string;
cache_key: string;
timestamp: number;
checksum: string;
checksum_algorithm: string;
platform: string;
arch: string;
size: number;
source?: {
type: 'download' | 'decompression';
url?: string;
path?: string;
};
extra?: Record<string, unknown>;
}
/**
* Clean expired entries from the DLX cache.
*/
export declare function cleanDlxCache(maxAge?: number): Promise<number>;
/**
* Download and execute a binary from a URL with caching.
*/
export declare function dlxBinary(args: readonly string[] | string[], options?: DlxBinaryOptions | undefined, spawnExtra?: SpawnExtra | undefined): Promise<DlxBinaryResult>;
/**
* Download a binary from a URL with caching (without execution).
* Similar to downloadPackage from dlx-package.
*
* @returns Object containing the path to the cached binary and whether it was downloaded
*/
export declare function downloadBinary(options: Omit<DlxBinaryOptions, 'spawnOptions'>): Promise<{
binaryPath: string;
downloaded: boolean;
}>;
/**
* Execute a cached binary without re-downloading.
* Similar to executePackage from dlx-package.
* Binary must have been previously downloaded via downloadBinary or dlxBinary.
*
* @param binaryPath Path to the cached binary (from downloadBinary result)
* @param args Arguments to pass to the binary
* @param spawnOptions Spawn options for execution
* @param spawnExtra Extra spawn configuration
* @returns The spawn promise for the running process
*/
export declare function executeBinary(binaryPath: string, args: readonly string[] | string[], spawnOptions?: SpawnOptions | undefined, spawnExtra?: SpawnExtra | undefined): ReturnType<typeof spawn>;
/**
* Get the DLX binary cache directory path.
* Returns normalized path for cross-platform compatibility.
* Uses same directory as dlx-package for unified DLX storage.
*/
export declare function getDlxCachePath(): string;
/**
* Get information about cached binaries.
*/
export declare function listDlxCache(): Promise<Array<{
age: number;
arch: string;
checksum: string;
name: string;
platform: string;
size: number;
url: string;
}>>;
"use strict";
/* Socket Lib - Built with esbuild */
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var dlx_binary_exports = {};
__export(dlx_binary_exports, {
cleanDlxCache: () => cleanDlxCache,
dlxBinary: () => dlxBinary,
downloadBinary: () => downloadBinary,
executeBinary: () => executeBinary,
getDlxCachePath: () => getDlxCachePath,
listDlxCache: () => listDlxCache
});
module.exports = __toCommonJS(dlx_binary_exports);
var import_crypto = require("crypto");
var import_os = __toESM(require("os"));
var import_path = __toESM(require("path"));
var import_platform = require("./constants/platform");
var import_time = require("./constants/time");
var import_dlx = require("./dlx");
var import_dlx_manifest = require("./dlx-manifest");
var import_http_request = require("./http-request");
var import_fs = require("./fs");
var import_objects = require("./objects");
var import_normalize = require("./paths/normalize");
var import_socket = require("./paths/socket");
var import_process_lock = require("./process-lock");
var import_spawn = require("./spawn");
let _fs;
// @__NO_SIDE_EFFECTS__
function getFs() {
if (_fs === void 0) {
_fs = require("node:fs");
}
return _fs;
}
function getMetadataPath(cacheEntryPath) {
return import_path.default.join(cacheEntryPath, ".dlx-metadata.json");
}
async function isCacheValid(cacheEntryPath, cacheTtl) {
const fs = /* @__PURE__ */ getFs();
try {
const metaPath = getMetadataPath(cacheEntryPath);
if (!fs.existsSync(metaPath)) {
return false;
}
const metadata = await (0, import_fs.readJson)(metaPath, { throws: false });
if (!(0, import_objects.isObjectObject)(metadata)) {
return false;
}
const now = Date.now();
const timestamp = metadata["timestamp"];
if (typeof timestamp !== "number" || timestamp <= 0) {
return false;
}
const age = now - timestamp;
return age < cacheTtl;
} catch {
return false;
}
}
async function downloadBinaryFile(url, destPath, checksum) {
const cacheEntryDir = import_path.default.dirname(destPath);
const lockPath = import_path.default.join(cacheEntryDir, "concurrency.lock");
return await import_process_lock.processLock.withLock(
lockPath,
async () => {
const fs = /* @__PURE__ */ getFs();
if (fs.existsSync(destPath)) {
const stats = await fs.promises.stat(destPath);
if (stats.size > 0) {
const fileBuffer2 = await fs.promises.readFile(destPath);
const hasher2 = (0, import_crypto.createHash)("sha256");
hasher2.update(fileBuffer2);
return hasher2.digest("hex");
}
}
try {
await (0, import_http_request.httpDownload)(url, destPath);
} catch (e) {
throw new Error(
`Failed to download binary from ${url}
Destination: ${destPath}
Check your internet connection or verify the URL is accessible.`,
{ cause: e }
);
}
const fileBuffer = await fs.promises.readFile(destPath);
const hasher = (0, import_crypto.createHash)("sha256");
hasher.update(fileBuffer);
const actualChecksum = hasher.digest("hex");
if (checksum && actualChecksum !== checksum) {
await (0, import_fs.safeDelete)(destPath);
throw new Error(
`Checksum mismatch: expected ${checksum}, got ${actualChecksum}`
);
}
if (!import_platform.WIN32) {
await fs.promises.chmod(destPath, 493);
}
return actualChecksum;
},
{
// Align with npm npx locking strategy.
staleMs: 5e3,
touchIntervalMs: 2e3
}
);
}
async function writeMetadata(cacheEntryPath, cacheKey, url, binaryName, checksum, size) {
const metaPath = getMetadataPath(cacheEntryPath);
const metadata = {
version: "1.0.0",
cache_key: cacheKey,
timestamp: Date.now(),
checksum,
checksum_algorithm: "sha256",
platform: import_os.default.platform(),
arch: import_os.default.arch(),
size,
source: {
type: "download",
url
}
};
const fs = /* @__PURE__ */ getFs();
await fs.promises.writeFile(metaPath, JSON.stringify(metadata, null, 2));
try {
const spec = `${url}:${binaryName}`;
await import_dlx_manifest.dlxManifest.setBinaryEntry(spec, cacheKey, {
checksum,
checksum_algorithm: "sha256",
platform: import_os.default.platform(),
arch: import_os.default.arch(),
size,
source: {
type: "download",
url
}
});
} catch {
}
}
async function cleanDlxCache(maxAge = import_time.DLX_BINARY_CACHE_TTL) {
const cacheDir = getDlxCachePath();
const fs = /* @__PURE__ */ getFs();
if (!fs.existsSync(cacheDir)) {
return 0;
}
let cleaned = 0;
const now = Date.now();
const entries = await fs.promises.readdir(cacheDir);
for (const entry of entries) {
const entryPath = import_path.default.join(cacheDir, entry);
const metaPath = getMetadataPath(entryPath);
try {
if (!await (0, import_fs.isDir)(entryPath)) {
continue;
}
const metadata = await (0, import_fs.readJson)(metaPath, { throws: false });
if (!metadata || typeof metadata !== "object" || Array.isArray(metadata)) {
continue;
}
const timestamp = metadata["timestamp"];
const age = typeof timestamp === "number" && timestamp > 0 ? now - timestamp : Number.POSITIVE_INFINITY;
if (age > maxAge) {
await (0, import_fs.safeDelete)(entryPath, { force: true, recursive: true });
cleaned += 1;
}
} catch {
try {
const contents = await fs.promises.readdir(entryPath);
if (!contents.length) {
await (0, import_fs.safeDelete)(entryPath);
cleaned += 1;
}
} catch {
}
}
}
return cleaned;
}
async function dlxBinary(args, options, spawnExtra) {
const {
cacheTtl = import_time.DLX_BINARY_CACHE_TTL,
checksum,
force: userForce = false,
name,
spawnOptions,
url,
yes
} = { __proto__: null, ...options };
const force = yes === true ? true : userForce;
const cacheDir = getDlxCachePath();
const binaryName = name || `binary-${process.platform}-${import_os.default.arch()}`;
const spec = `${url}:${binaryName}`;
const cacheKey = (0, import_dlx.generateCacheKey)(spec);
const cacheEntryDir = import_path.default.join(cacheDir, cacheKey);
const binaryPath = (0, import_normalize.normalizePath)(import_path.default.join(cacheEntryDir, binaryName));
const fs = /* @__PURE__ */ getFs();
let downloaded = false;
let computedChecksum = checksum;
if (!force && fs.existsSync(cacheEntryDir) && await isCacheValid(cacheEntryDir, cacheTtl)) {
try {
const metaPath = getMetadataPath(cacheEntryDir);
const metadata = await (0, import_fs.readJson)(metaPath, { throws: false });
if (metadata && typeof metadata === "object" && !Array.isArray(metadata) && typeof metadata["checksum"] === "string") {
computedChecksum = metadata["checksum"];
} else {
downloaded = true;
}
} catch {
downloaded = true;
}
} else {
downloaded = true;
}
if (downloaded) {
try {
await (0, import_fs.safeMkdir)(cacheEntryDir);
} catch (e) {
const code = e.code;
if (code === "EACCES" || code === "EPERM") {
throw new Error(
`Permission denied creating binary cache directory: ${cacheEntryDir}
Please check directory permissions or run with appropriate access.`,
{ cause: e }
);
}
if (code === "EROFS") {
throw new Error(
`Cannot create binary cache directory on read-only filesystem: ${cacheEntryDir}
Ensure the filesystem is writable or set SOCKET_DLX_DIR to a writable location.`,
{ cause: e }
);
}
throw new Error(
`Failed to create binary cache directory: ${cacheEntryDir}`,
{ cause: e }
);
}
computedChecksum = await downloadBinaryFile(url, binaryPath, checksum);
const stats = await fs.promises.stat(binaryPath);
await writeMetadata(
cacheEntryDir,
cacheKey,
url,
binaryName,
computedChecksum || "",
stats.size
);
}
const needsShell = import_platform.WIN32 && /\.(?:bat|cmd|ps1)$/i.test(binaryPath);
const finalSpawnOptions = needsShell ? {
...spawnOptions,
env: {
...spawnOptions?.env,
PATH: `${cacheEntryDir}${import_path.default.delimiter}${process.env["PATH"] || ""}`
},
shell: true
} : spawnOptions;
const spawnPromise = (0, import_spawn.spawn)(binaryPath, args, finalSpawnOptions, spawnExtra);
return {
binaryPath,
downloaded,
spawnPromise
};
}
async function downloadBinary(options) {
const {
cacheTtl = import_time.DLX_BINARY_CACHE_TTL,
checksum,
force = false,
name,
url
} = { __proto__: null, ...options };
const cacheDir = getDlxCachePath();
const binaryName = name || `binary-${process.platform}-${import_os.default.arch()}`;
const spec = `${url}:${binaryName}`;
const cacheKey = (0, import_dlx.generateCacheKey)(spec);
const cacheEntryDir = import_path.default.join(cacheDir, cacheKey);
const binaryPath = (0, import_normalize.normalizePath)(import_path.default.join(cacheEntryDir, binaryName));
const fs = /* @__PURE__ */ getFs();
let downloaded = false;
if (!force && fs.existsSync(cacheEntryDir) && await isCacheValid(cacheEntryDir, cacheTtl)) {
downloaded = false;
} else {
try {
await (0, import_fs.safeMkdir)(cacheEntryDir);
} catch (e) {
const code = e.code;
if (code === "EACCES" || code === "EPERM") {
throw new Error(
`Permission denied creating binary cache directory: ${cacheEntryDir}
Please check directory permissions or run with appropriate access.`,
{ cause: e }
);
}
if (code === "EROFS") {
throw new Error(
`Cannot create binary cache directory on read-only filesystem: ${cacheEntryDir}
Ensure the filesystem is writable or set SOCKET_DLX_DIR to a writable location.`,
{ cause: e }
);
}
throw new Error(
`Failed to create binary cache directory: ${cacheEntryDir}`,
{ cause: e }
);
}
const computedChecksum = await downloadBinaryFile(url, binaryPath, checksum);
const stats = await fs.promises.stat(binaryPath);
await writeMetadata(
cacheEntryDir,
cacheKey,
url,
binaryName,
computedChecksum || "",
stats.size
);
downloaded = true;
}
return {
binaryPath,
downloaded
};
}
function executeBinary(binaryPath, args, spawnOptions, spawnExtra) {
const needsShell = import_platform.WIN32 && /\.(?:bat|cmd|ps1)$/i.test(binaryPath);
const cacheEntryDir = import_path.default.dirname(binaryPath);
const finalSpawnOptions = needsShell ? {
...spawnOptions,
env: {
...spawnOptions?.env,
PATH: `${cacheEntryDir}${import_path.default.delimiter}${process.env["PATH"] || ""}`
},
shell: true
} : spawnOptions;
return (0, import_spawn.spawn)(binaryPath, args, finalSpawnOptions, spawnExtra);
}
function getDlxCachePath() {
return (0, import_socket.getSocketDlxDir)();
}
async function listDlxCache() {
const cacheDir = getDlxCachePath();
const fs = /* @__PURE__ */ getFs();
if (!fs.existsSync(cacheDir)) {
return [];
}
const results = [];
const now = Date.now();
const entries = await fs.promises.readdir(cacheDir);
for (const entry of entries) {
const entryPath = import_path.default.join(cacheDir, entry);
try {
if (!await (0, import_fs.isDir)(entryPath)) {
continue;
}
const metaPath = getMetadataPath(entryPath);
const metadata = await (0, import_fs.readJson)(metaPath, { throws: false });
if (!metadata || typeof metadata !== "object" || Array.isArray(metadata)) {
continue;
}
const metaObj = metadata;
const source = metaObj["source"];
const url = source?.["url"] || metaObj["url"] || "";
const files = await fs.promises.readdir(entryPath);
const binaryFile = files.find((f) => !f.startsWith("."));
if (binaryFile) {
const binaryPath = import_path.default.join(entryPath, binaryFile);
const binaryStats = await fs.promises.stat(binaryPath);
results.push({
age: now - (metaObj["timestamp"] || 0),
arch: metaObj["arch"] || "unknown",
checksum: metaObj["checksum"] || "",
name: binaryFile,
platform: metaObj["platform"] || "unknown",
size: binaryStats.size,
url
});
}
} catch {
}
}
return results;
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
cleanDlxCache,
dlxBinary,
downloadBinary,
executeBinary,
getDlxCachePath,
listDlxCache
});
/**
* Details for npm package entries.
*/
export interface PackageDetails {
installed_version: string;
size?: number;
update_check?: {
last_check: number;
last_notification: number;
latest_known: string;
};
}
/**
* Details for binary download entries.
*/
export interface BinaryDetails {
checksum: string;
checksum_algorithm: 'sha256' | 'sha512';
platform: string;
arch: string;
size: number;
source: {
type: 'download';
url: string;
};
}
/**
* Unified manifest entry for all cached items (packages and binaries).
* Shared fields at root, type-specific fields in details.
*/
export interface ManifestEntry {
type: 'package' | 'binary';
cache_key: string;
timestamp: number;
details: PackageDetails | BinaryDetails;
}
/**
* Type guard for package entries.
*/
export declare function isPackageEntry(entry: ManifestEntry): entry is ManifestEntry & {
details: PackageDetails;
};
/**
* Type guard for binary entries.
*/
export declare function isBinaryEntry(entry: ManifestEntry): entry is ManifestEntry & {
details: BinaryDetails;
};
/**
* Legacy store record format (deprecated, for migration).
*/
export interface StoreRecord {
timestampFetch: number;
timestampNotification: number;
version: string;
}
export interface DlxManifestOptions {
/**
* Custom manifest file path (defaults to ~/.socket/_dlx/.dlx-manifest.json).
*/
manifestPath?: string;
}
/**
* DLX manifest storage manager with atomic operations.
* Supports both legacy format (package name keys) and new unified manifest format (spec keys).
*/
export declare class DlxManifest {
private readonly manifestPath;
private readonly lockPath;
constructor(options?: DlxManifestOptions);
/**
* Read the entire manifest file.
*/
private readManifest;
/**
* Get a manifest entry by spec (e.g., "@socketsecurity/cli@^2.0.11").
*/
getManifestEntry(spec: string): ManifestEntry | undefined;
/**
* Get cached update information for a package (legacy format).
* @deprecated Use getManifestEntry() for new code.
*/
get(name: string): StoreRecord | undefined;
/**
* Set a package manifest entry.
*/
setPackageEntry(spec: string, cacheKey: string, details: PackageDetails): Promise<void>;
/**
* Set a binary manifest entry.
*/
setBinaryEntry(spec: string, cacheKey: string, details: BinaryDetails): Promise<void>;
private writeManifest;
/**
* Store update information for a package (legacy format).
* @deprecated Use setPackageEntry() for new code.
*/
set(name: string, record: StoreRecord): Promise<void>;
/**
* Clear cached data for a specific entry.
*/
clear(name: string): Promise<void>;
/**
* Clear all cached data.
*/
clearAll(): Promise<void>;
/**
* Check if cached data is fresh based on TTL.
*/
isFresh(record: StoreRecord | undefined, ttlMs: number): boolean;
/**
* Get all cached package names.
*/
getAllPackages(): string[];
}
// Export singleton instance using default manifest location.
export declare const dlxManifest: DlxManifest;
"use strict";
/* Socket Lib - Built with esbuild */
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var dlx_manifest_exports = {};
__export(dlx_manifest_exports, {
DlxManifest: () => DlxManifest,
dlxManifest: () => dlxManifest,
isBinaryEntry: () => isBinaryEntry,
isPackageEntry: () => isPackageEntry
});
module.exports = __toCommonJS(dlx_manifest_exports);
var import_fs = require("fs");
var import_path = __toESM(require("path"));
var import_fs2 = require("./fs");
var import_logger = require("./logger");
var import_socket = require("./paths/socket");
var import_process_lock = require("./process-lock");
const logger = (0, import_logger.getDefaultLogger)();
const MANIFEST_FILE_NAME = ".dlx-manifest.json";
function isPackageEntry(entry) {
return entry.type === "package";
}
function isBinaryEntry(entry) {
return entry.type === "binary";
}
class DlxManifest {
manifestPath;
lockPath;
constructor(options = {}) {
this.manifestPath = options.manifestPath ?? import_path.default.join((0, import_socket.getSocketDlxDir)(), MANIFEST_FILE_NAME);
this.lockPath = `${this.manifestPath}.lock`;
}
/**
* Read the entire manifest file.
*/
readManifest() {
try {
if (!(0, import_fs.existsSync)(this.manifestPath)) {
return /* @__PURE__ */ Object.create(null);
}
const rawContent = (0, import_fs2.readFileUtf8Sync)(this.manifestPath);
const content = (typeof rawContent === "string" ? rawContent : rawContent.toString("utf8")).trim();
if (!content) {
return /* @__PURE__ */ Object.create(null);
}
return JSON.parse(content);
} catch (error) {
logger.warn(
`Failed to read manifest: ${error instanceof Error ? error.message : String(error)}`
);
return /* @__PURE__ */ Object.create(null);
}
}
/**
* Get a manifest entry by spec (e.g., "@socketsecurity/cli@^2.0.11").
*/
getManifestEntry(spec) {
const data = this.readManifest();
const entry = data[spec];
if (entry && "type" in entry) {
return entry;
}
return void 0;
}
/**
* Get cached update information for a package (legacy format).
* @deprecated Use getManifestEntry() for new code.
*/
get(name) {
const data = this.readManifest();
const entry = data[name];
if (entry && !("type" in entry)) {
return entry;
}
return void 0;
}
/**
* Set a package manifest entry.
*/
async setPackageEntry(spec, cacheKey, details) {
await import_process_lock.processLock.withLock(this.lockPath, async () => {
const data = this.readManifest();
data[spec] = {
type: "package",
cache_key: cacheKey,
timestamp: Date.now(),
details
};
await this.writeManifest(data);
});
}
/**
* Set a binary manifest entry.
*/
async setBinaryEntry(spec, cacheKey, details) {
await import_process_lock.processLock.withLock(this.lockPath, async () => {
const data = this.readManifest();
data[spec] = {
type: "binary",
cache_key: cacheKey,
timestamp: Date.now(),
details
};
await this.writeManifest(data);
});
}
/**
* Write the manifest file atomically.
*/
async writeManifest(data) {
const manifestDir = import_path.default.dirname(this.manifestPath);
try {
(0, import_fs2.safeMkdirSync)(manifestDir, { recursive: true });
} catch (error) {
logger.warn(
`Failed to create manifest directory: ${error instanceof Error ? error.message : String(error)}`
);
}
const content = JSON.stringify(data, null, 2);
const tempPath = `${this.manifestPath}.tmp`;
try {
(0, import_fs.writeFileSync)(tempPath, content, "utf8");
(0, import_fs.writeFileSync)(this.manifestPath, content, "utf8");
try {
if ((0, import_fs.existsSync)(tempPath)) {
(0, import_fs.unlinkSync)(tempPath);
}
} catch {
}
} catch (error) {
try {
if ((0, import_fs.existsSync)(tempPath)) {
(0, import_fs.unlinkSync)(tempPath);
}
} catch {
}
throw error;
}
}
/**
* Store update information for a package (legacy format).
* @deprecated Use setPackageEntry() for new code.
*/
async set(name, record) {
await import_process_lock.processLock.withLock(this.lockPath, async () => {
let data = /* @__PURE__ */ Object.create(null);
try {
if ((0, import_fs.existsSync)(this.manifestPath)) {
const content2 = (0, import_fs.readFileSync)(this.manifestPath, "utf8");
if (content2.trim()) {
data = JSON.parse(content2);
}
}
} catch (error) {
logger.warn(
`Failed to read existing manifest: ${error instanceof Error ? error.message : String(error)}`
);
}
data[name] = record;
const manifestDir = import_path.default.dirname(this.manifestPath);
try {
(0, import_fs2.safeMkdirSync)(manifestDir, { recursive: true });
} catch (error) {
logger.warn(
`Failed to create manifest directory: ${error instanceof Error ? error.message : String(error)}`
);
}
const content = JSON.stringify(data, null, 2);
const tempPath = `${this.manifestPath}.tmp`;
try {
(0, import_fs.writeFileSync)(tempPath, content, "utf8");
(0, import_fs.writeFileSync)(this.manifestPath, content, "utf8");
try {
if ((0, import_fs.existsSync)(tempPath)) {
(0, import_fs.unlinkSync)(tempPath);
}
} catch {
}
} catch (error) {
try {
if ((0, import_fs.existsSync)(tempPath)) {
(0, import_fs.unlinkSync)(tempPath);
}
} catch {
}
throw error;
}
});
}
/**
* Clear cached data for a specific entry.
*/
async clear(name) {
await import_process_lock.processLock.withLock(this.lockPath, async () => {
try {
if (!(0, import_fs.existsSync)(this.manifestPath)) {
return;
}
const content = (0, import_fs.readFileSync)(this.manifestPath, "utf8");
if (!content.trim()) {
return;
}
const data = JSON.parse(content);
delete data[name];
const updatedContent = JSON.stringify(data, null, 2);
(0, import_fs.writeFileSync)(this.manifestPath, updatedContent, "utf8");
} catch (error) {
logger.warn(
`Failed to clear cache for ${name}: ${error instanceof Error ? error.message : String(error)}`
);
}
});
}
/**
* Clear all cached data.
*/
async clearAll() {
await import_process_lock.processLock.withLock(this.lockPath, async () => {
try {
if ((0, import_fs.existsSync)(this.manifestPath)) {
(0, import_fs.unlinkSync)(this.manifestPath);
}
} catch (error) {
logger.warn(
`Failed to clear all cache: ${error instanceof Error ? error.message : String(error)}`
);
}
});
}
/**
* Check if cached data is fresh based on TTL.
*/
isFresh(record, ttlMs) {
if (!record) {
return false;
}
const age = Date.now() - record.timestampFetch;
return age < ttlMs;
}
/**
* Get all cached package names.
*/
getAllPackages() {
try {
if (!(0, import_fs.existsSync)(this.manifestPath)) {
return [];
}
const rawContent = (0, import_fs2.readFileUtf8Sync)(this.manifestPath);
const content = (typeof rawContent === "string" ? rawContent : rawContent.toString("utf8")).trim();
if (!content) {
return [];
}
const data = JSON.parse(content);
return Object.keys(data);
} catch (error) {
logger.warn(
`Failed to get package list: ${error instanceof Error ? error.message : String(error)}`
);
return [];
}
}
}
const dlxManifest = new DlxManifest();
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
DlxManifest,
dlxManifest,
isBinaryEntry,
isPackageEntry
});
import type { SpawnExtra, SpawnOptions } from './spawn';
import { spawn } from './spawn';
export interface DownloadPackageResult {
/** Path to the installed package directory. */
packageDir: string;
/** Path to the binary. */
binaryPath: string;
/** Whether the package was newly installed. */
installed: boolean;
}
export interface DlxPackageOptions {
/**
* Package to install (e.g., '@cyclonedx/cdxgen@10.0.0').
* Aligns with npx --package flag.
*/
package: string;
/**
* Binary name to execute (optional - auto-detected in most cases).
*
* Auto-detection logic:
* 1. If package has only one binary, uses it automatically
* 2. Tries user-provided binaryName
* 3. Tries last segment of package name (e.g., 'cli' from '@socketsecurity/cli')
* 4. Falls back to first binary
*
* Only needed when package has multiple binaries and auto-detection fails.
*
* @example
* // Auto-detected (single binary)
* { package: '@socketsecurity/cli' } // Finds 'socket' binary automatically
*
* // Explicit (multiple binaries)
* { package: 'some-tool', binaryName: 'specific-tool' }
*/
binaryName?: string | undefined;
/**
* Force reinstallation even if package exists.
* Aligns with npx --yes/-y flag behavior.
*/
force?: boolean | undefined;
/**
* Skip confirmation prompts (auto-approve).
* Aligns with npx --yes/-y flag.
*/
yes?: boolean | undefined;
/**
* Suppress output (quiet mode).
* Aligns with npx --quiet/-q and pnpm --silent/-s flags.
*/
quiet?: boolean | undefined;
/**
* Additional spawn options for the execution.
*/
spawnOptions?: SpawnOptions | undefined;
}
export interface DlxPackageResult {
/** Path to the installed package directory. */
packageDir: string;
/** Path to the binary that was executed. */
binaryPath: string;
/** Whether the package was newly installed. */
installed: boolean;
/** The spawn promise for the running process. */
spawnPromise: ReturnType<typeof spawn>;
}
/**
* Execute a package via DLX - install if needed and run its binary.
*
* This is the Socket equivalent of npx/pnpm dlx/yarn dlx, but using
* our own cache directory (~/.socket/_dlx) and installation logic.
*
* Auto-forces reinstall for version ranges to get latest within range.
*
* @example
* ```typescript
* // Download and execute cdxgen
* const result = await dlxPackage(
* ['--version'],
* { package: '@cyclonedx/cdxgen@10.0.0' }
* )
* await result.spawnPromise
* ```
*/
export declare function dlxPackage(args: readonly string[] | string[], options?: DlxPackageOptions | undefined, spawnExtra?: SpawnExtra | undefined): Promise<DlxPackageResult>;
/**
* Download and install a package without executing it.
* This is useful for self-update or when you need the package files
* but don't want to run the binary immediately.
*
* @example
* ```typescript
* // Install @socketsecurity/cli without running it
* const result = await downloadPackage({
* package: '@socketsecurity/cli@1.2.0',
* force: true
* })
* console.log('Installed to:', result.packageDir)
* console.log('Binary at:', result.binaryPath)
* ```
*/
export declare function downloadPackage(options: DlxPackageOptions): Promise<DownloadPackageResult>;
/**
* Execute a package's binary with cross-platform shell handling.
* The package must already be installed (use downloadPackage first).
*
* On Windows, script files (.bat, .cmd, .ps1) require shell: true.
* Matches npm/npx execution behavior.
*
* @example
* ```typescript
* // Execute an already-installed package
* const downloaded = await downloadPackage({ package: 'cowsay@1.5.0' })
* const result = await executePackage(
* downloaded.binaryPath,
* ['Hello World'],
* { stdio: 'inherit' }
* )
* ```
*/
export declare function executePackage(binaryPath: string, args: readonly string[] | string[], spawnOptions?: SpawnOptions | undefined, spawnExtra?: SpawnExtra | undefined): ReturnType<typeof spawn>;
"use strict";
/* Socket Lib - Built with esbuild */
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var dlx_package_exports = {};
__export(dlx_package_exports, {
dlxPackage: () => dlxPackage,
downloadPackage: () => downloadPackage,
executePackage: () => executePackage
});
module.exports = __toCommonJS(dlx_package_exports);
var import_node_fs = __toESM(require("node:fs"));
var import_path = __toESM(require("path"));
var import_platform = require("./constants/platform");
var import_packages = require("./constants/packages");
var import_dlx = require("./dlx");
var import_arborist = __toESM(require("./external/@npmcli/arborist"));
var import_libnpmexec = __toESM(require("./external/libnpmexec"));
var import_npm_package_arg = __toESM(require("./external/npm-package-arg"));
var import_pacote = __toESM(require("./external/pacote"));
var import_fs = require("./fs");
var import_normalize = require("./paths/normalize");
var import_socket = require("./paths/socket");
var import_process_lock = require("./process-lock");
var import_spawn = require("./spawn");
const rangeOperatorsRegExp = /[~^><=xX* ]|\|\|/;
function parsePackageSpec(spec) {
try {
const parsed = (0, import_npm_package_arg.default)(spec);
const version = parsed.type === "tag" ? parsed.fetchSpec : parsed.type === "version" || parsed.type === "range" ? parsed.fetchSpec : void 0;
return {
name: parsed.name || spec,
version
};
} catch {
const atIndex = spec.lastIndexOf("@");
if (atIndex === -1 || spec.startsWith("@")) {
return { name: spec, version: void 0 };
}
return {
name: spec.slice(0, atIndex),
version: spec.slice(atIndex + 1)
};
}
}
async function ensurePackageInstalled(packageName, packageSpec, force) {
const cacheKey = (0, import_dlx.generateCacheKey)(packageSpec);
const packageDir = (0, import_normalize.normalizePath)(import_path.default.join((0, import_socket.getSocketDlxDir)(), cacheKey));
const installedDir = (0, import_normalize.normalizePath)(
import_path.default.join(packageDir, "node_modules", packageName)
);
try {
await (0, import_fs.safeMkdir)(packageDir);
} catch (e) {
const code = e.code;
if (code === "EACCES" || code === "EPERM") {
throw new Error(
`Permission denied creating package directory: ${packageDir}
Please check directory permissions or run with appropriate access.`,
{ cause: e }
);
}
if (code === "EROFS") {
throw new Error(
`Cannot create package directory on read-only filesystem: ${packageDir}
Ensure the filesystem is writable or set SOCKET_DLX_DIR to a writable location.`,
{ cause: e }
);
}
throw new Error(`Failed to create package directory: ${packageDir}`, {
cause: e
});
}
const lockPath = import_path.default.join(packageDir, "concurrency.lock");
return await import_process_lock.processLock.withLock(
lockPath,
async () => {
if (!force && import_node_fs.default.existsSync(installedDir)) {
const pkgJsonPath = import_path.default.join(installedDir, "package.json");
if (import_node_fs.default.existsSync(pkgJsonPath)) {
return { installed: false, packageDir };
}
}
const pacoteCachePath = (0, import_packages.getPacoteCachePath)();
try {
await import_pacote.default.extract(packageSpec, installedDir, {
// Use consistent pacote cache path (respects npm cache locations when available).
cache: pacoteCachePath || import_path.default.join(packageDir, ".cache")
});
const arb = new import_arborist.default({
path: installedDir,
cache: pacoteCachePath || import_path.default.join(packageDir, ".cache"),
// Skip devDependencies (production-only like npx).
omit: ["dev"],
// Security: Skip install/preinstall/postinstall scripts to prevent arbitrary code execution.
ignoreScripts: true,
// Security: Enable binary links (needed for dlx to execute the package binary).
binLinks: true,
// Suppress funding messages (unneeded for ephemeral dlx installs).
fund: false,
// Skip audit (unneeded for ephemeral dlx installs).
audit: false,
// Suppress output (unneeded for ephemeral dlx installs).
silent: true
});
await arb.buildIdealTree();
await arb.reify({ save: false });
} catch (e) {
const code = e.code;
if (code === "E404" || code === "ETARGET") {
throw new Error(
`Package not found: ${packageSpec}
Verify the package exists on npm registry and check the version.
Visit https://www.npmjs.com/package/${packageName} to see available versions.`,
{ cause: e }
);
}
if (code === "ENOTFOUND" || code === "ETIMEDOUT" || code === "EAI_AGAIN") {
throw new Error(
`Network error installing ${packageSpec}
Check your internet connection and try again.`,
{ cause: e }
);
}
throw new Error(
`Failed to install package: ${packageSpec}
Destination: ${installedDir}
Check npm registry connectivity or package name.`,
{ cause: e }
);
}
return { installed: true, packageDir };
},
{
// Align with npm npx locking strategy.
staleMs: 5e3,
touchIntervalMs: 2e3
}
);
}
function resolveBinaryPath(basePath) {
if (!import_platform.WIN32) {
return basePath;
}
const extensions = [".cmd", ".bat", ".ps1", ".exe", ""];
for (const ext of extensions) {
const testPath = basePath + ext;
if (import_node_fs.default.existsSync(testPath)) {
return testPath;
}
}
return basePath;
}
function findBinaryPath(packageDir, packageName, binaryName) {
const installedDir = (0, import_normalize.normalizePath)(
import_path.default.join(packageDir, "node_modules", packageName)
);
const pkgJsonPath = import_path.default.join(installedDir, "package.json");
const pkgJson = (0, import_fs.readJsonSync)(pkgJsonPath);
const bin = pkgJson["bin"];
let binName;
let binPath;
if (typeof bin === "string") {
binPath = bin;
} else if (typeof bin === "object" && bin !== null) {
const binObj = bin;
const binKeys = Object.keys(binObj);
if (binKeys.length === 1) {
binName = binKeys[0];
binPath = binObj[binName];
} else {
try {
const { getBinFromManifest } = import_libnpmexec.default;
binName = getBinFromManifest({
name: packageName,
bin: binObj,
_id: `${packageName}@${pkgJson.version || "unknown"}`
});
binPath = binObj[binName];
} catch {
const lastSegment = packageName.split("/").pop();
const candidates = [
binaryName,
lastSegment,
packageName.replace(/^@[^/]+\//, "")
].filter(Boolean);
for (const candidate of candidates) {
if (candidate && binObj[candidate]) {
binName = candidate;
binPath = binObj[candidate];
break;
}
}
if (!binPath && binKeys.length > 0) {
binName = binKeys[0];
binPath = binObj[binName];
}
}
}
}
if (!binPath) {
throw new Error(`No binary found for package "${packageName}"`);
}
const rawPath = (0, import_normalize.normalizePath)(import_path.default.join(installedDir, binPath));
return resolveBinaryPath(rawPath);
}
async function dlxPackage(args, options, spawnExtra) {
const downloadResult = await downloadPackage(options);
const spawnPromise = executePackage(
downloadResult.binaryPath,
args,
options?.spawnOptions,
spawnExtra
);
return {
...downloadResult,
spawnPromise
};
}
function makePackageBinsExecutable(packageDir, packageName) {
if (import_platform.WIN32) {
return;
}
const installedDir = (0, import_normalize.normalizePath)(
import_path.default.join(packageDir, "node_modules", packageName)
);
const pkgJsonPath = import_path.default.join(installedDir, "package.json");
try {
const pkgJson = (0, import_fs.readJsonSync)(pkgJsonPath);
const bin = pkgJson["bin"];
if (!bin) {
return;
}
const binPaths = [];
if (typeof bin === "string") {
binPaths.push(bin);
} else if (typeof bin === "object" && bin !== null) {
const binObj = bin;
binPaths.push(...Object.values(binObj));
}
for (const binPath of binPaths) {
const fullPath = (0, import_normalize.normalizePath)(import_path.default.join(installedDir, binPath));
if (import_node_fs.default.existsSync(fullPath)) {
try {
import_node_fs.default.chmodSync(fullPath, 493);
} catch {
}
}
}
} catch {
}
}
async function downloadPackage(options) {
const {
binaryName,
force: userForce,
package: packageSpec,
yes
} = {
__proto__: null,
...options
};
const { name: packageName, version: packageVersion } = parsePackageSpec(packageSpec);
const isVersionRange = packageVersion !== void 0 && rangeOperatorsRegExp.test(packageVersion);
const force = userForce !== void 0 ? userForce : yes === true ? true : isVersionRange;
const fullPackageSpec = packageVersion ? `${packageName}@${packageVersion}` : packageName;
const { installed, packageDir } = await ensurePackageInstalled(
packageName,
fullPackageSpec,
force
);
const binaryPath = findBinaryPath(packageDir, packageName, binaryName);
makePackageBinsExecutable(packageDir, packageName);
return {
binaryPath,
installed,
packageDir
};
}
function executePackage(binaryPath, args, spawnOptions, spawnExtra) {
const needsShell = import_platform.WIN32 && /\.(?:bat|cmd|ps1)$/i.test(binaryPath);
const finalOptions = needsShell ? {
...spawnOptions,
shell: true
} : spawnOptions;
return (0, import_spawn.spawn)(binaryPath, args, finalOptions, spawnExtra);
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
dlxPackage,
downloadPackage,
executePackage
});
/**
* Generate a cache directory name using npm/npx approach.
* Uses first 16 characters of SHA-512 hash (like npm/npx).
*
* Rationale for SHA-512 truncated (vs full SHA-256):
* - Matches npm/npx ecosystem behavior
* - Shorter paths for Windows MAX_PATH compatibility (260 chars)
* - 16 hex chars = 64 bits = acceptable collision risk for local cache
* - Collision probability ~1 in 18 quintillion with 1000 entries
*
* Input strategy (aligned with npx):
* - npx uses package spec strings (e.g., '@scope/pkg@1.0.0', 'prettier@3.0.0')
* - Caller provides complete spec string with version for accurate cache keying
* - For package installs: Use PURL-style spec with version
* Examples: 'npm:prettier@3.0.0', 'pypi:requests@2.31.0', 'gem:rails@7.0.0'
* Note: Socket uses shorthand format without 'pkg:' prefix
* (handled by @socketregistry/packageurl-js)
* - For binary downloads: Use URL:name for uniqueness
*
* Reference: npm/cli v11.6.2 libnpmexec/lib/index.js#L233-L244
* https://github.com/npm/cli/blob/v11.6.2/workspaces/libnpmexec/lib/index.js#L233-L244
* Implementation: packages.map().sort().join('\n') → SHA-512 → slice(0,16)
* npx hashes the package spec (name@version), not just name
*/
export declare function generateCacheKey(spec: string): string;
/**
* Clear all DLX package installations.
*/
export declare function clearDlx(): Promise<void>;
/**
* Clear all DLX package installations synchronously.
*/
export declare function clearDlxSync(): void;
/**
* Check if the DLX directory exists.
*/
export declare function dlxDirExists(): boolean;
/**
* Check if the DLX directory exists asynchronously.
*/
export declare function dlxDirExistsAsync(): Promise<boolean>;
/**
* Ensure the DLX directory exists, creating it if necessary.
*/
export declare function ensureDlxDir(): Promise<void>;
/**
* Ensure the DLX directory exists synchronously, creating it if necessary.
*/
export declare function ensureDlxDirSync(): void;
/**
* Get the installed package directory within DLX node_modules.
*/
export declare function getDlxInstalledPackageDir(packageName: string): string;
/**
* Get the DLX installation directory for a specific package.
*/
export declare function getDlxPackageDir(packageName: string): string;
/**
* Get the package.json path for a DLX installed package.
*/
export declare function getDlxPackageJsonPath(packageName: string): string;
/**
* Get the node_modules directory for a DLX package installation.
*/
export declare function getDlxPackageNodeModulesDir(packageName: string): string;
/**
* Check if a file path is within the Socket DLX directory.
* This is useful for determining if a binary or file is managed by Socket's DLX system.
*
* @param filePath - Absolute or relative path to check
* @returns true if the path is within ~/.socket/_dlx/, false otherwise
*
* @example
* ```typescript
* isInSocketDlx('/home/user/.socket/_dlx/abc123/bin/socket') // true
* isInSocketDlx('/usr/local/bin/socket') // false
* isInSocketDlx(process.argv[0]) // Check if current binary is in DLX
* ```
*/
export declare function isInSocketDlx(filePath: string): boolean;
/**
* Check if a package is installed in DLX.
*/
export declare function isDlxPackageInstalled(packageName: string): boolean;
/**
* Check if a package is installed in DLX asynchronously.
*/
export declare function isDlxPackageInstalledAsync(packageName: string): Promise<boolean>;
/**
* List all packages installed in DLX.
*/
export declare function listDlxPackages(): string[];
/**
* List all packages installed in DLX asynchronously.
*/
export declare function listDlxPackagesAsync(): Promise<string[]>;
/**
* Remove a DLX package installation.
*/
export declare function removeDlxPackage(packageName: string): Promise<void>;
/**
* Remove a DLX package installation synchronously.
*/
export declare function removeDlxPackageSync(packageName: string): void;
"use strict";
/* Socket Lib - Built with esbuild */
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var dlx_exports = {};
__export(dlx_exports, {
clearDlx: () => clearDlx,
clearDlxSync: () => clearDlxSync,
dlxDirExists: () => dlxDirExists,
dlxDirExistsAsync: () => dlxDirExistsAsync,
ensureDlxDir: () => ensureDlxDir,
ensureDlxDirSync: () => ensureDlxDirSync,
generateCacheKey: () => generateCacheKey,
getDlxInstalledPackageDir: () => getDlxInstalledPackageDir,
getDlxPackageDir: () => getDlxPackageDir,
getDlxPackageJsonPath: () => getDlxPackageJsonPath,
getDlxPackageNodeModulesDir: () => getDlxPackageNodeModulesDir,
isDlxPackageInstalled: () => isDlxPackageInstalled,
isDlxPackageInstalledAsync: () => isDlxPackageInstalledAsync,
isInSocketDlx: () => isInSocketDlx,
listDlxPackages: () => listDlxPackages,
listDlxPackagesAsync: () => listDlxPackagesAsync,
removeDlxPackage: () => removeDlxPackage,
removeDlxPackageSync: () => removeDlxPackageSync
});
module.exports = __toCommonJS(dlx_exports);
var import_crypto = require("crypto");
var import_fs = require("./fs");
var import_normalize = require("./paths/normalize");
var import_socket = require("./paths/socket");
var import_promises = require("./promises");
let _fs;
// @__NO_SIDE_EFFECTS__
function getFs() {
if (_fs === void 0) {
_fs = require("node:fs");
}
return _fs;
}
function generateCacheKey(spec) {
return (0, import_crypto.createHash)("sha512").update(spec).digest("hex").substring(0, 16);
}
let _path;
// @__NO_SIDE_EFFECTS__
function getPath() {
if (_path === void 0) {
_path = require("node:path");
}
return _path;
}
async function clearDlx() {
const packages = await listDlxPackagesAsync();
await (0, import_promises.pEach)(packages, (pkg) => removeDlxPackage(pkg));
}
function clearDlxSync() {
const packages = listDlxPackages();
for (const pkg of packages) {
removeDlxPackageSync(pkg);
}
}
function dlxDirExists() {
const fs = /* @__PURE__ */ getFs();
return fs.existsSync((0, import_socket.getSocketDlxDir)());
}
async function dlxDirExistsAsync() {
const fs = /* @__PURE__ */ getFs();
try {
await fs.promises.access((0, import_socket.getSocketDlxDir)());
return true;
} catch {
return false;
}
}
async function ensureDlxDir() {
await (0, import_fs.safeMkdir)((0, import_socket.getSocketDlxDir)());
}
function ensureDlxDirSync() {
(0, import_fs.safeMkdirSync)((0, import_socket.getSocketDlxDir)());
}
function getDlxInstalledPackageDir(packageName) {
const path = /* @__PURE__ */ getPath();
return (0, import_normalize.normalizePath)(
path.join(getDlxPackageNodeModulesDir(packageName), packageName)
);
}
function getDlxPackageDir(packageName) {
const path = /* @__PURE__ */ getPath();
return (0, import_normalize.normalizePath)(path.join((0, import_socket.getSocketDlxDir)(), packageName));
}
function getDlxPackageJsonPath(packageName) {
const path = /* @__PURE__ */ getPath();
return (0, import_normalize.normalizePath)(
path.join(getDlxInstalledPackageDir(packageName), "package.json")
);
}
function getDlxPackageNodeModulesDir(packageName) {
const path = /* @__PURE__ */ getPath();
return (0, import_normalize.normalizePath)(path.join(getDlxPackageDir(packageName), "node_modules"));
}
function isInSocketDlx(filePath) {
if (!filePath) {
return false;
}
const path = /* @__PURE__ */ getPath();
const dlxDir = (0, import_socket.getSocketDlxDir)();
const absolutePath = (0, import_normalize.normalizePath)(path.resolve(filePath));
return absolutePath.startsWith(`${dlxDir}/`);
}
function isDlxPackageInstalled(packageName) {
const fs = /* @__PURE__ */ getFs();
return fs.existsSync(getDlxInstalledPackageDir(packageName));
}
async function isDlxPackageInstalledAsync(packageName) {
const fs = /* @__PURE__ */ getFs();
try {
await fs.promises.access(getDlxInstalledPackageDir(packageName));
return true;
} catch {
return false;
}
}
function listDlxPackages() {
try {
return (0, import_fs.readDirNamesSync)((0, import_socket.getSocketDlxDir)(), { sort: true });
} catch {
return [];
}
}
async function listDlxPackagesAsync() {
const fs = /* @__PURE__ */ getFs();
try {
const entries = await fs.promises.readdir((0, import_socket.getSocketDlxDir)(), {
withFileTypes: true
});
return entries.filter((e) => e.isDirectory()).map((e) => e.name).sort();
} catch {
return [];
}
}
async function removeDlxPackage(packageName) {
const packageDir = getDlxPackageDir(packageName);
try {
await (0, import_fs.safeDelete)(packageDir, { recursive: true, force: true });
} catch (e) {
throw new Error(`Failed to remove DLX package "${packageName}"`, {
cause: e
});
}
}
function removeDlxPackageSync(packageName) {
const fs = /* @__PURE__ */ getFs();
const packageDir = getDlxPackageDir(packageName);
try {
fs.rmSync(packageDir, { recursive: true, force: true });
} catch (e) {
const code = e.code;
if (code === "EACCES" || code === "EPERM") {
throw new Error(
`Permission denied removing DLX package "${packageName}"
Directory: ${packageDir}
To resolve:
1. Check file/directory permissions
2. Close any programs using files in this directory
3. Try running with elevated privileges if necessary
4. Manually remove: rm -rf "${packageDir}"`,
{ cause: e }
);
}
if (code === "EROFS") {
throw new Error(
`Cannot remove DLX package "${packageName}" from read-only filesystem
Directory: ${packageDir}
The filesystem is mounted read-only.`,
{ cause: e }
);
}
throw new Error(
`Failed to remove DLX package "${packageName}"
Directory: ${packageDir}
Check permissions and ensure no programs are using this directory.`,
{ cause: e }
);
}
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
clearDlx,
clearDlxSync,
dlxDirExists,
dlxDirExistsAsync,
ensureDlxDir,
ensureDlxDirSync,
generateCacheKey,
getDlxInstalledPackageDir,
getDlxPackageDir,
getDlxPackageJsonPath,
getDlxPackageNodeModulesDir,
isDlxPackageInstalled,
isDlxPackageInstalledAsync,
isInSocketDlx,
listDlxPackages,
listDlxPackagesAsync,
removeDlxPackage,
removeDlxPackageSync
});
/**
* JSON primitive types: `null`, `boolean`, `number`, or `string`.
*
* @example
* ```ts
* const primitives: JsonPrimitive[] = [null, true, 42, 'hello']
* ```
*/
export type JsonPrimitive = null | boolean | number | string;
/**
* Any valid JSON value: primitive, object, or array.
*
* @example
* ```ts
* const values: JsonValue[] = [
* null,
* true,
* 42,
* 'hello',
* { key: 'value' },
* [1, 2, 3]
* ]
* ```
*/
export type JsonValue = JsonPrimitive | JsonObject | JsonArray;
/**
* A JSON object with string keys and JSON values.
*
* @example
* ```ts
* const obj: JsonObject = {
* name: 'example',
* count: 42,
* active: true,
* nested: { key: 'value' }
* }
* ```
*/
export interface JsonObject {
[key: string]: JsonValue;
}
/**
* A JSON array containing JSON values.
*
* @example
* ```ts
* const arr: JsonArray = [1, 'two', { three: 3 }, [4, 5]]
* ```
*/
export interface JsonArray extends Array<JsonValue> {
}
/**
* Reviver function for transforming parsed JSON values.
* Called for each key-value pair during parsing.
*
* @param key - The object key or array index being parsed
* @param value - The parsed value
* @returns The transformed value (or original if no transform needed)
*
* @example
* ```ts
* // Convert date strings to Date objects
* const reviver: JsonReviver = (key, value) => {
* if (typeof value === 'string' && /^\d{4}-\d{2}-\d{2}/.test(value)) {
* return new Date(value)
* }
* return value
* }
* ```
*/
export type JsonReviver = (key: string, value: unknown) => unknown;
/**
* Options for JSON parsing operations.
*/
export interface JsonParseOptions {
/**
* Optional filepath for improved error messages.
* When provided, errors will be prefixed with the filepath.
*
* @example
* ```ts
* // Error message will be: "config.json: Unexpected token } in JSON"
* jsonParse('invalid', { filepath: 'config.json' })
* ```
*/
filepath?: string | undefined;
/**
* Optional reviver function to transform parsed values.
* Called for each key-value pair during parsing.
*
* @example
* ```ts
* // Convert ISO date strings to Date objects
* const options = {
* reviver: (key, value) => {
* if (typeof value === 'string' && /^\d{4}-\d{2}-\d{2}/.test(value)) {
* return new Date(value)
* }
* return value
* }
* }
* ```
*/
reviver?: JsonReviver | undefined;
/**
* Whether to throw on parse errors.
* When `false`, returns `undefined` instead of throwing.
*
* @default true
*
* @example
* ```ts
* // Throws error
* jsonParse('invalid', { throws: true })
*
* // Returns undefined
* const result = jsonParse('invalid', { throws: false })
* ```
*/
throws?: boolean | undefined;
}
/**
* Check if a value is a JSON primitive type.
* JSON primitives are: `null`, `boolean`, `number`, or `string`.
*
* @param value - Value to check
* @returns `true` if value is a JSON primitive, `false` otherwise
*
* @example
* ```ts
* isJsonPrimitive(null) // => true
* isJsonPrimitive(true) // => true
* isJsonPrimitive(42) // => true
* isJsonPrimitive('hello') // => true
* isJsonPrimitive({}) // => false
* isJsonPrimitive([]) // => false
* isJsonPrimitive(undefined) // => false
* ```
*/
/*@__NO_SIDE_EFFECTS__*/
export declare function isJsonPrimitive(value: unknown): value is JsonPrimitive;
/**
* Parse JSON content with automatic Buffer handling and BOM stripping.
* Provides safer JSON parsing with helpful error messages and optional error suppression.
*
* Features:
* - Automatic UTF-8 Buffer conversion
* - BOM (Byte Order Mark) stripping for cross-platform compatibility
* - Enhanced error messages with filepath context
* - Optional error suppression (returns `undefined` instead of throwing)
* - Optional reviver for transforming parsed values
*
* @param content - JSON string or Buffer to parse
* @param options - Optional parsing configuration
* @returns Parsed JSON value, or `undefined` if parsing fails and `throws` is `false`
*
* @throws {SyntaxError} When JSON is invalid and `throws` is `true` (default)
*
* @example
* ```ts
* // Basic usage
* const data = jsonParse('{"name":"example"}')
* console.log(data.name) // => 'example'
*
* // Parse Buffer with UTF-8 BOM
* const buffer = Buffer.from('\uFEFF{"value":42}')
* const data = jsonParse(buffer)
* console.log(data.value) // => 42
*
* // Enhanced error messages with filepath
* try {
* jsonParse('invalid', { filepath: 'config.json' })
* } catch (err) {
* console.error(err.message)
* // => "config.json: Unexpected token i in JSON at position 0"
* }
*
* // Suppress errors
* const result = jsonParse('invalid', { throws: false })
* console.log(result) // => undefined
*
* // Transform values with reviver
* const json = '{"created":"2024-01-15T10:30:00Z"}'
* const data = jsonParse(json, {
* reviver: (key, value) => {
* if (key === 'created' && typeof value === 'string') {
* return new Date(value)
* }
* return value
* }
* })
* console.log(data.created instanceof Date) // => true
* ```
*/
/*@__NO_SIDE_EFFECTS__*/
export declare function jsonParse(content: string | Buffer, options?: JsonParseOptions | undefined): JsonValue | undefined;
"use strict";
/* Socket Lib - Built with esbuild */
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var json_exports = {};
__export(json_exports, {
isJsonPrimitive: () => isJsonPrimitive,
jsonParse: () => jsonParse
});
module.exports = __toCommonJS(json_exports);
var import_strings = require("./strings");
const JSONParse = JSON.parse;
// @__NO_SIDE_EFFECTS__
function isBuffer(x) {
if (!x || typeof x !== "object") {
return false;
}
const obj = x;
if (typeof obj["length"] !== "number") {
return false;
}
if (typeof obj["copy"] !== "function" || typeof obj["slice"] !== "function") {
return false;
}
if (typeof obj["length"] === "number" && obj["length"] > 0 && typeof obj[0] !== "number") {
return false;
}
const Ctor = x.constructor;
return !!(typeof Ctor?.isBuffer === "function" && Ctor.isBuffer(x));
}
// @__NO_SIDE_EFFECTS__
function isJsonPrimitive(value) {
return value === null || typeof value === "boolean" || typeof value === "number" || typeof value === "string";
}
// @__NO_SIDE_EFFECTS__
function jsonParse(content, options) {
const { filepath, reviver, throws } = {
__proto__: null,
...options
};
const shouldThrow = throws === void 0 || !!throws;
const jsonStr = /* @__PURE__ */ isBuffer(content) ? content.toString("utf8") : content;
try {
return JSONParse((0, import_strings.stripBom)(jsonStr), reviver);
} catch (e) {
if (shouldThrow) {
const error = e;
if (error && typeof filepath === "string") {
error.message = `${filepath}: ${error.message}`;
}
throw error;
}
}
return void 0;
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
isJsonPrimitive,
jsonParse
});
/**
* @fileoverview NPM lifecycle script names.
*
* Standard npm lifecycle hooks that can be defined in package.json scripts.
* https://docs.npmjs.com/cli/v10/using-npm/scripts#life-cycle-scripts
*/
declare const lifecycleScriptNames: Set<string>;
export { lifecycleScriptNames };
"use strict";
/* Socket Lib - Built with esbuild */
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var lifecycle_script_names_exports = {};
__export(lifecycle_script_names_exports, {
lifecycleScriptNames: () => lifecycleScriptNames
});
module.exports = __toCommonJS(lifecycle_script_names_exports);
const lifecycleScriptNames = new Set(
[
"dependencies",
"prepublishOnly",
...[
"install",
"pack",
"prepare",
"publish",
"restart",
"start",
"stop",
"version"
].map((n) => [`pre${n}`, n, `post${n}`])
].flat()
);
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
lifecycleScriptNames
});
declare const maintainedNodeVersions: readonly string[] & {
current: string;
last: string;
next: string;
previous: string;
};
export { maintainedNodeVersions };
"use strict";
/* Socket Lib - Built with esbuild */
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var maintained_node_versions_exports = {};
__export(maintained_node_versions_exports, {
maintainedNodeVersions: () => maintainedNodeVersions
});
module.exports = __toCommonJS(maintained_node_versions_exports);
const ObjectFreeze = Object.freeze;
const next = "25.0.0";
const current = "22.20.0";
const previous = "20.19.5";
const last = "18.20.8";
const maintainedNodeVersions = ObjectFreeze(
Object.assign([last, previous, current, next], {
current,
last,
next,
previous
})
);
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
maintainedNodeVersions
});
/* c8 ignore next - External semver call */
declare const packageDefaultNodeRange: string;
export { packageDefaultNodeRange };
"use strict";
/* Socket Lib - Built with esbuild */
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var package_default_node_range_exports = {};
__export(package_default_node_range_exports, {
packageDefaultNodeRange: () => packageDefaultNodeRange
});
module.exports = __toCommonJS(package_default_node_range_exports);
var import_maintained_node_versions = require("./maintained-node-versions");
var semver = __toESM(require("./external/semver.js"));
const packageDefaultNodeRange = `>=${semver.parse(import_maintained_node_versions.maintainedNodeVersions.last).major}`;
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
packageDefaultNodeRange
});
/**
* @fileoverview Default Socket security categories for packages.
*/
// Default category for new packages
declare const packageDefaultSocketCategories: readonly string[];
export { packageDefaultSocketCategories };
"use strict";
/* Socket Lib - Built with esbuild */
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var package_default_socket_categories_exports = {};
__export(package_default_socket_categories_exports, {
packageDefaultSocketCategories: () => packageDefaultSocketCategories
});
module.exports = __toCommonJS(package_default_socket_categories_exports);
const packageDefaultSocketCategories = Object.freeze(["cleanup"]);
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
packageDefaultSocketCategories
});
import type { EditablePackageJsonOptions, NormalizeOptions, PackageJson, SaveOptions } from '../packages';
// Define the interface for the dynamic class
interface EditablePackageJsonConstructor {
new (): EditablePackageJsonInstance;
fixSteps: unknown[];
normalizeSteps: unknown[];
prepareSteps: unknown[];
create(path: string, opts?: EditablePackageJsonOptions): Promise<EditablePackageJsonInstance>;
fix(path: string, opts?: unknown): Promise<EditablePackageJsonInstance>;
load(path: string, opts?: EditablePackageJsonOptions): Promise<EditablePackageJsonInstance>;
normalize(path: string, opts?: NormalizeOptions): Promise<EditablePackageJsonInstance>;
prepare(path: string, opts?: unknown): Promise<EditablePackageJsonInstance>;
}
/**
* EditablePackageJson instance interface extending NPMCliPackageJson functionality.
* Provides enhanced package.json manipulation with Socket-specific features.
* @extends NPMCliPackageJson (from @npmcli/package-json)
*/
export interface EditablePackageJsonInstance {
/**
* The parsed package.json content as a readonly object.
* @readonly
*/
content: Readonly<PackageJson>;
/**
* Create a new package.json file at the specified path.
* @param path - The directory path where package.json will be created
*/
create(path: string): this;
/**
* Apply automatic fixes to the package.json based on npm standards.
* @param opts - Optional fix configuration
*/
fix(opts?: unknown | undefined): Promise<this>;
/**
* Initialize the instance from a content object.
* @param content - The package.json content object
*/
fromContent(content: unknown): this;
/**
* Initialize the instance from a JSON string.
* @param json - The package.json content as a JSON string
*/
fromJSON(json: string): this;
/**
* Load a package.json file from the specified path.
* @param path - The directory containing the package.json
* @param create - Whether to create the file if it doesn't exist
*/
load(path: string, create?: boolean): Promise<this>;
/**
* Normalize the package.json content according to npm standards.
* @param opts - Normalization options
*/
normalize(opts?: NormalizeOptions): Promise<this>;
/**
* Prepare the package.json for publishing.
* @param opts - Preparation options
*/
prepare(opts?: unknown): Promise<this>;
/**
* Update the package.json content with new values.
* @param content - Partial package.json object with fields to update
* @override from NPMCliPackageJson
*/
update(content: Partial<PackageJson>): this;
/**
* Save the package.json file to disk.
* @param options - Save options for formatting and sorting
* @override from NPMCliPackageJson
*/
save(options?: SaveOptions | undefined): Promise<boolean>;
/**
* Synchronously save the package.json file to disk.
* @param options - Save options for formatting and sorting
*/
saveSync(options?: SaveOptions | undefined): boolean;
/**
* Check if the package.json will be saved based on current changes.
* @param options - Save options to evaluate
*/
willSave(options?: SaveOptions | undefined): boolean;
}
/**
* Get the EditablePackageJson class for package.json manipulation.
*/
/*@__NO_SIDE_EFFECTS__*/
export declare function getEditablePackageJsonClass(): EditablePackageJsonConstructor;
/**
* Convert a package.json object to an editable instance.
*/
/*@__NO_SIDE_EFFECTS__*/
export declare function pkgJsonToEditable(pkgJson: PackageJson, options?: EditablePackageJsonOptions): unknown;
/**
* Convert package.json to editable instance with file persistence.
*/
/*@__NO_SIDE_EFFECTS__*/
export declare function toEditablePackageJson(pkgJson: PackageJson, options?: EditablePackageJsonOptions): Promise<unknown>;
/**
* Convert package.json to editable instance with file persistence synchronously.
*/
/*@__NO_SIDE_EFFECTS__*/
export declare function toEditablePackageJsonSync(pkgJson: PackageJson, options?: EditablePackageJsonOptions): unknown;
export {};
"use strict";
/* Socket Lib - Built with esbuild */
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var editable_exports = {};
__export(editable_exports, {
getEditablePackageJsonClass: () => getEditablePackageJsonClass,
pkgJsonToEditable: () => pkgJsonToEditable,
toEditablePackageJson: () => toEditablePackageJson,
toEditablePackageJsonSync: () => toEditablePackageJsonSync
});
module.exports = __toCommonJS(editable_exports);
var import_package_json = __toESM(require("../external/@npmcli/package-json"));
var import_read_package = require("../external/@npmcli/package-json/lib/read-package");
var import_sort = require("../external/@npmcli/package-json/lib/sort");
var import_normalize = require("../paths/normalize");
var import_normalize2 = require("./normalize");
var import_packages = require("../paths/packages");
const identSymbol = Symbol.for("indent");
const newlineSymbol = Symbol.for("newline");
let _EditablePackageJsonClass;
let _fs;
// @__NO_SIDE_EFFECTS__
function getFs() {
if (_fs === void 0) {
_fs = require("node:fs");
}
return _fs;
}
let _path;
// @__NO_SIDE_EFFECTS__
function getPath() {
if (_path === void 0) {
_path = require("node:path");
}
return _path;
}
let _util;
// @__NO_SIDE_EFFECTS__
function getUtil() {
if (_util === void 0) {
_util = require("node:util");
}
return _util;
}
// @__NO_SIDE_EFFECTS__
function getEditablePackageJsonClass() {
if (_EditablePackageJsonClass === void 0) {
_EditablePackageJsonClass = class EditablePackageJson extends import_package_json.default {
static fixSteps = import_package_json.default.fixSteps;
static normalizeSteps = import_package_json.default.normalizeSteps;
static prepareSteps = import_package_json.default.prepareSteps;
_canSave = true;
_path = void 0;
_readFileContent = "";
_readFileJson = void 0;
get content() {
return super.content;
}
get filename() {
const path = this._path;
if (!path) {
return "";
}
if (path.endsWith("package.json")) {
return path;
}
const nodePath = /* @__PURE__ */ getPath();
return nodePath.join(path, "package.json");
}
static async create(path, opts = {}) {
const p = new _EditablePackageJsonClass();
await p.create(path);
return opts.data ? p.update(opts.data) : p;
}
static async fix(path, opts) {
const p = new _EditablePackageJsonClass();
await p.load(path, true);
return await p.fix(opts);
}
static async load(path, opts = {}) {
const p = new _EditablePackageJsonClass();
if (!opts.create) {
return await p.load(path);
}
try {
return await p.load(path);
} catch (err) {
if (!err.message.startsWith("Could not read package.json")) {
throw err;
}
return p.create(path);
}
}
static async normalize(path, opts) {
const p = new _EditablePackageJsonClass();
await p.load(path);
return await p.normalize(opts);
}
static async prepare(path, opts) {
const p = new _EditablePackageJsonClass();
await p.load(path, true);
return await p.prepare(opts);
}
create(path) {
super.create(path);
this._path = path;
return this;
}
async fix(opts = {}) {
await super.fix(opts);
return this;
}
fromContent(data) {
super.fromContent(data);
this._canSave = false;
return this;
}
fromJSON(data) {
super.fromJSON(data);
return this;
}
async load(path, create) {
this._path = path;
const { promises: fsPromises } = /* @__PURE__ */ getFs();
let parseErr;
try {
this._readFileContent = await (0, import_read_package.read)(this.filename);
} catch (err) {
if (!create) {
throw err;
}
parseErr = err;
}
if (parseErr) {
const nodePath = /* @__PURE__ */ getPath();
const indexFile = nodePath.resolve(this.path || "", "index.js");
let indexFileContent;
try {
indexFileContent = await fsPromises.readFile(indexFile, "utf8");
} catch {
throw parseErr;
}
try {
this.fromContent(indexFileContent);
} catch {
throw parseErr;
}
this._canSave = false;
return this;
}
this.fromJSON(this._readFileContent);
this._readFileJson = (0, import_read_package.parse)(this._readFileContent);
return this;
}
async normalize(opts = {}) {
await super.normalize(opts);
return this;
}
get path() {
return this._path;
}
async prepare(opts = {}) {
await super.prepare(opts);
return this;
}
async save(options) {
if (!this._canSave || this.content === void 0) {
throw new Error("No package.json to save to");
}
const { ignoreWhitespace = false, sort = false } = {
__proto__: null,
...options
};
const {
[identSymbol]: indent,
[newlineSymbol]: newline,
...rest
} = this.content;
const content = sort ? (0, import_sort.packageSort)(rest) : rest;
const {
[identSymbol]: _indent,
[newlineSymbol]: _newline,
...origContent
} = this._readFileJson || {};
if (ignoreWhitespace && (/* @__PURE__ */ getUtil()).isDeepStrictEqual(content, origContent)) {
return false;
}
const format = indent === void 0 || indent === null ? " " : indent;
const eol = newline === void 0 || newline === null ? "\n" : newline;
const fileContent = `${JSON.stringify(
content,
void 0,
format
)}
`.replace(/\n/g, eol);
if (!ignoreWhitespace && fileContent.trim() === this._readFileContent.trim()) {
return false;
}
const { promises: fsPromises } = /* @__PURE__ */ getFs();
await fsPromises.writeFile(this.filename, fileContent);
this._readFileContent = fileContent;
this._readFileJson = (0, import_read_package.parse)(fileContent);
return true;
}
saveSync(options) {
if (!this._canSave || this.content === void 0) {
throw new Error("No package.json to save to");
}
const { ignoreWhitespace = false, sort = false } = {
__proto__: null,
...options
};
const {
[Symbol.for("indent")]: indent,
[Symbol.for("newline")]: newline,
...rest
} = this.content;
const content = sort ? (0, import_sort.packageSort)(rest) : rest;
if (ignoreWhitespace && (/* @__PURE__ */ getUtil()).isDeepStrictEqual(content, this._readFileJson)) {
return false;
}
const format = indent === void 0 || indent === null ? " " : indent;
const eol = newline === void 0 || newline === null ? "\n" : newline;
const fileContent = `${JSON.stringify(
content,
void 0,
format
)}
`.replace(/\n/g, eol);
if (!ignoreWhitespace && fileContent.trim() === this._readFileContent.trim()) {
return false;
}
const fs = /* @__PURE__ */ getFs();
fs.writeFileSync(this.filename, fileContent);
this._readFileContent = fileContent;
this._readFileJson = (0, import_read_package.parse)(fileContent);
return true;
}
update(content) {
super.update(content);
return this;
}
willSave(options) {
const { ignoreWhitespace = false, sort = false } = {
__proto__: null,
...options
};
if (!this._canSave || this.content === void 0) {
return false;
}
const {
[Symbol.for("indent")]: indent,
[Symbol.for("newline")]: newline,
...rest
} = this.content;
const content = sort ? (0, import_sort.packageSort)(rest) : rest;
if (ignoreWhitespace && (/* @__PURE__ */ getUtil()).isDeepStrictEqual(content, this._readFileJson)) {
return false;
}
const format = indent === void 0 || indent === null ? " " : indent;
const eol = newline === void 0 || newline === null ? "\n" : newline;
const fileContent = `${JSON.stringify(
content,
void 0,
format
)}
`.replace(/\n/g, eol);
if (!ignoreWhitespace && fileContent.trim() === this._readFileContent.trim()) {
return false;
}
return true;
}
};
}
return _EditablePackageJsonClass;
}
// @__NO_SIDE_EFFECTS__
function pkgJsonToEditable(pkgJson, options) {
const { normalize, ...normalizeOptions } = {
__proto__: null,
...options
};
const EditablePackageJson = /* @__PURE__ */ getEditablePackageJsonClass();
return new EditablePackageJson().fromContent(
normalize ? (0, import_normalize2.normalizePackageJson)(pkgJson, normalizeOptions) : pkgJson
);
}
// @__NO_SIDE_EFFECTS__
async function toEditablePackageJson(pkgJson, options) {
const { path: filepath, ...pkgJsonToEditableOptions } = {
__proto__: null,
...options
};
const { normalize, ...normalizeOptions } = pkgJsonToEditableOptions;
if (typeof filepath !== "string") {
return /* @__PURE__ */ pkgJsonToEditable(pkgJson, pkgJsonToEditableOptions);
}
const EditablePackageJson = /* @__PURE__ */ getEditablePackageJsonClass();
const pkgJsonPath = (0, import_packages.resolvePackageJsonDirname)(filepath);
return (await EditablePackageJson.load(pkgJsonPath, { create: true })).fromJSON(
`${JSON.stringify(
normalize ? (0, import_normalize2.normalizePackageJson)(pkgJson, {
...(0, import_normalize.isNodeModules)(pkgJsonPath) ? {} : { preserve: ["repository"] },
...normalizeOptions
}) : pkgJson,
null,
2
)}
`
);
}
// @__NO_SIDE_EFFECTS__
function toEditablePackageJsonSync(pkgJson, options) {
const { path: filepath, ...pkgJsonToEditableOptions } = {
__proto__: null,
...options
};
const { normalize, ...normalizeOptions } = pkgJsonToEditableOptions;
if (typeof filepath !== "string") {
return /* @__PURE__ */ pkgJsonToEditable(pkgJson, pkgJsonToEditableOptions);
}
const EditablePackageJson = /* @__PURE__ */ getEditablePackageJsonClass();
const pkgJsonPath = (0, import_packages.resolvePackageJsonDirname)(filepath);
return new EditablePackageJson().create(pkgJsonPath).fromJSON(
`${JSON.stringify(
normalize ? (0, import_normalize2.normalizePackageJson)(pkgJson, {
...(0, import_normalize.isNodeModules)(pkgJsonPath) ? {} : { preserve: ["repository"] },
...normalizeOptions
}) : pkgJson,
null,
2
)}
`
);
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
getEditablePackageJsonClass,
pkgJsonToEditable,
toEditablePackageJson,
toEditablePackageJsonSync
});