@settlemint/sdk-utils 2.6.2-prf41b74b3 → 2.6.2-prf4fd4e0b
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/environment.cjs +24 -12
- package/dist/environment.cjs.map +1 -1
- package/dist/environment.js.map +1 -1
- package/dist/filesystem.cjs +8 -4
- package/dist/filesystem.cjs.map +1 -1
- package/dist/filesystem.js.map +1 -1
- package/dist/http.cjs.map +1 -1
- package/dist/http.js.map +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/json.cjs.map +1 -1
- package/dist/json.js.map +1 -1
- package/dist/logging.cjs.map +1 -1
- package/dist/logging.js.map +1 -1
- package/dist/package-manager.cjs +24 -12
- package/dist/package-manager.cjs.map +1 -1
- package/dist/package-manager.js.map +1 -1
- package/dist/retry.cjs.map +1 -1
- package/dist/retry.js.map +1 -1
- package/dist/runtime.cjs +2 -1
- package/dist/runtime.cjs.map +1 -1
- package/dist/runtime.js.map +1 -1
- package/dist/string.cjs.map +1 -1
- package/dist/string.js.map +1 -1
- package/dist/terminal.cjs +10 -5
- package/dist/terminal.cjs.map +1 -1
- package/dist/terminal.js.map +1 -1
- package/dist/url.cjs.map +1 -1
- package/dist/url.js.map +1 -1
- package/dist/validation.cjs +2 -1
- package/dist/validation.cjs.map +1 -1
- package/dist/validation.js.map +1 -1
- package/package.json +1 -1
package/dist/filesystem.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"filesystem.cjs","names":["value"],"sources":["../src/filesystem/project-root.ts","../src/filesystem/exists.ts","../src/json.ts","../src/filesystem/mono-repo.ts"],"sourcesContent":["import { dirname } from \"node:path\";\nimport { findUp } from \"find-up\";\n\n/**\n * Finds the root directory of the current project by locating the nearest package.json file\n *\n * @param fallbackToCwd - If true, will return the current working directory if no package.json is found\n * @param cwd - The directory to start searching for the package.json file from (defaults to process.cwd())\n * @returns Promise that resolves to the absolute path of the project root directory\n * @throws Will throw an error if no package.json is found in the directory tree\n * @example\n * import { projectRoot } from \"@settlemint/sdk-utils/filesystem\";\n *\n * // Get project root path\n * const rootDir = await projectRoot();\n * console.log(`Project root is at: ${rootDir}`);\n */\nexport async function projectRoot(fallbackToCwd = false, cwd?: string): Promise<string> {\n const packageJsonPath = await findUp(\"package.json\", { cwd });\n if (!packageJsonPath) {\n if (fallbackToCwd) {\n return process.cwd();\n }\n throw new Error(\"Unable to find project root (no package.json found)\");\n }\n return dirname(packageJsonPath);\n}\n","import type { PathLike } from \"node:fs\";\nimport { stat } from \"node:fs/promises\";\n\n/**\n * Checks if a file or directory exists at the given path\n *\n * @param path - The file system path to check for existence\n * @returns Promise that resolves to true if the path exists, false otherwise\n * @example\n * import { exists } from \"@settlemint/sdk-utils/filesystem\";\n *\n * // Check if file exists before reading\n * if (await exists('/path/to/file.txt')) {\n * // File exists, safe to read\n * }\n */\nexport async function exists(path: PathLike): Promise<boolean> {\n try {\n await stat(path);\n return true;\n } catch {\n return false;\n }\n}\n","/**\n * Attempts to parse a JSON string into a typed value, returning a default value if parsing fails.\n *\n * @param value - The JSON string to parse\n * @param defaultValue - The value to return if parsing fails or results in null/undefined\n * @returns The parsed JSON value as type T, or the default value if parsing fails\n *\n * @example\n * import { tryParseJson } from \"@settlemint/sdk-utils\";\n *\n * const config = tryParseJson<{ port: number }>(\n * '{\"port\": 3000}',\n * { port: 8080 }\n * );\n * // Returns: { port: 3000 }\n *\n * const invalid = tryParseJson<string[]>(\n * 'invalid json',\n * []\n * );\n * // Returns: []\n */\nexport function tryParseJson<T>(value: string, defaultValue: T | null = null): T | null {\n try {\n const parsed = JSON.parse(value) as T;\n if (parsed === undefined || parsed === null) {\n return defaultValue;\n }\n return parsed;\n } catch (_err) {\n // Invalid json\n return defaultValue;\n }\n}\n\n/**\n * Extracts a JSON object from a string.\n *\n * @param value - The string to extract the JSON object from\n * @returns The parsed JSON object, or null if no JSON object is found\n * @throws {Error} If the input string is too long (longer than 5000 characters)\n * @example\n * import { extractJsonObject } from \"@settlemint/sdk-utils\";\n *\n * const json = extractJsonObject<{ port: number }>(\n * 'port info: {\"port\": 3000}',\n * );\n * // Returns: { port: 3000 }\n */\nexport function extractJsonObject<T>(value: string): T | null {\n if (value.length > 5000) {\n throw new Error(\"Input too long\");\n }\n const result = /\\{([\\s\\S]*)\\}/.exec(value);\n if (!result) {\n return null;\n }\n return tryParseJson<T>(result[0]);\n}\n\n/**\n * Converts a value to a JSON stringifiable format.\n *\n * @param value - The value to convert\n * @returns The JSON stringifiable value\n *\n * @example\n * import { makeJsonStringifiable } from \"@settlemint/sdk-utils\";\n *\n * const json = makeJsonStringifiable<{ amount: bigint }>({ amount: BigInt(1000) });\n * // Returns: '{\"amount\":\"1000\"}'\n */\nexport function makeJsonStringifiable<T>(value: unknown): T {\n if (value === undefined || value === null) {\n return value as T;\n }\n return tryParseJson<T>(\n JSON.stringify(\n value,\n (_, value) => (typeof value === \"bigint\" ? value.toString() : value), // return everything else unchanged\n ),\n ) as T;\n}\n","import { readFile } from \"node:fs/promises\";\nimport { dirname, join } from \"node:path\";\nimport { findUp } from \"find-up\";\nimport { glob } from \"glob\";\nimport { exists } from \"@/filesystem.js\";\nimport { tryParseJson } from \"@/json.js\";\n\n/**\n * Finds the root directory of a monorepo\n *\n * @param startDir - The directory to start searching from\n * @returns The root directory of the monorepo or null if not found\n * @example\n * import { findMonoRepoRoot } from \"@settlemint/sdk-utils/filesystem\";\n *\n * const root = await findMonoRepoRoot(\"/path/to/your/project\");\n * console.log(root); // Output: /path/to/your/project/packages/core\n */\nexport async function findMonoRepoRoot(startDir: string): Promise<string | null> {\n const lockFilePath = await findUp([\"package-lock.json\", \"yarn.lock\", \"pnpm-lock.yaml\", \"bun.lockb\", \"bun.lock\"], {\n cwd: startDir,\n });\n if (lockFilePath) {\n const packageJsonPath = join(dirname(lockFilePath), \"package.json\");\n const hasWorkSpaces = await packageJsonHasWorkspaces(packageJsonPath);\n return hasWorkSpaces ? dirname(lockFilePath) : null;\n }\n\n let currentDir = startDir;\n\n while (currentDir !== \"/\") {\n const packageJsonPath = join(currentDir, \"package.json\");\n\n if (await packageJsonHasWorkspaces(packageJsonPath)) {\n return currentDir;\n }\n\n const parentDir = dirname(currentDir);\n if (parentDir === currentDir) {\n break; // We've reached the root\n }\n currentDir = parentDir;\n }\n\n return null;\n}\n\n/**\n * Finds all packages in a monorepo\n *\n * @param projectDir - The directory to start searching from\n * @returns An array of package directories\n * @example\n * import { findMonoRepoPackages } from \"@settlemint/sdk-utils/filesystem\";\n *\n * const packages = await findMonoRepoPackages(\"/path/to/your/project\");\n * console.log(packages); // Output: [\"/path/to/your/project/packages/core\", \"/path/to/your/project/packages/ui\"]\n */\nexport async function findMonoRepoPackages(projectDir: string): Promise<string[]> {\n try {\n const monoRepoRoot = await findMonoRepoRoot(projectDir);\n if (!monoRepoRoot) {\n return [projectDir];\n }\n\n const packageJsonPath = join(monoRepoRoot, \"package.json\");\n const packageJson = tryParseJson<{ workspaces: string[] }>(await readFile(packageJsonPath, \"utf-8\"));\n const workspaces = packageJson?.workspaces ?? [];\n\n const packagePaths = await Promise.all(\n workspaces.map(async (workspace: string) => {\n const matches = await glob(join(monoRepoRoot, workspace, \"package.json\"));\n return matches.map((match) => join(match, \"..\"));\n }),\n );\n\n const allPaths = packagePaths.flat();\n // If no packages found in workspaces, treat as non-monorepo\n return allPaths.length === 0 ? [projectDir] : [monoRepoRoot, ...allPaths];\n } catch (_error) {\n // If any error occurs, treat as non-monorepo\n return [projectDir];\n }\n}\n\nasync function packageJsonHasWorkspaces(packageJsonPath: string): Promise<boolean> {\n if (await exists(packageJsonPath)) {\n const packageJson = tryParseJson<{ workspaces: string[] }>(await readFile(packageJsonPath, \"utf-8\"));\n if (packageJson?.workspaces && Array.isArray(packageJson?.workspaces) && packageJson?.workspaces.length > 0) {\n return true;\n }\n }\n return false;\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"file":"filesystem.cjs","names":["value"],"sources":["../src/filesystem/project-root.ts","../src/filesystem/exists.ts","../src/json.ts","../src/filesystem/mono-repo.ts"],"sourcesContent":["import { dirname } from \"node:path\";\nimport { findUp } from \"find-up\";\n\n/**\n * Finds the root directory of the current project by locating the nearest package.json file\n *\n * @param fallbackToCwd - If true, will return the current working directory if no package.json is found\n * @param cwd - The directory to start searching for the package.json file from (defaults to process.cwd())\n * @returns Promise that resolves to the absolute path of the project root directory\n * @throws Will throw an error if no package.json is found in the directory tree\n * @example\n * import { projectRoot } from \"@settlemint/sdk-utils/filesystem\";\n *\n * // Get project root path\n * const rootDir = await projectRoot();\n * console.log(`Project root is at: ${rootDir}`);\n */\nexport async function projectRoot(fallbackToCwd = false, cwd?: string): Promise<string> {\n const packageJsonPath = await findUp(\"package.json\", { cwd });\n if (!packageJsonPath) {\n if (fallbackToCwd) {\n return process.cwd();\n }\n throw new Error(\"Unable to find project root (no package.json found)\");\n }\n return dirname(packageJsonPath);\n}\n","import type { PathLike } from \"node:fs\";\nimport { stat } from \"node:fs/promises\";\n\n/**\n * Checks if a file or directory exists at the given path\n *\n * @param path - The file system path to check for existence\n * @returns Promise that resolves to true if the path exists, false otherwise\n * @example\n * import { exists } from \"@settlemint/sdk-utils/filesystem\";\n *\n * // Check if file exists before reading\n * if (await exists('/path/to/file.txt')) {\n * // File exists, safe to read\n * }\n */\nexport async function exists(path: PathLike): Promise<boolean> {\n try {\n await stat(path);\n return true;\n } catch {\n return false;\n }\n}\n","/**\n * Attempts to parse a JSON string into a typed value, returning a default value if parsing fails.\n *\n * @param value - The JSON string to parse\n * @param defaultValue - The value to return if parsing fails or results in null/undefined\n * @returns The parsed JSON value as type T, or the default value if parsing fails\n *\n * @example\n * import { tryParseJson } from \"@settlemint/sdk-utils\";\n *\n * const config = tryParseJson<{ port: number }>(\n * '{\"port\": 3000}',\n * { port: 8080 }\n * );\n * // Returns: { port: 3000 }\n *\n * const invalid = tryParseJson<string[]>(\n * 'invalid json',\n * []\n * );\n * // Returns: []\n */\nexport function tryParseJson<T>(value: string, defaultValue: T | null = null): T | null {\n try {\n const parsed = JSON.parse(value) as T;\n if (parsed === undefined || parsed === null) {\n return defaultValue;\n }\n return parsed;\n } catch (_err) {\n // Invalid json\n return defaultValue;\n }\n}\n\n/**\n * Extracts a JSON object from a string.\n *\n * @param value - The string to extract the JSON object from\n * @returns The parsed JSON object, or null if no JSON object is found\n * @throws {Error} If the input string is too long (longer than 5000 characters)\n * @example\n * import { extractJsonObject } from \"@settlemint/sdk-utils\";\n *\n * const json = extractJsonObject<{ port: number }>(\n * 'port info: {\"port\": 3000}',\n * );\n * // Returns: { port: 3000 }\n */\nexport function extractJsonObject<T>(value: string): T | null {\n if (value.length > 5000) {\n throw new Error(\"Input too long\");\n }\n const result = /\\{([\\s\\S]*)\\}/.exec(value);\n if (!result) {\n return null;\n }\n return tryParseJson<T>(result[0]);\n}\n\n/**\n * Converts a value to a JSON stringifiable format.\n *\n * @param value - The value to convert\n * @returns The JSON stringifiable value\n *\n * @example\n * import { makeJsonStringifiable } from \"@settlemint/sdk-utils\";\n *\n * const json = makeJsonStringifiable<{ amount: bigint }>({ amount: BigInt(1000) });\n * // Returns: '{\"amount\":\"1000\"}'\n */\nexport function makeJsonStringifiable<T>(value: unknown): T {\n if (value === undefined || value === null) {\n return value as T;\n }\n return tryParseJson<T>(\n JSON.stringify(\n value,\n (_, value) => (typeof value === \"bigint\" ? value.toString() : value), // return everything else unchanged\n ),\n ) as T;\n}\n","import { readFile } from \"node:fs/promises\";\nimport { dirname, join } from \"node:path\";\nimport { findUp } from \"find-up\";\nimport { glob } from \"glob\";\nimport { exists } from \"@/filesystem.js\";\nimport { tryParseJson } from \"@/json.js\";\n\n/**\n * Finds the root directory of a monorepo\n *\n * @param startDir - The directory to start searching from\n * @returns The root directory of the monorepo or null if not found\n * @example\n * import { findMonoRepoRoot } from \"@settlemint/sdk-utils/filesystem\";\n *\n * const root = await findMonoRepoRoot(\"/path/to/your/project\");\n * console.log(root); // Output: /path/to/your/project/packages/core\n */\nexport async function findMonoRepoRoot(startDir: string): Promise<string | null> {\n const lockFilePath = await findUp([\"package-lock.json\", \"yarn.lock\", \"pnpm-lock.yaml\", \"bun.lockb\", \"bun.lock\"], {\n cwd: startDir,\n });\n if (lockFilePath) {\n const packageJsonPath = join(dirname(lockFilePath), \"package.json\");\n const hasWorkSpaces = await packageJsonHasWorkspaces(packageJsonPath);\n return hasWorkSpaces ? dirname(lockFilePath) : null;\n }\n\n let currentDir = startDir;\n\n while (currentDir !== \"/\") {\n const packageJsonPath = join(currentDir, \"package.json\");\n\n if (await packageJsonHasWorkspaces(packageJsonPath)) {\n return currentDir;\n }\n\n const parentDir = dirname(currentDir);\n if (parentDir === currentDir) {\n break; // We've reached the root\n }\n currentDir = parentDir;\n }\n\n return null;\n}\n\n/**\n * Finds all packages in a monorepo\n *\n * @param projectDir - The directory to start searching from\n * @returns An array of package directories\n * @example\n * import { findMonoRepoPackages } from \"@settlemint/sdk-utils/filesystem\";\n *\n * const packages = await findMonoRepoPackages(\"/path/to/your/project\");\n * console.log(packages); // Output: [\"/path/to/your/project/packages/core\", \"/path/to/your/project/packages/ui\"]\n */\nexport async function findMonoRepoPackages(projectDir: string): Promise<string[]> {\n try {\n const monoRepoRoot = await findMonoRepoRoot(projectDir);\n if (!monoRepoRoot) {\n return [projectDir];\n }\n\n const packageJsonPath = join(monoRepoRoot, \"package.json\");\n const packageJson = tryParseJson<{ workspaces: string[] }>(await readFile(packageJsonPath, \"utf-8\"));\n const workspaces = packageJson?.workspaces ?? [];\n\n const packagePaths = await Promise.all(\n workspaces.map(async (workspace: string) => {\n const matches = await glob(join(monoRepoRoot, workspace, \"package.json\"));\n return matches.map((match) => join(match, \"..\"));\n }),\n );\n\n const allPaths = packagePaths.flat();\n // If no packages found in workspaces, treat as non-monorepo\n return allPaths.length === 0 ? [projectDir] : [monoRepoRoot, ...allPaths];\n } catch (_error) {\n // If any error occurs, treat as non-monorepo\n return [projectDir];\n }\n}\n\nasync function packageJsonHasWorkspaces(packageJsonPath: string): Promise<boolean> {\n if (await exists(packageJsonPath)) {\n const packageJson = tryParseJson<{ workspaces: string[] }>(await readFile(packageJsonPath, \"utf-8\"));\n if (packageJson?.workspaces && Array.isArray(packageJson?.workspaces) && packageJson?.workspaces.length > 0) {\n return true;\n }\n }\n return false;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiBA,eAAsB,YAAY,gBAAgB,OAAO,KAA+B;CACtF,MAAM,kBAAkB,0BAAa,gBAAgB,EAAE,KAAK,CAAC;AAC7D,KAAI,CAAC,iBAAiB;AACpB,MAAI,eAAe;AACjB,UAAO,QAAQ,KAAK;;AAEtB,QAAM,IAAI,MAAM,sDAAsD;;AAExE,+BAAe,gBAAgB;;;;;;;;;;;;;;;;;;ACTjC,eAAsB,OAAO,MAAkC;AAC7D,KAAI;AACF,mCAAW,KAAK;AAChB,SAAO;SACD;AACN,SAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACCX,SAAgB,aAAgB,OAAe,eAAyB,MAAgB;AACtF,KAAI;EACF,MAAM,SAAS,KAAK,MAAM,MAAM;AAChC,MAAI,WAAW,aAAa,WAAW,MAAM;AAC3C,UAAO;;AAET,SAAO;UACA,MAAM;AAEb,SAAO;;;;;;;;;;;;;;;;;AAkBX,SAAgB,kBAAqB,OAAyB;AAC5D,KAAI,MAAM,SAAS,KAAM;AACvB,QAAM,IAAI,MAAM,iBAAiB;;CAEnC,MAAM,SAAS,gBAAgB,KAAK,MAAM;AAC1C,KAAI,CAAC,QAAQ;AACX,SAAO;;AAET,QAAO,aAAgB,OAAO,GAAG;;;;;;;;;;;;;;AAenC,SAAgB,sBAAyB,OAAmB;AAC1D,KAAI,UAAU,aAAa,UAAU,MAAM;AACzC,SAAO;;AAET,QAAO,aACL,KAAK,UACH,QACC,GAAG,YAAW,OAAOA,YAAU,WAAWA,QAAM,UAAU,GAAGA,QAC/D,CACF;;;;;;;;;;;;;;;;AC/DH,eAAsB,iBAAiB,UAA0C;CAC/E,MAAM,eAAe,0BAAa;EAAC;EAAqB;EAAa;EAAkB;EAAa;EAAW,EAAE,EAC/G,KAAK,UACN,CAAC;AACF,KAAI,cAAc;EAChB,MAAM,6DAA+B,aAAa,EAAE,eAAe;EACnE,MAAM,gBAAgB,MAAM,yBAAyB,gBAAgB;AACrE,SAAO,uCAAwB,aAAa,GAAG;;CAGjD,IAAI,aAAa;AAEjB,QAAO,eAAe,KAAK;EACzB,MAAM,sCAAuB,YAAY,eAAe;AAExD,MAAI,MAAM,yBAAyB,gBAAgB,EAAE;AACnD,UAAO;;EAGT,MAAM,mCAAoB,WAAW;AACrC,MAAI,cAAc,YAAY;AAC5B;;AAEF,eAAa;;AAGf,QAAO;;;;;;;;;;;;;AAcT,eAAsB,qBAAqB,YAAuC;AAChF,KAAI;EACF,MAAM,eAAe,MAAM,iBAAiB,WAAW;AACvD,MAAI,CAAC,cAAc;AACjB,UAAO,CAAC,WAAW;;EAGrB,MAAM,sCAAuB,cAAc,eAAe;EAC1D,MAAM,cAAc,aAAuC,qCAAe,iBAAiB,QAAQ,CAAC;EACpG,MAAM,aAAa,aAAa,cAAc,EAAE;EAEhD,MAAM,eAAe,MAAM,QAAQ,IACjC,WAAW,IAAI,OAAO,cAAsB;GAC1C,MAAM,UAAU,yCAAgB,cAAc,WAAW,eAAe,CAAC;AACzE,UAAO,QAAQ,KAAK,8BAAe,OAAO,KAAK,CAAC;IAChD,CACH;EAED,MAAM,WAAW,aAAa,MAAM;AAEpC,SAAO,SAAS,WAAW,IAAI,CAAC,WAAW,GAAG,CAAC,cAAc,GAAG,SAAS;UAClE,QAAQ;AAEf,SAAO,CAAC,WAAW;;;AAIvB,eAAe,yBAAyB,iBAA2C;AACjF,KAAI,MAAM,OAAO,gBAAgB,EAAE;EACjC,MAAM,cAAc,aAAuC,qCAAe,iBAAiB,QAAQ,CAAC;AACpG,MAAI,aAAa,cAAc,MAAM,QAAQ,aAAa,WAAW,IAAI,aAAa,WAAW,SAAS,GAAG;AAC3G,UAAO;;;AAGX,QAAO"}
|
package/dist/filesystem.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"filesystem.js","names":["value"],"sources":["../src/filesystem/project-root.ts","../src/filesystem/exists.ts","../src/json.ts","../src/filesystem/mono-repo.ts"],"sourcesContent":["import { dirname } from \"node:path\";\nimport { findUp } from \"find-up\";\n\n/**\n * Finds the root directory of the current project by locating the nearest package.json file\n *\n * @param fallbackToCwd - If true, will return the current working directory if no package.json is found\n * @param cwd - The directory to start searching for the package.json file from (defaults to process.cwd())\n * @returns Promise that resolves to the absolute path of the project root directory\n * @throws Will throw an error if no package.json is found in the directory tree\n * @example\n * import { projectRoot } from \"@settlemint/sdk-utils/filesystem\";\n *\n * // Get project root path\n * const rootDir = await projectRoot();\n * console.log(`Project root is at: ${rootDir}`);\n */\nexport async function projectRoot(fallbackToCwd = false, cwd?: string): Promise<string> {\n const packageJsonPath = await findUp(\"package.json\", { cwd });\n if (!packageJsonPath) {\n if (fallbackToCwd) {\n return process.cwd();\n }\n throw new Error(\"Unable to find project root (no package.json found)\");\n }\n return dirname(packageJsonPath);\n}\n","import type { PathLike } from \"node:fs\";\nimport { stat } from \"node:fs/promises\";\n\n/**\n * Checks if a file or directory exists at the given path\n *\n * @param path - The file system path to check for existence\n * @returns Promise that resolves to true if the path exists, false otherwise\n * @example\n * import { exists } from \"@settlemint/sdk-utils/filesystem\";\n *\n * // Check if file exists before reading\n * if (await exists('/path/to/file.txt')) {\n * // File exists, safe to read\n * }\n */\nexport async function exists(path: PathLike): Promise<boolean> {\n try {\n await stat(path);\n return true;\n } catch {\n return false;\n }\n}\n","/**\n * Attempts to parse a JSON string into a typed value, returning a default value if parsing fails.\n *\n * @param value - The JSON string to parse\n * @param defaultValue - The value to return if parsing fails or results in null/undefined\n * @returns The parsed JSON value as type T, or the default value if parsing fails\n *\n * @example\n * import { tryParseJson } from \"@settlemint/sdk-utils\";\n *\n * const config = tryParseJson<{ port: number }>(\n * '{\"port\": 3000}',\n * { port: 8080 }\n * );\n * // Returns: { port: 3000 }\n *\n * const invalid = tryParseJson<string[]>(\n * 'invalid json',\n * []\n * );\n * // Returns: []\n */\nexport function tryParseJson<T>(value: string, defaultValue: T | null = null): T | null {\n try {\n const parsed = JSON.parse(value) as T;\n if (parsed === undefined || parsed === null) {\n return defaultValue;\n }\n return parsed;\n } catch (_err) {\n // Invalid json\n return defaultValue;\n }\n}\n\n/**\n * Extracts a JSON object from a string.\n *\n * @param value - The string to extract the JSON object from\n * @returns The parsed JSON object, or null if no JSON object is found\n * @throws {Error} If the input string is too long (longer than 5000 characters)\n * @example\n * import { extractJsonObject } from \"@settlemint/sdk-utils\";\n *\n * const json = extractJsonObject<{ port: number }>(\n * 'port info: {\"port\": 3000}',\n * );\n * // Returns: { port: 3000 }\n */\nexport function extractJsonObject<T>(value: string): T | null {\n if (value.length > 5000) {\n throw new Error(\"Input too long\");\n }\n const result = /\\{([\\s\\S]*)\\}/.exec(value);\n if (!result) {\n return null;\n }\n return tryParseJson<T>(result[0]);\n}\n\n/**\n * Converts a value to a JSON stringifiable format.\n *\n * @param value - The value to convert\n * @returns The JSON stringifiable value\n *\n * @example\n * import { makeJsonStringifiable } from \"@settlemint/sdk-utils\";\n *\n * const json = makeJsonStringifiable<{ amount: bigint }>({ amount: BigInt(1000) });\n * // Returns: '{\"amount\":\"1000\"}'\n */\nexport function makeJsonStringifiable<T>(value: unknown): T {\n if (value === undefined || value === null) {\n return value as T;\n }\n return tryParseJson<T>(\n JSON.stringify(\n value,\n (_, value) => (typeof value === \"bigint\" ? value.toString() : value), // return everything else unchanged\n ),\n ) as T;\n}\n","import { readFile } from \"node:fs/promises\";\nimport { dirname, join } from \"node:path\";\nimport { findUp } from \"find-up\";\nimport { glob } from \"glob\";\nimport { exists } from \"@/filesystem.js\";\nimport { tryParseJson } from \"@/json.js\";\n\n/**\n * Finds the root directory of a monorepo\n *\n * @param startDir - The directory to start searching from\n * @returns The root directory of the monorepo or null if not found\n * @example\n * import { findMonoRepoRoot } from \"@settlemint/sdk-utils/filesystem\";\n *\n * const root = await findMonoRepoRoot(\"/path/to/your/project\");\n * console.log(root); // Output: /path/to/your/project/packages/core\n */\nexport async function findMonoRepoRoot(startDir: string): Promise<string | null> {\n const lockFilePath = await findUp([\"package-lock.json\", \"yarn.lock\", \"pnpm-lock.yaml\", \"bun.lockb\", \"bun.lock\"], {\n cwd: startDir,\n });\n if (lockFilePath) {\n const packageJsonPath = join(dirname(lockFilePath), \"package.json\");\n const hasWorkSpaces = await packageJsonHasWorkspaces(packageJsonPath);\n return hasWorkSpaces ? dirname(lockFilePath) : null;\n }\n\n let currentDir = startDir;\n\n while (currentDir !== \"/\") {\n const packageJsonPath = join(currentDir, \"package.json\");\n\n if (await packageJsonHasWorkspaces(packageJsonPath)) {\n return currentDir;\n }\n\n const parentDir = dirname(currentDir);\n if (parentDir === currentDir) {\n break; // We've reached the root\n }\n currentDir = parentDir;\n }\n\n return null;\n}\n\n/**\n * Finds all packages in a monorepo\n *\n * @param projectDir - The directory to start searching from\n * @returns An array of package directories\n * @example\n * import { findMonoRepoPackages } from \"@settlemint/sdk-utils/filesystem\";\n *\n * const packages = await findMonoRepoPackages(\"/path/to/your/project\");\n * console.log(packages); // Output: [\"/path/to/your/project/packages/core\", \"/path/to/your/project/packages/ui\"]\n */\nexport async function findMonoRepoPackages(projectDir: string): Promise<string[]> {\n try {\n const monoRepoRoot = await findMonoRepoRoot(projectDir);\n if (!monoRepoRoot) {\n return [projectDir];\n }\n\n const packageJsonPath = join(monoRepoRoot, \"package.json\");\n const packageJson = tryParseJson<{ workspaces: string[] }>(await readFile(packageJsonPath, \"utf-8\"));\n const workspaces = packageJson?.workspaces ?? [];\n\n const packagePaths = await Promise.all(\n workspaces.map(async (workspace: string) => {\n const matches = await glob(join(monoRepoRoot, workspace, \"package.json\"));\n return matches.map((match) => join(match, \"..\"));\n }),\n );\n\n const allPaths = packagePaths.flat();\n // If no packages found in workspaces, treat as non-monorepo\n return allPaths.length === 0 ? [projectDir] : [monoRepoRoot, ...allPaths];\n } catch (_error) {\n // If any error occurs, treat as non-monorepo\n return [projectDir];\n }\n}\n\nasync function packageJsonHasWorkspaces(packageJsonPath: string): Promise<boolean> {\n if (await exists(packageJsonPath)) {\n const packageJson = tryParseJson<{ workspaces: string[] }>(await readFile(packageJsonPath, \"utf-8\"));\n if (packageJson?.workspaces && Array.isArray(packageJson?.workspaces) && packageJson?.workspaces.length > 0) {\n return true;\n }\n }\n return false;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAiBA,eAAsB,YAAY,gBAAgB,OAAO,KAA+B;CACtF,MAAM,kBAAkB,MAAM,OAAO,gBAAgB,EAAE;
|
|
1
|
+
{"version":3,"file":"filesystem.js","names":["value"],"sources":["../src/filesystem/project-root.ts","../src/filesystem/exists.ts","../src/json.ts","../src/filesystem/mono-repo.ts"],"sourcesContent":["import { dirname } from \"node:path\";\nimport { findUp } from \"find-up\";\n\n/**\n * Finds the root directory of the current project by locating the nearest package.json file\n *\n * @param fallbackToCwd - If true, will return the current working directory if no package.json is found\n * @param cwd - The directory to start searching for the package.json file from (defaults to process.cwd())\n * @returns Promise that resolves to the absolute path of the project root directory\n * @throws Will throw an error if no package.json is found in the directory tree\n * @example\n * import { projectRoot } from \"@settlemint/sdk-utils/filesystem\";\n *\n * // Get project root path\n * const rootDir = await projectRoot();\n * console.log(`Project root is at: ${rootDir}`);\n */\nexport async function projectRoot(fallbackToCwd = false, cwd?: string): Promise<string> {\n const packageJsonPath = await findUp(\"package.json\", { cwd });\n if (!packageJsonPath) {\n if (fallbackToCwd) {\n return process.cwd();\n }\n throw new Error(\"Unable to find project root (no package.json found)\");\n }\n return dirname(packageJsonPath);\n}\n","import type { PathLike } from \"node:fs\";\nimport { stat } from \"node:fs/promises\";\n\n/**\n * Checks if a file or directory exists at the given path\n *\n * @param path - The file system path to check for existence\n * @returns Promise that resolves to true if the path exists, false otherwise\n * @example\n * import { exists } from \"@settlemint/sdk-utils/filesystem\";\n *\n * // Check if file exists before reading\n * if (await exists('/path/to/file.txt')) {\n * // File exists, safe to read\n * }\n */\nexport async function exists(path: PathLike): Promise<boolean> {\n try {\n await stat(path);\n return true;\n } catch {\n return false;\n }\n}\n","/**\n * Attempts to parse a JSON string into a typed value, returning a default value if parsing fails.\n *\n * @param value - The JSON string to parse\n * @param defaultValue - The value to return if parsing fails or results in null/undefined\n * @returns The parsed JSON value as type T, or the default value if parsing fails\n *\n * @example\n * import { tryParseJson } from \"@settlemint/sdk-utils\";\n *\n * const config = tryParseJson<{ port: number }>(\n * '{\"port\": 3000}',\n * { port: 8080 }\n * );\n * // Returns: { port: 3000 }\n *\n * const invalid = tryParseJson<string[]>(\n * 'invalid json',\n * []\n * );\n * // Returns: []\n */\nexport function tryParseJson<T>(value: string, defaultValue: T | null = null): T | null {\n try {\n const parsed = JSON.parse(value) as T;\n if (parsed === undefined || parsed === null) {\n return defaultValue;\n }\n return parsed;\n } catch (_err) {\n // Invalid json\n return defaultValue;\n }\n}\n\n/**\n * Extracts a JSON object from a string.\n *\n * @param value - The string to extract the JSON object from\n * @returns The parsed JSON object, or null if no JSON object is found\n * @throws {Error} If the input string is too long (longer than 5000 characters)\n * @example\n * import { extractJsonObject } from \"@settlemint/sdk-utils\";\n *\n * const json = extractJsonObject<{ port: number }>(\n * 'port info: {\"port\": 3000}',\n * );\n * // Returns: { port: 3000 }\n */\nexport function extractJsonObject<T>(value: string): T | null {\n if (value.length > 5000) {\n throw new Error(\"Input too long\");\n }\n const result = /\\{([\\s\\S]*)\\}/.exec(value);\n if (!result) {\n return null;\n }\n return tryParseJson<T>(result[0]);\n}\n\n/**\n * Converts a value to a JSON stringifiable format.\n *\n * @param value - The value to convert\n * @returns The JSON stringifiable value\n *\n * @example\n * import { makeJsonStringifiable } from \"@settlemint/sdk-utils\";\n *\n * const json = makeJsonStringifiable<{ amount: bigint }>({ amount: BigInt(1000) });\n * // Returns: '{\"amount\":\"1000\"}'\n */\nexport function makeJsonStringifiable<T>(value: unknown): T {\n if (value === undefined || value === null) {\n return value as T;\n }\n return tryParseJson<T>(\n JSON.stringify(\n value,\n (_, value) => (typeof value === \"bigint\" ? value.toString() : value), // return everything else unchanged\n ),\n ) as T;\n}\n","import { readFile } from \"node:fs/promises\";\nimport { dirname, join } from \"node:path\";\nimport { findUp } from \"find-up\";\nimport { glob } from \"glob\";\nimport { exists } from \"@/filesystem.js\";\nimport { tryParseJson } from \"@/json.js\";\n\n/**\n * Finds the root directory of a monorepo\n *\n * @param startDir - The directory to start searching from\n * @returns The root directory of the monorepo or null if not found\n * @example\n * import { findMonoRepoRoot } from \"@settlemint/sdk-utils/filesystem\";\n *\n * const root = await findMonoRepoRoot(\"/path/to/your/project\");\n * console.log(root); // Output: /path/to/your/project/packages/core\n */\nexport async function findMonoRepoRoot(startDir: string): Promise<string | null> {\n const lockFilePath = await findUp([\"package-lock.json\", \"yarn.lock\", \"pnpm-lock.yaml\", \"bun.lockb\", \"bun.lock\"], {\n cwd: startDir,\n });\n if (lockFilePath) {\n const packageJsonPath = join(dirname(lockFilePath), \"package.json\");\n const hasWorkSpaces = await packageJsonHasWorkspaces(packageJsonPath);\n return hasWorkSpaces ? dirname(lockFilePath) : null;\n }\n\n let currentDir = startDir;\n\n while (currentDir !== \"/\") {\n const packageJsonPath = join(currentDir, \"package.json\");\n\n if (await packageJsonHasWorkspaces(packageJsonPath)) {\n return currentDir;\n }\n\n const parentDir = dirname(currentDir);\n if (parentDir === currentDir) {\n break; // We've reached the root\n }\n currentDir = parentDir;\n }\n\n return null;\n}\n\n/**\n * Finds all packages in a monorepo\n *\n * @param projectDir - The directory to start searching from\n * @returns An array of package directories\n * @example\n * import { findMonoRepoPackages } from \"@settlemint/sdk-utils/filesystem\";\n *\n * const packages = await findMonoRepoPackages(\"/path/to/your/project\");\n * console.log(packages); // Output: [\"/path/to/your/project/packages/core\", \"/path/to/your/project/packages/ui\"]\n */\nexport async function findMonoRepoPackages(projectDir: string): Promise<string[]> {\n try {\n const monoRepoRoot = await findMonoRepoRoot(projectDir);\n if (!monoRepoRoot) {\n return [projectDir];\n }\n\n const packageJsonPath = join(monoRepoRoot, \"package.json\");\n const packageJson = tryParseJson<{ workspaces: string[] }>(await readFile(packageJsonPath, \"utf-8\"));\n const workspaces = packageJson?.workspaces ?? [];\n\n const packagePaths = await Promise.all(\n workspaces.map(async (workspace: string) => {\n const matches = await glob(join(monoRepoRoot, workspace, \"package.json\"));\n return matches.map((match) => join(match, \"..\"));\n }),\n );\n\n const allPaths = packagePaths.flat();\n // If no packages found in workspaces, treat as non-monorepo\n return allPaths.length === 0 ? [projectDir] : [monoRepoRoot, ...allPaths];\n } catch (_error) {\n // If any error occurs, treat as non-monorepo\n return [projectDir];\n }\n}\n\nasync function packageJsonHasWorkspaces(packageJsonPath: string): Promise<boolean> {\n if (await exists(packageJsonPath)) {\n const packageJson = tryParseJson<{ workspaces: string[] }>(await readFile(packageJsonPath, \"utf-8\"));\n if (packageJson?.workspaces && Array.isArray(packageJson?.workspaces) && packageJson?.workspaces.length > 0) {\n return true;\n }\n }\n return false;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAiBA,eAAsB,YAAY,gBAAgB,OAAO,KAA+B;CACtF,MAAM,kBAAkB,MAAM,OAAO,gBAAgB,EAAE,KAAK,CAAC;AAC7D,KAAI,CAAC,iBAAiB;AACpB,MAAI,eAAe;AACjB,UAAO,QAAQ,KAAK;;AAEtB,QAAM,IAAI,MAAM,sDAAsD;;AAExE,QAAO,QAAQ,gBAAgB;;;;;;;;;;;;;;;;;;ACTjC,eAAsB,OAAO,MAAkC;AAC7D,KAAI;AACF,QAAM,KAAK,KAAK;AAChB,SAAO;SACD;AACN,SAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACCX,SAAgB,aAAgB,OAAe,eAAyB,MAAgB;AACtF,KAAI;EACF,MAAM,SAAS,KAAK,MAAM,MAAM;AAChC,MAAI,WAAW,aAAa,WAAW,MAAM;AAC3C,UAAO;;AAET,SAAO;UACA,MAAM;AAEb,SAAO;;;;;;;;;;;;;;;;;AAkBX,SAAgB,kBAAqB,OAAyB;AAC5D,KAAI,MAAM,SAAS,KAAM;AACvB,QAAM,IAAI,MAAM,iBAAiB;;CAEnC,MAAM,SAAS,gBAAgB,KAAK,MAAM;AAC1C,KAAI,CAAC,QAAQ;AACX,SAAO;;AAET,QAAO,aAAgB,OAAO,GAAG;;;;;;;;;;;;;;AAenC,SAAgB,sBAAyB,OAAmB;AAC1D,KAAI,UAAU,aAAa,UAAU,MAAM;AACzC,SAAO;;AAET,QAAO,aACL,KAAK,UACH,QACC,GAAG,YAAW,OAAOA,YAAU,WAAWA,QAAM,UAAU,GAAGA,QAC/D,CACF;;;;;;;;;;;;;;;;AC/DH,eAAsB,iBAAiB,UAA0C;CAC/E,MAAM,eAAe,MAAM,OAAO;EAAC;EAAqB;EAAa;EAAkB;EAAa;EAAW,EAAE,EAC/G,KAAK,UACN,CAAC;AACF,KAAI,cAAc;EAChB,MAAM,kBAAkB,KAAK,QAAQ,aAAa,EAAE,eAAe;EACnE,MAAM,gBAAgB,MAAM,yBAAyB,gBAAgB;AACrE,SAAO,gBAAgB,QAAQ,aAAa,GAAG;;CAGjD,IAAI,aAAa;AAEjB,QAAO,eAAe,KAAK;EACzB,MAAM,kBAAkB,KAAK,YAAY,eAAe;AAExD,MAAI,MAAM,yBAAyB,gBAAgB,EAAE;AACnD,UAAO;;EAGT,MAAM,YAAY,QAAQ,WAAW;AACrC,MAAI,cAAc,YAAY;AAC5B;;AAEF,eAAa;;AAGf,QAAO;;;;;;;;;;;;;AAcT,eAAsB,qBAAqB,YAAuC;AAChF,KAAI;EACF,MAAM,eAAe,MAAM,iBAAiB,WAAW;AACvD,MAAI,CAAC,cAAc;AACjB,UAAO,CAAC,WAAW;;EAGrB,MAAM,kBAAkB,KAAK,cAAc,eAAe;EAC1D,MAAM,cAAc,aAAuC,MAAM,SAAS,iBAAiB,QAAQ,CAAC;EACpG,MAAM,aAAa,aAAa,cAAc,EAAE;EAEhD,MAAM,eAAe,MAAM,QAAQ,IACjC,WAAW,IAAI,OAAO,cAAsB;GAC1C,MAAM,UAAU,MAAM,KAAK,KAAK,cAAc,WAAW,eAAe,CAAC;AACzE,UAAO,QAAQ,KAAK,UAAU,KAAK,OAAO,KAAK,CAAC;IAChD,CACH;EAED,MAAM,WAAW,aAAa,MAAM;AAEpC,SAAO,SAAS,WAAW,IAAI,CAAC,WAAW,GAAG,CAAC,cAAc,GAAG,SAAS;UAClE,QAAQ;AAEf,SAAO,CAAC,WAAW;;;AAIvB,eAAe,yBAAyB,iBAA2C;AACjF,KAAI,MAAM,OAAO,gBAAgB,EAAE;EACjC,MAAM,cAAc,aAAuC,MAAM,SAAS,iBAAiB,QAAQ,CAAC;AACpG,MAAI,aAAa,cAAc,MAAM,QAAQ,aAAa,WAAW,IAAI,aAAa,WAAW,SAAS,GAAG;AAC3G,UAAO;;;AAGX,QAAO"}
|
package/dist/http.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"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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"}
|
|
1
|
+
{"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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"}
|
package/dist/http.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http.js","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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"}
|
|
1
|
+
{"version":3,"file":"http.js","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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"}
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":["value","logLevels: Record<LogLevel, number>","level"],"sources":["../src/json.ts","../src/logging/mask-tokens.ts","../src/logging/logger.ts","../src/retry.ts","../src/string.ts","../src/url.ts"],"sourcesContent":["/**\n * Attempts to parse a JSON string into a typed value, returning a default value if parsing fails.\n *\n * @param value - The JSON string to parse\n * @param defaultValue - The value to return if parsing fails or results in null/undefined\n * @returns The parsed JSON value as type T, or the default value if parsing fails\n *\n * @example\n * import { tryParseJson } from \"@settlemint/sdk-utils\";\n *\n * const config = tryParseJson<{ port: number }>(\n * '{\"port\": 3000}',\n * { port: 8080 }\n * );\n * // Returns: { port: 3000 }\n *\n * const invalid = tryParseJson<string[]>(\n * 'invalid json',\n * []\n * );\n * // Returns: []\n */\nexport function tryParseJson<T>(value: string, defaultValue: T | null = null): T | null {\n try {\n const parsed = JSON.parse(value) as T;\n if (parsed === undefined || parsed === null) {\n return defaultValue;\n }\n return parsed;\n } catch (_err) {\n // Invalid json\n return defaultValue;\n }\n}\n\n/**\n * Extracts a JSON object from a string.\n *\n * @param value - The string to extract the JSON object from\n * @returns The parsed JSON object, or null if no JSON object is found\n * @throws {Error} If the input string is too long (longer than 5000 characters)\n * @example\n * import { extractJsonObject } from \"@settlemint/sdk-utils\";\n *\n * const json = extractJsonObject<{ port: number }>(\n * 'port info: {\"port\": 3000}',\n * );\n * // Returns: { port: 3000 }\n */\nexport function extractJsonObject<T>(value: string): T | null {\n if (value.length > 5000) {\n throw new Error(\"Input too long\");\n }\n const result = /\\{([\\s\\S]*)\\}/.exec(value);\n if (!result) {\n return null;\n }\n return tryParseJson<T>(result[0]);\n}\n\n/**\n * Converts a value to a JSON stringifiable format.\n *\n * @param value - The value to convert\n * @returns The JSON stringifiable value\n *\n * @example\n * import { makeJsonStringifiable } from \"@settlemint/sdk-utils\";\n *\n * const json = makeJsonStringifiable<{ amount: bigint }>({ amount: BigInt(1000) });\n * // Returns: '{\"amount\":\"1000\"}'\n */\nexport function makeJsonStringifiable<T>(value: unknown): T {\n if (value === undefined || value === null) {\n return value as T;\n }\n return tryParseJson<T>(\n JSON.stringify(\n value,\n (_, value) => (typeof value === \"bigint\" ? value.toString() : value), // return everything else unchanged\n ),\n ) as T;\n}\n","/**\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","/**\n * Capitalizes the first letter of a string.\n *\n * @param val - The string to capitalize\n * @returns The input string with its first letter capitalized\n *\n * @example\n * import { capitalizeFirstLetter } from \"@settlemint/sdk-utils\";\n *\n * const capitalized = capitalizeFirstLetter(\"hello\");\n * // Returns: \"Hello\"\n */\nexport function capitalizeFirstLetter(val: string) {\n return String(val).charAt(0).toUpperCase() + String(val).slice(1);\n}\n\n/**\n * Converts a camelCase string to a human-readable string.\n *\n * @param s - The camelCase string to convert\n * @returns The human-readable string\n *\n * @example\n * import { camelCaseToWords } from \"@settlemint/sdk-utils\";\n *\n * const words = camelCaseToWords(\"camelCaseString\");\n * // Returns: \"Camel Case String\"\n */\nexport function camelCaseToWords(s: string) {\n const result = s.replace(/([a-z])([A-Z])/g, \"$1 $2\");\n const withSpaces = result.replace(/([A-Z])([a-z])/g, \" $1$2\");\n const capitalized = capitalizeFirstLetter(withSpaces);\n return capitalized.replace(/\\s+/g, \" \").trim();\n}\n\n/**\n * Replaces underscores and hyphens with spaces.\n *\n * @param s - The string to replace underscores and hyphens with spaces\n * @returns The input string with underscores and hyphens replaced with spaces\n *\n * @example\n * import { replaceUnderscoresAndHyphensWithSpaces } from \"@settlemint/sdk-utils\";\n *\n * const result = replaceUnderscoresAndHyphensWithSpaces(\"Already_Spaced-Second\");\n * // Returns: \"Already Spaced Second\"\n */\nexport function replaceUnderscoresAndHyphensWithSpaces(s: string) {\n return s.replace(/[-_]/g, \" \");\n}\n\n/**\n * Truncates a string to a maximum length and appends \"...\" if it is longer.\n *\n * @param value - The string to truncate\n * @param maxLength - The maximum length of the string\n * @returns The truncated string or the original string if it is shorter than the maximum length\n *\n * @example\n * import { truncate } from \"@settlemint/sdk-utils\";\n *\n * const truncated = truncate(\"Hello, world!\", 10);\n * // Returns: \"Hello, wor...\"\n */\nexport function truncate(value: string, maxLength: number) {\n if (value.length <= maxLength) {\n return value;\n }\n return `${value.slice(0, maxLength)}...`;\n}\n","/**\n * Extracts the base URL before a specific segment in a URL.\n *\n * @param baseUrl - The base URL to extract the path from\n * @param pathSegment - The path segment to start from\n * @returns The base URL before the specified segment\n * @example\n * ```typescript\n * import { extractBaseUrlBeforeSegment } from \"@settlemint/sdk-utils/url\";\n *\n * const baseUrl = extractBaseUrlBeforeSegment(\"https://example.com/api/v1/subgraphs/name/my-subgraph\", \"/subgraphs\");\n * // Returns: \"https://example.com/api/v1\"\n * ```\n */\nexport function extractBaseUrlBeforeSegment(baseUrl: string, pathSegment: string) {\n const url = new URL(baseUrl);\n if (pathSegment.trim() === \"\") {\n return url.toString();\n }\n const segmentIndex = url.pathname.indexOf(pathSegment);\n return url.origin + (segmentIndex >= 0 ? url.pathname.substring(0, segmentIndex) : url.pathname);\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["value","logLevels: Record<LogLevel, number>","level"],"sources":["../src/json.ts","../src/logging/mask-tokens.ts","../src/logging/logger.ts","../src/retry.ts","../src/string.ts","../src/url.ts"],"sourcesContent":["/**\n * Attempts to parse a JSON string into a typed value, returning a default value if parsing fails.\n *\n * @param value - The JSON string to parse\n * @param defaultValue - The value to return if parsing fails or results in null/undefined\n * @returns The parsed JSON value as type T, or the default value if parsing fails\n *\n * @example\n * import { tryParseJson } from \"@settlemint/sdk-utils\";\n *\n * const config = tryParseJson<{ port: number }>(\n * '{\"port\": 3000}',\n * { port: 8080 }\n * );\n * // Returns: { port: 3000 }\n *\n * const invalid = tryParseJson<string[]>(\n * 'invalid json',\n * []\n * );\n * // Returns: []\n */\nexport function tryParseJson<T>(value: string, defaultValue: T | null = null): T | null {\n try {\n const parsed = JSON.parse(value) as T;\n if (parsed === undefined || parsed === null) {\n return defaultValue;\n }\n return parsed;\n } catch (_err) {\n // Invalid json\n return defaultValue;\n }\n}\n\n/**\n * Extracts a JSON object from a string.\n *\n * @param value - The string to extract the JSON object from\n * @returns The parsed JSON object, or null if no JSON object is found\n * @throws {Error} If the input string is too long (longer than 5000 characters)\n * @example\n * import { extractJsonObject } from \"@settlemint/sdk-utils\";\n *\n * const json = extractJsonObject<{ port: number }>(\n * 'port info: {\"port\": 3000}',\n * );\n * // Returns: { port: 3000 }\n */\nexport function extractJsonObject<T>(value: string): T | null {\n if (value.length > 5000) {\n throw new Error(\"Input too long\");\n }\n const result = /\\{([\\s\\S]*)\\}/.exec(value);\n if (!result) {\n return null;\n }\n return tryParseJson<T>(result[0]);\n}\n\n/**\n * Converts a value to a JSON stringifiable format.\n *\n * @param value - The value to convert\n * @returns The JSON stringifiable value\n *\n * @example\n * import { makeJsonStringifiable } from \"@settlemint/sdk-utils\";\n *\n * const json = makeJsonStringifiable<{ amount: bigint }>({ amount: BigInt(1000) });\n * // Returns: '{\"amount\":\"1000\"}'\n */\nexport function makeJsonStringifiable<T>(value: unknown): T {\n if (value === undefined || value === null) {\n return value as T;\n }\n return tryParseJson<T>(\n JSON.stringify(\n value,\n (_, value) => (typeof value === \"bigint\" ? value.toString() : value), // return everything else unchanged\n ),\n ) as T;\n}\n","/**\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","/**\n * Capitalizes the first letter of a string.\n *\n * @param val - The string to capitalize\n * @returns The input string with its first letter capitalized\n *\n * @example\n * import { capitalizeFirstLetter } from \"@settlemint/sdk-utils\";\n *\n * const capitalized = capitalizeFirstLetter(\"hello\");\n * // Returns: \"Hello\"\n */\nexport function capitalizeFirstLetter(val: string) {\n return String(val).charAt(0).toUpperCase() + String(val).slice(1);\n}\n\n/**\n * Converts a camelCase string to a human-readable string.\n *\n * @param s - The camelCase string to convert\n * @returns The human-readable string\n *\n * @example\n * import { camelCaseToWords } from \"@settlemint/sdk-utils\";\n *\n * const words = camelCaseToWords(\"camelCaseString\");\n * // Returns: \"Camel Case String\"\n */\nexport function camelCaseToWords(s: string) {\n const result = s.replace(/([a-z])([A-Z])/g, \"$1 $2\");\n const withSpaces = result.replace(/([A-Z])([a-z])/g, \" $1$2\");\n const capitalized = capitalizeFirstLetter(withSpaces);\n return capitalized.replace(/\\s+/g, \" \").trim();\n}\n\n/**\n * Replaces underscores and hyphens with spaces.\n *\n * @param s - The string to replace underscores and hyphens with spaces\n * @returns The input string with underscores and hyphens replaced with spaces\n *\n * @example\n * import { replaceUnderscoresAndHyphensWithSpaces } from \"@settlemint/sdk-utils\";\n *\n * const result = replaceUnderscoresAndHyphensWithSpaces(\"Already_Spaced-Second\");\n * // Returns: \"Already Spaced Second\"\n */\nexport function replaceUnderscoresAndHyphensWithSpaces(s: string) {\n return s.replace(/[-_]/g, \" \");\n}\n\n/**\n * Truncates a string to a maximum length and appends \"...\" if it is longer.\n *\n * @param value - The string to truncate\n * @param maxLength - The maximum length of the string\n * @returns The truncated string or the original string if it is shorter than the maximum length\n *\n * @example\n * import { truncate } from \"@settlemint/sdk-utils\";\n *\n * const truncated = truncate(\"Hello, world!\", 10);\n * // Returns: \"Hello, wor...\"\n */\nexport function truncate(value: string, maxLength: number) {\n if (value.length <= maxLength) {\n return value;\n }\n return `${value.slice(0, maxLength)}...`;\n}\n","/**\n * Extracts the base URL before a specific segment in a URL.\n *\n * @param baseUrl - The base URL to extract the path from\n * @param pathSegment - The path segment to start from\n * @returns The base URL before the specified segment\n * @example\n * ```typescript\n * import { extractBaseUrlBeforeSegment } from \"@settlemint/sdk-utils/url\";\n *\n * const baseUrl = extractBaseUrlBeforeSegment(\"https://example.com/api/v1/subgraphs/name/my-subgraph\", \"/subgraphs\");\n * // Returns: \"https://example.com/api/v1\"\n * ```\n */\nexport function extractBaseUrlBeforeSegment(baseUrl: string, pathSegment: string) {\n const url = new URL(baseUrl);\n if (pathSegment.trim() === \"\") {\n return url.toString();\n }\n const segmentIndex = url.pathname.indexOf(pathSegment);\n return url.origin + (segmentIndex >= 0 ? url.pathname.substring(0, segmentIndex) : url.pathname);\n}\n"],"mappings":"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"}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["value","logLevels: Record<LogLevel, number>","level"],"sources":["../src/json.ts","../src/logging/mask-tokens.ts","../src/logging/logger.ts","../src/retry.ts","../src/string.ts","../src/url.ts"],"sourcesContent":["/**\n * Attempts to parse a JSON string into a typed value, returning a default value if parsing fails.\n *\n * @param value - The JSON string to parse\n * @param defaultValue - The value to return if parsing fails or results in null/undefined\n * @returns The parsed JSON value as type T, or the default value if parsing fails\n *\n * @example\n * import { tryParseJson } from \"@settlemint/sdk-utils\";\n *\n * const config = tryParseJson<{ port: number }>(\n * '{\"port\": 3000}',\n * { port: 8080 }\n * );\n * // Returns: { port: 3000 }\n *\n * const invalid = tryParseJson<string[]>(\n * 'invalid json',\n * []\n * );\n * // Returns: []\n */\nexport function tryParseJson<T>(value: string, defaultValue: T | null = null): T | null {\n try {\n const parsed = JSON.parse(value) as T;\n if (parsed === undefined || parsed === null) {\n return defaultValue;\n }\n return parsed;\n } catch (_err) {\n // Invalid json\n return defaultValue;\n }\n}\n\n/**\n * Extracts a JSON object from a string.\n *\n * @param value - The string to extract the JSON object from\n * @returns The parsed JSON object, or null if no JSON object is found\n * @throws {Error} If the input string is too long (longer than 5000 characters)\n * @example\n * import { extractJsonObject } from \"@settlemint/sdk-utils\";\n *\n * const json = extractJsonObject<{ port: number }>(\n * 'port info: {\"port\": 3000}',\n * );\n * // Returns: { port: 3000 }\n */\nexport function extractJsonObject<T>(value: string): T | null {\n if (value.length > 5000) {\n throw new Error(\"Input too long\");\n }\n const result = /\\{([\\s\\S]*)\\}/.exec(value);\n if (!result) {\n return null;\n }\n return tryParseJson<T>(result[0]);\n}\n\n/**\n * Converts a value to a JSON stringifiable format.\n *\n * @param value - The value to convert\n * @returns The JSON stringifiable value\n *\n * @example\n * import { makeJsonStringifiable } from \"@settlemint/sdk-utils\";\n *\n * const json = makeJsonStringifiable<{ amount: bigint }>({ amount: BigInt(1000) });\n * // Returns: '{\"amount\":\"1000\"}'\n */\nexport function makeJsonStringifiable<T>(value: unknown): T {\n if (value === undefined || value === null) {\n return value as T;\n }\n return tryParseJson<T>(\n JSON.stringify(\n value,\n (_, value) => (typeof value === \"bigint\" ? value.toString() : value), // return everything else unchanged\n ),\n ) as T;\n}\n","/**\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","/**\n * Capitalizes the first letter of a string.\n *\n * @param val - The string to capitalize\n * @returns The input string with its first letter capitalized\n *\n * @example\n * import { capitalizeFirstLetter } from \"@settlemint/sdk-utils\";\n *\n * const capitalized = capitalizeFirstLetter(\"hello\");\n * // Returns: \"Hello\"\n */\nexport function capitalizeFirstLetter(val: string) {\n return String(val).charAt(0).toUpperCase() + String(val).slice(1);\n}\n\n/**\n * Converts a camelCase string to a human-readable string.\n *\n * @param s - The camelCase string to convert\n * @returns The human-readable string\n *\n * @example\n * import { camelCaseToWords } from \"@settlemint/sdk-utils\";\n *\n * const words = camelCaseToWords(\"camelCaseString\");\n * // Returns: \"Camel Case String\"\n */\nexport function camelCaseToWords(s: string) {\n const result = s.replace(/([a-z])([A-Z])/g, \"$1 $2\");\n const withSpaces = result.replace(/([A-Z])([a-z])/g, \" $1$2\");\n const capitalized = capitalizeFirstLetter(withSpaces);\n return capitalized.replace(/\\s+/g, \" \").trim();\n}\n\n/**\n * Replaces underscores and hyphens with spaces.\n *\n * @param s - The string to replace underscores and hyphens with spaces\n * @returns The input string with underscores and hyphens replaced with spaces\n *\n * @example\n * import { replaceUnderscoresAndHyphensWithSpaces } from \"@settlemint/sdk-utils\";\n *\n * const result = replaceUnderscoresAndHyphensWithSpaces(\"Already_Spaced-Second\");\n * // Returns: \"Already Spaced Second\"\n */\nexport function replaceUnderscoresAndHyphensWithSpaces(s: string) {\n return s.replace(/[-_]/g, \" \");\n}\n\n/**\n * Truncates a string to a maximum length and appends \"...\" if it is longer.\n *\n * @param value - The string to truncate\n * @param maxLength - The maximum length of the string\n * @returns The truncated string or the original string if it is shorter than the maximum length\n *\n * @example\n * import { truncate } from \"@settlemint/sdk-utils\";\n *\n * const truncated = truncate(\"Hello, world!\", 10);\n * // Returns: \"Hello, wor...\"\n */\nexport function truncate(value: string, maxLength: number) {\n if (value.length <= maxLength) {\n return value;\n }\n return `${value.slice(0, maxLength)}...`;\n}\n","/**\n * Extracts the base URL before a specific segment in a URL.\n *\n * @param baseUrl - The base URL to extract the path from\n * @param pathSegment - The path segment to start from\n * @returns The base URL before the specified segment\n * @example\n * ```typescript\n * import { extractBaseUrlBeforeSegment } from \"@settlemint/sdk-utils/url\";\n *\n * const baseUrl = extractBaseUrlBeforeSegment(\"https://example.com/api/v1/subgraphs/name/my-subgraph\", \"/subgraphs\");\n * // Returns: \"https://example.com/api/v1\"\n * ```\n */\nexport function extractBaseUrlBeforeSegment(baseUrl: string, pathSegment: string) {\n const url = new URL(baseUrl);\n if (pathSegment.trim() === \"\") {\n return url.toString();\n }\n const segmentIndex = url.pathname.indexOf(pathSegment);\n return url.origin + (segmentIndex >= 0 ? url.pathname.substring(0, segmentIndex) : url.pathname);\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["value","logLevels: Record<LogLevel, number>","level"],"sources":["../src/json.ts","../src/logging/mask-tokens.ts","../src/logging/logger.ts","../src/retry.ts","../src/string.ts","../src/url.ts"],"sourcesContent":["/**\n * Attempts to parse a JSON string into a typed value, returning a default value if parsing fails.\n *\n * @param value - The JSON string to parse\n * @param defaultValue - The value to return if parsing fails or results in null/undefined\n * @returns The parsed JSON value as type T, or the default value if parsing fails\n *\n * @example\n * import { tryParseJson } from \"@settlemint/sdk-utils\";\n *\n * const config = tryParseJson<{ port: number }>(\n * '{\"port\": 3000}',\n * { port: 8080 }\n * );\n * // Returns: { port: 3000 }\n *\n * const invalid = tryParseJson<string[]>(\n * 'invalid json',\n * []\n * );\n * // Returns: []\n */\nexport function tryParseJson<T>(value: string, defaultValue: T | null = null): T | null {\n try {\n const parsed = JSON.parse(value) as T;\n if (parsed === undefined || parsed === null) {\n return defaultValue;\n }\n return parsed;\n } catch (_err) {\n // Invalid json\n return defaultValue;\n }\n}\n\n/**\n * Extracts a JSON object from a string.\n *\n * @param value - The string to extract the JSON object from\n * @returns The parsed JSON object, or null if no JSON object is found\n * @throws {Error} If the input string is too long (longer than 5000 characters)\n * @example\n * import { extractJsonObject } from \"@settlemint/sdk-utils\";\n *\n * const json = extractJsonObject<{ port: number }>(\n * 'port info: {\"port\": 3000}',\n * );\n * // Returns: { port: 3000 }\n */\nexport function extractJsonObject<T>(value: string): T | null {\n if (value.length > 5000) {\n throw new Error(\"Input too long\");\n }\n const result = /\\{([\\s\\S]*)\\}/.exec(value);\n if (!result) {\n return null;\n }\n return tryParseJson<T>(result[0]);\n}\n\n/**\n * Converts a value to a JSON stringifiable format.\n *\n * @param value - The value to convert\n * @returns The JSON stringifiable value\n *\n * @example\n * import { makeJsonStringifiable } from \"@settlemint/sdk-utils\";\n *\n * const json = makeJsonStringifiable<{ amount: bigint }>({ amount: BigInt(1000) });\n * // Returns: '{\"amount\":\"1000\"}'\n */\nexport function makeJsonStringifiable<T>(value: unknown): T {\n if (value === undefined || value === null) {\n return value as T;\n }\n return tryParseJson<T>(\n JSON.stringify(\n value,\n (_, value) => (typeof value === \"bigint\" ? value.toString() : value), // return everything else unchanged\n ),\n ) as T;\n}\n","/**\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","/**\n * Capitalizes the first letter of a string.\n *\n * @param val - The string to capitalize\n * @returns The input string with its first letter capitalized\n *\n * @example\n * import { capitalizeFirstLetter } from \"@settlemint/sdk-utils\";\n *\n * const capitalized = capitalizeFirstLetter(\"hello\");\n * // Returns: \"Hello\"\n */\nexport function capitalizeFirstLetter(val: string) {\n return String(val).charAt(0).toUpperCase() + String(val).slice(1);\n}\n\n/**\n * Converts a camelCase string to a human-readable string.\n *\n * @param s - The camelCase string to convert\n * @returns The human-readable string\n *\n * @example\n * import { camelCaseToWords } from \"@settlemint/sdk-utils\";\n *\n * const words = camelCaseToWords(\"camelCaseString\");\n * // Returns: \"Camel Case String\"\n */\nexport function camelCaseToWords(s: string) {\n const result = s.replace(/([a-z])([A-Z])/g, \"$1 $2\");\n const withSpaces = result.replace(/([A-Z])([a-z])/g, \" $1$2\");\n const capitalized = capitalizeFirstLetter(withSpaces);\n return capitalized.replace(/\\s+/g, \" \").trim();\n}\n\n/**\n * Replaces underscores and hyphens with spaces.\n *\n * @param s - The string to replace underscores and hyphens with spaces\n * @returns The input string with underscores and hyphens replaced with spaces\n *\n * @example\n * import { replaceUnderscoresAndHyphensWithSpaces } from \"@settlemint/sdk-utils\";\n *\n * const result = replaceUnderscoresAndHyphensWithSpaces(\"Already_Spaced-Second\");\n * // Returns: \"Already Spaced Second\"\n */\nexport function replaceUnderscoresAndHyphensWithSpaces(s: string) {\n return s.replace(/[-_]/g, \" \");\n}\n\n/**\n * Truncates a string to a maximum length and appends \"...\" if it is longer.\n *\n * @param value - The string to truncate\n * @param maxLength - The maximum length of the string\n * @returns The truncated string or the original string if it is shorter than the maximum length\n *\n * @example\n * import { truncate } from \"@settlemint/sdk-utils\";\n *\n * const truncated = truncate(\"Hello, world!\", 10);\n * // Returns: \"Hello, wor...\"\n */\nexport function truncate(value: string, maxLength: number) {\n if (value.length <= maxLength) {\n return value;\n }\n return `${value.slice(0, maxLength)}...`;\n}\n","/**\n * Extracts the base URL before a specific segment in a URL.\n *\n * @param baseUrl - The base URL to extract the path from\n * @param pathSegment - The path segment to start from\n * @returns The base URL before the specified segment\n * @example\n * ```typescript\n * import { extractBaseUrlBeforeSegment } from \"@settlemint/sdk-utils/url\";\n *\n * const baseUrl = extractBaseUrlBeforeSegment(\"https://example.com/api/v1/subgraphs/name/my-subgraph\", \"/subgraphs\");\n * // Returns: \"https://example.com/api/v1\"\n * ```\n */\nexport function extractBaseUrlBeforeSegment(baseUrl: string, pathSegment: string) {\n const url = new URL(baseUrl);\n if (pathSegment.trim() === \"\") {\n return url.toString();\n }\n const segmentIndex = url.pathname.indexOf(pathSegment);\n return url.origin + (segmentIndex >= 0 ? url.pathname.substring(0, segmentIndex) : url.pathname);\n}\n"],"mappings":"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"}
|
package/dist/json.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"json.cjs","names":["value"],"sources":["../src/json.ts"],"sourcesContent":["/**\n * Attempts to parse a JSON string into a typed value, returning a default value if parsing fails.\n *\n * @param value - The JSON string to parse\n * @param defaultValue - The value to return if parsing fails or results in null/undefined\n * @returns The parsed JSON value as type T, or the default value if parsing fails\n *\n * @example\n * import { tryParseJson } from \"@settlemint/sdk-utils\";\n *\n * const config = tryParseJson<{ port: number }>(\n * '{\"port\": 3000}',\n * { port: 8080 }\n * );\n * // Returns: { port: 3000 }\n *\n * const invalid = tryParseJson<string[]>(\n * 'invalid json',\n * []\n * );\n * // Returns: []\n */\nexport function tryParseJson<T>(value: string, defaultValue: T | null = null): T | null {\n try {\n const parsed = JSON.parse(value) as T;\n if (parsed === undefined || parsed === null) {\n return defaultValue;\n }\n return parsed;\n } catch (_err) {\n // Invalid json\n return defaultValue;\n }\n}\n\n/**\n * Extracts a JSON object from a string.\n *\n * @param value - The string to extract the JSON object from\n * @returns The parsed JSON object, or null if no JSON object is found\n * @throws {Error} If the input string is too long (longer than 5000 characters)\n * @example\n * import { extractJsonObject } from \"@settlemint/sdk-utils\";\n *\n * const json = extractJsonObject<{ port: number }>(\n * 'port info: {\"port\": 3000}',\n * );\n * // Returns: { port: 3000 }\n */\nexport function extractJsonObject<T>(value: string): T | null {\n if (value.length > 5000) {\n throw new Error(\"Input too long\");\n }\n const result = /\\{([\\s\\S]*)\\}/.exec(value);\n if (!result) {\n return null;\n }\n return tryParseJson<T>(result[0]);\n}\n\n/**\n * Converts a value to a JSON stringifiable format.\n *\n * @param value - The value to convert\n * @returns The JSON stringifiable value\n *\n * @example\n * import { makeJsonStringifiable } from \"@settlemint/sdk-utils\";\n *\n * const json = makeJsonStringifiable<{ amount: bigint }>({ amount: BigInt(1000) });\n * // Returns: '{\"amount\":\"1000\"}'\n */\nexport function makeJsonStringifiable<T>(value: unknown): T {\n if (value === undefined || value === null) {\n return value as T;\n }\n return tryParseJson<T>(\n JSON.stringify(\n value,\n (_, value) => (typeof value === \"bigint\" ? value.toString() : value), // return everything else unchanged\n ),\n ) as T;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAsBA,SAAgB,aAAgB,OAAe,eAAyB,MAAgB;AACtF,KAAI;EACF,MAAM,SAAS,KAAK,MAAM;
|
|
1
|
+
{"version":3,"file":"json.cjs","names":["value"],"sources":["../src/json.ts"],"sourcesContent":["/**\n * Attempts to parse a JSON string into a typed value, returning a default value if parsing fails.\n *\n * @param value - The JSON string to parse\n * @param defaultValue - The value to return if parsing fails or results in null/undefined\n * @returns The parsed JSON value as type T, or the default value if parsing fails\n *\n * @example\n * import { tryParseJson } from \"@settlemint/sdk-utils\";\n *\n * const config = tryParseJson<{ port: number }>(\n * '{\"port\": 3000}',\n * { port: 8080 }\n * );\n * // Returns: { port: 3000 }\n *\n * const invalid = tryParseJson<string[]>(\n * 'invalid json',\n * []\n * );\n * // Returns: []\n */\nexport function tryParseJson<T>(value: string, defaultValue: T | null = null): T | null {\n try {\n const parsed = JSON.parse(value) as T;\n if (parsed === undefined || parsed === null) {\n return defaultValue;\n }\n return parsed;\n } catch (_err) {\n // Invalid json\n return defaultValue;\n }\n}\n\n/**\n * Extracts a JSON object from a string.\n *\n * @param value - The string to extract the JSON object from\n * @returns The parsed JSON object, or null if no JSON object is found\n * @throws {Error} If the input string is too long (longer than 5000 characters)\n * @example\n * import { extractJsonObject } from \"@settlemint/sdk-utils\";\n *\n * const json = extractJsonObject<{ port: number }>(\n * 'port info: {\"port\": 3000}',\n * );\n * // Returns: { port: 3000 }\n */\nexport function extractJsonObject<T>(value: string): T | null {\n if (value.length > 5000) {\n throw new Error(\"Input too long\");\n }\n const result = /\\{([\\s\\S]*)\\}/.exec(value);\n if (!result) {\n return null;\n }\n return tryParseJson<T>(result[0]);\n}\n\n/**\n * Converts a value to a JSON stringifiable format.\n *\n * @param value - The value to convert\n * @returns The JSON stringifiable value\n *\n * @example\n * import { makeJsonStringifiable } from \"@settlemint/sdk-utils\";\n *\n * const json = makeJsonStringifiable<{ amount: bigint }>({ amount: BigInt(1000) });\n * // Returns: '{\"amount\":\"1000\"}'\n */\nexport function makeJsonStringifiable<T>(value: unknown): T {\n if (value === undefined || value === null) {\n return value as T;\n }\n return tryParseJson<T>(\n JSON.stringify(\n value,\n (_, value) => (typeof value === \"bigint\" ? value.toString() : value), // return everything else unchanged\n ),\n ) as T;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AAsBA,SAAgB,aAAgB,OAAe,eAAyB,MAAgB;AACtF,KAAI;EACF,MAAM,SAAS,KAAK,MAAM,MAAM;AAChC,MAAI,WAAW,aAAa,WAAW,MAAM;AAC3C,UAAO;;AAET,SAAO;UACA,MAAM;AAEb,SAAO;;;;;;;;;;;;;;;;;AAkBX,SAAgB,kBAAqB,OAAyB;AAC5D,KAAI,MAAM,SAAS,KAAM;AACvB,QAAM,IAAI,MAAM,iBAAiB;;CAEnC,MAAM,SAAS,gBAAgB,KAAK,MAAM;AAC1C,KAAI,CAAC,QAAQ;AACX,SAAO;;AAET,QAAO,aAAgB,OAAO,GAAG;;;;;;;;;;;;;;AAenC,SAAgB,sBAAyB,OAAmB;AAC1D,KAAI,UAAU,aAAa,UAAU,MAAM;AACzC,SAAO;;AAET,QAAO,aACL,KAAK,UACH,QACC,GAAG,YAAW,OAAOA,YAAU,WAAWA,QAAM,UAAU,GAAGA,QAC/D,CACF"}
|
package/dist/json.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"json.js","names":["value"],"sources":["../src/json.ts"],"sourcesContent":["/**\n * Attempts to parse a JSON string into a typed value, returning a default value if parsing fails.\n *\n * @param value - The JSON string to parse\n * @param defaultValue - The value to return if parsing fails or results in null/undefined\n * @returns The parsed JSON value as type T, or the default value if parsing fails\n *\n * @example\n * import { tryParseJson } from \"@settlemint/sdk-utils\";\n *\n * const config = tryParseJson<{ port: number }>(\n * '{\"port\": 3000}',\n * { port: 8080 }\n * );\n * // Returns: { port: 3000 }\n *\n * const invalid = tryParseJson<string[]>(\n * 'invalid json',\n * []\n * );\n * // Returns: []\n */\nexport function tryParseJson<T>(value: string, defaultValue: T | null = null): T | null {\n try {\n const parsed = JSON.parse(value) as T;\n if (parsed === undefined || parsed === null) {\n return defaultValue;\n }\n return parsed;\n } catch (_err) {\n // Invalid json\n return defaultValue;\n }\n}\n\n/**\n * Extracts a JSON object from a string.\n *\n * @param value - The string to extract the JSON object from\n * @returns The parsed JSON object, or null if no JSON object is found\n * @throws {Error} If the input string is too long (longer than 5000 characters)\n * @example\n * import { extractJsonObject } from \"@settlemint/sdk-utils\";\n *\n * const json = extractJsonObject<{ port: number }>(\n * 'port info: {\"port\": 3000}',\n * );\n * // Returns: { port: 3000 }\n */\nexport function extractJsonObject<T>(value: string): T | null {\n if (value.length > 5000) {\n throw new Error(\"Input too long\");\n }\n const result = /\\{([\\s\\S]*)\\}/.exec(value);\n if (!result) {\n return null;\n }\n return tryParseJson<T>(result[0]);\n}\n\n/**\n * Converts a value to a JSON stringifiable format.\n *\n * @param value - The value to convert\n * @returns The JSON stringifiable value\n *\n * @example\n * import { makeJsonStringifiable } from \"@settlemint/sdk-utils\";\n *\n * const json = makeJsonStringifiable<{ amount: bigint }>({ amount: BigInt(1000) });\n * // Returns: '{\"amount\":\"1000\"}'\n */\nexport function makeJsonStringifiable<T>(value: unknown): T {\n if (value === undefined || value === null) {\n return value as T;\n }\n return tryParseJson<T>(\n JSON.stringify(\n value,\n (_, value) => (typeof value === \"bigint\" ? value.toString() : value), // return everything else unchanged\n ),\n ) as T;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAsBA,SAAgB,aAAgB,OAAe,eAAyB,MAAgB;AACtF,KAAI;EACF,MAAM,SAAS,KAAK,MAAM;
|
|
1
|
+
{"version":3,"file":"json.js","names":["value"],"sources":["../src/json.ts"],"sourcesContent":["/**\n * Attempts to parse a JSON string into a typed value, returning a default value if parsing fails.\n *\n * @param value - The JSON string to parse\n * @param defaultValue - The value to return if parsing fails or results in null/undefined\n * @returns The parsed JSON value as type T, or the default value if parsing fails\n *\n * @example\n * import { tryParseJson } from \"@settlemint/sdk-utils\";\n *\n * const config = tryParseJson<{ port: number }>(\n * '{\"port\": 3000}',\n * { port: 8080 }\n * );\n * // Returns: { port: 3000 }\n *\n * const invalid = tryParseJson<string[]>(\n * 'invalid json',\n * []\n * );\n * // Returns: []\n */\nexport function tryParseJson<T>(value: string, defaultValue: T | null = null): T | null {\n try {\n const parsed = JSON.parse(value) as T;\n if (parsed === undefined || parsed === null) {\n return defaultValue;\n }\n return parsed;\n } catch (_err) {\n // Invalid json\n return defaultValue;\n }\n}\n\n/**\n * Extracts a JSON object from a string.\n *\n * @param value - The string to extract the JSON object from\n * @returns The parsed JSON object, or null if no JSON object is found\n * @throws {Error} If the input string is too long (longer than 5000 characters)\n * @example\n * import { extractJsonObject } from \"@settlemint/sdk-utils\";\n *\n * const json = extractJsonObject<{ port: number }>(\n * 'port info: {\"port\": 3000}',\n * );\n * // Returns: { port: 3000 }\n */\nexport function extractJsonObject<T>(value: string): T | null {\n if (value.length > 5000) {\n throw new Error(\"Input too long\");\n }\n const result = /\\{([\\s\\S]*)\\}/.exec(value);\n if (!result) {\n return null;\n }\n return tryParseJson<T>(result[0]);\n}\n\n/**\n * Converts a value to a JSON stringifiable format.\n *\n * @param value - The value to convert\n * @returns The JSON stringifiable value\n *\n * @example\n * import { makeJsonStringifiable } from \"@settlemint/sdk-utils\";\n *\n * const json = makeJsonStringifiable<{ amount: bigint }>({ amount: BigInt(1000) });\n * // Returns: '{\"amount\":\"1000\"}'\n */\nexport function makeJsonStringifiable<T>(value: unknown): T {\n if (value === undefined || value === null) {\n return value as T;\n }\n return tryParseJson<T>(\n JSON.stringify(\n value,\n (_, value) => (typeof value === \"bigint\" ? value.toString() : value), // return everything else unchanged\n ),\n ) as T;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAsBA,SAAgB,aAAgB,OAAe,eAAyB,MAAgB;AACtF,KAAI;EACF,MAAM,SAAS,KAAK,MAAM,MAAM;AAChC,MAAI,WAAW,aAAa,WAAW,MAAM;AAC3C,UAAO;;AAET,SAAO;UACA,MAAM;AAEb,SAAO;;;;;;;;;;;;;;;;;AAkBX,SAAgB,kBAAqB,OAAyB;AAC5D,KAAI,MAAM,SAAS,KAAM;AACvB,QAAM,IAAI,MAAM,iBAAiB;;CAEnC,MAAM,SAAS,gBAAgB,KAAK,MAAM;AAC1C,KAAI,CAAC,QAAQ;AACX,SAAO;;AAET,QAAO,aAAgB,OAAO,GAAG;;;;;;;;;;;;;;AAenC,SAAgB,sBAAyB,OAAmB;AAC1D,KAAI,UAAU,aAAa,UAAU,MAAM;AACzC,SAAO;;AAET,QAAO,aACL,KAAK,UACH,QACC,GAAG,YAAW,OAAOA,YAAU,WAAWA,QAAM,UAAU,GAAGA,QAC/D,CACF"}
|
package/dist/logging.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logging.cjs","names":["logLevels: Record<LogLevel, number>","level","dataToKeep: Record<string, unknown>"],"sources":["../src/logging/mask-tokens.ts","../src/logging/logger.ts","../src/string.ts","../src/logging/request-logger.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","/**\n * Capitalizes the first letter of a string.\n *\n * @param val - The string to capitalize\n * @returns The input string with its first letter capitalized\n *\n * @example\n * import { capitalizeFirstLetter } from \"@settlemint/sdk-utils\";\n *\n * const capitalized = capitalizeFirstLetter(\"hello\");\n * // Returns: \"Hello\"\n */\nexport function capitalizeFirstLetter(val: string) {\n return String(val).charAt(0).toUpperCase() + String(val).slice(1);\n}\n\n/**\n * Converts a camelCase string to a human-readable string.\n *\n * @param s - The camelCase string to convert\n * @returns The human-readable string\n *\n * @example\n * import { camelCaseToWords } from \"@settlemint/sdk-utils\";\n *\n * const words = camelCaseToWords(\"camelCaseString\");\n * // Returns: \"Camel Case String\"\n */\nexport function camelCaseToWords(s: string) {\n const result = s.replace(/([a-z])([A-Z])/g, \"$1 $2\");\n const withSpaces = result.replace(/([A-Z])([a-z])/g, \" $1$2\");\n const capitalized = capitalizeFirstLetter(withSpaces);\n return capitalized.replace(/\\s+/g, \" \").trim();\n}\n\n/**\n * Replaces underscores and hyphens with spaces.\n *\n * @param s - The string to replace underscores and hyphens with spaces\n * @returns The input string with underscores and hyphens replaced with spaces\n *\n * @example\n * import { replaceUnderscoresAndHyphensWithSpaces } from \"@settlemint/sdk-utils\";\n *\n * const result = replaceUnderscoresAndHyphensWithSpaces(\"Already_Spaced-Second\");\n * // Returns: \"Already Spaced Second\"\n */\nexport function replaceUnderscoresAndHyphensWithSpaces(s: string) {\n return s.replace(/[-_]/g, \" \");\n}\n\n/**\n * Truncates a string to a maximum length and appends \"...\" if it is longer.\n *\n * @param value - The string to truncate\n * @param maxLength - The maximum length of the string\n * @returns The truncated string or the original string if it is shorter than the maximum length\n *\n * @example\n * import { truncate } from \"@settlemint/sdk-utils\";\n *\n * const truncated = truncate(\"Hello, world!\", 10);\n * // Returns: \"Hello, wor...\"\n */\nexport function truncate(value: string, maxLength: number) {\n if (value.length <= maxLength) {\n return value;\n }\n return `${value.slice(0, maxLength)}...`;\n}\n","import { truncate } from \"../string.js\";\nimport type { Logger } from \"./logger.js\";\n\nconst WARNING_THRESHOLD = 500;\nconst TRUNCATE_LENGTH = 50;\n\n/**\n * Logs the request and duration of a fetch call (> 500ms is logged as warn, otherwise info)\n * @param logger - The logger to use\n * @param name - The name of the request\n * @param fn - The fetch function to use\n * @returns The fetch function\n */\nexport function requestLogger(logger: Logger, name: string, fn: typeof fetch) {\n return async (...args: Parameters<typeof fetch>) => {\n const start = Date.now();\n try {\n return await fn(...args);\n } finally {\n const end = Date.now();\n const duration = end - start;\n const body = extractInfoFromBody(args[1]?.body ?? \"{}\");\n const message = `${name} path: ${args[0]}, took ${formatDuration(duration)}`;\n if (duration > WARNING_THRESHOLD) {\n logger.warn(message, body);\n } else {\n logger.info(message, body);\n }\n }\n };\n}\n\nfunction formatDuration(duration: number) {\n return duration < 1000 ? `${duration}ms` : `${(duration / 1000).toFixed(3)}s`;\n}\n\nfunction extractInfoFromBody(body: BodyInit) {\n try {\n const parsedBody = typeof body === \"string\" ? JSON.parse(body) : body;\n\n if (parsedBody === null || parsedBody === undefined || Object.keys(parsedBody).length === 0) {\n return null;\n }\n\n const dataToKeep: Record<string, unknown> = {};\n // Check for graphql fields\n if (\"query\" in parsedBody) {\n dataToKeep.query = truncate(parsedBody.query, TRUNCATE_LENGTH);\n }\n if (\"variables\" in parsedBody) {\n dataToKeep.variables = truncate(JSON.stringify(parsedBody.variables), TRUNCATE_LENGTH);\n }\n if (\"operationName\" in parsedBody) {\n dataToKeep.operationName = truncate(parsedBody.operationName, TRUNCATE_LENGTH);\n }\n\n if (Object.keys(dataToKeep).length > 0) {\n return JSON.stringify(dataToKeep);\n }\n\n // Not graphql, return the body as is\n return truncate(JSON.stringify(parsedBody || \"{}\"), TRUNCATE_LENGTH);\n } catch {\n return \"{}\";\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"logging.cjs","names":["logLevels: Record<LogLevel, number>","level","dataToKeep: Record<string, unknown>"],"sources":["../src/logging/mask-tokens.ts","../src/logging/logger.ts","../src/string.ts","../src/logging/request-logger.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","/**\n * Capitalizes the first letter of a string.\n *\n * @param val - The string to capitalize\n * @returns The input string with its first letter capitalized\n *\n * @example\n * import { capitalizeFirstLetter } from \"@settlemint/sdk-utils\";\n *\n * const capitalized = capitalizeFirstLetter(\"hello\");\n * // Returns: \"Hello\"\n */\nexport function capitalizeFirstLetter(val: string) {\n return String(val).charAt(0).toUpperCase() + String(val).slice(1);\n}\n\n/**\n * Converts a camelCase string to a human-readable string.\n *\n * @param s - The camelCase string to convert\n * @returns The human-readable string\n *\n * @example\n * import { camelCaseToWords } from \"@settlemint/sdk-utils\";\n *\n * const words = camelCaseToWords(\"camelCaseString\");\n * // Returns: \"Camel Case String\"\n */\nexport function camelCaseToWords(s: string) {\n const result = s.replace(/([a-z])([A-Z])/g, \"$1 $2\");\n const withSpaces = result.replace(/([A-Z])([a-z])/g, \" $1$2\");\n const capitalized = capitalizeFirstLetter(withSpaces);\n return capitalized.replace(/\\s+/g, \" \").trim();\n}\n\n/**\n * Replaces underscores and hyphens with spaces.\n *\n * @param s - The string to replace underscores and hyphens with spaces\n * @returns The input string with underscores and hyphens replaced with spaces\n *\n * @example\n * import { replaceUnderscoresAndHyphensWithSpaces } from \"@settlemint/sdk-utils\";\n *\n * const result = replaceUnderscoresAndHyphensWithSpaces(\"Already_Spaced-Second\");\n * // Returns: \"Already Spaced Second\"\n */\nexport function replaceUnderscoresAndHyphensWithSpaces(s: string) {\n return s.replace(/[-_]/g, \" \");\n}\n\n/**\n * Truncates a string to a maximum length and appends \"...\" if it is longer.\n *\n * @param value - The string to truncate\n * @param maxLength - The maximum length of the string\n * @returns The truncated string or the original string if it is shorter than the maximum length\n *\n * @example\n * import { truncate } from \"@settlemint/sdk-utils\";\n *\n * const truncated = truncate(\"Hello, world!\", 10);\n * // Returns: \"Hello, wor...\"\n */\nexport function truncate(value: string, maxLength: number) {\n if (value.length <= maxLength) {\n return value;\n }\n return `${value.slice(0, maxLength)}...`;\n}\n","import { truncate } from \"../string.js\";\nimport type { Logger } from \"./logger.js\";\n\nconst WARNING_THRESHOLD = 500;\nconst TRUNCATE_LENGTH = 50;\n\n/**\n * Logs the request and duration of a fetch call (> 500ms is logged as warn, otherwise info)\n * @param logger - The logger to use\n * @param name - The name of the request\n * @param fn - The fetch function to use\n * @returns The fetch function\n */\nexport function requestLogger(logger: Logger, name: string, fn: typeof fetch) {\n return async (...args: Parameters<typeof fetch>) => {\n const start = Date.now();\n try {\n return await fn(...args);\n } finally {\n const end = Date.now();\n const duration = end - start;\n const body = extractInfoFromBody(args[1]?.body ?? \"{}\");\n const message = `${name} path: ${args[0]}, took ${formatDuration(duration)}`;\n if (duration > WARNING_THRESHOLD) {\n logger.warn(message, body);\n } else {\n logger.info(message, body);\n }\n }\n };\n}\n\nfunction formatDuration(duration: number) {\n return duration < 1000 ? `${duration}ms` : `${(duration / 1000).toFixed(3)}s`;\n}\n\nfunction extractInfoFromBody(body: BodyInit) {\n try {\n const parsedBody = typeof body === \"string\" ? JSON.parse(body) : body;\n\n if (parsedBody === null || parsedBody === undefined || Object.keys(parsedBody).length === 0) {\n return null;\n }\n\n const dataToKeep: Record<string, unknown> = {};\n // Check for graphql fields\n if (\"query\" in parsedBody) {\n dataToKeep.query = truncate(parsedBody.query, TRUNCATE_LENGTH);\n }\n if (\"variables\" in parsedBody) {\n dataToKeep.variables = truncate(JSON.stringify(parsedBody.variables), TRUNCATE_LENGTH);\n }\n if (\"operationName\" in parsedBody) {\n dataToKeep.operationName = truncate(parsedBody.operationName, TRUNCATE_LENGTH);\n }\n\n if (Object.keys(dataToKeep).length > 0) {\n return JSON.stringify(dataToKeep);\n }\n\n // Not graphql, return the body as is\n return truncate(JSON.stringify(parsedBody || \"{}\"), TRUNCATE_LENGTH);\n } catch {\n return \"{}\";\n }\n}\n"],"mappings":"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"}
|
package/dist/logging.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logging.js","names":["logLevels: Record<LogLevel, number>","level","dataToKeep: Record<string, unknown>"],"sources":["../src/logging/mask-tokens.ts","../src/logging/logger.ts","../src/string.ts","../src/logging/request-logger.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","/**\n * Capitalizes the first letter of a string.\n *\n * @param val - The string to capitalize\n * @returns The input string with its first letter capitalized\n *\n * @example\n * import { capitalizeFirstLetter } from \"@settlemint/sdk-utils\";\n *\n * const capitalized = capitalizeFirstLetter(\"hello\");\n * // Returns: \"Hello\"\n */\nexport function capitalizeFirstLetter(val: string) {\n return String(val).charAt(0).toUpperCase() + String(val).slice(1);\n}\n\n/**\n * Converts a camelCase string to a human-readable string.\n *\n * @param s - The camelCase string to convert\n * @returns The human-readable string\n *\n * @example\n * import { camelCaseToWords } from \"@settlemint/sdk-utils\";\n *\n * const words = camelCaseToWords(\"camelCaseString\");\n * // Returns: \"Camel Case String\"\n */\nexport function camelCaseToWords(s: string) {\n const result = s.replace(/([a-z])([A-Z])/g, \"$1 $2\");\n const withSpaces = result.replace(/([A-Z])([a-z])/g, \" $1$2\");\n const capitalized = capitalizeFirstLetter(withSpaces);\n return capitalized.replace(/\\s+/g, \" \").trim();\n}\n\n/**\n * Replaces underscores and hyphens with spaces.\n *\n * @param s - The string to replace underscores and hyphens with spaces\n * @returns The input string with underscores and hyphens replaced with spaces\n *\n * @example\n * import { replaceUnderscoresAndHyphensWithSpaces } from \"@settlemint/sdk-utils\";\n *\n * const result = replaceUnderscoresAndHyphensWithSpaces(\"Already_Spaced-Second\");\n * // Returns: \"Already Spaced Second\"\n */\nexport function replaceUnderscoresAndHyphensWithSpaces(s: string) {\n return s.replace(/[-_]/g, \" \");\n}\n\n/**\n * Truncates a string to a maximum length and appends \"...\" if it is longer.\n *\n * @param value - The string to truncate\n * @param maxLength - The maximum length of the string\n * @returns The truncated string or the original string if it is shorter than the maximum length\n *\n * @example\n * import { truncate } from \"@settlemint/sdk-utils\";\n *\n * const truncated = truncate(\"Hello, world!\", 10);\n * // Returns: \"Hello, wor...\"\n */\nexport function truncate(value: string, maxLength: number) {\n if (value.length <= maxLength) {\n return value;\n }\n return `${value.slice(0, maxLength)}...`;\n}\n","import { truncate } from \"../string.js\";\nimport type { Logger } from \"./logger.js\";\n\nconst WARNING_THRESHOLD = 500;\nconst TRUNCATE_LENGTH = 50;\n\n/**\n * Logs the request and duration of a fetch call (> 500ms is logged as warn, otherwise info)\n * @param logger - The logger to use\n * @param name - The name of the request\n * @param fn - The fetch function to use\n * @returns The fetch function\n */\nexport function requestLogger(logger: Logger, name: string, fn: typeof fetch) {\n return async (...args: Parameters<typeof fetch>) => {\n const start = Date.now();\n try {\n return await fn(...args);\n } finally {\n const end = Date.now();\n const duration = end - start;\n const body = extractInfoFromBody(args[1]?.body ?? \"{}\");\n const message = `${name} path: ${args[0]}, took ${formatDuration(duration)}`;\n if (duration > WARNING_THRESHOLD) {\n logger.warn(message, body);\n } else {\n logger.info(message, body);\n }\n }\n };\n}\n\nfunction formatDuration(duration: number) {\n return duration < 1000 ? `${duration}ms` : `${(duration / 1000).toFixed(3)}s`;\n}\n\nfunction extractInfoFromBody(body: BodyInit) {\n try {\n const parsedBody = typeof body === \"string\" ? JSON.parse(body) : body;\n\n if (parsedBody === null || parsedBody === undefined || Object.keys(parsedBody).length === 0) {\n return null;\n }\n\n const dataToKeep: Record<string, unknown> = {};\n // Check for graphql fields\n if (\"query\" in parsedBody) {\n dataToKeep.query = truncate(parsedBody.query, TRUNCATE_LENGTH);\n }\n if (\"variables\" in parsedBody) {\n dataToKeep.variables = truncate(JSON.stringify(parsedBody.variables), TRUNCATE_LENGTH);\n }\n if (\"operationName\" in parsedBody) {\n dataToKeep.operationName = truncate(parsedBody.operationName, TRUNCATE_LENGTH);\n }\n\n if (Object.keys(dataToKeep).length > 0) {\n return JSON.stringify(dataToKeep);\n }\n\n // Not graphql, return the body as is\n return truncate(JSON.stringify(parsedBody || \"{}\"), TRUNCATE_LENGTH);\n } catch {\n return \"{}\";\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"logging.js","names":["logLevels: Record<LogLevel, number>","level","dataToKeep: Record<string, unknown>"],"sources":["../src/logging/mask-tokens.ts","../src/logging/logger.ts","../src/string.ts","../src/logging/request-logger.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","/**\n * Capitalizes the first letter of a string.\n *\n * @param val - The string to capitalize\n * @returns The input string with its first letter capitalized\n *\n * @example\n * import { capitalizeFirstLetter } from \"@settlemint/sdk-utils\";\n *\n * const capitalized = capitalizeFirstLetter(\"hello\");\n * // Returns: \"Hello\"\n */\nexport function capitalizeFirstLetter(val: string) {\n return String(val).charAt(0).toUpperCase() + String(val).slice(1);\n}\n\n/**\n * Converts a camelCase string to a human-readable string.\n *\n * @param s - The camelCase string to convert\n * @returns The human-readable string\n *\n * @example\n * import { camelCaseToWords } from \"@settlemint/sdk-utils\";\n *\n * const words = camelCaseToWords(\"camelCaseString\");\n * // Returns: \"Camel Case String\"\n */\nexport function camelCaseToWords(s: string) {\n const result = s.replace(/([a-z])([A-Z])/g, \"$1 $2\");\n const withSpaces = result.replace(/([A-Z])([a-z])/g, \" $1$2\");\n const capitalized = capitalizeFirstLetter(withSpaces);\n return capitalized.replace(/\\s+/g, \" \").trim();\n}\n\n/**\n * Replaces underscores and hyphens with spaces.\n *\n * @param s - The string to replace underscores and hyphens with spaces\n * @returns The input string with underscores and hyphens replaced with spaces\n *\n * @example\n * import { replaceUnderscoresAndHyphensWithSpaces } from \"@settlemint/sdk-utils\";\n *\n * const result = replaceUnderscoresAndHyphensWithSpaces(\"Already_Spaced-Second\");\n * // Returns: \"Already Spaced Second\"\n */\nexport function replaceUnderscoresAndHyphensWithSpaces(s: string) {\n return s.replace(/[-_]/g, \" \");\n}\n\n/**\n * Truncates a string to a maximum length and appends \"...\" if it is longer.\n *\n * @param value - The string to truncate\n * @param maxLength - The maximum length of the string\n * @returns The truncated string or the original string if it is shorter than the maximum length\n *\n * @example\n * import { truncate } from \"@settlemint/sdk-utils\";\n *\n * const truncated = truncate(\"Hello, world!\", 10);\n * // Returns: \"Hello, wor...\"\n */\nexport function truncate(value: string, maxLength: number) {\n if (value.length <= maxLength) {\n return value;\n }\n return `${value.slice(0, maxLength)}...`;\n}\n","import { truncate } from \"../string.js\";\nimport type { Logger } from \"./logger.js\";\n\nconst WARNING_THRESHOLD = 500;\nconst TRUNCATE_LENGTH = 50;\n\n/**\n * Logs the request and duration of a fetch call (> 500ms is logged as warn, otherwise info)\n * @param logger - The logger to use\n * @param name - The name of the request\n * @param fn - The fetch function to use\n * @returns The fetch function\n */\nexport function requestLogger(logger: Logger, name: string, fn: typeof fetch) {\n return async (...args: Parameters<typeof fetch>) => {\n const start = Date.now();\n try {\n return await fn(...args);\n } finally {\n const end = Date.now();\n const duration = end - start;\n const body = extractInfoFromBody(args[1]?.body ?? \"{}\");\n const message = `${name} path: ${args[0]}, took ${formatDuration(duration)}`;\n if (duration > WARNING_THRESHOLD) {\n logger.warn(message, body);\n } else {\n logger.info(message, body);\n }\n }\n };\n}\n\nfunction formatDuration(duration: number) {\n return duration < 1000 ? `${duration}ms` : `${(duration / 1000).toFixed(3)}s`;\n}\n\nfunction extractInfoFromBody(body: BodyInit) {\n try {\n const parsedBody = typeof body === \"string\" ? JSON.parse(body) : body;\n\n if (parsedBody === null || parsedBody === undefined || Object.keys(parsedBody).length === 0) {\n return null;\n }\n\n const dataToKeep: Record<string, unknown> = {};\n // Check for graphql fields\n if (\"query\" in parsedBody) {\n dataToKeep.query = truncate(parsedBody.query, TRUNCATE_LENGTH);\n }\n if (\"variables\" in parsedBody) {\n dataToKeep.variables = truncate(JSON.stringify(parsedBody.variables), TRUNCATE_LENGTH);\n }\n if (\"operationName\" in parsedBody) {\n dataToKeep.operationName = truncate(parsedBody.operationName, TRUNCATE_LENGTH);\n }\n\n if (Object.keys(dataToKeep).length > 0) {\n return JSON.stringify(dataToKeep);\n }\n\n // Not graphql, return the body as is\n return truncate(JSON.stringify(parsedBody || \"{}\"), TRUNCATE_LENGTH);\n } catch {\n return \"{}\";\n }\n}\n"],"mappings":"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"}
|