@socketsecurity/lib 1.0.5 → 1.1.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 (55) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/dist/arrays.d.ts +143 -0
  3. package/dist/arrays.js.map +2 -2
  4. package/dist/fs.d.ts +595 -23
  5. package/dist/fs.js.map +2 -2
  6. package/dist/git.d.ts +488 -41
  7. package/dist/git.js.map +2 -2
  8. package/dist/github.d.ts +361 -12
  9. package/dist/github.js.map +2 -2
  10. package/dist/http-request.d.ts +463 -4
  11. package/dist/http-request.js.map +2 -2
  12. package/dist/json.d.ts +177 -4
  13. package/dist/json.js.map +2 -2
  14. package/dist/logger.d.ts +822 -67
  15. package/dist/logger.js +653 -46
  16. package/dist/logger.js.map +2 -2
  17. package/dist/objects.d.ts +386 -10
  18. package/dist/objects.js.map +2 -2
  19. package/dist/path.d.ts +270 -6
  20. package/dist/path.js.map +2 -2
  21. package/dist/promises.d.ts +432 -27
  22. package/dist/promises.js.map +2 -2
  23. package/dist/spawn.d.ts +239 -12
  24. package/dist/spawn.js.map +2 -2
  25. package/dist/spinner.d.ts +260 -20
  26. package/dist/spinner.js +201 -63
  27. package/dist/spinner.js.map +2 -2
  28. package/dist/stdio/clear.d.ts +130 -9
  29. package/dist/stdio/clear.js.map +2 -2
  30. package/dist/stdio/divider.d.ts +106 -10
  31. package/dist/stdio/divider.js +10 -0
  32. package/dist/stdio/divider.js.map +2 -2
  33. package/dist/stdio/footer.d.ts +70 -3
  34. package/dist/stdio/footer.js.map +2 -2
  35. package/dist/stdio/header.d.ts +93 -12
  36. package/dist/stdio/header.js.map +2 -2
  37. package/dist/stdio/mask.d.ts +82 -14
  38. package/dist/stdio/mask.js +25 -4
  39. package/dist/stdio/mask.js.map +2 -2
  40. package/dist/stdio/progress.d.ts +112 -15
  41. package/dist/stdio/progress.js +43 -3
  42. package/dist/stdio/progress.js.map +2 -2
  43. package/dist/stdio/prompts.d.ts +95 -5
  44. package/dist/stdio/prompts.js.map +2 -2
  45. package/dist/stdio/stderr.d.ts +114 -11
  46. package/dist/stdio/stderr.js.map +2 -2
  47. package/dist/stdio/stdout.d.ts +107 -11
  48. package/dist/stdio/stdout.js.map +2 -2
  49. package/dist/strings.d.ts +357 -28
  50. package/dist/strings.js.map +2 -2
  51. package/dist/validation/json-parser.d.ts +226 -7
  52. package/dist/validation/json-parser.js.map +2 -2
  53. package/dist/validation/types.d.ts +114 -8
  54. package/dist/validation/types.js.map +1 -1
  55. package/package.json +1 -1
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../src/github.ts"],
4
- "sourcesContent": ["/**\n * @fileoverview GitHub utilities for Socket projects.\n * Provides GitHub API integration for repository operations.\n *\n * Authentication:\n * - getGitHubToken: Retrieve GitHub token from environment variables\n * - fetchGitHub: Authenticated GitHub API requests with rate limit handling\n *\n * Ref Resolution:\n * - resolveRefToSha: Convert tags/branches to commit SHAs (with memoization and persistent cache)\n * - clearRefCache: Clear the in-memory memoization cache\n *\n * Caching:\n * - Uses cacache for persistent storage with in-memory memoization\n * - Two-tier caching: in-memory (Map) for hot data, persistent (cacache) for durability\n * - Default TTL: 5 minutes\n * - Disable with DISABLE_GITHUB_CACHE env var\n *\n * Rate Limiting:\n * - Automatic rate limit detection and error messages\n * - Cache to minimize API calls\n */\n\nimport type { TtlCache } from './cache-with-ttl'\nimport { createTtlCache } from './cache-with-ttl'\nimport { httpRequest } from './http-request'\nimport type { SpawnOptions } from './spawn'\nimport { spawn } from './spawn'\n\n// GitHub API base URL constant (inlined for coverage mode compatibility).\nconst GITHUB_API_BASE_URL = 'https://api.github.com'\n\n// 5 minutes.\nconst DEFAULT_CACHE_TTL_MS = 5 * 60 * 1000\n\n// Create TTL cache instance for GitHub ref resolution.\n// Uses cacache for persistent storage with in-memory memoization.\nlet _githubCache: TtlCache | undefined\n\n/**\n * Get or create the GitHub cache instance.\n */\nfunction getGithubCache(): TtlCache {\n if (_githubCache === undefined) {\n _githubCache = createTtlCache({\n memoize: true,\n prefix: 'github-refs',\n ttl: DEFAULT_CACHE_TTL_MS,\n })\n }\n return _githubCache\n}\n\nexport interface GitHubFetchOptions {\n token?: string | undefined\n headers?: Record<string, string> | undefined\n}\n\nexport interface GitHubRateLimitError extends Error {\n status: number\n resetTime?: Date | undefined\n}\n\n/**\n * Get GitHub token from environment variables.\n */\nexport function getGitHubToken(): string | undefined {\n const { env } = process\n return (\n env['GITHUB_TOKEN'] ||\n env['GH_TOKEN'] ||\n env['SOCKET_CLI_GITHUB_TOKEN'] ||\n undefined\n )\n}\n\n/**\n * Fetch data from GitHub API with rate limit handling.\n */\nexport async function fetchGitHub<T = unknown>(\n url: string,\n options?: GitHubFetchOptions | undefined,\n): Promise<T> {\n const opts = { __proto__: null, ...options } as GitHubFetchOptions\n const token = opts.token || getGitHubToken()\n\n const headers: Record<string, string> = {\n Accept: 'application/vnd.github.v3+json',\n 'User-Agent': 'socket-registry-github-client',\n ...opts.headers,\n }\n\n if (token) {\n headers['Authorization'] = `Bearer ${token}`\n }\n\n const response = await httpRequest(url, { headers })\n\n if (!response.ok) {\n if (response.status === 403) {\n const rateLimit = response.headers['x-ratelimit-remaining']\n const rateLimitStr =\n typeof rateLimit === 'string' ? rateLimit : rateLimit?.[0]\n if (rateLimitStr === '0') {\n const resetTime = response.headers['x-ratelimit-reset']\n const resetTimeStr =\n typeof resetTime === 'string' ? resetTime : resetTime?.[0]\n const resetDate = resetTimeStr\n ? new Date(Number(resetTimeStr) * 1000)\n : undefined\n const error = new Error(\n `GitHub API rate limit exceeded${resetDate ? `. Resets at ${resetDate.toLocaleString()}` : ''}. Use GITHUB_TOKEN environment variable to increase rate limit.`,\n ) as GitHubRateLimitError\n error.status = 403\n error.resetTime = resetDate\n throw error\n }\n }\n throw new Error(\n `GitHub API error ${response.status}: ${response.statusText}`,\n )\n }\n\n return JSON.parse(response.body.toString('utf8')) as T\n}\n\nexport interface GitHubRef {\n object: {\n sha: string\n type: string\n url: string\n }\n ref: string\n url: string\n}\n\nexport interface GitHubTag {\n message: string\n object: {\n sha: string\n type: string\n url: string\n }\n sha: string\n tag: string\n tagger?: {\n date: string\n email: string\n name: string\n }\n url: string\n}\n\nexport interface GitHubCommit {\n sha: string\n url: string\n commit: {\n message: string\n author: {\n date: string\n email: string\n name: string\n }\n }\n}\n\nexport interface ResolveRefOptions {\n token?: string | undefined\n}\n\n/**\n * Resolve a git ref (tag, branch, or commit SHA) to its full commit SHA.\n * Results are cached in-memory and on disk (with TTL) to minimize API calls.\n */\nexport async function resolveRefToSha(\n owner: string,\n repo: string,\n ref: string,\n options?: ResolveRefOptions | undefined,\n): Promise<string> {\n const opts = {\n __proto__: null,\n ...options,\n } as ResolveRefOptions\n\n const cacheKey = `${owner}/${repo}@${ref}`\n\n // Optionally disable cache.\n if (process.env['DISABLE_GITHUB_CACHE']) {\n return await fetchRefSha(owner, repo, ref, opts)\n }\n\n // Use TTL cache for persistent storage and in-memory memoization.\n const cache = getGithubCache()\n return await cache.getOrFetch(cacheKey, async () => {\n return await fetchRefSha(owner, repo, ref, opts)\n })\n}\n\n/**\n * Fetch the SHA for a git ref from GitHub API.\n */\nasync function fetchRefSha(\n owner: string,\n repo: string,\n ref: string,\n options: ResolveRefOptions,\n): Promise<string> {\n const fetchOptions: GitHubFetchOptions = {\n token: options.token,\n }\n\n try {\n // Try as a tag first.\n const tagUrl = `${GITHUB_API_BASE_URL}/repos/${owner}/${repo}/git/refs/tags/${ref}`\n const tagData = await fetchGitHub<GitHubRef>(tagUrl, fetchOptions)\n\n // Tag might point to a tag object or directly to a commit.\n if (tagData.object.type === 'tag') {\n // Dereference the tag object to get the commit.\n const tagObject = await fetchGitHub<GitHubTag>(\n tagData.object.url,\n fetchOptions,\n )\n return tagObject.object.sha\n }\n return tagData.object.sha\n } catch {\n // Not a tag, try as a branch.\n try {\n const branchUrl = `${GITHUB_API_BASE_URL}/repos/${owner}/${repo}/git/refs/heads/${ref}`\n const branchData = await fetchGitHub<GitHubRef>(branchUrl, fetchOptions)\n return branchData.object.sha\n } catch {\n // Try without refs/ prefix (for commit SHAs or other refs).\n try {\n const commitUrl = `${GITHUB_API_BASE_URL}/repos/${owner}/${repo}/commits/${ref}`\n const commitData = await fetchGitHub<GitHubCommit>(\n commitUrl,\n fetchOptions,\n )\n return commitData.sha\n } catch (e) {\n throw new Error(\n `failed to resolve ref \"${ref}\" for ${owner}/${repo}: ${e instanceof Error ? e.message : String(e)}`,\n )\n }\n }\n }\n}\n\n/**\n * Clear the ref resolution cache (in-memory only).\n */\nexport async function clearRefCache(): Promise<void> {\n if (_githubCache) {\n await _githubCache.clear({ memoOnly: true })\n }\n}\n\n/**\n * Get GitHub token from git config if not in environment.\n * Falls back to checking git config for github.token.\n */\nexport async function getGitHubTokenFromGitConfig(\n options?: SpawnOptions,\n): Promise<string | undefined> {\n try {\n const result = await spawn('git', ['config', 'github.token'], {\n ...options,\n stdio: 'pipe',\n })\n if (result.code === 0 && result.stdout) {\n return result.stdout.toString().trim()\n }\n } catch {\n // Ignore errors - git config may not have token.\n }\n return undefined\n}\n\n/**\n * Get GitHub token from all available sources.\n * Checks environment variables first, then git config.\n */\nexport async function getGitHubTokenWithFallback(): Promise<\n string | undefined\n> {\n return getGitHubToken() || (await getGitHubTokenFromGitConfig())\n}\n\n// GHSA (GitHub Security Advisory) types and utilities.\nexport interface GhsaDetails {\n ghsaId: string\n summary: string\n details: string\n severity: string\n aliases: string[]\n publishedAt: string\n updatedAt: string\n withdrawnAt: string | null\n references: Array<{ url: string }>\n vulnerabilities: Array<{\n package: {\n ecosystem: string\n name: string\n }\n vulnerableVersionRange: string\n firstPatchedVersion: { identifier: string } | null\n }>\n cvss: {\n score: number\n vectorString: string\n } | null\n cwes: Array<{\n cweId: string\n name: string\n description: string\n }>\n}\n\n/**\n * Generate GitHub Security Advisory URL from GHSA ID.\n */\nexport function getGhsaUrl(ghsaId: string): string {\n return `https://github.com/advisories/${ghsaId}`\n}\n\n/**\n * Fetch GitHub Security Advisory details.\n */\nexport async function fetchGhsaDetails(\n ghsaId: string,\n options?: GitHubFetchOptions,\n): Promise<GhsaDetails> {\n const url = `https://api.github.com/advisories/${ghsaId}`\n const data = await fetchGitHub<{\n aliases?: string[]\n cvss: unknown\n cwes?: Array<{ cweId: string; name: string; description: string }>\n details: string\n ghsa_id: string\n published_at: string\n references?: Array<{ url: string }>\n severity: string\n summary: string\n updated_at: string\n vulnerabilities?: Array<{\n package: { ecosystem: string; name: string }\n vulnerableVersionRange: string\n firstPatchedVersion: { identifier: string } | null\n }>\n withdrawn_at: string\n }>(url, options)\n\n return {\n ghsaId: data.ghsa_id,\n summary: data.summary,\n details: data.details,\n severity: data.severity,\n aliases: data.aliases || [],\n publishedAt: data.published_at,\n updatedAt: data.updated_at,\n withdrawnAt: data.withdrawn_at,\n references: data.references || [],\n vulnerabilities: data.vulnerabilities || [],\n cvss: data.cvss as { score: number; vectorString: string } | null,\n cwes: data.cwes || [],\n }\n}\n\n/**\n * Cached fetch for GHSA details.\n */\nexport async function cacheFetchGhsa(\n ghsaId: string,\n options?: GitHubFetchOptions,\n): Promise<GhsaDetails> {\n const cache = getGithubCache()\n const key = `ghsa:${ghsaId}`\n\n // Check cache first.\n if (!process.env['DISABLE_GITHUB_CACHE']) {\n const cached = await cache.get(key)\n if (cached) {\n return JSON.parse(cached as string) as GhsaDetails\n }\n }\n\n // Fetch and cache.\n const data = await fetchGhsaDetails(ghsaId, options)\n await cache.set(key, JSON.stringify(data))\n return data\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/**\n * @fileoverview GitHub utilities for Socket projects.\n * Provides GitHub API integration for repository operations.\n *\n * Authentication:\n * - getGitHubToken: Retrieve GitHub token from environment variables\n * - fetchGitHub: Authenticated GitHub API requests with rate limit handling\n *\n * Ref Resolution:\n * - resolveRefToSha: Convert tags/branches to commit SHAs (with memoization and persistent cache)\n * - clearRefCache: Clear the in-memory memoization cache\n *\n * Caching:\n * - Uses cacache for persistent storage with in-memory memoization\n * - Two-tier caching: in-memory (Map) for hot data, persistent (cacache) for durability\n * - Default TTL: 5 minutes\n * - Disable with DISABLE_GITHUB_CACHE env var\n *\n * Rate Limiting:\n * - Automatic rate limit detection and error messages\n * - Cache to minimize API calls\n */\n\nimport type { TtlCache } from './cache-with-ttl'\nimport { createTtlCache } from './cache-with-ttl'\nimport { httpRequest } from './http-request'\nimport type { SpawnOptions } from './spawn'\nimport { spawn } from './spawn'\n\n// GitHub API base URL constant (inlined for coverage mode compatibility).\nconst GITHUB_API_BASE_URL = 'https://api.github.com'\n\n// 5 minutes.\nconst DEFAULT_CACHE_TTL_MS = 5 * 60 * 1000\n\n// Create TTL cache instance for GitHub ref resolution.\n// Uses cacache for persistent storage with in-memory memoization.\nlet _githubCache: TtlCache | undefined\n\n/**\n * Get or create the GitHub cache instance.\n * Lazy initializes the cache with default TTL and memoization enabled.\n * Used internally for caching GitHub API responses.\n *\n * @returns The singleton cache instance\n */\nfunction getGithubCache(): TtlCache {\n if (_githubCache === undefined) {\n _githubCache = createTtlCache({\n memoize: true,\n prefix: 'github-refs',\n ttl: DEFAULT_CACHE_TTL_MS,\n })\n }\n return _githubCache\n}\n\n/**\n * Options for GitHub API fetch requests.\n */\nexport interface GitHubFetchOptions {\n /**\n * GitHub authentication token.\n * If not provided, will attempt to use token from environment variables.\n */\n token?: string | undefined\n /**\n * Additional HTTP headers to include in the request.\n * Will be merged with default headers (Accept, User-Agent, Authorization).\n */\n headers?: Record<string, string> | undefined\n}\n\n/**\n * Error thrown when GitHub API rate limit is exceeded.\n * Extends the standard Error with additional rate limit information.\n */\nexport interface GitHubRateLimitError extends Error {\n /** HTTP status code (always 403 for rate limit errors) */\n status: number\n /**\n * Date when the rate limit will reset.\n * Undefined if reset time is not available in response headers.\n */\n resetTime?: Date | undefined\n}\n\n/**\n * Get GitHub authentication token from environment variables.\n * Checks multiple environment variable names in priority order.\n *\n * Environment variables checked (in order):\n * 1. `GITHUB_TOKEN` - Standard GitHub token variable\n * 2. `GH_TOKEN` - Alternative GitHub CLI token variable\n * 3. `SOCKET_CLI_GITHUB_TOKEN` - Socket-specific token variable\n *\n * @returns The first available GitHub token, or `undefined` if none found\n *\n * @example\n * ```ts\n * const token = getGitHubToken()\n * if (!token) {\n * console.warn('No GitHub token found')\n * }\n * ```\n */\nexport function getGitHubToken(): string | undefined {\n const { env } = process\n return (\n env['GITHUB_TOKEN'] ||\n env['GH_TOKEN'] ||\n env['SOCKET_CLI_GITHUB_TOKEN'] ||\n undefined\n )\n}\n\n/**\n * Fetch data from GitHub API with automatic authentication and rate limit handling.\n * Makes authenticated requests to the GitHub REST API with proper error handling.\n *\n * Features:\n * - Automatic token injection from environment if not provided\n * - Rate limit detection with helpful error messages\n * - Standard GitHub API headers (Accept, User-Agent)\n * - JSON response parsing\n *\n * @template T - Expected response type (defaults to `unknown`)\n * @param url - Full GitHub API URL (e.g., 'https://api.github.com/repos/owner/repo')\n * @param options - Fetch options including token and custom headers\n * @returns Parsed JSON response of type `T`\n *\n * @throws {GitHubRateLimitError} When API rate limit is exceeded (status 403)\n * @throws {Error} For other API errors with status code and message\n *\n * @example\n * ```ts\n * // Fetch repository information\n * interface Repo {\n * name: string\n * full_name: string\n * default_branch: string\n * }\n * const repo = await fetchGitHub<Repo>(\n * 'https://api.github.com/repos/owner/repo'\n * )\n * console.log(`Default branch: ${repo.default_branch}`)\n * ```\n *\n * @example\n * ```ts\n * // With custom token and headers\n * const data = await fetchGitHub(\n * 'https://api.github.com/user',\n * {\n * token: 'ghp_customtoken',\n * headers: { 'X-Custom-Header': 'value' }\n * }\n * )\n * ```\n *\n * @example\n * ```ts\n * // Handle rate limit errors\n * try {\n * await fetchGitHub('https://api.github.com/repos/owner/repo')\n * } catch (error) {\n * if (error.status === 403 && error.resetTime) {\n * console.error(`Rate limited until ${error.resetTime}`)\n * }\n * }\n * ```\n */\nexport async function fetchGitHub<T = unknown>(\n url: string,\n options?: GitHubFetchOptions | undefined,\n): Promise<T> {\n const opts = { __proto__: null, ...options } as GitHubFetchOptions\n const token = opts.token || getGitHubToken()\n\n const headers: Record<string, string> = {\n Accept: 'application/vnd.github.v3+json',\n 'User-Agent': 'socket-registry-github-client',\n ...opts.headers,\n }\n\n if (token) {\n headers['Authorization'] = `Bearer ${token}`\n }\n\n const response = await httpRequest(url, { headers })\n\n if (!response.ok) {\n if (response.status === 403) {\n const rateLimit = response.headers['x-ratelimit-remaining']\n const rateLimitStr =\n typeof rateLimit === 'string' ? rateLimit : rateLimit?.[0]\n if (rateLimitStr === '0') {\n const resetTime = response.headers['x-ratelimit-reset']\n const resetTimeStr =\n typeof resetTime === 'string' ? resetTime : resetTime?.[0]\n const resetDate = resetTimeStr\n ? new Date(Number(resetTimeStr) * 1000)\n : undefined\n const error = new Error(\n `GitHub API rate limit exceeded${resetDate ? `. Resets at ${resetDate.toLocaleString()}` : ''}. Use GITHUB_TOKEN environment variable to increase rate limit.`,\n ) as GitHubRateLimitError\n error.status = 403\n error.resetTime = resetDate\n throw error\n }\n }\n throw new Error(\n `GitHub API error ${response.status}: ${response.statusText}`,\n )\n }\n\n return JSON.parse(response.body.toString('utf8')) as T\n}\n\n/**\n * GitHub ref object returned by the API.\n * Represents a git reference (tag or branch).\n */\nexport interface GitHubRef {\n /** The object this ref points to */\n object: {\n /** SHA of the commit or tag object */\n sha: string\n /** Type of object ('commit' or 'tag') */\n type: string\n /** API URL to fetch the full object details */\n url: string\n }\n /** Full ref path (e.g., 'refs/tags/v1.0.0' or 'refs/heads/main') */\n ref: string\n /** API URL for this ref */\n url: string\n}\n\n/**\n * GitHub annotated tag object returned by the API.\n * Represents a git tag with metadata.\n */\nexport interface GitHubTag {\n /** Tag annotation message */\n message: string\n /** The commit this tag points to */\n object: {\n /** SHA of the commit */\n sha: string\n /** Type of object (usually 'commit') */\n type: string\n /** API URL to fetch the commit details */\n url: string\n }\n /** SHA of this tag object itself */\n sha: string\n /** Tag name (e.g., 'v1.0.0') */\n tag: string\n /**\n * Information about who created the tag.\n * Undefined for lightweight tags.\n */\n tagger?: {\n /** Tag creation date in ISO 8601 format */\n date: string\n /** Tagger's email address */\n email: string\n /** Tagger's name */\n name: string\n }\n /** API URL for this tag object */\n url: string\n}\n\n/**\n * GitHub commit object returned by the API.\n * Represents a git commit with metadata.\n */\nexport interface GitHubCommit {\n /** Full commit SHA */\n sha: string\n /** API URL for this commit */\n url: string\n /** Commit details */\n commit: {\n /** Commit message */\n message: string\n /** Author information */\n author: {\n /** Commit author date in ISO 8601 format */\n date: string\n /** Author's email address */\n email: string\n /** Author's name */\n name: string\n }\n }\n}\n\n/**\n * Options for resolving git refs to commit SHAs.\n */\nexport interface ResolveRefOptions {\n /**\n * GitHub authentication token.\n * If not provided, will attempt to use token from environment variables.\n */\n token?: string | undefined\n}\n\n/**\n * Resolve a git ref (tag, branch, or commit SHA) to its full commit SHA.\n * Handles tags (annotated and lightweight), branches, and commit SHAs.\n * Results are cached in-memory and on disk (with TTL) to minimize API calls.\n *\n * Resolution strategy:\n * 1. Try as a tag (refs/tags/{ref})\n * 2. If tag is annotated, dereference to get the commit SHA\n * 3. If not a tag, try as a branch (refs/heads/{ref})\n * 4. If not a branch, try as a commit SHA directly\n *\n * Caching behavior:\n * - In-memory cache (Map) for immediate lookups\n * - Persistent disk cache (cacache) for durability across runs\n * - Default TTL: 5 minutes\n * - Disable caching with `DISABLE_GITHUB_CACHE` env var\n *\n * @param owner - Repository owner (user or organization name)\n * @param repo - Repository name\n * @param ref - Git reference to resolve (tag name, branch name, or commit SHA)\n * @param options - Resolution options including authentication token\n * @returns The full commit SHA (40-character hex string)\n *\n * @throws {Error} When ref cannot be resolved after trying all strategies\n * @throws {GitHubRateLimitError} When API rate limit is exceeded\n *\n * @example\n * ```ts\n * // Resolve a tag to commit SHA\n * const sha = await resolveRefToSha('owner', 'repo', 'v1.0.0')\n * console.log(sha) // 'a1b2c3d4e5f6...'\n * ```\n *\n * @example\n * ```ts\n * // Resolve a branch to latest commit SHA\n * const sha = await resolveRefToSha('owner', 'repo', 'main')\n * console.log(sha) // Latest commit on main branch\n * ```\n *\n * @example\n * ```ts\n * // Resolve with custom token\n * const sha = await resolveRefToSha(\n * 'owner',\n * 'repo',\n * 'develop',\n * { token: 'ghp_customtoken' }\n * )\n * ```\n *\n * @example\n * ```ts\n * // Commit SHA passes through unchanged (but validates it exists)\n * const sha = await resolveRefToSha('owner', 'repo', 'a1b2c3d4')\n * console.log(sha) // Full 40-char SHA\n * ```\n */\nexport async function resolveRefToSha(\n owner: string,\n repo: string,\n ref: string,\n options?: ResolveRefOptions | undefined,\n): Promise<string> {\n const opts = {\n __proto__: null,\n ...options,\n } as ResolveRefOptions\n\n const cacheKey = `${owner}/${repo}@${ref}`\n\n // Optionally disable cache.\n if (process.env['DISABLE_GITHUB_CACHE']) {\n return await fetchRefSha(owner, repo, ref, opts)\n }\n\n // Use TTL cache for persistent storage and in-memory memoization.\n const cache = getGithubCache()\n return await cache.getOrFetch(cacheKey, async () => {\n return await fetchRefSha(owner, repo, ref, opts)\n })\n}\n\n/**\n * Fetch the SHA for a git ref from GitHub API.\n * Internal helper that implements the multi-strategy ref resolution logic.\n * Tries tags, branches, and direct commit lookups in sequence.\n *\n * @param owner - Repository owner\n * @param repo - Repository name\n * @param ref - Git reference to resolve\n * @param options - Resolution options with authentication token\n * @returns The full commit SHA\n *\n * @throws {Error} When ref cannot be resolved after all strategies fail\n */\nasync function fetchRefSha(\n owner: string,\n repo: string,\n ref: string,\n options: ResolveRefOptions,\n): Promise<string> {\n const fetchOptions: GitHubFetchOptions = {\n token: options.token,\n }\n\n try {\n // Try as a tag first.\n const tagUrl = `${GITHUB_API_BASE_URL}/repos/${owner}/${repo}/git/refs/tags/${ref}`\n const tagData = await fetchGitHub<GitHubRef>(tagUrl, fetchOptions)\n\n // Tag might point to a tag object or directly to a commit.\n if (tagData.object.type === 'tag') {\n // Dereference the tag object to get the commit.\n const tagObject = await fetchGitHub<GitHubTag>(\n tagData.object.url,\n fetchOptions,\n )\n return tagObject.object.sha\n }\n return tagData.object.sha\n } catch {\n // Not a tag, try as a branch.\n try {\n const branchUrl = `${GITHUB_API_BASE_URL}/repos/${owner}/${repo}/git/refs/heads/${ref}`\n const branchData = await fetchGitHub<GitHubRef>(branchUrl, fetchOptions)\n return branchData.object.sha\n } catch {\n // Try without refs/ prefix (for commit SHAs or other refs).\n try {\n const commitUrl = `${GITHUB_API_BASE_URL}/repos/${owner}/${repo}/commits/${ref}`\n const commitData = await fetchGitHub<GitHubCommit>(\n commitUrl,\n fetchOptions,\n )\n return commitData.sha\n } catch (e) {\n throw new Error(\n `failed to resolve ref \"${ref}\" for ${owner}/${repo}: ${e instanceof Error ? e.message : String(e)}`,\n )\n }\n }\n }\n}\n\n/**\n * Clear the ref resolution cache (in-memory only).\n * Clears the in-memory memoization cache without affecting the persistent disk cache.\n * Useful for testing or when you need fresh data from the API.\n *\n * Note: This only clears the in-memory cache. The persistent cacache storage\n * remains intact and will be used to rebuild the in-memory cache on next access.\n *\n * @returns Promise that resolves when cache is cleared\n *\n * @example\n * ```ts\n * // Clear cache to force fresh API calls\n * await clearRefCache()\n * const sha = await resolveRefToSha('owner', 'repo', 'main')\n * // This will hit the persistent cache or API, not in-memory cache\n * ```\n */\nexport async function clearRefCache(): Promise<void> {\n if (_githubCache) {\n await _githubCache.clear({ memoOnly: true })\n }\n}\n\n/**\n * Get GitHub authentication token from git config.\n * Reads the `github.token` configuration value from git config.\n * This is a fallback method when environment variables don't contain a token.\n *\n * @param options - Spawn options for git command execution\n * @returns GitHub token from git config, or `undefined` if not configured\n *\n * @example\n * ```ts\n * const token = await getGitHubTokenFromGitConfig()\n * if (token) {\n * console.log('Found token in git config')\n * }\n * ```\n *\n * @example\n * ```ts\n * // With custom working directory\n * const token = await getGitHubTokenFromGitConfig({\n * cwd: '/path/to/repo'\n * })\n * ```\n */\nexport async function getGitHubTokenFromGitConfig(\n options?: SpawnOptions | undefined,\n): Promise<string | undefined> {\n try {\n const result = await spawn('git', ['config', 'github.token'], {\n ...options,\n stdio: 'pipe',\n })\n if (result.code === 0 && result.stdout) {\n return result.stdout.toString().trim()\n }\n } catch {\n // Ignore errors - git config may not have token.\n }\n return undefined\n}\n\n/**\n * Get GitHub authentication token from all available sources.\n * Checks environment variables first, then falls back to git config.\n * This is the recommended way to get a GitHub token with maximum compatibility.\n *\n * Priority order:\n * 1. Environment variables (GITHUB_TOKEN, GH_TOKEN, SOCKET_CLI_GITHUB_TOKEN)\n * 2. Git config (github.token)\n *\n * @returns GitHub token from first available source, or `undefined` if none found\n *\n * @example\n * ```ts\n * const token = await getGitHubTokenWithFallback()\n * if (!token) {\n * throw new Error('GitHub token required')\n * }\n * ```\n */\nexport async function getGitHubTokenWithFallback(): Promise<\n string | undefined\n> {\n return getGitHubToken() || (await getGitHubTokenFromGitConfig())\n}\n\n/**\n * GitHub Security Advisory (GHSA) details.\n * Represents a complete security advisory from GitHub's database.\n */\nexport interface GhsaDetails {\n /** GHSA identifier (e.g., 'GHSA-xxxx-yyyy-zzzz') */\n ghsaId: string\n /** Short summary of the vulnerability */\n summary: string\n /** Detailed description of the vulnerability */\n details: string\n /** Severity level ('low', 'moderate', 'high', 'critical') */\n severity: string\n /** Alternative identifiers (CVE IDs, etc.) */\n aliases: string[]\n /** ISO 8601 timestamp when advisory was published */\n publishedAt: string\n /** ISO 8601 timestamp when advisory was last updated */\n updatedAt: string\n /**\n * ISO 8601 timestamp when advisory was withdrawn.\n * `null` if advisory is still active.\n */\n withdrawnAt: string | null\n /** External reference URLs for more information */\n references: Array<{ url: string }>\n /** Affected packages and version ranges */\n vulnerabilities: Array<{\n /** Package information */\n package: {\n /** Ecosystem (e.g., 'npm', 'pip', 'maven') */\n ecosystem: string\n /** Package name */\n name: string\n }\n /** Version range expression for vulnerable versions */\n vulnerableVersionRange: string\n /**\n * First patched version that fixes the vulnerability.\n * `null` if no patched version exists yet.\n */\n firstPatchedVersion: { identifier: string } | null\n }>\n /**\n * CVSS (Common Vulnerability Scoring System) information.\n * `null` if CVSS score is not available.\n */\n cvss: {\n /** CVSS score (0.0-10.0) */\n score: number\n /** CVSS vector string describing the vulnerability characteristics */\n vectorString: string\n } | null\n /** CWE (Common Weakness Enumeration) categories */\n cwes: Array<{\n /** CWE identifier (e.g., 'CWE-79') */\n cweId: string\n /** Human-readable CWE name */\n name: string\n /** Description of the weakness category */\n description: string\n }>\n}\n\n/**\n * Generate GitHub Security Advisory URL from GHSA ID.\n * Constructs the public advisory URL for a given GHSA identifier.\n *\n * @param ghsaId - GHSA identifier (e.g., 'GHSA-xxxx-yyyy-zzzz')\n * @returns Full URL to the advisory page\n *\n * @example\n * ```ts\n * const url = getGhsaUrl('GHSA-1234-5678-90ab')\n * console.log(url) // 'https://github.com/advisories/GHSA-1234-5678-90ab'\n * ```\n */\nexport function getGhsaUrl(ghsaId: string): string {\n return `https://github.com/advisories/${ghsaId}`\n}\n\n/**\n * Fetch GitHub Security Advisory details from the API.\n * Retrieves complete advisory information including severity, affected packages,\n * CVSS scores, and CWE classifications.\n *\n * @param ghsaId - GHSA identifier to fetch (e.g., 'GHSA-xxxx-yyyy-zzzz')\n * @param options - Fetch options including authentication token\n * @returns Complete advisory details with normalized field names\n *\n * @throws {Error} If advisory cannot be found or API request fails\n * @throws {GitHubRateLimitError} When API rate limit is exceeded\n *\n * @example\n * ```ts\n * const advisory = await fetchGhsaDetails('GHSA-1234-5678-90ab')\n * console.log(`Severity: ${advisory.severity}`)\n * console.log(`Affects: ${advisory.vulnerabilities.length} packages`)\n * if (advisory.cvss) {\n * console.log(`CVSS Score: ${advisory.cvss.score}`)\n * }\n * ```\n *\n * @example\n * ```ts\n * // Check if vulnerability is patched\n * const advisory = await fetchGhsaDetails('GHSA-xxxx-yyyy-zzzz')\n * for (const vuln of advisory.vulnerabilities) {\n * if (vuln.firstPatchedVersion) {\n * console.log(\n * `Patched in ${vuln.package.name}@${vuln.firstPatchedVersion.identifier}`\n * )\n * }\n * }\n * ```\n */\nexport async function fetchGhsaDetails(\n ghsaId: string,\n options?: GitHubFetchOptions | undefined,\n): Promise<GhsaDetails> {\n const url = `https://api.github.com/advisories/${ghsaId}`\n const data = await fetchGitHub<{\n aliases?: string[]\n cvss: unknown\n cwes?: Array<{ cweId: string; name: string; description: string }>\n details: string\n ghsa_id: string\n published_at: string\n references?: Array<{ url: string }>\n severity: string\n summary: string\n updated_at: string\n vulnerabilities?: Array<{\n package: { ecosystem: string; name: string }\n vulnerableVersionRange: string\n firstPatchedVersion: { identifier: string } | null\n }>\n withdrawn_at: string\n }>(url, options)\n\n return {\n ghsaId: data.ghsa_id,\n summary: data.summary,\n details: data.details,\n severity: data.severity,\n aliases: data.aliases || [],\n publishedAt: data.published_at,\n updatedAt: data.updated_at,\n withdrawnAt: data.withdrawn_at,\n references: data.references || [],\n vulnerabilities: data.vulnerabilities || [],\n cvss: data.cvss as { score: number; vectorString: string } | null,\n cwes: data.cwes || [],\n }\n}\n\n/**\n * Fetch GitHub Security Advisory details with caching.\n * Retrieves advisory information with two-tier caching (in-memory + persistent).\n * Cached results are stored with the default TTL (5 minutes).\n *\n * Caching behavior:\n * - Checks in-memory cache first for immediate response\n * - Falls back to persistent disk cache if not in memory\n * - Fetches from API only if not cached\n * - Stores result in both cache tiers\n * - Respects `DISABLE_GITHUB_CACHE` env var\n *\n * @param ghsaId - GHSA identifier to fetch\n * @param options - Fetch options including authentication token\n * @returns Complete advisory details\n *\n * @throws {Error} If advisory cannot be found or API request fails\n * @throws {GitHubRateLimitError} When API rate limit is exceeded\n *\n * @example\n * ```ts\n * // First call hits API\n * const advisory = await cacheFetchGhsa('GHSA-1234-5678-90ab')\n *\n * // Second call within 5 minutes returns cached data\n * const cached = await cacheFetchGhsa('GHSA-1234-5678-90ab')\n * ```\n *\n * @example\n * ```ts\n * // Disable caching for fresh data\n * process.env.DISABLE_GITHUB_CACHE = '1'\n * const advisory = await cacheFetchGhsa('GHSA-xxxx-yyyy-zzzz')\n * ```\n */\nexport async function cacheFetchGhsa(\n ghsaId: string,\n options?: GitHubFetchOptions | undefined,\n): Promise<GhsaDetails> {\n const cache = getGithubCache()\n const key = `ghsa:${ghsaId}`\n\n // Check cache first.\n if (!process.env['DISABLE_GITHUB_CACHE']) {\n const cached = await cache.get(key)\n if (cached) {\n return JSON.parse(cached as string) as GhsaDetails\n }\n }\n\n // Fetch and cache.\n const data = await fetchGhsaDetails(ghsaId, options)\n await cache.set(key, JSON.stringify(data))\n return data\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,53 +1,512 @@
1
+ /**
2
+ * Configuration options for HTTP/HTTPS requests.
3
+ */
1
4
  export interface HttpRequestOptions {
5
+ /**
6
+ * Request body to send.
7
+ * Can be a string (e.g., JSON) or Buffer (e.g., binary data).
8
+ *
9
+ * @example
10
+ * ```ts
11
+ * // Send JSON data
12
+ * await httpRequest('https://api.example.com/data', {
13
+ * method: 'POST',
14
+ * body: JSON.stringify({ name: 'Alice' }),
15
+ * headers: { 'Content-Type': 'application/json' }
16
+ * })
17
+ *
18
+ * // Send binary data
19
+ * const buffer = Buffer.from([0x00, 0x01, 0x02])
20
+ * await httpRequest('https://api.example.com/upload', {
21
+ * method: 'POST',
22
+ * body: buffer
23
+ * })
24
+ * ```
25
+ */
2
26
  body?: Buffer | string | undefined;
27
+ /**
28
+ * Whether to automatically follow HTTP redirects (3xx status codes).
29
+ *
30
+ * @default true
31
+ *
32
+ * @example
33
+ * ```ts
34
+ * // Follow redirects (default)
35
+ * await httpRequest('https://example.com/redirect')
36
+ *
37
+ * // Don't follow redirects
38
+ * const response = await httpRequest('https://example.com/redirect', {
39
+ * followRedirects: false
40
+ * })
41
+ * console.log(response.status) // 301 or 302
42
+ * ```
43
+ */
3
44
  followRedirects?: boolean | undefined;
45
+ /**
46
+ * HTTP headers to send with the request.
47
+ * A `User-Agent` header is automatically added if not provided.
48
+ *
49
+ * @example
50
+ * ```ts
51
+ * await httpRequest('https://api.example.com/data', {
52
+ * headers: {
53
+ * 'Authorization': 'Bearer token123',
54
+ * 'Content-Type': 'application/json',
55
+ * 'Accept': 'application/json'
56
+ * }
57
+ * })
58
+ * ```
59
+ */
4
60
  headers?: Record<string, string> | undefined;
61
+ /**
62
+ * Maximum number of redirects to follow before throwing an error.
63
+ * Only relevant when `followRedirects` is `true`.
64
+ *
65
+ * @default 5
66
+ *
67
+ * @example
68
+ * ```ts
69
+ * // Allow up to 10 redirects
70
+ * await httpRequest('https://example.com/many-redirects', {
71
+ * maxRedirects: 10
72
+ * })
73
+ * ```
74
+ */
5
75
  maxRedirects?: number | undefined;
76
+ /**
77
+ * HTTP method to use for the request.
78
+ *
79
+ * @default 'GET'
80
+ *
81
+ * @example
82
+ * ```ts
83
+ * // GET request (default)
84
+ * await httpRequest('https://api.example.com/data')
85
+ *
86
+ * // POST request
87
+ * await httpRequest('https://api.example.com/data', {
88
+ * method: 'POST',
89
+ * body: JSON.stringify({ name: 'Alice' })
90
+ * })
91
+ *
92
+ * // DELETE request
93
+ * await httpRequest('https://api.example.com/data/123', {
94
+ * method: 'DELETE'
95
+ * })
96
+ * ```
97
+ */
6
98
  method?: string | undefined;
99
+ /**
100
+ * Number of retry attempts for failed requests.
101
+ * Uses exponential backoff: delay = `retryDelay` * 2^attempt.
102
+ *
103
+ * @default 0
104
+ *
105
+ * @example
106
+ * ```ts
107
+ * // Retry up to 3 times with exponential backoff
108
+ * await httpRequest('https://api.example.com/data', {
109
+ * retries: 3,
110
+ * retryDelay: 1000 // 1s, then 2s, then 4s
111
+ * })
112
+ * ```
113
+ */
7
114
  retries?: number | undefined;
115
+ /**
116
+ * Initial delay in milliseconds before first retry.
117
+ * Subsequent retries use exponential backoff.
118
+ *
119
+ * @default 1000
120
+ *
121
+ * @example
122
+ * ```ts
123
+ * // Start with 2 second delay, then 4s, 8s, etc.
124
+ * await httpRequest('https://api.example.com/data', {
125
+ * retries: 3,
126
+ * retryDelay: 2000
127
+ * })
128
+ * ```
129
+ */
8
130
  retryDelay?: number | undefined;
131
+ /**
132
+ * Request timeout in milliseconds.
133
+ * If the request takes longer than this, it will be aborted.
134
+ *
135
+ * @default 30000
136
+ *
137
+ * @example
138
+ * ```ts
139
+ * // 60 second timeout
140
+ * await httpRequest('https://api.example.com/slow-endpoint', {
141
+ * timeout: 60000
142
+ * })
143
+ * ```
144
+ */
9
145
  timeout?: number | undefined;
10
146
  }
147
+ /**
148
+ * HTTP response object with fetch-like interface.
149
+ * Provides multiple ways to access the response body.
150
+ */
11
151
  export interface HttpResponse {
152
+ /**
153
+ * Get response body as ArrayBuffer.
154
+ * Useful for binary data or when you need compatibility with browser APIs.
155
+ *
156
+ * @returns The response body as an ArrayBuffer
157
+ *
158
+ * @example
159
+ * ```ts
160
+ * const response = await httpRequest('https://example.com/image.png')
161
+ * const arrayBuffer = response.arrayBuffer()
162
+ * console.log(arrayBuffer.byteLength)
163
+ * ```
164
+ */
12
165
  arrayBuffer(): ArrayBuffer;
166
+ /**
167
+ * Raw response body as Buffer.
168
+ * Direct access to the underlying Node.js Buffer.
169
+ *
170
+ * @example
171
+ * ```ts
172
+ * const response = await httpRequest('https://example.com/data')
173
+ * console.log(response.body.length) // Size in bytes
174
+ * console.log(response.body.toString('hex')) // View as hex
175
+ * ```
176
+ */
13
177
  body: Buffer;
178
+ /**
179
+ * HTTP response headers.
180
+ * Keys are lowercase header names, values can be strings or string arrays.
181
+ *
182
+ * @example
183
+ * ```ts
184
+ * const response = await httpRequest('https://example.com')
185
+ * console.log(response.headers['content-type'])
186
+ * console.log(response.headers['set-cookie']) // May be string[]
187
+ * ```
188
+ */
14
189
  headers: Record<string, string | string[] | undefined>;
190
+ /**
191
+ * Parse response body as JSON.
192
+ * Type parameter `T` allows specifying the expected JSON structure.
193
+ *
194
+ * @template T - Expected JSON type (defaults to `unknown`)
195
+ * @returns Parsed JSON data
196
+ * @throws {SyntaxError} When response body is not valid JSON
197
+ *
198
+ * @example
199
+ * ```ts
200
+ * interface User { name: string; id: number }
201
+ * const response = await httpRequest('https://api.example.com/user')
202
+ * const user = response.json<User>()
203
+ * console.log(user.name, user.id)
204
+ * ```
205
+ */
15
206
  json<T = unknown>(): T;
207
+ /**
208
+ * Whether the request was successful (status code 200-299).
209
+ *
210
+ * @example
211
+ * ```ts
212
+ * const response = await httpRequest('https://example.com/data')
213
+ * if (response.ok) {
214
+ * console.log('Success:', response.json())
215
+ * } else {
216
+ * console.error('Failed:', response.status, response.statusText)
217
+ * }
218
+ * ```
219
+ */
16
220
  ok: boolean;
221
+ /**
222
+ * HTTP status code (e.g., 200, 404, 500).
223
+ *
224
+ * @example
225
+ * ```ts
226
+ * const response = await httpRequest('https://example.com')
227
+ * console.log(response.status) // 200, 404, etc.
228
+ * ```
229
+ */
17
230
  status: number;
231
+ /**
232
+ * HTTP status message (e.g., "OK", "Not Found", "Internal Server Error").
233
+ *
234
+ * @example
235
+ * ```ts
236
+ * const response = await httpRequest('https://example.com')
237
+ * console.log(response.statusText) // "OK"
238
+ * ```
239
+ */
18
240
  statusText: string;
241
+ /**
242
+ * Get response body as UTF-8 text string.
243
+ *
244
+ * @returns The response body as a string
245
+ *
246
+ * @example
247
+ * ```ts
248
+ * const response = await httpRequest('https://example.com')
249
+ * const html = response.text()
250
+ * console.log(html.includes('<html>'))
251
+ * ```
252
+ */
19
253
  text(): string;
20
254
  }
255
+ /**
256
+ * Configuration options for file downloads.
257
+ */
21
258
  export interface HttpDownloadOptions {
259
+ /**
260
+ * HTTP headers to send with the download request.
261
+ * A `User-Agent` header is automatically added if not provided.
262
+ *
263
+ * @example
264
+ * ```ts
265
+ * await httpDownload('https://example.com/file.zip', '/tmp/file.zip', {
266
+ * headers: {
267
+ * 'Authorization': 'Bearer token123'
268
+ * }
269
+ * })
270
+ * ```
271
+ */
22
272
  headers?: Record<string, string> | undefined;
273
+ /**
274
+ * Callback for tracking download progress.
275
+ * Called periodically as data is received.
276
+ *
277
+ * @param downloaded - Number of bytes downloaded so far
278
+ * @param total - Total file size in bytes (from Content-Length header)
279
+ *
280
+ * @example
281
+ * ```ts
282
+ * await httpDownload('https://example.com/large-file.zip', '/tmp/file.zip', {
283
+ * onProgress: (downloaded, total) => {
284
+ * const percent = ((downloaded / total) * 100).toFixed(1)
285
+ * console.log(`Progress: ${percent}%`)
286
+ * }
287
+ * })
288
+ * ```
289
+ */
23
290
  onProgress?: ((downloaded: number, total: number) => void) | undefined;
291
+ /**
292
+ * Number of retry attempts for failed downloads.
293
+ * Uses exponential backoff: delay = `retryDelay` * 2^attempt.
294
+ *
295
+ * @default 0
296
+ *
297
+ * @example
298
+ * ```ts
299
+ * // Retry up to 3 times for unreliable connections
300
+ * await httpDownload('https://example.com/file.zip', '/tmp/file.zip', {
301
+ * retries: 3,
302
+ * retryDelay: 2000
303
+ * })
304
+ * ```
305
+ */
24
306
  retries?: number | undefined;
307
+ /**
308
+ * Initial delay in milliseconds before first retry.
309
+ * Subsequent retries use exponential backoff.
310
+ *
311
+ * @default 1000
312
+ */
25
313
  retryDelay?: number | undefined;
314
+ /**
315
+ * Download timeout in milliseconds.
316
+ * If the download takes longer than this, it will be aborted.
317
+ *
318
+ * @default 120000
319
+ *
320
+ * @example
321
+ * ```ts
322
+ * // 5 minute timeout for large files
323
+ * await httpDownload('https://example.com/huge-file.zip', '/tmp/file.zip', {
324
+ * timeout: 300000
325
+ * })
326
+ * ```
327
+ */
26
328
  timeout?: number | undefined;
27
329
  }
330
+ /**
331
+ * Result of a successful file download.
332
+ */
28
333
  export interface HttpDownloadResult {
334
+ /**
335
+ * Absolute path where the file was saved.
336
+ *
337
+ * @example
338
+ * ```ts
339
+ * const result = await httpDownload('https://example.com/file.zip', '/tmp/file.zip')
340
+ * console.log(`Downloaded to: ${result.path}`)
341
+ * ```
342
+ */
29
343
  path: string;
344
+ /**
345
+ * Total size of downloaded file in bytes.
346
+ *
347
+ * @example
348
+ * ```ts
349
+ * const result = await httpDownload('https://example.com/file.zip', '/tmp/file.zip')
350
+ * console.log(`Downloaded ${result.size} bytes`)
351
+ * ```
352
+ */
30
353
  size: number;
31
354
  }
32
355
  /**
33
356
  * Make an HTTP/HTTPS request with retry logic and redirect support.
34
357
  * Provides a fetch-like API using Node.js native http/https modules.
35
- * @throws {Error} When all retries are exhausted or non-retryable error occurs.
358
+ *
359
+ * This is the main entry point for making HTTP requests. It handles retries,
360
+ * redirects, timeouts, and provides a fetch-compatible response interface.
361
+ *
362
+ * @param url - The URL to request (must start with http:// or https://)
363
+ * @param options - Request configuration options
364
+ * @returns Promise resolving to response object with `.json()`, `.text()`, etc.
365
+ * @throws {Error} When all retries are exhausted, timeout occurs, or non-retryable error happens
366
+ *
367
+ * @example
368
+ * ```ts
369
+ * // Simple GET request
370
+ * const response = await httpRequest('https://api.example.com/data')
371
+ * const data = response.json()
372
+ *
373
+ * // POST with JSON body
374
+ * const response = await httpRequest('https://api.example.com/users', {
375
+ * method: 'POST',
376
+ * headers: { 'Content-Type': 'application/json' },
377
+ * body: JSON.stringify({ name: 'Alice', email: 'alice@example.com' })
378
+ * })
379
+ *
380
+ * // With retries and timeout
381
+ * const response = await httpRequest('https://api.example.com/data', {
382
+ * retries: 3,
383
+ * retryDelay: 1000,
384
+ * timeout: 60000
385
+ * })
386
+ *
387
+ * // Don't follow redirects
388
+ * const response = await httpRequest('https://example.com/redirect', {
389
+ * followRedirects: false
390
+ * })
391
+ * console.log(response.status) // 301, 302, etc.
392
+ * ```
36
393
  */
37
394
  export declare function httpRequest(url: string, options?: HttpRequestOptions | undefined): Promise<HttpResponse>;
38
395
  /**
39
396
  * Download a file from a URL to a local path with retry logic and progress callbacks.
40
397
  * Uses streaming to avoid loading entire file in memory.
41
- * @throws {Error} When all retries are exhausted or download fails.
398
+ *
399
+ * The download is streamed directly to disk, making it memory-efficient even for
400
+ * large files. Progress callbacks allow for real-time download status updates.
401
+ *
402
+ * @param url - The URL to download from (must start with http:// or https://)
403
+ * @param destPath - Absolute path where the file should be saved
404
+ * @param options - Download configuration options
405
+ * @returns Promise resolving to download result with path and size
406
+ * @throws {Error} When all retries are exhausted, download fails, or file cannot be written
407
+ *
408
+ * @example
409
+ * ```ts
410
+ * // Simple download
411
+ * const result = await httpDownload(
412
+ * 'https://example.com/file.zip',
413
+ * '/tmp/file.zip'
414
+ * )
415
+ * console.log(`Downloaded ${result.size} bytes to ${result.path}`)
416
+ *
417
+ * // With progress tracking
418
+ * await httpDownload(
419
+ * 'https://example.com/large-file.zip',
420
+ * '/tmp/file.zip',
421
+ * {
422
+ * onProgress: (downloaded, total) => {
423
+ * const percent = ((downloaded / total) * 100).toFixed(1)
424
+ * console.log(`Progress: ${percent}% (${downloaded}/${total} bytes)`)
425
+ * }
426
+ * }
427
+ * )
428
+ *
429
+ * // With retries and custom timeout
430
+ * await httpDownload(
431
+ * 'https://example.com/file.zip',
432
+ * '/tmp/file.zip',
433
+ * {
434
+ * retries: 3,
435
+ * retryDelay: 2000,
436
+ * timeout: 300000, // 5 minutes
437
+ * headers: { 'Authorization': 'Bearer token123' }
438
+ * }
439
+ * )
440
+ * ```
42
441
  */
43
442
  export declare function httpDownload(url: string, destPath: string, options?: HttpDownloadOptions | undefined): Promise<HttpDownloadResult>;
44
443
  /**
45
444
  * Perform a GET request and parse JSON response.
46
- * @throws {Error} When request fails or JSON parsing fails.
445
+ * Convenience wrapper around `httpRequest` for common JSON API calls.
446
+ *
447
+ * @template T - Expected JSON response type (defaults to `unknown`)
448
+ * @param url - The URL to request (must start with http:// or https://)
449
+ * @param options - Request configuration options
450
+ * @returns Promise resolving to parsed JSON data
451
+ * @throws {Error} When request fails, response is not ok (status < 200 or >= 300), or JSON parsing fails
452
+ *
453
+ * @example
454
+ * ```ts
455
+ * // Simple JSON GET
456
+ * const data = await httpGetJson('https://api.example.com/data')
457
+ * console.log(data)
458
+ *
459
+ * // With type safety
460
+ * interface User { id: number; name: string; email: string }
461
+ * const user = await httpGetJson<User>('https://api.example.com/user/123')
462
+ * console.log(user.name, user.email)
463
+ *
464
+ * // With custom headers
465
+ * const data = await httpGetJson('https://api.example.com/data', {
466
+ * headers: {
467
+ * 'Authorization': 'Bearer token123',
468
+ * 'Accept': 'application/json'
469
+ * }
470
+ * })
471
+ *
472
+ * // With retries
473
+ * const data = await httpGetJson('https://api.example.com/data', {
474
+ * retries: 3,
475
+ * retryDelay: 1000
476
+ * })
477
+ * ```
47
478
  */
48
479
  export declare function httpGetJson<T = unknown>(url: string, options?: HttpRequestOptions | undefined): Promise<T>;
49
480
  /**
50
481
  * Perform a GET request and return text response.
51
- * @throws {Error} When request fails.
482
+ * Convenience wrapper around `httpRequest` for fetching text content.
483
+ *
484
+ * @param url - The URL to request (must start with http:// or https://)
485
+ * @param options - Request configuration options
486
+ * @returns Promise resolving to response body as UTF-8 string
487
+ * @throws {Error} When request fails or response is not ok (status < 200 or >= 300)
488
+ *
489
+ * @example
490
+ * ```ts
491
+ * // Fetch HTML
492
+ * const html = await httpGetText('https://example.com')
493
+ * console.log(html.includes('<!DOCTYPE html>'))
494
+ *
495
+ * // Fetch plain text
496
+ * const text = await httpGetText('https://example.com/file.txt')
497
+ * console.log(text)
498
+ *
499
+ * // With custom headers
500
+ * const text = await httpGetText('https://example.com/data.txt', {
501
+ * headers: {
502
+ * 'Authorization': 'Bearer token123'
503
+ * }
504
+ * })
505
+ *
506
+ * // With timeout
507
+ * const text = await httpGetText('https://example.com/large-file.txt', {
508
+ * timeout: 60000 // 1 minute
509
+ * })
510
+ * ```
52
511
  */
53
512
  export declare function httpGetText(url: string, options?: HttpRequestOptions | undefined): Promise<string>;