@settlemint/sdk-utils 2.1.0 → 2.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +106 -73
- package/dist/environment.cjs +3 -1
- package/dist/environment.cjs.map +1 -1
- package/dist/environment.d.cts +7 -0
- package/dist/environment.d.ts +7 -0
- package/dist/environment.mjs +3 -1
- package/dist/environment.mjs.map +1 -1
- package/dist/index.cjs +8 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +15 -1
- package/dist/index.d.ts +15 -1
- package/dist/index.mjs +7 -0
- package/dist/index.mjs.map +1 -1
- package/dist/logging.cjs +45 -8
- package/dist/logging.cjs.map +1 -1
- package/dist/logging.d.cts +3 -1
- package/dist/logging.d.ts +3 -1
- package/dist/logging.mjs +45 -8
- package/dist/logging.mjs.map +1 -1
- package/dist/terminal.cjs.map +1 -1
- package/dist/terminal.mjs.map +1 -1
- package/dist/validation.cjs +3 -1
- package/dist/validation.cjs.map +1 -1
- package/dist/validation.d.cts +7 -0
- package/dist/validation.d.ts +7 -0
- package/dist/validation.mjs +3 -1
- package/dist/validation.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/json.ts","../src/retry.ts","../src/string.ts"],"sourcesContent":["export * from \"./json.js\";\nexport * from \"./retry.js\";\nexport * from \"./string.js\";\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 * 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 attempt = 0;\n\n while (attempt < maxRetries) {\n try {\n return await fn();\n } catch (e) {\n if (typeof stopOnError === \"function\") {\n const error = e as Error;\n if (stopOnError(error)) {\n throw error;\n }\n }\n attempt += 1;\n if (attempt >= maxRetries) {\n throw e;\n }\n // Exponential backoff with full jitter to prevent thundering herd\n const jitter = Math.random();\n const delay = 2 ** attempt * initialSleepTime * jitter; // 0-1x of 1s, 2s, 4s base\n await new Promise((resolve) => setTimeout(resolve, delay));\n }\n }\n\n throw new Error(\"Retry failed\");\n}\n","/**\n * Capitalizes the first letter of a string.\n *\n * @param val - The string to capitalize\n * @returns The input string with its first letter capitalized\n *\n * @example\n * import { capitalizeFirstLetter } from \"@settlemint/sdk-utils\";\n *\n * const capitalized = capitalizeFirstLetter(\"hello\");\n * // Returns: \"Hello\"\n */\nexport function capitalizeFirstLetter(val: string) {\n return String(val).charAt(0).toUpperCase() + String(val).slice(1);\n}\n\n/**\n * Converts a camelCase string to a human-readable string.\n *\n * @param s - The camelCase string to convert\n * @returns The human-readable string\n *\n * @example\n * import { camelCaseToWords } from \"@settlemint/sdk-utils\";\n *\n * const words = camelCaseToWords(\"camelCaseString\");\n * // Returns: \"Camel Case String\"\n */\nexport function camelCaseToWords(s: string) {\n const result = s.replace(/([a-z])([A-Z])/g, \"$1 $2\");\n const withSpaces = result.replace(/([A-Z])([a-z])/g, \" $1$2\");\n const capitalized = capitalizeFirstLetter(withSpaces);\n return capitalized.replace(/\\s+/g, \" \").trim();\n}\n\n/**\n * Replaces underscores and hyphens with spaces.\n *\n * @param s - The string to replace underscores and hyphens with spaces\n * @returns The input string with underscores and hyphens replaced with spaces\n *\n * @example\n * import { replaceUnderscoresAndHyphensWithSpaces } from \"@settlemint/sdk-utils\";\n *\n * const result = replaceUnderscoresAndHyphensWithSpaces(\"Already_Spaced-Second\");\n * // Returns: \"Already Spaced Second\"\n */\nexport function replaceUnderscoresAndHyphensWithSpaces(s: string) {\n return s.replace(/[-_]/g, \" \");\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACsBO,SAAS,aAAgB,OAAe,eAAyB,MAAgB;AACtF,MAAI;AACF,UAAM,SAAS,KAAK,MAAM,KAAK;AAC/B,QAAI,WAAW,UAAa,WAAW,MAAM;AAC3C,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT,SAAS,KAAK;AAEZ,WAAO;AAAA,EACT;AACF;;;ACpBA,eAAsB,gBACpB,IACA,aAAa,GACb,mBAAmB,KACnB,aACY;AACZ,MAAI,UAAU;AAEd,SAAO,UAAU,YAAY;AAC3B,QAAI;AACF,aAAO,MAAM,GAAG;AAAA,IAClB,SAAS,GAAG;AACV,UAAI,OAAO,gBAAgB,YAAY;AACrC,cAAM,QAAQ;AACd,YAAI,YAAY,KAAK,GAAG;AACtB,gBAAM;AAAA,QACR;AAAA,MACF;AACA,iBAAW;AACX,UAAI,WAAW,YAAY;AACzB,cAAM;AAAA,MACR;AAEA,YAAM,SAAS,KAAK,OAAO;AAC3B,YAAM,QAAQ,KAAK,UAAU,mBAAmB;AAChD,YAAM,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,KAAK,CAAC;AAAA,IAC3D;AAAA,EACF;AAEA,QAAM,IAAI,MAAM,cAAc;AAChC;;;AC/BO,SAAS,sBAAsB,KAAa;AACjD,SAAO,OAAO,GAAG,EAAE,OAAO,CAAC,EAAE,YAAY,IAAI,OAAO,GAAG,EAAE,MAAM,CAAC;AAClE;AAcO,SAAS,iBAAiB,GAAW;AAC1C,QAAM,SAAS,EAAE,QAAQ,mBAAmB,OAAO;AACnD,QAAM,aAAa,OAAO,QAAQ,mBAAmB,OAAO;AAC5D,QAAM,cAAc,sBAAsB,UAAU;AACpD,SAAO,YAAY,QAAQ,QAAQ,GAAG,EAAE,KAAK;AAC/C;AAcO,SAAS,uCAAuC,GAAW;AAChE,SAAO,EAAE,QAAQ,SAAS,GAAG;AAC/B;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/json.ts","../src/retry.ts","../src/string.ts"],"sourcesContent":["export * from \"./json.js\";\nexport * from \"./retry.js\";\nexport * from \"./string.js\";\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 * 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 attempt = 0;\n\n while (attempt < maxRetries) {\n try {\n return await fn();\n } catch (e) {\n if (typeof stopOnError === \"function\") {\n const error = e as Error;\n if (stopOnError(error)) {\n throw error;\n }\n }\n attempt += 1;\n if (attempt >= maxRetries) {\n throw e;\n }\n // Exponential backoff with full jitter to prevent thundering herd\n const jitter = Math.random();\n const delay = 2 ** attempt * initialSleepTime * jitter; // 0-1x of 1s, 2s, 4s base\n await new Promise((resolve) => setTimeout(resolve, delay));\n }\n }\n\n throw new Error(\"Retry failed\");\n}\n","/**\n * Capitalizes the first letter of a string.\n *\n * @param val - The string to capitalize\n * @returns The input string with its first letter capitalized\n *\n * @example\n * import { capitalizeFirstLetter } from \"@settlemint/sdk-utils\";\n *\n * const capitalized = capitalizeFirstLetter(\"hello\");\n * // Returns: \"Hello\"\n */\nexport function capitalizeFirstLetter(val: string) {\n return String(val).charAt(0).toUpperCase() + String(val).slice(1);\n}\n\n/**\n * Converts a camelCase string to a human-readable string.\n *\n * @param s - The camelCase string to convert\n * @returns The human-readable string\n *\n * @example\n * import { camelCaseToWords } from \"@settlemint/sdk-utils\";\n *\n * const words = camelCaseToWords(\"camelCaseString\");\n * // Returns: \"Camel Case String\"\n */\nexport function camelCaseToWords(s: string) {\n const result = s.replace(/([a-z])([A-Z])/g, \"$1 $2\");\n const withSpaces = result.replace(/([A-Z])([a-z])/g, \" $1$2\");\n const capitalized = capitalizeFirstLetter(withSpaces);\n return capitalized.replace(/\\s+/g, \" \").trim();\n}\n\n/**\n * Replaces underscores and hyphens with spaces.\n *\n * @param s - The string to replace underscores and hyphens with spaces\n * @returns The input string with underscores and hyphens replaced with spaces\n *\n * @example\n * import { replaceUnderscoresAndHyphensWithSpaces } from \"@settlemint/sdk-utils\";\n *\n * const result = replaceUnderscoresAndHyphensWithSpaces(\"Already_Spaced-Second\");\n * // Returns: \"Already Spaced Second\"\n */\nexport function replaceUnderscoresAndHyphensWithSpaces(s: string) {\n return s.replace(/[-_]/g, \" \");\n}\n\n/**\n * Truncates a string to a maximum length and appends \"...\" if it is longer.\n *\n * @param value - The string to truncate\n * @param maxLength - The maximum length of the string\n * @returns The truncated string or the original string if it is shorter than the maximum length\n *\n * @example\n * import { truncate } from \"@settlemint/sdk-utils\";\n *\n * const truncated = truncate(\"Hello, world!\", 10);\n * // Returns: \"Hello, wor...\"\n */\nexport function truncate(value: string, maxLength: number) {\n if (value.length <= maxLength) {\n return value;\n }\n return `${value.slice(0, maxLength)}...`;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACsBO,SAAS,aAAgB,OAAe,eAAyB,MAAgB;AACtF,MAAI;AACF,UAAM,SAAS,KAAK,MAAM,KAAK;AAC/B,QAAI,WAAW,UAAa,WAAW,MAAM;AAC3C,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT,SAAS,KAAK;AAEZ,WAAO;AAAA,EACT;AACF;;;ACpBA,eAAsB,gBACpB,IACA,aAAa,GACb,mBAAmB,KACnB,aACY;AACZ,MAAI,UAAU;AAEd,SAAO,UAAU,YAAY;AAC3B,QAAI;AACF,aAAO,MAAM,GAAG;AAAA,IAClB,SAAS,GAAG;AACV,UAAI,OAAO,gBAAgB,YAAY;AACrC,cAAM,QAAQ;AACd,YAAI,YAAY,KAAK,GAAG;AACtB,gBAAM;AAAA,QACR;AAAA,MACF;AACA,iBAAW;AACX,UAAI,WAAW,YAAY;AACzB,cAAM;AAAA,MACR;AAEA,YAAM,SAAS,KAAK,OAAO;AAC3B,YAAM,QAAQ,KAAK,UAAU,mBAAmB;AAChD,YAAM,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,KAAK,CAAC;AAAA,IAC3D;AAAA,EACF;AAEA,QAAM,IAAI,MAAM,cAAc;AAChC;;;AC/BO,SAAS,sBAAsB,KAAa;AACjD,SAAO,OAAO,GAAG,EAAE,OAAO,CAAC,EAAE,YAAY,IAAI,OAAO,GAAG,EAAE,MAAM,CAAC;AAClE;AAcO,SAAS,iBAAiB,GAAW;AAC1C,QAAM,SAAS,EAAE,QAAQ,mBAAmB,OAAO;AACnD,QAAM,aAAa,OAAO,QAAQ,mBAAmB,OAAO;AAC5D,QAAM,cAAc,sBAAsB,UAAU;AACpD,SAAO,YAAY,QAAQ,QAAQ,GAAG,EAAE,KAAK;AAC/C;AAcO,SAAS,uCAAuC,GAAW;AAChE,SAAO,EAAE,QAAQ,SAAS,GAAG;AAC/B;AAeO,SAAS,SAAS,OAAe,WAAmB;AACzD,MAAI,MAAM,UAAU,WAAW;AAC7B,WAAO;AAAA,EACT;AACA,SAAO,GAAG,MAAM,MAAM,GAAG,SAAS,CAAC;AACrC;","names":[]}
|
package/dist/index.d.cts
CHANGED
|
@@ -76,5 +76,19 @@ declare function camelCaseToWords(s: string): string;
|
|
|
76
76
|
* // Returns: "Already Spaced Second"
|
|
77
77
|
*/
|
|
78
78
|
declare function replaceUnderscoresAndHyphensWithSpaces(s: string): string;
|
|
79
|
+
/**
|
|
80
|
+
* Truncates a string to a maximum length and appends "..." if it is longer.
|
|
81
|
+
*
|
|
82
|
+
* @param value - The string to truncate
|
|
83
|
+
* @param maxLength - The maximum length of the string
|
|
84
|
+
* @returns The truncated string or the original string if it is shorter than the maximum length
|
|
85
|
+
*
|
|
86
|
+
* @example
|
|
87
|
+
* import { truncate } from "@settlemint/sdk-utils";
|
|
88
|
+
*
|
|
89
|
+
* const truncated = truncate("Hello, world!", 10);
|
|
90
|
+
* // Returns: "Hello, wor..."
|
|
91
|
+
*/
|
|
92
|
+
declare function truncate(value: string, maxLength: number): string;
|
|
79
93
|
|
|
80
|
-
export { camelCaseToWords, capitalizeFirstLetter, replaceUnderscoresAndHyphensWithSpaces, retryWhenFailed, tryParseJson };
|
|
94
|
+
export { camelCaseToWords, capitalizeFirstLetter, replaceUnderscoresAndHyphensWithSpaces, retryWhenFailed, truncate, tryParseJson };
|
package/dist/index.d.ts
CHANGED
|
@@ -76,5 +76,19 @@ declare function camelCaseToWords(s: string): string;
|
|
|
76
76
|
* // Returns: "Already Spaced Second"
|
|
77
77
|
*/
|
|
78
78
|
declare function replaceUnderscoresAndHyphensWithSpaces(s: string): string;
|
|
79
|
+
/**
|
|
80
|
+
* Truncates a string to a maximum length and appends "..." if it is longer.
|
|
81
|
+
*
|
|
82
|
+
* @param value - The string to truncate
|
|
83
|
+
* @param maxLength - The maximum length of the string
|
|
84
|
+
* @returns The truncated string or the original string if it is shorter than the maximum length
|
|
85
|
+
*
|
|
86
|
+
* @example
|
|
87
|
+
* import { truncate } from "@settlemint/sdk-utils";
|
|
88
|
+
*
|
|
89
|
+
* const truncated = truncate("Hello, world!", 10);
|
|
90
|
+
* // Returns: "Hello, wor..."
|
|
91
|
+
*/
|
|
92
|
+
declare function truncate(value: string, maxLength: number): string;
|
|
79
93
|
|
|
80
|
-
export { camelCaseToWords, capitalizeFirstLetter, replaceUnderscoresAndHyphensWithSpaces, retryWhenFailed, tryParseJson };
|
|
94
|
+
export { camelCaseToWords, capitalizeFirstLetter, replaceUnderscoresAndHyphensWithSpaces, retryWhenFailed, truncate, tryParseJson };
|
package/dist/index.mjs
CHANGED
|
@@ -49,11 +49,18 @@ function camelCaseToWords(s) {
|
|
|
49
49
|
function replaceUnderscoresAndHyphensWithSpaces(s) {
|
|
50
50
|
return s.replace(/[-_]/g, " ");
|
|
51
51
|
}
|
|
52
|
+
function truncate(value, maxLength) {
|
|
53
|
+
if (value.length <= maxLength) {
|
|
54
|
+
return value;
|
|
55
|
+
}
|
|
56
|
+
return `${value.slice(0, maxLength)}...`;
|
|
57
|
+
}
|
|
52
58
|
export {
|
|
53
59
|
camelCaseToWords,
|
|
54
60
|
capitalizeFirstLetter,
|
|
55
61
|
replaceUnderscoresAndHyphensWithSpaces,
|
|
56
62
|
retryWhenFailed,
|
|
63
|
+
truncate,
|
|
57
64
|
tryParseJson
|
|
58
65
|
};
|
|
59
66
|
//# sourceMappingURL=index.mjs.map
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/json.ts","../src/retry.ts","../src/string.ts"],"sourcesContent":["/**\n * Attempts to parse a JSON string into a typed value, returning a default value if parsing fails.\n *\n * @param value - The JSON string to parse\n * @param defaultValue - The value to return if parsing fails or results in null/undefined\n * @returns The parsed JSON value as type T, or the default value if parsing fails\n *\n * @example\n * import { tryParseJson } from \"@settlemint/sdk-utils\";\n *\n * const config = tryParseJson<{ port: number }>(\n * '{\"port\": 3000}',\n * { port: 8080 }\n * );\n * // Returns: { port: 3000 }\n *\n * const invalid = tryParseJson<string[]>(\n * 'invalid json',\n * []\n * );\n * // Returns: []\n */\nexport function tryParseJson<T>(value: string, defaultValue: T | null = null): T | null {\n try {\n const parsed = JSON.parse(value) as T;\n if (parsed === undefined || parsed === null) {\n return defaultValue;\n }\n return parsed;\n } catch (err) {\n // Invalid json\n return defaultValue;\n }\n}\n","/**\n * 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 attempt = 0;\n\n while (attempt < maxRetries) {\n try {\n return await fn();\n } catch (e) {\n if (typeof stopOnError === \"function\") {\n const error = e as Error;\n if (stopOnError(error)) {\n throw error;\n }\n }\n attempt += 1;\n if (attempt >= maxRetries) {\n throw e;\n }\n // Exponential backoff with full jitter to prevent thundering herd\n const jitter = Math.random();\n const delay = 2 ** attempt * initialSleepTime * jitter; // 0-1x of 1s, 2s, 4s base\n await new Promise((resolve) => setTimeout(resolve, delay));\n }\n }\n\n throw new Error(\"Retry failed\");\n}\n","/**\n * Capitalizes the first letter of a string.\n *\n * @param val - The string to capitalize\n * @returns The input string with its first letter capitalized\n *\n * @example\n * import { capitalizeFirstLetter } from \"@settlemint/sdk-utils\";\n *\n * const capitalized = capitalizeFirstLetter(\"hello\");\n * // Returns: \"Hello\"\n */\nexport function capitalizeFirstLetter(val: string) {\n return String(val).charAt(0).toUpperCase() + String(val).slice(1);\n}\n\n/**\n * Converts a camelCase string to a human-readable string.\n *\n * @param s - The camelCase string to convert\n * @returns The human-readable string\n *\n * @example\n * import { camelCaseToWords } from \"@settlemint/sdk-utils\";\n *\n * const words = camelCaseToWords(\"camelCaseString\");\n * // Returns: \"Camel Case String\"\n */\nexport function camelCaseToWords(s: string) {\n const result = s.replace(/([a-z])([A-Z])/g, \"$1 $2\");\n const withSpaces = result.replace(/([A-Z])([a-z])/g, \" $1$2\");\n const capitalized = capitalizeFirstLetter(withSpaces);\n return capitalized.replace(/\\s+/g, \" \").trim();\n}\n\n/**\n * Replaces underscores and hyphens with spaces.\n *\n * @param s - The string to replace underscores and hyphens with spaces\n * @returns The input string with underscores and hyphens replaced with spaces\n *\n * @example\n * import { replaceUnderscoresAndHyphensWithSpaces } from \"@settlemint/sdk-utils\";\n *\n * const result = replaceUnderscoresAndHyphensWithSpaces(\"Already_Spaced-Second\");\n * // Returns: \"Already Spaced Second\"\n */\nexport function replaceUnderscoresAndHyphensWithSpaces(s: string) {\n return s.replace(/[-_]/g, \" \");\n}\n"],"mappings":";AAsBO,SAAS,aAAgB,OAAe,eAAyB,MAAgB;AACtF,MAAI;AACF,UAAM,SAAS,KAAK,MAAM,KAAK;AAC/B,QAAI,WAAW,UAAa,WAAW,MAAM;AAC3C,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT,SAAS,KAAK;AAEZ,WAAO;AAAA,EACT;AACF;;;ACpBA,eAAsB,gBACpB,IACA,aAAa,GACb,mBAAmB,KACnB,aACY;AACZ,MAAI,UAAU;AAEd,SAAO,UAAU,YAAY;AAC3B,QAAI;AACF,aAAO,MAAM,GAAG;AAAA,IAClB,SAAS,GAAG;AACV,UAAI,OAAO,gBAAgB,YAAY;AACrC,cAAM,QAAQ;AACd,YAAI,YAAY,KAAK,GAAG;AACtB,gBAAM;AAAA,QACR;AAAA,MACF;AACA,iBAAW;AACX,UAAI,WAAW,YAAY;AACzB,cAAM;AAAA,MACR;AAEA,YAAM,SAAS,KAAK,OAAO;AAC3B,YAAM,QAAQ,KAAK,UAAU,mBAAmB;AAChD,YAAM,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,KAAK,CAAC;AAAA,IAC3D;AAAA,EACF;AAEA,QAAM,IAAI,MAAM,cAAc;AAChC;;;AC/BO,SAAS,sBAAsB,KAAa;AACjD,SAAO,OAAO,GAAG,EAAE,OAAO,CAAC,EAAE,YAAY,IAAI,OAAO,GAAG,EAAE,MAAM,CAAC;AAClE;AAcO,SAAS,iBAAiB,GAAW;AAC1C,QAAM,SAAS,EAAE,QAAQ,mBAAmB,OAAO;AACnD,QAAM,aAAa,OAAO,QAAQ,mBAAmB,OAAO;AAC5D,QAAM,cAAc,sBAAsB,UAAU;AACpD,SAAO,YAAY,QAAQ,QAAQ,GAAG,EAAE,KAAK;AAC/C;AAcO,SAAS,uCAAuC,GAAW;AAChE,SAAO,EAAE,QAAQ,SAAS,GAAG;AAC/B;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/json.ts","../src/retry.ts","../src/string.ts"],"sourcesContent":["/**\n * Attempts to parse a JSON string into a typed value, returning a default value if parsing fails.\n *\n * @param value - The JSON string to parse\n * @param defaultValue - The value to return if parsing fails or results in null/undefined\n * @returns The parsed JSON value as type T, or the default value if parsing fails\n *\n * @example\n * import { tryParseJson } from \"@settlemint/sdk-utils\";\n *\n * const config = tryParseJson<{ port: number }>(\n * '{\"port\": 3000}',\n * { port: 8080 }\n * );\n * // Returns: { port: 3000 }\n *\n * const invalid = tryParseJson<string[]>(\n * 'invalid json',\n * []\n * );\n * // Returns: []\n */\nexport function tryParseJson<T>(value: string, defaultValue: T | null = null): T | null {\n try {\n const parsed = JSON.parse(value) as T;\n if (parsed === undefined || parsed === null) {\n return defaultValue;\n }\n return parsed;\n } catch (err) {\n // Invalid json\n return defaultValue;\n }\n}\n","/**\n * 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 attempt = 0;\n\n while (attempt < maxRetries) {\n try {\n return await fn();\n } catch (e) {\n if (typeof stopOnError === \"function\") {\n const error = e as Error;\n if (stopOnError(error)) {\n throw error;\n }\n }\n attempt += 1;\n if (attempt >= maxRetries) {\n throw e;\n }\n // Exponential backoff with full jitter to prevent thundering herd\n const jitter = Math.random();\n const delay = 2 ** attempt * initialSleepTime * jitter; // 0-1x of 1s, 2s, 4s base\n await new Promise((resolve) => setTimeout(resolve, delay));\n }\n }\n\n throw new Error(\"Retry failed\");\n}\n","/**\n * Capitalizes the first letter of a string.\n *\n * @param val - The string to capitalize\n * @returns The input string with its first letter capitalized\n *\n * @example\n * import { capitalizeFirstLetter } from \"@settlemint/sdk-utils\";\n *\n * const capitalized = capitalizeFirstLetter(\"hello\");\n * // Returns: \"Hello\"\n */\nexport function capitalizeFirstLetter(val: string) {\n return String(val).charAt(0).toUpperCase() + String(val).slice(1);\n}\n\n/**\n * Converts a camelCase string to a human-readable string.\n *\n * @param s - The camelCase string to convert\n * @returns The human-readable string\n *\n * @example\n * import { camelCaseToWords } from \"@settlemint/sdk-utils\";\n *\n * const words = camelCaseToWords(\"camelCaseString\");\n * // Returns: \"Camel Case String\"\n */\nexport function camelCaseToWords(s: string) {\n const result = s.replace(/([a-z])([A-Z])/g, \"$1 $2\");\n const withSpaces = result.replace(/([A-Z])([a-z])/g, \" $1$2\");\n const capitalized = capitalizeFirstLetter(withSpaces);\n return capitalized.replace(/\\s+/g, \" \").trim();\n}\n\n/**\n * Replaces underscores and hyphens with spaces.\n *\n * @param s - The string to replace underscores and hyphens with spaces\n * @returns The input string with underscores and hyphens replaced with spaces\n *\n * @example\n * import { replaceUnderscoresAndHyphensWithSpaces } from \"@settlemint/sdk-utils\";\n *\n * const result = replaceUnderscoresAndHyphensWithSpaces(\"Already_Spaced-Second\");\n * // Returns: \"Already Spaced Second\"\n */\nexport function replaceUnderscoresAndHyphensWithSpaces(s: string) {\n return s.replace(/[-_]/g, \" \");\n}\n\n/**\n * Truncates a string to a maximum length and appends \"...\" if it is longer.\n *\n * @param value - The string to truncate\n * @param maxLength - The maximum length of the string\n * @returns The truncated string or the original string if it is shorter than the maximum length\n *\n * @example\n * import { truncate } from \"@settlemint/sdk-utils\";\n *\n * const truncated = truncate(\"Hello, world!\", 10);\n * // Returns: \"Hello, wor...\"\n */\nexport function truncate(value: string, maxLength: number) {\n if (value.length <= maxLength) {\n return value;\n }\n return `${value.slice(0, maxLength)}...`;\n}\n"],"mappings":";AAsBO,SAAS,aAAgB,OAAe,eAAyB,MAAgB;AACtF,MAAI;AACF,UAAM,SAAS,KAAK,MAAM,KAAK;AAC/B,QAAI,WAAW,UAAa,WAAW,MAAM;AAC3C,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT,SAAS,KAAK;AAEZ,WAAO;AAAA,EACT;AACF;;;ACpBA,eAAsB,gBACpB,IACA,aAAa,GACb,mBAAmB,KACnB,aACY;AACZ,MAAI,UAAU;AAEd,SAAO,UAAU,YAAY;AAC3B,QAAI;AACF,aAAO,MAAM,GAAG;AAAA,IAClB,SAAS,GAAG;AACV,UAAI,OAAO,gBAAgB,YAAY;AACrC,cAAM,QAAQ;AACd,YAAI,YAAY,KAAK,GAAG;AACtB,gBAAM;AAAA,QACR;AAAA,MACF;AACA,iBAAW;AACX,UAAI,WAAW,YAAY;AACzB,cAAM;AAAA,MACR;AAEA,YAAM,SAAS,KAAK,OAAO;AAC3B,YAAM,QAAQ,KAAK,UAAU,mBAAmB;AAChD,YAAM,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,KAAK,CAAC;AAAA,IAC3D;AAAA,EACF;AAEA,QAAM,IAAI,MAAM,cAAc;AAChC;;;AC/BO,SAAS,sBAAsB,KAAa;AACjD,SAAO,OAAO,GAAG,EAAE,OAAO,CAAC,EAAE,YAAY,IAAI,OAAO,GAAG,EAAE,MAAM,CAAC;AAClE;AAcO,SAAS,iBAAiB,GAAW;AAC1C,QAAM,SAAS,EAAE,QAAQ,mBAAmB,OAAO;AACnD,QAAM,aAAa,OAAO,QAAQ,mBAAmB,OAAO;AAC5D,QAAM,cAAc,sBAAsB,UAAU;AACpD,SAAO,YAAY,QAAQ,QAAQ,GAAG,EAAE,KAAK;AAC/C;AAcO,SAAS,uCAAuC,GAAW;AAChE,SAAO,EAAE,QAAQ,SAAS,GAAG;AAC/B;AAeO,SAAS,SAAS,OAAe,WAAmB;AACzD,MAAI,MAAM,UAAU,WAAW;AAC7B,WAAO;AAAA,EACT;AACA,SAAO,GAAG,MAAM,MAAM,GAAG,SAAS,CAAC;AACrC;","names":[]}
|
package/dist/logging.cjs
CHANGED
|
@@ -33,7 +33,7 @@ var maskTokens = (output) => {
|
|
|
33
33
|
|
|
34
34
|
// src/logging/logger.ts
|
|
35
35
|
function createLogger(options = {}) {
|
|
36
|
-
const { level = "
|
|
36
|
+
const { level = "warn", prefix = "" } = options;
|
|
37
37
|
const logLevels = {
|
|
38
38
|
debug: 0,
|
|
39
39
|
info: 1,
|
|
@@ -43,8 +43,10 @@ function createLogger(options = {}) {
|
|
|
43
43
|
};
|
|
44
44
|
const currentLevelValue = logLevels[level];
|
|
45
45
|
const formatArgs = (args) => {
|
|
46
|
-
if (args.length === 0)
|
|
47
|
-
|
|
46
|
+
if (args.length === 0 || args.every((arg) => arg === void 0 || arg === null)) {
|
|
47
|
+
return "";
|
|
48
|
+
}
|
|
49
|
+
const formatted = args.map((arg) => {
|
|
48
50
|
if (arg instanceof Error) {
|
|
49
51
|
return `
|
|
50
52
|
${arg.stack || arg.message}`;
|
|
@@ -55,6 +57,7 @@ ${JSON.stringify(arg, null, 2)}`;
|
|
|
55
57
|
}
|
|
56
58
|
return ` ${String(arg)}`;
|
|
57
59
|
}).join("");
|
|
60
|
+
return `, args:${formatted}`;
|
|
58
61
|
};
|
|
59
62
|
const shouldLog = (level2) => {
|
|
60
63
|
return logLevels[level2] >= currentLevelValue;
|
|
@@ -84,7 +87,17 @@ ${JSON.stringify(arg, null, 2)}`;
|
|
|
84
87
|
}
|
|
85
88
|
var logger = createLogger();
|
|
86
89
|
|
|
90
|
+
// src/string.ts
|
|
91
|
+
function truncate(value, maxLength) {
|
|
92
|
+
if (value.length <= maxLength) {
|
|
93
|
+
return value;
|
|
94
|
+
}
|
|
95
|
+
return `${value.slice(0, maxLength)}...`;
|
|
96
|
+
}
|
|
97
|
+
|
|
87
98
|
// src/logging/request-logger.ts
|
|
99
|
+
var WARNING_THRESHOLD = 500;
|
|
100
|
+
var TRUNCATE_LENGTH = 50;
|
|
88
101
|
function requestLogger(logger2, name, fn) {
|
|
89
102
|
return async (...args) => {
|
|
90
103
|
const start = Date.now();
|
|
@@ -93,12 +106,12 @@ function requestLogger(logger2, name, fn) {
|
|
|
93
106
|
} finally {
|
|
94
107
|
const end = Date.now();
|
|
95
108
|
const duration = end - start;
|
|
96
|
-
const body =
|
|
97
|
-
const message = `${name} path: ${args[0]},
|
|
98
|
-
if (duration >
|
|
99
|
-
logger2.warn(message);
|
|
109
|
+
const body = extractInfoFromBody(args[1]?.body ?? "{}");
|
|
110
|
+
const message = `${name} path: ${args[0]}, took ${formatDuration(duration)}`;
|
|
111
|
+
if (duration > WARNING_THRESHOLD) {
|
|
112
|
+
logger2.warn(message, body);
|
|
100
113
|
} else {
|
|
101
|
-
logger2.info(message);
|
|
114
|
+
logger2.info(message, body);
|
|
102
115
|
}
|
|
103
116
|
}
|
|
104
117
|
};
|
|
@@ -106,6 +119,30 @@ function requestLogger(logger2, name, fn) {
|
|
|
106
119
|
function formatDuration(duration) {
|
|
107
120
|
return duration < 1e3 ? `${duration}ms` : `${(duration / 1e3).toFixed(3)}s`;
|
|
108
121
|
}
|
|
122
|
+
function extractInfoFromBody(body) {
|
|
123
|
+
try {
|
|
124
|
+
const parsedBody = typeof body === "string" ? JSON.parse(body) : body;
|
|
125
|
+
if (parsedBody === null || parsedBody === void 0 || Object.keys(parsedBody).length === 0) {
|
|
126
|
+
return null;
|
|
127
|
+
}
|
|
128
|
+
const dataToKeep = {};
|
|
129
|
+
if ("query" in parsedBody) {
|
|
130
|
+
dataToKeep.query = truncate(parsedBody.query, TRUNCATE_LENGTH);
|
|
131
|
+
}
|
|
132
|
+
if ("variables" in parsedBody) {
|
|
133
|
+
dataToKeep.variables = truncate(JSON.stringify(parsedBody.variables), TRUNCATE_LENGTH);
|
|
134
|
+
}
|
|
135
|
+
if ("operationName" in parsedBody) {
|
|
136
|
+
dataToKeep.operationName = truncate(parsedBody.operationName, TRUNCATE_LENGTH);
|
|
137
|
+
}
|
|
138
|
+
if (Object.keys(dataToKeep).length > 0) {
|
|
139
|
+
return JSON.stringify(dataToKeep);
|
|
140
|
+
}
|
|
141
|
+
return truncate(JSON.stringify(parsedBody || "{}"), TRUNCATE_LENGTH);
|
|
142
|
+
} catch {
|
|
143
|
+
return "{}";
|
|
144
|
+
}
|
|
145
|
+
}
|
|
109
146
|
// Annotate the CommonJS export names for ESM import in node:
|
|
110
147
|
0 && (module.exports = {
|
|
111
148
|
createLogger,
|
package/dist/logging.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/logging.ts","../src/logging/mask-tokens.ts","../src/logging/logger.ts","../src/logging/request-logger.ts"],"sourcesContent":["export { createLogger, type Logger, type LoggerOptions, type LogLevel } from \"./logging/logger.js\";\nexport { requestLogger } from \"./logging/request-logger.js\";\nexport { maskTokens } from \"./logging/mask-tokens.js\";\n","/**\n * Masks sensitive SettleMint tokens in output text by replacing them with asterisks.\n * Handles personal access tokens (PAT), application access tokens (AAT), and service account tokens (SAT).\n *\n * @param output - The text string that may contain sensitive tokens\n * @returns The text with any sensitive tokens masked with asterisks\n * @example\n * import { maskTokens } from \"@settlemint/sdk-utils/terminal\";\n *\n * // Masks a token in text\n * const masked = maskTokens(\"Token: sm_pat_****\"); // \"Token: ***\"\n */\nexport const maskTokens = (output: string): string => {\n return output.replace(/sm_(pat|aat|sat)_[0-9a-zA-Z]+/g, \"***\");\n};\n","import { maskTokens } from \"./mask-tokens.js\";\n\n/**\n * Log levels supported by the logger\n */\nexport type LogLevel = \"debug\" | \"info\" | \"warn\" | \"error\" | \"none\";\n\n/**\n * Configuration options for the logger\n * @interface LoggerOptions\n */\nexport interface LoggerOptions {\n /** The minimum log level to output */\n level?: LogLevel;\n /** The prefix to add to the log message */\n prefix?: string;\n}\n\n/**\n * Simple logger interface with basic logging methods\n * @interface Logger\n */\nexport interface Logger {\n /** Log debug information */\n debug: (message: string, ...args: unknown[]) => void;\n /** Log general information */\n info: (message: string, ...args: unknown[]) => void;\n /** Log warnings */\n warn: (message: string, ...args: unknown[]) => void;\n /** Log errors */\n error: (message: string, ...args: unknown[]) => void;\n}\n\n/**\n * Creates a simple logger with configurable log level\n *\n * @param options - Configuration options for the logger\n * @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 = \"info\", 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) return \"\";\n\n return 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\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 type { Logger } from \"./logger.js\";\n\n/**\n * Logs the request and duration of a fetch call (> 3s is logged as warn, otherwise info)\n * @param logger - The logger to use\n * @param name - The name of the request\n * @param fn - The fetch function to use\n * @returns The fetch function\n */\nexport function requestLogger(logger: Logger, name: string, fn: typeof fetch) {\n return async (...args: Parameters<typeof fetch>) => {\n const start = Date.now();\n try {\n return await fn(...args);\n } finally {\n const end = Date.now();\n const duration = end - start;\n const body = args[1]\n ? typeof args[1]?.body === \"string\"\n ? args[1]?.body\n : JSON.stringify(args[1]?.body ?? {})\n : \"{}\";\n const message = `${name} path: ${args[0]}, body: ${body}, took ${formatDuration(duration)}`;\n if (duration > 3000) {\n logger.warn(message);\n } else {\n logger.info(message);\n }\n }\n };\n}\n\nfunction formatDuration(duration: number) {\n return duration < 1000 ? `${duration}ms` : `${(duration / 1000).toFixed(3)}s`;\n}\n"],"mappings":"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","names":["level","logger"]}
|
|
1
|
+
{"version":3,"sources":["../src/logging.ts","../src/logging/mask-tokens.ts","../src/logging/logger.ts","../src/string.ts","../src/logging/request-logger.ts"],"sourcesContent":["export { createLogger, type Logger, type LoggerOptions, type LogLevel } from \"./logging/logger.js\";\nexport { requestLogger } from \"./logging/request-logger.js\";\nexport { maskTokens } from \"./logging/mask-tokens.js\";\n","/**\n * Masks sensitive SettleMint tokens in output text by replacing them with asterisks.\n * Handles personal access tokens (PAT), application access tokens (AAT), and service account tokens (SAT).\n *\n * @param output - The text string that may contain sensitive tokens\n * @returns The text with any sensitive tokens masked with asterisks\n * @example\n * import { maskTokens } from \"@settlemint/sdk-utils/terminal\";\n *\n * // Masks a token in text\n * const masked = maskTokens(\"Token: sm_pat_****\"); // \"Token: ***\"\n */\nexport const maskTokens = (output: string): string => {\n return output.replace(/sm_(pat|aat|sat)_[0-9a-zA-Z]+/g, \"***\");\n};\n","import { maskTokens } from \"./mask-tokens.js\";\n\n/**\n * Log levels supported by the logger\n */\nexport type LogLevel = \"debug\" | \"info\" | \"warn\" | \"error\" | \"none\";\n\n/**\n * Configuration options for the logger\n * @interface LoggerOptions\n */\nexport interface LoggerOptions {\n /** The minimum log level to output */\n level?: LogLevel;\n /** The prefix to add to the log message */\n prefix?: string;\n}\n\n/**\n * Simple logger interface with basic logging methods\n * @interface Logger\n */\nexport interface Logger {\n /** Log debug information */\n debug: (message: string, ...args: unknown[]) => void;\n /** Log general information */\n info: (message: string, ...args: unknown[]) => void;\n /** Log warnings */\n warn: (message: string, ...args: unknown[]) => void;\n /** Log errors */\n error: (message: string, ...args: unknown[]) => void;\n}\n\n/**\n * Creates a simple logger with configurable log level\n *\n * @param options - Configuration options for the logger\n * @param options.level - The minimum log level to output (default: warn)\n * @param options.prefix - The prefix to add to the log message (default: \"\")\n * @returns A logger instance with debug, info, warn, and error methods\n *\n * @example\n * import { createLogger } from \"@/utils/logging/logger\";\n *\n * const logger = createLogger({ level: 'info' });\n *\n * logger.info('User logged in', { userId: '123' });\n * logger.error('Operation failed', new Error('Connection timeout'));\n */\nexport function createLogger(options: LoggerOptions = {}): Logger {\n const { level = \"warn\", prefix = \"\" } = options;\n\n const logLevels: Record<LogLevel, number> = {\n debug: 0,\n info: 1,\n warn: 2,\n error: 3,\n none: 4,\n };\n\n const currentLevelValue = logLevels[level];\n\n const formatArgs = (args: unknown[]): string => {\n if (args.length === 0 || args.every((arg) => arg === undefined || arg === null)) {\n return \"\";\n }\n\n const formatted = args\n .map((arg) => {\n if (arg instanceof Error) {\n return `\\n${arg.stack || arg.message}`;\n }\n if (typeof arg === \"object\" && arg !== null) {\n return `\\n${JSON.stringify(arg, null, 2)}`;\n }\n return ` ${String(arg)}`;\n })\n .join(\"\");\n\n return `, args:${formatted}`;\n };\n\n const shouldLog = (level: LogLevel): boolean => {\n return logLevels[level] >= currentLevelValue;\n };\n\n return {\n debug: (message: string, ...args: unknown[]) => {\n if (shouldLog(\"debug\")) {\n console.debug(`\\x1b[32m${prefix}[DEBUG] ${maskTokens(message)}${maskTokens(formatArgs(args))}\\x1b[0m`);\n }\n },\n info: (message: string, ...args: unknown[]) => {\n if (shouldLog(\"info\")) {\n console.info(`\\x1b[34m${prefix}[INFO] ${maskTokens(message)}${maskTokens(formatArgs(args))}\\x1b[0m`);\n }\n },\n warn: (message: string, ...args: unknown[]) => {\n if (shouldLog(\"warn\")) {\n console.warn(`\\x1b[33m${prefix}[WARN] ${maskTokens(message)}${maskTokens(formatArgs(args))}\\x1b[0m`);\n }\n },\n error: (message: string, ...args: unknown[]) => {\n if (shouldLog(\"error\")) {\n console.error(`\\x1b[31m${prefix}[ERROR] ${maskTokens(message)}${maskTokens(formatArgs(args))}\\x1b[0m`);\n }\n },\n };\n}\n\n/**\n * Default logger instance with standard configuration\n */\nexport const logger = createLogger();\n","/**\n * Capitalizes the first letter of a string.\n *\n * @param val - The string to capitalize\n * @returns The input string with its first letter capitalized\n *\n * @example\n * import { capitalizeFirstLetter } from \"@settlemint/sdk-utils\";\n *\n * const capitalized = capitalizeFirstLetter(\"hello\");\n * // Returns: \"Hello\"\n */\nexport function capitalizeFirstLetter(val: string) {\n return String(val).charAt(0).toUpperCase() + String(val).slice(1);\n}\n\n/**\n * Converts a camelCase string to a human-readable string.\n *\n * @param s - The camelCase string to convert\n * @returns The human-readable string\n *\n * @example\n * import { camelCaseToWords } from \"@settlemint/sdk-utils\";\n *\n * const words = camelCaseToWords(\"camelCaseString\");\n * // Returns: \"Camel Case String\"\n */\nexport function camelCaseToWords(s: string) {\n const result = s.replace(/([a-z])([A-Z])/g, \"$1 $2\");\n const withSpaces = result.replace(/([A-Z])([a-z])/g, \" $1$2\");\n const capitalized = capitalizeFirstLetter(withSpaces);\n return capitalized.replace(/\\s+/g, \" \").trim();\n}\n\n/**\n * Replaces underscores and hyphens with spaces.\n *\n * @param s - The string to replace underscores and hyphens with spaces\n * @returns The input string with underscores and hyphens replaced with spaces\n *\n * @example\n * import { replaceUnderscoresAndHyphensWithSpaces } from \"@settlemint/sdk-utils\";\n *\n * const result = replaceUnderscoresAndHyphensWithSpaces(\"Already_Spaced-Second\");\n * // Returns: \"Already Spaced Second\"\n */\nexport function replaceUnderscoresAndHyphensWithSpaces(s: string) {\n return s.replace(/[-_]/g, \" \");\n}\n\n/**\n * Truncates a string to a maximum length and appends \"...\" if it is longer.\n *\n * @param value - The string to truncate\n * @param maxLength - The maximum length of the string\n * @returns The truncated string or the original string if it is shorter than the maximum length\n *\n * @example\n * import { truncate } from \"@settlemint/sdk-utils\";\n *\n * const truncated = truncate(\"Hello, world!\", 10);\n * // Returns: \"Hello, wor...\"\n */\nexport function truncate(value: string, maxLength: number) {\n if (value.length <= maxLength) {\n return value;\n }\n return `${value.slice(0, maxLength)}...`;\n}\n","import { truncate } from \"../string.js\";\nimport type { Logger } from \"./logger.js\";\n\nconst WARNING_THRESHOLD = 500;\nconst TRUNCATE_LENGTH = 50;\n\n/**\n * Logs the request and duration of a fetch call (> 500ms is logged as warn, otherwise info)\n * @param logger - The logger to use\n * @param name - The name of the request\n * @param fn - The fetch function to use\n * @returns The fetch function\n */\nexport function requestLogger(logger: Logger, name: string, fn: typeof fetch) {\n return async (...args: Parameters<typeof fetch>) => {\n const start = Date.now();\n try {\n return await fn(...args);\n } finally {\n const end = Date.now();\n const duration = end - start;\n const body = extractInfoFromBody(args[1]?.body ?? \"{}\");\n const message = `${name} path: ${args[0]}, took ${formatDuration(duration)}`;\n if (duration > WARNING_THRESHOLD) {\n logger.warn(message, body);\n } else {\n logger.info(message, body);\n }\n }\n };\n}\n\nfunction formatDuration(duration: number) {\n return duration < 1000 ? `${duration}ms` : `${(duration / 1000).toFixed(3)}s`;\n}\n\nfunction extractInfoFromBody(body: BodyInit) {\n try {\n const parsedBody = typeof body === \"string\" ? JSON.parse(body) : body;\n\n if (parsedBody === null || parsedBody === undefined || Object.keys(parsedBody).length === 0) {\n return null;\n }\n\n const dataToKeep: Record<string, unknown> = {};\n // Check for graphql fields\n if (\"query\" in parsedBody) {\n dataToKeep.query = truncate(parsedBody.query, TRUNCATE_LENGTH);\n }\n if (\"variables\" in parsedBody) {\n dataToKeep.variables = truncate(JSON.stringify(parsedBody.variables), TRUNCATE_LENGTH);\n }\n if (\"operationName\" in parsedBody) {\n dataToKeep.operationName = truncate(parsedBody.operationName, TRUNCATE_LENGTH);\n }\n\n if (Object.keys(dataToKeep).length > 0) {\n return JSON.stringify(dataToKeep);\n }\n\n // Not graphql, return the body as is\n return truncate(JSON.stringify(parsedBody || \"{}\"), TRUNCATE_LENGTH);\n } catch {\n return \"{}\";\n }\n}\n"],"mappings":"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","names":["level","logger"]}
|
package/dist/logging.d.cts
CHANGED
|
@@ -30,6 +30,8 @@ interface Logger {
|
|
|
30
30
|
* Creates a simple logger with configurable log level
|
|
31
31
|
*
|
|
32
32
|
* @param options - Configuration options for the logger
|
|
33
|
+
* @param options.level - The minimum log level to output (default: warn)
|
|
34
|
+
* @param options.prefix - The prefix to add to the log message (default: "")
|
|
33
35
|
* @returns A logger instance with debug, info, warn, and error methods
|
|
34
36
|
*
|
|
35
37
|
* @example
|
|
@@ -43,7 +45,7 @@ interface Logger {
|
|
|
43
45
|
declare function createLogger(options?: LoggerOptions): Logger;
|
|
44
46
|
|
|
45
47
|
/**
|
|
46
|
-
* Logs the request and duration of a fetch call (>
|
|
48
|
+
* Logs the request and duration of a fetch call (> 500ms is logged as warn, otherwise info)
|
|
47
49
|
* @param logger - The logger to use
|
|
48
50
|
* @param name - The name of the request
|
|
49
51
|
* @param fn - The fetch function to use
|
package/dist/logging.d.ts
CHANGED
|
@@ -30,6 +30,8 @@ interface Logger {
|
|
|
30
30
|
* Creates a simple logger with configurable log level
|
|
31
31
|
*
|
|
32
32
|
* @param options - Configuration options for the logger
|
|
33
|
+
* @param options.level - The minimum log level to output (default: warn)
|
|
34
|
+
* @param options.prefix - The prefix to add to the log message (default: "")
|
|
33
35
|
* @returns A logger instance with debug, info, warn, and error methods
|
|
34
36
|
*
|
|
35
37
|
* @example
|
|
@@ -43,7 +45,7 @@ interface Logger {
|
|
|
43
45
|
declare function createLogger(options?: LoggerOptions): Logger;
|
|
44
46
|
|
|
45
47
|
/**
|
|
46
|
-
* Logs the request and duration of a fetch call (>
|
|
48
|
+
* Logs the request and duration of a fetch call (> 500ms is logged as warn, otherwise info)
|
|
47
49
|
* @param logger - The logger to use
|
|
48
50
|
* @param name - The name of the request
|
|
49
51
|
* @param fn - The fetch function to use
|
package/dist/logging.mjs
CHANGED
|
@@ -5,7 +5,7 @@ var maskTokens = (output) => {
|
|
|
5
5
|
|
|
6
6
|
// src/logging/logger.ts
|
|
7
7
|
function createLogger(options = {}) {
|
|
8
|
-
const { level = "
|
|
8
|
+
const { level = "warn", prefix = "" } = options;
|
|
9
9
|
const logLevels = {
|
|
10
10
|
debug: 0,
|
|
11
11
|
info: 1,
|
|
@@ -15,8 +15,10 @@ function createLogger(options = {}) {
|
|
|
15
15
|
};
|
|
16
16
|
const currentLevelValue = logLevels[level];
|
|
17
17
|
const formatArgs = (args) => {
|
|
18
|
-
if (args.length === 0)
|
|
19
|
-
|
|
18
|
+
if (args.length === 0 || args.every((arg) => arg === void 0 || arg === null)) {
|
|
19
|
+
return "";
|
|
20
|
+
}
|
|
21
|
+
const formatted = args.map((arg) => {
|
|
20
22
|
if (arg instanceof Error) {
|
|
21
23
|
return `
|
|
22
24
|
${arg.stack || arg.message}`;
|
|
@@ -27,6 +29,7 @@ ${JSON.stringify(arg, null, 2)}`;
|
|
|
27
29
|
}
|
|
28
30
|
return ` ${String(arg)}`;
|
|
29
31
|
}).join("");
|
|
32
|
+
return `, args:${formatted}`;
|
|
30
33
|
};
|
|
31
34
|
const shouldLog = (level2) => {
|
|
32
35
|
return logLevels[level2] >= currentLevelValue;
|
|
@@ -56,7 +59,17 @@ ${JSON.stringify(arg, null, 2)}`;
|
|
|
56
59
|
}
|
|
57
60
|
var logger = createLogger();
|
|
58
61
|
|
|
62
|
+
// src/string.ts
|
|
63
|
+
function truncate(value, maxLength) {
|
|
64
|
+
if (value.length <= maxLength) {
|
|
65
|
+
return value;
|
|
66
|
+
}
|
|
67
|
+
return `${value.slice(0, maxLength)}...`;
|
|
68
|
+
}
|
|
69
|
+
|
|
59
70
|
// src/logging/request-logger.ts
|
|
71
|
+
var WARNING_THRESHOLD = 500;
|
|
72
|
+
var TRUNCATE_LENGTH = 50;
|
|
60
73
|
function requestLogger(logger2, name, fn) {
|
|
61
74
|
return async (...args) => {
|
|
62
75
|
const start = Date.now();
|
|
@@ -65,12 +78,12 @@ function requestLogger(logger2, name, fn) {
|
|
|
65
78
|
} finally {
|
|
66
79
|
const end = Date.now();
|
|
67
80
|
const duration = end - start;
|
|
68
|
-
const body =
|
|
69
|
-
const message = `${name} path: ${args[0]},
|
|
70
|
-
if (duration >
|
|
71
|
-
logger2.warn(message);
|
|
81
|
+
const body = extractInfoFromBody(args[1]?.body ?? "{}");
|
|
82
|
+
const message = `${name} path: ${args[0]}, took ${formatDuration(duration)}`;
|
|
83
|
+
if (duration > WARNING_THRESHOLD) {
|
|
84
|
+
logger2.warn(message, body);
|
|
72
85
|
} else {
|
|
73
|
-
logger2.info(message);
|
|
86
|
+
logger2.info(message, body);
|
|
74
87
|
}
|
|
75
88
|
}
|
|
76
89
|
};
|
|
@@ -78,6 +91,30 @@ function requestLogger(logger2, name, fn) {
|
|
|
78
91
|
function formatDuration(duration) {
|
|
79
92
|
return duration < 1e3 ? `${duration}ms` : `${(duration / 1e3).toFixed(3)}s`;
|
|
80
93
|
}
|
|
94
|
+
function extractInfoFromBody(body) {
|
|
95
|
+
try {
|
|
96
|
+
const parsedBody = typeof body === "string" ? JSON.parse(body) : body;
|
|
97
|
+
if (parsedBody === null || parsedBody === void 0 || Object.keys(parsedBody).length === 0) {
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
const dataToKeep = {};
|
|
101
|
+
if ("query" in parsedBody) {
|
|
102
|
+
dataToKeep.query = truncate(parsedBody.query, TRUNCATE_LENGTH);
|
|
103
|
+
}
|
|
104
|
+
if ("variables" in parsedBody) {
|
|
105
|
+
dataToKeep.variables = truncate(JSON.stringify(parsedBody.variables), TRUNCATE_LENGTH);
|
|
106
|
+
}
|
|
107
|
+
if ("operationName" in parsedBody) {
|
|
108
|
+
dataToKeep.operationName = truncate(parsedBody.operationName, TRUNCATE_LENGTH);
|
|
109
|
+
}
|
|
110
|
+
if (Object.keys(dataToKeep).length > 0) {
|
|
111
|
+
return JSON.stringify(dataToKeep);
|
|
112
|
+
}
|
|
113
|
+
return truncate(JSON.stringify(parsedBody || "{}"), TRUNCATE_LENGTH);
|
|
114
|
+
} catch {
|
|
115
|
+
return "{}";
|
|
116
|
+
}
|
|
117
|
+
}
|
|
81
118
|
export {
|
|
82
119
|
createLogger,
|
|
83
120
|
maskTokens,
|
package/dist/logging.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/logging/mask-tokens.ts","../src/logging/logger.ts","../src/logging/request-logger.ts"],"sourcesContent":["/**\n * Masks sensitive SettleMint tokens in output text by replacing them with asterisks.\n * Handles personal access tokens (PAT), application access tokens (AAT), and service account tokens (SAT).\n *\n * @param output - The text string that may contain sensitive tokens\n * @returns The text with any sensitive tokens masked with asterisks\n * @example\n * import { maskTokens } from \"@settlemint/sdk-utils/terminal\";\n *\n * // Masks a token in text\n * const masked = maskTokens(\"Token: sm_pat_****\"); // \"Token: ***\"\n */\nexport const maskTokens = (output: string): string => {\n return output.replace(/sm_(pat|aat|sat)_[0-9a-zA-Z]+/g, \"***\");\n};\n","import { maskTokens } from \"./mask-tokens.js\";\n\n/**\n * Log levels supported by the logger\n */\nexport type LogLevel = \"debug\" | \"info\" | \"warn\" | \"error\" | \"none\";\n\n/**\n * Configuration options for the logger\n * @interface LoggerOptions\n */\nexport interface LoggerOptions {\n /** The minimum log level to output */\n level?: LogLevel;\n /** The prefix to add to the log message */\n prefix?: string;\n}\n\n/**\n * Simple logger interface with basic logging methods\n * @interface Logger\n */\nexport interface Logger {\n /** Log debug information */\n debug: (message: string, ...args: unknown[]) => void;\n /** Log general information */\n info: (message: string, ...args: unknown[]) => void;\n /** Log warnings */\n warn: (message: string, ...args: unknown[]) => void;\n /** Log errors */\n error: (message: string, ...args: unknown[]) => void;\n}\n\n/**\n * Creates a simple logger with configurable log level\n *\n * @param options - Configuration options for the logger\n * @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 = \"info\", 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) return \"\";\n\n return 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\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 type { Logger } from \"./logger.js\";\n\n/**\n * Logs the request and duration of a fetch call (> 3s is logged as warn, otherwise info)\n * @param logger - The logger to use\n * @param name - The name of the request\n * @param fn - The fetch function to use\n * @returns The fetch function\n */\nexport function requestLogger(logger: Logger, name: string, fn: typeof fetch) {\n return async (...args: Parameters<typeof fetch>) => {\n const start = Date.now();\n try {\n return await fn(...args);\n } finally {\n const end = Date.now();\n const duration = end - start;\n const body = args[1]\n ? typeof args[1]?.body === \"string\"\n ? args[1]?.body\n : JSON.stringify(args[1]?.body ?? {})\n : \"{}\";\n const message = `${name} path: ${args[0]}, body: ${body}, took ${formatDuration(duration)}`;\n if (duration > 3000) {\n logger.warn(message);\n } else {\n logger.info(message);\n }\n }\n };\n}\n\nfunction formatDuration(duration: number) {\n return duration < 1000 ? `${duration}ms` : `${(duration / 1000).toFixed(3)}s`;\n}\n"],"mappings":";AAYO,IAAM,aAAa,CAAC,WAA2B;AACpD,SAAO,OAAO,QAAQ,kCAAkC,KAAK;AAC/D;;;ACiCO,SAAS,aAAa,UAAyB,CAAC,GAAW;AAChE,QAAM,EAAE,QAAQ,QAAQ,SAAS,GAAG,IAAI;AAExC,QAAM,YAAsC;AAAA,IAC1C,OAAO;AAAA,IACP,MAAM;AAAA,IACN,MAAM;AAAA,IACN,OAAO;AAAA,IACP,MAAM;AAAA,EACR;AAEA,QAAM,oBAAoB,UAAU,KAAK;AAEzC,QAAM,aAAa,CAAC,SAA4B;AAC9C,QAAI,KAAK,WAAW,EAAG,QAAO;AAE9B,WAAO,KACJ,IAAI,CAAC,QAAQ;AACZ,UAAI,eAAe,OAAO;AACxB,eAAO;AAAA,EAAK,IAAI,SAAS,IAAI,OAAO;AAAA,MACtC;AACA,UAAI,OAAO,QAAQ,YAAY,QAAQ,MAAM;AAC3C,eAAO;AAAA,EAAK,KAAK,UAAU,KAAK,MAAM,CAAC,CAAC;AAAA,MAC1C;AACA,aAAO,IAAI,OAAO,GAAG,CAAC;AAAA,IACxB,CAAC,EACA,KAAK,EAAE;AAAA,EACZ;AAEA,QAAM,YAAY,CAACA,WAA6B;AAC9C,WAAO,UAAUA,MAAK,KAAK;AAAA,EAC7B;AAEA,SAAO;AAAA,IACL,OAAO,CAAC,YAAoB,SAAoB;AAC9C,UAAI,UAAU,OAAO,GAAG;AACtB,gBAAQ,MAAM,WAAW,MAAM,WAAW,WAAW,OAAO,CAAC,GAAG,WAAW,WAAW,IAAI,CAAC,CAAC,SAAS;AAAA,MACvG;AAAA,IACF;AAAA,IACA,MAAM,CAAC,YAAoB,SAAoB;AAC7C,UAAI,UAAU,MAAM,GAAG;AACrB,gBAAQ,KAAK,WAAW,MAAM,UAAU,WAAW,OAAO,CAAC,GAAG,WAAW,WAAW,IAAI,CAAC,CAAC,SAAS;AAAA,MACrG;AAAA,IACF;AAAA,IACA,MAAM,CAAC,YAAoB,SAAoB;AAC7C,UAAI,UAAU,MAAM,GAAG;AACrB,gBAAQ,KAAK,WAAW,MAAM,UAAU,WAAW,OAAO,CAAC,GAAG,WAAW,WAAW,IAAI,CAAC,CAAC,SAAS;AAAA,MACrG;AAAA,IACF;AAAA,IACA,OAAO,CAAC,YAAoB,SAAoB;AAC9C,UAAI,UAAU,OAAO,GAAG;AACtB,gBAAQ,MAAM,WAAW,MAAM,WAAW,WAAW,OAAO,CAAC,GAAG,WAAW,WAAW,IAAI,CAAC,CAAC,SAAS;AAAA,MACvG;AAAA,IACF;AAAA,EACF;AACF;AAKO,IAAM,SAAS,aAAa;;;AClG5B,SAAS,cAAcC,SAAgB,MAAc,IAAkB;AAC5E,SAAO,UAAU,SAAmC;AAClD,UAAM,QAAQ,KAAK,IAAI;AACvB,QAAI;AACF,aAAO,MAAM,GAAG,GAAG,IAAI;AAAA,IACzB,UAAE;AACA,YAAM,MAAM,KAAK,IAAI;AACrB,YAAM,WAAW,MAAM;AACvB,YAAM,OAAO,KAAK,CAAC,IACf,OAAO,KAAK,CAAC,GAAG,SAAS,WACvB,KAAK,CAAC,GAAG,OACT,KAAK,UAAU,KAAK,CAAC,GAAG,QAAQ,CAAC,CAAC,IACpC;AACJ,YAAM,UAAU,GAAG,IAAI,UAAU,KAAK,CAAC,CAAC,WAAW,IAAI,UAAU,eAAe,QAAQ,CAAC;AACzF,UAAI,WAAW,KAAM;AACnB,QAAAA,QAAO,KAAK,OAAO;AAAA,MACrB,OAAO;AACL,QAAAA,QAAO,KAAK,OAAO;AAAA,MACrB;AAAA,IACF;AAAA,EACF;AACF;AAEA,SAAS,eAAe,UAAkB;AACxC,SAAO,WAAW,MAAO,GAAG,QAAQ,OAAO,IAAI,WAAW,KAAM,QAAQ,CAAC,CAAC;AAC5E;","names":["level","logger"]}
|
|
1
|
+
{"version":3,"sources":["../src/logging/mask-tokens.ts","../src/logging/logger.ts","../src/string.ts","../src/logging/request-logger.ts"],"sourcesContent":["/**\n * Masks sensitive SettleMint tokens in output text by replacing them with asterisks.\n * Handles personal access tokens (PAT), application access tokens (AAT), and service account tokens (SAT).\n *\n * @param output - The text string that may contain sensitive tokens\n * @returns The text with any sensitive tokens masked with asterisks\n * @example\n * import { maskTokens } from \"@settlemint/sdk-utils/terminal\";\n *\n * // Masks a token in text\n * const masked = maskTokens(\"Token: sm_pat_****\"); // \"Token: ***\"\n */\nexport const maskTokens = (output: string): string => {\n return output.replace(/sm_(pat|aat|sat)_[0-9a-zA-Z]+/g, \"***\");\n};\n","import { maskTokens } from \"./mask-tokens.js\";\n\n/**\n * Log levels supported by the logger\n */\nexport type LogLevel = \"debug\" | \"info\" | \"warn\" | \"error\" | \"none\";\n\n/**\n * Configuration options for the logger\n * @interface LoggerOptions\n */\nexport interface LoggerOptions {\n /** The minimum log level to output */\n level?: LogLevel;\n /** The prefix to add to the log message */\n prefix?: string;\n}\n\n/**\n * Simple logger interface with basic logging methods\n * @interface Logger\n */\nexport interface Logger {\n /** Log debug information */\n debug: (message: string, ...args: unknown[]) => void;\n /** Log general information */\n info: (message: string, ...args: unknown[]) => void;\n /** Log warnings */\n warn: (message: string, ...args: unknown[]) => void;\n /** Log errors */\n error: (message: string, ...args: unknown[]) => void;\n}\n\n/**\n * Creates a simple logger with configurable log level\n *\n * @param options - Configuration options for the logger\n * @param options.level - The minimum log level to output (default: warn)\n * @param options.prefix - The prefix to add to the log message (default: \"\")\n * @returns A logger instance with debug, info, warn, and error methods\n *\n * @example\n * import { createLogger } from \"@/utils/logging/logger\";\n *\n * const logger = createLogger({ level: 'info' });\n *\n * logger.info('User logged in', { userId: '123' });\n * logger.error('Operation failed', new Error('Connection timeout'));\n */\nexport function createLogger(options: LoggerOptions = {}): Logger {\n const { level = \"warn\", prefix = \"\" } = options;\n\n const logLevels: Record<LogLevel, number> = {\n debug: 0,\n info: 1,\n warn: 2,\n error: 3,\n none: 4,\n };\n\n const currentLevelValue = logLevels[level];\n\n const formatArgs = (args: unknown[]): string => {\n if (args.length === 0 || args.every((arg) => arg === undefined || arg === null)) {\n return \"\";\n }\n\n const formatted = args\n .map((arg) => {\n if (arg instanceof Error) {\n return `\\n${arg.stack || arg.message}`;\n }\n if (typeof arg === \"object\" && arg !== null) {\n return `\\n${JSON.stringify(arg, null, 2)}`;\n }\n return ` ${String(arg)}`;\n })\n .join(\"\");\n\n return `, args:${formatted}`;\n };\n\n const shouldLog = (level: LogLevel): boolean => {\n return logLevels[level] >= currentLevelValue;\n };\n\n return {\n debug: (message: string, ...args: unknown[]) => {\n if (shouldLog(\"debug\")) {\n console.debug(`\\x1b[32m${prefix}[DEBUG] ${maskTokens(message)}${maskTokens(formatArgs(args))}\\x1b[0m`);\n }\n },\n info: (message: string, ...args: unknown[]) => {\n if (shouldLog(\"info\")) {\n console.info(`\\x1b[34m${prefix}[INFO] ${maskTokens(message)}${maskTokens(formatArgs(args))}\\x1b[0m`);\n }\n },\n warn: (message: string, ...args: unknown[]) => {\n if (shouldLog(\"warn\")) {\n console.warn(`\\x1b[33m${prefix}[WARN] ${maskTokens(message)}${maskTokens(formatArgs(args))}\\x1b[0m`);\n }\n },\n error: (message: string, ...args: unknown[]) => {\n if (shouldLog(\"error\")) {\n console.error(`\\x1b[31m${prefix}[ERROR] ${maskTokens(message)}${maskTokens(formatArgs(args))}\\x1b[0m`);\n }\n },\n };\n}\n\n/**\n * Default logger instance with standard configuration\n */\nexport const logger = createLogger();\n","/**\n * Capitalizes the first letter of a string.\n *\n * @param val - The string to capitalize\n * @returns The input string with its first letter capitalized\n *\n * @example\n * import { capitalizeFirstLetter } from \"@settlemint/sdk-utils\";\n *\n * const capitalized = capitalizeFirstLetter(\"hello\");\n * // Returns: \"Hello\"\n */\nexport function capitalizeFirstLetter(val: string) {\n return String(val).charAt(0).toUpperCase() + String(val).slice(1);\n}\n\n/**\n * Converts a camelCase string to a human-readable string.\n *\n * @param s - The camelCase string to convert\n * @returns The human-readable string\n *\n * @example\n * import { camelCaseToWords } from \"@settlemint/sdk-utils\";\n *\n * const words = camelCaseToWords(\"camelCaseString\");\n * // Returns: \"Camel Case String\"\n */\nexport function camelCaseToWords(s: string) {\n const result = s.replace(/([a-z])([A-Z])/g, \"$1 $2\");\n const withSpaces = result.replace(/([A-Z])([a-z])/g, \" $1$2\");\n const capitalized = capitalizeFirstLetter(withSpaces);\n return capitalized.replace(/\\s+/g, \" \").trim();\n}\n\n/**\n * Replaces underscores and hyphens with spaces.\n *\n * @param s - The string to replace underscores and hyphens with spaces\n * @returns The input string with underscores and hyphens replaced with spaces\n *\n * @example\n * import { replaceUnderscoresAndHyphensWithSpaces } from \"@settlemint/sdk-utils\";\n *\n * const result = replaceUnderscoresAndHyphensWithSpaces(\"Already_Spaced-Second\");\n * // Returns: \"Already Spaced Second\"\n */\nexport function replaceUnderscoresAndHyphensWithSpaces(s: string) {\n return s.replace(/[-_]/g, \" \");\n}\n\n/**\n * Truncates a string to a maximum length and appends \"...\" if it is longer.\n *\n * @param value - The string to truncate\n * @param maxLength - The maximum length of the string\n * @returns The truncated string or the original string if it is shorter than the maximum length\n *\n * @example\n * import { truncate } from \"@settlemint/sdk-utils\";\n *\n * const truncated = truncate(\"Hello, world!\", 10);\n * // Returns: \"Hello, wor...\"\n */\nexport function truncate(value: string, maxLength: number) {\n if (value.length <= maxLength) {\n return value;\n }\n return `${value.slice(0, maxLength)}...`;\n}\n","import { truncate } from \"../string.js\";\nimport type { Logger } from \"./logger.js\";\n\nconst WARNING_THRESHOLD = 500;\nconst TRUNCATE_LENGTH = 50;\n\n/**\n * Logs the request and duration of a fetch call (> 500ms is logged as warn, otherwise info)\n * @param logger - The logger to use\n * @param name - The name of the request\n * @param fn - The fetch function to use\n * @returns The fetch function\n */\nexport function requestLogger(logger: Logger, name: string, fn: typeof fetch) {\n return async (...args: Parameters<typeof fetch>) => {\n const start = Date.now();\n try {\n return await fn(...args);\n } finally {\n const end = Date.now();\n const duration = end - start;\n const body = extractInfoFromBody(args[1]?.body ?? \"{}\");\n const message = `${name} path: ${args[0]}, took ${formatDuration(duration)}`;\n if (duration > WARNING_THRESHOLD) {\n logger.warn(message, body);\n } else {\n logger.info(message, body);\n }\n }\n };\n}\n\nfunction formatDuration(duration: number) {\n return duration < 1000 ? `${duration}ms` : `${(duration / 1000).toFixed(3)}s`;\n}\n\nfunction extractInfoFromBody(body: BodyInit) {\n try {\n const parsedBody = typeof body === \"string\" ? JSON.parse(body) : body;\n\n if (parsedBody === null || parsedBody === undefined || Object.keys(parsedBody).length === 0) {\n return null;\n }\n\n const dataToKeep: Record<string, unknown> = {};\n // Check for graphql fields\n if (\"query\" in parsedBody) {\n dataToKeep.query = truncate(parsedBody.query, TRUNCATE_LENGTH);\n }\n if (\"variables\" in parsedBody) {\n dataToKeep.variables = truncate(JSON.stringify(parsedBody.variables), TRUNCATE_LENGTH);\n }\n if (\"operationName\" in parsedBody) {\n dataToKeep.operationName = truncate(parsedBody.operationName, TRUNCATE_LENGTH);\n }\n\n if (Object.keys(dataToKeep).length > 0) {\n return JSON.stringify(dataToKeep);\n }\n\n // Not graphql, return the body as is\n return truncate(JSON.stringify(parsedBody || \"{}\"), TRUNCATE_LENGTH);\n } catch {\n return \"{}\";\n }\n}\n"],"mappings":";AAYO,IAAM,aAAa,CAAC,WAA2B;AACpD,SAAO,OAAO,QAAQ,kCAAkC,KAAK;AAC/D;;;ACmCO,SAAS,aAAa,UAAyB,CAAC,GAAW;AAChE,QAAM,EAAE,QAAQ,QAAQ,SAAS,GAAG,IAAI;AAExC,QAAM,YAAsC;AAAA,IAC1C,OAAO;AAAA,IACP,MAAM;AAAA,IACN,MAAM;AAAA,IACN,OAAO;AAAA,IACP,MAAM;AAAA,EACR;AAEA,QAAM,oBAAoB,UAAU,KAAK;AAEzC,QAAM,aAAa,CAAC,SAA4B;AAC9C,QAAI,KAAK,WAAW,KAAK,KAAK,MAAM,CAAC,QAAQ,QAAQ,UAAa,QAAQ,IAAI,GAAG;AAC/E,aAAO;AAAA,IACT;AAEA,UAAM,YAAY,KACf,IAAI,CAAC,QAAQ;AACZ,UAAI,eAAe,OAAO;AACxB,eAAO;AAAA,EAAK,IAAI,SAAS,IAAI,OAAO;AAAA,MACtC;AACA,UAAI,OAAO,QAAQ,YAAY,QAAQ,MAAM;AAC3C,eAAO;AAAA,EAAK,KAAK,UAAU,KAAK,MAAM,CAAC,CAAC;AAAA,MAC1C;AACA,aAAO,IAAI,OAAO,GAAG,CAAC;AAAA,IACxB,CAAC,EACA,KAAK,EAAE;AAEV,WAAO,UAAU,SAAS;AAAA,EAC5B;AAEA,QAAM,YAAY,CAACA,WAA6B;AAC9C,WAAO,UAAUA,MAAK,KAAK;AAAA,EAC7B;AAEA,SAAO;AAAA,IACL,OAAO,CAAC,YAAoB,SAAoB;AAC9C,UAAI,UAAU,OAAO,GAAG;AACtB,gBAAQ,MAAM,WAAW,MAAM,WAAW,WAAW,OAAO,CAAC,GAAG,WAAW,WAAW,IAAI,CAAC,CAAC,SAAS;AAAA,MACvG;AAAA,IACF;AAAA,IACA,MAAM,CAAC,YAAoB,SAAoB;AAC7C,UAAI,UAAU,MAAM,GAAG;AACrB,gBAAQ,KAAK,WAAW,MAAM,UAAU,WAAW,OAAO,CAAC,GAAG,WAAW,WAAW,IAAI,CAAC,CAAC,SAAS;AAAA,MACrG;AAAA,IACF;AAAA,IACA,MAAM,CAAC,YAAoB,SAAoB;AAC7C,UAAI,UAAU,MAAM,GAAG;AACrB,gBAAQ,KAAK,WAAW,MAAM,UAAU,WAAW,OAAO,CAAC,GAAG,WAAW,WAAW,IAAI,CAAC,CAAC,SAAS;AAAA,MACrG;AAAA,IACF;AAAA,IACA,OAAO,CAAC,YAAoB,SAAoB;AAC9C,UAAI,UAAU,OAAO,GAAG;AACtB,gBAAQ,MAAM,WAAW,MAAM,WAAW,WAAW,OAAO,CAAC,GAAG,WAAW,WAAW,IAAI,CAAC,CAAC,SAAS;AAAA,MACvG;AAAA,IACF;AAAA,EACF;AACF;AAKO,IAAM,SAAS,aAAa;;;ACjD5B,SAAS,SAAS,OAAe,WAAmB;AACzD,MAAI,MAAM,UAAU,WAAW;AAC7B,WAAO;AAAA,EACT;AACA,SAAO,GAAG,MAAM,MAAM,GAAG,SAAS,CAAC;AACrC;;;AClEA,IAAM,oBAAoB;AAC1B,IAAM,kBAAkB;AASjB,SAAS,cAAcC,SAAgB,MAAc,IAAkB;AAC5E,SAAO,UAAU,SAAmC;AAClD,UAAM,QAAQ,KAAK,IAAI;AACvB,QAAI;AACF,aAAO,MAAM,GAAG,GAAG,IAAI;AAAA,IACzB,UAAE;AACA,YAAM,MAAM,KAAK,IAAI;AACrB,YAAM,WAAW,MAAM;AACvB,YAAM,OAAO,oBAAoB,KAAK,CAAC,GAAG,QAAQ,IAAI;AACtD,YAAM,UAAU,GAAG,IAAI,UAAU,KAAK,CAAC,CAAC,UAAU,eAAe,QAAQ,CAAC;AAC1E,UAAI,WAAW,mBAAmB;AAChC,QAAAA,QAAO,KAAK,SAAS,IAAI;AAAA,MAC3B,OAAO;AACL,QAAAA,QAAO,KAAK,SAAS,IAAI;AAAA,MAC3B;AAAA,IACF;AAAA,EACF;AACF;AAEA,SAAS,eAAe,UAAkB;AACxC,SAAO,WAAW,MAAO,GAAG,QAAQ,OAAO,IAAI,WAAW,KAAM,QAAQ,CAAC,CAAC;AAC5E;AAEA,SAAS,oBAAoB,MAAgB;AAC3C,MAAI;AACF,UAAM,aAAa,OAAO,SAAS,WAAW,KAAK,MAAM,IAAI,IAAI;AAEjE,QAAI,eAAe,QAAQ,eAAe,UAAa,OAAO,KAAK,UAAU,EAAE,WAAW,GAAG;AAC3F,aAAO;AAAA,IACT;AAEA,UAAM,aAAsC,CAAC;AAE7C,QAAI,WAAW,YAAY;AACzB,iBAAW,QAAQ,SAAS,WAAW,OAAO,eAAe;AAAA,IAC/D;AACA,QAAI,eAAe,YAAY;AAC7B,iBAAW,YAAY,SAAS,KAAK,UAAU,WAAW,SAAS,GAAG,eAAe;AAAA,IACvF;AACA,QAAI,mBAAmB,YAAY;AACjC,iBAAW,gBAAgB,SAAS,WAAW,eAAe,eAAe;AAAA,IAC/E;AAEA,QAAI,OAAO,KAAK,UAAU,EAAE,SAAS,GAAG;AACtC,aAAO,KAAK,UAAU,UAAU;AAAA,IAClC;AAGA,WAAO,SAAS,KAAK,UAAU,cAAc,IAAI,GAAG,eAAe;AAAA,EACrE,QAAQ;AACN,WAAO;AAAA,EACT;AACF;","names":["level","logger"]}
|
package/dist/terminal.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/terminal.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"],"sourcesContent":["export { ascii } from \"./terminal/ascii.js\";\nexport { cancel, CancelError } from \"./terminal/cancel.js\";\nexport { executeCommand, type ExecuteCommandOptions } from \"./terminal/execute-command.js\";\nexport { intro } from \"./terminal/intro.js\";\nexport { list } from \"./terminal/list.js\";\nexport { note } from \"./terminal/note.js\";\nexport { outro } from \"./terminal/outro.js\";\nexport { spinner, type SpinnerOptions, SpinnerError } from \"./terminal/spinner.js\";\nexport { table } from \"./terminal/table.js\";\n/**\n * @deprecated use @settlemint/sdk-utils/logging instead\n */\nexport { maskTokens } from \"./logging/mask-tokens.js\";\n","import { magentaBright } from \"yoctocolors\";\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 console.log(\n magentaBright(`\n _________ __ __ .__ _____ .__ __\n / _____/ _____/ |__/ |_| | ____ / \\\\ |__| _____/ |_\n \\\\_____ \\\\_/ __ \\\\ __\\\\ __\\\\ | _/ __ \\\\ / \\\\ / \\\\| |/ \\\\ __\\\\\n / \\\\ ___/| | | | | |_\\\\ ___// Y \\\\ | | \\\\ |\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 * 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 {Error} 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 child = spawn(command, args, { 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 (!options?.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 (!options?.silent) {\n process.stderr.write(maskedData);\n }\n output.push(maskedData);\n });\n child.on(\"error\", (err) => reject(err));\n child.on(\"close\", (code) => {\n if (code === 0 || code === null || code === 143) {\n process.stdin.unpipe(child.stdin);\n resolve(output);\n return;\n }\n reject(new Error(`Command \"${command}\" exited with code ${code}`));\n });\n });\n}\n","import { maskTokens } from \"@/logging/mask-tokens.js\";\nimport { magentaBright } from \"yoctocolors\";\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 console.log(\"\");\n console.log(magentaBright(maskTokens(msg)));\n console.log(\"\");\n};\n","import { maskTokens } from \"@/logging/mask-tokens.js\";\nimport { yellowBright } from \"yoctocolors\";\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 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 { 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 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\";\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) {\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","import { camelCaseToWords } from \"@/string.js\";\nimport { Table } from \"console-table-printer\";\nimport { whiteBright } from \"yoctocolors\";\nimport { note } from \"./note.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 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 table.addRows(data);\n table.printTable();\n}\n"],"mappings":"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","names":["import_yoctocolors","import_yoctocolors","import_yoctocolors","items","import_yoctocolors","import_yoctocolors","isInCi","spinner","yoctoSpinner","import_yoctocolors","table"]}
|
|
1
|
+
{"version":3,"sources":["../src/terminal.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"],"sourcesContent":["export { ascii } from \"./terminal/ascii.js\";\nexport { cancel, CancelError } from \"./terminal/cancel.js\";\nexport { executeCommand, type ExecuteCommandOptions } from \"./terminal/execute-command.js\";\nexport { intro } from \"./terminal/intro.js\";\nexport { list } from \"./terminal/list.js\";\nexport { note } from \"./terminal/note.js\";\nexport { outro } from \"./terminal/outro.js\";\nexport { spinner, type SpinnerOptions, SpinnerError } from \"./terminal/spinner.js\";\nexport { table } from \"./terminal/table.js\";\n/**\n * @deprecated use @settlemint/sdk-utils/logging instead\n */\nexport { maskTokens } from \"./logging/mask-tokens.js\";\n","import { magentaBright } from \"yoctocolors\";\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 console.log(\n magentaBright(`\n _________ __ __ .__ _____ .__ __\n / _____/ _____/ |__/ |_| | ____ / \\\\ |__| _____/ |_\n \\\\_____ \\\\_/ __ \\\\ __\\\\ __\\\\ | _/ __ \\\\ / \\\\ / \\\\| |/ \\\\ __\\\\\n / \\\\ ___/| | | | | |_\\\\ ___// Y \\\\ | | \\\\ |\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 * 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 {Error} 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 child = spawn(command, args, { 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 (!options?.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 (!options?.silent) {\n process.stderr.write(maskedData);\n }\n output.push(maskedData);\n });\n child.on(\"error\", (err) => reject(err));\n child.on(\"close\", (code) => {\n if (code === 0 || code === null || code === 143) {\n process.stdin.unpipe(child.stdin);\n resolve(output);\n return;\n }\n reject(new Error(`Command \"${command}\" exited with code ${code}`));\n });\n });\n}\n","import { maskTokens } from \"@/logging/mask-tokens.js\";\nimport { magentaBright } from \"yoctocolors\";\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 console.log(\"\");\n console.log(magentaBright(maskTokens(msg)));\n console.log(\"\");\n};\n","import { maskTokens } from \"@/logging/mask-tokens.js\";\nimport { yellowBright } from \"yoctocolors\";\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 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 { 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 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\";\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) {\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 { camelCaseToWords } from \"@/string.js\";\nimport { Table } from \"console-table-printer\";\nimport { whiteBright } from \"yoctocolors\";\nimport { note } from \"./note.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 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 table.addRows(data);\n table.printTable();\n}\n"],"mappings":"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","names":["import_yoctocolors","import_yoctocolors","import_yoctocolors","items","import_yoctocolors","import_yoctocolors","isInCi","spinner","yoctoSpinner","import_yoctocolors","table"]}
|