@settlemint/sdk-utils 2.6.2-prf41b74b3 → 2.6.2-prfaedf028

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.
@@ -21,18 +21,30 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
21
21
  }) : target, mod));
22
22
 
23
23
  //#endregion
24
- const node_fs_promises = __toESM(require("node:fs/promises"));
25
- const node_path = __toESM(require("node:path"));
26
- const find_up = __toESM(require("find-up"));
27
- const glob = __toESM(require("glob"));
28
- const package_manager_detector_detect = __toESM(require("package-manager-detector/detect"));
29
- const __antfu_install_pkg = __toESM(require("@antfu/install-pkg"));
30
- const yoctocolors = __toESM(require("yoctocolors"));
31
- const node_child_process = __toESM(require("node:child_process"));
32
- const is_in_ci = __toESM(require("is-in-ci"));
33
- const yocto_spinner = __toESM(require("yocto-spinner"));
34
- const console_table_printer = __toESM(require("console-table-printer"));
35
- const __npmcli_package_json = __toESM(require("@npmcli/package-json"));
24
+ let node_fs_promises = require("node:fs/promises");
25
+ node_fs_promises = __toESM(node_fs_promises);
26
+ let node_path = require("node:path");
27
+ node_path = __toESM(node_path);
28
+ let find_up = require("find-up");
29
+ find_up = __toESM(find_up);
30
+ let glob = require("glob");
31
+ glob = __toESM(glob);
32
+ let package_manager_detector_detect = require("package-manager-detector/detect");
33
+ package_manager_detector_detect = __toESM(package_manager_detector_detect);
34
+ let __antfu_install_pkg = require("@antfu/install-pkg");
35
+ __antfu_install_pkg = __toESM(__antfu_install_pkg);
36
+ let yoctocolors = require("yoctocolors");
37
+ yoctocolors = __toESM(yoctocolors);
38
+ let node_child_process = require("node:child_process");
39
+ node_child_process = __toESM(node_child_process);
40
+ let is_in_ci = require("is-in-ci");
41
+ is_in_ci = __toESM(is_in_ci);
42
+ let yocto_spinner = require("yocto-spinner");
43
+ yocto_spinner = __toESM(yocto_spinner);
44
+ let console_table_printer = require("console-table-printer");
45
+ console_table_printer = __toESM(console_table_printer);
46
+ let __npmcli_package_json = require("@npmcli/package-json");
47
+ __npmcli_package_json = __toESM(__npmcli_package_json);
36
48
 
37
49
  //#region src/filesystem/project-root.ts
38
50
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"package-manager.cjs","names":["value","code: number","output: string[]","items","originalError: Error","isInCi","spinner","resolve","table","Table","pkgjs","pkgjs"],"sources":["../src/filesystem/project-root.ts","../src/filesystem/exists.ts","../src/json.ts","../src/filesystem/mono-repo.ts","../src/package-manager/download-and-extract.ts","../src/package-manager/get-package-manager.ts","../src/package-manager/get-package-manager-executable.ts","../src/terminal/should-print.ts","../src/terminal/ascii.ts","../src/logging/mask-tokens.ts","../src/terminal/cancel.ts","../src/terminal/execute-command.ts","../src/terminal/intro.ts","../src/terminal/note.ts","../src/terminal/list.ts","../src/terminal/outro.ts","../src/terminal/spinner.ts","../src/string.ts","../src/terminal/table.ts","../src/package-manager/install-dependencies.ts","../src/package-manager/is-package-installed.ts","../src/package-manager/set-name.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","import { readdir, rm } from \"node:fs/promises\";\nimport { resolve } from \"node:path\";\nimport { exists } from \"../filesystem.js\";\n\n/**\n * Formats a directory path by removing trailing slashes and whitespace\n *\n * @param targetDir - The directory path to format\n * @returns The formatted directory path\n * @example\n * import { formatTargetDir } from \"@settlemint/sdk-utils/package-manager\";\n *\n * const formatted = formatTargetDir(\"/path/to/dir/ \"); // \"/path/to/dir\"\n */\nexport function formatTargetDir(targetDir: string): string {\n return targetDir?.trim().replace(/\\/+$/g, \"\");\n}\n\n/**\n * Checks if a directory is empty or contains only a .git folder\n *\n * @param path - The directory path to check\n * @returns True if directory is empty or contains only .git, false otherwise\n * @example\n * import { isEmpty } from \"@settlemint/sdk-utils/package-manager\";\n *\n * if (await isEmpty(\"/path/to/dir\")) {\n * // Directory is empty\n * }\n */\nexport async function isEmpty(path: string): Promise<boolean> {\n const files = await readdir(path);\n return files.length === 0 || (files.length === 1 && files[0] === \".git\");\n}\n\n/**\n * Removes all contents of a directory except the .git folder\n *\n * @param dir - The directory path to empty\n * @example\n * import { emptyDir } from \"@settlemint/sdk-utils/package-manager\";\n *\n * await emptyDir(\"/path/to/dir\"); // Removes all contents except .git\n */\nexport async function emptyDir(dir: string): Promise<void> {\n if (!(await exists(dir))) return;\n for (const file of await readdir(dir)) {\n if (file === \".git\") continue;\n await rm(resolve(dir, file), { recursive: true, force: true });\n }\n}\n","import type { AgentName } from \"package-manager-detector\";\nimport { detect } from \"package-manager-detector/detect\";\n\n/**\n * Detects the package manager used in the current project\n *\n * @param targetDir - The directory to check for package manager (optional, defaults to process.cwd())\n * @returns The name of the package manager\n * @example\n * import { getPackageManager } from \"@settlemint/sdk-utils/package-manager\";\n *\n * const packageManager = await getPackageManager();\n * console.log(`Using ${packageManager}`);\n */\nexport async function getPackageManager(targetDir?: string): Promise<AgentName> {\n const packageManager = await detect({ cwd: targetDir || process.cwd() });\n\n return packageManager?.name ?? \"npm\";\n}\n","import { getPackageManager } from \"./get-package-manager.js\";\n\n/**\n * Retrieves the executable command and arguments for the package manager\n *\n * @param targetDir - The directory to check for package manager (optional, defaults to process.cwd())\n * @returns An object containing the command and arguments for the package manager\n * @example\n * import { getPackageManagerExecutable } from \"@settlemint/sdk-utils/package-manager\";\n *\n * const { command, args } = await getPackageManagerExecutable();\n * console.log(`Using ${command} with args: ${args.join(\" \")}`);\n */\nexport async function getPackageManagerExecutable(targetDir?: string): Promise<{ command: string; args: string[] }> {\n const packageManager = await getPackageManager(targetDir ?? process.cwd());\n\n switch (packageManager) {\n case \"pnpm\":\n return { command: \"pnpm\", args: [\"dlx\"] };\n case \"bun\":\n return { command: \"bunx\", args: [] };\n case \"yarn\":\n return { command: \"yarn\", args: [\"create\"] };\n }\n\n // Default to npm\n return { command: \"npx\", args: [] };\n}\n","/**\n * Returns true if the terminal should print, false otherwise.\n * @returns true if the terminal should print, false otherwise.\n */\nexport function shouldPrint() {\n return process.env.SETTLEMINT_DISABLE_TERMINAL !== \"true\";\n}\n","import { magentaBright } from \"yoctocolors\";\nimport { shouldPrint } from \"./should-print.js\";\n\n/**\n * Prints the SettleMint ASCII art logo to the console in magenta color.\n * Used for CLI branding and visual identification.\n *\n * @example\n * import { ascii } from \"@settlemint/sdk-utils/terminal\";\n *\n * // Prints the SettleMint logo\n * ascii();\n */\nexport const ascii = (): void => {\n if (!shouldPrint()) {\n return;\n }\n console.log(\n magentaBright(`\n _________ __ __ .__ _____ .__ __\n / _____/ _____/ |__/ |_| | ____ / \\\\ |__| _____/ |_\n \\\\_____ \\\\_/ __ \\\\ __\\\\ __\\\\ | _/ __ \\\\ / \\\\ / \\\\| |/ \\\\ __\\\\\n / \\\\ ___/| | | | | |_\\\\ ___// Y \\\\ | | \\\\ |\n/_________/\\\\_____>__| |__| |____/\\\\_____>____|____/__|___|__/__|\n`),\n );\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 \"@/logging/mask-tokens.js\";\nimport { inverse, redBright } from \"yoctocolors\";\n\n/**\n * Error class used to indicate that the operation was cancelled.\n * This error is used to signal that the operation should be aborted.\n */\nexport class CancelError extends Error {}\n\n/**\n * Displays an error message in red inverse text and throws a CancelError.\n * Used to terminate execution with a visible error message.\n * Any sensitive tokens in the message are masked before display.\n *\n * @param msg - The error message to display\n * @returns never - Function does not return as it throws an error\n * @example\n * import { cancel } from \"@settlemint/sdk-utils/terminal\";\n *\n * // Exits process with error message\n * cancel(\"An error occurred\");\n */\nexport const cancel = (msg: string): never => {\n console.log(\"\");\n console.log(inverse(redBright(maskTokens(msg))));\n console.log(\"\");\n throw new CancelError(msg);\n};\n","import { type SpawnOptionsWithoutStdio, spawn } from \"node:child_process\";\nimport { maskTokens } from \"../logging/mask-tokens.js\";\n\n/**\n * Options for executing a command, extending SpawnOptionsWithoutStdio\n */\nexport interface ExecuteCommandOptions extends SpawnOptionsWithoutStdio {\n /** Whether to suppress output to stdout/stderr */\n silent?: boolean;\n}\n\n/**\n * Error class for command execution errors\n * @extends Error\n */\nexport class CommandError extends Error {\n /**\n * Constructs a new CommandError\n * @param message - The error message\n * @param code - The exit code of the command\n * @param output - The output of the command\n */\n constructor(\n message: string,\n public readonly code: number,\n public readonly output: string[],\n ) {\n super(message);\n }\n}\n\n/**\n * Executes a command with the given arguments in a child process.\n * Pipes stdin to the child process and captures stdout/stderr output.\n * Masks any sensitive tokens in the output before displaying or returning.\n *\n * @param command - The command to execute\n * @param args - Array of arguments to pass to the command\n * @param options - Options for customizing command execution\n * @returns Array of output strings from stdout and stderr\n * @throws {CommandError} If the process fails to start or exits with non-zero code\n * @example\n * import { executeCommand } from \"@settlemint/sdk-utils/terminal\";\n *\n * // Execute git clone\n * await executeCommand(\"git\", [\"clone\", \"repo-url\"]);\n *\n * // Execute silently\n * await executeCommand(\"npm\", [\"install\"], { silent: true });\n */\nexport async function executeCommand(\n command: string,\n args: string[],\n options?: ExecuteCommandOptions,\n): Promise<string[]> {\n const { silent, ...spawnOptions } = options ?? {};\n const child = spawn(command, args, { ...spawnOptions, env: { ...process.env, ...options?.env } });\n process.stdin.pipe(child.stdin);\n const output: string[] = [];\n return new Promise((resolve, reject) => {\n child.stdout.on(\"data\", (data: Buffer | string) => {\n const maskedData = maskTokens(data.toString());\n if (!silent) {\n process.stdout.write(maskedData);\n }\n output.push(maskedData);\n });\n child.stderr.on(\"data\", (data: Buffer | string) => {\n const maskedData = maskTokens(data.toString());\n if (!silent) {\n process.stderr.write(maskedData);\n }\n output.push(maskedData);\n });\n child.on(\"error\", (err) => {\n process.stdin.unpipe(child.stdin);\n reject(new CommandError(err.message, \"code\" in err && typeof err.code === \"number\" ? err.code : 1, output));\n });\n child.on(\"close\", (code) => {\n process.stdin.unpipe(child.stdin);\n if (code === 0 || code === null || code === 143) {\n resolve(output);\n return;\n }\n reject(new CommandError(`Command \"${command}\" exited with code ${code}`, code, output));\n });\n });\n}\n","import { maskTokens } from \"@/logging/mask-tokens.js\";\nimport { magentaBright } from \"yoctocolors\";\nimport { shouldPrint } from \"./should-print.js\";\n\n/**\n * Displays an introductory message in magenta text with padding.\n * Any sensitive tokens in the message are masked before display.\n *\n * @param msg - The message to display as introduction\n * @example\n * import { intro } from \"@settlemint/sdk-utils/terminal\";\n *\n * // Display intro message\n * intro(\"Starting deployment...\");\n */\nexport const intro = (msg: string): void => {\n if (!shouldPrint()) {\n return;\n }\n console.log(\"\");\n console.log(magentaBright(maskTokens(msg)));\n console.log(\"\");\n};\n","import { maskTokens } from \"@/logging/mask-tokens.js\";\nimport { yellowBright } from \"yoctocolors\";\nimport { shouldPrint } from \"./should-print.js\";\n\n/**\n * Displays a note message with optional warning level formatting.\n * Regular notes are displayed in normal text, while warnings are shown in yellow.\n * Any sensitive tokens in the message are masked before display.\n *\n * @param message - The message to display as a note\n * @param level - The note level: \"info\" (default) or \"warn\" for warning styling\n * @example\n * import { note } from \"@settlemint/sdk-utils/terminal\";\n *\n * // Display info note\n * note(\"Operation completed successfully\");\n *\n * // Display warning note\n * note(\"Low disk space remaining\", \"warn\");\n */\nexport const note = (message: string, level: \"info\" | \"warn\" = \"info\"): void => {\n if (!shouldPrint()) {\n return;\n }\n const maskedMessage = maskTokens(message);\n\n console.log(\"\");\n if (level === \"warn\") {\n console.warn(yellowBright(maskedMessage));\n return;\n }\n\n console.log(maskedMessage);\n};\n","import { note } from \"./note.js\";\n\n/**\n * Displays a list of items in a formatted manner, supporting nested items.\n *\n * @param title - The title of the list\n * @param items - The items to display, can be strings or arrays for nested items\n * @returns The formatted list\n * @example\n * import { list } from \"@settlemint/sdk-utils/terminal\";\n *\n * // Simple list\n * list(\"Use cases\", [\"use case 1\", \"use case 2\", \"use case 3\"]);\n *\n * // Nested list\n * list(\"Providers\", [\n * \"AWS\",\n * [\"us-east-1\", \"eu-west-1\"],\n * \"Azure\",\n * [\"eastus\", \"westeurope\"]\n * ]);\n */\nexport function list(title: string, items: Array<string | string[]>) {\n const formatItems = (items: Array<string | string[]>): string => {\n return items\n .map((item) => {\n if (Array.isArray(item)) {\n return item.map((subItem) => ` • ${subItem}`).join(\"\\n\");\n }\n return ` • ${item}`;\n })\n .join(\"\\n\");\n };\n\n return note(`${title}:\\n\\n${formatItems(items)}`);\n}\n","import { maskTokens } from \"@/logging/mask-tokens.js\";\nimport { shouldPrint } from \"@/terminal/should-print.js\";\nimport { greenBright, inverse } from \"yoctocolors\";\n\n/**\n * Displays a closing message in green inverted text with padding.\n * Any sensitive tokens in the message are masked before display.\n *\n * @param msg - The message to display as conclusion\n * @example\n * import { outro } from \"@settlemint/sdk-utils/terminal\";\n *\n * // Display outro message\n * outro(\"Deployment completed successfully!\");\n */\nexport const outro = (msg: string): void => {\n if (!shouldPrint()) {\n return;\n }\n console.log(\"\");\n console.log(inverse(greenBright(maskTokens(msg))));\n console.log(\"\");\n};\n","import isInCi from \"is-in-ci\";\nimport yoctoSpinner, { type Spinner } from \"yocto-spinner\";\nimport { redBright } from \"yoctocolors\";\nimport { maskTokens } from \"../logging/mask-tokens.js\";\nimport { note } from \"./note.js\";\nimport { shouldPrint } from \"./should-print.js\";\n\n/**\n * Error class used to indicate that the spinner operation failed.\n * This error is used to signal that the operation should be aborted.\n */\nexport class SpinnerError extends Error {\n constructor(\n message: string,\n public readonly originalError: Error,\n ) {\n super(message);\n this.name = \"SpinnerError\";\n }\n}\n\n/**\n * Options for configuring the spinner behavior\n */\nexport interface SpinnerOptions<R> {\n /** Message to display when spinner starts */\n startMessage: string;\n /** Async task to execute while spinner is active */\n task: (spinner?: Spinner) => Promise<R>;\n /** Message to display when spinner completes successfully */\n stopMessage: string;\n}\n\n/**\n * Displays a loading spinner while executing an async task.\n * Shows progress with start/stop messages and handles errors.\n * Spinner is disabled in CI environments.\n *\n * @param options - Configuration options for the spinner\n * @returns The result from the executed task\n * @throws Will exit process with code 1 if task fails\n * @example\n * import { spinner } from \"@settlemint/sdk-utils/terminal\";\n *\n * // Show spinner during async task\n * const result = await spinner({\n * startMessage: \"Deploying...\",\n * task: async () => {\n * // Async work here\n * return \"success\";\n * },\n * stopMessage: \"Deployed successfully!\"\n * });\n */\nexport const spinner = async <R>(options: SpinnerOptions<R>): Promise<R> => {\n const handleError = (error: Error) => {\n const errorMessage = maskTokens(error.message);\n note(redBright(`${errorMessage}\\n\\n${error.stack}`));\n throw new SpinnerError(errorMessage, error);\n };\n if (isInCi || !shouldPrint()) {\n try {\n return await options.task();\n } catch (err) {\n return handleError(err as Error);\n }\n }\n const spinner = yoctoSpinner({ stream: process.stdout }).start(options.startMessage);\n try {\n const result = await options.task(spinner);\n spinner.success(options.stopMessage);\n // Ensure spinner success message renders before proceeding to avoid\n // terminal output overlap issues with subsequent messages\n await new Promise((resolve) => process.nextTick(resolve));\n return result;\n } catch (err) {\n spinner.error(redBright(`${options.startMessage} --> Error!`));\n return handleError(err as Error);\n }\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","import { Table } from \"console-table-printer\";\nimport { whiteBright } from \"yoctocolors\";\nimport { camelCaseToWords } from \"@/string.js\";\nimport { note } from \"./note.js\";\nimport { shouldPrint } from \"./should-print.js\";\n/**\n * Displays data in a formatted table in the terminal.\n *\n * @param title - Title to display above the table\n * @param data - Array of objects to display in table format\n * @example\n * import { table } from \"@settlemint/sdk-utils/terminal\";\n *\n * const data = [\n * { name: \"Item 1\", value: 100 },\n * { name: \"Item 2\", value: 200 }\n * ];\n *\n * table(\"My Table\", data);\n */\nexport function table(title: string, data: unknown[]): void {\n if (!shouldPrint()) {\n return;\n }\n\n note(title);\n\n if (!data || data.length === 0) {\n note(\"No data to display\");\n return;\n }\n\n const columnKeys = Object.keys(data[0] as Record<string, unknown>);\n const table = new Table({\n columns: columnKeys.map((key) => ({\n name: key,\n title: whiteBright(camelCaseToWords(key)),\n alignment: \"left\",\n })),\n });\n // biome-ignore lint/suspicious/noExplicitAny: Data structure varies based on table content\n table.addRows(data as Array<Record<string, any>>);\n table.printTable();\n}\n","import { installPackage } from \"@antfu/install-pkg\";\nimport { note } from \"../terminal.js\";\n\n/**\n * Installs one or more packages as dependencies using the detected package manager\n *\n * @param pkgs - A single package name or array of package names to install\n * @param cwd - The directory to run the installation in\n * @returns A promise that resolves when installation is complete\n * @throws If package installation fails\n * @example\n * import { installDependencies } from \"@settlemint/sdk-utils/package-manager\";\n *\n * // Install a single package\n * await installDependencies(\"express\");\n *\n * // Install multiple packages\n * await installDependencies([\"express\", \"cors\"]);\n */\nexport async function installDependencies(pkgs: string | string[], cwd?: string) {\n try {\n await installPackage(pkgs, { silent: true, additionalArgs: [\"--exact\"], cwd });\n } catch (err) {\n const error = err instanceof Error ? err.message : \"Unknown error\";\n note(\n `Failed to install ${Array.isArray(pkgs) ? `dependencies '${pkgs.join(\", \")}'` : `dependency '${pkgs}'`}: ${error}`,\n \"warn\",\n );\n }\n}\n","import { projectRoot } from \"@/filesystem/project-root.js\";\nimport pkgjs from \"@npmcli/package-json\";\n\n/**\n * Checks if a package is installed in the project's dependencies, devDependencies, or peerDependencies.\n *\n * @param name - The name of the package to check\n * @param path - The path to the project root directory. If not provided, will be automatically determined\n * @returns Whether the package is installed\n * @throws If unable to read or parse the package.json file\n * @example\n * import { isPackageInstalled } from \"@settlemint/sdk-utils/package-manager\";\n *\n * const isInstalled = await isPackageInstalled(\"@settlemint/sdk-utils\");\n * console.log(`@settlemint/sdk-utils is installed: ${isInstalled}`);\n */\nexport async function isPackageInstalled(name: string, path?: string) {\n // Read the package.json file\n const pkgJson = await pkgjs.load(path ?? (await projectRoot()));\n\n const inDependencies = !!pkgJson.content.dependencies?.[name];\n const inDevDependencies = !!pkgJson.content.devDependencies?.[name];\n const inPeerDependencies = !!pkgJson.content.peerDependencies?.[name];\n\n return inDependencies || inDevDependencies || inPeerDependencies;\n}\n","import { projectRoot } from \"@/filesystem/project-root.js\";\nimport pkgjs from \"@npmcli/package-json\";\n\n/**\n * Sets the name field in the package.json file\n *\n * @param name - The new name to set in the package.json file\n * @param path - The path to the project root directory. If not provided, will be automatically determined\n * @returns A promise that resolves when the package.json has been updated\n * @throws If unable to read, update or save the package.json file\n * @example\n * import { setName } from \"@settlemint/sdk-utils/package-manager\";\n *\n * await setName(\"my-new-project-name\");\n */\nexport async function setName(name: string, path?: string) {\n // Read the package.json file\n const pkgJson = await pkgjs.load(path ?? (await projectRoot()));\n\n pkgJson.update({\n name,\n });\n\n await pkgJson.save();\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"package-manager.cjs","names":["value","code: number","output: string[]","items","originalError: Error","isInCi","spinner","resolve","table","Table","pkgjs","pkgjs"],"sources":["../src/filesystem/project-root.ts","../src/filesystem/exists.ts","../src/json.ts","../src/filesystem/mono-repo.ts","../src/package-manager/download-and-extract.ts","../src/package-manager/get-package-manager.ts","../src/package-manager/get-package-manager-executable.ts","../src/terminal/should-print.ts","../src/terminal/ascii.ts","../src/logging/mask-tokens.ts","../src/terminal/cancel.ts","../src/terminal/execute-command.ts","../src/terminal/intro.ts","../src/terminal/note.ts","../src/terminal/list.ts","../src/terminal/outro.ts","../src/terminal/spinner.ts","../src/string.ts","../src/terminal/table.ts","../src/package-manager/install-dependencies.ts","../src/package-manager/is-package-installed.ts","../src/package-manager/set-name.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","import { readdir, rm } from \"node:fs/promises\";\nimport { resolve } from \"node:path\";\nimport { exists } from \"../filesystem.js\";\n\n/**\n * Formats a directory path by removing trailing slashes and whitespace\n *\n * @param targetDir - The directory path to format\n * @returns The formatted directory path\n * @example\n * import { formatTargetDir } from \"@settlemint/sdk-utils/package-manager\";\n *\n * const formatted = formatTargetDir(\"/path/to/dir/ \"); // \"/path/to/dir\"\n */\nexport function formatTargetDir(targetDir: string): string {\n return targetDir?.trim().replace(/\\/+$/g, \"\");\n}\n\n/**\n * Checks if a directory is empty or contains only a .git folder\n *\n * @param path - The directory path to check\n * @returns True if directory is empty or contains only .git, false otherwise\n * @example\n * import { isEmpty } from \"@settlemint/sdk-utils/package-manager\";\n *\n * if (await isEmpty(\"/path/to/dir\")) {\n * // Directory is empty\n * }\n */\nexport async function isEmpty(path: string): Promise<boolean> {\n const files = await readdir(path);\n return files.length === 0 || (files.length === 1 && files[0] === \".git\");\n}\n\n/**\n * Removes all contents of a directory except the .git folder\n *\n * @param dir - The directory path to empty\n * @example\n * import { emptyDir } from \"@settlemint/sdk-utils/package-manager\";\n *\n * await emptyDir(\"/path/to/dir\"); // Removes all contents except .git\n */\nexport async function emptyDir(dir: string): Promise<void> {\n if (!(await exists(dir))) return;\n for (const file of await readdir(dir)) {\n if (file === \".git\") continue;\n await rm(resolve(dir, file), { recursive: true, force: true });\n }\n}\n","import type { AgentName } from \"package-manager-detector\";\nimport { detect } from \"package-manager-detector/detect\";\n\n/**\n * Detects the package manager used in the current project\n *\n * @param targetDir - The directory to check for package manager (optional, defaults to process.cwd())\n * @returns The name of the package manager\n * @example\n * import { getPackageManager } from \"@settlemint/sdk-utils/package-manager\";\n *\n * const packageManager = await getPackageManager();\n * console.log(`Using ${packageManager}`);\n */\nexport async function getPackageManager(targetDir?: string): Promise<AgentName> {\n const packageManager = await detect({ cwd: targetDir || process.cwd() });\n\n return packageManager?.name ?? \"npm\";\n}\n","import { getPackageManager } from \"./get-package-manager.js\";\n\n/**\n * Retrieves the executable command and arguments for the package manager\n *\n * @param targetDir - The directory to check for package manager (optional, defaults to process.cwd())\n * @returns An object containing the command and arguments for the package manager\n * @example\n * import { getPackageManagerExecutable } from \"@settlemint/sdk-utils/package-manager\";\n *\n * const { command, args } = await getPackageManagerExecutable();\n * console.log(`Using ${command} with args: ${args.join(\" \")}`);\n */\nexport async function getPackageManagerExecutable(targetDir?: string): Promise<{ command: string; args: string[] }> {\n const packageManager = await getPackageManager(targetDir ?? process.cwd());\n\n switch (packageManager) {\n case \"pnpm\":\n return { command: \"pnpm\", args: [\"dlx\"] };\n case \"bun\":\n return { command: \"bunx\", args: [] };\n case \"yarn\":\n return { command: \"yarn\", args: [\"create\"] };\n }\n\n // Default to npm\n return { command: \"npx\", args: [] };\n}\n","/**\n * Returns true if the terminal should print, false otherwise.\n * @returns true if the terminal should print, false otherwise.\n */\nexport function shouldPrint() {\n return process.env.SETTLEMINT_DISABLE_TERMINAL !== \"true\";\n}\n","import { magentaBright } from \"yoctocolors\";\nimport { shouldPrint } from \"./should-print.js\";\n\n/**\n * Prints the SettleMint ASCII art logo to the console in magenta color.\n * Used for CLI branding and visual identification.\n *\n * @example\n * import { ascii } from \"@settlemint/sdk-utils/terminal\";\n *\n * // Prints the SettleMint logo\n * ascii();\n */\nexport const ascii = (): void => {\n if (!shouldPrint()) {\n return;\n }\n console.log(\n magentaBright(`\n _________ __ __ .__ _____ .__ __\n / _____/ _____/ |__/ |_| | ____ / \\\\ |__| _____/ |_\n \\\\_____ \\\\_/ __ \\\\ __\\\\ __\\\\ | _/ __ \\\\ / \\\\ / \\\\| |/ \\\\ __\\\\\n / \\\\ ___/| | | | | |_\\\\ ___// Y \\\\ | | \\\\ |\n/_________/\\\\_____>__| |__| |____/\\\\_____>____|____/__|___|__/__|\n`),\n );\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 \"@/logging/mask-tokens.js\";\nimport { inverse, redBright } from \"yoctocolors\";\n\n/**\n * Error class used to indicate that the operation was cancelled.\n * This error is used to signal that the operation should be aborted.\n */\nexport class CancelError extends Error {}\n\n/**\n * Displays an error message in red inverse text and throws a CancelError.\n * Used to terminate execution with a visible error message.\n * Any sensitive tokens in the message are masked before display.\n *\n * @param msg - The error message to display\n * @returns never - Function does not return as it throws an error\n * @example\n * import { cancel } from \"@settlemint/sdk-utils/terminal\";\n *\n * // Exits process with error message\n * cancel(\"An error occurred\");\n */\nexport const cancel = (msg: string): never => {\n console.log(\"\");\n console.log(inverse(redBright(maskTokens(msg))));\n console.log(\"\");\n throw new CancelError(msg);\n};\n","import { type SpawnOptionsWithoutStdio, spawn } from \"node:child_process\";\nimport { maskTokens } from \"../logging/mask-tokens.js\";\n\n/**\n * Options for executing a command, extending SpawnOptionsWithoutStdio\n */\nexport interface ExecuteCommandOptions extends SpawnOptionsWithoutStdio {\n /** Whether to suppress output to stdout/stderr */\n silent?: boolean;\n}\n\n/**\n * Error class for command execution errors\n * @extends Error\n */\nexport class CommandError extends Error {\n /**\n * Constructs a new CommandError\n * @param message - The error message\n * @param code - The exit code of the command\n * @param output - The output of the command\n */\n constructor(\n message: string,\n public readonly code: number,\n public readonly output: string[],\n ) {\n super(message);\n }\n}\n\n/**\n * Executes a command with the given arguments in a child process.\n * Pipes stdin to the child process and captures stdout/stderr output.\n * Masks any sensitive tokens in the output before displaying or returning.\n *\n * @param command - The command to execute\n * @param args - Array of arguments to pass to the command\n * @param options - Options for customizing command execution\n * @returns Array of output strings from stdout and stderr\n * @throws {CommandError} If the process fails to start or exits with non-zero code\n * @example\n * import { executeCommand } from \"@settlemint/sdk-utils/terminal\";\n *\n * // Execute git clone\n * await executeCommand(\"git\", [\"clone\", \"repo-url\"]);\n *\n * // Execute silently\n * await executeCommand(\"npm\", [\"install\"], { silent: true });\n */\nexport async function executeCommand(\n command: string,\n args: string[],\n options?: ExecuteCommandOptions,\n): Promise<string[]> {\n const { silent, ...spawnOptions } = options ?? {};\n const child = spawn(command, args, { ...spawnOptions, env: { ...process.env, ...options?.env } });\n process.stdin.pipe(child.stdin);\n const output: string[] = [];\n return new Promise((resolve, reject) => {\n child.stdout.on(\"data\", (data: Buffer | string) => {\n const maskedData = maskTokens(data.toString());\n if (!silent) {\n process.stdout.write(maskedData);\n }\n output.push(maskedData);\n });\n child.stderr.on(\"data\", (data: Buffer | string) => {\n const maskedData = maskTokens(data.toString());\n if (!silent) {\n process.stderr.write(maskedData);\n }\n output.push(maskedData);\n });\n child.on(\"error\", (err) => {\n process.stdin.unpipe(child.stdin);\n reject(new CommandError(err.message, \"code\" in err && typeof err.code === \"number\" ? err.code : 1, output));\n });\n child.on(\"close\", (code) => {\n process.stdin.unpipe(child.stdin);\n if (code === 0 || code === null || code === 143) {\n resolve(output);\n return;\n }\n reject(new CommandError(`Command \"${command}\" exited with code ${code}`, code, output));\n });\n });\n}\n","import { maskTokens } from \"@/logging/mask-tokens.js\";\nimport { magentaBright } from \"yoctocolors\";\nimport { shouldPrint } from \"./should-print.js\";\n\n/**\n * Displays an introductory message in magenta text with padding.\n * Any sensitive tokens in the message are masked before display.\n *\n * @param msg - The message to display as introduction\n * @example\n * import { intro } from \"@settlemint/sdk-utils/terminal\";\n *\n * // Display intro message\n * intro(\"Starting deployment...\");\n */\nexport const intro = (msg: string): void => {\n if (!shouldPrint()) {\n return;\n }\n console.log(\"\");\n console.log(magentaBright(maskTokens(msg)));\n console.log(\"\");\n};\n","import { maskTokens } from \"@/logging/mask-tokens.js\";\nimport { yellowBright } from \"yoctocolors\";\nimport { shouldPrint } from \"./should-print.js\";\n\n/**\n * Displays a note message with optional warning level formatting.\n * Regular notes are displayed in normal text, while warnings are shown in yellow.\n * Any sensitive tokens in the message are masked before display.\n *\n * @param message - The message to display as a note\n * @param level - The note level: \"info\" (default) or \"warn\" for warning styling\n * @example\n * import { note } from \"@settlemint/sdk-utils/terminal\";\n *\n * // Display info note\n * note(\"Operation completed successfully\");\n *\n * // Display warning note\n * note(\"Low disk space remaining\", \"warn\");\n */\nexport const note = (message: string, level: \"info\" | \"warn\" = \"info\"): void => {\n if (!shouldPrint()) {\n return;\n }\n const maskedMessage = maskTokens(message);\n\n console.log(\"\");\n if (level === \"warn\") {\n console.warn(yellowBright(maskedMessage));\n return;\n }\n\n console.log(maskedMessage);\n};\n","import { note } from \"./note.js\";\n\n/**\n * Displays a list of items in a formatted manner, supporting nested items.\n *\n * @param title - The title of the list\n * @param items - The items to display, can be strings or arrays for nested items\n * @returns The formatted list\n * @example\n * import { list } from \"@settlemint/sdk-utils/terminal\";\n *\n * // Simple list\n * list(\"Use cases\", [\"use case 1\", \"use case 2\", \"use case 3\"]);\n *\n * // Nested list\n * list(\"Providers\", [\n * \"AWS\",\n * [\"us-east-1\", \"eu-west-1\"],\n * \"Azure\",\n * [\"eastus\", \"westeurope\"]\n * ]);\n */\nexport function list(title: string, items: Array<string | string[]>) {\n const formatItems = (items: Array<string | string[]>): string => {\n return items\n .map((item) => {\n if (Array.isArray(item)) {\n return item.map((subItem) => ` • ${subItem}`).join(\"\\n\");\n }\n return ` • ${item}`;\n })\n .join(\"\\n\");\n };\n\n return note(`${title}:\\n\\n${formatItems(items)}`);\n}\n","import { maskTokens } from \"@/logging/mask-tokens.js\";\nimport { shouldPrint } from \"@/terminal/should-print.js\";\nimport { greenBright, inverse } from \"yoctocolors\";\n\n/**\n * Displays a closing message in green inverted text with padding.\n * Any sensitive tokens in the message are masked before display.\n *\n * @param msg - The message to display as conclusion\n * @example\n * import { outro } from \"@settlemint/sdk-utils/terminal\";\n *\n * // Display outro message\n * outro(\"Deployment completed successfully!\");\n */\nexport const outro = (msg: string): void => {\n if (!shouldPrint()) {\n return;\n }\n console.log(\"\");\n console.log(inverse(greenBright(maskTokens(msg))));\n console.log(\"\");\n};\n","import isInCi from \"is-in-ci\";\nimport yoctoSpinner, { type Spinner } from \"yocto-spinner\";\nimport { redBright } from \"yoctocolors\";\nimport { maskTokens } from \"../logging/mask-tokens.js\";\nimport { note } from \"./note.js\";\nimport { shouldPrint } from \"./should-print.js\";\n\n/**\n * Error class used to indicate that the spinner operation failed.\n * This error is used to signal that the operation should be aborted.\n */\nexport class SpinnerError extends Error {\n constructor(\n message: string,\n public readonly originalError: Error,\n ) {\n super(message);\n this.name = \"SpinnerError\";\n }\n}\n\n/**\n * Options for configuring the spinner behavior\n */\nexport interface SpinnerOptions<R> {\n /** Message to display when spinner starts */\n startMessage: string;\n /** Async task to execute while spinner is active */\n task: (spinner?: Spinner) => Promise<R>;\n /** Message to display when spinner completes successfully */\n stopMessage: string;\n}\n\n/**\n * Displays a loading spinner while executing an async task.\n * Shows progress with start/stop messages and handles errors.\n * Spinner is disabled in CI environments.\n *\n * @param options - Configuration options for the spinner\n * @returns The result from the executed task\n * @throws Will exit process with code 1 if task fails\n * @example\n * import { spinner } from \"@settlemint/sdk-utils/terminal\";\n *\n * // Show spinner during async task\n * const result = await spinner({\n * startMessage: \"Deploying...\",\n * task: async () => {\n * // Async work here\n * return \"success\";\n * },\n * stopMessage: \"Deployed successfully!\"\n * });\n */\nexport const spinner = async <R>(options: SpinnerOptions<R>): Promise<R> => {\n const handleError = (error: Error) => {\n const errorMessage = maskTokens(error.message);\n note(redBright(`${errorMessage}\\n\\n${error.stack}`));\n throw new SpinnerError(errorMessage, error);\n };\n if (isInCi || !shouldPrint()) {\n try {\n return await options.task();\n } catch (err) {\n return handleError(err as Error);\n }\n }\n const spinner = yoctoSpinner({ stream: process.stdout }).start(options.startMessage);\n try {\n const result = await options.task(spinner);\n spinner.success(options.stopMessage);\n // Ensure spinner success message renders before proceeding to avoid\n // terminal output overlap issues with subsequent messages\n await new Promise((resolve) => process.nextTick(resolve));\n return result;\n } catch (err) {\n spinner.error(redBright(`${options.startMessage} --> Error!`));\n return handleError(err as Error);\n }\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","import { Table } from \"console-table-printer\";\nimport { whiteBright } from \"yoctocolors\";\nimport { camelCaseToWords } from \"@/string.js\";\nimport { note } from \"./note.js\";\nimport { shouldPrint } from \"./should-print.js\";\n/**\n * Displays data in a formatted table in the terminal.\n *\n * @param title - Title to display above the table\n * @param data - Array of objects to display in table format\n * @example\n * import { table } from \"@settlemint/sdk-utils/terminal\";\n *\n * const data = [\n * { name: \"Item 1\", value: 100 },\n * { name: \"Item 2\", value: 200 }\n * ];\n *\n * table(\"My Table\", data);\n */\nexport function table(title: string, data: unknown[]): void {\n if (!shouldPrint()) {\n return;\n }\n\n note(title);\n\n if (!data || data.length === 0) {\n note(\"No data to display\");\n return;\n }\n\n const columnKeys = Object.keys(data[0] as Record<string, unknown>);\n const table = new Table({\n columns: columnKeys.map((key) => ({\n name: key,\n title: whiteBright(camelCaseToWords(key)),\n alignment: \"left\",\n })),\n });\n // biome-ignore lint/suspicious/noExplicitAny: Data structure varies based on table content\n table.addRows(data as Array<Record<string, any>>);\n table.printTable();\n}\n","import { installPackage } from \"@antfu/install-pkg\";\nimport { note } from \"../terminal.js\";\n\n/**\n * Installs one or more packages as dependencies using the detected package manager\n *\n * @param pkgs - A single package name or array of package names to install\n * @param cwd - The directory to run the installation in\n * @returns A promise that resolves when installation is complete\n * @throws If package installation fails\n * @example\n * import { installDependencies } from \"@settlemint/sdk-utils/package-manager\";\n *\n * // Install a single package\n * await installDependencies(\"express\");\n *\n * // Install multiple packages\n * await installDependencies([\"express\", \"cors\"]);\n */\nexport async function installDependencies(pkgs: string | string[], cwd?: string) {\n try {\n await installPackage(pkgs, { silent: true, additionalArgs: [\"--exact\"], cwd });\n } catch (err) {\n const error = err instanceof Error ? err.message : \"Unknown error\";\n note(\n `Failed to install ${Array.isArray(pkgs) ? `dependencies '${pkgs.join(\", \")}'` : `dependency '${pkgs}'`}: ${error}`,\n \"warn\",\n );\n }\n}\n","import { projectRoot } from \"@/filesystem/project-root.js\";\nimport pkgjs from \"@npmcli/package-json\";\n\n/**\n * Checks if a package is installed in the project's dependencies, devDependencies, or peerDependencies.\n *\n * @param name - The name of the package to check\n * @param path - The path to the project root directory. If not provided, will be automatically determined\n * @returns Whether the package is installed\n * @throws If unable to read or parse the package.json file\n * @example\n * import { isPackageInstalled } from \"@settlemint/sdk-utils/package-manager\";\n *\n * const isInstalled = await isPackageInstalled(\"@settlemint/sdk-utils\");\n * console.log(`@settlemint/sdk-utils is installed: ${isInstalled}`);\n */\nexport async function isPackageInstalled(name: string, path?: string) {\n // Read the package.json file\n const pkgJson = await pkgjs.load(path ?? (await projectRoot()));\n\n const inDependencies = !!pkgJson.content.dependencies?.[name];\n const inDevDependencies = !!pkgJson.content.devDependencies?.[name];\n const inPeerDependencies = !!pkgJson.content.peerDependencies?.[name];\n\n return inDependencies || inDevDependencies || inPeerDependencies;\n}\n","import { projectRoot } from \"@/filesystem/project-root.js\";\nimport pkgjs from \"@npmcli/package-json\";\n\n/**\n * Sets the name field in the package.json file\n *\n * @param name - The new name to set in the package.json file\n * @param path - The path to the project root directory. If not provided, will be automatically determined\n * @returns A promise that resolves when the package.json has been updated\n * @throws If unable to read, update or save the package.json file\n * @example\n * import { setName } from \"@settlemint/sdk-utils/package-manager\";\n *\n * await setName(\"my-new-project-name\");\n */\nexport async function setName(name: string, path?: string) {\n // Read the package.json file\n const pkgJson = await pkgjs.load(path ?? (await projectRoot()));\n\n pkgJson.update({\n name,\n });\n\n await pkgJson.save();\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"package-manager.js","names":["value","code: number","output: string[]","items","originalError: Error","spinner","resolve","table"],"sources":["../src/filesystem/project-root.ts","../src/filesystem/exists.ts","../src/json.ts","../src/filesystem/mono-repo.ts","../src/package-manager/download-and-extract.ts","../src/package-manager/get-package-manager.ts","../src/package-manager/get-package-manager-executable.ts","../src/terminal/should-print.ts","../src/terminal/ascii.ts","../src/logging/mask-tokens.ts","../src/terminal/cancel.ts","../src/terminal/execute-command.ts","../src/terminal/intro.ts","../src/terminal/note.ts","../src/terminal/list.ts","../src/terminal/outro.ts","../src/terminal/spinner.ts","../src/string.ts","../src/terminal/table.ts","../src/package-manager/install-dependencies.ts","../src/package-manager/is-package-installed.ts","../src/package-manager/set-name.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","import { readdir, rm } from \"node:fs/promises\";\nimport { resolve } from \"node:path\";\nimport { exists } from \"../filesystem.js\";\n\n/**\n * Formats a directory path by removing trailing slashes and whitespace\n *\n * @param targetDir - The directory path to format\n * @returns The formatted directory path\n * @example\n * import { formatTargetDir } from \"@settlemint/sdk-utils/package-manager\";\n *\n * const formatted = formatTargetDir(\"/path/to/dir/ \"); // \"/path/to/dir\"\n */\nexport function formatTargetDir(targetDir: string): string {\n return targetDir?.trim().replace(/\\/+$/g, \"\");\n}\n\n/**\n * Checks if a directory is empty or contains only a .git folder\n *\n * @param path - The directory path to check\n * @returns True if directory is empty or contains only .git, false otherwise\n * @example\n * import { isEmpty } from \"@settlemint/sdk-utils/package-manager\";\n *\n * if (await isEmpty(\"/path/to/dir\")) {\n * // Directory is empty\n * }\n */\nexport async function isEmpty(path: string): Promise<boolean> {\n const files = await readdir(path);\n return files.length === 0 || (files.length === 1 && files[0] === \".git\");\n}\n\n/**\n * Removes all contents of a directory except the .git folder\n *\n * @param dir - The directory path to empty\n * @example\n * import { emptyDir } from \"@settlemint/sdk-utils/package-manager\";\n *\n * await emptyDir(\"/path/to/dir\"); // Removes all contents except .git\n */\nexport async function emptyDir(dir: string): Promise<void> {\n if (!(await exists(dir))) return;\n for (const file of await readdir(dir)) {\n if (file === \".git\") continue;\n await rm(resolve(dir, file), { recursive: true, force: true });\n }\n}\n","import type { AgentName } from \"package-manager-detector\";\nimport { detect } from \"package-manager-detector/detect\";\n\n/**\n * Detects the package manager used in the current project\n *\n * @param targetDir - The directory to check for package manager (optional, defaults to process.cwd())\n * @returns The name of the package manager\n * @example\n * import { getPackageManager } from \"@settlemint/sdk-utils/package-manager\";\n *\n * const packageManager = await getPackageManager();\n * console.log(`Using ${packageManager}`);\n */\nexport async function getPackageManager(targetDir?: string): Promise<AgentName> {\n const packageManager = await detect({ cwd: targetDir || process.cwd() });\n\n return packageManager?.name ?? \"npm\";\n}\n","import { getPackageManager } from \"./get-package-manager.js\";\n\n/**\n * Retrieves the executable command and arguments for the package manager\n *\n * @param targetDir - The directory to check for package manager (optional, defaults to process.cwd())\n * @returns An object containing the command and arguments for the package manager\n * @example\n * import { getPackageManagerExecutable } from \"@settlemint/sdk-utils/package-manager\";\n *\n * const { command, args } = await getPackageManagerExecutable();\n * console.log(`Using ${command} with args: ${args.join(\" \")}`);\n */\nexport async function getPackageManagerExecutable(targetDir?: string): Promise<{ command: string; args: string[] }> {\n const packageManager = await getPackageManager(targetDir ?? process.cwd());\n\n switch (packageManager) {\n case \"pnpm\":\n return { command: \"pnpm\", args: [\"dlx\"] };\n case \"bun\":\n return { command: \"bunx\", args: [] };\n case \"yarn\":\n return { command: \"yarn\", args: [\"create\"] };\n }\n\n // Default to npm\n return { command: \"npx\", args: [] };\n}\n","/**\n * Returns true if the terminal should print, false otherwise.\n * @returns true if the terminal should print, false otherwise.\n */\nexport function shouldPrint() {\n return process.env.SETTLEMINT_DISABLE_TERMINAL !== \"true\";\n}\n","import { magentaBright } from \"yoctocolors\";\nimport { shouldPrint } from \"./should-print.js\";\n\n/**\n * Prints the SettleMint ASCII art logo to the console in magenta color.\n * Used for CLI branding and visual identification.\n *\n * @example\n * import { ascii } from \"@settlemint/sdk-utils/terminal\";\n *\n * // Prints the SettleMint logo\n * ascii();\n */\nexport const ascii = (): void => {\n if (!shouldPrint()) {\n return;\n }\n console.log(\n magentaBright(`\n _________ __ __ .__ _____ .__ __\n / _____/ _____/ |__/ |_| | ____ / \\\\ |__| _____/ |_\n \\\\_____ \\\\_/ __ \\\\ __\\\\ __\\\\ | _/ __ \\\\ / \\\\ / \\\\| |/ \\\\ __\\\\\n / \\\\ ___/| | | | | |_\\\\ ___// Y \\\\ | | \\\\ |\n/_________/\\\\_____>__| |__| |____/\\\\_____>____|____/__|___|__/__|\n`),\n );\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 \"@/logging/mask-tokens.js\";\nimport { inverse, redBright } from \"yoctocolors\";\n\n/**\n * Error class used to indicate that the operation was cancelled.\n * This error is used to signal that the operation should be aborted.\n */\nexport class CancelError extends Error {}\n\n/**\n * Displays an error message in red inverse text and throws a CancelError.\n * Used to terminate execution with a visible error message.\n * Any sensitive tokens in the message are masked before display.\n *\n * @param msg - The error message to display\n * @returns never - Function does not return as it throws an error\n * @example\n * import { cancel } from \"@settlemint/sdk-utils/terminal\";\n *\n * // Exits process with error message\n * cancel(\"An error occurred\");\n */\nexport const cancel = (msg: string): never => {\n console.log(\"\");\n console.log(inverse(redBright(maskTokens(msg))));\n console.log(\"\");\n throw new CancelError(msg);\n};\n","import { type SpawnOptionsWithoutStdio, spawn } from \"node:child_process\";\nimport { maskTokens } from \"../logging/mask-tokens.js\";\n\n/**\n * Options for executing a command, extending SpawnOptionsWithoutStdio\n */\nexport interface ExecuteCommandOptions extends SpawnOptionsWithoutStdio {\n /** Whether to suppress output to stdout/stderr */\n silent?: boolean;\n}\n\n/**\n * Error class for command execution errors\n * @extends Error\n */\nexport class CommandError extends Error {\n /**\n * Constructs a new CommandError\n * @param message - The error message\n * @param code - The exit code of the command\n * @param output - The output of the command\n */\n constructor(\n message: string,\n public readonly code: number,\n public readonly output: string[],\n ) {\n super(message);\n }\n}\n\n/**\n * Executes a command with the given arguments in a child process.\n * Pipes stdin to the child process and captures stdout/stderr output.\n * Masks any sensitive tokens in the output before displaying or returning.\n *\n * @param command - The command to execute\n * @param args - Array of arguments to pass to the command\n * @param options - Options for customizing command execution\n * @returns Array of output strings from stdout and stderr\n * @throws {CommandError} If the process fails to start or exits with non-zero code\n * @example\n * import { executeCommand } from \"@settlemint/sdk-utils/terminal\";\n *\n * // Execute git clone\n * await executeCommand(\"git\", [\"clone\", \"repo-url\"]);\n *\n * // Execute silently\n * await executeCommand(\"npm\", [\"install\"], { silent: true });\n */\nexport async function executeCommand(\n command: string,\n args: string[],\n options?: ExecuteCommandOptions,\n): Promise<string[]> {\n const { silent, ...spawnOptions } = options ?? {};\n const child = spawn(command, args, { ...spawnOptions, env: { ...process.env, ...options?.env } });\n process.stdin.pipe(child.stdin);\n const output: string[] = [];\n return new Promise((resolve, reject) => {\n child.stdout.on(\"data\", (data: Buffer | string) => {\n const maskedData = maskTokens(data.toString());\n if (!silent) {\n process.stdout.write(maskedData);\n }\n output.push(maskedData);\n });\n child.stderr.on(\"data\", (data: Buffer | string) => {\n const maskedData = maskTokens(data.toString());\n if (!silent) {\n process.stderr.write(maskedData);\n }\n output.push(maskedData);\n });\n child.on(\"error\", (err) => {\n process.stdin.unpipe(child.stdin);\n reject(new CommandError(err.message, \"code\" in err && typeof err.code === \"number\" ? err.code : 1, output));\n });\n child.on(\"close\", (code) => {\n process.stdin.unpipe(child.stdin);\n if (code === 0 || code === null || code === 143) {\n resolve(output);\n return;\n }\n reject(new CommandError(`Command \"${command}\" exited with code ${code}`, code, output));\n });\n });\n}\n","import { maskTokens } from \"@/logging/mask-tokens.js\";\nimport { magentaBright } from \"yoctocolors\";\nimport { shouldPrint } from \"./should-print.js\";\n\n/**\n * Displays an introductory message in magenta text with padding.\n * Any sensitive tokens in the message are masked before display.\n *\n * @param msg - The message to display as introduction\n * @example\n * import { intro } from \"@settlemint/sdk-utils/terminal\";\n *\n * // Display intro message\n * intro(\"Starting deployment...\");\n */\nexport const intro = (msg: string): void => {\n if (!shouldPrint()) {\n return;\n }\n console.log(\"\");\n console.log(magentaBright(maskTokens(msg)));\n console.log(\"\");\n};\n","import { maskTokens } from \"@/logging/mask-tokens.js\";\nimport { yellowBright } from \"yoctocolors\";\nimport { shouldPrint } from \"./should-print.js\";\n\n/**\n * Displays a note message with optional warning level formatting.\n * Regular notes are displayed in normal text, while warnings are shown in yellow.\n * Any sensitive tokens in the message are masked before display.\n *\n * @param message - The message to display as a note\n * @param level - The note level: \"info\" (default) or \"warn\" for warning styling\n * @example\n * import { note } from \"@settlemint/sdk-utils/terminal\";\n *\n * // Display info note\n * note(\"Operation completed successfully\");\n *\n * // Display warning note\n * note(\"Low disk space remaining\", \"warn\");\n */\nexport const note = (message: string, level: \"info\" | \"warn\" = \"info\"): void => {\n if (!shouldPrint()) {\n return;\n }\n const maskedMessage = maskTokens(message);\n\n console.log(\"\");\n if (level === \"warn\") {\n console.warn(yellowBright(maskedMessage));\n return;\n }\n\n console.log(maskedMessage);\n};\n","import { note } from \"./note.js\";\n\n/**\n * Displays a list of items in a formatted manner, supporting nested items.\n *\n * @param title - The title of the list\n * @param items - The items to display, can be strings or arrays for nested items\n * @returns The formatted list\n * @example\n * import { list } from \"@settlemint/sdk-utils/terminal\";\n *\n * // Simple list\n * list(\"Use cases\", [\"use case 1\", \"use case 2\", \"use case 3\"]);\n *\n * // Nested list\n * list(\"Providers\", [\n * \"AWS\",\n * [\"us-east-1\", \"eu-west-1\"],\n * \"Azure\",\n * [\"eastus\", \"westeurope\"]\n * ]);\n */\nexport function list(title: string, items: Array<string | string[]>) {\n const formatItems = (items: Array<string | string[]>): string => {\n return items\n .map((item) => {\n if (Array.isArray(item)) {\n return item.map((subItem) => ` • ${subItem}`).join(\"\\n\");\n }\n return ` • ${item}`;\n })\n .join(\"\\n\");\n };\n\n return note(`${title}:\\n\\n${formatItems(items)}`);\n}\n","import { maskTokens } from \"@/logging/mask-tokens.js\";\nimport { shouldPrint } from \"@/terminal/should-print.js\";\nimport { greenBright, inverse } from \"yoctocolors\";\n\n/**\n * Displays a closing message in green inverted text with padding.\n * Any sensitive tokens in the message are masked before display.\n *\n * @param msg - The message to display as conclusion\n * @example\n * import { outro } from \"@settlemint/sdk-utils/terminal\";\n *\n * // Display outro message\n * outro(\"Deployment completed successfully!\");\n */\nexport const outro = (msg: string): void => {\n if (!shouldPrint()) {\n return;\n }\n console.log(\"\");\n console.log(inverse(greenBright(maskTokens(msg))));\n console.log(\"\");\n};\n","import isInCi from \"is-in-ci\";\nimport yoctoSpinner, { type Spinner } from \"yocto-spinner\";\nimport { redBright } from \"yoctocolors\";\nimport { maskTokens } from \"../logging/mask-tokens.js\";\nimport { note } from \"./note.js\";\nimport { shouldPrint } from \"./should-print.js\";\n\n/**\n * Error class used to indicate that the spinner operation failed.\n * This error is used to signal that the operation should be aborted.\n */\nexport class SpinnerError extends Error {\n constructor(\n message: string,\n public readonly originalError: Error,\n ) {\n super(message);\n this.name = \"SpinnerError\";\n }\n}\n\n/**\n * Options for configuring the spinner behavior\n */\nexport interface SpinnerOptions<R> {\n /** Message to display when spinner starts */\n startMessage: string;\n /** Async task to execute while spinner is active */\n task: (spinner?: Spinner) => Promise<R>;\n /** Message to display when spinner completes successfully */\n stopMessage: string;\n}\n\n/**\n * Displays a loading spinner while executing an async task.\n * Shows progress with start/stop messages and handles errors.\n * Spinner is disabled in CI environments.\n *\n * @param options - Configuration options for the spinner\n * @returns The result from the executed task\n * @throws Will exit process with code 1 if task fails\n * @example\n * import { spinner } from \"@settlemint/sdk-utils/terminal\";\n *\n * // Show spinner during async task\n * const result = await spinner({\n * startMessage: \"Deploying...\",\n * task: async () => {\n * // Async work here\n * return \"success\";\n * },\n * stopMessage: \"Deployed successfully!\"\n * });\n */\nexport const spinner = async <R>(options: SpinnerOptions<R>): Promise<R> => {\n const handleError = (error: Error) => {\n const errorMessage = maskTokens(error.message);\n note(redBright(`${errorMessage}\\n\\n${error.stack}`));\n throw new SpinnerError(errorMessage, error);\n };\n if (isInCi || !shouldPrint()) {\n try {\n return await options.task();\n } catch (err) {\n return handleError(err as Error);\n }\n }\n const spinner = yoctoSpinner({ stream: process.stdout }).start(options.startMessage);\n try {\n const result = await options.task(spinner);\n spinner.success(options.stopMessage);\n // Ensure spinner success message renders before proceeding to avoid\n // terminal output overlap issues with subsequent messages\n await new Promise((resolve) => process.nextTick(resolve));\n return result;\n } catch (err) {\n spinner.error(redBright(`${options.startMessage} --> Error!`));\n return handleError(err as Error);\n }\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","import { Table } from \"console-table-printer\";\nimport { whiteBright } from \"yoctocolors\";\nimport { camelCaseToWords } from \"@/string.js\";\nimport { note } from \"./note.js\";\nimport { shouldPrint } from \"./should-print.js\";\n/**\n * Displays data in a formatted table in the terminal.\n *\n * @param title - Title to display above the table\n * @param data - Array of objects to display in table format\n * @example\n * import { table } from \"@settlemint/sdk-utils/terminal\";\n *\n * const data = [\n * { name: \"Item 1\", value: 100 },\n * { name: \"Item 2\", value: 200 }\n * ];\n *\n * table(\"My Table\", data);\n */\nexport function table(title: string, data: unknown[]): void {\n if (!shouldPrint()) {\n return;\n }\n\n note(title);\n\n if (!data || data.length === 0) {\n note(\"No data to display\");\n return;\n }\n\n const columnKeys = Object.keys(data[0] as Record<string, unknown>);\n const table = new Table({\n columns: columnKeys.map((key) => ({\n name: key,\n title: whiteBright(camelCaseToWords(key)),\n alignment: \"left\",\n })),\n });\n // biome-ignore lint/suspicious/noExplicitAny: Data structure varies based on table content\n table.addRows(data as Array<Record<string, any>>);\n table.printTable();\n}\n","import { installPackage } from \"@antfu/install-pkg\";\nimport { note } from \"../terminal.js\";\n\n/**\n * Installs one or more packages as dependencies using the detected package manager\n *\n * @param pkgs - A single package name or array of package names to install\n * @param cwd - The directory to run the installation in\n * @returns A promise that resolves when installation is complete\n * @throws If package installation fails\n * @example\n * import { installDependencies } from \"@settlemint/sdk-utils/package-manager\";\n *\n * // Install a single package\n * await installDependencies(\"express\");\n *\n * // Install multiple packages\n * await installDependencies([\"express\", \"cors\"]);\n */\nexport async function installDependencies(pkgs: string | string[], cwd?: string) {\n try {\n await installPackage(pkgs, { silent: true, additionalArgs: [\"--exact\"], cwd });\n } catch (err) {\n const error = err instanceof Error ? err.message : \"Unknown error\";\n note(\n `Failed to install ${Array.isArray(pkgs) ? `dependencies '${pkgs.join(\", \")}'` : `dependency '${pkgs}'`}: ${error}`,\n \"warn\",\n );\n }\n}\n","import { projectRoot } from \"@/filesystem/project-root.js\";\nimport pkgjs from \"@npmcli/package-json\";\n\n/**\n * Checks if a package is installed in the project's dependencies, devDependencies, or peerDependencies.\n *\n * @param name - The name of the package to check\n * @param path - The path to the project root directory. If not provided, will be automatically determined\n * @returns Whether the package is installed\n * @throws If unable to read or parse the package.json file\n * @example\n * import { isPackageInstalled } from \"@settlemint/sdk-utils/package-manager\";\n *\n * const isInstalled = await isPackageInstalled(\"@settlemint/sdk-utils\");\n * console.log(`@settlemint/sdk-utils is installed: ${isInstalled}`);\n */\nexport async function isPackageInstalled(name: string, path?: string) {\n // Read the package.json file\n const pkgJson = await pkgjs.load(path ?? (await projectRoot()));\n\n const inDependencies = !!pkgJson.content.dependencies?.[name];\n const inDevDependencies = !!pkgJson.content.devDependencies?.[name];\n const inPeerDependencies = !!pkgJson.content.peerDependencies?.[name];\n\n return inDependencies || inDevDependencies || inPeerDependencies;\n}\n","import { projectRoot } from \"@/filesystem/project-root.js\";\nimport pkgjs from \"@npmcli/package-json\";\n\n/**\n * Sets the name field in the package.json file\n *\n * @param name - The new name to set in the package.json file\n * @param path - The path to the project root directory. If not provided, will be automatically determined\n * @returns A promise that resolves when the package.json has been updated\n * @throws If unable to read, update or save the package.json file\n * @example\n * import { setName } from \"@settlemint/sdk-utils/package-manager\";\n *\n * await setName(\"my-new-project-name\");\n */\nexport async function setName(name: string, path?: string) {\n // Read the package.json file\n const pkgJson = await pkgjs.load(path ?? (await projectRoot()));\n\n pkgJson.update({\n name,\n });\n\n await pkgJson.save();\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"package-manager.js","names":["value","code: number","output: string[]","items","originalError: Error","spinner","resolve","table"],"sources":["../src/filesystem/project-root.ts","../src/filesystem/exists.ts","../src/json.ts","../src/filesystem/mono-repo.ts","../src/package-manager/download-and-extract.ts","../src/package-manager/get-package-manager.ts","../src/package-manager/get-package-manager-executable.ts","../src/terminal/should-print.ts","../src/terminal/ascii.ts","../src/logging/mask-tokens.ts","../src/terminal/cancel.ts","../src/terminal/execute-command.ts","../src/terminal/intro.ts","../src/terminal/note.ts","../src/terminal/list.ts","../src/terminal/outro.ts","../src/terminal/spinner.ts","../src/string.ts","../src/terminal/table.ts","../src/package-manager/install-dependencies.ts","../src/package-manager/is-package-installed.ts","../src/package-manager/set-name.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","import { readdir, rm } from \"node:fs/promises\";\nimport { resolve } from \"node:path\";\nimport { exists } from \"../filesystem.js\";\n\n/**\n * Formats a directory path by removing trailing slashes and whitespace\n *\n * @param targetDir - The directory path to format\n * @returns The formatted directory path\n * @example\n * import { formatTargetDir } from \"@settlemint/sdk-utils/package-manager\";\n *\n * const formatted = formatTargetDir(\"/path/to/dir/ \"); // \"/path/to/dir\"\n */\nexport function formatTargetDir(targetDir: string): string {\n return targetDir?.trim().replace(/\\/+$/g, \"\");\n}\n\n/**\n * Checks if a directory is empty or contains only a .git folder\n *\n * @param path - The directory path to check\n * @returns True if directory is empty or contains only .git, false otherwise\n * @example\n * import { isEmpty } from \"@settlemint/sdk-utils/package-manager\";\n *\n * if (await isEmpty(\"/path/to/dir\")) {\n * // Directory is empty\n * }\n */\nexport async function isEmpty(path: string): Promise<boolean> {\n const files = await readdir(path);\n return files.length === 0 || (files.length === 1 && files[0] === \".git\");\n}\n\n/**\n * Removes all contents of a directory except the .git folder\n *\n * @param dir - The directory path to empty\n * @example\n * import { emptyDir } from \"@settlemint/sdk-utils/package-manager\";\n *\n * await emptyDir(\"/path/to/dir\"); // Removes all contents except .git\n */\nexport async function emptyDir(dir: string): Promise<void> {\n if (!(await exists(dir))) return;\n for (const file of await readdir(dir)) {\n if (file === \".git\") continue;\n await rm(resolve(dir, file), { recursive: true, force: true });\n }\n}\n","import type { AgentName } from \"package-manager-detector\";\nimport { detect } from \"package-manager-detector/detect\";\n\n/**\n * Detects the package manager used in the current project\n *\n * @param targetDir - The directory to check for package manager (optional, defaults to process.cwd())\n * @returns The name of the package manager\n * @example\n * import { getPackageManager } from \"@settlemint/sdk-utils/package-manager\";\n *\n * const packageManager = await getPackageManager();\n * console.log(`Using ${packageManager}`);\n */\nexport async function getPackageManager(targetDir?: string): Promise<AgentName> {\n const packageManager = await detect({ cwd: targetDir || process.cwd() });\n\n return packageManager?.name ?? \"npm\";\n}\n","import { getPackageManager } from \"./get-package-manager.js\";\n\n/**\n * Retrieves the executable command and arguments for the package manager\n *\n * @param targetDir - The directory to check for package manager (optional, defaults to process.cwd())\n * @returns An object containing the command and arguments for the package manager\n * @example\n * import { getPackageManagerExecutable } from \"@settlemint/sdk-utils/package-manager\";\n *\n * const { command, args } = await getPackageManagerExecutable();\n * console.log(`Using ${command} with args: ${args.join(\" \")}`);\n */\nexport async function getPackageManagerExecutable(targetDir?: string): Promise<{ command: string; args: string[] }> {\n const packageManager = await getPackageManager(targetDir ?? process.cwd());\n\n switch (packageManager) {\n case \"pnpm\":\n return { command: \"pnpm\", args: [\"dlx\"] };\n case \"bun\":\n return { command: \"bunx\", args: [] };\n case \"yarn\":\n return { command: \"yarn\", args: [\"create\"] };\n }\n\n // Default to npm\n return { command: \"npx\", args: [] };\n}\n","/**\n * Returns true if the terminal should print, false otherwise.\n * @returns true if the terminal should print, false otherwise.\n */\nexport function shouldPrint() {\n return process.env.SETTLEMINT_DISABLE_TERMINAL !== \"true\";\n}\n","import { magentaBright } from \"yoctocolors\";\nimport { shouldPrint } from \"./should-print.js\";\n\n/**\n * Prints the SettleMint ASCII art logo to the console in magenta color.\n * Used for CLI branding and visual identification.\n *\n * @example\n * import { ascii } from \"@settlemint/sdk-utils/terminal\";\n *\n * // Prints the SettleMint logo\n * ascii();\n */\nexport const ascii = (): void => {\n if (!shouldPrint()) {\n return;\n }\n console.log(\n magentaBright(`\n _________ __ __ .__ _____ .__ __\n / _____/ _____/ |__/ |_| | ____ / \\\\ |__| _____/ |_\n \\\\_____ \\\\_/ __ \\\\ __\\\\ __\\\\ | _/ __ \\\\ / \\\\ / \\\\| |/ \\\\ __\\\\\n / \\\\ ___/| | | | | |_\\\\ ___// Y \\\\ | | \\\\ |\n/_________/\\\\_____>__| |__| |____/\\\\_____>____|____/__|___|__/__|\n`),\n );\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 \"@/logging/mask-tokens.js\";\nimport { inverse, redBright } from \"yoctocolors\";\n\n/**\n * Error class used to indicate that the operation was cancelled.\n * This error is used to signal that the operation should be aborted.\n */\nexport class CancelError extends Error {}\n\n/**\n * Displays an error message in red inverse text and throws a CancelError.\n * Used to terminate execution with a visible error message.\n * Any sensitive tokens in the message are masked before display.\n *\n * @param msg - The error message to display\n * @returns never - Function does not return as it throws an error\n * @example\n * import { cancel } from \"@settlemint/sdk-utils/terminal\";\n *\n * // Exits process with error message\n * cancel(\"An error occurred\");\n */\nexport const cancel = (msg: string): never => {\n console.log(\"\");\n console.log(inverse(redBright(maskTokens(msg))));\n console.log(\"\");\n throw new CancelError(msg);\n};\n","import { type SpawnOptionsWithoutStdio, spawn } from \"node:child_process\";\nimport { maskTokens } from \"../logging/mask-tokens.js\";\n\n/**\n * Options for executing a command, extending SpawnOptionsWithoutStdio\n */\nexport interface ExecuteCommandOptions extends SpawnOptionsWithoutStdio {\n /** Whether to suppress output to stdout/stderr */\n silent?: boolean;\n}\n\n/**\n * Error class for command execution errors\n * @extends Error\n */\nexport class CommandError extends Error {\n /**\n * Constructs a new CommandError\n * @param message - The error message\n * @param code - The exit code of the command\n * @param output - The output of the command\n */\n constructor(\n message: string,\n public readonly code: number,\n public readonly output: string[],\n ) {\n super(message);\n }\n}\n\n/**\n * Executes a command with the given arguments in a child process.\n * Pipes stdin to the child process and captures stdout/stderr output.\n * Masks any sensitive tokens in the output before displaying or returning.\n *\n * @param command - The command to execute\n * @param args - Array of arguments to pass to the command\n * @param options - Options for customizing command execution\n * @returns Array of output strings from stdout and stderr\n * @throws {CommandError} If the process fails to start or exits with non-zero code\n * @example\n * import { executeCommand } from \"@settlemint/sdk-utils/terminal\";\n *\n * // Execute git clone\n * await executeCommand(\"git\", [\"clone\", \"repo-url\"]);\n *\n * // Execute silently\n * await executeCommand(\"npm\", [\"install\"], { silent: true });\n */\nexport async function executeCommand(\n command: string,\n args: string[],\n options?: ExecuteCommandOptions,\n): Promise<string[]> {\n const { silent, ...spawnOptions } = options ?? {};\n const child = spawn(command, args, { ...spawnOptions, env: { ...process.env, ...options?.env } });\n process.stdin.pipe(child.stdin);\n const output: string[] = [];\n return new Promise((resolve, reject) => {\n child.stdout.on(\"data\", (data: Buffer | string) => {\n const maskedData = maskTokens(data.toString());\n if (!silent) {\n process.stdout.write(maskedData);\n }\n output.push(maskedData);\n });\n child.stderr.on(\"data\", (data: Buffer | string) => {\n const maskedData = maskTokens(data.toString());\n if (!silent) {\n process.stderr.write(maskedData);\n }\n output.push(maskedData);\n });\n child.on(\"error\", (err) => {\n process.stdin.unpipe(child.stdin);\n reject(new CommandError(err.message, \"code\" in err && typeof err.code === \"number\" ? err.code : 1, output));\n });\n child.on(\"close\", (code) => {\n process.stdin.unpipe(child.stdin);\n if (code === 0 || code === null || code === 143) {\n resolve(output);\n return;\n }\n reject(new CommandError(`Command \"${command}\" exited with code ${code}`, code, output));\n });\n });\n}\n","import { maskTokens } from \"@/logging/mask-tokens.js\";\nimport { magentaBright } from \"yoctocolors\";\nimport { shouldPrint } from \"./should-print.js\";\n\n/**\n * Displays an introductory message in magenta text with padding.\n * Any sensitive tokens in the message are masked before display.\n *\n * @param msg - The message to display as introduction\n * @example\n * import { intro } from \"@settlemint/sdk-utils/terminal\";\n *\n * // Display intro message\n * intro(\"Starting deployment...\");\n */\nexport const intro = (msg: string): void => {\n if (!shouldPrint()) {\n return;\n }\n console.log(\"\");\n console.log(magentaBright(maskTokens(msg)));\n console.log(\"\");\n};\n","import { maskTokens } from \"@/logging/mask-tokens.js\";\nimport { yellowBright } from \"yoctocolors\";\nimport { shouldPrint } from \"./should-print.js\";\n\n/**\n * Displays a note message with optional warning level formatting.\n * Regular notes are displayed in normal text, while warnings are shown in yellow.\n * Any sensitive tokens in the message are masked before display.\n *\n * @param message - The message to display as a note\n * @param level - The note level: \"info\" (default) or \"warn\" for warning styling\n * @example\n * import { note } from \"@settlemint/sdk-utils/terminal\";\n *\n * // Display info note\n * note(\"Operation completed successfully\");\n *\n * // Display warning note\n * note(\"Low disk space remaining\", \"warn\");\n */\nexport const note = (message: string, level: \"info\" | \"warn\" = \"info\"): void => {\n if (!shouldPrint()) {\n return;\n }\n const maskedMessage = maskTokens(message);\n\n console.log(\"\");\n if (level === \"warn\") {\n console.warn(yellowBright(maskedMessage));\n return;\n }\n\n console.log(maskedMessage);\n};\n","import { note } from \"./note.js\";\n\n/**\n * Displays a list of items in a formatted manner, supporting nested items.\n *\n * @param title - The title of the list\n * @param items - The items to display, can be strings or arrays for nested items\n * @returns The formatted list\n * @example\n * import { list } from \"@settlemint/sdk-utils/terminal\";\n *\n * // Simple list\n * list(\"Use cases\", [\"use case 1\", \"use case 2\", \"use case 3\"]);\n *\n * // Nested list\n * list(\"Providers\", [\n * \"AWS\",\n * [\"us-east-1\", \"eu-west-1\"],\n * \"Azure\",\n * [\"eastus\", \"westeurope\"]\n * ]);\n */\nexport function list(title: string, items: Array<string | string[]>) {\n const formatItems = (items: Array<string | string[]>): string => {\n return items\n .map((item) => {\n if (Array.isArray(item)) {\n return item.map((subItem) => ` • ${subItem}`).join(\"\\n\");\n }\n return ` • ${item}`;\n })\n .join(\"\\n\");\n };\n\n return note(`${title}:\\n\\n${formatItems(items)}`);\n}\n","import { maskTokens } from \"@/logging/mask-tokens.js\";\nimport { shouldPrint } from \"@/terminal/should-print.js\";\nimport { greenBright, inverse } from \"yoctocolors\";\n\n/**\n * Displays a closing message in green inverted text with padding.\n * Any sensitive tokens in the message are masked before display.\n *\n * @param msg - The message to display as conclusion\n * @example\n * import { outro } from \"@settlemint/sdk-utils/terminal\";\n *\n * // Display outro message\n * outro(\"Deployment completed successfully!\");\n */\nexport const outro = (msg: string): void => {\n if (!shouldPrint()) {\n return;\n }\n console.log(\"\");\n console.log(inverse(greenBright(maskTokens(msg))));\n console.log(\"\");\n};\n","import isInCi from \"is-in-ci\";\nimport yoctoSpinner, { type Spinner } from \"yocto-spinner\";\nimport { redBright } from \"yoctocolors\";\nimport { maskTokens } from \"../logging/mask-tokens.js\";\nimport { note } from \"./note.js\";\nimport { shouldPrint } from \"./should-print.js\";\n\n/**\n * Error class used to indicate that the spinner operation failed.\n * This error is used to signal that the operation should be aborted.\n */\nexport class SpinnerError extends Error {\n constructor(\n message: string,\n public readonly originalError: Error,\n ) {\n super(message);\n this.name = \"SpinnerError\";\n }\n}\n\n/**\n * Options for configuring the spinner behavior\n */\nexport interface SpinnerOptions<R> {\n /** Message to display when spinner starts */\n startMessage: string;\n /** Async task to execute while spinner is active */\n task: (spinner?: Spinner) => Promise<R>;\n /** Message to display when spinner completes successfully */\n stopMessage: string;\n}\n\n/**\n * Displays a loading spinner while executing an async task.\n * Shows progress with start/stop messages and handles errors.\n * Spinner is disabled in CI environments.\n *\n * @param options - Configuration options for the spinner\n * @returns The result from the executed task\n * @throws Will exit process with code 1 if task fails\n * @example\n * import { spinner } from \"@settlemint/sdk-utils/terminal\";\n *\n * // Show spinner during async task\n * const result = await spinner({\n * startMessage: \"Deploying...\",\n * task: async () => {\n * // Async work here\n * return \"success\";\n * },\n * stopMessage: \"Deployed successfully!\"\n * });\n */\nexport const spinner = async <R>(options: SpinnerOptions<R>): Promise<R> => {\n const handleError = (error: Error) => {\n const errorMessage = maskTokens(error.message);\n note(redBright(`${errorMessage}\\n\\n${error.stack}`));\n throw new SpinnerError(errorMessage, error);\n };\n if (isInCi || !shouldPrint()) {\n try {\n return await options.task();\n } catch (err) {\n return handleError(err as Error);\n }\n }\n const spinner = yoctoSpinner({ stream: process.stdout }).start(options.startMessage);\n try {\n const result = await options.task(spinner);\n spinner.success(options.stopMessage);\n // Ensure spinner success message renders before proceeding to avoid\n // terminal output overlap issues with subsequent messages\n await new Promise((resolve) => process.nextTick(resolve));\n return result;\n } catch (err) {\n spinner.error(redBright(`${options.startMessage} --> Error!`));\n return handleError(err as Error);\n }\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","import { Table } from \"console-table-printer\";\nimport { whiteBright } from \"yoctocolors\";\nimport { camelCaseToWords } from \"@/string.js\";\nimport { note } from \"./note.js\";\nimport { shouldPrint } from \"./should-print.js\";\n/**\n * Displays data in a formatted table in the terminal.\n *\n * @param title - Title to display above the table\n * @param data - Array of objects to display in table format\n * @example\n * import { table } from \"@settlemint/sdk-utils/terminal\";\n *\n * const data = [\n * { name: \"Item 1\", value: 100 },\n * { name: \"Item 2\", value: 200 }\n * ];\n *\n * table(\"My Table\", data);\n */\nexport function table(title: string, data: unknown[]): void {\n if (!shouldPrint()) {\n return;\n }\n\n note(title);\n\n if (!data || data.length === 0) {\n note(\"No data to display\");\n return;\n }\n\n const columnKeys = Object.keys(data[0] as Record<string, unknown>);\n const table = new Table({\n columns: columnKeys.map((key) => ({\n name: key,\n title: whiteBright(camelCaseToWords(key)),\n alignment: \"left\",\n })),\n });\n // biome-ignore lint/suspicious/noExplicitAny: Data structure varies based on table content\n table.addRows(data as Array<Record<string, any>>);\n table.printTable();\n}\n","import { installPackage } from \"@antfu/install-pkg\";\nimport { note } from \"../terminal.js\";\n\n/**\n * Installs one or more packages as dependencies using the detected package manager\n *\n * @param pkgs - A single package name or array of package names to install\n * @param cwd - The directory to run the installation in\n * @returns A promise that resolves when installation is complete\n * @throws If package installation fails\n * @example\n * import { installDependencies } from \"@settlemint/sdk-utils/package-manager\";\n *\n * // Install a single package\n * await installDependencies(\"express\");\n *\n * // Install multiple packages\n * await installDependencies([\"express\", \"cors\"]);\n */\nexport async function installDependencies(pkgs: string | string[], cwd?: string) {\n try {\n await installPackage(pkgs, { silent: true, additionalArgs: [\"--exact\"], cwd });\n } catch (err) {\n const error = err instanceof Error ? err.message : \"Unknown error\";\n note(\n `Failed to install ${Array.isArray(pkgs) ? `dependencies '${pkgs.join(\", \")}'` : `dependency '${pkgs}'`}: ${error}`,\n \"warn\",\n );\n }\n}\n","import { projectRoot } from \"@/filesystem/project-root.js\";\nimport pkgjs from \"@npmcli/package-json\";\n\n/**\n * Checks if a package is installed in the project's dependencies, devDependencies, or peerDependencies.\n *\n * @param name - The name of the package to check\n * @param path - The path to the project root directory. If not provided, will be automatically determined\n * @returns Whether the package is installed\n * @throws If unable to read or parse the package.json file\n * @example\n * import { isPackageInstalled } from \"@settlemint/sdk-utils/package-manager\";\n *\n * const isInstalled = await isPackageInstalled(\"@settlemint/sdk-utils\");\n * console.log(`@settlemint/sdk-utils is installed: ${isInstalled}`);\n */\nexport async function isPackageInstalled(name: string, path?: string) {\n // Read the package.json file\n const pkgJson = await pkgjs.load(path ?? (await projectRoot()));\n\n const inDependencies = !!pkgJson.content.dependencies?.[name];\n const inDevDependencies = !!pkgJson.content.devDependencies?.[name];\n const inPeerDependencies = !!pkgJson.content.peerDependencies?.[name];\n\n return inDependencies || inDevDependencies || inPeerDependencies;\n}\n","import { projectRoot } from \"@/filesystem/project-root.js\";\nimport pkgjs from \"@npmcli/package-json\";\n\n/**\n * Sets the name field in the package.json file\n *\n * @param name - The new name to set in the package.json file\n * @param path - The path to the project root directory. If not provided, will be automatically determined\n * @returns A promise that resolves when the package.json has been updated\n * @throws If unable to read, update or save the package.json file\n * @example\n * import { setName } from \"@settlemint/sdk-utils/package-manager\";\n *\n * await setName(\"my-new-project-name\");\n */\nexport async function setName(name: string, path?: string) {\n // Read the package.json file\n const pkgJson = await pkgjs.load(path ?? (await projectRoot()));\n\n pkgJson.update({\n name,\n });\n\n await pkgJson.save();\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"retry.cjs","names":["logLevels: Record<LogLevel, number>","level"],"sources":["../src/logging/mask-tokens.ts","../src/logging/logger.ts","../src/retry.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"],"mappings":";;;;;;;;;;;;;;AAYA,MAAa,cAAc,WAA2B;AACpD,QAAO,OAAO,QAAQ,kCAAkC;;;;;;;;;;;;;;;;;;;;;ACoC1D,SAAgB,aAAa,UAAyB,IAAY;CAChE,MAAM,EAAE,QAAQ,QAAQ,SAAS,OAAO;CAExC,MAAMA,YAAsC;EAC1C,OAAO;EACP,MAAM;EACN,MAAM;EACN,OAAO;EACP,MAAM;;CAGR,MAAM,oBAAoB,UAAU;CAEpC,MAAM,cAAc,SAA4B;AAC9C,MAAI,KAAK,WAAW,KAAK,KAAK,OAAO,QAAQ,QAAQ,aAAa,QAAQ,OAAO;AAC/E,UAAO;;EAGT,MAAM,YAAY,KACf,KAAK,QAAQ;AACZ,OAAI,eAAe,OAAO;AACxB,WAAO,KAAK,IAAI,SAAS,IAAI;;AAE/B,OAAI,OAAO,QAAQ,YAAY,QAAQ,MAAM;AAC3C,WAAO,KAAK,KAAK,UAAU,KAAK,MAAM;;AAExC,UAAO,IAAI,OAAO;KAEnB,KAAK;AAER,SAAO,UAAU;;CAGnB,MAAM,aAAa,YAA6B;AAC9C,SAAO,UAAUC,YAAU;;AAG7B,QAAO;EACL,QAAQ,SAAiB,GAAG,SAAoB;AAC9C,OAAI,UAAU,UAAU;AACtB,YAAQ,MAAM,WAAW,OAAO,UAAU,WAAW,WAAW,WAAW,WAAW,OAAO;;;EAGjG,OAAO,SAAiB,GAAG,SAAoB;AAC7C,OAAI,UAAU,SAAS;AACrB,YAAQ,KAAK,WAAW,OAAO,SAAS,WAAW,WAAW,WAAW,WAAW,OAAO;;;EAG/F,OAAO,SAAiB,GAAG,SAAoB;AAC7C,OAAI,UAAU,SAAS;AACrB,YAAQ,KAAK,WAAW,OAAO,SAAS,WAAW,WAAW,WAAW,WAAW,OAAO;;;EAG/F,QAAQ,SAAiB,GAAG,SAAoB;AAC9C,OAAI,UAAU,UAAU;AACtB,YAAQ,MAAM,WAAW,OAAO,UAAU,WAAW,WAAW,WAAW,WAAW,OAAO;;;;;;;;AASrG,MAAa,SAAS;;;;;;;;;;;;;;;;;AClGtB,eAAsB,gBACpB,IACA,aAAa,GACb,mBAAmB,KACnB,aACY;CACZ,IAAI,UAAU;CACd,MAAM,cAAc,aAAa;AAEjC,QAAO,UAAU,aAAa;AAC5B,MAAI;AACF,UAAO,MAAM;WACN,GAAG;GACV,MAAM,QAAQ;AACd,OAAI,OAAO,gBAAgB,YAAY;AACrC,QAAI,YAAY,QAAQ;AACtB,WAAM;;;AAGV,OAAI,WAAW,YAAY;AACzB,UAAM;;GAIR,MAAM,YAAY,KAAK,UAAU;GACjC,MAAM,eAAe,oBAAoB,KAAK,WAAW;GACzD,MAAM,QAAQ,YAAY;AAC1B,cAAW;AACX,UAAO,KACL,qBAAqB,MAAM,QAAQ,gBAAgB,MAAM,QAAQ,GAAG,YAAY,QAAQ,MAAM,WAAW;AAE3G,SAAM,IAAI,SAAS,YAAY,WAAW,SAAS;;;AAIvD,OAAM,IAAI,MAAM"}
1
+ {"version":3,"file":"retry.cjs","names":["logLevels: Record<LogLevel, number>","level"],"sources":["../src/logging/mask-tokens.ts","../src/logging/logger.ts","../src/retry.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"],"mappings":";;;;;;;;;;;;;;AAYA,MAAa,cAAc,WAA2B;AACpD,QAAO,OAAO,QAAQ,kCAAkC,MAAM;;;;;;;;;;;;;;;;;;;;;ACoChE,SAAgB,aAAa,UAAyB,EAAE,EAAU;CAChE,MAAM,EAAE,QAAQ,QAAQ,SAAS,OAAO;CAExC,MAAMA,YAAsC;EAC1C,OAAO;EACP,MAAM;EACN,MAAM;EACN,OAAO;EACP,MAAM;EACP;CAED,MAAM,oBAAoB,UAAU;CAEpC,MAAM,cAAc,SAA4B;AAC9C,MAAI,KAAK,WAAW,KAAK,KAAK,OAAO,QAAQ,QAAQ,aAAa,QAAQ,KAAK,EAAE;AAC/E,UAAO;;EAGT,MAAM,YAAY,KACf,KAAK,QAAQ;AACZ,OAAI,eAAe,OAAO;AACxB,WAAO,KAAK,IAAI,SAAS,IAAI;;AAE/B,OAAI,OAAO,QAAQ,YAAY,QAAQ,MAAM;AAC3C,WAAO,KAAK,KAAK,UAAU,KAAK,MAAM,EAAE;;AAE1C,UAAO,IAAI,OAAO,IAAI;IACtB,CACD,KAAK,GAAG;AAEX,SAAO,UAAU;;CAGnB,MAAM,aAAa,YAA6B;AAC9C,SAAO,UAAUC,YAAU;;AAG7B,QAAO;EACL,QAAQ,SAAiB,GAAG,SAAoB;AAC9C,OAAI,UAAU,QAAQ,EAAE;AACtB,YAAQ,MAAM,WAAW,OAAO,UAAU,WAAW,QAAQ,GAAG,WAAW,WAAW,KAAK,CAAC,CAAC,SAAS;;;EAG1G,OAAO,SAAiB,GAAG,SAAoB;AAC7C,OAAI,UAAU,OAAO,EAAE;AACrB,YAAQ,KAAK,WAAW,OAAO,SAAS,WAAW,QAAQ,GAAG,WAAW,WAAW,KAAK,CAAC,CAAC,SAAS;;;EAGxG,OAAO,SAAiB,GAAG,SAAoB;AAC7C,OAAI,UAAU,OAAO,EAAE;AACrB,YAAQ,KAAK,WAAW,OAAO,SAAS,WAAW,QAAQ,GAAG,WAAW,WAAW,KAAK,CAAC,CAAC,SAAS;;;EAGxG,QAAQ,SAAiB,GAAG,SAAoB;AAC9C,OAAI,UAAU,QAAQ,EAAE;AACtB,YAAQ,MAAM,WAAW,OAAO,UAAU,WAAW,QAAQ,GAAG,WAAW,WAAW,KAAK,CAAC,CAAC,SAAS;;;EAG3G;;;;;AAMH,MAAa,SAAS,cAAc;;;;;;;;;;;;;;;;;AClGpC,eAAsB,gBACpB,IACA,aAAa,GACb,mBAAmB,KACnB,aACY;CACZ,IAAI,UAAU;CACd,MAAM,cAAc,aAAa;AAEjC,QAAO,UAAU,aAAa;AAC5B,MAAI;AACF,UAAO,MAAM,IAAI;WACV,GAAG;GACV,MAAM,QAAQ;AACd,OAAI,OAAO,gBAAgB,YAAY;AACrC,QAAI,YAAY,MAAM,EAAE;AACtB,WAAM;;;AAGV,OAAI,WAAW,YAAY;AACzB,UAAM;;GAIR,MAAM,YAAY,KAAK,UAAU;GACjC,MAAM,eAAe,oBAAoB,KAAK,QAAQ,GAAG;GACzD,MAAM,QAAQ,YAAY;AAC1B,cAAW;AACX,UAAO,KACL,qBAAqB,MAAM,QAAQ,gBAAgB,MAAM,QAAQ,EAAE,CAAC,YAAY,QAAQ,MAAM,WAAW,MAC1G;AACD,SAAM,IAAI,SAAS,YAAY,WAAW,SAAS,MAAM,CAAC;;;AAI9D,OAAM,IAAI,MAAM,eAAe"}
package/dist/retry.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"retry.js","names":["logLevels: Record<LogLevel, number>","level"],"sources":["../src/logging/mask-tokens.ts","../src/logging/logger.ts","../src/retry.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"],"mappings":";;;;;;;;;;;;;AAYA,MAAa,cAAc,WAA2B;AACpD,QAAO,OAAO,QAAQ,kCAAkC;;;;;;;;;;;;;;;;;;;;;ACoC1D,SAAgB,aAAa,UAAyB,IAAY;CAChE,MAAM,EAAE,QAAQ,QAAQ,SAAS,OAAO;CAExC,MAAMA,YAAsC;EAC1C,OAAO;EACP,MAAM;EACN,MAAM;EACN,OAAO;EACP,MAAM;;CAGR,MAAM,oBAAoB,UAAU;CAEpC,MAAM,cAAc,SAA4B;AAC9C,MAAI,KAAK,WAAW,KAAK,KAAK,OAAO,QAAQ,QAAQ,aAAa,QAAQ,OAAO;AAC/E,UAAO;;EAGT,MAAM,YAAY,KACf,KAAK,QAAQ;AACZ,OAAI,eAAe,OAAO;AACxB,WAAO,KAAK,IAAI,SAAS,IAAI;;AAE/B,OAAI,OAAO,QAAQ,YAAY,QAAQ,MAAM;AAC3C,WAAO,KAAK,KAAK,UAAU,KAAK,MAAM;;AAExC,UAAO,IAAI,OAAO;KAEnB,KAAK;AAER,SAAO,UAAU;;CAGnB,MAAM,aAAa,YAA6B;AAC9C,SAAO,UAAUC,YAAU;;AAG7B,QAAO;EACL,QAAQ,SAAiB,GAAG,SAAoB;AAC9C,OAAI,UAAU,UAAU;AACtB,YAAQ,MAAM,WAAW,OAAO,UAAU,WAAW,WAAW,WAAW,WAAW,OAAO;;;EAGjG,OAAO,SAAiB,GAAG,SAAoB;AAC7C,OAAI,UAAU,SAAS;AACrB,YAAQ,KAAK,WAAW,OAAO,SAAS,WAAW,WAAW,WAAW,WAAW,OAAO;;;EAG/F,OAAO,SAAiB,GAAG,SAAoB;AAC7C,OAAI,UAAU,SAAS;AACrB,YAAQ,KAAK,WAAW,OAAO,SAAS,WAAW,WAAW,WAAW,WAAW,OAAO;;;EAG/F,QAAQ,SAAiB,GAAG,SAAoB;AAC9C,OAAI,UAAU,UAAU;AACtB,YAAQ,MAAM,WAAW,OAAO,UAAU,WAAW,WAAW,WAAW,WAAW,OAAO;;;;;;;;AASrG,MAAa,SAAS;;;;;;;;;;;;;;;;;AClGtB,eAAsB,gBACpB,IACA,aAAa,GACb,mBAAmB,KACnB,aACY;CACZ,IAAI,UAAU;CACd,MAAM,cAAc,aAAa;AAEjC,QAAO,UAAU,aAAa;AAC5B,MAAI;AACF,UAAO,MAAM;WACN,GAAG;GACV,MAAM,QAAQ;AACd,OAAI,OAAO,gBAAgB,YAAY;AACrC,QAAI,YAAY,QAAQ;AACtB,WAAM;;;AAGV,OAAI,WAAW,YAAY;AACzB,UAAM;;GAIR,MAAM,YAAY,KAAK,UAAU;GACjC,MAAM,eAAe,oBAAoB,KAAK,WAAW;GACzD,MAAM,QAAQ,YAAY;AAC1B,cAAW;AACX,UAAO,KACL,qBAAqB,MAAM,QAAQ,gBAAgB,MAAM,QAAQ,GAAG,YAAY,QAAQ,MAAM,WAAW;AAE3G,SAAM,IAAI,SAAS,YAAY,WAAW,SAAS;;;AAIvD,OAAM,IAAI,MAAM"}
1
+ {"version":3,"file":"retry.js","names":["logLevels: Record<LogLevel, number>","level"],"sources":["../src/logging/mask-tokens.ts","../src/logging/logger.ts","../src/retry.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"],"mappings":";;;;;;;;;;;;;AAYA,MAAa,cAAc,WAA2B;AACpD,QAAO,OAAO,QAAQ,kCAAkC,MAAM;;;;;;;;;;;;;;;;;;;;;ACoChE,SAAgB,aAAa,UAAyB,EAAE,EAAU;CAChE,MAAM,EAAE,QAAQ,QAAQ,SAAS,OAAO;CAExC,MAAMA,YAAsC;EAC1C,OAAO;EACP,MAAM;EACN,MAAM;EACN,OAAO;EACP,MAAM;EACP;CAED,MAAM,oBAAoB,UAAU;CAEpC,MAAM,cAAc,SAA4B;AAC9C,MAAI,KAAK,WAAW,KAAK,KAAK,OAAO,QAAQ,QAAQ,aAAa,QAAQ,KAAK,EAAE;AAC/E,UAAO;;EAGT,MAAM,YAAY,KACf,KAAK,QAAQ;AACZ,OAAI,eAAe,OAAO;AACxB,WAAO,KAAK,IAAI,SAAS,IAAI;;AAE/B,OAAI,OAAO,QAAQ,YAAY,QAAQ,MAAM;AAC3C,WAAO,KAAK,KAAK,UAAU,KAAK,MAAM,EAAE;;AAE1C,UAAO,IAAI,OAAO,IAAI;IACtB,CACD,KAAK,GAAG;AAEX,SAAO,UAAU;;CAGnB,MAAM,aAAa,YAA6B;AAC9C,SAAO,UAAUC,YAAU;;AAG7B,QAAO;EACL,QAAQ,SAAiB,GAAG,SAAoB;AAC9C,OAAI,UAAU,QAAQ,EAAE;AACtB,YAAQ,MAAM,WAAW,OAAO,UAAU,WAAW,QAAQ,GAAG,WAAW,WAAW,KAAK,CAAC,CAAC,SAAS;;;EAG1G,OAAO,SAAiB,GAAG,SAAoB;AAC7C,OAAI,UAAU,OAAO,EAAE;AACrB,YAAQ,KAAK,WAAW,OAAO,SAAS,WAAW,QAAQ,GAAG,WAAW,WAAW,KAAK,CAAC,CAAC,SAAS;;;EAGxG,OAAO,SAAiB,GAAG,SAAoB;AAC7C,OAAI,UAAU,OAAO,EAAE;AACrB,YAAQ,KAAK,WAAW,OAAO,SAAS,WAAW,QAAQ,GAAG,WAAW,WAAW,KAAK,CAAC,CAAC,SAAS;;;EAGxG,QAAQ,SAAiB,GAAG,SAAoB;AAC9C,OAAI,UAAU,QAAQ,EAAE;AACtB,YAAQ,MAAM,WAAW,OAAO,UAAU,WAAW,QAAQ,GAAG,WAAW,WAAW,KAAK,CAAC,CAAC,SAAS;;;EAG3G;;;;;AAMH,MAAa,SAAS,cAAc;;;;;;;;;;;;;;;;;AClGpC,eAAsB,gBACpB,IACA,aAAa,GACb,mBAAmB,KACnB,aACY;CACZ,IAAI,UAAU;CACd,MAAM,cAAc,aAAa;AAEjC,QAAO,UAAU,aAAa;AAC5B,MAAI;AACF,UAAO,MAAM,IAAI;WACV,GAAG;GACV,MAAM,QAAQ;AACd,OAAI,OAAO,gBAAgB,YAAY;AACrC,QAAI,YAAY,MAAM,EAAE;AACtB,WAAM;;;AAGV,OAAI,WAAW,YAAY;AACzB,UAAM;;GAIR,MAAM,YAAY,KAAK,UAAU;GACjC,MAAM,eAAe,oBAAoB,KAAK,QAAQ,GAAG;GACzD,MAAM,QAAQ,YAAY;AAC1B,cAAW;AACX,UAAO,KACL,qBAAqB,MAAM,QAAQ,gBAAgB,MAAM,QAAQ,EAAE,CAAC,YAAY,QAAQ,MAAM,WAAW,MAC1G;AACD,SAAM,IAAI,SAAS,YAAY,WAAW,SAAS,MAAM,CAAC;;;AAI9D,OAAM,IAAI,MAAM,eAAe"}
package/dist/runtime.cjs CHANGED
@@ -21,7 +21,8 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
21
21
  }) : target, mod));
22
22
 
23
23
  //#endregion
24
- const environment = __toESM(require("environment"));
24
+ let environment = require("environment");
25
+ environment = __toESM(environment);
25
26
 
26
27
  //#region src/runtime/ensure-server.ts
27
28
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"runtime.cjs","names":["isBrowser"],"sources":["../src/runtime/ensure-server.ts"],"sourcesContent":["import { isBrowser } from \"environment\";\n\n/**\n * Ensures that code is running on the server and not in a browser environment.\n *\n * @throws {Error} If called from a browser environment\n * @example\n * import { ensureServer } from \"@settlemint/sdk-utils/runtime\";\n *\n * // Will throw if running in browser\n * ensureServer();\n */\nexport function ensureServer(): void {\n if (isBrowser) {\n throw new Error(\n \"This function can only be used on the server as including it in the browser will expose your access token.\",\n );\n }\n}\n\n/**\n * Ensures that code is running in a browser environment and not on the server.\n *\n * @throws {Error} If called from a server environment\n * @example\n * import { ensureBrowser } from \"@settlemint/sdk-utils/runtime\";\n *\n * // Will throw if running on server\n * ensureBrowser();\n */\nexport function ensureBrowser(): void {\n if (!isBrowser) {\n throw new Error(\"This function can only be used on the browser as it is missing the access token.\");\n }\n}\n\n/**\n * Boolean indicating if code is currently running in a browser environment\n */\nexport const runsInBrowser = isBrowser;\n\n/**\n * Boolean indicating if code is currently running in a server environment\n */\nexport const runsOnServer = !isBrowser;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAYA,SAAgB,eAAqB;AACnC,KAAIA,uBAAW;AACb,QAAM,IAAI,MACR;;;;;;;;;;;;;AAeN,SAAgB,gBAAsB;AACpC,KAAI,CAACA,uBAAW;AACd,QAAM,IAAI,MAAM;;;;;;AAOpB,MAAa,gBAAgBA;;;;AAK7B,MAAa,eAAe,CAACA"}
1
+ {"version":3,"file":"runtime.cjs","names":["isBrowser"],"sources":["../src/runtime/ensure-server.ts"],"sourcesContent":["import { isBrowser } from \"environment\";\n\n/**\n * Ensures that code is running on the server and not in a browser environment.\n *\n * @throws {Error} If called from a browser environment\n * @example\n * import { ensureServer } from \"@settlemint/sdk-utils/runtime\";\n *\n * // Will throw if running in browser\n * ensureServer();\n */\nexport function ensureServer(): void {\n if (isBrowser) {\n throw new Error(\n \"This function can only be used on the server as including it in the browser will expose your access token.\",\n );\n }\n}\n\n/**\n * Ensures that code is running in a browser environment and not on the server.\n *\n * @throws {Error} If called from a server environment\n * @example\n * import { ensureBrowser } from \"@settlemint/sdk-utils/runtime\";\n *\n * // Will throw if running on server\n * ensureBrowser();\n */\nexport function ensureBrowser(): void {\n if (!isBrowser) {\n throw new Error(\"This function can only be used on the browser as it is missing the access token.\");\n }\n}\n\n/**\n * Boolean indicating if code is currently running in a browser environment\n */\nexport const runsInBrowser = isBrowser;\n\n/**\n * Boolean indicating if code is currently running in a server environment\n */\nexport const runsOnServer = !isBrowser;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAYA,SAAgB,eAAqB;AACnC,KAAIA,uBAAW;AACb,QAAM,IAAI,MACR,6GACD;;;;;;;;;;;;;AAcL,SAAgB,gBAAsB;AACpC,KAAI,CAACA,uBAAW;AACd,QAAM,IAAI,MAAM,mFAAmF;;;;;;AAOvG,MAAa,gBAAgBA;;;;AAK7B,MAAa,eAAe,CAACA"}
@@ -1 +1 @@
1
- {"version":3,"file":"runtime.js","names":[],"sources":["../src/runtime/ensure-server.ts"],"sourcesContent":["import { isBrowser } from \"environment\";\n\n/**\n * Ensures that code is running on the server and not in a browser environment.\n *\n * @throws {Error} If called from a browser environment\n * @example\n * import { ensureServer } from \"@settlemint/sdk-utils/runtime\";\n *\n * // Will throw if running in browser\n * ensureServer();\n */\nexport function ensureServer(): void {\n if (isBrowser) {\n throw new Error(\n \"This function can only be used on the server as including it in the browser will expose your access token.\",\n );\n }\n}\n\n/**\n * Ensures that code is running in a browser environment and not on the server.\n *\n * @throws {Error} If called from a server environment\n * @example\n * import { ensureBrowser } from \"@settlemint/sdk-utils/runtime\";\n *\n * // Will throw if running on server\n * ensureBrowser();\n */\nexport function ensureBrowser(): void {\n if (!isBrowser) {\n throw new Error(\"This function can only be used on the browser as it is missing the access token.\");\n }\n}\n\n/**\n * Boolean indicating if code is currently running in a browser environment\n */\nexport const runsInBrowser = isBrowser;\n\n/**\n * Boolean indicating if code is currently running in a server environment\n */\nexport const runsOnServer = !isBrowser;\n"],"mappings":";;;;;;;;;;;;;AAYA,SAAgB,eAAqB;AACnC,KAAI,WAAW;AACb,QAAM,IAAI,MACR;;;;;;;;;;;;;AAeN,SAAgB,gBAAsB;AACpC,KAAI,CAAC,WAAW;AACd,QAAM,IAAI,MAAM;;;;;;AAOpB,MAAa,gBAAgB;;;;AAK7B,MAAa,eAAe,CAAC"}
1
+ {"version":3,"file":"runtime.js","names":[],"sources":["../src/runtime/ensure-server.ts"],"sourcesContent":["import { isBrowser } from \"environment\";\n\n/**\n * Ensures that code is running on the server and not in a browser environment.\n *\n * @throws {Error} If called from a browser environment\n * @example\n * import { ensureServer } from \"@settlemint/sdk-utils/runtime\";\n *\n * // Will throw if running in browser\n * ensureServer();\n */\nexport function ensureServer(): void {\n if (isBrowser) {\n throw new Error(\n \"This function can only be used on the server as including it in the browser will expose your access token.\",\n );\n }\n}\n\n/**\n * Ensures that code is running in a browser environment and not on the server.\n *\n * @throws {Error} If called from a server environment\n * @example\n * import { ensureBrowser } from \"@settlemint/sdk-utils/runtime\";\n *\n * // Will throw if running on server\n * ensureBrowser();\n */\nexport function ensureBrowser(): void {\n if (!isBrowser) {\n throw new Error(\"This function can only be used on the browser as it is missing the access token.\");\n }\n}\n\n/**\n * Boolean indicating if code is currently running in a browser environment\n */\nexport const runsInBrowser = isBrowser;\n\n/**\n * Boolean indicating if code is currently running in a server environment\n */\nexport const runsOnServer = !isBrowser;\n"],"mappings":";;;;;;;;;;;;;AAYA,SAAgB,eAAqB;AACnC,KAAI,WAAW;AACb,QAAM,IAAI,MACR,6GACD;;;;;;;;;;;;;AAcL,SAAgB,gBAAsB;AACpC,KAAI,CAAC,WAAW;AACd,QAAM,IAAI,MAAM,mFAAmF;;;;;;AAOvG,MAAa,gBAAgB;;;;AAK7B,MAAa,eAAe,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"string.cjs","names":[],"sources":["../src/string.ts"],"sourcesContent":["/**\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"],"mappings":";;;;;;;;;;;;;;AAYA,SAAgB,sBAAsB,KAAa;AACjD,QAAO,OAAO,KAAK,OAAO,GAAG,gBAAgB,OAAO,KAAK,MAAM;;;;;;;;;;;;;;AAejE,SAAgB,iBAAiB,GAAW;CAC1C,MAAM,SAAS,EAAE,QAAQ,mBAAmB;CAC5C,MAAM,aAAa,OAAO,QAAQ,mBAAmB;CACrD,MAAM,cAAc,sBAAsB;AAC1C,QAAO,YAAY,QAAQ,QAAQ,KAAK;;;;;;;;;;;;;;AAe1C,SAAgB,uCAAuC,GAAW;AAChE,QAAO,EAAE,QAAQ,SAAS;;;;;;;;;;;;;;;AAgB5B,SAAgB,SAAS,OAAe,WAAmB;AACzD,KAAI,MAAM,UAAU,WAAW;AAC7B,SAAO;;AAET,QAAO,GAAG,MAAM,MAAM,GAAG,WAAW"}
1
+ {"version":3,"file":"string.cjs","names":[],"sources":["../src/string.ts"],"sourcesContent":["/**\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"],"mappings":";;;;;;;;;;;;;;AAYA,SAAgB,sBAAsB,KAAa;AACjD,QAAO,OAAO,IAAI,CAAC,OAAO,EAAE,CAAC,aAAa,GAAG,OAAO,IAAI,CAAC,MAAM,EAAE;;;;;;;;;;;;;;AAenE,SAAgB,iBAAiB,GAAW;CAC1C,MAAM,SAAS,EAAE,QAAQ,mBAAmB,QAAQ;CACpD,MAAM,aAAa,OAAO,QAAQ,mBAAmB,QAAQ;CAC7D,MAAM,cAAc,sBAAsB,WAAW;AACrD,QAAO,YAAY,QAAQ,QAAQ,IAAI,CAAC,MAAM;;;;;;;;;;;;;;AAehD,SAAgB,uCAAuC,GAAW;AAChE,QAAO,EAAE,QAAQ,SAAS,IAAI;;;;;;;;;;;;;;;AAgBhC,SAAgB,SAAS,OAAe,WAAmB;AACzD,KAAI,MAAM,UAAU,WAAW;AAC7B,SAAO;;AAET,QAAO,GAAG,MAAM,MAAM,GAAG,UAAU,CAAC"}