@socketsecurity/lib 3.1.3 → 3.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/dlx-binary.js +19 -1
- package/dist/dlx-binary.js.map +2 -2
- package/dist/dlx-manifest.d.ts +116 -0
- package/dist/dlx-manifest.js +295 -0
- package/dist/dlx-manifest.js.map +7 -0
- package/dist/env/socket-cli.d.ts +14 -0
- package/dist/env/socket-cli.js +10 -0
- package/dist/env/socket-cli.js.map +2 -2
- package/package.json +5 -1
package/dist/dlx-binary.js
CHANGED
|
@@ -41,6 +41,7 @@ var import_os = __toESM(require("os"));
|
|
|
41
41
|
var import_path = __toESM(require("path"));
|
|
42
42
|
var import_platform = require("#constants/platform");
|
|
43
43
|
var import_dlx = require("./dlx");
|
|
44
|
+
var import_dlx_manifest = require("./dlx-manifest");
|
|
44
45
|
var import_http_request = require("./http-request");
|
|
45
46
|
var import_fs = require("./fs");
|
|
46
47
|
var import_objects = require("./objects");
|
|
@@ -129,7 +130,7 @@ Check your internet connection or verify the URL is accessible.`,
|
|
|
129
130
|
}
|
|
130
131
|
);
|
|
131
132
|
}
|
|
132
|
-
async function writeMetadata(cacheEntryPath, cacheKey, url, checksum, size) {
|
|
133
|
+
async function writeMetadata(cacheEntryPath, cacheKey, url, binaryName, checksum, size) {
|
|
133
134
|
const metaPath = getMetadataPath(cacheEntryPath);
|
|
134
135
|
const metadata = {
|
|
135
136
|
version: "1.0.0",
|
|
@@ -147,6 +148,21 @@ async function writeMetadata(cacheEntryPath, cacheKey, url, checksum, size) {
|
|
|
147
148
|
};
|
|
148
149
|
const fs = /* @__PURE__ */ getFs();
|
|
149
150
|
await fs.promises.writeFile(metaPath, JSON.stringify(metadata, null, 2));
|
|
151
|
+
try {
|
|
152
|
+
const spec = `${url}:${binaryName}`;
|
|
153
|
+
await import_dlx_manifest.dlxManifest.setBinaryEntry(spec, cacheKey, {
|
|
154
|
+
checksum,
|
|
155
|
+
checksum_algorithm: "sha256",
|
|
156
|
+
platform: import_os.default.platform(),
|
|
157
|
+
arch: import_os.default.arch(),
|
|
158
|
+
size,
|
|
159
|
+
source: {
|
|
160
|
+
type: "download",
|
|
161
|
+
url
|
|
162
|
+
}
|
|
163
|
+
});
|
|
164
|
+
} catch {
|
|
165
|
+
}
|
|
150
166
|
}
|
|
151
167
|
async function cleanDlxCache(maxAge = (
|
|
152
168
|
/*@__INLINE__*/
|
|
@@ -258,6 +274,7 @@ Ensure the filesystem is writable or set SOCKET_DLX_DIR to a writable location.`
|
|
|
258
274
|
cacheEntryDir,
|
|
259
275
|
cacheKey,
|
|
260
276
|
url,
|
|
277
|
+
binaryName,
|
|
261
278
|
computedChecksum || "",
|
|
262
279
|
stats.size
|
|
263
280
|
);
|
|
@@ -329,6 +346,7 @@ Ensure the filesystem is writable or set SOCKET_DLX_DIR to a writable location.`
|
|
|
329
346
|
cacheEntryDir,
|
|
330
347
|
cacheKey,
|
|
331
348
|
url,
|
|
349
|
+
binaryName,
|
|
332
350
|
computedChecksum || "",
|
|
333
351
|
stats.size
|
|
334
352
|
);
|
package/dist/dlx-binary.js.map
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../src/dlx-binary.ts"],
|
|
4
|
-
"sourcesContent": ["/** @fileoverview DLX binary execution utilities for Socket ecosystem. */\n\nimport { createHash } from 'crypto'\n\nimport os from 'os'\n\nimport path from 'path'\n\nimport { WIN32 } from '#constants/platform'\n\nimport { generateCacheKey } from './dlx'\nimport { httpDownload } from './http-request'\nimport { isDir, readJson, safeDelete, safeMkdir } from './fs'\nimport { isObjectObject } from './objects'\nimport { normalizePath } from './path'\nimport { getSocketDlxDir } from './paths'\nimport { processLock } from './process-lock'\nimport type { SpawnExtra, SpawnOptions } from './spawn'\nimport { spawn } from './spawn'\n\nlet _fs: typeof import('fs') | undefined\n/**\n * Lazily load the fs module to avoid Webpack errors.\n * Uses non-'node:' prefixed require to prevent Webpack bundling issues.\n *\n * @returns The Node.js fs module\n * @private\n */\n/*@__NO_SIDE_EFFECTS__*/\nfunction getFs() {\n if (_fs === undefined) {\n // Use non-'node:' prefixed require to avoid Webpack errors.\n\n _fs = /*@__PURE__*/ require('node:fs')\n }\n return _fs as typeof import('fs')\n}\n\nexport interface DlxBinaryOptions {\n /**\n * URL to download the binary from.\n */\n url: string\n\n /**\n * Optional name for the cached binary (defaults to URL hash).\n */\n name?: string | undefined\n\n /**\n * Expected checksum (sha256) for verification.\n */\n checksum?: string | undefined\n\n /**\n * Cache TTL in milliseconds (default: 7 days).\n */\n cacheTtl?: number | undefined\n\n /**\n * Force re-download even if cached.\n * Aligns with npm/npx --force flag.\n */\n force?: boolean | undefined\n\n /**\n * Skip confirmation prompts (auto-approve).\n * Aligns with npx --yes/-y flag.\n */\n yes?: boolean | undefined\n\n /**\n * Suppress output (quiet mode).\n * Aligns with npx --quiet/-q and pnpm --silent/-s flags.\n */\n quiet?: boolean | undefined\n\n /**\n * Additional spawn options.\n */\n spawnOptions?: SpawnOptions | undefined\n}\n\nexport interface DlxBinaryResult {\n /** Path to the cached binary. */\n binaryPath: string\n /** Whether the binary was newly downloaded. */\n downloaded: boolean\n /** The spawn promise for the running process. */\n spawnPromise: ReturnType<typeof spawn>\n}\n\n/**\n * Metadata structure for cached binaries (.dlx-metadata.json).\n * Unified schema shared across TypeScript (dlxBinary) and C++ (socket_macho_decompress).\n *\n * Core Fields (present in all implementations):\n * - version: Schema version (currently \"1.0.0\")\n * - cache_key: First 16 chars of SHA-512 hash (matches directory name)\n * - timestamp: Unix timestamp in milliseconds\n * - checksum: Full hash of cached binary (SHA-512 for C++, SHA-256 for TypeScript)\n * - checksum_algorithm: \"sha512\" or \"sha256\"\n * - platform: \"darwin\" | \"linux\" | \"win32\"\n * - arch: \"x64\" | \"arm64\"\n * - size: Size of cached binary in bytes\n * - source: Origin information\n * - type: \"download\" (from URL) or \"decompression\" (from embedded binary)\n * - url: Download URL (if type is \"download\")\n * - path: Source binary path (if type is \"decompression\")\n *\n * Extra Fields (implementation-specific):\n * - For C++ decompression:\n * - compressed_size: Size of compressed data in bytes\n * - compression_algorithm: Brotli level (numeric)\n * - compression_ratio: original_size / compressed_size\n *\n * Example (TypeScript download):\n * ```json\n * {\n * \"version\": \"1.0.0\",\n * \"cache_key\": \"a1b2c3d4e5f67890\",\n * \"timestamp\": 1730332800000,\n * \"checksum\": \"sha256-abc123...\",\n * \"checksum_algorithm\": \"sha256\",\n * \"platform\": \"darwin\",\n * \"arch\": \"arm64\",\n * \"size\": 15000000,\n * \"source\": {\n * \"type\": \"download\",\n * \"url\": \"https://example.com/binary\"\n * }\n * }\n * ```\n *\n * Example (C++ decompression):\n * ```json\n * {\n * \"version\": \"1.0.0\",\n * \"cache_key\": \"0123456789abcdef\",\n * \"timestamp\": 1730332800000,\n * \"checksum\": \"sha512-def456...\",\n * \"checksum_algorithm\": \"sha512\",\n * \"platform\": \"darwin\",\n * \"arch\": \"arm64\",\n * \"size\": 13000000,\n * \"source\": {\n * \"type\": \"decompression\",\n * \"path\": \"/usr/local/bin/socket\"\n * },\n * \"extra\": {\n * \"compressed_size\": 1700000,\n * \"compression_algorithm\": 3,\n * \"compression_ratio\": 7.647\n * }\n * }\n * ```\n *\n * @internal This interface documents the metadata file format.\n */\nexport interface DlxMetadata {\n version: string\n cache_key: string\n timestamp: number\n checksum: string\n checksum_algorithm: string\n platform: string\n arch: string\n size: number\n source?: {\n type: 'download' | 'decompression'\n url?: string\n path?: string\n }\n extra?: Record<string, unknown>\n}\n\n/**\n * Get metadata file path for a cached binary.\n */\nfunction getMetadataPath(cacheEntryPath: string): string {\n return path.join(cacheEntryPath, '.dlx-metadata.json')\n}\n\n/**\n * Check if a cached binary is still valid.\n */\nasync function isCacheValid(\n cacheEntryPath: string,\n cacheTtl: number,\n): Promise<boolean> {\n const fs = getFs()\n try {\n const metaPath = getMetadataPath(cacheEntryPath)\n if (!fs.existsSync(metaPath)) {\n return false\n }\n\n const metadata = await readJson(metaPath, { throws: false })\n if (!isObjectObject(metadata)) {\n return false\n }\n const now = Date.now()\n const timestamp = (metadata as Record<string, unknown>)['timestamp']\n // If timestamp is missing or invalid, cache is invalid\n if (typeof timestamp !== 'number' || timestamp <= 0) {\n return false\n }\n const age = now - timestamp\n\n return age < cacheTtl\n } catch {\n return false\n }\n}\n\n/**\n * Download a file from a URL with integrity checking and concurrent download protection.\n * Uses processLock to prevent multiple processes from downloading the same binary simultaneously.\n * Internal helper function for downloading binary files.\n */\nasync function downloadBinaryFile(\n url: string,\n destPath: string,\n checksum?: string | undefined,\n): Promise<string> {\n // Use process lock to prevent concurrent downloads.\n // Lock is placed in the cache entry directory as 'concurrency.lock'.\n const cacheEntryDir = path.dirname(destPath)\n const lockPath = path.join(cacheEntryDir, 'concurrency.lock')\n\n return await processLock.withLock(\n lockPath,\n async () => {\n const fs = getFs()\n // Check if file was downloaded while waiting for lock.\n if (fs.existsSync(destPath)) {\n const stats = await fs.promises.stat(destPath)\n if (stats.size > 0) {\n // File exists, compute and return checksum.\n const fileBuffer = await fs.promises.readFile(destPath)\n const hasher = createHash('sha256')\n hasher.update(fileBuffer)\n return hasher.digest('hex')\n }\n }\n\n // Download the file.\n try {\n await httpDownload(url, destPath)\n } catch (e) {\n throw new Error(\n `Failed to download binary from ${url}\\n` +\n `Destination: ${destPath}\\n` +\n 'Check your internet connection or verify the URL is accessible.',\n { cause: e },\n )\n }\n\n // Compute checksum of downloaded file.\n const fileBuffer = await fs.promises.readFile(destPath)\n const hasher = createHash('sha256')\n hasher.update(fileBuffer)\n const actualChecksum = hasher.digest('hex')\n\n // Verify checksum if provided.\n if (checksum && actualChecksum !== checksum) {\n // Clean up invalid file.\n await safeDelete(destPath)\n throw new Error(\n `Checksum mismatch: expected ${checksum}, got ${actualChecksum}`,\n )\n }\n\n // Make executable on POSIX systems.\n if (!WIN32) {\n await fs.promises.chmod(destPath, 0o755)\n }\n\n return actualChecksum\n },\n {\n // Align with npm npx locking strategy.\n staleMs: 5000,\n touchIntervalMs: 2000,\n },\n )\n}\n\n/**\n * Write metadata for a cached binary.\n * Uses unified schema shared with C++ decompressor and CLI dlxBinary.\n * Schema documentation: See DlxMetadata interface in this file (exported).\n * Core fields: version, cache_key, timestamp, checksum, checksum_algorithm, platform, arch, size, source\n * Note: This implementation uses SHA-256 checksums instead of SHA-512.\n */\nasync function writeMetadata(\n cacheEntryPath: string,\n cacheKey: string,\n url: string,\n checksum: string,\n size: number,\n): Promise<void> {\n const metaPath = getMetadataPath(cacheEntryPath)\n const metadata = {\n version: '1.0.0',\n cache_key: cacheKey,\n timestamp: Date.now(),\n checksum,\n checksum_algorithm: 'sha256',\n platform: os.platform(),\n arch: os.arch(),\n size,\n source: {\n type: 'download',\n url,\n },\n }\n const fs = getFs()\n await fs.promises.writeFile(metaPath, JSON.stringify(metadata, null, 2))\n}\n\n/**\n * Clean expired entries from the DLX cache.\n */\nexport async function cleanDlxCache(\n maxAge: number = /*@__INLINE__*/ require('#constants/time').DLX_BINARY_CACHE_TTL,\n): Promise<number> {\n const cacheDir = getDlxCachePath()\n const fs = getFs()\n\n if (!fs.existsSync(cacheDir)) {\n return 0\n }\n\n let cleaned = 0\n const now = Date.now()\n const entries = await fs.promises.readdir(cacheDir)\n\n for (const entry of entries) {\n const entryPath = path.join(cacheDir, entry)\n const metaPath = getMetadataPath(entryPath)\n\n try {\n // eslint-disable-next-line no-await-in-loop\n if (!(await isDir(entryPath))) {\n continue\n }\n\n // eslint-disable-next-line no-await-in-loop\n const metadata = await readJson(metaPath, { throws: false })\n if (\n !metadata ||\n typeof metadata !== 'object' ||\n Array.isArray(metadata)\n ) {\n continue\n }\n const timestamp = (metadata as Record<string, unknown>)['timestamp']\n // If timestamp is missing or invalid, treat as expired (age = infinity)\n const age =\n typeof timestamp === 'number' && timestamp > 0\n ? now - timestamp\n : Number.POSITIVE_INFINITY\n\n if (age > maxAge) {\n // Remove entire cache entry directory.\n // eslint-disable-next-line no-await-in-loop\n await safeDelete(entryPath, { force: true, recursive: true })\n cleaned += 1\n }\n } catch {\n // If we can't read metadata, check if directory is empty or corrupted.\n try {\n // eslint-disable-next-line no-await-in-loop\n const contents = await fs.promises.readdir(entryPath)\n if (!contents.length) {\n // Remove empty directory.\n // eslint-disable-next-line no-await-in-loop\n await safeDelete(entryPath)\n cleaned += 1\n }\n } catch {}\n }\n }\n\n return cleaned\n}\n\n/**\n * Download and execute a binary from a URL with caching.\n */\nexport async function dlxBinary(\n args: readonly string[] | string[],\n options?: DlxBinaryOptions | undefined,\n spawnExtra?: SpawnExtra | undefined,\n): Promise<DlxBinaryResult> {\n const {\n cacheTtl = /*@__INLINE__*/ require('#constants/time').DLX_BINARY_CACHE_TTL,\n checksum,\n force: userForce = false,\n name,\n spawnOptions,\n url,\n yes,\n } = { __proto__: null, ...options } as DlxBinaryOptions\n\n // Map --yes flag to force behavior (auto-approve/skip prompts)\n const force = yes === true ? true : userForce\n\n // Generate cache paths similar to pnpm/npx structure.\n const cacheDir = getDlxCachePath()\n const binaryName = name || `binary-${process.platform}-${os.arch()}`\n // Create spec from URL and binary name for unique cache identity.\n const spec = `${url}:${binaryName}`\n const cacheKey = generateCacheKey(spec)\n const cacheEntryDir = path.join(cacheDir, cacheKey)\n const binaryPath = normalizePath(path.join(cacheEntryDir, binaryName))\n const fs = getFs()\n\n let downloaded = false\n let computedChecksum = checksum\n\n // Check if we need to download.\n if (\n !force &&\n fs.existsSync(cacheEntryDir) &&\n (await isCacheValid(cacheEntryDir, cacheTtl))\n ) {\n // Binary is cached and valid, read the checksum from metadata.\n try {\n const metaPath = getMetadataPath(cacheEntryDir)\n const metadata = await readJson(metaPath, { throws: false })\n if (\n metadata &&\n typeof metadata === 'object' &&\n !Array.isArray(metadata) &&\n typeof (metadata as Record<string, unknown>)['checksum'] === 'string'\n ) {\n computedChecksum = (metadata as Record<string, unknown>)[\n 'checksum'\n ] as string\n } else {\n // If metadata is invalid, re-download.\n downloaded = true\n }\n } catch {\n // If we can't read metadata, re-download.\n downloaded = true\n }\n } else {\n downloaded = true\n }\n\n if (downloaded) {\n // Ensure cache directory exists before downloading.\n try {\n await safeMkdir(cacheEntryDir)\n } catch (e) {\n const code = (e as NodeJS.ErrnoException).code\n if (code === 'EACCES' || code === 'EPERM') {\n throw new Error(\n `Permission denied creating binary cache directory: ${cacheEntryDir}\\n` +\n 'Please check directory permissions or run with appropriate access.',\n { cause: e },\n )\n }\n if (code === 'EROFS') {\n throw new Error(\n `Cannot create binary cache directory on read-only filesystem: ${cacheEntryDir}\\n` +\n 'Ensure the filesystem is writable or set SOCKET_DLX_DIR to a writable location.',\n { cause: e },\n )\n }\n throw new Error(\n `Failed to create binary cache directory: ${cacheEntryDir}`,\n { cause: e },\n )\n }\n\n // Download the binary.\n computedChecksum = await downloadBinaryFile(url, binaryPath, checksum)\n\n // Get file size for metadata.\n const stats = await fs.promises.stat(binaryPath)\n await writeMetadata(\n cacheEntryDir,\n cacheKey,\n url,\n computedChecksum || '',\n stats.size,\n )\n }\n\n // Execute the binary.\n // On Windows, script files (.bat, .cmd, .ps1) require shell: true because\n // they are not executable on their own and must be run through cmd.exe.\n // Note: .exe files are actual binaries and don't need shell mode.\n const needsShell = WIN32 && /\\.(?:bat|cmd|ps1)$/i.test(binaryPath)\n // Windows cmd.exe PATH resolution behavior:\n // When shell: true on Windows with .cmd/.bat/.ps1 files, spawn will automatically\n // strip the full path down to just the basename without extension (e.g.,\n // C:\\cache\\test.cmd becomes just \"test\"). Windows cmd.exe then searches for \"test\"\n // in directories listed in PATH, trying each extension from PATHEXT environment\n // variable (.COM, .EXE, .BAT, .CMD, etc.) until it finds a match.\n //\n // Since our binaries are downloaded to a custom cache directory that's not in PATH\n // (unlike system package managers like npm/pnpm/yarn which are already in PATH),\n // we must prepend the cache directory to PATH so cmd.exe can locate the binary.\n //\n // This approach is consistent with how other tools handle Windows command execution:\n // - npm's promise-spawn: uses which.sync() to find commands in PATH\n // - cross-spawn: spawns cmd.exe with escaped arguments\n // - Node.js spawn with shell: true: delegates to cmd.exe which uses PATH\n const finalSpawnOptions = needsShell\n ? {\n ...spawnOptions,\n env: {\n ...spawnOptions?.env,\n PATH: `${cacheEntryDir}${path.delimiter}${process.env['PATH'] || ''}`,\n },\n shell: true,\n }\n : spawnOptions\n const spawnPromise = spawn(binaryPath, args, finalSpawnOptions, spawnExtra)\n\n return {\n binaryPath,\n downloaded,\n spawnPromise,\n }\n}\n\n/**\n * Download a binary from a URL with caching (without execution).\n * Similar to downloadPackage from dlx-package.\n *\n * @returns Object containing the path to the cached binary and whether it was downloaded\n */\nexport async function downloadBinary(\n options: Omit<DlxBinaryOptions, 'spawnOptions'>,\n): Promise<{ binaryPath: string; downloaded: boolean }> {\n const {\n cacheTtl = /*@__INLINE__*/ require('#constants/time').DLX_BINARY_CACHE_TTL,\n checksum,\n force = false,\n name,\n url,\n } = { __proto__: null, ...options } as DlxBinaryOptions\n\n // Generate cache paths similar to pnpm/npx structure.\n const cacheDir = getDlxCachePath()\n const binaryName = name || `binary-${process.platform}-${os.arch()}`\n // Create spec from URL and binary name for unique cache identity.\n const spec = `${url}:${binaryName}`\n const cacheKey = generateCacheKey(spec)\n const cacheEntryDir = path.join(cacheDir, cacheKey)\n const binaryPath = normalizePath(path.join(cacheEntryDir, binaryName))\n const fs = getFs()\n\n let downloaded = false\n\n // Check if we need to download.\n if (\n !force &&\n fs.existsSync(cacheEntryDir) &&\n (await isCacheValid(cacheEntryDir, cacheTtl))\n ) {\n // Binary is cached and valid.\n downloaded = false\n } else {\n // Ensure cache directory exists before downloading.\n try {\n await safeMkdir(cacheEntryDir)\n } catch (e) {\n const code = (e as NodeJS.ErrnoException).code\n if (code === 'EACCES' || code === 'EPERM') {\n throw new Error(\n `Permission denied creating binary cache directory: ${cacheEntryDir}\\n` +\n 'Please check directory permissions or run with appropriate access.',\n { cause: e },\n )\n }\n if (code === 'EROFS') {\n throw new Error(\n `Cannot create binary cache directory on read-only filesystem: ${cacheEntryDir}\\n` +\n 'Ensure the filesystem is writable or set SOCKET_DLX_DIR to a writable location.',\n { cause: e },\n )\n }\n throw new Error(\n `Failed to create binary cache directory: ${cacheEntryDir}`,\n { cause: e },\n )\n }\n\n // Download the binary.\n const computedChecksum = await downloadBinaryFile(url, binaryPath, checksum)\n\n // Get file size for metadata.\n const stats = await fs.promises.stat(binaryPath)\n await writeMetadata(\n cacheEntryDir,\n cacheKey,\n url,\n computedChecksum || '',\n stats.size,\n )\n downloaded = true\n }\n\n return {\n binaryPath,\n downloaded,\n }\n}\n\n/**\n * Execute a cached binary without re-downloading.\n * Similar to executePackage from dlx-package.\n * Binary must have been previously downloaded via downloadBinary or dlxBinary.\n *\n * @param binaryPath Path to the cached binary (from downloadBinary result)\n * @param args Arguments to pass to the binary\n * @param spawnOptions Spawn options for execution\n * @param spawnExtra Extra spawn configuration\n * @returns The spawn promise for the running process\n */\nexport function executeBinary(\n binaryPath: string,\n args: readonly string[] | string[],\n spawnOptions?: SpawnOptions | undefined,\n spawnExtra?: SpawnExtra | undefined,\n): ReturnType<typeof spawn> {\n // On Windows, script files (.bat, .cmd, .ps1) require shell: true because\n // they are not executable on their own and must be run through cmd.exe.\n // Note: .exe files are actual binaries and don't need shell mode.\n const needsShell = WIN32 && /\\.(?:bat|cmd|ps1)$/i.test(binaryPath)\n\n // Windows cmd.exe PATH resolution behavior:\n // When shell: true on Windows with .cmd/.bat/.ps1 files, spawn will automatically\n // strip the full path down to just the basename without extension. Windows cmd.exe\n // then searches for the binary in directories listed in PATH.\n //\n // Since our binaries are downloaded to a custom cache directory that's not in PATH,\n // we must prepend the cache directory to PATH so cmd.exe can locate the binary.\n const cacheEntryDir = path.dirname(binaryPath)\n const finalSpawnOptions = needsShell\n ? {\n ...spawnOptions,\n env: {\n ...spawnOptions?.env,\n PATH: `${cacheEntryDir}${path.delimiter}${process.env['PATH'] || ''}`,\n },\n shell: true,\n }\n : spawnOptions\n\n return spawn(binaryPath, args, finalSpawnOptions, spawnExtra)\n}\n\n/**\n * Get the DLX binary cache directory path.\n * Returns normalized path for cross-platform compatibility.\n * Uses same directory as dlx-package for unified DLX storage.\n */\nexport function getDlxCachePath(): string {\n return getSocketDlxDir()\n}\n\n/**\n * Get information about cached binaries.\n */\nexport async function listDlxCache(): Promise<\n Array<{\n age: number\n arch: string\n checksum: string\n name: string\n platform: string\n size: number\n url: string\n }>\n> {\n const cacheDir = getDlxCachePath()\n const fs = getFs()\n\n if (!fs.existsSync(cacheDir)) {\n return []\n }\n\n const results = []\n const now = Date.now()\n const entries = await fs.promises.readdir(cacheDir)\n\n for (const entry of entries) {\n const entryPath = path.join(cacheDir, entry)\n try {\n // eslint-disable-next-line no-await-in-loop\n if (!(await isDir(entryPath))) {\n continue\n }\n\n const metaPath = getMetadataPath(entryPath)\n // eslint-disable-next-line no-await-in-loop\n const metadata = await readJson(metaPath, { throws: false })\n if (\n !metadata ||\n typeof metadata !== 'object' ||\n Array.isArray(metadata)\n ) {\n continue\n }\n\n const metaObj = metadata as Record<string, unknown>\n\n // Get URL from unified schema (source.url) or legacy schema (url).\n // Allow empty URL for backward compatibility with partial metadata.\n const source = metaObj['source'] as Record<string, unknown> | undefined\n const url =\n (source?.['url'] as string) || (metaObj['url'] as string) || ''\n\n // Find the binary file in the directory.\n // eslint-disable-next-line no-await-in-loop\n const files = await fs.promises.readdir(entryPath)\n const binaryFile = files.find(f => !f.startsWith('.'))\n\n if (binaryFile) {\n const binaryPath = path.join(entryPath, binaryFile)\n // eslint-disable-next-line no-await-in-loop\n const binaryStats = await fs.promises.stat(binaryPath)\n\n results.push({\n age: now - ((metaObj['timestamp'] as number) || 0),\n arch: (metaObj['arch'] as string) || 'unknown',\n checksum: (metaObj['checksum'] as string) || '',\n name: binaryFile,\n platform: (metaObj['platform'] as string) || 'unknown',\n size: binaryStats.size,\n url,\n })\n }\n } catch {}\n }\n\n return results\n}\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAEA,oBAA2B;AAE3B,gBAAe;AAEf,kBAAiB;AAEjB,sBAAsB;AAEtB,iBAAiC;AACjC,0BAA6B;AAC7B,gBAAuD;AACvD,qBAA+B;AAC/B,IAAAA,eAA8B;AAC9B,mBAAgC;AAChC,0BAA4B;AAE5B,mBAAsB;AAEtB,IAAI;AAAA;AASJ,SAAS,QAAQ;AACf,MAAI,QAAQ,QAAW;AAGrB,UAAoB,QAAQ,SAAS;AAAA,EACvC;AACA,SAAO;AACT;AA+IA,SAAS,gBAAgB,gBAAgC;AACvD,SAAO,YAAAC,QAAK,KAAK,gBAAgB,oBAAoB;AACvD;AAKA,eAAe,aACb,gBACA,UACkB;AAClB,QAAM,KAAK,sBAAM;AACjB,MAAI;AACF,UAAM,WAAW,gBAAgB,cAAc;AAC/C,QAAI,CAAC,GAAG,WAAW,QAAQ,GAAG;AAC5B,aAAO;AAAA,IACT;AAEA,UAAM,WAAW,UAAM,oBAAS,UAAU,EAAE,QAAQ,MAAM,CAAC;AAC3D,QAAI,KAAC,+BAAe,QAAQ,GAAG;AAC7B,aAAO;AAAA,IACT;AACA,UAAM,MAAM,KAAK,IAAI;AACrB,UAAM,YAAa,SAAqC,WAAW;AAEnE,QAAI,OAAO,cAAc,YAAY,aAAa,GAAG;AACnD,aAAO;AAAA,IACT;AACA,UAAM,MAAM,MAAM;AAElB,WAAO,MAAM;AAAA,EACf,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAOA,eAAe,mBACb,KACA,UACA,UACiB;AAGjB,QAAM,gBAAgB,YAAAA,QAAK,QAAQ,QAAQ;AAC3C,QAAM,WAAW,YAAAA,QAAK,KAAK,eAAe,kBAAkB;AAE5D,SAAO,MAAM,gCAAY;AAAA,IACvB;AAAA,IACA,YAAY;AACV,YAAM,KAAK,sBAAM;AAEjB,UAAI,GAAG,WAAW,QAAQ,GAAG;AAC3B,cAAM,QAAQ,MAAM,GAAG,SAAS,KAAK,QAAQ;AAC7C,YAAI,MAAM,OAAO,GAAG;AAElB,gBAAMC,cAAa,MAAM,GAAG,SAAS,SAAS,QAAQ;AACtD,gBAAMC,cAAS,0BAAW,QAAQ;AAClC,UAAAA,QAAO,OAAOD,WAAU;AACxB,iBAAOC,QAAO,OAAO,KAAK;AAAA,QAC5B;AAAA,MACF;AAGA,UAAI;AACF,kBAAM,kCAAa,KAAK,QAAQ;AAAA,MAClC,SAAS,GAAG;AACV,cAAM,IAAI;AAAA,UACR,kCAAkC,GAAG;AAAA,eACnB,QAAQ;AAAA;AAAA,UAE1B,EAAE,OAAO,EAAE;AAAA,QACb;AAAA,MACF;AAGA,YAAM,aAAa,MAAM,GAAG,SAAS,SAAS,QAAQ;AACtD,YAAM,aAAS,0BAAW,QAAQ;AAClC,aAAO,OAAO,UAAU;AACxB,YAAM,iBAAiB,OAAO,OAAO,KAAK;AAG1C,UAAI,YAAY,mBAAmB,UAAU;AAE3C,kBAAM,sBAAW,QAAQ;AACzB,cAAM,IAAI;AAAA,UACR,+BAA+B,QAAQ,SAAS,cAAc;AAAA,QAChE;AAAA,MACF;AAGA,UAAI,CAAC,uBAAO;AACV,cAAM,GAAG,SAAS,MAAM,UAAU,GAAK;AAAA,MACzC;AAEA,aAAO;AAAA,IACT;AAAA,IACA;AAAA;AAAA,MAEE,SAAS;AAAA,MACT,iBAAiB;AAAA,IACnB;AAAA,EACF;AACF;
|
|
4
|
+
"sourcesContent": ["/** @fileoverview DLX binary execution utilities for Socket ecosystem. */\n\nimport { createHash } from 'crypto'\n\nimport os from 'os'\n\nimport path from 'path'\n\nimport { WIN32 } from '#constants/platform'\n\nimport { generateCacheKey } from './dlx'\nimport { dlxManifest } from './dlx-manifest'\nimport { httpDownload } from './http-request'\nimport { isDir, readJson, safeDelete, safeMkdir } from './fs'\nimport { isObjectObject } from './objects'\nimport { normalizePath } from './path'\nimport { getSocketDlxDir } from './paths'\nimport { processLock } from './process-lock'\nimport type { SpawnExtra, SpawnOptions } from './spawn'\nimport { spawn } from './spawn'\n\nlet _fs: typeof import('fs') | undefined\n/**\n * Lazily load the fs module to avoid Webpack errors.\n * Uses non-'node:' prefixed require to prevent Webpack bundling issues.\n *\n * @returns The Node.js fs module\n * @private\n */\n/*@__NO_SIDE_EFFECTS__*/\nfunction getFs() {\n if (_fs === undefined) {\n // Use non-'node:' prefixed require to avoid Webpack errors.\n\n _fs = /*@__PURE__*/ require('node:fs')\n }\n return _fs as typeof import('fs')\n}\n\nexport interface DlxBinaryOptions {\n /**\n * URL to download the binary from.\n */\n url: string\n\n /**\n * Optional name for the cached binary (defaults to URL hash).\n */\n name?: string | undefined\n\n /**\n * Expected checksum (sha256) for verification.\n */\n checksum?: string | undefined\n\n /**\n * Cache TTL in milliseconds (default: 7 days).\n */\n cacheTtl?: number | undefined\n\n /**\n * Force re-download even if cached.\n * Aligns with npm/npx --force flag.\n */\n force?: boolean | undefined\n\n /**\n * Skip confirmation prompts (auto-approve).\n * Aligns with npx --yes/-y flag.\n */\n yes?: boolean | undefined\n\n /**\n * Suppress output (quiet mode).\n * Aligns with npx --quiet/-q and pnpm --silent/-s flags.\n */\n quiet?: boolean | undefined\n\n /**\n * Additional spawn options.\n */\n spawnOptions?: SpawnOptions | undefined\n}\n\nexport interface DlxBinaryResult {\n /** Path to the cached binary. */\n binaryPath: string\n /** Whether the binary was newly downloaded. */\n downloaded: boolean\n /** The spawn promise for the running process. */\n spawnPromise: ReturnType<typeof spawn>\n}\n\n/**\n * Metadata structure for cached binaries (.dlx-metadata.json).\n * Unified schema shared across TypeScript (dlxBinary) and C++ (socket_macho_decompress).\n *\n * Core Fields (present in all implementations):\n * - version: Schema version (currently \"1.0.0\")\n * - cache_key: First 16 chars of SHA-512 hash (matches directory name)\n * - timestamp: Unix timestamp in milliseconds\n * - checksum: Full hash of cached binary (SHA-512 for C++, SHA-256 for TypeScript)\n * - checksum_algorithm: \"sha512\" or \"sha256\"\n * - platform: \"darwin\" | \"linux\" | \"win32\"\n * - arch: \"x64\" | \"arm64\"\n * - size: Size of cached binary in bytes\n * - source: Origin information\n * - type: \"download\" (from URL) or \"decompression\" (from embedded binary)\n * - url: Download URL (if type is \"download\")\n * - path: Source binary path (if type is \"decompression\")\n *\n * Extra Fields (implementation-specific):\n * - For C++ decompression:\n * - compressed_size: Size of compressed data in bytes\n * - compression_algorithm: Brotli level (numeric)\n * - compression_ratio: original_size / compressed_size\n *\n * Example (TypeScript download):\n * ```json\n * {\n * \"version\": \"1.0.0\",\n * \"cache_key\": \"a1b2c3d4e5f67890\",\n * \"timestamp\": 1730332800000,\n * \"checksum\": \"sha256-abc123...\",\n * \"checksum_algorithm\": \"sha256\",\n * \"platform\": \"darwin\",\n * \"arch\": \"arm64\",\n * \"size\": 15000000,\n * \"source\": {\n * \"type\": \"download\",\n * \"url\": \"https://example.com/binary\"\n * }\n * }\n * ```\n *\n * Example (C++ decompression):\n * ```json\n * {\n * \"version\": \"1.0.0\",\n * \"cache_key\": \"0123456789abcdef\",\n * \"timestamp\": 1730332800000,\n * \"checksum\": \"sha512-def456...\",\n * \"checksum_algorithm\": \"sha512\",\n * \"platform\": \"darwin\",\n * \"arch\": \"arm64\",\n * \"size\": 13000000,\n * \"source\": {\n * \"type\": \"decompression\",\n * \"path\": \"/usr/local/bin/socket\"\n * },\n * \"extra\": {\n * \"compressed_size\": 1700000,\n * \"compression_algorithm\": 3,\n * \"compression_ratio\": 7.647\n * }\n * }\n * ```\n *\n * @internal This interface documents the metadata file format.\n */\nexport interface DlxMetadata {\n version: string\n cache_key: string\n timestamp: number\n checksum: string\n checksum_algorithm: string\n platform: string\n arch: string\n size: number\n source?: {\n type: 'download' | 'decompression'\n url?: string\n path?: string\n }\n extra?: Record<string, unknown>\n}\n\n/**\n * Get metadata file path for a cached binary.\n */\nfunction getMetadataPath(cacheEntryPath: string): string {\n return path.join(cacheEntryPath, '.dlx-metadata.json')\n}\n\n/**\n * Check if a cached binary is still valid.\n */\nasync function isCacheValid(\n cacheEntryPath: string,\n cacheTtl: number,\n): Promise<boolean> {\n const fs = getFs()\n try {\n const metaPath = getMetadataPath(cacheEntryPath)\n if (!fs.existsSync(metaPath)) {\n return false\n }\n\n const metadata = await readJson(metaPath, { throws: false })\n if (!isObjectObject(metadata)) {\n return false\n }\n const now = Date.now()\n const timestamp = (metadata as Record<string, unknown>)['timestamp']\n // If timestamp is missing or invalid, cache is invalid\n if (typeof timestamp !== 'number' || timestamp <= 0) {\n return false\n }\n const age = now - timestamp\n\n return age < cacheTtl\n } catch {\n return false\n }\n}\n\n/**\n * Download a file from a URL with integrity checking and concurrent download protection.\n * Uses processLock to prevent multiple processes from downloading the same binary simultaneously.\n * Internal helper function for downloading binary files.\n */\nasync function downloadBinaryFile(\n url: string,\n destPath: string,\n checksum?: string | undefined,\n): Promise<string> {\n // Use process lock to prevent concurrent downloads.\n // Lock is placed in the cache entry directory as 'concurrency.lock'.\n const cacheEntryDir = path.dirname(destPath)\n const lockPath = path.join(cacheEntryDir, 'concurrency.lock')\n\n return await processLock.withLock(\n lockPath,\n async () => {\n const fs = getFs()\n // Check if file was downloaded while waiting for lock.\n if (fs.existsSync(destPath)) {\n const stats = await fs.promises.stat(destPath)\n if (stats.size > 0) {\n // File exists, compute and return checksum.\n const fileBuffer = await fs.promises.readFile(destPath)\n const hasher = createHash('sha256')\n hasher.update(fileBuffer)\n return hasher.digest('hex')\n }\n }\n\n // Download the file.\n try {\n await httpDownload(url, destPath)\n } catch (e) {\n throw new Error(\n `Failed to download binary from ${url}\\n` +\n `Destination: ${destPath}\\n` +\n 'Check your internet connection or verify the URL is accessible.',\n { cause: e },\n )\n }\n\n // Compute checksum of downloaded file.\n const fileBuffer = await fs.promises.readFile(destPath)\n const hasher = createHash('sha256')\n hasher.update(fileBuffer)\n const actualChecksum = hasher.digest('hex')\n\n // Verify checksum if provided.\n if (checksum && actualChecksum !== checksum) {\n // Clean up invalid file.\n await safeDelete(destPath)\n throw new Error(\n `Checksum mismatch: expected ${checksum}, got ${actualChecksum}`,\n )\n }\n\n // Make executable on POSIX systems.\n if (!WIN32) {\n await fs.promises.chmod(destPath, 0o755)\n }\n\n return actualChecksum\n },\n {\n // Align with npm npx locking strategy.\n staleMs: 5000,\n touchIntervalMs: 2000,\n },\n )\n}\n\n/**\n * Write metadata for a cached binary.\n * Writes to both per-directory metadata file (for backward compatibility)\n * and global manifest (~/.socket/_dlx/.dlx-manifest.json).\n * Uses unified schema shared with C++ decompressor and CLI dlxBinary.\n * Schema documentation: See DlxMetadata interface in this file (exported).\n * Core fields: version, cache_key, timestamp, checksum, checksum_algorithm, platform, arch, size, source\n * Note: This implementation uses SHA-256 checksums instead of SHA-512.\n */\nasync function writeMetadata(\n cacheEntryPath: string,\n cacheKey: string,\n url: string,\n binaryName: string,\n checksum: string,\n size: number,\n): Promise<void> {\n // Write per-directory metadata file for backward compatibility.\n const metaPath = getMetadataPath(cacheEntryPath)\n const metadata = {\n version: '1.0.0',\n cache_key: cacheKey,\n timestamp: Date.now(),\n checksum,\n checksum_algorithm: 'sha256',\n platform: os.platform(),\n arch: os.arch(),\n size,\n source: {\n type: 'download',\n url,\n },\n }\n const fs = getFs()\n await fs.promises.writeFile(metaPath, JSON.stringify(metadata, null, 2))\n\n // Write to global manifest.\n try {\n const spec = `${url}:${binaryName}`\n await dlxManifest.setBinaryEntry(spec, cacheKey, {\n checksum,\n checksum_algorithm: 'sha256',\n platform: os.platform(),\n arch: os.arch(),\n size,\n source: {\n type: 'download',\n url,\n },\n })\n } catch {\n // Silently ignore manifest write errors - not critical.\n // The per-directory metadata is the source of truth for now.\n }\n}\n\n/**\n * Clean expired entries from the DLX cache.\n */\nexport async function cleanDlxCache(\n maxAge: number = /*@__INLINE__*/ require('#constants/time').DLX_BINARY_CACHE_TTL,\n): Promise<number> {\n const cacheDir = getDlxCachePath()\n const fs = getFs()\n\n if (!fs.existsSync(cacheDir)) {\n return 0\n }\n\n let cleaned = 0\n const now = Date.now()\n const entries = await fs.promises.readdir(cacheDir)\n\n for (const entry of entries) {\n const entryPath = path.join(cacheDir, entry)\n const metaPath = getMetadataPath(entryPath)\n\n try {\n // eslint-disable-next-line no-await-in-loop\n if (!(await isDir(entryPath))) {\n continue\n }\n\n // eslint-disable-next-line no-await-in-loop\n const metadata = await readJson(metaPath, { throws: false })\n if (\n !metadata ||\n typeof metadata !== 'object' ||\n Array.isArray(metadata)\n ) {\n continue\n }\n const timestamp = (metadata as Record<string, unknown>)['timestamp']\n // If timestamp is missing or invalid, treat as expired (age = infinity)\n const age =\n typeof timestamp === 'number' && timestamp > 0\n ? now - timestamp\n : Number.POSITIVE_INFINITY\n\n if (age > maxAge) {\n // Remove entire cache entry directory.\n // eslint-disable-next-line no-await-in-loop\n await safeDelete(entryPath, { force: true, recursive: true })\n cleaned += 1\n }\n } catch {\n // If we can't read metadata, check if directory is empty or corrupted.\n try {\n // eslint-disable-next-line no-await-in-loop\n const contents = await fs.promises.readdir(entryPath)\n if (!contents.length) {\n // Remove empty directory.\n // eslint-disable-next-line no-await-in-loop\n await safeDelete(entryPath)\n cleaned += 1\n }\n } catch {}\n }\n }\n\n return cleaned\n}\n\n/**\n * Download and execute a binary from a URL with caching.\n */\nexport async function dlxBinary(\n args: readonly string[] | string[],\n options?: DlxBinaryOptions | undefined,\n spawnExtra?: SpawnExtra | undefined,\n): Promise<DlxBinaryResult> {\n const {\n cacheTtl = /*@__INLINE__*/ require('#constants/time').DLX_BINARY_CACHE_TTL,\n checksum,\n force: userForce = false,\n name,\n spawnOptions,\n url,\n yes,\n } = { __proto__: null, ...options } as DlxBinaryOptions\n\n // Map --yes flag to force behavior (auto-approve/skip prompts)\n const force = yes === true ? true : userForce\n\n // Generate cache paths similar to pnpm/npx structure.\n const cacheDir = getDlxCachePath()\n const binaryName = name || `binary-${process.platform}-${os.arch()}`\n // Create spec from URL and binary name for unique cache identity.\n const spec = `${url}:${binaryName}`\n const cacheKey = generateCacheKey(spec)\n const cacheEntryDir = path.join(cacheDir, cacheKey)\n const binaryPath = normalizePath(path.join(cacheEntryDir, binaryName))\n const fs = getFs()\n\n let downloaded = false\n let computedChecksum = checksum\n\n // Check if we need to download.\n if (\n !force &&\n fs.existsSync(cacheEntryDir) &&\n (await isCacheValid(cacheEntryDir, cacheTtl))\n ) {\n // Binary is cached and valid, read the checksum from metadata.\n try {\n const metaPath = getMetadataPath(cacheEntryDir)\n const metadata = await readJson(metaPath, { throws: false })\n if (\n metadata &&\n typeof metadata === 'object' &&\n !Array.isArray(metadata) &&\n typeof (metadata as Record<string, unknown>)['checksum'] === 'string'\n ) {\n computedChecksum = (metadata as Record<string, unknown>)[\n 'checksum'\n ] as string\n } else {\n // If metadata is invalid, re-download.\n downloaded = true\n }\n } catch {\n // If we can't read metadata, re-download.\n downloaded = true\n }\n } else {\n downloaded = true\n }\n\n if (downloaded) {\n // Ensure cache directory exists before downloading.\n try {\n await safeMkdir(cacheEntryDir)\n } catch (e) {\n const code = (e as NodeJS.ErrnoException).code\n if (code === 'EACCES' || code === 'EPERM') {\n throw new Error(\n `Permission denied creating binary cache directory: ${cacheEntryDir}\\n` +\n 'Please check directory permissions or run with appropriate access.',\n { cause: e },\n )\n }\n if (code === 'EROFS') {\n throw new Error(\n `Cannot create binary cache directory on read-only filesystem: ${cacheEntryDir}\\n` +\n 'Ensure the filesystem is writable or set SOCKET_DLX_DIR to a writable location.',\n { cause: e },\n )\n }\n throw new Error(\n `Failed to create binary cache directory: ${cacheEntryDir}`,\n { cause: e },\n )\n }\n\n // Download the binary.\n computedChecksum = await downloadBinaryFile(url, binaryPath, checksum)\n\n // Get file size for metadata.\n const stats = await fs.promises.stat(binaryPath)\n await writeMetadata(\n cacheEntryDir,\n cacheKey,\n url,\n binaryName,\n computedChecksum || '',\n stats.size,\n )\n }\n\n // Execute the binary.\n // On Windows, script files (.bat, .cmd, .ps1) require shell: true because\n // they are not executable on their own and must be run through cmd.exe.\n // Note: .exe files are actual binaries and don't need shell mode.\n const needsShell = WIN32 && /\\.(?:bat|cmd|ps1)$/i.test(binaryPath)\n // Windows cmd.exe PATH resolution behavior:\n // When shell: true on Windows with .cmd/.bat/.ps1 files, spawn will automatically\n // strip the full path down to just the basename without extension (e.g.,\n // C:\\cache\\test.cmd becomes just \"test\"). Windows cmd.exe then searches for \"test\"\n // in directories listed in PATH, trying each extension from PATHEXT environment\n // variable (.COM, .EXE, .BAT, .CMD, etc.) until it finds a match.\n //\n // Since our binaries are downloaded to a custom cache directory that's not in PATH\n // (unlike system package managers like npm/pnpm/yarn which are already in PATH),\n // we must prepend the cache directory to PATH so cmd.exe can locate the binary.\n //\n // This approach is consistent with how other tools handle Windows command execution:\n // - npm's promise-spawn: uses which.sync() to find commands in PATH\n // - cross-spawn: spawns cmd.exe with escaped arguments\n // - Node.js spawn with shell: true: delegates to cmd.exe which uses PATH\n const finalSpawnOptions = needsShell\n ? {\n ...spawnOptions,\n env: {\n ...spawnOptions?.env,\n PATH: `${cacheEntryDir}${path.delimiter}${process.env['PATH'] || ''}`,\n },\n shell: true,\n }\n : spawnOptions\n const spawnPromise = spawn(binaryPath, args, finalSpawnOptions, spawnExtra)\n\n return {\n binaryPath,\n downloaded,\n spawnPromise,\n }\n}\n\n/**\n * Download a binary from a URL with caching (without execution).\n * Similar to downloadPackage from dlx-package.\n *\n * @returns Object containing the path to the cached binary and whether it was downloaded\n */\nexport async function downloadBinary(\n options: Omit<DlxBinaryOptions, 'spawnOptions'>,\n): Promise<{ binaryPath: string; downloaded: boolean }> {\n const {\n cacheTtl = /*@__INLINE__*/ require('#constants/time').DLX_BINARY_CACHE_TTL,\n checksum,\n force = false,\n name,\n url,\n } = { __proto__: null, ...options } as DlxBinaryOptions\n\n // Generate cache paths similar to pnpm/npx structure.\n const cacheDir = getDlxCachePath()\n const binaryName = name || `binary-${process.platform}-${os.arch()}`\n // Create spec from URL and binary name for unique cache identity.\n const spec = `${url}:${binaryName}`\n const cacheKey = generateCacheKey(spec)\n const cacheEntryDir = path.join(cacheDir, cacheKey)\n const binaryPath = normalizePath(path.join(cacheEntryDir, binaryName))\n const fs = getFs()\n\n let downloaded = false\n\n // Check if we need to download.\n if (\n !force &&\n fs.existsSync(cacheEntryDir) &&\n (await isCacheValid(cacheEntryDir, cacheTtl))\n ) {\n // Binary is cached and valid.\n downloaded = false\n } else {\n // Ensure cache directory exists before downloading.\n try {\n await safeMkdir(cacheEntryDir)\n } catch (e) {\n const code = (e as NodeJS.ErrnoException).code\n if (code === 'EACCES' || code === 'EPERM') {\n throw new Error(\n `Permission denied creating binary cache directory: ${cacheEntryDir}\\n` +\n 'Please check directory permissions or run with appropriate access.',\n { cause: e },\n )\n }\n if (code === 'EROFS') {\n throw new Error(\n `Cannot create binary cache directory on read-only filesystem: ${cacheEntryDir}\\n` +\n 'Ensure the filesystem is writable or set SOCKET_DLX_DIR to a writable location.',\n { cause: e },\n )\n }\n throw new Error(\n `Failed to create binary cache directory: ${cacheEntryDir}`,\n { cause: e },\n )\n }\n\n // Download the binary.\n const computedChecksum = await downloadBinaryFile(url, binaryPath, checksum)\n\n // Get file size for metadata.\n const stats = await fs.promises.stat(binaryPath)\n await writeMetadata(\n cacheEntryDir,\n cacheKey,\n url,\n binaryName,\n computedChecksum || '',\n stats.size,\n )\n downloaded = true\n }\n\n return {\n binaryPath,\n downloaded,\n }\n}\n\n/**\n * Execute a cached binary without re-downloading.\n * Similar to executePackage from dlx-package.\n * Binary must have been previously downloaded via downloadBinary or dlxBinary.\n *\n * @param binaryPath Path to the cached binary (from downloadBinary result)\n * @param args Arguments to pass to the binary\n * @param spawnOptions Spawn options for execution\n * @param spawnExtra Extra spawn configuration\n * @returns The spawn promise for the running process\n */\nexport function executeBinary(\n binaryPath: string,\n args: readonly string[] | string[],\n spawnOptions?: SpawnOptions | undefined,\n spawnExtra?: SpawnExtra | undefined,\n): ReturnType<typeof spawn> {\n // On Windows, script files (.bat, .cmd, .ps1) require shell: true because\n // they are not executable on their own and must be run through cmd.exe.\n // Note: .exe files are actual binaries and don't need shell mode.\n const needsShell = WIN32 && /\\.(?:bat|cmd|ps1)$/i.test(binaryPath)\n\n // Windows cmd.exe PATH resolution behavior:\n // When shell: true on Windows with .cmd/.bat/.ps1 files, spawn will automatically\n // strip the full path down to just the basename without extension. Windows cmd.exe\n // then searches for the binary in directories listed in PATH.\n //\n // Since our binaries are downloaded to a custom cache directory that's not in PATH,\n // we must prepend the cache directory to PATH so cmd.exe can locate the binary.\n const cacheEntryDir = path.dirname(binaryPath)\n const finalSpawnOptions = needsShell\n ? {\n ...spawnOptions,\n env: {\n ...spawnOptions?.env,\n PATH: `${cacheEntryDir}${path.delimiter}${process.env['PATH'] || ''}`,\n },\n shell: true,\n }\n : spawnOptions\n\n return spawn(binaryPath, args, finalSpawnOptions, spawnExtra)\n}\n\n/**\n * Get the DLX binary cache directory path.\n * Returns normalized path for cross-platform compatibility.\n * Uses same directory as dlx-package for unified DLX storage.\n */\nexport function getDlxCachePath(): string {\n return getSocketDlxDir()\n}\n\n/**\n * Get information about cached binaries.\n */\nexport async function listDlxCache(): Promise<\n Array<{\n age: number\n arch: string\n checksum: string\n name: string\n platform: string\n size: number\n url: string\n }>\n> {\n const cacheDir = getDlxCachePath()\n const fs = getFs()\n\n if (!fs.existsSync(cacheDir)) {\n return []\n }\n\n const results = []\n const now = Date.now()\n const entries = await fs.promises.readdir(cacheDir)\n\n for (const entry of entries) {\n const entryPath = path.join(cacheDir, entry)\n try {\n // eslint-disable-next-line no-await-in-loop\n if (!(await isDir(entryPath))) {\n continue\n }\n\n const metaPath = getMetadataPath(entryPath)\n // eslint-disable-next-line no-await-in-loop\n const metadata = await readJson(metaPath, { throws: false })\n if (\n !metadata ||\n typeof metadata !== 'object' ||\n Array.isArray(metadata)\n ) {\n continue\n }\n\n const metaObj = metadata as Record<string, unknown>\n\n // Get URL from unified schema (source.url) or legacy schema (url).\n // Allow empty URL for backward compatibility with partial metadata.\n const source = metaObj['source'] as Record<string, unknown> | undefined\n const url =\n (source?.['url'] as string) || (metaObj['url'] as string) || ''\n\n // Find the binary file in the directory.\n // eslint-disable-next-line no-await-in-loop\n const files = await fs.promises.readdir(entryPath)\n const binaryFile = files.find(f => !f.startsWith('.'))\n\n if (binaryFile) {\n const binaryPath = path.join(entryPath, binaryFile)\n // eslint-disable-next-line no-await-in-loop\n const binaryStats = await fs.promises.stat(binaryPath)\n\n results.push({\n age: now - ((metaObj['timestamp'] as number) || 0),\n arch: (metaObj['arch'] as string) || 'unknown',\n checksum: (metaObj['checksum'] as string) || '',\n name: binaryFile,\n platform: (metaObj['platform'] as string) || 'unknown',\n size: binaryStats.size,\n url,\n })\n }\n } catch {}\n }\n\n return results\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": ["import_path", "path", "fileBuffer", "hasher", "os"]
|
|
7
7
|
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Details for npm package entries.
|
|
3
|
+
*/
|
|
4
|
+
export interface PackageDetails {
|
|
5
|
+
installed_version: string;
|
|
6
|
+
size?: number;
|
|
7
|
+
update_check?: {
|
|
8
|
+
last_check: number;
|
|
9
|
+
last_notification: number;
|
|
10
|
+
latest_known: string;
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Details for binary download entries.
|
|
15
|
+
*/
|
|
16
|
+
export interface BinaryDetails {
|
|
17
|
+
checksum: string;
|
|
18
|
+
checksum_algorithm: 'sha256' | 'sha512';
|
|
19
|
+
platform: string;
|
|
20
|
+
arch: string;
|
|
21
|
+
size: number;
|
|
22
|
+
source: {
|
|
23
|
+
type: 'download';
|
|
24
|
+
url: string;
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Unified manifest entry for all cached items (packages and binaries).
|
|
29
|
+
* Shared fields at root, type-specific fields in details.
|
|
30
|
+
*/
|
|
31
|
+
export interface ManifestEntry {
|
|
32
|
+
type: 'package' | 'binary';
|
|
33
|
+
cache_key: string;
|
|
34
|
+
timestamp: number;
|
|
35
|
+
details: PackageDetails | BinaryDetails;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Type guard for package entries.
|
|
39
|
+
*/
|
|
40
|
+
export declare function isPackageEntry(entry: ManifestEntry): entry is ManifestEntry & {
|
|
41
|
+
details: PackageDetails;
|
|
42
|
+
};
|
|
43
|
+
/**
|
|
44
|
+
* Type guard for binary entries.
|
|
45
|
+
*/
|
|
46
|
+
export declare function isBinaryEntry(entry: ManifestEntry): entry is ManifestEntry & {
|
|
47
|
+
details: BinaryDetails;
|
|
48
|
+
};
|
|
49
|
+
/**
|
|
50
|
+
* Legacy store record format (deprecated, for migration).
|
|
51
|
+
*/
|
|
52
|
+
export interface StoreRecord {
|
|
53
|
+
timestampFetch: number;
|
|
54
|
+
timestampNotification: number;
|
|
55
|
+
version: string;
|
|
56
|
+
}
|
|
57
|
+
export interface DlxManifestOptions {
|
|
58
|
+
/**
|
|
59
|
+
* Custom manifest file path (defaults to ~/.socket/_dlx/.dlx-manifest.json).
|
|
60
|
+
*/
|
|
61
|
+
manifestPath?: string;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* DLX manifest storage manager with atomic operations.
|
|
65
|
+
* Supports both legacy format (package name keys) and new unified manifest format (spec keys).
|
|
66
|
+
*/
|
|
67
|
+
export declare class DlxManifest {
|
|
68
|
+
private readonly manifestPath;
|
|
69
|
+
private readonly lockPath;
|
|
70
|
+
constructor(options?: DlxManifestOptions);
|
|
71
|
+
/**
|
|
72
|
+
* Read the entire manifest file.
|
|
73
|
+
*/
|
|
74
|
+
private readManifest;
|
|
75
|
+
/**
|
|
76
|
+
* Get a manifest entry by spec (e.g., "@socketsecurity/cli@^2.0.11").
|
|
77
|
+
*/
|
|
78
|
+
getManifestEntry(spec: string): ManifestEntry | undefined;
|
|
79
|
+
/**
|
|
80
|
+
* Get cached update information for a package (legacy format).
|
|
81
|
+
* @deprecated Use getManifestEntry() for new code.
|
|
82
|
+
*/
|
|
83
|
+
get(name: string): StoreRecord | undefined;
|
|
84
|
+
/**
|
|
85
|
+
* Set a package manifest entry.
|
|
86
|
+
*/
|
|
87
|
+
setPackageEntry(spec: string, cacheKey: string, details: PackageDetails): Promise<void>;
|
|
88
|
+
/**
|
|
89
|
+
* Set a binary manifest entry.
|
|
90
|
+
*/
|
|
91
|
+
setBinaryEntry(spec: string, cacheKey: string, details: BinaryDetails): Promise<void>;
|
|
92
|
+
private writeManifest;
|
|
93
|
+
/**
|
|
94
|
+
* Store update information for a package (legacy format).
|
|
95
|
+
* @deprecated Use setPackageEntry() for new code.
|
|
96
|
+
*/
|
|
97
|
+
set(name: string, record: StoreRecord): Promise<void>;
|
|
98
|
+
/**
|
|
99
|
+
* Clear cached data for a specific entry.
|
|
100
|
+
*/
|
|
101
|
+
clear(name: string): Promise<void>;
|
|
102
|
+
/**
|
|
103
|
+
* Clear all cached data.
|
|
104
|
+
*/
|
|
105
|
+
clearAll(): Promise<void>;
|
|
106
|
+
/**
|
|
107
|
+
* Check if cached data is fresh based on TTL.
|
|
108
|
+
*/
|
|
109
|
+
isFresh(record: StoreRecord | undefined, ttlMs: number): boolean;
|
|
110
|
+
/**
|
|
111
|
+
* Get all cached package names.
|
|
112
|
+
*/
|
|
113
|
+
getAllPackages(): string[];
|
|
114
|
+
}
|
|
115
|
+
// Export singleton instance using default manifest location.
|
|
116
|
+
export declare const dlxManifest: DlxManifest;
|
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
/* Socket Lib - Built with esbuild */
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
var dlx_manifest_exports = {};
|
|
30
|
+
__export(dlx_manifest_exports, {
|
|
31
|
+
DlxManifest: () => DlxManifest,
|
|
32
|
+
dlxManifest: () => dlxManifest,
|
|
33
|
+
isBinaryEntry: () => isBinaryEntry,
|
|
34
|
+
isPackageEntry: () => isPackageEntry
|
|
35
|
+
});
|
|
36
|
+
module.exports = __toCommonJS(dlx_manifest_exports);
|
|
37
|
+
var import_fs = require("fs");
|
|
38
|
+
var import_path = __toESM(require("path"));
|
|
39
|
+
var import_fs2 = require("./fs");
|
|
40
|
+
var import_logger = require("./logger");
|
|
41
|
+
var import_paths = require("./paths");
|
|
42
|
+
var import_process_lock = require("./process-lock");
|
|
43
|
+
const MANIFEST_FILE_NAME = ".dlx-manifest.json";
|
|
44
|
+
function isPackageEntry(entry) {
|
|
45
|
+
return entry.type === "package";
|
|
46
|
+
}
|
|
47
|
+
function isBinaryEntry(entry) {
|
|
48
|
+
return entry.type === "binary";
|
|
49
|
+
}
|
|
50
|
+
class DlxManifest {
|
|
51
|
+
manifestPath;
|
|
52
|
+
lockPath;
|
|
53
|
+
constructor(options = {}) {
|
|
54
|
+
this.manifestPath = options.manifestPath ?? import_path.default.join((0, import_paths.getSocketDlxDir)(), MANIFEST_FILE_NAME);
|
|
55
|
+
this.lockPath = `${this.manifestPath}.lock`;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Read the entire manifest file.
|
|
59
|
+
*/
|
|
60
|
+
readManifest() {
|
|
61
|
+
try {
|
|
62
|
+
if (!(0, import_fs.existsSync)(this.manifestPath)) {
|
|
63
|
+
return /* @__PURE__ */ Object.create(null);
|
|
64
|
+
}
|
|
65
|
+
const rawContent = (0, import_fs2.readFileUtf8Sync)(this.manifestPath);
|
|
66
|
+
const content = (typeof rawContent === "string" ? rawContent : rawContent.toString("utf8")).trim();
|
|
67
|
+
if (!content) {
|
|
68
|
+
return /* @__PURE__ */ Object.create(null);
|
|
69
|
+
}
|
|
70
|
+
return JSON.parse(content);
|
|
71
|
+
} catch (error) {
|
|
72
|
+
(0, import_logger.getDefaultLogger)().warn(
|
|
73
|
+
`Failed to read manifest: ${error instanceof Error ? error.message : String(error)}`
|
|
74
|
+
);
|
|
75
|
+
return /* @__PURE__ */ Object.create(null);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Get a manifest entry by spec (e.g., "@socketsecurity/cli@^2.0.11").
|
|
80
|
+
*/
|
|
81
|
+
getManifestEntry(spec) {
|
|
82
|
+
const data = this.readManifest();
|
|
83
|
+
const entry = data[spec];
|
|
84
|
+
if (entry && "type" in entry) {
|
|
85
|
+
return entry;
|
|
86
|
+
}
|
|
87
|
+
return void 0;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Get cached update information for a package (legacy format).
|
|
91
|
+
* @deprecated Use getManifestEntry() for new code.
|
|
92
|
+
*/
|
|
93
|
+
get(name) {
|
|
94
|
+
const data = this.readManifest();
|
|
95
|
+
const entry = data[name];
|
|
96
|
+
if (entry && !("type" in entry)) {
|
|
97
|
+
return entry;
|
|
98
|
+
}
|
|
99
|
+
return void 0;
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Set a package manifest entry.
|
|
103
|
+
*/
|
|
104
|
+
async setPackageEntry(spec, cacheKey, details) {
|
|
105
|
+
await import_process_lock.processLock.withLock(this.lockPath, async () => {
|
|
106
|
+
const data = this.readManifest();
|
|
107
|
+
data[spec] = {
|
|
108
|
+
type: "package",
|
|
109
|
+
cache_key: cacheKey,
|
|
110
|
+
timestamp: Date.now(),
|
|
111
|
+
details
|
|
112
|
+
};
|
|
113
|
+
await this.writeManifest(data);
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Set a binary manifest entry.
|
|
118
|
+
*/
|
|
119
|
+
async setBinaryEntry(spec, cacheKey, details) {
|
|
120
|
+
await import_process_lock.processLock.withLock(this.lockPath, async () => {
|
|
121
|
+
const data = this.readManifest();
|
|
122
|
+
data[spec] = {
|
|
123
|
+
type: "binary",
|
|
124
|
+
cache_key: cacheKey,
|
|
125
|
+
timestamp: Date.now(),
|
|
126
|
+
details
|
|
127
|
+
};
|
|
128
|
+
await this.writeManifest(data);
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Write the manifest file atomically.
|
|
133
|
+
*/
|
|
134
|
+
async writeManifest(data) {
|
|
135
|
+
const manifestDir = import_path.default.dirname(this.manifestPath);
|
|
136
|
+
try {
|
|
137
|
+
(0, import_fs2.safeMkdirSync)(manifestDir, { recursive: true });
|
|
138
|
+
} catch (error) {
|
|
139
|
+
(0, import_logger.getDefaultLogger)().warn(
|
|
140
|
+
`Failed to create manifest directory: ${error instanceof Error ? error.message : String(error)}`
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
const content = JSON.stringify(data, null, 2);
|
|
144
|
+
const tempPath = `${this.manifestPath}.tmp`;
|
|
145
|
+
try {
|
|
146
|
+
(0, import_fs.writeFileSync)(tempPath, content, "utf8");
|
|
147
|
+
(0, import_fs.writeFileSync)(this.manifestPath, content, "utf8");
|
|
148
|
+
try {
|
|
149
|
+
if ((0, import_fs.existsSync)(tempPath)) {
|
|
150
|
+
(0, import_fs.unlinkSync)(tempPath);
|
|
151
|
+
}
|
|
152
|
+
} catch {
|
|
153
|
+
}
|
|
154
|
+
} catch (error) {
|
|
155
|
+
try {
|
|
156
|
+
if ((0, import_fs.existsSync)(tempPath)) {
|
|
157
|
+
(0, import_fs.unlinkSync)(tempPath);
|
|
158
|
+
}
|
|
159
|
+
} catch {
|
|
160
|
+
}
|
|
161
|
+
throw error;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Store update information for a package (legacy format).
|
|
166
|
+
* @deprecated Use setPackageEntry() for new code.
|
|
167
|
+
*/
|
|
168
|
+
async set(name, record) {
|
|
169
|
+
await import_process_lock.processLock.withLock(this.lockPath, async () => {
|
|
170
|
+
let data = /* @__PURE__ */ Object.create(null);
|
|
171
|
+
try {
|
|
172
|
+
if ((0, import_fs.existsSync)(this.manifestPath)) {
|
|
173
|
+
const content2 = (0, import_fs.readFileSync)(this.manifestPath, "utf8");
|
|
174
|
+
if (content2.trim()) {
|
|
175
|
+
data = JSON.parse(content2);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
} catch (error) {
|
|
179
|
+
(0, import_logger.getDefaultLogger)().warn(
|
|
180
|
+
`Failed to read existing manifest: ${error instanceof Error ? error.message : String(error)}`
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
data[name] = record;
|
|
184
|
+
const manifestDir = import_path.default.dirname(this.manifestPath);
|
|
185
|
+
try {
|
|
186
|
+
(0, import_fs2.safeMkdirSync)(manifestDir, { recursive: true });
|
|
187
|
+
} catch (error) {
|
|
188
|
+
(0, import_logger.getDefaultLogger)().warn(
|
|
189
|
+
`Failed to create manifest directory: ${error instanceof Error ? error.message : String(error)}`
|
|
190
|
+
);
|
|
191
|
+
}
|
|
192
|
+
const content = JSON.stringify(data, null, 2);
|
|
193
|
+
const tempPath = `${this.manifestPath}.tmp`;
|
|
194
|
+
try {
|
|
195
|
+
(0, import_fs.writeFileSync)(tempPath, content, "utf8");
|
|
196
|
+
(0, import_fs.writeFileSync)(this.manifestPath, content, "utf8");
|
|
197
|
+
try {
|
|
198
|
+
if ((0, import_fs.existsSync)(tempPath)) {
|
|
199
|
+
(0, import_fs.unlinkSync)(tempPath);
|
|
200
|
+
}
|
|
201
|
+
} catch {
|
|
202
|
+
}
|
|
203
|
+
} catch (error) {
|
|
204
|
+
try {
|
|
205
|
+
if ((0, import_fs.existsSync)(tempPath)) {
|
|
206
|
+
(0, import_fs.unlinkSync)(tempPath);
|
|
207
|
+
}
|
|
208
|
+
} catch {
|
|
209
|
+
}
|
|
210
|
+
throw error;
|
|
211
|
+
}
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Clear cached data for a specific entry.
|
|
216
|
+
*/
|
|
217
|
+
async clear(name) {
|
|
218
|
+
await import_process_lock.processLock.withLock(this.lockPath, async () => {
|
|
219
|
+
try {
|
|
220
|
+
if (!(0, import_fs.existsSync)(this.manifestPath)) {
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
const content = (0, import_fs.readFileSync)(this.manifestPath, "utf8");
|
|
224
|
+
if (!content.trim()) {
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
const data = JSON.parse(content);
|
|
228
|
+
delete data[name];
|
|
229
|
+
const updatedContent = JSON.stringify(data, null, 2);
|
|
230
|
+
(0, import_fs.writeFileSync)(this.manifestPath, updatedContent, "utf8");
|
|
231
|
+
} catch (error) {
|
|
232
|
+
(0, import_logger.getDefaultLogger)().warn(
|
|
233
|
+
`Failed to clear cache for ${name}: ${error instanceof Error ? error.message : String(error)}`
|
|
234
|
+
);
|
|
235
|
+
}
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Clear all cached data.
|
|
240
|
+
*/
|
|
241
|
+
async clearAll() {
|
|
242
|
+
await import_process_lock.processLock.withLock(this.lockPath, async () => {
|
|
243
|
+
try {
|
|
244
|
+
if ((0, import_fs.existsSync)(this.manifestPath)) {
|
|
245
|
+
(0, import_fs.unlinkSync)(this.manifestPath);
|
|
246
|
+
}
|
|
247
|
+
} catch (error) {
|
|
248
|
+
(0, import_logger.getDefaultLogger)().warn(
|
|
249
|
+
`Failed to clear all cache: ${error instanceof Error ? error.message : String(error)}`
|
|
250
|
+
);
|
|
251
|
+
}
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* Check if cached data is fresh based on TTL.
|
|
256
|
+
*/
|
|
257
|
+
isFresh(record, ttlMs) {
|
|
258
|
+
if (!record) {
|
|
259
|
+
return false;
|
|
260
|
+
}
|
|
261
|
+
const age = Date.now() - record.timestampFetch;
|
|
262
|
+
return age < ttlMs;
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* Get all cached package names.
|
|
266
|
+
*/
|
|
267
|
+
getAllPackages() {
|
|
268
|
+
try {
|
|
269
|
+
if (!(0, import_fs.existsSync)(this.manifestPath)) {
|
|
270
|
+
return [];
|
|
271
|
+
}
|
|
272
|
+
const rawContent = (0, import_fs2.readFileUtf8Sync)(this.manifestPath);
|
|
273
|
+
const content = (typeof rawContent === "string" ? rawContent : rawContent.toString("utf8")).trim();
|
|
274
|
+
if (!content) {
|
|
275
|
+
return [];
|
|
276
|
+
}
|
|
277
|
+
const data = JSON.parse(content);
|
|
278
|
+
return Object.keys(data);
|
|
279
|
+
} catch (error) {
|
|
280
|
+
(0, import_logger.getDefaultLogger)().warn(
|
|
281
|
+
`Failed to get package list: ${error instanceof Error ? error.message : String(error)}`
|
|
282
|
+
);
|
|
283
|
+
return [];
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
const dlxManifest = new DlxManifest();
|
|
288
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
289
|
+
0 && (module.exports = {
|
|
290
|
+
DlxManifest,
|
|
291
|
+
dlxManifest,
|
|
292
|
+
isBinaryEntry,
|
|
293
|
+
isPackageEntry
|
|
294
|
+
});
|
|
295
|
+
//# sourceMappingURL=dlx-manifest.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../src/dlx-manifest.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * @fileoverview DLX manifest storage utilities.\n * Manages persistent caching of DLX package and binary metadata with TTL support\n * and atomic file operations.\n *\n * Key Functions:\n * - getManifestEntry: Retrieve manifest entry by spec\n * - setPackageEntry: Store npm package metadata\n * - setBinaryEntry: Store binary download metadata\n *\n * Features:\n * - TTL-based cache expiration\n * - Atomic file operations with locking\n * - JSON-based persistent storage\n * - Error-resistant implementation\n *\n * Storage Format:\n * - Stores in ~/.socket/_dlx/.dlx-manifest.json\n * - Per-spec manifest entries with timestamps\n * - Thread-safe operations using process lock utility\n *\n * Usage:\n * - Update check caching\n * - Binary metadata tracking\n * - Rate limiting registry requests\n */\n\nimport { existsSync, readFileSync, unlinkSync, writeFileSync } from 'fs'\nimport path from 'path'\n\nimport { readFileUtf8Sync, safeMkdirSync } from './fs'\nimport { getDefaultLogger } from './logger'\nimport { getSocketDlxDir } from './paths'\nimport { processLock } from './process-lock'\n\n/**\n * Manifest file name.\n */\nconst MANIFEST_FILE_NAME = '.dlx-manifest.json'\n\n/**\n * Details for npm package entries.\n */\nexport interface PackageDetails {\n installed_version: string\n size?: number\n update_check?: {\n last_check: number\n last_notification: number\n latest_known: string\n }\n}\n\n/**\n * Details for binary download entries.\n */\nexport interface BinaryDetails {\n checksum: string\n checksum_algorithm: 'sha256' | 'sha512'\n platform: string\n arch: string\n size: number\n source: {\n type: 'download'\n url: string\n }\n}\n\n/**\n * Unified manifest entry for all cached items (packages and binaries).\n * Shared fields at root, type-specific fields in details.\n */\nexport interface ManifestEntry {\n type: 'package' | 'binary'\n cache_key: string\n timestamp: number\n details: PackageDetails | BinaryDetails\n}\n\n/**\n * Type guard for package entries.\n */\nexport function isPackageEntry(\n entry: ManifestEntry,\n): entry is ManifestEntry & { details: PackageDetails } {\n return entry.type === 'package'\n}\n\n/**\n * Type guard for binary entries.\n */\nexport function isBinaryEntry(\n entry: ManifestEntry,\n): entry is ManifestEntry & { details: BinaryDetails } {\n return entry.type === 'binary'\n}\n\n/**\n * Legacy store record format (deprecated, for migration).\n */\nexport interface StoreRecord {\n timestampFetch: number\n timestampNotification: number\n version: string\n}\n\nexport interface DlxManifestOptions {\n /**\n * Custom manifest file path (defaults to ~/.socket/_dlx/.dlx-manifest.json).\n */\n manifestPath?: string\n}\n\n/**\n * DLX manifest storage manager with atomic operations.\n * Supports both legacy format (package name keys) and new unified manifest format (spec keys).\n */\nexport class DlxManifest {\n private readonly manifestPath: string\n private readonly lockPath: string\n\n constructor(options: DlxManifestOptions = {}) {\n this.manifestPath =\n options.manifestPath ?? path.join(getSocketDlxDir(), MANIFEST_FILE_NAME)\n this.lockPath = `${this.manifestPath}.lock`\n }\n\n /**\n * Read the entire manifest file.\n */\n private readManifest(): Record<string, ManifestEntry | StoreRecord> {\n try {\n if (!existsSync(this.manifestPath)) {\n return Object.create(null)\n }\n\n const rawContent = readFileUtf8Sync(this.manifestPath)\n const content = (\n typeof rawContent === 'string'\n ? rawContent\n : rawContent.toString('utf8')\n ).trim()\n\n if (!content) {\n return Object.create(null)\n }\n\n return JSON.parse(content) as Record<string, ManifestEntry | StoreRecord>\n } catch (error) {\n getDefaultLogger().warn(\n `Failed to read manifest: ${error instanceof Error ? error.message : String(error)}`,\n )\n return Object.create(null)\n }\n }\n\n /**\n * Get a manifest entry by spec (e.g., \"@socketsecurity/cli@^2.0.11\").\n */\n getManifestEntry(spec: string): ManifestEntry | undefined {\n const data = this.readManifest()\n const entry = data[spec]\n\n // Check if it's a new-format entry (has 'type' field).\n if (entry && 'type' in entry) {\n return entry as ManifestEntry\n }\n\n return undefined\n }\n\n /**\n * Get cached update information for a package (legacy format).\n * @deprecated Use getManifestEntry() for new code.\n */\n get(name: string): StoreRecord | undefined {\n const data = this.readManifest()\n const entry = data[name]\n\n // Return legacy format entries only.\n if (entry && !('type' in entry)) {\n return entry as StoreRecord\n }\n\n return undefined\n }\n\n /**\n * Set a package manifest entry.\n */\n async setPackageEntry(\n spec: string,\n cacheKey: string,\n details: PackageDetails,\n ): Promise<void> {\n await processLock.withLock(this.lockPath, async () => {\n const data = this.readManifest()\n\n data[spec] = {\n type: 'package',\n cache_key: cacheKey,\n timestamp: Date.now(),\n details,\n }\n\n await this.writeManifest(data)\n })\n }\n\n /**\n * Set a binary manifest entry.\n */\n async setBinaryEntry(\n spec: string,\n cacheKey: string,\n details: BinaryDetails,\n ): Promise<void> {\n await processLock.withLock(this.lockPath, async () => {\n const data = this.readManifest()\n\n data[spec] = {\n type: 'binary',\n cache_key: cacheKey,\n timestamp: Date.now(),\n details,\n }\n\n await this.writeManifest(data)\n })\n }\n\n /**\n * Write the manifest file atomically.\n */\n private async writeManifest(\n data: Record<string, ManifestEntry | StoreRecord>,\n ): Promise<void> {\n // Ensure directory exists.\n const manifestDir = path.dirname(this.manifestPath)\n try {\n safeMkdirSync(manifestDir, { recursive: true })\n } catch (error) {\n getDefaultLogger().warn(\n `Failed to create manifest directory: ${error instanceof Error ? error.message : String(error)}`,\n )\n }\n\n // Write atomically.\n const content = JSON.stringify(data, null, 2)\n const tempPath = `${this.manifestPath}.tmp`\n\n try {\n writeFileSync(tempPath, content, 'utf8')\n writeFileSync(this.manifestPath, content, 'utf8')\n\n // Clean up temp file.\n try {\n if (existsSync(tempPath)) {\n unlinkSync(tempPath)\n }\n } catch {\n // Cleanup failed, not critical.\n }\n } catch (error) {\n // Clean up temp file on error.\n try {\n if (existsSync(tempPath)) {\n unlinkSync(tempPath)\n }\n } catch {\n // Best effort cleanup.\n }\n throw error\n }\n }\n\n /**\n * Store update information for a package (legacy format).\n * @deprecated Use setPackageEntry() for new code.\n */\n async set(name: string, record: StoreRecord): Promise<void> {\n await processLock.withLock(this.lockPath, async () => {\n let data: Record<string, StoreRecord> = Object.create(null)\n\n // Read existing data.\n try {\n if (existsSync(this.manifestPath)) {\n const content = readFileSync(this.manifestPath, 'utf8')\n if (content.trim()) {\n data = JSON.parse(content) as Record<string, StoreRecord>\n }\n }\n } catch (error) {\n getDefaultLogger().warn(\n `Failed to read existing manifest: ${error instanceof Error ? error.message : String(error)}`,\n )\n }\n\n // Update record.\n data[name] = record\n\n // Ensure directory exists.\n const manifestDir = path.dirname(this.manifestPath)\n try {\n safeMkdirSync(manifestDir, { recursive: true })\n } catch (error) {\n getDefaultLogger().warn(\n `Failed to create manifest directory: ${error instanceof Error ? error.message : String(error)}`,\n )\n }\n\n // Write atomically.\n const content = JSON.stringify(data, null, 2)\n const tempPath = `${this.manifestPath}.tmp`\n\n try {\n writeFileSync(tempPath, content, 'utf8')\n writeFileSync(this.manifestPath, content, 'utf8')\n\n // Clean up temp file.\n try {\n if (existsSync(tempPath)) {\n unlinkSync(tempPath)\n }\n } catch {\n // Cleanup failed, not critical.\n }\n } catch (error) {\n // Clean up temp file on error.\n try {\n if (existsSync(tempPath)) {\n unlinkSync(tempPath)\n }\n } catch {\n // Best effort cleanup.\n }\n throw error\n }\n })\n }\n\n /**\n * Clear cached data for a specific entry.\n */\n async clear(name: string): Promise<void> {\n await processLock.withLock(this.lockPath, async () => {\n try {\n if (!existsSync(this.manifestPath)) {\n return\n }\n\n const content = readFileSync(this.manifestPath, 'utf8')\n if (!content.trim()) {\n return\n }\n\n const data = JSON.parse(content) as Record<string, StoreRecord>\n delete data[name]\n\n const updatedContent = JSON.stringify(data, null, 2)\n writeFileSync(this.manifestPath, updatedContent, 'utf8')\n } catch (error) {\n getDefaultLogger().warn(\n `Failed to clear cache for ${name}: ${error instanceof Error ? error.message : String(error)}`,\n )\n }\n })\n }\n\n /**\n * Clear all cached data.\n */\n async clearAll(): Promise<void> {\n await processLock.withLock(this.lockPath, async () => {\n try {\n if (existsSync(this.manifestPath)) {\n unlinkSync(this.manifestPath)\n }\n } catch (error) {\n getDefaultLogger().warn(\n `Failed to clear all cache: ${error instanceof Error ? error.message : String(error)}`,\n )\n }\n })\n }\n\n /**\n * Check if cached data is fresh based on TTL.\n */\n isFresh(record: StoreRecord | undefined, ttlMs: number): boolean {\n if (!record) {\n return false\n }\n\n const age = Date.now() - record.timestampFetch\n return age < ttlMs\n }\n\n /**\n * Get all cached package names.\n */\n getAllPackages(): string[] {\n try {\n if (!existsSync(this.manifestPath)) {\n return []\n }\n\n const rawContent = readFileUtf8Sync(this.manifestPath)\n const content = (\n typeof rawContent === 'string'\n ? rawContent\n : rawContent.toString('utf8')\n ).trim()\n if (!content) {\n return []\n }\n\n const data = JSON.parse(content) as Record<string, StoreRecord>\n return Object.keys(data)\n } catch (error) {\n getDefaultLogger().warn(\n `Failed to get package list: ${error instanceof Error ? error.message : String(error)}`,\n )\n return []\n }\n }\n}\n\n// Export singleton instance using default manifest location.\nexport const dlxManifest = new DlxManifest()\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA2BA,gBAAoE;AACpE,kBAAiB;AAEjB,IAAAA,aAAgD;AAChD,oBAAiC;AACjC,mBAAgC;AAChC,0BAA4B;AAK5B,MAAM,qBAAqB;AA4CpB,SAAS,eACd,OACsD;AACtD,SAAO,MAAM,SAAS;AACxB;AAKO,SAAS,cACd,OACqD;AACrD,SAAO,MAAM,SAAS;AACxB;AAsBO,MAAM,YAAY;AAAA,EACN;AAAA,EACA;AAAA,EAEjB,YAAY,UAA8B,CAAC,GAAG;AAC5C,SAAK,eACH,QAAQ,gBAAgB,YAAAC,QAAK,SAAK,8BAAgB,GAAG,kBAAkB;AACzE,SAAK,WAAW,GAAG,KAAK,YAAY;AAAA,EACtC;AAAA;AAAA;AAAA;AAAA,EAKQ,eAA4D;AAClE,QAAI;AACF,UAAI,KAAC,sBAAW,KAAK,YAAY,GAAG;AAClC,eAAO,uBAAO,OAAO,IAAI;AAAA,MAC3B;AAEA,YAAM,iBAAa,6BAAiB,KAAK,YAAY;AACrD,YAAM,WACJ,OAAO,eAAe,WAClB,aACA,WAAW,SAAS,MAAM,GAC9B,KAAK;AAEP,UAAI,CAAC,SAAS;AACZ,eAAO,uBAAO,OAAO,IAAI;AAAA,MAC3B;AAEA,aAAO,KAAK,MAAM,OAAO;AAAA,IAC3B,SAAS,OAAO;AACd,0CAAiB,EAAE;AAAA,QACjB,4BAA4B,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AAAA,MACpF;AACA,aAAO,uBAAO,OAAO,IAAI;AAAA,IAC3B;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,iBAAiB,MAAyC;AACxD,UAAM,OAAO,KAAK,aAAa;AAC/B,UAAM,QAAQ,KAAK,IAAI;AAGvB,QAAI,SAAS,UAAU,OAAO;AAC5B,aAAO;AAAA,IACT;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,IAAI,MAAuC;AACzC,UAAM,OAAO,KAAK,aAAa;AAC/B,UAAM,QAAQ,KAAK,IAAI;AAGvB,QAAI,SAAS,EAAE,UAAU,QAAQ;AAC/B,aAAO;AAAA,IACT;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,gBACJ,MACA,UACA,SACe;AACf,UAAM,gCAAY,SAAS,KAAK,UAAU,YAAY;AACpD,YAAM,OAAO,KAAK,aAAa;AAE/B,WAAK,IAAI,IAAI;AAAA,QACX,MAAM;AAAA,QACN,WAAW;AAAA,QACX,WAAW,KAAK,IAAI;AAAA,QACpB;AAAA,MACF;AAEA,YAAM,KAAK,cAAc,IAAI;AAAA,IAC/B,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,eACJ,MACA,UACA,SACe;AACf,UAAM,gCAAY,SAAS,KAAK,UAAU,YAAY;AACpD,YAAM,OAAO,KAAK,aAAa;AAE/B,WAAK,IAAI,IAAI;AAAA,QACX,MAAM;AAAA,QACN,WAAW;AAAA,QACX,WAAW,KAAK,IAAI;AAAA,QACpB;AAAA,MACF;AAEA,YAAM,KAAK,cAAc,IAAI;AAAA,IAC/B,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,cACZ,MACe;AAEf,UAAM,cAAc,YAAAA,QAAK,QAAQ,KAAK,YAAY;AAClD,QAAI;AACF,oCAAc,aAAa,EAAE,WAAW,KAAK,CAAC;AAAA,IAChD,SAAS,OAAO;AACd,0CAAiB,EAAE;AAAA,QACjB,wCAAwC,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AAAA,MAChG;AAAA,IACF;AAGA,UAAM,UAAU,KAAK,UAAU,MAAM,MAAM,CAAC;AAC5C,UAAM,WAAW,GAAG,KAAK,YAAY;AAErC,QAAI;AACF,mCAAc,UAAU,SAAS,MAAM;AACvC,mCAAc,KAAK,cAAc,SAAS,MAAM;AAGhD,UAAI;AACF,gBAAI,sBAAW,QAAQ,GAAG;AACxB,oCAAW,QAAQ;AAAA,QACrB;AAAA,MACF,QAAQ;AAAA,MAER;AAAA,IACF,SAAS,OAAO;AAEd,UAAI;AACF,gBAAI,sBAAW,QAAQ,GAAG;AACxB,oCAAW,QAAQ;AAAA,QACrB;AAAA,MACF,QAAQ;AAAA,MAER;AACA,YAAM;AAAA,IACR;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,IAAI,MAAc,QAAoC;AAC1D,UAAM,gCAAY,SAAS,KAAK,UAAU,YAAY;AACpD,UAAI,OAAoC,uBAAO,OAAO,IAAI;AAG1D,UAAI;AACF,gBAAI,sBAAW,KAAK,YAAY,GAAG;AACjC,gBAAMC,eAAU,wBAAa,KAAK,cAAc,MAAM;AACtD,cAAIA,SAAQ,KAAK,GAAG;AAClB,mBAAO,KAAK,MAAMA,QAAO;AAAA,UAC3B;AAAA,QACF;AAAA,MACF,SAAS,OAAO;AACd,4CAAiB,EAAE;AAAA,UACjB,qCAAqC,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AAAA,QAC7F;AAAA,MACF;AAGA,WAAK,IAAI,IAAI;AAGb,YAAM,cAAc,YAAAD,QAAK,QAAQ,KAAK,YAAY;AAClD,UAAI;AACF,sCAAc,aAAa,EAAE,WAAW,KAAK,CAAC;AAAA,MAChD,SAAS,OAAO;AACd,4CAAiB,EAAE;AAAA,UACjB,wCAAwC,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AAAA,QAChG;AAAA,MACF;AAGA,YAAM,UAAU,KAAK,UAAU,MAAM,MAAM,CAAC;AAC5C,YAAM,WAAW,GAAG,KAAK,YAAY;AAErC,UAAI;AACF,qCAAc,UAAU,SAAS,MAAM;AACvC,qCAAc,KAAK,cAAc,SAAS,MAAM;AAGhD,YAAI;AACF,kBAAI,sBAAW,QAAQ,GAAG;AACxB,sCAAW,QAAQ;AAAA,UACrB;AAAA,QACF,QAAQ;AAAA,QAER;AAAA,MACF,SAAS,OAAO;AAEd,YAAI;AACF,kBAAI,sBAAW,QAAQ,GAAG;AACxB,sCAAW,QAAQ;AAAA,UACrB;AAAA,QACF,QAAQ;AAAA,QAER;AACA,cAAM;AAAA,MACR;AAAA,IACF,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,MAAM,MAA6B;AACvC,UAAM,gCAAY,SAAS,KAAK,UAAU,YAAY;AACpD,UAAI;AACF,YAAI,KAAC,sBAAW,KAAK,YAAY,GAAG;AAClC;AAAA,QACF;AAEA,cAAM,cAAU,wBAAa,KAAK,cAAc,MAAM;AACtD,YAAI,CAAC,QAAQ,KAAK,GAAG;AACnB;AAAA,QACF;AAEA,cAAM,OAAO,KAAK,MAAM,OAAO;AAC/B,eAAO,KAAK,IAAI;AAEhB,cAAM,iBAAiB,KAAK,UAAU,MAAM,MAAM,CAAC;AACnD,qCAAc,KAAK,cAAc,gBAAgB,MAAM;AAAA,MACzD,SAAS,OAAO;AACd,4CAAiB,EAAE;AAAA,UACjB,6BAA6B,IAAI,KAAK,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AAAA,QAC9F;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,WAA0B;AAC9B,UAAM,gCAAY,SAAS,KAAK,UAAU,YAAY;AACpD,UAAI;AACF,gBAAI,sBAAW,KAAK,YAAY,GAAG;AACjC,oCAAW,KAAK,YAAY;AAAA,QAC9B;AAAA,MACF,SAAS,OAAO;AACd,4CAAiB,EAAE;AAAA,UACjB,8BAA8B,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AAAA,QACtF;AAAA,MACF;AAAA,IACF,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA,EAKA,QAAQ,QAAiC,OAAwB;AAC/D,QAAI,CAAC,QAAQ;AACX,aAAO;AAAA,IACT;AAEA,UAAM,MAAM,KAAK,IAAI,IAAI,OAAO;AAChC,WAAO,MAAM;AAAA,EACf;AAAA;AAAA;AAAA;AAAA,EAKA,iBAA2B;AACzB,QAAI;AACF,UAAI,KAAC,sBAAW,KAAK,YAAY,GAAG;AAClC,eAAO,CAAC;AAAA,MACV;AAEA,YAAM,iBAAa,6BAAiB,KAAK,YAAY;AACrD,YAAM,WACJ,OAAO,eAAe,WAClB,aACA,WAAW,SAAS,MAAM,GAC9B,KAAK;AACP,UAAI,CAAC,SAAS;AACZ,eAAO,CAAC;AAAA,MACV;AAEA,YAAM,OAAO,KAAK,MAAM,OAAO;AAC/B,aAAO,OAAO,KAAK,IAAI;AAAA,IACzB,SAAS,OAAO;AACd,0CAAiB,EAAE;AAAA,QACjB,+BAA+B,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK,CAAC;AAAA,MACvF;AACA,aAAO,CAAC;AAAA,IACV;AAAA,EACF;AACF;AAGO,MAAM,cAAc,IAAI,YAAY;",
|
|
6
|
+
"names": ["import_fs", "path", "content"]
|
|
7
|
+
}
|
package/dist/env/socket-cli.d.ts
CHANGED
|
@@ -77,3 +77,17 @@ export declare function getSocketCliViewAllRisks(): boolean;
|
|
|
77
77
|
* @returns GitHub token or undefined
|
|
78
78
|
*/
|
|
79
79
|
export declare function getSocketCliGithubToken(): string | undefined;
|
|
80
|
+
/**
|
|
81
|
+
* Bootstrap package spec (e.g., @socketsecurity/cli@^2.0.11).
|
|
82
|
+
* Set by bootstrap wrappers (SEA/smol/npm) to pass package spec to CLI.
|
|
83
|
+
*
|
|
84
|
+
* @returns Bootstrap package spec or undefined
|
|
85
|
+
*/
|
|
86
|
+
export declare function getSocketCliBootstrapSpec(): string | undefined;
|
|
87
|
+
/**
|
|
88
|
+
* Bootstrap cache directory path.
|
|
89
|
+
* Set by bootstrap wrappers to pass dlx cache location to CLI.
|
|
90
|
+
*
|
|
91
|
+
* @returns Bootstrap cache directory or undefined
|
|
92
|
+
*/
|
|
93
|
+
export declare function getSocketCliBootstrapCacheDir(): string | undefined;
|
package/dist/env/socket-cli.js
CHANGED
|
@@ -23,6 +23,8 @@ __export(socket_cli_exports, {
|
|
|
23
23
|
getSocketCliApiProxy: () => getSocketCliApiProxy,
|
|
24
24
|
getSocketCliApiTimeout: () => getSocketCliApiTimeout,
|
|
25
25
|
getSocketCliApiToken: () => getSocketCliApiToken,
|
|
26
|
+
getSocketCliBootstrapCacheDir: () => getSocketCliBootstrapCacheDir,
|
|
27
|
+
getSocketCliBootstrapSpec: () => getSocketCliBootstrapSpec,
|
|
26
28
|
getSocketCliConfig: () => getSocketCliConfig,
|
|
27
29
|
getSocketCliFix: () => getSocketCliFix,
|
|
28
30
|
getSocketCliGithubToken: () => getSocketCliGithubToken,
|
|
@@ -70,6 +72,12 @@ function getSocketCliViewAllRisks() {
|
|
|
70
72
|
function getSocketCliGithubToken() {
|
|
71
73
|
return (0, import_rewire.getEnvValue)("SOCKET_CLI_GITHUB_TOKEN") || (0, import_rewire.getEnvValue)("SOCKET_SECURITY_GITHUB_PAT") || (0, import_rewire.getEnvValue)("GITHUB_TOKEN");
|
|
72
74
|
}
|
|
75
|
+
function getSocketCliBootstrapSpec() {
|
|
76
|
+
return (0, import_rewire.getEnvValue)("SOCKET_CLI_BOOTSTRAP_SPEC");
|
|
77
|
+
}
|
|
78
|
+
function getSocketCliBootstrapCacheDir() {
|
|
79
|
+
return (0, import_rewire.getEnvValue)("SOCKET_CLI_BOOTSTRAP_CACHE_DIR");
|
|
80
|
+
}
|
|
73
81
|
// Annotate the CommonJS export names for ESM import in node:
|
|
74
82
|
0 && (module.exports = {
|
|
75
83
|
getSocketCliAcceptRisks,
|
|
@@ -77,6 +85,8 @@ function getSocketCliGithubToken() {
|
|
|
77
85
|
getSocketCliApiProxy,
|
|
78
86
|
getSocketCliApiTimeout,
|
|
79
87
|
getSocketCliApiToken,
|
|
88
|
+
getSocketCliBootstrapCacheDir,
|
|
89
|
+
getSocketCliBootstrapSpec,
|
|
80
90
|
getSocketCliConfig,
|
|
81
91
|
getSocketCliFix,
|
|
82
92
|
getSocketCliGithubToken,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/env/socket-cli.ts"],
|
|
4
|
-
"sourcesContent": ["/**\n * @fileoverview Socket CLI environment variables.\n * Provides typed getters for SOCKET_CLI_* environment variables (excluding shadow).\n */\n\nimport { envAsBoolean, envAsNumber } from '#env/helpers'\nimport { getEnvValue } from '#env/rewire'\n\n/**\n * Whether to accept all Socket CLI risks (alternative name).\n *\n * @returns Whether to accept all risks\n */\nexport function getSocketCliAcceptRisks(): boolean {\n return envAsBoolean(getEnvValue('SOCKET_CLI_ACCEPT_RISKS'))\n}\n\n/**\n * Socket CLI API base URL (alternative name).\n * Checks SOCKET_CLI_API_BASE_URL first, then falls back to legacy SOCKET_SECURITY_API_BASE_URL.\n *\n * @returns API base URL or undefined\n */\nexport function getSocketCliApiBaseUrl(): string | undefined {\n return (\n getEnvValue('SOCKET_CLI_API_BASE_URL') ||\n getEnvValue('SOCKET_SECURITY_API_BASE_URL')\n )\n}\n\n/**\n * Proxy URL for Socket CLI API requests (alternative name).\n * Checks SOCKET_CLI_API_PROXY, SOCKET_SECURITY_API_PROXY, then standard proxy env vars.\n * Follows the same precedence as v1.x: HTTPS_PROXY \u2192 https_proxy \u2192 HTTP_PROXY \u2192 http_proxy.\n *\n * @returns API proxy URL or undefined\n */\nexport function getSocketCliApiProxy(): string | undefined {\n return (\n getEnvValue('SOCKET_CLI_API_PROXY') ||\n getEnvValue('SOCKET_SECURITY_API_PROXY') ||\n getEnvValue('HTTPS_PROXY') ||\n getEnvValue('https_proxy') ||\n getEnvValue('HTTP_PROXY') ||\n getEnvValue('http_proxy')\n )\n}\n\n/**\n * Timeout in milliseconds for Socket CLI API requests (alternative name).\n *\n * @returns API timeout in milliseconds\n */\nexport function getSocketCliApiTimeout(): number {\n return envAsNumber(getEnvValue('SOCKET_CLI_API_TIMEOUT'))\n}\n\n/**\n * Socket CLI API authentication token (alternative name).\n * Checks SOCKET_CLI_API_TOKEN, SOCKET_CLI_API_KEY, SOCKET_SECURITY_API_TOKEN, SOCKET_SECURITY_API_KEY.\n * Maintains full v1.x backward compatibility.\n *\n * @returns API token or undefined\n */\nexport function getSocketCliApiToken(): string | undefined {\n return (\n getEnvValue('SOCKET_CLI_API_TOKEN') ||\n getEnvValue('SOCKET_CLI_API_KEY') ||\n getEnvValue('SOCKET_SECURITY_API_TOKEN') ||\n getEnvValue('SOCKET_SECURITY_API_KEY')\n )\n}\n\n/**\n * Socket CLI configuration file path (alternative name).\n *\n * @returns Config file path or undefined\n */\nexport function getSocketCliConfig(): string | undefined {\n return getEnvValue('SOCKET_CLI_CONFIG')\n}\n\n/**\n * Controls Socket CLI fix mode.\n *\n * @returns Fix mode value or undefined\n */\nexport function getSocketCliFix(): string | undefined {\n return getEnvValue('SOCKET_CLI_FIX')\n}\n\n/**\n * Whether to skip Socket CLI API token requirement (alternative name).\n *\n * @returns Whether to skip API token requirement\n */\nexport function getSocketCliNoApiToken(): boolean {\n return envAsBoolean(getEnvValue('SOCKET_CLI_NO_API_TOKEN'))\n}\n\n/**\n * Controls Socket CLI optimization mode.\n *\n * @returns Whether optimization mode is enabled\n */\nexport function getSocketCliOptimize(): boolean {\n return envAsBoolean(getEnvValue('SOCKET_CLI_OPTIMIZE'))\n}\n\n/**\n * Socket CLI organization slug identifier (alternative name).\n * Checks SOCKET_CLI_ORG_SLUG first, then falls back to SOCKET_ORG_SLUG.\n *\n * @returns Organization slug or undefined\n */\nexport function getSocketCliOrgSlug(): string | undefined {\n return getEnvValue('SOCKET_CLI_ORG_SLUG') || getEnvValue('SOCKET_ORG_SLUG')\n}\n\n/**\n * Whether to view all Socket CLI risks (alternative name).\n *\n * @returns Whether to view all risks\n */\nexport function getSocketCliViewAllRisks(): boolean {\n return envAsBoolean(getEnvValue('SOCKET_CLI_VIEW_ALL_RISKS'))\n}\n\n/**\n * Socket CLI GitHub authentication token.\n * Checks SOCKET_CLI_GITHUB_TOKEN, SOCKET_SECURITY_GITHUB_PAT, then falls back to GITHUB_TOKEN.\n *\n * @returns GitHub token or undefined\n */\nexport function getSocketCliGithubToken(): string | undefined {\n return (\n getEnvValue('SOCKET_CLI_GITHUB_TOKEN') ||\n getEnvValue('SOCKET_SECURITY_GITHUB_PAT') ||\n getEnvValue('GITHUB_TOKEN')\n )\n}\n"],
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAKA,qBAA0C;AAC1C,oBAA4B;AAOrB,SAAS,0BAAmC;AACjD,aAAO,iCAAa,2BAAY,yBAAyB,CAAC;AAC5D;AAQO,SAAS,yBAA6C;AAC3D,aACE,2BAAY,yBAAyB,SACrC,2BAAY,8BAA8B;AAE9C;AASO,SAAS,uBAA2C;AACzD,aACE,2BAAY,sBAAsB,SAClC,2BAAY,2BAA2B,SACvC,2BAAY,aAAa,SACzB,2BAAY,aAAa,SACzB,2BAAY,YAAY,SACxB,2BAAY,YAAY;AAE5B;AAOO,SAAS,yBAAiC;AAC/C,aAAO,gCAAY,2BAAY,wBAAwB,CAAC;AAC1D;AASO,SAAS,uBAA2C;AACzD,aACE,2BAAY,sBAAsB,SAClC,2BAAY,oBAAoB,SAChC,2BAAY,2BAA2B,SACvC,2BAAY,yBAAyB;AAEzC;AAOO,SAAS,qBAAyC;AACvD,aAAO,2BAAY,mBAAmB;AACxC;AAOO,SAAS,kBAAsC;AACpD,aAAO,2BAAY,gBAAgB;AACrC;AAOO,SAAS,yBAAkC;AAChD,aAAO,iCAAa,2BAAY,yBAAyB,CAAC;AAC5D;AAOO,SAAS,uBAAgC;AAC9C,aAAO,iCAAa,2BAAY,qBAAqB,CAAC;AACxD;AAQO,SAAS,sBAA0C;AACxD,aAAO,2BAAY,qBAAqB,SAAK,2BAAY,iBAAiB;AAC5E;AAOO,SAAS,2BAAoC;AAClD,aAAO,iCAAa,2BAAY,2BAA2B,CAAC;AAC9D;AAQO,SAAS,0BAA8C;AAC5D,aACE,2BAAY,yBAAyB,SACrC,2BAAY,4BAA4B,SACxC,2BAAY,cAAc;AAE9B;",
|
|
4
|
+
"sourcesContent": ["/**\n * @fileoverview Socket CLI environment variables.\n * Provides typed getters for SOCKET_CLI_* environment variables (excluding shadow).\n */\n\nimport { envAsBoolean, envAsNumber } from '#env/helpers'\nimport { getEnvValue } from '#env/rewire'\n\n/**\n * Whether to accept all Socket CLI risks (alternative name).\n *\n * @returns Whether to accept all risks\n */\nexport function getSocketCliAcceptRisks(): boolean {\n return envAsBoolean(getEnvValue('SOCKET_CLI_ACCEPT_RISKS'))\n}\n\n/**\n * Socket CLI API base URL (alternative name).\n * Checks SOCKET_CLI_API_BASE_URL first, then falls back to legacy SOCKET_SECURITY_API_BASE_URL.\n *\n * @returns API base URL or undefined\n */\nexport function getSocketCliApiBaseUrl(): string | undefined {\n return (\n getEnvValue('SOCKET_CLI_API_BASE_URL') ||\n getEnvValue('SOCKET_SECURITY_API_BASE_URL')\n )\n}\n\n/**\n * Proxy URL for Socket CLI API requests (alternative name).\n * Checks SOCKET_CLI_API_PROXY, SOCKET_SECURITY_API_PROXY, then standard proxy env vars.\n * Follows the same precedence as v1.x: HTTPS_PROXY \u2192 https_proxy \u2192 HTTP_PROXY \u2192 http_proxy.\n *\n * @returns API proxy URL or undefined\n */\nexport function getSocketCliApiProxy(): string | undefined {\n return (\n getEnvValue('SOCKET_CLI_API_PROXY') ||\n getEnvValue('SOCKET_SECURITY_API_PROXY') ||\n getEnvValue('HTTPS_PROXY') ||\n getEnvValue('https_proxy') ||\n getEnvValue('HTTP_PROXY') ||\n getEnvValue('http_proxy')\n )\n}\n\n/**\n * Timeout in milliseconds for Socket CLI API requests (alternative name).\n *\n * @returns API timeout in milliseconds\n */\nexport function getSocketCliApiTimeout(): number {\n return envAsNumber(getEnvValue('SOCKET_CLI_API_TIMEOUT'))\n}\n\n/**\n * Socket CLI API authentication token (alternative name).\n * Checks SOCKET_CLI_API_TOKEN, SOCKET_CLI_API_KEY, SOCKET_SECURITY_API_TOKEN, SOCKET_SECURITY_API_KEY.\n * Maintains full v1.x backward compatibility.\n *\n * @returns API token or undefined\n */\nexport function getSocketCliApiToken(): string | undefined {\n return (\n getEnvValue('SOCKET_CLI_API_TOKEN') ||\n getEnvValue('SOCKET_CLI_API_KEY') ||\n getEnvValue('SOCKET_SECURITY_API_TOKEN') ||\n getEnvValue('SOCKET_SECURITY_API_KEY')\n )\n}\n\n/**\n * Socket CLI configuration file path (alternative name).\n *\n * @returns Config file path or undefined\n */\nexport function getSocketCliConfig(): string | undefined {\n return getEnvValue('SOCKET_CLI_CONFIG')\n}\n\n/**\n * Controls Socket CLI fix mode.\n *\n * @returns Fix mode value or undefined\n */\nexport function getSocketCliFix(): string | undefined {\n return getEnvValue('SOCKET_CLI_FIX')\n}\n\n/**\n * Whether to skip Socket CLI API token requirement (alternative name).\n *\n * @returns Whether to skip API token requirement\n */\nexport function getSocketCliNoApiToken(): boolean {\n return envAsBoolean(getEnvValue('SOCKET_CLI_NO_API_TOKEN'))\n}\n\n/**\n * Controls Socket CLI optimization mode.\n *\n * @returns Whether optimization mode is enabled\n */\nexport function getSocketCliOptimize(): boolean {\n return envAsBoolean(getEnvValue('SOCKET_CLI_OPTIMIZE'))\n}\n\n/**\n * Socket CLI organization slug identifier (alternative name).\n * Checks SOCKET_CLI_ORG_SLUG first, then falls back to SOCKET_ORG_SLUG.\n *\n * @returns Organization slug or undefined\n */\nexport function getSocketCliOrgSlug(): string | undefined {\n return getEnvValue('SOCKET_CLI_ORG_SLUG') || getEnvValue('SOCKET_ORG_SLUG')\n}\n\n/**\n * Whether to view all Socket CLI risks (alternative name).\n *\n * @returns Whether to view all risks\n */\nexport function getSocketCliViewAllRisks(): boolean {\n return envAsBoolean(getEnvValue('SOCKET_CLI_VIEW_ALL_RISKS'))\n}\n\n/**\n * Socket CLI GitHub authentication token.\n * Checks SOCKET_CLI_GITHUB_TOKEN, SOCKET_SECURITY_GITHUB_PAT, then falls back to GITHUB_TOKEN.\n *\n * @returns GitHub token or undefined\n */\nexport function getSocketCliGithubToken(): string | undefined {\n return (\n getEnvValue('SOCKET_CLI_GITHUB_TOKEN') ||\n getEnvValue('SOCKET_SECURITY_GITHUB_PAT') ||\n getEnvValue('GITHUB_TOKEN')\n )\n}\n\n/**\n * Bootstrap package spec (e.g., @socketsecurity/cli@^2.0.11).\n * Set by bootstrap wrappers (SEA/smol/npm) to pass package spec to CLI.\n *\n * @returns Bootstrap package spec or undefined\n */\nexport function getSocketCliBootstrapSpec(): string | undefined {\n return getEnvValue('SOCKET_CLI_BOOTSTRAP_SPEC')\n}\n\n/**\n * Bootstrap cache directory path.\n * Set by bootstrap wrappers to pass dlx cache location to CLI.\n *\n * @returns Bootstrap cache directory or undefined\n */\nexport function getSocketCliBootstrapCacheDir(): string | undefined {\n return getEnvValue('SOCKET_CLI_BOOTSTRAP_CACHE_DIR')\n}\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAKA,qBAA0C;AAC1C,oBAA4B;AAOrB,SAAS,0BAAmC;AACjD,aAAO,iCAAa,2BAAY,yBAAyB,CAAC;AAC5D;AAQO,SAAS,yBAA6C;AAC3D,aACE,2BAAY,yBAAyB,SACrC,2BAAY,8BAA8B;AAE9C;AASO,SAAS,uBAA2C;AACzD,aACE,2BAAY,sBAAsB,SAClC,2BAAY,2BAA2B,SACvC,2BAAY,aAAa,SACzB,2BAAY,aAAa,SACzB,2BAAY,YAAY,SACxB,2BAAY,YAAY;AAE5B;AAOO,SAAS,yBAAiC;AAC/C,aAAO,gCAAY,2BAAY,wBAAwB,CAAC;AAC1D;AASO,SAAS,uBAA2C;AACzD,aACE,2BAAY,sBAAsB,SAClC,2BAAY,oBAAoB,SAChC,2BAAY,2BAA2B,SACvC,2BAAY,yBAAyB;AAEzC;AAOO,SAAS,qBAAyC;AACvD,aAAO,2BAAY,mBAAmB;AACxC;AAOO,SAAS,kBAAsC;AACpD,aAAO,2BAAY,gBAAgB;AACrC;AAOO,SAAS,yBAAkC;AAChD,aAAO,iCAAa,2BAAY,yBAAyB,CAAC;AAC5D;AAOO,SAAS,uBAAgC;AAC9C,aAAO,iCAAa,2BAAY,qBAAqB,CAAC;AACxD;AAQO,SAAS,sBAA0C;AACxD,aAAO,2BAAY,qBAAqB,SAAK,2BAAY,iBAAiB;AAC5E;AAOO,SAAS,2BAAoC;AAClD,aAAO,iCAAa,2BAAY,2BAA2B,CAAC;AAC9D;AAQO,SAAS,0BAA8C;AAC5D,aACE,2BAAY,yBAAyB,SACrC,2BAAY,4BAA4B,SACxC,2BAAY,cAAc;AAE9B;AAQO,SAAS,4BAAgD;AAC9D,aAAO,2BAAY,2BAA2B;AAChD;AAQO,SAAS,gCAAoD;AAClE,aAAO,2BAAY,gCAAgC;AACrD;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@socketsecurity/lib",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.2.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "Core utilities and infrastructure for Socket.dev security tools",
|
|
6
6
|
"keywords": [
|
|
@@ -140,6 +140,10 @@
|
|
|
140
140
|
"types": "./dist/dlx-binary.d.ts",
|
|
141
141
|
"default": "./dist/dlx-binary.js"
|
|
142
142
|
},
|
|
143
|
+
"./dlx-manifest": {
|
|
144
|
+
"types": "./dist/dlx-manifest.d.ts",
|
|
145
|
+
"default": "./dist/dlx-manifest.js"
|
|
146
|
+
},
|
|
143
147
|
"./dlx-package": {
|
|
144
148
|
"types": "./dist/dlx-package.d.ts",
|
|
145
149
|
"default": "./dist/dlx-package.js"
|