@settlemint/sdk-utils
Version:
Shared utilities and helper functions for SettleMint SDK modules
1 lines • 13 kB
Source Map (JSON)
{"version":3,"file":"http.cjs","names":["logLevels: Record<LogLevel, number>","level","json: { errors?: { message: string }[]; data: Data }"],"sources":["../src/logging/mask-tokens.ts","../src/logging/logger.ts","../src/retry.ts","../src/http/fetch-with-retry.ts","../src/http/graphql-fetch-with-retry.ts","../src/http/headers.ts"],"sourcesContent":["/**\n * Masks sensitive SettleMint tokens in output text by replacing them with asterisks.\n * Handles personal access tokens (PAT), application access tokens (AAT), and service account tokens (SAT).\n *\n * @param output - The text string that may contain sensitive tokens\n * @returns The text with any sensitive tokens masked with asterisks\n * @example\n * import { maskTokens } from \"@settlemint/sdk-utils/terminal\";\n *\n * // Masks a token in text\n * const masked = maskTokens(\"Token: sm_pat_****\"); // \"Token: ***\"\n */\nexport const maskTokens = (output: string): string => {\n return output.replace(/sm_(pat|aat|sat)_[0-9a-zA-Z]+/g, \"***\");\n};\n","import { maskTokens } from \"./mask-tokens.js\";\n\n/**\n * Log levels supported by the logger\n */\nexport type LogLevel = \"debug\" | \"info\" | \"warn\" | \"error\" | \"none\";\n\n/**\n * Configuration options for the logger\n * @interface LoggerOptions\n */\nexport interface LoggerOptions {\n /** The minimum log level to output */\n level?: LogLevel;\n /** The prefix to add to the log message */\n prefix?: string;\n}\n\n/**\n * Simple logger interface with basic logging methods\n * @interface Logger\n */\nexport interface Logger {\n /** Log debug information */\n debug: (message: string, ...args: unknown[]) => void;\n /** Log general information */\n info: (message: string, ...args: unknown[]) => void;\n /** Log warnings */\n warn: (message: string, ...args: unknown[]) => void;\n /** Log errors */\n error: (message: string, ...args: unknown[]) => void;\n}\n\n/**\n * Creates a simple logger with configurable log level\n *\n * @param options - Configuration options for the logger\n * @param options.level - The minimum log level to output (default: warn)\n * @param options.prefix - The prefix to add to the log message (default: \"\")\n * @returns A logger instance with debug, info, warn, and error methods\n *\n * @example\n * import { createLogger } from \"@/utils/logging/logger\";\n *\n * const logger = createLogger({ level: 'info' });\n *\n * logger.info('User logged in', { userId: '123' });\n * logger.error('Operation failed', new Error('Connection timeout'));\n */\nexport function createLogger(options: LoggerOptions = {}): Logger {\n const { level = \"warn\", prefix = \"\" } = options;\n\n const logLevels: Record<LogLevel, number> = {\n debug: 0,\n info: 1,\n warn: 2,\n error: 3,\n none: 4,\n };\n\n const currentLevelValue = logLevels[level];\n\n const formatArgs = (args: unknown[]): string => {\n if (args.length === 0 || args.every((arg) => arg === undefined || arg === null)) {\n return \"\";\n }\n\n const formatted = args\n .map((arg) => {\n if (arg instanceof Error) {\n return `\\n${arg.stack || arg.message}`;\n }\n if (typeof arg === \"object\" && arg !== null) {\n return `\\n${JSON.stringify(arg, null, 2)}`;\n }\n return ` ${String(arg)}`;\n })\n .join(\"\");\n\n return `, args:${formatted}`;\n };\n\n const shouldLog = (level: LogLevel): boolean => {\n return logLevels[level] >= currentLevelValue;\n };\n\n return {\n debug: (message: string, ...args: unknown[]) => {\n if (shouldLog(\"debug\")) {\n console.debug(`\\x1b[32m${prefix}[DEBUG] ${maskTokens(message)}${maskTokens(formatArgs(args))}\\x1b[0m`);\n }\n },\n info: (message: string, ...args: unknown[]) => {\n if (shouldLog(\"info\")) {\n console.info(`\\x1b[34m${prefix}[INFO] ${maskTokens(message)}${maskTokens(formatArgs(args))}\\x1b[0m`);\n }\n },\n warn: (message: string, ...args: unknown[]) => {\n if (shouldLog(\"warn\")) {\n console.warn(`\\x1b[33m${prefix}[WARN] ${maskTokens(message)}${maskTokens(formatArgs(args))}\\x1b[0m`);\n }\n },\n error: (message: string, ...args: unknown[]) => {\n if (shouldLog(\"error\")) {\n console.error(`\\x1b[31m${prefix}[ERROR] ${maskTokens(message)}${maskTokens(formatArgs(args))}\\x1b[0m`);\n }\n },\n };\n}\n\n/**\n * Default logger instance with standard configuration\n */\nexport const logger = createLogger();\n","import { logger } from \"./logging/logger.js\";\n\n/**\n * Retry a function when it fails.\n * @param fn - The function to retry.\n * @param maxRetries - The maximum number of retries.\n * @param initialSleepTime - The initial time to sleep between exponential backoff retries.\n * @param stopOnError - The function to stop on error.\n * @returns The result of the function or undefined if it fails.\n * @example\n * import { retryWhenFailed } from \"@settlemint/sdk-utils\";\n * import { readFile } from \"node:fs/promises\";\n *\n * const result = await retryWhenFailed(() => readFile(\"/path/to/file.txt\"), 3, 1_000);\n */\nexport async function retryWhenFailed<T>(\n fn: () => Promise<T>,\n maxRetries = 5,\n initialSleepTime = 1_000,\n stopOnError?: (error: Error) => boolean,\n): Promise<T> {\n let retries = 0;\n const maxAttempts = maxRetries + 1;\n\n while (retries < maxAttempts) {\n try {\n return await fn();\n } catch (e) {\n const error = e as Error;\n if (typeof stopOnError === \"function\") {\n if (stopOnError(error)) {\n throw error;\n }\n }\n if (retries >= maxRetries) {\n throw e;\n }\n // Exponential backoff with jitter to prevent thundering herd\n // Jitter: Random value between 0-10% of initialSleepTime\n const baseDelay = 2 ** retries * initialSleepTime;\n const jitterAmount = initialSleepTime * (Math.random() / 10);\n const delay = baseDelay + jitterAmount;\n retries += 1;\n logger.warn(\n `An error occurred ${error.message}, retrying in ${delay.toFixed(0)}ms (retry ${retries} of ${maxRetries})...`,\n );\n await new Promise((resolve) => setTimeout(resolve, delay));\n }\n }\n\n throw new Error(\"Retry failed\");\n}\n","import { retryWhenFailed } from \"../retry.js\";\n\n/**\n * Retry an HTTP request with exponential backoff and jitter.\n * Only retries on server errors (5xx), rate limits (429), timeouts (408), and network errors.\n *\n * @param input - The URL or Request object to fetch\n * @param init - The fetch init options\n * @param maxRetries - Maximum number of retry attempts\n * @param initialSleepTime - Initial sleep time between retries in ms\n * @returns The fetch Response\n * @throws Error if all retries fail\n * @example\n * import { fetchWithRetry } from \"@settlemint/sdk-utils/http\";\n *\n * const response = await fetchWithRetry(\"https://api.example.com/data\");\n */\nexport async function fetchWithRetry(\n input: RequestInfo | URL,\n init?: RequestInit,\n maxRetries = 5,\n initialSleepTime = 3_000,\n): Promise<Response> {\n return retryWhenFailed(\n async () => {\n const response = await fetch(input, init);\n if (response.ok) {\n return response;\n }\n // Only retry on 5xx server errors, 429 rate limit, timeout, and network errors\n if (response.status < 500 && response.status !== 429 && response.status !== 408 && response.status !== 0) {\n return response;\n }\n throw new Error(`HTTP error! status: ${response.status} ${response.statusText}`);\n },\n maxRetries,\n initialSleepTime,\n );\n}\n","import { retryWhenFailed } from \"../retry.js\";\nimport { fetchWithRetry } from \"./fetch-with-retry.js\";\n\n/**\n * Executes a GraphQL request with automatic retries using exponential backoff and jitter.\n * Only retries on server errors (5xx), rate limits (429), timeouts (408), and network errors.\n * Will also retry if the GraphQL response contains errors.\n *\n * @param input - The URL or Request object for the GraphQL endpoint\n * @param init - Optional fetch configuration options\n * @param maxRetries - Maximum retry attempts before failing (default: 5)\n * @param initialSleepTime - Initial delay between retries in milliseconds (default: 3000)\n * @returns The parsed GraphQL response data\n * @throws Error if all retries fail or if GraphQL response contains errors\n * @example\n * import { graphqlFetchWithRetry } from \"@settlemint/sdk-utils/http\";\n *\n * const data = await graphqlFetchWithRetry<{ user: { id: string } }>(\n * \"https://api.example.com/graphql\",\n * {\n * method: \"POST\",\n * headers: { \"Content-Type\": \"application/json\" },\n * body: JSON.stringify({\n * query: `query GetUser($id: ID!) {\n * user(id: $id) {\n * id\n * }\n * }`,\n * variables: { id: \"123\" }\n * })\n * }\n * );\n */\nexport async function graphqlFetchWithRetry<Data>(\n input: RequestInfo | URL,\n init?: RequestInit,\n maxRetries = 5,\n initialSleepTime = 3_000,\n): Promise<Data> {\n return retryWhenFailed<Data>(\n async () => {\n const response = await fetchWithRetry(input, init);\n const json: { errors?: { message: string }[]; data: Data } = await response.json();\n if (json.errors) {\n throw new Error(`GraphQL errors in response: ${json.errors.map((error) => error.message).join(\", \")}`);\n }\n return json.data;\n },\n maxRetries,\n initialSleepTime,\n );\n}\n","type MaybeLazy<T> = T | (() => T);\n\nexport function appendHeaders(\n headers: MaybeLazy<HeadersInit> | undefined,\n additionalHeaders: Record<string, string | undefined>,\n) {\n const defaultHeaders = typeof headers === \"function\" ? headers() : headers;\n const filteredAdditionalHeaders = Object.entries(additionalHeaders).filter(([_, value]) => value !== undefined) as [\n string,\n string,\n ][];\n if (Array.isArray(defaultHeaders)) {\n return [...defaultHeaders, ...filteredAdditionalHeaders];\n }\n if (defaultHeaders instanceof Headers) {\n return new Headers([...defaultHeaders, ...filteredAdditionalHeaders]);\n }\n return {\n ...defaultHeaders,\n ...Object.fromEntries(filteredAdditionalHeaders),\n };\n}\n"],"mappings":"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"}