@socketsecurity/lib 2.10.3 → 3.0.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.
Files changed (76) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/README.md +231 -40
  3. package/dist/constants/platform.js +1 -1
  4. package/dist/constants/platform.js.map +3 -3
  5. package/dist/cover/code.js +1 -1
  6. package/dist/cover/code.js.map +3 -3
  7. package/dist/debug.js +2 -2
  8. package/dist/debug.js.map +3 -3
  9. package/dist/dlx-binary.d.ts +29 -6
  10. package/dist/dlx-binary.js +7 -7
  11. package/dist/dlx-binary.js.map +3 -3
  12. package/dist/dlx-package.d.ts +16 -1
  13. package/dist/dlx-package.js +7 -7
  14. package/dist/dlx-package.js.map +3 -3
  15. package/dist/dlx.js +4 -4
  16. package/dist/dlx.js.map +3 -3
  17. package/dist/env/rewire.js +1 -1
  18. package/dist/env/rewire.js.map +3 -3
  19. package/dist/env/socket-cli.d.ts +7 -0
  20. package/dist/env/socket-cli.js +1 -1
  21. package/dist/env/socket-cli.js.map +2 -2
  22. package/dist/external/yoctocolors-cjs.d.ts +14 -0
  23. package/dist/fs.d.ts +82 -27
  24. package/dist/fs.js +7 -7
  25. package/dist/fs.js.map +3 -3
  26. package/dist/git.js +1 -1
  27. package/dist/git.js.map +3 -3
  28. package/dist/http-request.js +1 -1
  29. package/dist/http-request.js.map +3 -3
  30. package/dist/ipc.js +1 -1
  31. package/dist/ipc.js.map +3 -3
  32. package/dist/links/index.d.ts +65 -0
  33. package/dist/links/index.js +3 -0
  34. package/dist/links/index.js.map +7 -0
  35. package/dist/logger.d.ts +21 -18
  36. package/dist/logger.js +1 -1
  37. package/dist/logger.js.map +3 -3
  38. package/dist/packages/isolation.js +1 -1
  39. package/dist/packages/isolation.js.map +3 -3
  40. package/dist/paths.js +1 -1
  41. package/dist/paths.js.map +2 -2
  42. package/dist/process-lock.js +2 -2
  43. package/dist/process-lock.js.map +3 -3
  44. package/dist/promises.d.ts +6 -21
  45. package/dist/promises.js +1 -1
  46. package/dist/promises.js.map +2 -2
  47. package/dist/prompts/index.d.ts +115 -0
  48. package/dist/prompts/index.js +3 -0
  49. package/dist/prompts/index.js.map +7 -0
  50. package/dist/spinner.d.ts +33 -23
  51. package/dist/spinner.js +1 -1
  52. package/dist/spinner.js.map +3 -3
  53. package/dist/stdio/mask.d.ts +2 -2
  54. package/dist/stdio/mask.js +4 -4
  55. package/dist/stdio/mask.js.map +3 -3
  56. package/dist/stdio/stdout.js +1 -1
  57. package/dist/stdio/stdout.js.map +3 -3
  58. package/dist/themes/context.d.ts +80 -0
  59. package/dist/themes/context.js +3 -0
  60. package/dist/themes/context.js.map +7 -0
  61. package/dist/themes/index.d.ts +53 -0
  62. package/dist/themes/index.js +3 -0
  63. package/dist/themes/index.js.map +7 -0
  64. package/dist/themes/themes.d.ts +49 -0
  65. package/dist/themes/themes.js +3 -0
  66. package/dist/themes/themes.js.map +7 -0
  67. package/dist/themes/types.d.ts +92 -0
  68. package/dist/themes/types.js +3 -0
  69. package/dist/themes/types.js.map +7 -0
  70. package/dist/themes/utils.d.ts +78 -0
  71. package/dist/themes/utils.js +3 -0
  72. package/dist/themes/utils.js.map +7 -0
  73. package/package.json +40 -8
  74. package/dist/download-lock.d.ts +0 -49
  75. package/dist/download-lock.js +0 -10
  76. package/dist/download-lock.js.map +0 -7
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/http-request.ts"],
4
- "sourcesContent": ["/**\n * @fileoverview HTTP/HTTPS request utilities using Node.js built-in modules with retry logic, redirects, and download support.\n *\n * This module provides a fetch-like API built on top of Node.js native `http` and `https` modules.\n * It supports automatic retries with exponential backoff, redirect following, streaming downloads,\n * and provides a familiar fetch-style response interface.\n *\n * Key Features:\n * - Automatic retries with exponential backoff for failed requests.\n * - Redirect following with configurable max redirects.\n * - Streaming downloads with progress callbacks.\n * - Fetch-like response interface (`.json()`, `.text()`, `.arrayBuffer()`).\n * - Timeout support for all operations.\n * - Zero dependencies on external HTTP libraries.\n */\n\nimport { createWriteStream } from 'node:fs'\n\nimport type { IncomingMessage } from 'node:http'\n\nlet _http: typeof import('http') | undefined\nlet _https: typeof import('https') | undefined\n/**\n * Lazily load http and https modules to avoid Webpack errors.\n * @private\n */\n/*@__NO_SIDE_EFFECTS__*/\nfunction getHttp() {\n if (_http === undefined) {\n // Use non-'node:' prefixed require to avoid Webpack errors.\n\n _http = /*@__PURE__*/ require('node:http')\n }\n return _http as typeof import('http')\n}\n\n/*@__NO_SIDE_EFFECTS__*/\nfunction getHttps() {\n if (_https === undefined) {\n // Use non-'node:' prefixed require to avoid Webpack errors.\n\n _https = /*@__PURE__*/ require('node:https')\n }\n return _https as typeof import('https')\n}\n\n/**\n * Configuration options for HTTP/HTTPS requests.\n */\nexport interface HttpRequestOptions {\n /**\n * Request body to send.\n * Can be a string (e.g., JSON) or Buffer (e.g., binary data).\n *\n * @example\n * ```ts\n * // Send JSON data\n * await httpRequest('https://api.example.com/data', {\n * method: 'POST',\n * body: JSON.stringify({ name: 'Alice' }),\n * headers: { 'Content-Type': 'application/json' }\n * })\n *\n * // Send binary data\n * const buffer = Buffer.from([0x00, 0x01, 0x02])\n * await httpRequest('https://api.example.com/upload', {\n * method: 'POST',\n * body: buffer\n * })\n * ```\n */\n body?: Buffer | string | undefined\n /**\n * Whether to automatically follow HTTP redirects (3xx status codes).\n *\n * @default true\n *\n * @example\n * ```ts\n * // Follow redirects (default)\n * await httpRequest('https://example.com/redirect')\n *\n * // Don't follow redirects\n * const response = await httpRequest('https://example.com/redirect', {\n * followRedirects: false\n * })\n * console.log(response.status) // 301 or 302\n * ```\n */\n followRedirects?: boolean | undefined\n /**\n * HTTP headers to send with the request.\n * A `User-Agent` header is automatically added if not provided.\n *\n * @example\n * ```ts\n * await httpRequest('https://api.example.com/data', {\n * headers: {\n * 'Authorization': 'Bearer token123',\n * 'Content-Type': 'application/json',\n * 'Accept': 'application/json'\n * }\n * })\n * ```\n */\n headers?: Record<string, string> | undefined\n /**\n * Maximum number of redirects to follow before throwing an error.\n * Only relevant when `followRedirects` is `true`.\n *\n * @default 5\n *\n * @example\n * ```ts\n * // Allow up to 10 redirects\n * await httpRequest('https://example.com/many-redirects', {\n * maxRedirects: 10\n * })\n * ```\n */\n maxRedirects?: number | undefined\n /**\n * HTTP method to use for the request.\n *\n * @default 'GET'\n *\n * @example\n * ```ts\n * // GET request (default)\n * await httpRequest('https://api.example.com/data')\n *\n * // POST request\n * await httpRequest('https://api.example.com/data', {\n * method: 'POST',\n * body: JSON.stringify({ name: 'Alice' })\n * })\n *\n * // DELETE request\n * await httpRequest('https://api.example.com/data/123', {\n * method: 'DELETE'\n * })\n * ```\n */\n method?: string | undefined\n /**\n * Number of retry attempts for failed requests.\n * Uses exponential backoff: delay = `retryDelay` * 2^attempt.\n *\n * @default 0\n *\n * @example\n * ```ts\n * // Retry up to 3 times with exponential backoff\n * await httpRequest('https://api.example.com/data', {\n * retries: 3,\n * retryDelay: 1000 // 1s, then 2s, then 4s\n * })\n * ```\n */\n retries?: number | undefined\n /**\n * Initial delay in milliseconds before first retry.\n * Subsequent retries use exponential backoff.\n *\n * @default 1000\n *\n * @example\n * ```ts\n * // Start with 2 second delay, then 4s, 8s, etc.\n * await httpRequest('https://api.example.com/data', {\n * retries: 3,\n * retryDelay: 2000\n * })\n * ```\n */\n retryDelay?: number | undefined\n /**\n * Request timeout in milliseconds.\n * If the request takes longer than this, it will be aborted.\n *\n * @default 30000\n *\n * @example\n * ```ts\n * // 60 second timeout\n * await httpRequest('https://api.example.com/slow-endpoint', {\n * timeout: 60000\n * })\n * ```\n */\n timeout?: number | undefined\n}\n\n/**\n * HTTP response object with fetch-like interface.\n * Provides multiple ways to access the response body.\n */\nexport interface HttpResponse {\n /**\n * Get response body as ArrayBuffer.\n * Useful for binary data or when you need compatibility with browser APIs.\n *\n * @returns The response body as an ArrayBuffer\n *\n * @example\n * ```ts\n * const response = await httpRequest('https://example.com/image.png')\n * const arrayBuffer = response.arrayBuffer()\n * console.log(arrayBuffer.byteLength)\n * ```\n */\n arrayBuffer(): ArrayBuffer\n /**\n * Raw response body as Buffer.\n * Direct access to the underlying Node.js Buffer.\n *\n * @example\n * ```ts\n * const response = await httpRequest('https://example.com/data')\n * console.log(response.body.length) // Size in bytes\n * console.log(response.body.toString('hex')) // View as hex\n * ```\n */\n body: Buffer\n /**\n * HTTP response headers.\n * Keys are lowercase header names, values can be strings or string arrays.\n *\n * @example\n * ```ts\n * const response = await httpRequest('https://example.com')\n * console.log(response.headers['content-type'])\n * console.log(response.headers['set-cookie']) // May be string[]\n * ```\n */\n headers: Record<string, string | string[] | undefined>\n /**\n * Parse response body as JSON.\n * Type parameter `T` allows specifying the expected JSON structure.\n *\n * @template T - Expected JSON type (defaults to `unknown`)\n * @returns Parsed JSON data\n * @throws {SyntaxError} When response body is not valid JSON\n *\n * @example\n * ```ts\n * interface User { name: string; id: number }\n * const response = await httpRequest('https://api.example.com/user')\n * const user = response.json<User>()\n * console.log(user.name, user.id)\n * ```\n */\n json<T = unknown>(): T\n /**\n * Whether the request was successful (status code 200-299).\n *\n * @example\n * ```ts\n * const response = await httpRequest('https://example.com/data')\n * if (response.ok) {\n * console.log('Success:', response.json())\n * } else {\n * console.error('Failed:', response.status, response.statusText)\n * }\n * ```\n */\n ok: boolean\n /**\n * HTTP status code (e.g., 200, 404, 500).\n *\n * @example\n * ```ts\n * const response = await httpRequest('https://example.com')\n * console.log(response.status) // 200, 404, etc.\n * ```\n */\n status: number\n /**\n * HTTP status message (e.g., \"OK\", \"Not Found\", \"Internal Server Error\").\n *\n * @example\n * ```ts\n * const response = await httpRequest('https://example.com')\n * console.log(response.statusText) // \"OK\"\n * ```\n */\n statusText: string\n /**\n * Get response body as UTF-8 text string.\n *\n * @returns The response body as a string\n *\n * @example\n * ```ts\n * const response = await httpRequest('https://example.com')\n * const html = response.text()\n * console.log(html.includes('<html>'))\n * ```\n */\n text(): string\n}\n\n/**\n * Configuration options for file downloads.\n */\nexport interface HttpDownloadOptions {\n /**\n * HTTP headers to send with the download request.\n * A `User-Agent` header is automatically added if not provided.\n *\n * @example\n * ```ts\n * await httpDownload('https://example.com/file.zip', '/tmp/file.zip', {\n * headers: {\n * 'Authorization': 'Bearer token123'\n * }\n * })\n * ```\n */\n headers?: Record<string, string> | undefined\n /**\n * Callback for tracking download progress.\n * Called periodically as data is received.\n *\n * @param downloaded - Number of bytes downloaded so far\n * @param total - Total file size in bytes (from Content-Length header)\n *\n * @example\n * ```ts\n * await httpDownload('https://example.com/large-file.zip', '/tmp/file.zip', {\n * onProgress: (downloaded, total) => {\n * const percent = ((downloaded / total) * 100).toFixed(1)\n * console.log(`Progress: ${percent}%`)\n * }\n * })\n * ```\n */\n onProgress?: ((downloaded: number, total: number) => void) | undefined\n /**\n * Number of retry attempts for failed downloads.\n * Uses exponential backoff: delay = `retryDelay` * 2^attempt.\n *\n * @default 0\n *\n * @example\n * ```ts\n * // Retry up to 3 times for unreliable connections\n * await httpDownload('https://example.com/file.zip', '/tmp/file.zip', {\n * retries: 3,\n * retryDelay: 2000\n * })\n * ```\n */\n retries?: number | undefined\n /**\n * Initial delay in milliseconds before first retry.\n * Subsequent retries use exponential backoff.\n *\n * @default 1000\n */\n retryDelay?: number | undefined\n /**\n * Download timeout in milliseconds.\n * If the download takes longer than this, it will be aborted.\n *\n * @default 120000\n *\n * @example\n * ```ts\n * // 5 minute timeout for large files\n * await httpDownload('https://example.com/huge-file.zip', '/tmp/file.zip', {\n * timeout: 300000\n * })\n * ```\n */\n timeout?: number | undefined\n}\n\n/**\n * Result of a successful file download.\n */\nexport interface HttpDownloadResult {\n /**\n * Absolute path where the file was saved.\n *\n * @example\n * ```ts\n * const result = await httpDownload('https://example.com/file.zip', '/tmp/file.zip')\n * console.log(`Downloaded to: ${result.path}`)\n * ```\n */\n path: string\n /**\n * Total size of downloaded file in bytes.\n *\n * @example\n * ```ts\n * const result = await httpDownload('https://example.com/file.zip', '/tmp/file.zip')\n * console.log(`Downloaded ${result.size} bytes`)\n * ```\n */\n size: number\n}\n\n/**\n * Make an HTTP/HTTPS request with retry logic and redirect support.\n * Provides a fetch-like API using Node.js native http/https modules.\n *\n * This is the main entry point for making HTTP requests. It handles retries,\n * redirects, timeouts, and provides a fetch-compatible response interface.\n *\n * @param url - The URL to request (must start with http:// or https://)\n * @param options - Request configuration options\n * @returns Promise resolving to response object with `.json()`, `.text()`, etc.\n * @throws {Error} When all retries are exhausted, timeout occurs, or non-retryable error happens\n *\n * @example\n * ```ts\n * // Simple GET request\n * const response = await httpRequest('https://api.example.com/data')\n * const data = response.json()\n *\n * // POST with JSON body\n * const response = await httpRequest('https://api.example.com/users', {\n * method: 'POST',\n * headers: { 'Content-Type': 'application/json' },\n * body: JSON.stringify({ name: 'Alice', email: 'alice@example.com' })\n * })\n *\n * // With retries and timeout\n * const response = await httpRequest('https://api.example.com/data', {\n * retries: 3,\n * retryDelay: 1000,\n * timeout: 60000\n * })\n *\n * // Don't follow redirects\n * const response = await httpRequest('https://example.com/redirect', {\n * followRedirects: false\n * })\n * console.log(response.status) // 301, 302, etc.\n * ```\n */\nexport async function httpRequest(\n url: string,\n options?: HttpRequestOptions | undefined,\n): Promise<HttpResponse> {\n const {\n body,\n followRedirects = true,\n headers = {},\n maxRedirects = 5,\n method = 'GET',\n retries = 0,\n retryDelay = 1000,\n timeout = 30_000,\n } = { __proto__: null, ...options } as HttpRequestOptions\n\n // Retry logic with exponential backoff\n let lastError: Error | undefined\n for (let attempt = 0; attempt <= retries; attempt++) {\n try {\n // eslint-disable-next-line no-await-in-loop\n return await httpRequestAttempt(url, {\n body,\n followRedirects,\n headers,\n maxRedirects,\n method,\n timeout,\n })\n } catch (e) {\n lastError = e as Error\n\n // Last attempt - throw error\n if (attempt === retries) {\n break\n }\n\n // Retry with exponential backoff\n const delayMs = retryDelay * 2 ** attempt\n // eslint-disable-next-line no-await-in-loop\n await new Promise(resolve => setTimeout(resolve, delayMs))\n }\n }\n\n throw lastError || new Error('Request failed after retries')\n}\n\n/**\n * Single HTTP request attempt (used internally by httpRequest with retry logic).\n * @private\n */\nasync function httpRequestAttempt(\n url: string,\n options: HttpRequestOptions,\n): Promise<HttpResponse> {\n const {\n body,\n followRedirects = true,\n headers = {},\n maxRedirects = 5,\n method = 'GET',\n timeout = 30_000,\n } = { __proto__: null, ...options } as HttpRequestOptions\n\n return await new Promise((resolve, reject) => {\n const parsedUrl = new URL(url)\n const isHttps = parsedUrl.protocol === 'https:'\n const httpModule = isHttps ? getHttps() : getHttp()\n\n const requestOptions = {\n headers: {\n 'User-Agent': 'socket-registry/1.0',\n ...headers,\n },\n hostname: parsedUrl.hostname,\n method,\n path: parsedUrl.pathname + parsedUrl.search,\n port: parsedUrl.port,\n timeout,\n }\n\n const request = httpModule.request(\n requestOptions,\n (res: IncomingMessage) => {\n // Handle redirects\n if (\n followRedirects &&\n res.statusCode &&\n res.statusCode >= 300 &&\n res.statusCode < 400 &&\n res.headers.location\n ) {\n if (maxRedirects <= 0) {\n reject(\n new Error(\n `Too many redirects (exceeded maximum: ${maxRedirects})`,\n ),\n )\n return\n }\n\n // Follow redirect\n const redirectUrl = res.headers.location.startsWith('http')\n ? res.headers.location\n : new URL(res.headers.location, url).toString()\n\n resolve(\n httpRequestAttempt(redirectUrl, {\n body,\n followRedirects,\n headers,\n maxRedirects: maxRedirects - 1,\n method,\n timeout,\n }),\n )\n return\n }\n\n // Collect response data\n const chunks: Buffer[] = []\n res.on('data', (chunk: Buffer) => {\n chunks.push(chunk)\n })\n\n res.on('end', () => {\n const responseBody = Buffer.concat(chunks)\n const ok =\n res.statusCode !== undefined &&\n res.statusCode >= 200 &&\n res.statusCode < 300\n\n const response: HttpResponse = {\n arrayBuffer(): ArrayBuffer {\n return responseBody.buffer.slice(\n responseBody.byteOffset,\n responseBody.byteOffset + responseBody.byteLength,\n )\n },\n body: responseBody,\n headers: res.headers as Record<\n string,\n string | string[] | undefined\n >,\n json<T = unknown>(): T {\n return JSON.parse(responseBody.toString('utf8')) as T\n },\n ok,\n status: res.statusCode || 0,\n statusText: res.statusMessage || '',\n text(): string {\n return responseBody.toString('utf8')\n },\n }\n\n resolve(response)\n })\n },\n )\n\n request.on('error', (error: Error) => {\n const code = (error as NodeJS.ErrnoException).code\n let message = `HTTP request failed for ${url}: ${error.message}\\n`\n\n if (code === 'ENOTFOUND') {\n message +=\n 'DNS lookup failed. Check the hostname and your network connection.'\n } else if (code === 'ECONNREFUSED') {\n message +=\n 'Connection refused. Verify the server is running and accessible.'\n } else if (code === 'ETIMEDOUT') {\n message +=\n 'Request timed out. Check your network or increase the timeout value.'\n } else if (code === 'ECONNRESET') {\n message +=\n 'Connection reset. The server may have closed the connection unexpectedly.'\n } else {\n message +=\n 'Check your network connection and verify the URL is correct.'\n }\n\n reject(new Error(message, { cause: error }))\n })\n\n request.on('timeout', () => {\n request.destroy()\n reject(new Error(`Request timed out after ${timeout}ms`))\n })\n\n // Send body if present\n if (body) {\n request.write(body)\n }\n\n request.end()\n })\n}\n\n/**\n * Download a file from a URL to a local path with retry logic and progress callbacks.\n * Uses streaming to avoid loading entire file in memory.\n *\n * The download is streamed directly to disk, making it memory-efficient even for\n * large files. Progress callbacks allow for real-time download status updates.\n *\n * @param url - The URL to download from (must start with http:// or https://)\n * @param destPath - Absolute path where the file should be saved\n * @param options - Download configuration options\n * @returns Promise resolving to download result with path and size\n * @throws {Error} When all retries are exhausted, download fails, or file cannot be written\n *\n * @example\n * ```ts\n * // Simple download\n * const result = await httpDownload(\n * 'https://example.com/file.zip',\n * '/tmp/file.zip'\n * )\n * console.log(`Downloaded ${result.size} bytes to ${result.path}`)\n *\n * // With progress tracking\n * await httpDownload(\n * 'https://example.com/large-file.zip',\n * '/tmp/file.zip',\n * {\n * onProgress: (downloaded, total) => {\n * const percent = ((downloaded / total) * 100).toFixed(1)\n * console.log(`Progress: ${percent}% (${downloaded}/${total} bytes)`)\n * }\n * }\n * )\n *\n * // With retries and custom timeout\n * await httpDownload(\n * 'https://example.com/file.zip',\n * '/tmp/file.zip',\n * {\n * retries: 3,\n * retryDelay: 2000,\n * timeout: 300000, // 5 minutes\n * headers: { 'Authorization': 'Bearer token123' }\n * }\n * )\n * ```\n */\nexport async function httpDownload(\n url: string,\n destPath: string,\n options?: HttpDownloadOptions | undefined,\n): Promise<HttpDownloadResult> {\n const {\n headers = {},\n onProgress,\n retries = 0,\n retryDelay = 1000,\n timeout = 120_000,\n } = { __proto__: null, ...options } as HttpDownloadOptions\n\n // Retry logic with exponential backoff\n let lastError: Error | undefined\n for (let attempt = 0; attempt <= retries; attempt++) {\n try {\n // eslint-disable-next-line no-await-in-loop\n return await httpDownloadAttempt(url, destPath, {\n headers,\n onProgress,\n timeout,\n })\n } catch (e) {\n lastError = e as Error\n\n // Last attempt - throw error\n if (attempt === retries) {\n break\n }\n\n // Retry with exponential backoff\n const delayMs = retryDelay * 2 ** attempt\n // eslint-disable-next-line no-await-in-loop\n await new Promise(resolve => setTimeout(resolve, delayMs))\n }\n }\n\n throw lastError || new Error('Download failed after retries')\n}\n\n/**\n * Single download attempt (used internally by httpDownload with retry logic).\n * @private\n */\nasync function httpDownloadAttempt(\n url: string,\n destPath: string,\n options: HttpDownloadOptions,\n): Promise<HttpDownloadResult> {\n const {\n headers = {},\n onProgress,\n timeout = 120_000,\n } = { __proto__: null, ...options } as HttpDownloadOptions\n\n return await new Promise((resolve, reject) => {\n const parsedUrl = new URL(url)\n const isHttps = parsedUrl.protocol === 'https:'\n const httpModule = isHttps ? getHttps() : getHttp()\n\n const requestOptions = {\n headers: {\n 'User-Agent': 'socket-registry/1.0',\n ...headers,\n },\n hostname: parsedUrl.hostname,\n method: 'GET',\n path: parsedUrl.pathname + parsedUrl.search,\n port: parsedUrl.port,\n timeout,\n }\n\n let fileStream: ReturnType<typeof createWriteStream> | undefined\n let streamClosed = false\n\n const closeStream = () => {\n if (!streamClosed && fileStream) {\n streamClosed = true\n fileStream.close()\n }\n }\n\n const request = httpModule.request(\n requestOptions,\n (res: IncomingMessage) => {\n // Check status code\n if (!res.statusCode || res.statusCode < 200 || res.statusCode >= 300) {\n closeStream()\n reject(\n new Error(\n `Download failed: HTTP ${res.statusCode} ${res.statusMessage}`,\n ),\n )\n return\n }\n\n const totalSize = Number.parseInt(\n res.headers['content-length'] || '0',\n 10,\n )\n let downloadedSize = 0\n\n // Create write stream\n fileStream = createWriteStream(destPath)\n\n fileStream.on('error', (error: Error) => {\n closeStream()\n const err = new Error(`Failed to write file: ${error.message}`, {\n cause: error,\n })\n reject(err)\n })\n\n res.on('data', (chunk: Buffer) => {\n downloadedSize += chunk.length\n if (onProgress && totalSize > 0) {\n onProgress(downloadedSize, totalSize)\n }\n })\n\n res.on('end', () => {\n fileStream?.close(() => {\n streamClosed = true\n resolve({\n path: destPath,\n size: downloadedSize,\n })\n })\n })\n\n res.on('error', (error: Error) => {\n closeStream()\n reject(error)\n })\n\n // Pipe response to file\n res.pipe(fileStream)\n },\n )\n\n request.on('error', (error: Error) => {\n closeStream()\n const code = (error as NodeJS.ErrnoException).code\n let message = `HTTP download failed for ${url}: ${error.message}\\n`\n\n if (code === 'ENOTFOUND') {\n message +=\n 'DNS lookup failed. Check the hostname and your network connection.'\n } else if (code === 'ECONNREFUSED') {\n message +=\n 'Connection refused. Verify the server is running and accessible.'\n } else if (code === 'ETIMEDOUT') {\n message +=\n 'Request timed out. Check your network or increase the timeout value.'\n } else if (code === 'ECONNRESET') {\n message +=\n 'Connection reset. The server may have closed the connection unexpectedly.'\n } else {\n message +=\n 'Check your network connection and verify the URL is correct.'\n }\n\n reject(new Error(message, { cause: error }))\n })\n\n request.on('timeout', () => {\n request.destroy()\n closeStream()\n reject(new Error(`Download timed out after ${timeout}ms`))\n })\n\n request.end()\n })\n}\n\n/**\n * Perform a GET request and parse JSON response.\n * Convenience wrapper around `httpRequest` for common JSON API calls.\n *\n * @template T - Expected JSON response type (defaults to `unknown`)\n * @param url - The URL to request (must start with http:// or https://)\n * @param options - Request configuration options\n * @returns Promise resolving to parsed JSON data\n * @throws {Error} When request fails, response is not ok (status < 200 or >= 300), or JSON parsing fails\n *\n * @example\n * ```ts\n * // Simple JSON GET\n * const data = await httpGetJson('https://api.example.com/data')\n * console.log(data)\n *\n * // With type safety\n * interface User { id: number; name: string; email: string }\n * const user = await httpGetJson<User>('https://api.example.com/user/123')\n * console.log(user.name, user.email)\n *\n * // With custom headers\n * const data = await httpGetJson('https://api.example.com/data', {\n * headers: {\n * 'Authorization': 'Bearer token123',\n * 'Accept': 'application/json'\n * }\n * })\n *\n * // With retries\n * const data = await httpGetJson('https://api.example.com/data', {\n * retries: 3,\n * retryDelay: 1000\n * })\n * ```\n */\nexport async function httpGetJson<T = unknown>(\n url: string,\n options?: HttpRequestOptions | undefined,\n): Promise<T> {\n const response = await httpRequest(url, { ...options, method: 'GET' })\n\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}: ${response.statusText}`)\n }\n\n try {\n return response.json<T>()\n } catch (e) {\n throw new Error('Failed to parse JSON response', { cause: e })\n }\n}\n\n/**\n * Perform a GET request and return text response.\n * Convenience wrapper around `httpRequest` for fetching text content.\n *\n * @param url - The URL to request (must start with http:// or https://)\n * @param options - Request configuration options\n * @returns Promise resolving to response body as UTF-8 string\n * @throws {Error} When request fails or response is not ok (status < 200 or >= 300)\n *\n * @example\n * ```ts\n * // Fetch HTML\n * const html = await httpGetText('https://example.com')\n * console.log(html.includes('<!DOCTYPE html>'))\n *\n * // Fetch plain text\n * const text = await httpGetText('https://example.com/file.txt')\n * console.log(text)\n *\n * // With custom headers\n * const text = await httpGetText('https://example.com/data.txt', {\n * headers: {\n * 'Authorization': 'Bearer token123'\n * }\n * })\n *\n * // With timeout\n * const text = await httpGetText('https://example.com/large-file.txt', {\n * timeout: 60000 // 1 minute\n * })\n * ```\n */\nexport async function httpGetText(\n url: string,\n options?: HttpRequestOptions | undefined,\n): Promise<string> {\n const response = await httpRequest(url, { ...options, method: 'GET' })\n\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}: ${response.statusText}`)\n }\n\n return response.text()\n}\n"],
5
- "mappings": "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",
6
- "names": ["http_request_exports", "__export", "httpDownload", "httpGetJson", "httpGetText", "httpRequest", "__toCommonJS", "import_node_fs", "_http", "_https", "getHttp", "getHttps", "url", "options", "body", "followRedirects", "headers", "maxRedirects", "method", "retries", "retryDelay", "timeout", "lastError", "attempt", "httpRequestAttempt", "e", "delayMs", "resolve", "reject", "parsedUrl", "httpModule", "requestOptions", "request", "res", "redirectUrl", "chunks", "chunk", "responseBody", "ok", "response", "error", "code", "message", "destPath", "onProgress", "httpDownloadAttempt", "fileStream", "streamClosed", "closeStream", "totalSize", "downloadedSize", "err"]
4
+ "sourcesContent": ["/**\n * @fileoverview HTTP/HTTPS request utilities using Node.js built-in modules with retry logic, redirects, and download support.\n *\n * This module provides a fetch-like API built on top of Node.js native `http` and `https` modules.\n * It supports automatic retries with exponential backoff, redirect following, streaming downloads,\n * and provides a familiar fetch-style response interface.\n *\n * Key Features:\n * - Automatic retries with exponential backoff for failed requests.\n * - Redirect following with configurable max redirects.\n * - Streaming downloads with progress callbacks.\n * - Fetch-like response interface (`.json()`, `.text()`, `.arrayBuffer()`).\n * - Timeout support for all operations.\n * - Zero dependencies on external HTTP libraries.\n */\n\nimport { createWriteStream } from 'fs'\n\nimport type { IncomingMessage } from 'http'\n\nlet _http: typeof import('http') | undefined\nlet _https: typeof import('https') | undefined\n/**\n * Lazily load http and https modules to avoid Webpack errors.\n * @private\n */\n/*@__NO_SIDE_EFFECTS__*/\nfunction getHttp() {\n if (_http === undefined) {\n // Use non-'node:' prefixed require to avoid Webpack errors.\n\n _http = /*@__PURE__*/ require('node:http')\n }\n return _http as typeof import('http')\n}\n\n/*@__NO_SIDE_EFFECTS__*/\nfunction getHttps() {\n if (_https === undefined) {\n // Use non-'node:' prefixed require to avoid Webpack errors.\n\n _https = /*@__PURE__*/ require('node:https')\n }\n return _https as typeof import('https')\n}\n\n/**\n * Configuration options for HTTP/HTTPS requests.\n */\nexport interface HttpRequestOptions {\n /**\n * Request body to send.\n * Can be a string (e.g., JSON) or Buffer (e.g., binary data).\n *\n * @example\n * ```ts\n * // Send JSON data\n * await httpRequest('https://api.example.com/data', {\n * method: 'POST',\n * body: JSON.stringify({ name: 'Alice' }),\n * headers: { 'Content-Type': 'application/json' }\n * })\n *\n * // Send binary data\n * const buffer = Buffer.from([0x00, 0x01, 0x02])\n * await httpRequest('https://api.example.com/upload', {\n * method: 'POST',\n * body: buffer\n * })\n * ```\n */\n body?: Buffer | string | undefined\n /**\n * Whether to automatically follow HTTP redirects (3xx status codes).\n *\n * @default true\n *\n * @example\n * ```ts\n * // Follow redirects (default)\n * await httpRequest('https://example.com/redirect')\n *\n * // Don't follow redirects\n * const response = await httpRequest('https://example.com/redirect', {\n * followRedirects: false\n * })\n * console.log(response.status) // 301 or 302\n * ```\n */\n followRedirects?: boolean | undefined\n /**\n * HTTP headers to send with the request.\n * A `User-Agent` header is automatically added if not provided.\n *\n * @example\n * ```ts\n * await httpRequest('https://api.example.com/data', {\n * headers: {\n * 'Authorization': 'Bearer token123',\n * 'Content-Type': 'application/json',\n * 'Accept': 'application/json'\n * }\n * })\n * ```\n */\n headers?: Record<string, string> | undefined\n /**\n * Maximum number of redirects to follow before throwing an error.\n * Only relevant when `followRedirects` is `true`.\n *\n * @default 5\n *\n * @example\n * ```ts\n * // Allow up to 10 redirects\n * await httpRequest('https://example.com/many-redirects', {\n * maxRedirects: 10\n * })\n * ```\n */\n maxRedirects?: number | undefined\n /**\n * HTTP method to use for the request.\n *\n * @default 'GET'\n *\n * @example\n * ```ts\n * // GET request (default)\n * await httpRequest('https://api.example.com/data')\n *\n * // POST request\n * await httpRequest('https://api.example.com/data', {\n * method: 'POST',\n * body: JSON.stringify({ name: 'Alice' })\n * })\n *\n * // DELETE request\n * await httpRequest('https://api.example.com/data/123', {\n * method: 'DELETE'\n * })\n * ```\n */\n method?: string | undefined\n /**\n * Number of retry attempts for failed requests.\n * Uses exponential backoff: delay = `retryDelay` * 2^attempt.\n *\n * @default 0\n *\n * @example\n * ```ts\n * // Retry up to 3 times with exponential backoff\n * await httpRequest('https://api.example.com/data', {\n * retries: 3,\n * retryDelay: 1000 // 1s, then 2s, then 4s\n * })\n * ```\n */\n retries?: number | undefined\n /**\n * Initial delay in milliseconds before first retry.\n * Subsequent retries use exponential backoff.\n *\n * @default 1000\n *\n * @example\n * ```ts\n * // Start with 2 second delay, then 4s, 8s, etc.\n * await httpRequest('https://api.example.com/data', {\n * retries: 3,\n * retryDelay: 2000\n * })\n * ```\n */\n retryDelay?: number | undefined\n /**\n * Request timeout in milliseconds.\n * If the request takes longer than this, it will be aborted.\n *\n * @default 30000\n *\n * @example\n * ```ts\n * // 60 second timeout\n * await httpRequest('https://api.example.com/slow-endpoint', {\n * timeout: 60000\n * })\n * ```\n */\n timeout?: number | undefined\n}\n\n/**\n * HTTP response object with fetch-like interface.\n * Provides multiple ways to access the response body.\n */\nexport interface HttpResponse {\n /**\n * Get response body as ArrayBuffer.\n * Useful for binary data or when you need compatibility with browser APIs.\n *\n * @returns The response body as an ArrayBuffer\n *\n * @example\n * ```ts\n * const response = await httpRequest('https://example.com/image.png')\n * const arrayBuffer = response.arrayBuffer()\n * console.log(arrayBuffer.byteLength)\n * ```\n */\n arrayBuffer(): ArrayBuffer\n /**\n * Raw response body as Buffer.\n * Direct access to the underlying Node.js Buffer.\n *\n * @example\n * ```ts\n * const response = await httpRequest('https://example.com/data')\n * console.log(response.body.length) // Size in bytes\n * console.log(response.body.toString('hex')) // View as hex\n * ```\n */\n body: Buffer\n /**\n * HTTP response headers.\n * Keys are lowercase header names, values can be strings or string arrays.\n *\n * @example\n * ```ts\n * const response = await httpRequest('https://example.com')\n * console.log(response.headers['content-type'])\n * console.log(response.headers['set-cookie']) // May be string[]\n * ```\n */\n headers: Record<string, string | string[] | undefined>\n /**\n * Parse response body as JSON.\n * Type parameter `T` allows specifying the expected JSON structure.\n *\n * @template T - Expected JSON type (defaults to `unknown`)\n * @returns Parsed JSON data\n * @throws {SyntaxError} When response body is not valid JSON\n *\n * @example\n * ```ts\n * interface User { name: string; id: number }\n * const response = await httpRequest('https://api.example.com/user')\n * const user = response.json<User>()\n * console.log(user.name, user.id)\n * ```\n */\n json<T = unknown>(): T\n /**\n * Whether the request was successful (status code 200-299).\n *\n * @example\n * ```ts\n * const response = await httpRequest('https://example.com/data')\n * if (response.ok) {\n * console.log('Success:', response.json())\n * } else {\n * console.error('Failed:', response.status, response.statusText)\n * }\n * ```\n */\n ok: boolean\n /**\n * HTTP status code (e.g., 200, 404, 500).\n *\n * @example\n * ```ts\n * const response = await httpRequest('https://example.com')\n * console.log(response.status) // 200, 404, etc.\n * ```\n */\n status: number\n /**\n * HTTP status message (e.g., \"OK\", \"Not Found\", \"Internal Server Error\").\n *\n * @example\n * ```ts\n * const response = await httpRequest('https://example.com')\n * console.log(response.statusText) // \"OK\"\n * ```\n */\n statusText: string\n /**\n * Get response body as UTF-8 text string.\n *\n * @returns The response body as a string\n *\n * @example\n * ```ts\n * const response = await httpRequest('https://example.com')\n * const html = response.text()\n * console.log(html.includes('<html>'))\n * ```\n */\n text(): string\n}\n\n/**\n * Configuration options for file downloads.\n */\nexport interface HttpDownloadOptions {\n /**\n * HTTP headers to send with the download request.\n * A `User-Agent` header is automatically added if not provided.\n *\n * @example\n * ```ts\n * await httpDownload('https://example.com/file.zip', '/tmp/file.zip', {\n * headers: {\n * 'Authorization': 'Bearer token123'\n * }\n * })\n * ```\n */\n headers?: Record<string, string> | undefined\n /**\n * Callback for tracking download progress.\n * Called periodically as data is received.\n *\n * @param downloaded - Number of bytes downloaded so far\n * @param total - Total file size in bytes (from Content-Length header)\n *\n * @example\n * ```ts\n * await httpDownload('https://example.com/large-file.zip', '/tmp/file.zip', {\n * onProgress: (downloaded, total) => {\n * const percent = ((downloaded / total) * 100).toFixed(1)\n * console.log(`Progress: ${percent}%`)\n * }\n * })\n * ```\n */\n onProgress?: ((downloaded: number, total: number) => void) | undefined\n /**\n * Number of retry attempts for failed downloads.\n * Uses exponential backoff: delay = `retryDelay` * 2^attempt.\n *\n * @default 0\n *\n * @example\n * ```ts\n * // Retry up to 3 times for unreliable connections\n * await httpDownload('https://example.com/file.zip', '/tmp/file.zip', {\n * retries: 3,\n * retryDelay: 2000\n * })\n * ```\n */\n retries?: number | undefined\n /**\n * Initial delay in milliseconds before first retry.\n * Subsequent retries use exponential backoff.\n *\n * @default 1000\n */\n retryDelay?: number | undefined\n /**\n * Download timeout in milliseconds.\n * If the download takes longer than this, it will be aborted.\n *\n * @default 120000\n *\n * @example\n * ```ts\n * // 5 minute timeout for large files\n * await httpDownload('https://example.com/huge-file.zip', '/tmp/file.zip', {\n * timeout: 300000\n * })\n * ```\n */\n timeout?: number | undefined\n}\n\n/**\n * Result of a successful file download.\n */\nexport interface HttpDownloadResult {\n /**\n * Absolute path where the file was saved.\n *\n * @example\n * ```ts\n * const result = await httpDownload('https://example.com/file.zip', '/tmp/file.zip')\n * console.log(`Downloaded to: ${result.path}`)\n * ```\n */\n path: string\n /**\n * Total size of downloaded file in bytes.\n *\n * @example\n * ```ts\n * const result = await httpDownload('https://example.com/file.zip', '/tmp/file.zip')\n * console.log(`Downloaded ${result.size} bytes`)\n * ```\n */\n size: number\n}\n\n/**\n * Make an HTTP/HTTPS request with retry logic and redirect support.\n * Provides a fetch-like API using Node.js native http/https modules.\n *\n * This is the main entry point for making HTTP requests. It handles retries,\n * redirects, timeouts, and provides a fetch-compatible response interface.\n *\n * @param url - The URL to request (must start with http:// or https://)\n * @param options - Request configuration options\n * @returns Promise resolving to response object with `.json()`, `.text()`, etc.\n * @throws {Error} When all retries are exhausted, timeout occurs, or non-retryable error happens\n *\n * @example\n * ```ts\n * // Simple GET request\n * const response = await httpRequest('https://api.example.com/data')\n * const data = response.json()\n *\n * // POST with JSON body\n * const response = await httpRequest('https://api.example.com/users', {\n * method: 'POST',\n * headers: { 'Content-Type': 'application/json' },\n * body: JSON.stringify({ name: 'Alice', email: 'alice@example.com' })\n * })\n *\n * // With retries and timeout\n * const response = await httpRequest('https://api.example.com/data', {\n * retries: 3,\n * retryDelay: 1000,\n * timeout: 60000\n * })\n *\n * // Don't follow redirects\n * const response = await httpRequest('https://example.com/redirect', {\n * followRedirects: false\n * })\n * console.log(response.status) // 301, 302, etc.\n * ```\n */\nexport async function httpRequest(\n url: string,\n options?: HttpRequestOptions | undefined,\n): Promise<HttpResponse> {\n const {\n body,\n followRedirects = true,\n headers = {},\n maxRedirects = 5,\n method = 'GET',\n retries = 0,\n retryDelay = 1000,\n timeout = 30_000,\n } = { __proto__: null, ...options } as HttpRequestOptions\n\n // Retry logic with exponential backoff\n let lastError: Error | undefined\n for (let attempt = 0; attempt <= retries; attempt++) {\n try {\n // eslint-disable-next-line no-await-in-loop\n return await httpRequestAttempt(url, {\n body,\n followRedirects,\n headers,\n maxRedirects,\n method,\n timeout,\n })\n } catch (e) {\n lastError = e as Error\n\n // Last attempt - throw error\n if (attempt === retries) {\n break\n }\n\n // Retry with exponential backoff\n const delayMs = retryDelay * 2 ** attempt\n // eslint-disable-next-line no-await-in-loop\n await new Promise(resolve => setTimeout(resolve, delayMs))\n }\n }\n\n throw lastError || new Error('Request failed after retries')\n}\n\n/**\n * Single HTTP request attempt (used internally by httpRequest with retry logic).\n * @private\n */\nasync function httpRequestAttempt(\n url: string,\n options: HttpRequestOptions,\n): Promise<HttpResponse> {\n const {\n body,\n followRedirects = true,\n headers = {},\n maxRedirects = 5,\n method = 'GET',\n timeout = 30_000,\n } = { __proto__: null, ...options } as HttpRequestOptions\n\n return await new Promise((resolve, reject) => {\n const parsedUrl = new URL(url)\n const isHttps = parsedUrl.protocol === 'https:'\n const httpModule = isHttps ? getHttps() : getHttp()\n\n const requestOptions = {\n headers: {\n 'User-Agent': 'socket-registry/1.0',\n ...headers,\n },\n hostname: parsedUrl.hostname,\n method,\n path: parsedUrl.pathname + parsedUrl.search,\n port: parsedUrl.port,\n timeout,\n }\n\n const request = httpModule.request(\n requestOptions,\n (res: IncomingMessage) => {\n // Handle redirects\n if (\n followRedirects &&\n res.statusCode &&\n res.statusCode >= 300 &&\n res.statusCode < 400 &&\n res.headers.location\n ) {\n if (maxRedirects <= 0) {\n reject(\n new Error(\n `Too many redirects (exceeded maximum: ${maxRedirects})`,\n ),\n )\n return\n }\n\n // Follow redirect\n const redirectUrl = res.headers.location.startsWith('http')\n ? res.headers.location\n : new URL(res.headers.location, url).toString()\n\n resolve(\n httpRequestAttempt(redirectUrl, {\n body,\n followRedirects,\n headers,\n maxRedirects: maxRedirects - 1,\n method,\n timeout,\n }),\n )\n return\n }\n\n // Collect response data\n const chunks: Buffer[] = []\n res.on('data', (chunk: Buffer) => {\n chunks.push(chunk)\n })\n\n res.on('end', () => {\n const responseBody = Buffer.concat(chunks)\n const ok =\n res.statusCode !== undefined &&\n res.statusCode >= 200 &&\n res.statusCode < 300\n\n const response: HttpResponse = {\n arrayBuffer(): ArrayBuffer {\n return responseBody.buffer.slice(\n responseBody.byteOffset,\n responseBody.byteOffset + responseBody.byteLength,\n )\n },\n body: responseBody,\n headers: res.headers as Record<\n string,\n string | string[] | undefined\n >,\n json<T = unknown>(): T {\n return JSON.parse(responseBody.toString('utf8')) as T\n },\n ok,\n status: res.statusCode || 0,\n statusText: res.statusMessage || '',\n text(): string {\n return responseBody.toString('utf8')\n },\n }\n\n resolve(response)\n })\n },\n )\n\n request.on('error', (error: Error) => {\n const code = (error as NodeJS.ErrnoException).code\n let message = `HTTP request failed for ${url}: ${error.message}\\n`\n\n if (code === 'ENOTFOUND') {\n message +=\n 'DNS lookup failed. Check the hostname and your network connection.'\n } else if (code === 'ECONNREFUSED') {\n message +=\n 'Connection refused. Verify the server is running and accessible.'\n } else if (code === 'ETIMEDOUT') {\n message +=\n 'Request timed out. Check your network or increase the timeout value.'\n } else if (code === 'ECONNRESET') {\n message +=\n 'Connection reset. The server may have closed the connection unexpectedly.'\n } else {\n message +=\n 'Check your network connection and verify the URL is correct.'\n }\n\n reject(new Error(message, { cause: error }))\n })\n\n request.on('timeout', () => {\n request.destroy()\n reject(new Error(`Request timed out after ${timeout}ms`))\n })\n\n // Send body if present\n if (body) {\n request.write(body)\n }\n\n request.end()\n })\n}\n\n/**\n * Download a file from a URL to a local path with retry logic and progress callbacks.\n * Uses streaming to avoid loading entire file in memory.\n *\n * The download is streamed directly to disk, making it memory-efficient even for\n * large files. Progress callbacks allow for real-time download status updates.\n *\n * @param url - The URL to download from (must start with http:// or https://)\n * @param destPath - Absolute path where the file should be saved\n * @param options - Download configuration options\n * @returns Promise resolving to download result with path and size\n * @throws {Error} When all retries are exhausted, download fails, or file cannot be written\n *\n * @example\n * ```ts\n * // Simple download\n * const result = await httpDownload(\n * 'https://example.com/file.zip',\n * '/tmp/file.zip'\n * )\n * console.log(`Downloaded ${result.size} bytes to ${result.path}`)\n *\n * // With progress tracking\n * await httpDownload(\n * 'https://example.com/large-file.zip',\n * '/tmp/file.zip',\n * {\n * onProgress: (downloaded, total) => {\n * const percent = ((downloaded / total) * 100).toFixed(1)\n * console.log(`Progress: ${percent}% (${downloaded}/${total} bytes)`)\n * }\n * }\n * )\n *\n * // With retries and custom timeout\n * await httpDownload(\n * 'https://example.com/file.zip',\n * '/tmp/file.zip',\n * {\n * retries: 3,\n * retryDelay: 2000,\n * timeout: 300000, // 5 minutes\n * headers: { 'Authorization': 'Bearer token123' }\n * }\n * )\n * ```\n */\nexport async function httpDownload(\n url: string,\n destPath: string,\n options?: HttpDownloadOptions | undefined,\n): Promise<HttpDownloadResult> {\n const {\n headers = {},\n onProgress,\n retries = 0,\n retryDelay = 1000,\n timeout = 120_000,\n } = { __proto__: null, ...options } as HttpDownloadOptions\n\n // Retry logic with exponential backoff\n let lastError: Error | undefined\n for (let attempt = 0; attempt <= retries; attempt++) {\n try {\n // eslint-disable-next-line no-await-in-loop\n return await httpDownloadAttempt(url, destPath, {\n headers,\n onProgress,\n timeout,\n })\n } catch (e) {\n lastError = e as Error\n\n // Last attempt - throw error\n if (attempt === retries) {\n break\n }\n\n // Retry with exponential backoff\n const delayMs = retryDelay * 2 ** attempt\n // eslint-disable-next-line no-await-in-loop\n await new Promise(resolve => setTimeout(resolve, delayMs))\n }\n }\n\n throw lastError || new Error('Download failed after retries')\n}\n\n/**\n * Single download attempt (used internally by httpDownload with retry logic).\n * @private\n */\nasync function httpDownloadAttempt(\n url: string,\n destPath: string,\n options: HttpDownloadOptions,\n): Promise<HttpDownloadResult> {\n const {\n headers = {},\n onProgress,\n timeout = 120_000,\n } = { __proto__: null, ...options } as HttpDownloadOptions\n\n return await new Promise((resolve, reject) => {\n const parsedUrl = new URL(url)\n const isHttps = parsedUrl.protocol === 'https:'\n const httpModule = isHttps ? getHttps() : getHttp()\n\n const requestOptions = {\n headers: {\n 'User-Agent': 'socket-registry/1.0',\n ...headers,\n },\n hostname: parsedUrl.hostname,\n method: 'GET',\n path: parsedUrl.pathname + parsedUrl.search,\n port: parsedUrl.port,\n timeout,\n }\n\n let fileStream: ReturnType<typeof createWriteStream> | undefined\n let streamClosed = false\n\n const closeStream = () => {\n if (!streamClosed && fileStream) {\n streamClosed = true\n fileStream.close()\n }\n }\n\n const request = httpModule.request(\n requestOptions,\n (res: IncomingMessage) => {\n // Check status code\n if (!res.statusCode || res.statusCode < 200 || res.statusCode >= 300) {\n closeStream()\n reject(\n new Error(\n `Download failed: HTTP ${res.statusCode} ${res.statusMessage}`,\n ),\n )\n return\n }\n\n const totalSize = Number.parseInt(\n res.headers['content-length'] || '0',\n 10,\n )\n let downloadedSize = 0\n\n // Create write stream\n fileStream = createWriteStream(destPath)\n\n fileStream.on('error', (error: Error) => {\n closeStream()\n const err = new Error(`Failed to write file: ${error.message}`, {\n cause: error,\n })\n reject(err)\n })\n\n res.on('data', (chunk: Buffer) => {\n downloadedSize += chunk.length\n if (onProgress && totalSize > 0) {\n onProgress(downloadedSize, totalSize)\n }\n })\n\n res.on('end', () => {\n fileStream?.close(() => {\n streamClosed = true\n resolve({\n path: destPath,\n size: downloadedSize,\n })\n })\n })\n\n res.on('error', (error: Error) => {\n closeStream()\n reject(error)\n })\n\n // Pipe response to file\n res.pipe(fileStream)\n },\n )\n\n request.on('error', (error: Error) => {\n closeStream()\n const code = (error as NodeJS.ErrnoException).code\n let message = `HTTP download failed for ${url}: ${error.message}\\n`\n\n if (code === 'ENOTFOUND') {\n message +=\n 'DNS lookup failed. Check the hostname and your network connection.'\n } else if (code === 'ECONNREFUSED') {\n message +=\n 'Connection refused. Verify the server is running and accessible.'\n } else if (code === 'ETIMEDOUT') {\n message +=\n 'Request timed out. Check your network or increase the timeout value.'\n } else if (code === 'ECONNRESET') {\n message +=\n 'Connection reset. The server may have closed the connection unexpectedly.'\n } else {\n message +=\n 'Check your network connection and verify the URL is correct.'\n }\n\n reject(new Error(message, { cause: error }))\n })\n\n request.on('timeout', () => {\n request.destroy()\n closeStream()\n reject(new Error(`Download timed out after ${timeout}ms`))\n })\n\n request.end()\n })\n}\n\n/**\n * Perform a GET request and parse JSON response.\n * Convenience wrapper around `httpRequest` for common JSON API calls.\n *\n * @template T - Expected JSON response type (defaults to `unknown`)\n * @param url - The URL to request (must start with http:// or https://)\n * @param options - Request configuration options\n * @returns Promise resolving to parsed JSON data\n * @throws {Error} When request fails, response is not ok (status < 200 or >= 300), or JSON parsing fails\n *\n * @example\n * ```ts\n * // Simple JSON GET\n * const data = await httpGetJson('https://api.example.com/data')\n * console.log(data)\n *\n * // With type safety\n * interface User { id: number; name: string; email: string }\n * const user = await httpGetJson<User>('https://api.example.com/user/123')\n * console.log(user.name, user.email)\n *\n * // With custom headers\n * const data = await httpGetJson('https://api.example.com/data', {\n * headers: {\n * 'Authorization': 'Bearer token123',\n * 'Accept': 'application/json'\n * }\n * })\n *\n * // With retries\n * const data = await httpGetJson('https://api.example.com/data', {\n * retries: 3,\n * retryDelay: 1000\n * })\n * ```\n */\nexport async function httpGetJson<T = unknown>(\n url: string,\n options?: HttpRequestOptions | undefined,\n): Promise<T> {\n const response = await httpRequest(url, { ...options, method: 'GET' })\n\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}: ${response.statusText}`)\n }\n\n try {\n return response.json<T>()\n } catch (e) {\n throw new Error('Failed to parse JSON response', { cause: e })\n }\n}\n\n/**\n * Perform a GET request and return text response.\n * Convenience wrapper around `httpRequest` for fetching text content.\n *\n * @param url - The URL to request (must start with http:// or https://)\n * @param options - Request configuration options\n * @returns Promise resolving to response body as UTF-8 string\n * @throws {Error} When request fails or response is not ok (status < 200 or >= 300)\n *\n * @example\n * ```ts\n * // Fetch HTML\n * const html = await httpGetText('https://example.com')\n * console.log(html.includes('<!DOCTYPE html>'))\n *\n * // Fetch plain text\n * const text = await httpGetText('https://example.com/file.txt')\n * console.log(text)\n *\n * // With custom headers\n * const text = await httpGetText('https://example.com/data.txt', {\n * headers: {\n * 'Authorization': 'Bearer token123'\n * }\n * })\n *\n * // With timeout\n * const text = await httpGetText('https://example.com/large-file.txt', {\n * timeout: 60000 // 1 minute\n * })\n * ```\n */\nexport async function httpGetText(\n url: string,\n options?: HttpRequestOptions | undefined,\n): Promise<string> {\n const response = await httpRequest(url, { ...options, method: 'GET' })\n\n if (!response.ok) {\n throw new Error(`HTTP ${response.status}: ${response.statusText}`)\n }\n\n return response.text()\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["http_request_exports", "__export", "httpDownload", "httpGetJson", "httpGetText", "httpRequest", "__toCommonJS", "import_fs", "_http", "_https", "getHttp", "getHttps", "url", "options", "body", "followRedirects", "headers", "maxRedirects", "method", "retries", "retryDelay", "timeout", "lastError", "attempt", "httpRequestAttempt", "e", "delayMs", "resolve", "reject", "parsedUrl", "httpModule", "requestOptions", "request", "res", "redirectUrl", "chunks", "chunk", "responseBody", "ok", "response", "error", "code", "message", "destPath", "onProgress", "httpDownloadAttempt", "fileStream", "streamClosed", "closeStream", "totalSize", "downloadedSize", "err"]
7
7
  }
package/dist/ipc.js CHANGED
@@ -1,3 +1,3 @@
1
1
  /* Socket Lib - Built with esbuild */
2
- var P=Object.create;var m=Object.defineProperty;var N=Object.getOwnPropertyDescriptor;var B=Object.getOwnPropertyNames;var O=Object.getPrototypeOf,A=Object.prototype.hasOwnProperty;var J=(t,e)=>{for(var n in e)m(t,n,{get:e[n],enumerable:!0})},y=(t,e,n,o)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of B(e))!A.call(t,s)&&s!==n&&m(t,s,{get:()=>e[s],enumerable:!(o=N(e,s))||o.enumerable});return t};var k=(t,e,n)=>(n=t!=null?P(O(t)):{},y(e||!t||!t.__esModule?m(n,"default",{value:t,enumerable:!0}):n,t)),$=t=>y(m({},"__esModule",{value:!0}),t);var L={};J(L,{IpcHandshakeSchema:()=>E,cleanupIpcStubs:()=>z,createIpcChannelId:()=>F,createIpcMessage:()=>G,getIpcStubPath:()=>x,hasIpcChannel:()=>K,onIpc:()=>S,parseIpcMessage:()=>v,readIpcStub:()=>W,sendIpc:()=>_,waitForIpc:()=>q,writeIpcStub:()=>H});module.exports=$(L);var l=k(require("node:crypto")),c=require("node:fs"),p=k(require("node:path")),g=require("./fs"),h=require("./paths"),i=require("./zod");const w=i.z.object({id:i.z.string().min(1),timestamp:i.z.number().positive(),type:i.z.string().min(1),data:i.z.unknown()}),E=w.extend({type:i.z.literal("handshake"),data:i.z.object({version:i.z.string(),pid:i.z.number().int().positive(),apiToken:i.z.string().optional(),appName:i.z.string()})}),I=i.z.object({pid:i.z.number().int().positive(),timestamp:i.z.number().positive(),data:i.z.unknown()});function F(t="socket"){return`${t}-${process.pid}-${l.default.randomBytes(8).toString("hex")}`}function x(t){const e=(0,h.getOsTmpDir)(),n=p.default.join(e,".socket-ipc",t);return p.default.join(n,`stub-${process.pid}.json`)}async function C(t){const e=p.default.dirname(t);await c.promises.mkdir(e,{recursive:!0})}async function H(t,e){const n=x(t);await C(n);const o={data:e,pid:process.pid,timestamp:Date.now()},s=I.parse(o);return await c.promises.writeFile(n,JSON.stringify(s,null,2),"utf8"),n}async function W(t){try{const e=await c.promises.readFile(t,"utf8"),n=JSON.parse(e),o=I.parse(n),s=Date.now()-o.timestamp,a=300*1e3;if(s>a){try{(0,g.safeDeleteSync)(t,{force:!0})}catch{}return null}return o.data}catch{return null}}async function z(t){const e=(0,h.getOsTmpDir)(),n=p.default.join(e,".socket-ipc",t);try{const o=await c.promises.readdir(n),s=Date.now(),a=300*1e3;await Promise.all(o.map(async r=>{if(r.startsWith("stub-")&&r.endsWith(".json")){const u=p.default.join(n,r);try{const b=await c.promises.stat(u);let f=s-b.mtimeMs>a;try{const M=await c.promises.readFile(u,"utf8"),T=JSON.parse(M),D=I.parse(T),j=s-D.timestamp;f=f||j>a}catch{}f&&(0,g.safeDeleteSync)(u,{force:!0})}catch{}}}))}catch{}}function _(t,e){if(t&&typeof t=="object"&&"send"in t&&typeof t.send=="function")try{const n=w.parse(e);return t.send(n)}catch{return!1}return!1}function S(t){const e=n=>{const o=v(n);o&&t(o)};return process.on("message",e),()=>{process.off("message",e)}}function q(t,e={}){const{timeout:n=3e4}=e;return new Promise((o,s)=>{let a=null,r=null;const u=()=>{a&&a(),s(new Error(`IPC timeout waiting for message type: ${t}`))};a=S(d=>{d.type===t&&(r&&clearTimeout(r),a&&a(),o(d.data))}),n>0&&(r=setTimeout(u,n))})}function G(t,e){return{id:l.default.randomBytes(16).toString("hex"),timestamp:Date.now(),type:t,data:e}}function K(t){return!!(t&&typeof t=="object"&&"send"in t&&typeof t.send=="function"&&"channel"in t&&t.channel!==void 0)}function v(t){try{return w.parse(t)}catch{return null}}0&&(module.exports={IpcHandshakeSchema,cleanupIpcStubs,createIpcChannelId,createIpcMessage,getIpcStubPath,hasIpcChannel,onIpc,parseIpcMessage,readIpcStub,sendIpc,waitForIpc,writeIpcStub});
2
+ var P=Object.create;var m=Object.defineProperty;var N=Object.getOwnPropertyDescriptor;var B=Object.getOwnPropertyNames;var O=Object.getPrototypeOf,A=Object.prototype.hasOwnProperty;var J=(t,e)=>{for(var n in e)m(t,n,{get:e[n],enumerable:!0})},y=(t,e,n,o)=>{if(e&&typeof e=="object"||typeof e=="function")for(let s of B(e))!A.call(t,s)&&s!==n&&m(t,s,{get:()=>e[s],enumerable:!(o=N(e,s))||o.enumerable});return t};var k=(t,e,n)=>(n=t!=null?P(O(t)):{},y(e||!t||!t.__esModule?m(n,"default",{value:t,enumerable:!0}):n,t)),$=t=>y(m({},"__esModule",{value:!0}),t);var L={};J(L,{IpcHandshakeSchema:()=>E,cleanupIpcStubs:()=>z,createIpcChannelId:()=>F,createIpcMessage:()=>G,getIpcStubPath:()=>x,hasIpcChannel:()=>K,onIpc:()=>S,parseIpcMessage:()=>v,readIpcStub:()=>W,sendIpc:()=>_,waitForIpc:()=>q,writeIpcStub:()=>H});module.exports=$(L);var l=k(require("crypto")),c=require("fs"),p=k(require("path")),g=require("./fs"),h=require("./paths"),i=require("./zod");const w=i.z.object({id:i.z.string().min(1),timestamp:i.z.number().positive(),type:i.z.string().min(1),data:i.z.unknown()}),E=w.extend({type:i.z.literal("handshake"),data:i.z.object({version:i.z.string(),pid:i.z.number().int().positive(),apiToken:i.z.string().optional(),appName:i.z.string()})}),I=i.z.object({pid:i.z.number().int().positive(),timestamp:i.z.number().positive(),data:i.z.unknown()});function F(t="socket"){return`${t}-${process.pid}-${l.default.randomBytes(8).toString("hex")}`}function x(t){const e=(0,h.getOsTmpDir)(),n=p.default.join(e,".socket-ipc",t);return p.default.join(n,`stub-${process.pid}.json`)}async function C(t){const e=p.default.dirname(t);await c.promises.mkdir(e,{recursive:!0})}async function H(t,e){const n=x(t);await C(n);const o={data:e,pid:process.pid,timestamp:Date.now()},s=I.parse(o);return await c.promises.writeFile(n,JSON.stringify(s,null,2),"utf8"),n}async function W(t){try{const e=await c.promises.readFile(t,"utf8"),n=JSON.parse(e),o=I.parse(n),s=Date.now()-o.timestamp,a=300*1e3;if(s>a){try{(0,g.safeDeleteSync)(t,{force:!0})}catch{}return null}return o.data}catch{return null}}async function z(t){const e=(0,h.getOsTmpDir)(),n=p.default.join(e,".socket-ipc",t);try{const o=await c.promises.readdir(n),s=Date.now(),a=300*1e3;await Promise.all(o.map(async r=>{if(r.startsWith("stub-")&&r.endsWith(".json")){const u=p.default.join(n,r);try{const b=await c.promises.stat(u);let f=s-b.mtimeMs>a;try{const M=await c.promises.readFile(u,"utf8"),T=JSON.parse(M),D=I.parse(T),j=s-D.timestamp;f=f||j>a}catch{}f&&(0,g.safeDeleteSync)(u,{force:!0})}catch{}}}))}catch{}}function _(t,e){if(t&&typeof t=="object"&&"send"in t&&typeof t.send=="function")try{const n=w.parse(e);return t.send(n)}catch{return!1}return!1}function S(t){const e=n=>{const o=v(n);o&&t(o)};return process.on("message",e),()=>{process.off("message",e)}}function q(t,e={}){const{timeout:n=3e4}=e;return new Promise((o,s)=>{let a=null,r=null;const u=()=>{a&&a(),s(new Error(`IPC timeout waiting for message type: ${t}`))};a=S(d=>{d.type===t&&(r&&clearTimeout(r),a&&a(),o(d.data))}),n>0&&(r=setTimeout(u,n))})}function G(t,e){return{id:l.default.randomBytes(16).toString("hex"),timestamp:Date.now(),type:t,data:e}}function K(t){return!!(t&&typeof t=="object"&&"send"in t&&typeof t.send=="function"&&"channel"in t&&t.channel!==void 0)}function v(t){try{return w.parse(t)}catch{return null}}0&&(module.exports={IpcHandshakeSchema,cleanupIpcStubs,createIpcChannelId,createIpcMessage,getIpcStubPath,hasIpcChannel,onIpc,parseIpcMessage,readIpcStub,sendIpc,waitForIpc,writeIpcStub});
3
3
  //# sourceMappingURL=ipc.js.map
package/dist/ipc.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/ipc.ts"],
4
- "sourcesContent": ["/**\n * IPC (Inter-Process Communication) Module\n * ==========================================\n *\n * This module provides secure inter-process communication utilities for Socket CLI\n * and related tools. It replaces environment variable passing with more secure and\n * scalable alternatives.\n *\n * ## Key Features:\n * - File-based stub communication for initial data handoff\n * - Node.js IPC channel support for real-time bidirectional messaging\n * - Automatic cleanup of temporary files\n * - Type-safe message validation with Zod schemas\n * - Timeout handling for reliability\n *\n * ## Use Cases:\n * 1. Passing API tokens between processes without exposing them in env vars\n * 2. Transferring large configuration objects that exceed env var size limits\n * 3. Bidirectional communication between parent and child processes\n * 4. Secure handshake protocols between Socket CLI components\n *\n * ## Security Considerations:\n * - Stub files are created with restricted permissions in OS temp directory\n * - Messages include timestamps for freshness validation\n * - Automatic cleanup prevents sensitive data persistence\n * - Unique IDs prevent message replay attacks\n *\n * @module ipc\n */\n\nimport crypto from 'node:crypto'\nimport { promises as fs } from 'node:fs'\nimport path from 'node:path'\n\nimport { safeDeleteSync } from './fs'\nimport { getOsTmpDir } from './paths'\nimport { z } from './zod'\n\n// Define BufferEncoding type for TypeScript compatibility.\ntype BufferEncoding = globalThis.BufferEncoding\n\n/**\n * Zod Schemas for Runtime Validation\n * ====================================\n * These schemas provide runtime type safety for IPC messages,\n * ensuring data integrity across process boundaries.\n */\n\n/**\n * Base IPC message schema - validates the core message structure.\n * All IPC messages must conform to this schema.\n */\nconst IpcMessageSchema = z.object({\n /** Unique identifier for message tracking and response correlation. */\n id: z.string().min(1),\n /** Unix timestamp for freshness validation and replay prevention. */\n timestamp: z.number().positive(),\n /** Message type identifier for routing and handling. */\n type: z.string().min(1),\n /** Payload data - can be any JSON-serializable value. */\n data: z.unknown(),\n})\n\n/**\n * IPC handshake schema - used for initial connection establishment.\n * The handshake includes version info and authentication tokens.\n * @internal Exported for testing purposes.\n */\nexport const IpcHandshakeSchema = IpcMessageSchema.extend({\n type: z.literal('handshake'),\n data: z.object({\n /** Protocol version for compatibility checking. */\n version: z.string(),\n /** Process ID for identification. */\n pid: z.number().int().positive(),\n /** Optional API token for authentication. */\n apiToken: z.string().optional(),\n /** Application name for multi-app support. */\n appName: z.string(),\n }),\n})\n\n/**\n * IPC stub file schema - validates the structure of stub files.\n * Stub files are used for passing data between processes via filesystem.\n */\nconst IpcStubSchema = z.object({\n /** Process ID that created the stub. */\n pid: z.number().int().positive(),\n /** Creation timestamp for age validation. */\n timestamp: z.number().positive(),\n /** The actual data payload. */\n data: z.unknown(),\n})\n\n/**\n * TypeScript interfaces for IPC communication.\n * These types ensure type consistency across the IPC module.\n */\n\n/**\n * Base IPC message interface.\n * All IPC messages must conform to this structure.\n */\nexport interface IpcMessage<T = unknown> {\n /** Unique identifier for message tracking and response correlation. */\n id: string\n /** Unix timestamp for freshness validation and replay prevention. */\n timestamp: number\n /** Message type identifier for routing and handling. */\n type: string\n /** Payload data - can be any JSON-serializable value. */\n data: T\n}\n\n/**\n * IPC handshake message interface.\n * Used for initial connection establishment.\n */\nexport interface IpcHandshake\n extends IpcMessage<{\n /** Protocol version for compatibility checking. */\n version: string\n /** Process ID for identification. */\n pid: number\n /** Optional API token for authentication. */\n apiToken?: string\n /** Application name for multi-app support. */\n appName: string\n }> {\n type: 'handshake'\n}\n\n/**\n * IPC stub file interface.\n * Represents the structure of stub files used for filesystem-based IPC.\n */\nexport interface IpcStub {\n /** Process ID that created the stub. */\n pid: number\n /** Creation timestamp for age validation. */\n timestamp: number\n /** The actual data payload. */\n data: unknown\n}\n\n/**\n * Options for IPC communication\n */\nexport interface IpcOptions {\n /** Timeout in milliseconds for async operations. */\n timeout?: number\n /** Text encoding for message serialization. */\n encoding?: BufferEncoding\n}\n\n/**\n * Create a unique IPC channel identifier for message correlation.\n *\n * Generates a unique identifier that combines:\n * - A prefix for namespacing (defaults to 'socket')\n * - The current process ID for process identification\n * - A random hex string for uniqueness\n *\n * @param prefix - Optional prefix to namespace the channel ID\n * @returns A unique channel identifier string\n *\n * @example\n * ```typescript\n * const channelId = createIpcChannelId('socket-cli')\n * // Returns: 'socket-cli-12345-a1b2c3d4e5f6g7h8'\n * ```\n */\nexport function createIpcChannelId(prefix = 'socket'): string {\n return `${prefix}-${process.pid}-${crypto.randomBytes(8).toString('hex')}`\n}\n\n/**\n * Get the IPC stub path for a given application.\n *\n * This function generates a unique file path for IPC stub files that are used\n * to pass data between processes. The stub files are stored in a hidden directory\n * within the system's temporary folder.\n *\n * ## Path Structure:\n * - Base: System temp directory (e.g., /tmp on Unix, %TEMP% on Windows)\n * - Directory: `.socket-ipc/{appName}/`\n * - Filename: `stub-{pid}.json`\n *\n * ## Security Features:\n * - Files are isolated per application via appName parameter\n * - Process ID in filename prevents collisions between concurrent processes\n * - Temporary directory location ensures automatic cleanup on system restart\n *\n * @param appName - The application identifier (e.g., 'socket-cli', 'socket-dlx')\n * @returns Full path to the IPC stub file\n *\n * @example\n * ```typescript\n * const stubPath = getIpcStubPath('socket-cli')\n * // Returns: '/tmp/.socket-ipc/socket-cli/stub-12345.json' (Unix)\n * // Returns: 'C:\\\\Users\\\\Name\\\\AppData\\\\Local\\\\Temp\\\\.socket-ipc\\\\socket-cli\\\\stub-12345.json' (Windows)\n * ```\n *\n * @used Currently used by socket-cli for self-update and inter-process communication\n */\nexport function getIpcStubPath(appName: string): string {\n // Get the system's temporary directory - this is platform-specific.\n const tempDir = getOsTmpDir()\n\n // Create a hidden directory structure for Socket IPC files.\n // The dot prefix makes it hidden on Unix-like systems.\n const stubDir = path.join(tempDir, '.socket-ipc', appName)\n\n // Generate filename with process ID to ensure uniqueness.\n // The PID prevents conflicts when multiple processes run simultaneously.\n return path.join(stubDir, `stub-${process.pid}.json`)\n}\n\n/**\n * Ensure IPC directory exists for stub file creation.\n *\n * This helper function creates the directory structure needed for IPC stub files.\n * It's called before writing stub files to ensure the parent directories exist.\n *\n * @param filePath - Full path to the file that needs its directory created\n * @returns Promise that resolves when directory is created\n *\n * @internal Helper function used by writeIpcStub\n */\nasync function ensureIpcDirectory(filePath: string): Promise<void> {\n const dir = path.dirname(filePath)\n // Create directory recursively if it doesn't exist.\n await fs.mkdir(dir, { recursive: true })\n}\n\n/**\n * Write IPC data to a stub file for inter-process data transfer.\n *\n * This function creates a stub file containing data that needs to be passed\n * between processes. The stub file includes metadata like process ID and\n * timestamp for validation.\n *\n * ## File Structure:\n * ```json\n * {\n * \"pid\": 12345,\n * \"timestamp\": 1699564234567,\n * \"data\": { ... }\n * }\n * ```\n *\n * ## Use Cases:\n * - Passing API tokens to child processes\n * - Transferring configuration between Socket CLI components\n * - Sharing large data that exceeds environment variable limits\n *\n * @param appName - The application identifier\n * @param data - The data to write to the stub file\n * @returns Promise resolving to the stub file path\n *\n * @example\n * ```typescript\n * const stubPath = await writeIpcStub('socket-cli', {\n * apiToken: 'secret-token',\n * config: { ... }\n * })\n * // Pass stubPath to child process for reading\n * ```\n */\nexport async function writeIpcStub(\n appName: string,\n data: unknown,\n): Promise<string> {\n const stubPath = getIpcStubPath(appName)\n await ensureIpcDirectory(stubPath)\n\n // Create stub data with validation metadata.\n const ipcData: IpcStub = {\n data,\n pid: process.pid,\n timestamp: Date.now(),\n }\n\n // Validate data structure with Zod schema.\n const validated = IpcStubSchema.parse(ipcData)\n\n // Write with pretty printing for debugging.\n await fs.writeFile(stubPath, JSON.stringify(validated, null, 2), 'utf8')\n return stubPath\n}\n\n/**\n * Read IPC data from a stub file with automatic cleanup.\n *\n * This function reads data from an IPC stub file and validates its freshness.\n * Stale files (older than 5 minutes) are automatically cleaned up to prevent\n * accumulation of temporary files.\n *\n * ## Validation Steps:\n * 1. Read and parse JSON file\n * 2. Validate structure with Zod schema\n * 3. Check timestamp freshness\n * 4. Clean up if stale\n * 5. Return data if valid\n *\n * @param stubPath - Path to the stub file to read\n * @returns Promise resolving to the data or null if invalid/stale\n *\n * @example\n * ```typescript\n * const data = await readIpcStub('/tmp/.socket-ipc/socket-cli/stub-12345.json')\n * if (data) {\n * console.log('Received:', data)\n * }\n * ```\n *\n * @unused Reserved for future implementation\n */\nexport async function readIpcStub(stubPath: string): Promise<unknown> {\n try {\n const content = await fs.readFile(stubPath, 'utf8')\n const parsed = JSON.parse(content)\n // Validate structure with Zod schema.\n const validated = IpcStubSchema.parse(parsed)\n // Check age for freshness validation.\n const ageMs = Date.now() - validated.timestamp\n // 5 minutes.\n const maxAgeMs = 5 * 60 * 1000\n if (ageMs > maxAgeMs) {\n // Clean up stale file. IPC stubs are always in tmpdir, so use force: true.\n try {\n safeDeleteSync(stubPath, { force: true })\n } catch {\n // Ignore deletion errors\n }\n return null\n }\n return validated.data\n } catch {\n // Return null for any errors (file not found, invalid JSON, validation failure).\n return null\n }\n}\n\n/**\n * Clean up IPC stub files for an application.\n *\n * This maintenance function removes stale IPC stub files to prevent\n * accumulation in the temporary directory. It's designed to be called\n * periodically or on application startup.\n *\n * ## Cleanup Rules:\n * - Files older than 5 minutes are removed (checked via both filesystem mtime and JSON timestamp)\n * - Only stub files (stub-*.json) are processed\n * - Errors are silently ignored (best-effort cleanup)\n *\n * @param appName - The application identifier\n * @returns Promise that resolves when cleanup is complete\n *\n * @example\n * ```typescript\n * // Clean up on application startup\n * await cleanupIpcStubs('socket-cli')\n * ```\n *\n * @unused Reserved for future implementation\n */\nexport async function cleanupIpcStubs(appName: string): Promise<void> {\n const tempDir = getOsTmpDir()\n const stubDir = path.join(tempDir, '.socket-ipc', appName)\n try {\n const files = await fs.readdir(stubDir)\n const now = Date.now()\n // 5 minutes.\n const maxAgeMs = 5 * 60 * 1000\n // Process each file in parallel for efficiency.\n await Promise.all(\n files.map(async file => {\n if (file.startsWith('stub-') && file.endsWith('.json')) {\n const filePath = path.join(stubDir, file)\n try {\n // Check both filesystem mtime and JSON timestamp for more reliable detection\n const stats = await fs.stat(filePath)\n const mtimeAge = now - stats.mtimeMs\n let isStale = mtimeAge > maxAgeMs\n\n // Always check the timestamp inside the JSON file for accuracy\n // This is more reliable than filesystem mtime in some environments\n try {\n const content = await fs.readFile(filePath, 'utf8')\n const parsed = JSON.parse(content)\n const validated = IpcStubSchema.parse(parsed)\n const contentAge = now - validated.timestamp\n // File is stale if EITHER check indicates staleness\n isStale = isStale || contentAge > maxAgeMs\n } catch {\n // If we can't read/parse the file, rely on mtime check\n }\n\n if (isStale) {\n // IPC stubs are always in tmpdir, so we can use force: true to skip path checks\n safeDeleteSync(filePath, { force: true })\n }\n } catch {\n // Ignore errors for individual files.\n }\n }\n }),\n )\n } catch {\n // Directory might not exist, that's ok.\n }\n}\n\n/**\n * Send data through Node.js IPC channel.\n *\n * This function sends structured messages through the Node.js IPC channel\n * when available. The IPC channel must be established with stdio: ['pipe', 'pipe', 'pipe', 'ipc'].\n *\n * ## Requirements:\n * - Process must have been spawned with IPC channel enabled\n * - Message must be serializable to JSON\n * - Process.send() must be available\n *\n * @param process - The process object with IPC channel\n * @param message - The IPC message to send\n * @returns true if message was sent, false otherwise\n *\n * @example\n * ```typescript\n * const message = createIpcMessage('handshake', { version: '1.0.0' })\n * const sent = sendIpc(childProcess, message)\n * ```\n *\n * @unused Reserved for bidirectional communication implementation\n */\nexport function sendIpc(\n process: NodeJS.Process | unknown,\n message: IpcMessage,\n): boolean {\n if (\n process &&\n typeof process === 'object' &&\n 'send' in process &&\n typeof process.send === 'function'\n ) {\n try {\n // Validate message structure before sending.\n const validated = IpcMessageSchema.parse(message)\n return process.send(validated)\n } catch {\n return false\n }\n }\n return false\n}\n\n/**\n * Receive data through Node.js IPC channel.\n *\n * Sets up a listener for IPC messages with automatic validation and parsing.\n * Returns a cleanup function to remove the listener when no longer needed.\n *\n * ## Message Flow:\n * 1. Receive raw message from IPC channel\n * 2. Validate with parseIpcMessage\n * 3. Call handler if valid\n * 4. Ignore invalid messages\n *\n * @param handler - Function to call with valid IPC messages\n * @returns Cleanup function to remove the listener\n *\n * @example\n * ```typescript\n * const cleanup = onIpc((message) => {\n * console.log('Received:', message.type, message.data)\n * })\n * // Later...\n * cleanup() // Remove listener\n * ```\n *\n * @unused Reserved for bidirectional communication\n */\nexport function onIpc(handler: (message: IpcMessage) => void): () => void {\n const listener = (message: unknown) => {\n const parsed = parseIpcMessage(message)\n if (parsed) {\n handler(parsed)\n }\n }\n process.on('message', listener)\n // Return cleanup function for proper resource management.\n return () => {\n process.off('message', listener)\n }\n}\n\n/**\n * Create a promise that resolves when a specific IPC message is received.\n *\n * This utility function provides async/await support for IPC communication,\n * allowing you to wait for specific message types with timeout support.\n *\n * ## Features:\n * - Automatic timeout handling\n * - Type-safe message data\n * - Resource cleanup on completion\n * - Promise-based API\n *\n * @param messageType - The message type to wait for\n * @param options - Options including timeout configuration\n * @returns Promise resolving to the message data\n *\n * @example\n * ```typescript\n * try {\n * const response = await waitForIpc<ConfigData>('config-response', {\n * timeout: 5000 // 5 seconds\n * })\n * console.log('Config received:', response)\n * } catch (error) {\n * console.error('Timeout waiting for config')\n * }\n * ```\n *\n * @unused Reserved for request-response pattern implementation\n */\nexport function waitForIpc<T = unknown>(\n messageType: string,\n options: IpcOptions = {},\n): Promise<T> {\n const { timeout = 30_000 } = options\n return new Promise((resolve, reject) => {\n let cleanup: (() => void) | null = null\n let timeoutId: NodeJS.Timeout | null = null\n const handleTimeout = () => {\n if (cleanup) {\n cleanup()\n }\n reject(new Error(`IPC timeout waiting for message type: ${messageType}`))\n }\n const handleMessage = (message: IpcMessage) => {\n if (message.type === messageType) {\n if (timeoutId) {\n clearTimeout(timeoutId)\n }\n if (cleanup) {\n cleanup()\n }\n resolve(message.data as T)\n }\n }\n cleanup = onIpc(handleMessage)\n if (timeout > 0) {\n timeoutId = setTimeout(handleTimeout, timeout)\n }\n })\n}\n\n/**\n * Create an IPC message with proper structure and metadata.\n *\n * This factory function creates properly structured IPC messages with:\n * - Unique ID for tracking\n * - Timestamp for freshness\n * - Type for routing\n * - Data payload\n *\n * @param type - The message type identifier\n * @param data - The message payload\n * @returns A properly structured IPC message\n *\n * @example\n * ```typescript\n * const handshake = createIpcMessage('handshake', {\n * version: '1.0.0',\n * pid: process.pid,\n * appName: 'socket-cli'\n * })\n * ```\n *\n * @unused Reserved for future message creation needs\n */\nexport function createIpcMessage<T = unknown>(\n type: string,\n data: T,\n): IpcMessage<T> {\n return {\n id: crypto.randomBytes(16).toString('hex'),\n timestamp: Date.now(),\n type,\n data,\n }\n}\n\n/**\n * Check if process has IPC channel available.\n *\n * This utility checks whether a process object has the necessary\n * properties for IPC communication. Used to determine if IPC\n * messaging is possible before attempting to send.\n *\n * @param process - The process object to check\n * @returns true if IPC is available, false otherwise\n *\n * @example\n * ```typescript\n * if (hasIpcChannel(childProcess)) {\n * sendIpc(childProcess, message)\n * } else {\n * // Fall back to alternative communication method\n * }\n * ```\n *\n * @unused Reserved for IPC availability detection\n */\nexport function hasIpcChannel(process: unknown): boolean {\n return Boolean(\n process &&\n typeof process === 'object' &&\n 'send' in process &&\n typeof process.send === 'function' &&\n 'channel' in process &&\n process.channel !== undefined,\n )\n}\n\n/**\n * Safely parse and validate IPC messages.\n *\n * This function performs runtime validation of incoming messages\n * to ensure they conform to the IPC message structure. It uses\n * Zod schemas for robust validation.\n *\n * ## Validation Steps:\n * 1. Check if message is an object\n * 2. Validate required fields exist\n * 3. Validate field types\n * 4. Return typed message or null\n *\n * @param message - The raw message to parse\n * @returns Parsed IPC message or null if invalid\n *\n * @example\n * ```typescript\n * const parsed = parseIpcMessage(rawMessage)\n * if (parsed) {\n * handleMessage(parsed)\n * }\n * ```\n *\n * @unused Reserved for message validation needs\n */\nexport function parseIpcMessage(message: unknown): IpcMessage | null {\n try {\n // Use Zod schema for comprehensive validation.\n const validated = IpcMessageSchema.parse(message)\n return validated as IpcMessage\n } catch {\n // Return null for any validation failure.\n return null\n }\n}\n"],
5
- "mappings": "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",
6
- "names": ["ipc_exports", "__export", "IpcHandshakeSchema", "cleanupIpcStubs", "createIpcChannelId", "createIpcMessage", "getIpcStubPath", "hasIpcChannel", "onIpc", "parseIpcMessage", "readIpcStub", "sendIpc", "waitForIpc", "writeIpcStub", "__toCommonJS", "import_node_crypto", "import_node_fs", "import_node_path", "import_fs", "import_paths", "import_zod", "IpcMessageSchema", "IpcStubSchema", "prefix", "crypto", "appName", "tempDir", "stubDir", "path", "ensureIpcDirectory", "filePath", "dir", "fs", "data", "stubPath", "ipcData", "validated", "content", "parsed", "ageMs", "maxAgeMs", "files", "now", "file", "stats", "isStale", "contentAge", "process", "message", "handler", "listener", "messageType", "options", "timeout", "resolve", "reject", "cleanup", "timeoutId", "handleTimeout", "type"]
4
+ "sourcesContent": ["/**\n * IPC (Inter-Process Communication) Module\n * ==========================================\n *\n * This module provides secure inter-process communication utilities for Socket CLI\n * and related tools. It replaces environment variable passing with more secure and\n * scalable alternatives.\n *\n * ## Key Features:\n * - File-based stub communication for initial data handoff\n * - Node.js IPC channel support for real-time bidirectional messaging\n * - Automatic cleanup of temporary files\n * - Type-safe message validation with Zod schemas\n * - Timeout handling for reliability\n *\n * ## Use Cases:\n * 1. Passing API tokens between processes without exposing them in env vars\n * 2. Transferring large configuration objects that exceed env var size limits\n * 3. Bidirectional communication between parent and child processes\n * 4. Secure handshake protocols between Socket CLI components\n *\n * ## Security Considerations:\n * - Stub files are created with restricted permissions in OS temp directory\n * - Messages include timestamps for freshness validation\n * - Automatic cleanup prevents sensitive data persistence\n * - Unique IDs prevent message replay attacks\n *\n * @module ipc\n */\n\nimport crypto from 'crypto'\n\nimport { promises as fs } from 'fs'\n\nimport path from 'path'\n\nimport { safeDeleteSync } from './fs'\nimport { getOsTmpDir } from './paths'\nimport { z } from './zod'\n\n// Define BufferEncoding type for TypeScript compatibility.\ntype BufferEncoding = globalThis.BufferEncoding\n\n/**\n * Zod Schemas for Runtime Validation\n * ====================================\n * These schemas provide runtime type safety for IPC messages,\n * ensuring data integrity across process boundaries.\n */\n\n/**\n * Base IPC message schema - validates the core message structure.\n * All IPC messages must conform to this schema.\n */\nconst IpcMessageSchema = z.object({\n /** Unique identifier for message tracking and response correlation. */\n id: z.string().min(1),\n /** Unix timestamp for freshness validation and replay prevention. */\n timestamp: z.number().positive(),\n /** Message type identifier for routing and handling. */\n type: z.string().min(1),\n /** Payload data - can be any JSON-serializable value. */\n data: z.unknown(),\n})\n\n/**\n * IPC handshake schema - used for initial connection establishment.\n * The handshake includes version info and authentication tokens.\n * @internal Exported for testing purposes.\n */\nexport const IpcHandshakeSchema = IpcMessageSchema.extend({\n type: z.literal('handshake'),\n data: z.object({\n /** Protocol version for compatibility checking. */\n version: z.string(),\n /** Process ID for identification. */\n pid: z.number().int().positive(),\n /** Optional API token for authentication. */\n apiToken: z.string().optional(),\n /** Application name for multi-app support. */\n appName: z.string(),\n }),\n})\n\n/**\n * IPC stub file schema - validates the structure of stub files.\n * Stub files are used for passing data between processes via filesystem.\n */\nconst IpcStubSchema = z.object({\n /** Process ID that created the stub. */\n pid: z.number().int().positive(),\n /** Creation timestamp for age validation. */\n timestamp: z.number().positive(),\n /** The actual data payload. */\n data: z.unknown(),\n})\n\n/**\n * TypeScript interfaces for IPC communication.\n * These types ensure type consistency across the IPC module.\n */\n\n/**\n * Base IPC message interface.\n * All IPC messages must conform to this structure.\n */\nexport interface IpcMessage<T = unknown> {\n /** Unique identifier for message tracking and response correlation. */\n id: string\n /** Unix timestamp for freshness validation and replay prevention. */\n timestamp: number\n /** Message type identifier for routing and handling. */\n type: string\n /** Payload data - can be any JSON-serializable value. */\n data: T\n}\n\n/**\n * IPC handshake message interface.\n * Used for initial connection establishment.\n */\nexport interface IpcHandshake\n extends IpcMessage<{\n /** Protocol version for compatibility checking. */\n version: string\n /** Process ID for identification. */\n pid: number\n /** Optional API token for authentication. */\n apiToken?: string\n /** Application name for multi-app support. */\n appName: string\n }> {\n type: 'handshake'\n}\n\n/**\n * IPC stub file interface.\n * Represents the structure of stub files used for filesystem-based IPC.\n */\nexport interface IpcStub {\n /** Process ID that created the stub. */\n pid: number\n /** Creation timestamp for age validation. */\n timestamp: number\n /** The actual data payload. */\n data: unknown\n}\n\n/**\n * Options for IPC communication\n */\nexport interface IpcOptions {\n /** Timeout in milliseconds for async operations. */\n timeout?: number\n /** Text encoding for message serialization. */\n encoding?: BufferEncoding\n}\n\n/**\n * Create a unique IPC channel identifier for message correlation.\n *\n * Generates a unique identifier that combines:\n * - A prefix for namespacing (defaults to 'socket')\n * - The current process ID for process identification\n * - A random hex string for uniqueness\n *\n * @param prefix - Optional prefix to namespace the channel ID\n * @returns A unique channel identifier string\n *\n * @example\n * ```typescript\n * const channelId = createIpcChannelId('socket-cli')\n * // Returns: 'socket-cli-12345-a1b2c3d4e5f6g7h8'\n * ```\n */\nexport function createIpcChannelId(prefix = 'socket'): string {\n return `${prefix}-${process.pid}-${crypto.randomBytes(8).toString('hex')}`\n}\n\n/**\n * Get the IPC stub path for a given application.\n *\n * This function generates a unique file path for IPC stub files that are used\n * to pass data between processes. The stub files are stored in a hidden directory\n * within the system's temporary folder.\n *\n * ## Path Structure:\n * - Base: System temp directory (e.g., /tmp on Unix, %TEMP% on Windows)\n * - Directory: `.socket-ipc/{appName}/`\n * - Filename: `stub-{pid}.json`\n *\n * ## Security Features:\n * - Files are isolated per application via appName parameter\n * - Process ID in filename prevents collisions between concurrent processes\n * - Temporary directory location ensures automatic cleanup on system restart\n *\n * @param appName - The application identifier (e.g., 'socket-cli', 'socket-dlx')\n * @returns Full path to the IPC stub file\n *\n * @example\n * ```typescript\n * const stubPath = getIpcStubPath('socket-cli')\n * // Returns: '/tmp/.socket-ipc/socket-cli/stub-12345.json' (Unix)\n * // Returns: 'C:\\\\Users\\\\Name\\\\AppData\\\\Local\\\\Temp\\\\.socket-ipc\\\\socket-cli\\\\stub-12345.json' (Windows)\n * ```\n *\n * @used Currently used by socket-cli for self-update and inter-process communication\n */\nexport function getIpcStubPath(appName: string): string {\n // Get the system's temporary directory - this is platform-specific.\n const tempDir = getOsTmpDir()\n\n // Create a hidden directory structure for Socket IPC files.\n // The dot prefix makes it hidden on Unix-like systems.\n const stubDir = path.join(tempDir, '.socket-ipc', appName)\n\n // Generate filename with process ID to ensure uniqueness.\n // The PID prevents conflicts when multiple processes run simultaneously.\n return path.join(stubDir, `stub-${process.pid}.json`)\n}\n\n/**\n * Ensure IPC directory exists for stub file creation.\n *\n * This helper function creates the directory structure needed for IPC stub files.\n * It's called before writing stub files to ensure the parent directories exist.\n *\n * @param filePath - Full path to the file that needs its directory created\n * @returns Promise that resolves when directory is created\n *\n * @internal Helper function used by writeIpcStub\n */\nasync function ensureIpcDirectory(filePath: string): Promise<void> {\n const dir = path.dirname(filePath)\n // Create directory recursively if it doesn't exist.\n await fs.mkdir(dir, { recursive: true })\n}\n\n/**\n * Write IPC data to a stub file for inter-process data transfer.\n *\n * This function creates a stub file containing data that needs to be passed\n * between processes. The stub file includes metadata like process ID and\n * timestamp for validation.\n *\n * ## File Structure:\n * ```json\n * {\n * \"pid\": 12345,\n * \"timestamp\": 1699564234567,\n * \"data\": { ... }\n * }\n * ```\n *\n * ## Use Cases:\n * - Passing API tokens to child processes\n * - Transferring configuration between Socket CLI components\n * - Sharing large data that exceeds environment variable limits\n *\n * @param appName - The application identifier\n * @param data - The data to write to the stub file\n * @returns Promise resolving to the stub file path\n *\n * @example\n * ```typescript\n * const stubPath = await writeIpcStub('socket-cli', {\n * apiToken: 'secret-token',\n * config: { ... }\n * })\n * // Pass stubPath to child process for reading\n * ```\n */\nexport async function writeIpcStub(\n appName: string,\n data: unknown,\n): Promise<string> {\n const stubPath = getIpcStubPath(appName)\n await ensureIpcDirectory(stubPath)\n\n // Create stub data with validation metadata.\n const ipcData: IpcStub = {\n data,\n pid: process.pid,\n timestamp: Date.now(),\n }\n\n // Validate data structure with Zod schema.\n const validated = IpcStubSchema.parse(ipcData)\n\n // Write with pretty printing for debugging.\n await fs.writeFile(stubPath, JSON.stringify(validated, null, 2), 'utf8')\n return stubPath\n}\n\n/**\n * Read IPC data from a stub file with automatic cleanup.\n *\n * This function reads data from an IPC stub file and validates its freshness.\n * Stale files (older than 5 minutes) are automatically cleaned up to prevent\n * accumulation of temporary files.\n *\n * ## Validation Steps:\n * 1. Read and parse JSON file\n * 2. Validate structure with Zod schema\n * 3. Check timestamp freshness\n * 4. Clean up if stale\n * 5. Return data if valid\n *\n * @param stubPath - Path to the stub file to read\n * @returns Promise resolving to the data or null if invalid/stale\n *\n * @example\n * ```typescript\n * const data = await readIpcStub('/tmp/.socket-ipc/socket-cli/stub-12345.json')\n * if (data) {\n * console.log('Received:', data)\n * }\n * ```\n *\n * @unused Reserved for future implementation\n */\nexport async function readIpcStub(stubPath: string): Promise<unknown> {\n try {\n const content = await fs.readFile(stubPath, 'utf8')\n const parsed = JSON.parse(content)\n // Validate structure with Zod schema.\n const validated = IpcStubSchema.parse(parsed)\n // Check age for freshness validation.\n const ageMs = Date.now() - validated.timestamp\n // 5 minutes.\n const maxAgeMs = 5 * 60 * 1000\n if (ageMs > maxAgeMs) {\n // Clean up stale file. IPC stubs are always in tmpdir, so use force: true.\n try {\n safeDeleteSync(stubPath, { force: true })\n } catch {\n // Ignore deletion errors\n }\n return null\n }\n return validated.data\n } catch {\n // Return null for any errors (file not found, invalid JSON, validation failure).\n return null\n }\n}\n\n/**\n * Clean up IPC stub files for an application.\n *\n * This maintenance function removes stale IPC stub files to prevent\n * accumulation in the temporary directory. It's designed to be called\n * periodically or on application startup.\n *\n * ## Cleanup Rules:\n * - Files older than 5 minutes are removed (checked via both filesystem mtime and JSON timestamp)\n * - Only stub files (stub-*.json) are processed\n * - Errors are silently ignored (best-effort cleanup)\n *\n * @param appName - The application identifier\n * @returns Promise that resolves when cleanup is complete\n *\n * @example\n * ```typescript\n * // Clean up on application startup\n * await cleanupIpcStubs('socket-cli')\n * ```\n *\n * @unused Reserved for future implementation\n */\nexport async function cleanupIpcStubs(appName: string): Promise<void> {\n const tempDir = getOsTmpDir()\n const stubDir = path.join(tempDir, '.socket-ipc', appName)\n try {\n const files = await fs.readdir(stubDir)\n const now = Date.now()\n // 5 minutes.\n const maxAgeMs = 5 * 60 * 1000\n // Process each file in parallel for efficiency.\n await Promise.all(\n files.map(async file => {\n if (file.startsWith('stub-') && file.endsWith('.json')) {\n const filePath = path.join(stubDir, file)\n try {\n // Check both filesystem mtime and JSON timestamp for more reliable detection\n const stats = await fs.stat(filePath)\n const mtimeAge = now - stats.mtimeMs\n let isStale = mtimeAge > maxAgeMs\n\n // Always check the timestamp inside the JSON file for accuracy\n // This is more reliable than filesystem mtime in some environments\n try {\n const content = await fs.readFile(filePath, 'utf8')\n const parsed = JSON.parse(content)\n const validated = IpcStubSchema.parse(parsed)\n const contentAge = now - validated.timestamp\n // File is stale if EITHER check indicates staleness\n isStale = isStale || contentAge > maxAgeMs\n } catch {\n // If we can't read/parse the file, rely on mtime check\n }\n\n if (isStale) {\n // IPC stubs are always in tmpdir, so we can use force: true to skip path checks\n safeDeleteSync(filePath, { force: true })\n }\n } catch {\n // Ignore errors for individual files.\n }\n }\n }),\n )\n } catch {\n // Directory might not exist, that's ok.\n }\n}\n\n/**\n * Send data through Node.js IPC channel.\n *\n * This function sends structured messages through the Node.js IPC channel\n * when available. The IPC channel must be established with stdio: ['pipe', 'pipe', 'pipe', 'ipc'].\n *\n * ## Requirements:\n * - Process must have been spawned with IPC channel enabled\n * - Message must be serializable to JSON\n * - Process.send() must be available\n *\n * @param process - The process object with IPC channel\n * @param message - The IPC message to send\n * @returns true if message was sent, false otherwise\n *\n * @example\n * ```typescript\n * const message = createIpcMessage('handshake', { version: '1.0.0' })\n * const sent = sendIpc(childProcess, message)\n * ```\n *\n * @unused Reserved for bidirectional communication implementation\n */\nexport function sendIpc(\n process: NodeJS.Process | unknown,\n message: IpcMessage,\n): boolean {\n if (\n process &&\n typeof process === 'object' &&\n 'send' in process &&\n typeof process.send === 'function'\n ) {\n try {\n // Validate message structure before sending.\n const validated = IpcMessageSchema.parse(message)\n return process.send(validated)\n } catch {\n return false\n }\n }\n return false\n}\n\n/**\n * Receive data through Node.js IPC channel.\n *\n * Sets up a listener for IPC messages with automatic validation and parsing.\n * Returns a cleanup function to remove the listener when no longer needed.\n *\n * ## Message Flow:\n * 1. Receive raw message from IPC channel\n * 2. Validate with parseIpcMessage\n * 3. Call handler if valid\n * 4. Ignore invalid messages\n *\n * @param handler - Function to call with valid IPC messages\n * @returns Cleanup function to remove the listener\n *\n * @example\n * ```typescript\n * const cleanup = onIpc((message) => {\n * console.log('Received:', message.type, message.data)\n * })\n * // Later...\n * cleanup() // Remove listener\n * ```\n *\n * @unused Reserved for bidirectional communication\n */\nexport function onIpc(handler: (message: IpcMessage) => void): () => void {\n const listener = (message: unknown) => {\n const parsed = parseIpcMessage(message)\n if (parsed) {\n handler(parsed)\n }\n }\n process.on('message', listener)\n // Return cleanup function for proper resource management.\n return () => {\n process.off('message', listener)\n }\n}\n\n/**\n * Create a promise that resolves when a specific IPC message is received.\n *\n * This utility function provides async/await support for IPC communication,\n * allowing you to wait for specific message types with timeout support.\n *\n * ## Features:\n * - Automatic timeout handling\n * - Type-safe message data\n * - Resource cleanup on completion\n * - Promise-based API\n *\n * @param messageType - The message type to wait for\n * @param options - Options including timeout configuration\n * @returns Promise resolving to the message data\n *\n * @example\n * ```typescript\n * try {\n * const response = await waitForIpc<ConfigData>('config-response', {\n * timeout: 5000 // 5 seconds\n * })\n * console.log('Config received:', response)\n * } catch (error) {\n * console.error('Timeout waiting for config')\n * }\n * ```\n *\n * @unused Reserved for request-response pattern implementation\n */\nexport function waitForIpc<T = unknown>(\n messageType: string,\n options: IpcOptions = {},\n): Promise<T> {\n const { timeout = 30_000 } = options\n return new Promise((resolve, reject) => {\n let cleanup: (() => void) | null = null\n let timeoutId: NodeJS.Timeout | null = null\n const handleTimeout = () => {\n if (cleanup) {\n cleanup()\n }\n reject(new Error(`IPC timeout waiting for message type: ${messageType}`))\n }\n const handleMessage = (message: IpcMessage) => {\n if (message.type === messageType) {\n if (timeoutId) {\n clearTimeout(timeoutId)\n }\n if (cleanup) {\n cleanup()\n }\n resolve(message.data as T)\n }\n }\n cleanup = onIpc(handleMessage)\n if (timeout > 0) {\n timeoutId = setTimeout(handleTimeout, timeout)\n }\n })\n}\n\n/**\n * Create an IPC message with proper structure and metadata.\n *\n * This factory function creates properly structured IPC messages with:\n * - Unique ID for tracking\n * - Timestamp for freshness\n * - Type for routing\n * - Data payload\n *\n * @param type - The message type identifier\n * @param data - The message payload\n * @returns A properly structured IPC message\n *\n * @example\n * ```typescript\n * const handshake = createIpcMessage('handshake', {\n * version: '1.0.0',\n * pid: process.pid,\n * appName: 'socket-cli'\n * })\n * ```\n *\n * @unused Reserved for future message creation needs\n */\nexport function createIpcMessage<T = unknown>(\n type: string,\n data: T,\n): IpcMessage<T> {\n return {\n id: crypto.randomBytes(16).toString('hex'),\n timestamp: Date.now(),\n type,\n data,\n }\n}\n\n/**\n * Check if process has IPC channel available.\n *\n * This utility checks whether a process object has the necessary\n * properties for IPC communication. Used to determine if IPC\n * messaging is possible before attempting to send.\n *\n * @param process - The process object to check\n * @returns true if IPC is available, false otherwise\n *\n * @example\n * ```typescript\n * if (hasIpcChannel(childProcess)) {\n * sendIpc(childProcess, message)\n * } else {\n * // Fall back to alternative communication method\n * }\n * ```\n *\n * @unused Reserved for IPC availability detection\n */\nexport function hasIpcChannel(process: unknown): boolean {\n return Boolean(\n process &&\n typeof process === 'object' &&\n 'send' in process &&\n typeof process.send === 'function' &&\n 'channel' in process &&\n process.channel !== undefined,\n )\n}\n\n/**\n * Safely parse and validate IPC messages.\n *\n * This function performs runtime validation of incoming messages\n * to ensure they conform to the IPC message structure. It uses\n * Zod schemas for robust validation.\n *\n * ## Validation Steps:\n * 1. Check if message is an object\n * 2. Validate required fields exist\n * 3. Validate field types\n * 4. Return typed message or null\n *\n * @param message - The raw message to parse\n * @returns Parsed IPC message or null if invalid\n *\n * @example\n * ```typescript\n * const parsed = parseIpcMessage(rawMessage)\n * if (parsed) {\n * handleMessage(parsed)\n * }\n * ```\n *\n * @unused Reserved for message validation needs\n */\nexport function parseIpcMessage(message: unknown): IpcMessage | null {\n try {\n // Use Zod schema for comprehensive validation.\n const validated = IpcMessageSchema.parse(message)\n return validated as IpcMessage\n } catch {\n // Return null for any validation failure.\n return null\n }\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["ipc_exports", "__export", "IpcHandshakeSchema", "cleanupIpcStubs", "createIpcChannelId", "createIpcMessage", "getIpcStubPath", "hasIpcChannel", "onIpc", "parseIpcMessage", "readIpcStub", "sendIpc", "waitForIpc", "writeIpcStub", "__toCommonJS", "import_crypto", "import_fs", "import_path", "import_paths", "import_zod", "IpcMessageSchema", "IpcStubSchema", "prefix", "crypto", "appName", "tempDir", "stubDir", "path", "ensureIpcDirectory", "filePath", "dir", "fs", "data", "stubPath", "ipcData", "validated", "content", "parsed", "ageMs", "maxAgeMs", "files", "now", "file", "stats", "isStale", "contentAge", "process", "message", "handler", "listener", "messageType", "options", "timeout", "resolve", "reject", "cleanup", "timeoutId", "handleTimeout", "type"]
7
7
  }
@@ -0,0 +1,65 @@
1
+ import type { Theme } from '../themes/types';
2
+ import type { ThemeName } from '../themes/themes';
3
+ /**
4
+ * Options for creating themed links.
5
+ */
6
+ export type LinkOptions = {
7
+ /** Theme to use (overrides global) */
8
+ theme?: Theme | ThemeName | undefined;
9
+ /** Show URL as fallback if terminal doesn't support links */
10
+ fallback?: boolean | undefined;
11
+ };
12
+ /**
13
+ * Create a themed hyperlink for terminal output.
14
+ * The link text is colored using the theme's link color.
15
+ *
16
+ * Note: Most terminals support ANSI color codes but not clickable links.
17
+ * This function colors the text but does not create clickable hyperlinks.
18
+ * For clickable links, use a library like 'terminal-link' separately.
19
+ *
20
+ * @param text - Link text to display
21
+ * @param url - URL (included in fallback mode)
22
+ * @param options - Link configuration options
23
+ * @returns Colored link text
24
+ *
25
+ * @example
26
+ * ```ts
27
+ * import { link } from '@socketsecurity/lib/links'
28
+ *
29
+ * // Use current theme
30
+ * console.log(link('Documentation', 'https://socket.dev'))
31
+ *
32
+ * // Override theme
33
+ * console.log(link('API Docs', 'https://api.socket.dev', {
34
+ * theme: 'coana'
35
+ * }))
36
+ *
37
+ * // Show URL as fallback
38
+ * console.log(link('GitHub', 'https://github.com', {
39
+ * fallback: true
40
+ * }))
41
+ * // Output: "GitHub (https://github.com)"
42
+ * ```
43
+ */
44
+ export declare function link(text: string, url: string, options?: LinkOptions): string;
45
+ /**
46
+ * Create multiple themed links from an array of link specifications.
47
+ *
48
+ * @param links - Array of [text, url] pairs
49
+ * @param options - Link configuration options
50
+ * @returns Array of colored link texts
51
+ *
52
+ * @example
53
+ * ```ts
54
+ * import { links } from '@socketsecurity/lib/links'
55
+ *
56
+ * const formatted = links([
57
+ * ['Documentation', 'https://socket.dev'],
58
+ * ['API Reference', 'https://api.socket.dev'],
59
+ * ['GitHub', 'https://github.com/SocketDev']
60
+ * ])
61
+ *
62
+ * formatted.forEach(link => console.log(link))
63
+ * ```
64
+ */
65
+ export declare function links(linkSpecs: Array<[text: string, url: string]>, options?: LinkOptions): string[];
@@ -0,0 +1,3 @@
1
+ /* Socket Lib - Built with esbuild */
2
+ var k=Object.create;var l=Object.defineProperty;var g=Object.getOwnPropertyDescriptor;var u=Object.getOwnPropertyNames;var d=Object.getPrototypeOf,T=Object.prototype.hasOwnProperty;var C=(e,o)=>{for(var r in o)l(e,r,{get:o[r],enumerable:!0})},a=(e,o,r,t)=>{if(o&&typeof o=="object"||typeof o=="function")for(let n of u(o))!T.call(e,n)&&n!==r&&l(e,n,{get:()=>o[n],enumerable:!(t=g(o,n))||t.enumerable});return e};var b=(e,o,r)=>(r=e!=null?k(d(e)):{},a(o||!e||!e.__esModule?l(r,"default",{value:e,enumerable:!0}):r,e)),L=e=>a(l({},"__esModule",{value:!0}),e);var O={};C(O,{link:()=>y,links:()=>N});module.exports=L(O);var c=b(require("../external/yoctocolors-cjs")),f=require("../themes/context"),h=require("../themes/utils");function y(e,o,r){const t={__proto__:null,fallback:!1,...r},n=typeof t.theme=="string"?require("../themes/themes").THEMES[t.theme]:t.theme??(0,f.getTheme)(),s=(0,h.resolveColor)(n.colors.link,n.colors),m=c.default;let i;if(typeof s=="string"&&s!=="inherit"){const p=m[s];i=p?p(e):m.cyan(e)}else Array.isArray(s),i=m.cyan(e);return t.fallback?`${i} (${o})`:i}function N(e,o){return e.map(([r,t])=>y(r,t,o))}0&&(module.exports={link,links});
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../src/links/index.ts"],
4
+ "sourcesContent": ["/**\n * @fileoverview Themed hyperlink utilities for terminal output.\n * Provides colored hyperlinks using theme configuration.\n */\n\nimport yoctocolorsCjs from '../external/yoctocolors-cjs'\nimport type { ColorName } from '../spinner'\nimport { getTheme } from '../themes/context'\nimport { resolveColor } from '../themes/utils'\nimport type { Theme } from '../themes/types'\nimport type { ThemeName } from '../themes/themes'\n\n/**\n * Options for creating themed links.\n */\nexport type LinkOptions = {\n /** Theme to use (overrides global) */\n theme?: Theme | ThemeName | undefined\n /** Show URL as fallback if terminal doesn't support links */\n fallback?: boolean | undefined\n}\n\n/**\n * Create a themed hyperlink for terminal output.\n * The link text is colored using the theme's link color.\n *\n * Note: Most terminals support ANSI color codes but not clickable links.\n * This function colors the text but does not create clickable hyperlinks.\n * For clickable links, use a library like 'terminal-link' separately.\n *\n * @param text - Link text to display\n * @param url - URL (included in fallback mode)\n * @param options - Link configuration options\n * @returns Colored link text\n *\n * @example\n * ```ts\n * import { link } from '@socketsecurity/lib/links'\n *\n * // Use current theme\n * console.log(link('Documentation', 'https://socket.dev'))\n *\n * // Override theme\n * console.log(link('API Docs', 'https://api.socket.dev', {\n * theme: 'coana'\n * }))\n *\n * // Show URL as fallback\n * console.log(link('GitHub', 'https://github.com', {\n * fallback: true\n * }))\n * // Output: \"GitHub (https://github.com)\"\n * ```\n */\nexport function link(text: string, url: string, options?: LinkOptions): string {\n const opts = { __proto__: null, fallback: false, ...options } as LinkOptions\n\n // Resolve theme\n const theme =\n typeof opts.theme === 'string'\n ? require('../themes/themes').THEMES[opts.theme]\n : (opts.theme ?? getTheme())\n\n // Resolve link color\n const linkColor = resolveColor(theme.colors.link, theme.colors)\n\n // Apply color - for now just use cyan as a simple fallback\n // Note: RGB color support to be added in yoctocolors wrapper\n const colors = yoctocolorsCjs\n let colored: string\n if (typeof linkColor === 'string' && linkColor !== 'inherit') {\n // Use named color method if available\n const colorMethod = colors[linkColor as ColorName]\n colored = colorMethod ? colorMethod(text) : colors.cyan(text)\n } else if (Array.isArray(linkColor)) {\n // RGB color - for now fallback to cyan\n // Note: RGB color support to be implemented\n colored = colors.cyan(text)\n } else {\n colored = colors.cyan(text)\n }\n\n // Return with or without URL fallback\n return opts.fallback ? `${colored} (${url})` : colored\n}\n\n/**\n * Create multiple themed links from an array of link specifications.\n *\n * @param links - Array of [text, url] pairs\n * @param options - Link configuration options\n * @returns Array of colored link texts\n *\n * @example\n * ```ts\n * import { links } from '@socketsecurity/lib/links'\n *\n * const formatted = links([\n * ['Documentation', 'https://socket.dev'],\n * ['API Reference', 'https://api.socket.dev'],\n * ['GitHub', 'https://github.com/SocketDev']\n * ])\n *\n * formatted.forEach(link => console.log(link))\n * ```\n */\nexport function links(\n linkSpecs: Array<[text: string, url: string]>,\n options?: LinkOptions,\n): string[] {\n return linkSpecs.map(([text, url]) => link(text, url, options))\n}\n"],
5
+ "mappings": ";6iBAAA,IAAAA,EAAA,GAAAC,EAAAD,EAAA,UAAAE,EAAA,UAAAC,IAAA,eAAAC,EAAAJ,GAKA,IAAAK,EAA2B,0CAE3BC,EAAyB,6BACzBC,EAA6B,2BA8CtB,SAASL,EAAKM,EAAcC,EAAaC,EAA+B,CAC7E,MAAMC,EAAO,CAAE,UAAW,KAAM,SAAU,GAAO,GAAGD,CAAQ,EAGtDE,EACJ,OAAOD,EAAK,OAAU,SAClB,QAAQ,kBAAkB,EAAE,OAAOA,EAAK,KAAK,EAC5CA,EAAK,UAAS,YAAS,EAGxBE,KAAY,gBAAaD,EAAM,OAAO,KAAMA,EAAM,MAAM,EAIxDE,EAAS,EAAAC,QACf,IAAIC,EACJ,GAAI,OAAOH,GAAc,UAAYA,IAAc,UAAW,CAE5D,MAAMI,EAAcH,EAAOD,CAAsB,EACjDG,EAAUC,EAAcA,EAAYT,CAAI,EAAIM,EAAO,KAAKN,CAAI,CAC9D,MAAW,MAAM,QAAQK,CAAS,EAGhCG,EAAUF,EAAO,KAAKN,CAAI,EAM5B,OAAOG,EAAK,SAAW,GAAGK,CAAO,KAAKP,CAAG,IAAMO,CACjD,CAsBO,SAASb,EACde,EACAR,EACU,CACV,OAAOQ,EAAU,IAAI,CAAC,CAACV,EAAMC,CAAG,IAAMP,EAAKM,EAAMC,EAAKC,CAAO,CAAC,CAChE",
6
+ "names": ["links_exports", "__export", "link", "links", "__toCommonJS", "import_yoctocolors_cjs", "import_context", "import_utils", "text", "url", "options", "opts", "theme", "linkColor", "colors", "yoctocolorsCjs", "colored", "colorMethod", "linkSpecs"]
7
+ }
package/dist/logger.d.ts CHANGED
@@ -63,20 +63,22 @@ export type { LogSymbols, LoggerMethods, Task };
63
63
  * Log symbols for terminal output with colored indicators.
64
64
  *
65
65
  * Provides colored Unicode symbols (✔, ✖, ⚠, ℹ, →) with ASCII fallbacks (√, ×, ‼, i, >)
66
- * for terminals that don't support Unicode. Symbols are color-coded: green for
67
- * success, red for failure, yellow for warnings, blue for info, cyan for step.
66
+ * for terminals that don't support Unicode. Symbols are colored according to the active
67
+ * theme's color palette (success, error, warning, info, step).
68
68
  *
69
- * The symbols are lazily initialized on first access and then frozen for immutability.
69
+ * The symbols are lazily initialized on first access and automatically update when the
70
+ * fallback theme changes (via setTheme()). Note that LOG_SYMBOLS reflect the global
71
+ * fallback theme, not async-local theme contexts from withTheme().
70
72
  *
71
73
  * @example
72
74
  * ```typescript
73
75
  * import { LOG_SYMBOLS } from '@socketsecurity/lib'
74
76
  *
75
- * console.log(`${LOG_SYMBOLS.success} Build completed`) // Green
76
- * console.log(`${LOG_SYMBOLS.fail} Build failed`) // Red
77
- * console.log(`${LOG_SYMBOLS.warn} Deprecated API used`) // Yellow
78
- * console.log(`${LOG_SYMBOLS.info} Starting process`) // Blue
79
- * console.log(`${LOG_SYMBOLS.step} Processing files`) // Cyan
77
+ * console.log(`${LOG_SYMBOLS.success} Build completed`) // Theme success color
78
+ * console.log(`${LOG_SYMBOLS.fail} Build failed`) // Theme error color
79
+ * console.log(`${LOG_SYMBOLS.warn} Deprecated API used`) // Theme warning color
80
+ * console.log(`${LOG_SYMBOLS.info} Starting process`) // Theme info color
81
+ * console.log(`${LOG_SYMBOLS.step} Processing files`) // Theme step color
80
82
  * ```
81
83
  */
82
84
  export declare const LOG_SYMBOLS: Record<string, string>;
@@ -923,21 +925,22 @@ export declare class Logger {
923
925
  clearLine(): this;
924
926
  }
925
927
  /**
926
- * Default logger instance for the application.
928
+ * Get the default logger instance.
929
+ * Lazily creates the logger to avoid circular dependencies during module initialization.
930
+ * Reuses the same instance across calls.
927
931
  *
928
- * A pre-configured `Logger` instance that uses the standard `process.stdout`
929
- * and `process.stderr` streams. This is the recommended logger to import
930
- * and use throughout your application.
932
+ * @returns Shared default logger instance
931
933
  *
932
934
  * @example
933
- * ```typescript
934
- * import { logger } from '@socketsecurity/lib'
935
+ * ```ts
936
+ * import { getDefaultLogger } from '@socketsecurity/lib/logger'
935
937
  *
938
+ * const logger = getDefaultLogger()
936
939
  * logger.log('Application started')
937
940
  * logger.success('Configuration loaded')
938
- * logger.indent()
939
- * logger.log('Using port 3000')
940
- * logger.dedent()
941
941
  * ```
942
942
  */
943
- export declare const logger: Logger;
943
+ export declare function getDefaultLogger(): Logger;
944
+ // REMOVED: Deprecated `logger` export
945
+ // Migration: Use getDefaultLogger() instead
946
+ // See: getDefaultLogger() function above
package/dist/logger.js CHANGED
@@ -1,3 +1,3 @@
1
1
  /* Socket Lib - Built with esbuild */
2
- var j=Object.create;var p=Object.defineProperty;var E=Object.getOwnPropertyDescriptor;var B=Object.getOwnPropertyNames;var M=Object.getPrototypeOf,$=Object.prototype.hasOwnProperty;var K=(o,t)=>{for(var s in t)p(o,s,{get:t[s],enumerable:!0})},T=(o,t,s,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let e of B(t))!$.call(o,e)&&e!==s&&p(o,e,{get:()=>t[e],enumerable:!(n=E(t,e))||n.enumerable});return o};var R=(o,t,s)=>(s=o!=null?j(M(o)):{},T(t||!o||!o.__esModule?p(s,"default",{value:o,enumerable:!0}):s,o)),G=o=>T(p({},"__esModule",{value:!0}),o);var D={};K(D,{LOG_SYMBOLS:()=>y,Logger:()=>h,incLogCallCountSymbol:()=>u,lastWasBlankSymbol:()=>i,logger:()=>F});module.exports=G(D);var I=R(require("./external/@socketregistry/is-unicode-supported")),O=R(require("./external/yoctocolors-cjs")),m=require("./objects"),a=require("./strings");const g=console,_=Reflect.apply,Y=Reflect.construct;let S;function w(...o){return S===void 0&&(S=require("node:console").Console),Y(S,o)}function v(){return O.default}const y=(()=>{const o={__proto__:null},t={__proto__:null},s=()=>{const n=(0,I.default)(),e=v();(0,m.objectAssign)(o,{fail:e.red(n?"\u2716":"\xD7"),info:e.blue(n?"\u2139":"i"),step:e.cyan(n?"\u2192":">"),success:e.green(n?"\u2714":"\u221A"),warn:e.yellow(n?"\u26A0":"\u203C")}),(0,m.objectFreeze)(o);for(const r in t)delete t[r]};for(const n of Reflect.ownKeys(Reflect)){const e=Reflect[n];typeof e=="function"&&(t[n]=(...r)=>(s(),e(...r)))}return new Proxy(o,t)})(),P=["_stderrErrorHandler","_stdoutErrorHandler","assert","clear","count","countReset","createTask","debug","dir","dirxml","error","info","log","table","time","timeEnd","timeLog","trace","warn"].filter(o=>typeof g[o]=="function").map(o=>[o,g[o].bind(g)]),A={__proto__:null,writable:!0,enumerable:!1,configurable:!0},H=1e3,k=new WeakMap,l=new WeakMap;let C;function N(){return C===void 0&&(C=Object.getOwnPropertySymbols(g)),C}const u=Symbol.for("logger.logCallCount++");let L;function x(){return L===void 0&&(L=N().find(o=>o.label==="kGroupIndentWidth")??Symbol("kGroupIndentWidth")),L}const i=Symbol.for("logger.lastWasBlank");class h{static LOG_SYMBOLS=y;#c;#s;#l;#h;#g="";#f="";#p=!1;#y=!1;#a=0;#o;#w;constructor(...t){l.set(this,t);const s=t[0];typeof s=="object"&&s!==null?(this.#o={__proto__:null,...s},this.#w=s.stdout):this.#o={__proto__:null}}#t(){z();let t=k.get(this);if(!t){const s=l.get(this)??[];if(s.length)t=w(...s);else{t=w({stdout:process.stdout,stderr:process.stderr});for(const{0:n,1:e}of P)t[n]=e}k.set(this,t),l.delete(this)}return t}get stderr(){if(!this.#l){const t=l.get(this)??[],s=new h(...t);s.#c=this,s.#s="stderr",s.#o={__proto__:null,...this.#o},this.#l=s}return this.#l}get stdout(){if(!this.#h){const t=l.get(this)??[],s=new h(...t);s.#c=this,s.#s="stdout",s.#o={__proto__:null,...this.#o},this.#h=s}return this.#h}#r(){return this.#c||this}#n(t){const s=this.#r();return t==="stderr"?s.#g:s.#f}#e(t,s){const n=this.#r();t==="stderr"?n.#g=s:n.#f=s}#d(t){const s=this.#r();return t==="stderr"?s.#p:s.#y}#u(t,s){const n=this.#r();t==="stderr"?n.#p=s:n.#y=s}#k(){return this.#s||"stderr"}#m(t,s,n){const e=this.#t(),r=s.at(0),c=typeof r=="string",d=n||(t==="log"?"stdout":"stderr"),b=this.#n(d),f=c?[(0,a.applyLinePrefix)(r,{prefix:b}),...s.slice(1)]:s;return _(e[t],e,f),this[i](c&&(0,a.isBlankString)(f[0]),d),this[u](),this}#b(t){return t.replace(/^[✖✗×⚠‼✔✓√ℹ→]\uFE0F?\s*/u,"")}#i(t,s){const n=this.#t();let e=s.at(0),r;typeof e=="string"?(e=this.#b(e),r=s.slice(1)):(r=s,e="");const c=this.#n("stderr");return n.error((0,a.applyLinePrefix)(`${y[t]} ${e}`,{prefix:c}),...r),this[i](!1,"stderr"),this[u](),this}get logCallCount(){return this.#r().#a}[u](){const t=this.#r();return t.#a+=1,this}[i](t,s){return s?this.#u(s,!!t):this.#s?this.#u(this.#s,!!t):(this.#u("stderr",!!t),this.#u("stdout",!!t)),this}assert(t,...s){return this.#t().assert(t,s[0],...s.slice(1)),this[i](!1),t?this:this[u]()}clearVisible(){if(this.#s)throw new Error("clearVisible() is only available on the main logger instance, not on stream-bound instances");const t=this.#t();return t.clear(),t._stdout.isTTY&&(this[i](!0),this.#a=0),this}count(t){return this.#t().count(t),this[i](!1),this[u]()}createTask(t){return{run:s=>{this.log(`Starting task: ${t}`);const n=s();return this.log(`Completed task: ${t}`),n}}}dedent(t=2){if(this.#s){const s=this.#n(this.#s);this.#e(this.#s,s.slice(0,-t))}else{const s=this.#n("stderr"),n=this.#n("stdout");this.#e("stderr",s.slice(0,-t)),this.#e("stdout",n.slice(0,-t))}return this}dir(t,s){return this.#t().dir(t,s),this[i](!1),this[u]()}dirxml(...t){return this.#t().dirxml(t),this[i](!1),this[u]()}error(...t){return this.#m("error",t)}errorNewline(){return this.#d("stderr")?this:this.error("")}fail(...t){return this.#i("fail",t)}group(...t){const{length:s}=t;return s&&_(this.log,this,t),this.indent(this[x()]),s&&(this[i](!1),this[u]()),this}groupCollapsed(...t){return _(this.group,this,t)}groupEnd(){return this.dedent(this[x()]),this}indent(t=2){const s=" ".repeat(Math.min(t,H));if(this.#s){const n=this.#n(this.#s);this.#e(this.#s,n+s)}else{const n=this.#n("stderr"),e=this.#n("stdout");this.#e("stderr",n+s),this.#e("stdout",e+s)}return this}info(...t){return this.#i("info",t)}log(...t){return this.#m("log",t)}logNewline(){return this.#d("stdout")?this:this.log("")}resetIndent(){return this.#s?this.#e(this.#s,""):(this.#e("stderr",""),this.#e("stdout","")),this}step(t,...s){this.#d("stdout")||this.log("");const n=this.#b(t),e=this.#n("stdout");return this.#t().log((0,a.applyLinePrefix)(`${y.step} ${n}`,{prefix:e}),...s),this[i](!1,"stdout"),this[u](),this}substep(t,...s){const n=` ${t}`;return this.log(n,...s)}success(...t){return this.#i("success",t)}done(...t){return this.#i("success",t)}table(t,s){return this.#t().table(t,s),this[i](!1),this[u]()}timeEnd(t){return this.#t().timeEnd(t),this[i](!1),this[u]()}timeLog(t,...s){return this.#t().timeLog(t,...s),this[i](!1),this[u]()}trace(t,...s){return this.#t().trace(t,...s),this[i](!1),this[u]()}warn(...t){return this.#i("warn",t)}write(t){const s=this.#t(),n=l.get(this)??[];return(this.#w||n[0]?.stdout||s._stdout).write(t),this[i](!1),this}progress(t){const s=this.#t();return(this.#k()==="stderr"?s._stderr:s._stdout).write(`\u2234 ${t}`),this[i](!1),this}clearLine(){const t=this.#t(),n=this.#k()==="stderr"?t._stderr:t._stdout;return n.isTTY?(n.cursorTo(0),n.clearLine(0)):n.write("\r\x1B[K"),this}}let W=!1;function z(){if(W)return;W=!0;const o=[[x(),{...A,value:2}],[Symbol.toStringTag,{__proto__:null,configurable:!0,value:"logger"}]];for(const{0:t,1:s}of Object.entries(g))if(!h.prototype[t]&&typeof s=="function"){const{[t]:n}={[t](...e){let r=k.get(this);if(r===void 0){const d=l.get(this)??[];if(l.delete(this),d.length)r=w(...d);else{r=w({stdout:process.stdout,stderr:process.stderr});for(const{0:b,1:f}of P)r[b]=f}k.set(this,r)}const c=r[t](...e);return c===void 0||c===r?this:c}};o.push([t,{...A,value:n}])}Object.defineProperties(h.prototype,Object.fromEntries(o))}const F=new h;0&&(module.exports={LOG_SYMBOLS,Logger,incLogCallCountSymbol,lastWasBlankSymbol,logger});
2
+ var G=Object.create;var w=Object.defineProperty;var Y=Object.getOwnPropertyDescriptor;var v=Object.getOwnPropertyNames;var H=Object.getPrototypeOf,N=Object.prototype.hasOwnProperty;var V=(e,t)=>{for(var s in t)w(e,s,{get:t[s],enumerable:!0})},A=(e,t,s,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of v(t))!N.call(e,o)&&o!==s&&w(e,o,{get:()=>t[o],enumerable:!(n=Y(t,o))||n.enumerable});return e};var W=(e,t,s)=>(s=e!=null?G(H(e)):{},A(t||!e||!e.__esModule?w(s,"default",{value:e,enumerable:!0}):s,e)),z=e=>A(w({},"__esModule",{value:!0}),e);var X={};V(X,{LOG_SYMBOLS:()=>m,Logger:()=>d,getDefaultLogger:()=>Q,incLogCallCountSymbol:()=>l,lastWasBlankSymbol:()=>u});module.exports=z(X);var P=W(require("./external/@socketregistry/is-unicode-supported")),j=W(require("./external/yoctocolors-cjs")),f=require("./strings"),_=require("./themes/context");const y=console,C=Reflect.apply,D=Reflect.construct;let L;function k(...e){return L===void 0&&(L=require("node:console").Console),D(L,e)}function F(){return j.default}function p(e,t,s){return typeof t=="string"?s[t](e):s.rgb(t[0],t[1],t[2])(e)}const m=(()=>{const e={__proto__:null};let t=!1;const s={__proto__:null},n=()=>{const r=(0,P.default)(),c=F(),a=(0,_.getTheme)(),g=a.colors.success,B=a.colors.error,M=a.colors.warning,$=a.colors.info,K=a.colors.step;e.fail=p(r?"\u2716":"\xD7",B,c),e.info=p(r?"\u2139":"i",$,c),e.step=p(r?"\u2192":">",K,c),e.success=p(r?"\u2714":"\u221A",g,c),e.warn=p(r?"\u26A0":"\u203C",M,c)},o=()=>{if(!t){n(),t=!0;for(const r in s)delete s[r]}},i=()=>{t&&n()};for(const r of Reflect.ownKeys(Reflect)){const c=Reflect[r];typeof c=="function"&&(s[r]=(...a)=>(o(),c(...a)))}return(0,_.onThemeChange)(()=>{i()}),new Proxy(e,s)})(),E=["_stderrErrorHandler","_stdoutErrorHandler","assert","clear","count","countReset","createTask","debug","dir","dirxml","error","info","log","table","time","timeEnd","timeLog","trace","warn"].filter(e=>typeof y[e]=="function").map(e=>[e,y[e].bind(y)]),I={__proto__:null,writable:!0,enumerable:!1,configurable:!0},J=1e3,b=new WeakMap,h=new WeakMap;let S;function q(){return S===void 0&&(S=Object.getOwnPropertySymbols(y)),S}const l=Symbol.for("logger.logCallCount++");let x;function R(){return x===void 0&&(x=q().find(e=>e.label==="kGroupIndentWidth")??Symbol("kGroupIndentWidth")),x}const u=Symbol.for("logger.lastWasBlank");class d{static LOG_SYMBOLS=m;#c;#s;#l;#a;#g="";#f="";#p=!1;#y=!1;#h=0;#o;#w;constructor(...t){h.set(this,t);const s=t[0];typeof s=="object"&&s!==null?(this.#o={__proto__:null,...s},this.#w=s.stdout):this.#o={__proto__:null}}#t(){U();let t=b.get(this);if(!t){const s=h.get(this)??[];if(s.length)t=k(...s);else{t=k({stdout:process.stdout,stderr:process.stderr});for(const{0:n,1:o}of E)t[n]=o}b.set(this,t),h.delete(this)}return t}get stderr(){if(!this.#l){const t=h.get(this)??[],s=new d(...t);s.#c=this,s.#s="stderr",s.#o={__proto__:null,...this.#o},this.#l=s}return this.#l}get stdout(){if(!this.#a){const t=h.get(this)??[],s=new d(...t);s.#c=this,s.#s="stdout",s.#o={__proto__:null,...this.#o},this.#a=s}return this.#a}#r(){return this.#c||this}#n(t){const s=this.#r();return t==="stderr"?s.#g:s.#f}#e(t,s){const n=this.#r();t==="stderr"?n.#g=s:n.#f=s}#d(t){const s=this.#r();return t==="stderr"?s.#p:s.#y}#u(t,s){const n=this.#r();t==="stderr"?n.#p=s:n.#y=s}#m(){return this.#s||"stderr"}#k(t,s,n){const o=this.#t(),i=s.at(0),r=typeof i=="string",c=n||(t==="log"?"stdout":"stderr"),a=this.#n(c),g=r?[(0,f.applyLinePrefix)(i,{prefix:a}),...s.slice(1)]:s;return C(o[t],o,g),this[u](r&&(0,f.isBlankString)(g[0]),c),this[l](),this}#b(t){return t.replace(/^[✖✗×⚠‼✔✓√ℹ→]\uFE0F?\s*/u,"")}#i(t,s){const n=this.#t();let o=s.at(0),i;typeof o=="string"?(o=this.#b(o),i=s.slice(1)):(i=s,o="");const r=this.#n("stderr");return n.error((0,f.applyLinePrefix)(`${m[t]} ${o}`,{prefix:r}),...i),this[u](!1,"stderr"),this[l](),this}get logCallCount(){return this.#r().#h}[l](){const t=this.#r();return t.#h+=1,this}[u](t,s){return s?this.#u(s,!!t):this.#s?this.#u(this.#s,!!t):(this.#u("stderr",!!t),this.#u("stdout",!!t)),this}assert(t,...s){return this.#t().assert(t,s[0],...s.slice(1)),this[u](!1),t?this:this[l]()}clearVisible(){if(this.#s)throw new Error("clearVisible() is only available on the main logger instance, not on stream-bound instances");const t=this.#t();return t.clear(),t._stdout.isTTY&&(this[u](!0),this.#h=0),this}count(t){return this.#t().count(t),this[u](!1),this[l]()}createTask(t){return{run:s=>{this.log(`Starting task: ${t}`);const n=s();return this.log(`Completed task: ${t}`),n}}}dedent(t=2){if(this.#s){const s=this.#n(this.#s);this.#e(this.#s,s.slice(0,-t))}else{const s=this.#n("stderr"),n=this.#n("stdout");this.#e("stderr",s.slice(0,-t)),this.#e("stdout",n.slice(0,-t))}return this}dir(t,s){return this.#t().dir(t,s),this[u](!1),this[l]()}dirxml(...t){return this.#t().dirxml(t),this[u](!1),this[l]()}error(...t){return this.#k("error",t)}errorNewline(){return this.#d("stderr")?this:this.error("")}fail(...t){return this.#i("fail",t)}group(...t){const{length:s}=t;return s&&C(this.log,this,t),this.indent(this[R()]),s&&(this[u](!1),this[l]()),this}groupCollapsed(...t){return C(this.group,this,t)}groupEnd(){return this.dedent(this[R()]),this}indent(t=2){const s=" ".repeat(Math.min(t,J));if(this.#s){const n=this.#n(this.#s);this.#e(this.#s,n+s)}else{const n=this.#n("stderr"),o=this.#n("stdout");this.#e("stderr",n+s),this.#e("stdout",o+s)}return this}info(...t){return this.#i("info",t)}log(...t){return this.#k("log",t)}logNewline(){return this.#d("stdout")?this:this.log("")}resetIndent(){return this.#s?this.#e(this.#s,""):(this.#e("stderr",""),this.#e("stdout","")),this}step(t,...s){this.#d("stdout")||this.log("");const n=this.#b(t),o=this.#n("stdout");return this.#t().log((0,f.applyLinePrefix)(`${m.step} ${n}`,{prefix:o}),...s),this[u](!1,"stdout"),this[l](),this}substep(t,...s){const n=` ${t}`;return this.log(n,...s)}success(...t){return this.#i("success",t)}done(...t){return this.#i("success",t)}table(t,s){return this.#t().table(t,s),this[u](!1),this[l]()}timeEnd(t){return this.#t().timeEnd(t),this[u](!1),this[l]()}timeLog(t,...s){return this.#t().timeLog(t,...s),this[u](!1),this[l]()}trace(t,...s){return this.#t().trace(t,...s),this[u](!1),this[l]()}warn(...t){return this.#i("warn",t)}write(t){const s=this.#t(),n=h.get(this)??[];return(this.#w||n[0]?.stdout||s._stdout).write(t),this[u](!1),this}progress(t){const s=this.#t();return(this.#m()==="stderr"?s._stderr:s._stdout).write(`\u2234 ${t}`),this[u](!1),this}clearLine(){const t=this.#t(),n=this.#m()==="stderr"?t._stderr:t._stdout;return n.isTTY?(n.cursorTo(0),n.clearLine(0)):n.write("\r\x1B[K"),this}}let O=!1;function U(){if(O)return;O=!0;const e=[[R(),{...I,value:2}],[Symbol.toStringTag,{__proto__:null,configurable:!0,value:"logger"}]];for(const{0:t,1:s}of Object.entries(y))if(!d.prototype[t]&&typeof s=="function"){const{[t]:n}={[t](...o){let i=b.get(this);if(i===void 0){const c=h.get(this)??[];if(h.delete(this),c.length)i=k(...c);else{i=k({stdout:process.stdout,stderr:process.stderr});for(const{0:a,1:g}of E)i[a]=g}b.set(this,i)}const r=i[t](...o);return r===void 0||r===i?this:r}};e.push([t,{...I,value:n}])}Object.defineProperties(d.prototype,Object.fromEntries(e))}let T;function Q(){return T===void 0&&(T=new d),T}0&&(module.exports={LOG_SYMBOLS,Logger,getDefaultLogger,incLogCallCountSymbol,lastWasBlankSymbol});
3
3
  //# sourceMappingURL=logger.js.map