@socketsecurity/lib 1.0.5 → 1.1.1

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 (57) hide show
  1. package/CHANGELOG.md +25 -0
  2. package/dist/arrays.d.ts +143 -0
  3. package/dist/arrays.js.map +2 -2
  4. package/dist/effects/text-shimmer.js +2 -1
  5. package/dist/effects/text-shimmer.js.map +2 -2
  6. package/dist/fs.d.ts +595 -23
  7. package/dist/fs.js.map +2 -2
  8. package/dist/git.d.ts +488 -41
  9. package/dist/git.js.map +2 -2
  10. package/dist/github.d.ts +361 -12
  11. package/dist/github.js.map +2 -2
  12. package/dist/http-request.d.ts +463 -4
  13. package/dist/http-request.js.map +2 -2
  14. package/dist/json.d.ts +177 -4
  15. package/dist/json.js.map +2 -2
  16. package/dist/logger.d.ts +822 -67
  17. package/dist/logger.js +653 -46
  18. package/dist/logger.js.map +2 -2
  19. package/dist/objects.d.ts +386 -10
  20. package/dist/objects.js.map +2 -2
  21. package/dist/path.d.ts +270 -6
  22. package/dist/path.js.map +2 -2
  23. package/dist/promises.d.ts +432 -27
  24. package/dist/promises.js.map +2 -2
  25. package/dist/spawn.d.ts +239 -12
  26. package/dist/spawn.js.map +2 -2
  27. package/dist/spinner.d.ts +260 -20
  28. package/dist/spinner.js +201 -63
  29. package/dist/spinner.js.map +2 -2
  30. package/dist/stdio/clear.d.ts +130 -9
  31. package/dist/stdio/clear.js.map +2 -2
  32. package/dist/stdio/divider.d.ts +106 -10
  33. package/dist/stdio/divider.js +10 -0
  34. package/dist/stdio/divider.js.map +2 -2
  35. package/dist/stdio/footer.d.ts +70 -3
  36. package/dist/stdio/footer.js.map +2 -2
  37. package/dist/stdio/header.d.ts +93 -12
  38. package/dist/stdio/header.js.map +2 -2
  39. package/dist/stdio/mask.d.ts +82 -14
  40. package/dist/stdio/mask.js +25 -4
  41. package/dist/stdio/mask.js.map +2 -2
  42. package/dist/stdio/progress.d.ts +112 -15
  43. package/dist/stdio/progress.js +43 -3
  44. package/dist/stdio/progress.js.map +2 -2
  45. package/dist/stdio/prompts.d.ts +95 -5
  46. package/dist/stdio/prompts.js.map +2 -2
  47. package/dist/stdio/stderr.d.ts +114 -11
  48. package/dist/stdio/stderr.js.map +2 -2
  49. package/dist/stdio/stdout.d.ts +107 -11
  50. package/dist/stdio/stdout.js.map +2 -2
  51. package/dist/strings.d.ts +357 -28
  52. package/dist/strings.js.map +2 -2
  53. package/dist/validation/json-parser.d.ts +226 -7
  54. package/dist/validation/json-parser.js.map +2 -2
  55. package/dist/validation/types.d.ts +114 -8
  56. package/dist/validation/types.js.map +1 -1
  57. package/package.json +1 -1
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/http-request.ts"],
4
- "sourcesContent": ["/** @fileoverview HTTP/HTTPS request utilities using Node.js built-in modules with retry logic, redirects, and download support. */\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\nexport interface HttpRequestOptions {\n body?: Buffer | string | undefined\n followRedirects?: boolean | undefined\n headers?: Record<string, string> | undefined\n maxRedirects?: number | undefined\n method?: string | undefined\n retries?: number | undefined\n retryDelay?: number | undefined\n timeout?: number | undefined\n}\n\nexport interface HttpResponse {\n arrayBuffer(): ArrayBuffer\n body: Buffer\n headers: Record<string, string | string[] | undefined>\n json<T = unknown>(): T\n ok: boolean\n status: number\n statusText: string\n text(): string\n}\n\nexport interface HttpDownloadOptions {\n headers?: Record<string, string> | undefined\n onProgress?: ((downloaded: number, total: number) => void) | undefined\n retries?: number | undefined\n retryDelay?: number | undefined\n timeout?: number | undefined\n}\n\nexport interface HttpDownloadResult {\n path: string\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 * @throws {Error} When all retries are exhausted or non-retryable error occurs.\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 */\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 err = new Error(`HTTP request failed: ${error.message}`, {\n cause: error,\n })\n reject(err)\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 * @throws {Error} When all retries are exhausted or download fails.\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 */\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 err = new Error(`HTTP download failed: ${error.message}`, {\n cause: error,\n })\n reject(err)\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 * @throws {Error} When request fails or JSON parsing fails.\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 * @throws {Error} When request fails.\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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",
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 err = new Error(`HTTP request failed: ${error.message}`, {\n cause: error,\n })\n reject(err)\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 err = new Error(`HTTP download failed: ${error.message}`, {\n cause: error,\n })\n reject(err)\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
6
  "names": []
7
7
  }
package/dist/json.d.ts CHANGED
@@ -1,23 +1,196 @@
1
+ /**
2
+ * JSON primitive types: `null`, `boolean`, `number`, or `string`.
3
+ *
4
+ * @example
5
+ * ```ts
6
+ * const primitives: JsonPrimitive[] = [null, true, 42, 'hello']
7
+ * ```
8
+ */
1
9
  export type JsonPrimitive = null | boolean | number | string;
10
+ /**
11
+ * Any valid JSON value: primitive, object, or array.
12
+ *
13
+ * @example
14
+ * ```ts
15
+ * const values: JsonValue[] = [
16
+ * null,
17
+ * true,
18
+ * 42,
19
+ * 'hello',
20
+ * { key: 'value' },
21
+ * [1, 2, 3]
22
+ * ]
23
+ * ```
24
+ */
2
25
  export type JsonValue = JsonPrimitive | JsonObject | JsonArray;
26
+ /**
27
+ * A JSON object with string keys and JSON values.
28
+ *
29
+ * @example
30
+ * ```ts
31
+ * const obj: JsonObject = {
32
+ * name: 'example',
33
+ * count: 42,
34
+ * active: true,
35
+ * nested: { key: 'value' }
36
+ * }
37
+ * ```
38
+ */
3
39
  export interface JsonObject {
4
40
  [key: string]: JsonValue;
5
41
  }
42
+ /**
43
+ * A JSON array containing JSON values.
44
+ *
45
+ * @example
46
+ * ```ts
47
+ * const arr: JsonArray = [1, 'two', { three: 3 }, [4, 5]]
48
+ * ```
49
+ */
6
50
  export interface JsonArray extends Array<JsonValue> {
7
51
  }
52
+ /**
53
+ * Reviver function for transforming parsed JSON values.
54
+ * Called for each key-value pair during parsing.
55
+ *
56
+ * @param key - The object key or array index being parsed
57
+ * @param value - The parsed value
58
+ * @returns The transformed value (or original if no transform needed)
59
+ *
60
+ * @example
61
+ * ```ts
62
+ * // Convert date strings to Date objects
63
+ * const reviver: JsonReviver = (key, value) => {
64
+ * if (typeof value === 'string' && /^\d{4}-\d{2}-\d{2}/.test(value)) {
65
+ * return new Date(value)
66
+ * }
67
+ * return value
68
+ * }
69
+ * ```
70
+ */
8
71
  export type JsonReviver = (key: string, value: unknown) => unknown;
72
+ /**
73
+ * Options for JSON parsing operations.
74
+ */
9
75
  export interface JsonParseOptions {
10
- filepath?: string;
76
+ /**
77
+ * Optional filepath for improved error messages.
78
+ * When provided, errors will be prefixed with the filepath.
79
+ *
80
+ * @example
81
+ * ```ts
82
+ * // Error message will be: "config.json: Unexpected token } in JSON"
83
+ * jsonParse('invalid', { filepath: 'config.json' })
84
+ * ```
85
+ */
86
+ filepath?: string | undefined;
87
+ /**
88
+ * Optional reviver function to transform parsed values.
89
+ * Called for each key-value pair during parsing.
90
+ *
91
+ * @example
92
+ * ```ts
93
+ * // Convert ISO date strings to Date objects
94
+ * const options = {
95
+ * reviver: (key, value) => {
96
+ * if (typeof value === 'string' && /^\d{4}-\d{2}-\d{2}/.test(value)) {
97
+ * return new Date(value)
98
+ * }
99
+ * return value
100
+ * }
101
+ * }
102
+ * ```
103
+ */
11
104
  reviver?: JsonReviver | undefined;
12
- throws?: boolean;
105
+ /**
106
+ * Whether to throw on parse errors.
107
+ * When `false`, returns `undefined` instead of throwing.
108
+ *
109
+ * @default true
110
+ *
111
+ * @example
112
+ * ```ts
113
+ * // Throws error
114
+ * jsonParse('invalid', { throws: true })
115
+ *
116
+ * // Returns undefined
117
+ * const result = jsonParse('invalid', { throws: false })
118
+ * ```
119
+ */
120
+ throws?: boolean | undefined;
13
121
  }
14
122
  /**
15
- * Check if a value is a JSON primitive (null, boolean, number, or string).
123
+ * Check if a value is a JSON primitive type.
124
+ * JSON primitives are: `null`, `boolean`, `number`, or `string`.
125
+ *
126
+ * @param value - Value to check
127
+ * @returns `true` if value is a JSON primitive, `false` otherwise
128
+ *
129
+ * @example
130
+ * ```ts
131
+ * isJsonPrimitive(null) // => true
132
+ * isJsonPrimitive(true) // => true
133
+ * isJsonPrimitive(42) // => true
134
+ * isJsonPrimitive('hello') // => true
135
+ * isJsonPrimitive({}) // => false
136
+ * isJsonPrimitive([]) // => false
137
+ * isJsonPrimitive(undefined) // => false
138
+ * ```
16
139
  */
17
140
  /*@__NO_SIDE_EFFECTS__*/
18
141
  export declare function isJsonPrimitive(value: unknown): value is JsonPrimitive;
19
142
  /**
20
- * Parse JSON content with error handling and BOM stripping.
143
+ * Parse JSON content with automatic Buffer handling and BOM stripping.
144
+ * Provides safer JSON parsing with helpful error messages and optional error suppression.
145
+ *
146
+ * Features:
147
+ * - Automatic UTF-8 Buffer conversion
148
+ * - BOM (Byte Order Mark) stripping for cross-platform compatibility
149
+ * - Enhanced error messages with filepath context
150
+ * - Optional error suppression (returns `undefined` instead of throwing)
151
+ * - Optional reviver for transforming parsed values
152
+ *
153
+ * @param content - JSON string or Buffer to parse
154
+ * @param options - Optional parsing configuration
155
+ * @returns Parsed JSON value, or `undefined` if parsing fails and `throws` is `false`
156
+ *
157
+ * @throws {SyntaxError} When JSON is invalid and `throws` is `true` (default)
158
+ *
159
+ * @example
160
+ * ```ts
161
+ * // Basic usage
162
+ * const data = jsonParse('{"name":"example"}')
163
+ * console.log(data.name) // => 'example'
164
+ *
165
+ * // Parse Buffer with UTF-8 BOM
166
+ * const buffer = Buffer.from('\uFEFF{"value":42}')
167
+ * const data = jsonParse(buffer)
168
+ * console.log(data.value) // => 42
169
+ *
170
+ * // Enhanced error messages with filepath
171
+ * try {
172
+ * jsonParse('invalid', { filepath: 'config.json' })
173
+ * } catch (err) {
174
+ * console.error(err.message)
175
+ * // => "config.json: Unexpected token i in JSON at position 0"
176
+ * }
177
+ *
178
+ * // Suppress errors
179
+ * const result = jsonParse('invalid', { throws: false })
180
+ * console.log(result) // => undefined
181
+ *
182
+ * // Transform values with reviver
183
+ * const json = '{"created":"2024-01-15T10:30:00Z"}'
184
+ * const data = jsonParse(json, {
185
+ * reviver: (key, value) => {
186
+ * if (key === 'created' && typeof value === 'string') {
187
+ * return new Date(value)
188
+ * }
189
+ * return value
190
+ * }
191
+ * })
192
+ * console.log(data.created instanceof Date) // => true
193
+ * ```
21
194
  */
22
195
  /*@__NO_SIDE_EFFECTS__*/
23
196
  export declare function jsonParse(content: string | Buffer, options?: JsonParseOptions | undefined): JsonValue | undefined;
package/dist/json.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/json.ts"],
4
- "sourcesContent": ["/**\n * @fileoverview JSON parsing utilities with Buffer detection and BOM stripping.\n * Provides safe JSON parsing with automatic encoding handling.\n */\n\nimport { stripBom } from './strings'\n\nexport type JsonPrimitive = null | boolean | number | string\n\nexport type JsonValue = JsonPrimitive | JsonObject | JsonArray\n\nexport interface JsonObject {\n [key: string]: JsonValue\n}\n\nexport interface JsonArray extends Array<JsonValue> {}\n\nexport type JsonReviver = (key: string, value: unknown) => unknown\n\nexport interface JsonParseOptions {\n filepath?: string\n reviver?: JsonReviver | undefined\n throws?: boolean\n}\n\n// IMPORTANT: Do not use destructuring here - use direct assignment instead.\n// tsgo has a bug that incorrectly transpiles destructured exports, resulting in\n// `exports.SomeName = void 0;` which causes runtime errors.\n// See: https://github.com/SocketDev/socket-packageurl-js/issues/3\nconst JSONParse = JSON.parse\n\n/**\n * Check if a value is a Buffer instance.\n */\n/*@__NO_SIDE_EFFECTS__*/\nfunction isBuffer(x: unknown): x is Buffer {\n if (!x || typeof x !== 'object') {\n return false\n }\n const obj = x as Record<string | number, unknown>\n if (typeof obj['length'] !== 'number') {\n return false\n }\n if (typeof obj['copy'] !== 'function' || typeof obj['slice'] !== 'function') {\n return false\n }\n if (\n typeof obj['length'] === 'number' &&\n obj['length'] > 0 &&\n typeof obj[0] !== 'number'\n ) {\n return false\n }\n\n const Ctor = (x as { constructor?: unknown }).constructor as\n | { isBuffer?: unknown }\n | undefined\n return !!(typeof Ctor?.isBuffer === 'function' && Ctor.isBuffer(x))\n}\n\n/**\n * Check if a value is a JSON primitive (null, boolean, number, or string).\n */\n/*@__NO_SIDE_EFFECTS__*/\nexport function isJsonPrimitive(value: unknown): value is JsonPrimitive {\n return (\n value === null ||\n typeof value === 'boolean' ||\n typeof value === 'number' ||\n typeof value === 'string'\n )\n}\n\n/**\n * Parse JSON content with error handling and BOM stripping.\n */\n/*@__NO_SIDE_EFFECTS__*/\nexport function jsonParse(\n content: string | Buffer,\n options?: JsonParseOptions | undefined,\n): JsonValue | undefined {\n const { filepath, reviver, throws } = {\n __proto__: null,\n ...options,\n } as JsonParseOptions\n const shouldThrow = throws === undefined || !!throws\n const jsonStr = isBuffer(content) ? content.toString('utf8') : content\n try {\n return JSONParse(stripBom(jsonStr), reviver)\n } catch (e) {\n if (shouldThrow) {\n const error = e as Error\n if (error && typeof filepath === 'string') {\n error.message = `${filepath}: ${error.message}`\n }\n throw error\n }\n }\n return undefined\n}\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAKA,qBAAyB;AAwBzB,MAAM,YAAY,KAAK;AAAA;AAMvB,SAAS,SAAS,GAAyB;AACzC,MAAI,CAAC,KAAK,OAAO,MAAM,UAAU;AAC/B,WAAO;AAAA,EACT;AACA,QAAM,MAAM;AACZ,MAAI,OAAO,IAAI,QAAQ,MAAM,UAAU;AACrC,WAAO;AAAA,EACT;AACA,MAAI,OAAO,IAAI,MAAM,MAAM,cAAc,OAAO,IAAI,OAAO,MAAM,YAAY;AAC3E,WAAO;AAAA,EACT;AACA,MACE,OAAO,IAAI,QAAQ,MAAM,YACzB,IAAI,QAAQ,IAAI,KAChB,OAAO,IAAI,CAAC,MAAM,UAClB;AACA,WAAO;AAAA,EACT;AAEA,QAAM,OAAQ,EAAgC;AAG9C,SAAO,CAAC,EAAE,OAAO,MAAM,aAAa,cAAc,KAAK,SAAS,CAAC;AACnE;AAAA;AAMO,SAAS,gBAAgB,OAAwC;AACtE,SACE,UAAU,QACV,OAAO,UAAU,aACjB,OAAO,UAAU,YACjB,OAAO,UAAU;AAErB;AAAA;AAMO,SAAS,UACd,SACA,SACuB;AACvB,QAAM,EAAE,UAAU,SAAS,OAAO,IAAI;AAAA,IACpC,WAAW;AAAA,IACX,GAAG;AAAA,EACL;AACA,QAAM,cAAc,WAAW,UAAa,CAAC,CAAC;AAC9C,QAAM,UAAU,yBAAS,OAAO,IAAI,QAAQ,SAAS,MAAM,IAAI;AAC/D,MAAI;AACF,WAAO,cAAU,yBAAS,OAAO,GAAG,OAAO;AAAA,EAC7C,SAAS,GAAG;AACV,QAAI,aAAa;AACf,YAAM,QAAQ;AACd,UAAI,SAAS,OAAO,aAAa,UAAU;AACzC,cAAM,UAAU,GAAG,QAAQ,KAAK,MAAM,OAAO;AAAA,MAC/C;AACA,YAAM;AAAA,IACR;AAAA,EACF;AACA,SAAO;AACT;",
4
+ "sourcesContent": ["/**\n * @fileoverview JSON parsing utilities with Buffer detection and BOM stripping.\n * Provides safe JSON parsing with automatic encoding handling.\n */\n\nimport { stripBom } from './strings'\n\n/**\n * JSON primitive types: `null`, `boolean`, `number`, or `string`.\n *\n * @example\n * ```ts\n * const primitives: JsonPrimitive[] = [null, true, 42, 'hello']\n * ```\n */\nexport type JsonPrimitive = null | boolean | number | string\n\n/**\n * Any valid JSON value: primitive, object, or array.\n *\n * @example\n * ```ts\n * const values: JsonValue[] = [\n * null,\n * true,\n * 42,\n * 'hello',\n * { key: 'value' },\n * [1, 2, 3]\n * ]\n * ```\n */\nexport type JsonValue = JsonPrimitive | JsonObject | JsonArray\n\n/**\n * A JSON object with string keys and JSON values.\n *\n * @example\n * ```ts\n * const obj: JsonObject = {\n * name: 'example',\n * count: 42,\n * active: true,\n * nested: { key: 'value' }\n * }\n * ```\n */\nexport interface JsonObject {\n [key: string]: JsonValue\n}\n\n/**\n * A JSON array containing JSON values.\n *\n * @example\n * ```ts\n * const arr: JsonArray = [1, 'two', { three: 3 }, [4, 5]]\n * ```\n */\nexport interface JsonArray extends Array<JsonValue> {}\n\n/**\n * Reviver function for transforming parsed JSON values.\n * Called for each key-value pair during parsing.\n *\n * @param key - The object key or array index being parsed\n * @param value - The parsed value\n * @returns The transformed value (or original if no transform needed)\n *\n * @example\n * ```ts\n * // Convert date strings to Date objects\n * const reviver: JsonReviver = (key, value) => {\n * if (typeof value === 'string' && /^\\d{4}-\\d{2}-\\d{2}/.test(value)) {\n * return new Date(value)\n * }\n * return value\n * }\n * ```\n */\nexport type JsonReviver = (key: string, value: unknown) => unknown\n\n/**\n * Options for JSON parsing operations.\n */\nexport interface JsonParseOptions {\n /**\n * Optional filepath for improved error messages.\n * When provided, errors will be prefixed with the filepath.\n *\n * @example\n * ```ts\n * // Error message will be: \"config.json: Unexpected token } in JSON\"\n * jsonParse('invalid', { filepath: 'config.json' })\n * ```\n */\n filepath?: string | undefined\n /**\n * Optional reviver function to transform parsed values.\n * Called for each key-value pair during parsing.\n *\n * @example\n * ```ts\n * // Convert ISO date strings to Date objects\n * const options = {\n * reviver: (key, value) => {\n * if (typeof value === 'string' && /^\\d{4}-\\d{2}-\\d{2}/.test(value)) {\n * return new Date(value)\n * }\n * return value\n * }\n * }\n * ```\n */\n reviver?: JsonReviver | undefined\n /**\n * Whether to throw on parse errors.\n * When `false`, returns `undefined` instead of throwing.\n *\n * @default true\n *\n * @example\n * ```ts\n * // Throws error\n * jsonParse('invalid', { throws: true })\n *\n * // Returns undefined\n * const result = jsonParse('invalid', { throws: false })\n * ```\n */\n throws?: boolean | undefined\n}\n\n// IMPORTANT: Do not use destructuring here - use direct assignment instead.\n// tsgo has a bug that incorrectly transpiles destructured exports, resulting in\n// `exports.SomeName = void 0;` which causes runtime errors.\n// See: https://github.com/SocketDev/socket-packageurl-js/issues/3\nconst JSONParse = JSON.parse\n\n/**\n * Check if a value is a Buffer instance.\n * Uses duck-typing to detect Buffer without requiring Node.js Buffer in type system.\n *\n * @param x - Value to check\n * @returns `true` if value is a Buffer, `false` otherwise\n *\n * @example\n * ```ts\n * isBuffer(Buffer.from('hello')) // => true\n * isBuffer('hello') // => false\n * isBuffer({ length: 5 }) // => false\n * ```\n */\n/*@__NO_SIDE_EFFECTS__*/\nfunction isBuffer(x: unknown): x is Buffer {\n if (!x || typeof x !== 'object') {\n return false\n }\n const obj = x as Record<string | number, unknown>\n if (typeof obj['length'] !== 'number') {\n return false\n }\n if (typeof obj['copy'] !== 'function' || typeof obj['slice'] !== 'function') {\n return false\n }\n if (\n typeof obj['length'] === 'number' &&\n obj['length'] > 0 &&\n typeof obj[0] !== 'number'\n ) {\n return false\n }\n\n const Ctor = (x as { constructor?: unknown }).constructor as\n | { isBuffer?: unknown }\n | undefined\n return !!(typeof Ctor?.isBuffer === 'function' && Ctor.isBuffer(x))\n}\n\n/**\n * Check if a value is a JSON primitive type.\n * JSON primitives are: `null`, `boolean`, `number`, or `string`.\n *\n * @param value - Value to check\n * @returns `true` if value is a JSON primitive, `false` otherwise\n *\n * @example\n * ```ts\n * isJsonPrimitive(null) // => true\n * isJsonPrimitive(true) // => true\n * isJsonPrimitive(42) // => true\n * isJsonPrimitive('hello') // => true\n * isJsonPrimitive({}) // => false\n * isJsonPrimitive([]) // => false\n * isJsonPrimitive(undefined) // => false\n * ```\n */\n/*@__NO_SIDE_EFFECTS__*/\nexport function isJsonPrimitive(value: unknown): value is JsonPrimitive {\n return (\n value === null ||\n typeof value === 'boolean' ||\n typeof value === 'number' ||\n typeof value === 'string'\n )\n}\n\n/**\n * Parse JSON content with automatic Buffer handling and BOM stripping.\n * Provides safer JSON parsing with helpful error messages and optional error suppression.\n *\n * Features:\n * - Automatic UTF-8 Buffer conversion\n * - BOM (Byte Order Mark) stripping for cross-platform compatibility\n * - Enhanced error messages with filepath context\n * - Optional error suppression (returns `undefined` instead of throwing)\n * - Optional reviver for transforming parsed values\n *\n * @param content - JSON string or Buffer to parse\n * @param options - Optional parsing configuration\n * @returns Parsed JSON value, or `undefined` if parsing fails and `throws` is `false`\n *\n * @throws {SyntaxError} When JSON is invalid and `throws` is `true` (default)\n *\n * @example\n * ```ts\n * // Basic usage\n * const data = jsonParse('{\"name\":\"example\"}')\n * console.log(data.name) // => 'example'\n *\n * // Parse Buffer with UTF-8 BOM\n * const buffer = Buffer.from('\\uFEFF{\"value\":42}')\n * const data = jsonParse(buffer)\n * console.log(data.value) // => 42\n *\n * // Enhanced error messages with filepath\n * try {\n * jsonParse('invalid', { filepath: 'config.json' })\n * } catch (err) {\n * console.error(err.message)\n * // => \"config.json: Unexpected token i in JSON at position 0\"\n * }\n *\n * // Suppress errors\n * const result = jsonParse('invalid', { throws: false })\n * console.log(result) // => undefined\n *\n * // Transform values with reviver\n * const json = '{\"created\":\"2024-01-15T10:30:00Z\"}'\n * const data = jsonParse(json, {\n * reviver: (key, value) => {\n * if (key === 'created' && typeof value === 'string') {\n * return new Date(value)\n * }\n * return value\n * }\n * })\n * console.log(data.created instanceof Date) // => true\n * ```\n */\n/*@__NO_SIDE_EFFECTS__*/\nexport function jsonParse(\n content: string | Buffer,\n options?: JsonParseOptions | undefined,\n): JsonValue | undefined {\n const { filepath, reviver, throws } = {\n __proto__: null,\n ...options,\n } as JsonParseOptions\n const shouldThrow = throws === undefined || !!throws\n const jsonStr = isBuffer(content) ? content.toString('utf8') : content\n try {\n return JSONParse(stripBom(jsonStr), reviver)\n } catch (e) {\n if (shouldThrow) {\n const error = e as Error\n if (error && typeof filepath === 'string') {\n error.message = `${filepath}: ${error.message}`\n }\n throw error\n }\n }\n return undefined\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAKA,qBAAyB;AAoIzB,MAAM,YAAY,KAAK;AAAA;AAiBvB,SAAS,SAAS,GAAyB;AACzC,MAAI,CAAC,KAAK,OAAO,MAAM,UAAU;AAC/B,WAAO;AAAA,EACT;AACA,QAAM,MAAM;AACZ,MAAI,OAAO,IAAI,QAAQ,MAAM,UAAU;AACrC,WAAO;AAAA,EACT;AACA,MAAI,OAAO,IAAI,MAAM,MAAM,cAAc,OAAO,IAAI,OAAO,MAAM,YAAY;AAC3E,WAAO;AAAA,EACT;AACA,MACE,OAAO,IAAI,QAAQ,MAAM,YACzB,IAAI,QAAQ,IAAI,KAChB,OAAO,IAAI,CAAC,MAAM,UAClB;AACA,WAAO;AAAA,EACT;AAEA,QAAM,OAAQ,EAAgC;AAG9C,SAAO,CAAC,EAAE,OAAO,MAAM,aAAa,cAAc,KAAK,SAAS,CAAC;AACnE;AAAA;AAqBO,SAAS,gBAAgB,OAAwC;AACtE,SACE,UAAU,QACV,OAAO,UAAU,aACjB,OAAO,UAAU,YACjB,OAAO,UAAU;AAErB;AAAA;AAwDO,SAAS,UACd,SACA,SACuB;AACvB,QAAM,EAAE,UAAU,SAAS,OAAO,IAAI;AAAA,IACpC,WAAW;AAAA,IACX,GAAG;AAAA,EACL;AACA,QAAM,cAAc,WAAW,UAAa,CAAC,CAAC;AAC9C,QAAM,UAAU,yBAAS,OAAO,IAAI,QAAQ,SAAS,MAAM,IAAI;AAC/D,MAAI;AACF,WAAO,cAAU,yBAAS,OAAO,GAAG,OAAO;AAAA,EAC7C,SAAS,GAAG;AACV,QAAI,aAAa;AACf,YAAM,QAAQ;AACd,UAAI,SAAS,OAAO,aAAa,UAAU;AACzC,cAAM,UAAU,GAAG,QAAQ,KAAK,MAAM,OAAO;AAAA,MAC/C;AACA,YAAM;AAAA,IACR;AAAA,EACF;AACA,SAAO;AACT;",
6
6
  "names": []
7
7
  }