@n8n/utils 1.39.0 → 1.41.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (110) hide show
  1. package/dist/assert.cjs +2 -2
  2. package/dist/assert.cjs.map +1 -1
  3. package/dist/assert.mjs +1 -1
  4. package/dist/assert.mjs.map +1 -1
  5. package/dist/client-assertion.cjs +3 -3
  6. package/dist/client-assertion.cjs.map +1 -1
  7. package/dist/client-assertion.mjs +2 -3
  8. package/dist/client-assertion.mjs.map +1 -1
  9. package/dist/create-event-queue.cjs +2 -2
  10. package/dist/create-event-queue.cjs.map +1 -1
  11. package/dist/create-event-queue.mjs +1 -1
  12. package/dist/create-event-queue.mjs.map +1 -1
  13. package/dist/errors/ensure-error.cjs +9 -2
  14. package/dist/errors/ensure-error.cjs.map +1 -0
  15. package/dist/errors/ensure-error.mjs +8 -2
  16. package/dist/errors/ensure-error.mjs.map +1 -0
  17. package/dist/event-bus.cjs +2 -2
  18. package/dist/event-bus.cjs.map +1 -1
  19. package/dist/event-bus.d.cts +1 -1
  20. package/dist/event-bus.d.mts +1 -1
  21. package/dist/event-bus.mjs +1 -1
  22. package/dist/event-bus.mjs.map +1 -1
  23. package/dist/files/is-windows-file-path.cjs +2 -2
  24. package/dist/files/is-windows-file-path.cjs.map +1 -1
  25. package/dist/files/is-windows-file-path.mjs +1 -1
  26. package/dist/files/is-windows-file-path.mjs.map +1 -1
  27. package/dist/files/sanitize-filename.cjs +3 -3
  28. package/dist/files/sanitize-filename.cjs.map +1 -1
  29. package/dist/files/sanitize-filename.mjs +2 -2
  30. package/dist/files/sanitize-filename.mjs.map +1 -1
  31. package/dist/format-pem-block.cjs +41 -2
  32. package/dist/format-pem-block.cjs.map +1 -0
  33. package/dist/format-pem-block.mjs +40 -2
  34. package/dist/format-pem-block.mjs.map +1 -0
  35. package/dist/generate-nano-id.cjs +4 -5
  36. package/dist/generate-nano-id.cjs.map +1 -1
  37. package/dist/generate-nano-id.mjs +1 -2
  38. package/dist/generate-nano-id.mjs.map +1 -1
  39. package/dist/get-jwt-expiry.cjs +2 -2
  40. package/dist/get-jwt-expiry.cjs.map +1 -1
  41. package/dist/get-jwt-expiry.mjs +1 -1
  42. package/dist/get-jwt-expiry.mjs.map +1 -1
  43. package/dist/is-record.cjs +2 -2
  44. package/dist/is-record.cjs.map +1 -1
  45. package/dist/is-record.mjs +1 -1
  46. package/dist/is-record.mjs.map +1 -1
  47. package/dist/json/to-json-value.cjs +40 -0
  48. package/dist/json/to-json-value.cjs.map +1 -0
  49. package/dist/json/to-json-value.d.cts +10 -0
  50. package/dist/json/to-json-value.d.mts +10 -0
  51. package/dist/json/to-json-value.mjs +39 -0
  52. package/dist/json/to-json-value.mjs.map +1 -0
  53. package/dist/lazy-import.cjs +23 -0
  54. package/dist/lazy-import.cjs.map +1 -0
  55. package/dist/lazy-import.d.cts +5 -0
  56. package/dist/lazy-import.d.mts +5 -0
  57. package/dist/lazy-import.mjs +22 -0
  58. package/dist/lazy-import.mjs.map +1 -0
  59. package/dist/number/smart-decimal.cjs +2 -2
  60. package/dist/number/smart-decimal.cjs.map +1 -1
  61. package/dist/number/smart-decimal.mjs +1 -1
  62. package/dist/number/smart-decimal.mjs.map +1 -1
  63. package/dist/placeholder.cjs +2 -2
  64. package/dist/placeholder.cjs.map +1 -1
  65. package/dist/placeholder.mjs +1 -1
  66. package/dist/placeholder.mjs.map +1 -1
  67. package/dist/promise/deferred-promise.cjs +2 -2
  68. package/dist/promise/deferred-promise.cjs.map +1 -1
  69. package/dist/promise/deferred-promise.mjs +1 -1
  70. package/dist/promise/deferred-promise.mjs.map +1 -1
  71. package/dist/result.cjs +5 -4
  72. package/dist/result.cjs.map +1 -1
  73. package/dist/result.mjs +4 -4
  74. package/dist/result.mjs.map +1 -1
  75. package/dist/retry.cjs +2 -2
  76. package/dist/retry.cjs.map +1 -1
  77. package/dist/retry.mjs +1 -1
  78. package/dist/retry.mjs.map +1 -1
  79. package/dist/scrub-secrets.cjs +2 -2
  80. package/dist/scrub-secrets.cjs.map +1 -1
  81. package/dist/scrub-secrets.mjs +1 -1
  82. package/dist/scrub-secrets.mjs.map +1 -1
  83. package/dist/search/re-rank-search-results.cjs +2 -2
  84. package/dist/search/re-rank-search-results.cjs.map +1 -1
  85. package/dist/search/re-rank-search-results.mjs +1 -1
  86. package/dist/search/re-rank-search-results.mjs.map +1 -1
  87. package/dist/search/sublime-search.cjs +2 -2
  88. package/dist/search/sublime-search.cjs.map +1 -1
  89. package/dist/search/sublime-search.mjs +1 -1
  90. package/dist/search/sublime-search.mjs.map +1 -1
  91. package/dist/sort/sort-by-property.cjs +2 -2
  92. package/dist/sort/sort-by-property.cjs.map +1 -1
  93. package/dist/sort/sort-by-property.d.cts +1 -1
  94. package/dist/sort/sort-by-property.d.mts +1 -1
  95. package/dist/sort/sort-by-property.mjs +1 -1
  96. package/dist/sort/sort-by-property.mjs.map +1 -1
  97. package/dist/string/truncate.cjs +2 -2
  98. package/dist/string/truncate.cjs.map +1 -1
  99. package/dist/string/truncate.mjs +1 -1
  100. package/dist/string/truncate.mjs.map +1 -1
  101. package/dist/types.mjs +1 -1
  102. package/package.json +8 -8
  103. package/dist/ensure-error.cjs +0 -15
  104. package/dist/ensure-error.cjs.map +0 -1
  105. package/dist/ensure-error.mjs +0 -9
  106. package/dist/ensure-error.mjs.map +0 -1
  107. package/dist/format-pem-block2.cjs +0 -47
  108. package/dist/format-pem-block2.cjs.map +0 -1
  109. package/dist/format-pem-block2.mjs +0 -41
  110. package/dist/format-pem-block2.mjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"scrub-secrets.cjs","names":["SECRET_VALUE_PATTERNS: readonly RegExp[]"],"sources":["../src/scrub-secrets.ts"],"sourcesContent":["/**\n * Replace common credential patterns in free-form text with `[REDACTED]`.\n *\n * Used before persisting or transmitting user-supplied text (telemetry\n * excerpts, eval report HTML, free-form feedback) where keys/tokens\n * accidentally pasted into prompts or command lines could otherwise leak\n * downstream.\n *\n * Conservative by design: matches well-known prefixed tokens, explicit\n * `key=value` pairs, and quoted JSON/JS-object fields with sensitive\n * names. We don't attempt to redact arbitrary long opaque strings — false\n * positives on file paths, IDs, or base64 payloads would make the output\n * unreadable.\n */\nexport const SECRET_KEYS =\n\t'password|passwd|secret|credentials?|api[_-]?key|authorization|access[_-]?token|refresh[_-]?token|id[_-]?token|session[_-]?token|auth[_-]?token';\n\nexport const SECRET_VALUE_PATTERNS: readonly RegExp[] = [\n\t// PEM private-key blocks (RSA/EC/DSA/OpenSSH/PGP). Whole block, multiline.\n\t/-----BEGIN (?:RSA |EC |DSA |OPENSSH |PGP )?PRIVATE KEY-----[\\s\\S]*?-----END (?:RSA |EC |DSA |OPENSSH |PGP )?PRIVATE KEY-----/g,\n\t// JWTs: `eyJ<header>.eyJ<payload>.<signature>` (both leading segments are\n\t// base64url of a `{\"` object, which makes this highly distinctive).\n\t/\\beyJ[A-Za-z0-9_-]+\\.eyJ[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+/g,\n\t// Authorization-header substrings: `Bearer <token>`, `Basic <token>`, `Token <token>`\n\t/\\b(?:Bearer|Basic|Token)\\s+[A-Za-z0-9._~+/=-]{12,}/gi,\n\t// OpenAI / Anthropic API keys\n\t/\\bsk-(?:ant-|proj-)?[A-Za-z0-9_-]{16,}/g,\n\t// Stripe secret/restricted/publishable keys (`sk_live_…`, `rk_test_…`, …)\n\t/\\b(?:sk|rk|pk)_(?:live|test)_[A-Za-z0-9]{16,}/g,\n\t// Google API keys\n\t/\\bAIza[0-9A-Za-z_-]{35}\\b/g,\n\t// Slack tokens (xoxb, xoxp, xoxa, xoxr, xoxs, xoxo)\n\t/\\bxox[abprso]-[A-Za-z0-9-]{10,}/g,\n\t// GitHub tokens (ghp, ghs, gho, ghr, ghu)\n\t/\\bgh[psoru]_[A-Za-z0-9]{20,}/g,\n\t// GitHub fine-grained personal access tokens\n\t/\\bgithub_pat_[A-Za-z0-9_]{22,}/g,\n\t// AWS access key id\n\t/\\bAKIA[0-9A-Z]{16}\\b/g,\n\t// Telegram bot token (`<bot id>:<35-char secret>`, also inside `/bot…/` URLs)\n\t/\\b(?:bot)?\\d{8,10}:[A-Za-z0-9_-]{35}\\b/g,\n\t// Credentials embedded in a URL: `scheme://user:password@` — redact the userinfo.\n\t/(?<=:\\/\\/)[^\\s:/@]+:[^\\s:/@]+(?=@)/g,\n\t// JSON-shaped `\"key\": \"value\"` — matches the quoted field as a whole.\n\t// Run before the loose pattern so nested objects like\n\t// `{\"credentials\": {\"apiKey\": \"...\"}}` don't have the outer key consume\n\t// the inner key on its way to a non-quoted (object) value. The value\n\t// body uses the unrolled JSON-string idiom `(?:[^\"\\\\\\r\\n]|\\\\.)*`: the\n\t// negated class excludes the backslash so a backslash can only be consumed\n\t// by the `\\\\.` escape branch. Keep the two alternatives disjoint (don't\n\t// fold `\\\\` back into the negated class) — that keeps every run of\n\t// backslashes to a single, unambiguous parse, so matching stays fast on any\n\t// input. An escaped quote inside the value (`\"abc\\\"def\"`) still doesn't end\n\t// the match early, via the escape branch. The negative lookahead skips\n\t// values that are already a `[redacted]` / `[REDACTED]` / typed\n\t// `[REDACTED:<type>:<index>]` placeholder so this stays idempotent when\n\t// chained behind upstream object-walking redaction (langsmith trace\n\t// payloads, mcp-browser markers).\n\tnew RegExp(\n\t\t`\"(?:${SECRET_KEYS})\"\\\\s*:\\\\s*\"(?!\\\\[(?:redacted|REDACTED)(?::[^\"\\\\]]*)?\\\\]\")(?:[^\"\\\\\\\\\\\\r\\\\n]|\\\\\\\\.)*\"`,\n\t\t'gi',\n\t),\n\t// JS-object-shaped `'key': 'value'`\n\tnew RegExp(\n\t\t`'(?:${SECRET_KEYS})'\\\\s*:\\\\s*'(?!\\\\[(?:redacted|REDACTED)(?::[^'\\\\]]*)?\\\\]')(?:[^'\\\\\\\\\\\\r\\\\n]|\\\\\\\\.)*'`,\n\t\t'gi',\n\t),\n\t// Generic `password=...` / `api_key=...` / `secret=...` style assignments.\n\t// The negative lookbehind skips a keyword sitting at the `<type>` position of\n\t// an upstream `[REDACTED:<type>:<index>]` marker (e.g. mcp-browser output), so\n\t// the `secret:1]` tail isn't re-matched into a nested `[REDACTED:[REDACTED]`.\n\t// Checking only the `[REDACTED:` prefix suffices: inside a marker a keyword can\n\t// only start a `\\b` match right after that prefix — every other keyword-shaped\n\t// substring is preceded by `_` (snake_case type slug) or a digit, so no word\n\t// boundary opens there. The value lookahead skips values that are already a\n\t// redaction placeholder (bracketed, typed, or URL-safe bare form) — the same\n\t// idempotency convention as the quoted forms.\n\tnew RegExp(\n\t\t`(?<!\\\\[(?:redacted|REDACTED):)\\\\b(?:${SECRET_KEYS})\\\\s*[:=]\\\\s*(?!\\\\[?(?:redacted|REDACTED)\\\\b)\\\\S+`,\n\t\t'gi',\n\t),\n];\n\nexport function scrubSecretsInText(input: string): string {\n\tlet out = input;\n\tfor (const pattern of SECRET_VALUE_PATTERNS) {\n\t\tout = out.replace(pattern, '[REDACTED]');\n\t}\n\treturn out;\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAcA,MAAa,cACZ;AAED,MAAaA,wBAA2C;CAEvD;CAGA;CAEA;CAEA;CAEA;CAEA;CAEA;CAEA;CAEA;CAEA;CAEA;CAEA;CAgBA,IAAI,OACH,OAAO,YAAY,uFACnB,KACA;CAED,IAAI,OACH,OAAO,YAAY,uFACnB,KACA;CAWD,IAAI,OACH,uCAAuC,YAAY,oDACnD,KACA;CACD;AAED,SAAgB,mBAAmB,OAAuB;CACzD,IAAI,MAAM;AACV,MAAK,MAAM,WAAW,sBACrB,OAAM,IAAI,QAAQ,SAAS,aAAa;AAEzC,QAAO"}
1
+ {"version":3,"file":"scrub-secrets.cjs","names":[],"sources":["../src/scrub-secrets.ts"],"sourcesContent":["/**\n * Replace common credential patterns in free-form text with `[REDACTED]`.\n *\n * Used before persisting or transmitting user-supplied text (telemetry\n * excerpts, eval report HTML, free-form feedback) where keys/tokens\n * accidentally pasted into prompts or command lines could otherwise leak\n * downstream.\n *\n * Conservative by design: matches well-known prefixed tokens, explicit\n * `key=value` pairs, and quoted JSON/JS-object fields with sensitive\n * names. We don't attempt to redact arbitrary long opaque strings — false\n * positives on file paths, IDs, or base64 payloads would make the output\n * unreadable.\n */\nexport const SECRET_KEYS =\n\t'password|passwd|secret|credentials?|api[_-]?key|authorization|access[_-]?token|refresh[_-]?token|id[_-]?token|session[_-]?token|auth[_-]?token';\n\nexport const SECRET_VALUE_PATTERNS: readonly RegExp[] = [\n\t// PEM private-key blocks (RSA/EC/DSA/OpenSSH/PGP). Whole block, multiline.\n\t/-----BEGIN (?:RSA |EC |DSA |OPENSSH |PGP )?PRIVATE KEY-----[\\s\\S]*?-----END (?:RSA |EC |DSA |OPENSSH |PGP )?PRIVATE KEY-----/g,\n\t// JWTs: `eyJ<header>.eyJ<payload>.<signature>` (both leading segments are\n\t// base64url of a `{\"` object, which makes this highly distinctive).\n\t/\\beyJ[A-Za-z0-9_-]+\\.eyJ[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+/g,\n\t// Authorization-header substrings: `Bearer <token>`, `Basic <token>`, `Token <token>`\n\t/\\b(?:Bearer|Basic|Token)\\s+[A-Za-z0-9._~+/=-]{12,}/gi,\n\t// OpenAI / Anthropic API keys\n\t/\\bsk-(?:ant-|proj-)?[A-Za-z0-9_-]{16,}/g,\n\t// Stripe secret/restricted/publishable keys (`sk_live_…`, `rk_test_…`, …)\n\t/\\b(?:sk|rk|pk)_(?:live|test)_[A-Za-z0-9]{16,}/g,\n\t// Google API keys\n\t/\\bAIza[0-9A-Za-z_-]{35}\\b/g,\n\t// Slack tokens (xoxb, xoxp, xoxa, xoxr, xoxs, xoxo)\n\t/\\bxox[abprso]-[A-Za-z0-9-]{10,}/g,\n\t// GitHub tokens (ghp, ghs, gho, ghr, ghu)\n\t/\\bgh[psoru]_[A-Za-z0-9]{20,}/g,\n\t// GitHub fine-grained personal access tokens\n\t/\\bgithub_pat_[A-Za-z0-9_]{22,}/g,\n\t// AWS access key id\n\t/\\bAKIA[0-9A-Z]{16}\\b/g,\n\t// Telegram bot token (`<bot id>:<35-char secret>`, also inside `/bot…/` URLs)\n\t/\\b(?:bot)?\\d{8,10}:[A-Za-z0-9_-]{35}\\b/g,\n\t// Credentials embedded in a URL: `scheme://user:password@` — redact the userinfo.\n\t/(?<=:\\/\\/)[^\\s:/@]+:[^\\s:/@]+(?=@)/g,\n\t// JSON-shaped `\"key\": \"value\"` — matches the quoted field as a whole.\n\t// Run before the loose pattern so nested objects like\n\t// `{\"credentials\": {\"apiKey\": \"...\"}}` don't have the outer key consume\n\t// the inner key on its way to a non-quoted (object) value. The value\n\t// body uses the unrolled JSON-string idiom `(?:[^\"\\\\\\r\\n]|\\\\.)*`: the\n\t// negated class excludes the backslash so a backslash can only be consumed\n\t// by the `\\\\.` escape branch. Keep the two alternatives disjoint (don't\n\t// fold `\\\\` back into the negated class) — that keeps every run of\n\t// backslashes to a single, unambiguous parse, so matching stays fast on any\n\t// input. An escaped quote inside the value (`\"abc\\\"def\"`) still doesn't end\n\t// the match early, via the escape branch. The negative lookahead skips\n\t// values that are already a `[redacted]` / `[REDACTED]` / typed\n\t// `[REDACTED:<type>:<index>]` placeholder so this stays idempotent when\n\t// chained behind upstream object-walking redaction (langsmith trace\n\t// payloads, mcp-browser markers).\n\tnew RegExp(\n\t\t`\"(?:${SECRET_KEYS})\"\\\\s*:\\\\s*\"(?!\\\\[(?:redacted|REDACTED)(?::[^\"\\\\]]*)?\\\\]\")(?:[^\"\\\\\\\\\\\\r\\\\n]|\\\\\\\\.)*\"`,\n\t\t'gi',\n\t),\n\t// JS-object-shaped `'key': 'value'`\n\tnew RegExp(\n\t\t`'(?:${SECRET_KEYS})'\\\\s*:\\\\s*'(?!\\\\[(?:redacted|REDACTED)(?::[^'\\\\]]*)?\\\\]')(?:[^'\\\\\\\\\\\\r\\\\n]|\\\\\\\\.)*'`,\n\t\t'gi',\n\t),\n\t// Generic `password=...` / `api_key=...` / `secret=...` style assignments.\n\t// The negative lookbehind skips a keyword sitting at the `<type>` position of\n\t// an upstream `[REDACTED:<type>:<index>]` marker (e.g. mcp-browser output), so\n\t// the `secret:1]` tail isn't re-matched into a nested `[REDACTED:[REDACTED]`.\n\t// Checking only the `[REDACTED:` prefix suffices: inside a marker a keyword can\n\t// only start a `\\b` match right after that prefix — every other keyword-shaped\n\t// substring is preceded by `_` (snake_case type slug) or a digit, so no word\n\t// boundary opens there. The value lookahead skips values that are already a\n\t// redaction placeholder (bracketed, typed, or URL-safe bare form) — the same\n\t// idempotency convention as the quoted forms.\n\tnew RegExp(\n\t\t`(?<!\\\\[(?:redacted|REDACTED):)\\\\b(?:${SECRET_KEYS})\\\\s*[:=]\\\\s*(?!\\\\[?(?:redacted|REDACTED)\\\\b)\\\\S+`,\n\t\t'gi',\n\t),\n];\n\nexport function scrubSecretsInText(input: string): string {\n\tlet out = input;\n\tfor (const pattern of SECRET_VALUE_PATTERNS) {\n\t\tout = out.replace(pattern, '[REDACTED]');\n\t}\n\treturn out;\n}\n"],"mappings":";;;;;;;;;;;;;;;;AAcA,MAAa,cACZ;AAED,MAAa,wBAA2C;CAEvD;CAGA;CAEA;CAEA;CAEA;CAEA;CAEA;CAEA;CAEA;CAEA;CAEA;CAEA;CAgBA,IAAI,OACH,OAAO,YAAY,uFACnB,IACD;CAEA,IAAI,OACH,OAAO,YAAY,uFACnB,IACD;CAWA,IAAI,OACH,uCAAuC,YAAY,oDACnD,IACD;AACD;AAEA,SAAgB,mBAAmB,OAAuB;CACzD,IAAI,MAAM;CACV,KAAK,MAAM,WAAW,uBACrB,MAAM,IAAI,QAAQ,SAAS,YAAY;CAExC,OAAO;AACR"}
@@ -36,7 +36,7 @@ function scrubSecretsInText(input) {
36
36
  for (const pattern of SECRET_VALUE_PATTERNS) out = out.replace(pattern, "[REDACTED]");
37
37
  return out;
38
38
  }
39
-
40
39
  //#endregion
41
40
  export { SECRET_KEYS, SECRET_VALUE_PATTERNS, scrubSecretsInText };
41
+
42
42
  //# sourceMappingURL=scrub-secrets.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"scrub-secrets.mjs","names":["SECRET_VALUE_PATTERNS: readonly RegExp[]"],"sources":["../src/scrub-secrets.ts"],"sourcesContent":["/**\n * Replace common credential patterns in free-form text with `[REDACTED]`.\n *\n * Used before persisting or transmitting user-supplied text (telemetry\n * excerpts, eval report HTML, free-form feedback) where keys/tokens\n * accidentally pasted into prompts or command lines could otherwise leak\n * downstream.\n *\n * Conservative by design: matches well-known prefixed tokens, explicit\n * `key=value` pairs, and quoted JSON/JS-object fields with sensitive\n * names. We don't attempt to redact arbitrary long opaque strings — false\n * positives on file paths, IDs, or base64 payloads would make the output\n * unreadable.\n */\nexport const SECRET_KEYS =\n\t'password|passwd|secret|credentials?|api[_-]?key|authorization|access[_-]?token|refresh[_-]?token|id[_-]?token|session[_-]?token|auth[_-]?token';\n\nexport const SECRET_VALUE_PATTERNS: readonly RegExp[] = [\n\t// PEM private-key blocks (RSA/EC/DSA/OpenSSH/PGP). Whole block, multiline.\n\t/-----BEGIN (?:RSA |EC |DSA |OPENSSH |PGP )?PRIVATE KEY-----[\\s\\S]*?-----END (?:RSA |EC |DSA |OPENSSH |PGP )?PRIVATE KEY-----/g,\n\t// JWTs: `eyJ<header>.eyJ<payload>.<signature>` (both leading segments are\n\t// base64url of a `{\"` object, which makes this highly distinctive).\n\t/\\beyJ[A-Za-z0-9_-]+\\.eyJ[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+/g,\n\t// Authorization-header substrings: `Bearer <token>`, `Basic <token>`, `Token <token>`\n\t/\\b(?:Bearer|Basic|Token)\\s+[A-Za-z0-9._~+/=-]{12,}/gi,\n\t// OpenAI / Anthropic API keys\n\t/\\bsk-(?:ant-|proj-)?[A-Za-z0-9_-]{16,}/g,\n\t// Stripe secret/restricted/publishable keys (`sk_live_…`, `rk_test_…`, …)\n\t/\\b(?:sk|rk|pk)_(?:live|test)_[A-Za-z0-9]{16,}/g,\n\t// Google API keys\n\t/\\bAIza[0-9A-Za-z_-]{35}\\b/g,\n\t// Slack tokens (xoxb, xoxp, xoxa, xoxr, xoxs, xoxo)\n\t/\\bxox[abprso]-[A-Za-z0-9-]{10,}/g,\n\t// GitHub tokens (ghp, ghs, gho, ghr, ghu)\n\t/\\bgh[psoru]_[A-Za-z0-9]{20,}/g,\n\t// GitHub fine-grained personal access tokens\n\t/\\bgithub_pat_[A-Za-z0-9_]{22,}/g,\n\t// AWS access key id\n\t/\\bAKIA[0-9A-Z]{16}\\b/g,\n\t// Telegram bot token (`<bot id>:<35-char secret>`, also inside `/bot…/` URLs)\n\t/\\b(?:bot)?\\d{8,10}:[A-Za-z0-9_-]{35}\\b/g,\n\t// Credentials embedded in a URL: `scheme://user:password@` — redact the userinfo.\n\t/(?<=:\\/\\/)[^\\s:/@]+:[^\\s:/@]+(?=@)/g,\n\t// JSON-shaped `\"key\": \"value\"` — matches the quoted field as a whole.\n\t// Run before the loose pattern so nested objects like\n\t// `{\"credentials\": {\"apiKey\": \"...\"}}` don't have the outer key consume\n\t// the inner key on its way to a non-quoted (object) value. The value\n\t// body uses the unrolled JSON-string idiom `(?:[^\"\\\\\\r\\n]|\\\\.)*`: the\n\t// negated class excludes the backslash so a backslash can only be consumed\n\t// by the `\\\\.` escape branch. Keep the two alternatives disjoint (don't\n\t// fold `\\\\` back into the negated class) — that keeps every run of\n\t// backslashes to a single, unambiguous parse, so matching stays fast on any\n\t// input. An escaped quote inside the value (`\"abc\\\"def\"`) still doesn't end\n\t// the match early, via the escape branch. The negative lookahead skips\n\t// values that are already a `[redacted]` / `[REDACTED]` / typed\n\t// `[REDACTED:<type>:<index>]` placeholder so this stays idempotent when\n\t// chained behind upstream object-walking redaction (langsmith trace\n\t// payloads, mcp-browser markers).\n\tnew RegExp(\n\t\t`\"(?:${SECRET_KEYS})\"\\\\s*:\\\\s*\"(?!\\\\[(?:redacted|REDACTED)(?::[^\"\\\\]]*)?\\\\]\")(?:[^\"\\\\\\\\\\\\r\\\\n]|\\\\\\\\.)*\"`,\n\t\t'gi',\n\t),\n\t// JS-object-shaped `'key': 'value'`\n\tnew RegExp(\n\t\t`'(?:${SECRET_KEYS})'\\\\s*:\\\\s*'(?!\\\\[(?:redacted|REDACTED)(?::[^'\\\\]]*)?\\\\]')(?:[^'\\\\\\\\\\\\r\\\\n]|\\\\\\\\.)*'`,\n\t\t'gi',\n\t),\n\t// Generic `password=...` / `api_key=...` / `secret=...` style assignments.\n\t// The negative lookbehind skips a keyword sitting at the `<type>` position of\n\t// an upstream `[REDACTED:<type>:<index>]` marker (e.g. mcp-browser output), so\n\t// the `secret:1]` tail isn't re-matched into a nested `[REDACTED:[REDACTED]`.\n\t// Checking only the `[REDACTED:` prefix suffices: inside a marker a keyword can\n\t// only start a `\\b` match right after that prefix — every other keyword-shaped\n\t// substring is preceded by `_` (snake_case type slug) or a digit, so no word\n\t// boundary opens there. The value lookahead skips values that are already a\n\t// redaction placeholder (bracketed, typed, or URL-safe bare form) — the same\n\t// idempotency convention as the quoted forms.\n\tnew RegExp(\n\t\t`(?<!\\\\[(?:redacted|REDACTED):)\\\\b(?:${SECRET_KEYS})\\\\s*[:=]\\\\s*(?!\\\\[?(?:redacted|REDACTED)\\\\b)\\\\S+`,\n\t\t'gi',\n\t),\n];\n\nexport function scrubSecretsInText(input: string): string {\n\tlet out = input;\n\tfor (const pattern of SECRET_VALUE_PATTERNS) {\n\t\tout = out.replace(pattern, '[REDACTED]');\n\t}\n\treturn out;\n}\n"],"mappings":";;;;;;;;;;;;;;;AAcA,MAAa,cACZ;AAED,MAAaA,wBAA2C;CAEvD;CAGA;CAEA;CAEA;CAEA;CAEA;CAEA;CAEA;CAEA;CAEA;CAEA;CAEA;CAgBA,IAAI,OACH,OAAO,YAAY,uFACnB,KACA;CAED,IAAI,OACH,OAAO,YAAY,uFACnB,KACA;CAWD,IAAI,OACH,uCAAuC,YAAY,oDACnD,KACA;CACD;AAED,SAAgB,mBAAmB,OAAuB;CACzD,IAAI,MAAM;AACV,MAAK,MAAM,WAAW,sBACrB,OAAM,IAAI,QAAQ,SAAS,aAAa;AAEzC,QAAO"}
1
+ {"version":3,"file":"scrub-secrets.mjs","names":[],"sources":["../src/scrub-secrets.ts"],"sourcesContent":["/**\n * Replace common credential patterns in free-form text with `[REDACTED]`.\n *\n * Used before persisting or transmitting user-supplied text (telemetry\n * excerpts, eval report HTML, free-form feedback) where keys/tokens\n * accidentally pasted into prompts or command lines could otherwise leak\n * downstream.\n *\n * Conservative by design: matches well-known prefixed tokens, explicit\n * `key=value` pairs, and quoted JSON/JS-object fields with sensitive\n * names. We don't attempt to redact arbitrary long opaque strings — false\n * positives on file paths, IDs, or base64 payloads would make the output\n * unreadable.\n */\nexport const SECRET_KEYS =\n\t'password|passwd|secret|credentials?|api[_-]?key|authorization|access[_-]?token|refresh[_-]?token|id[_-]?token|session[_-]?token|auth[_-]?token';\n\nexport const SECRET_VALUE_PATTERNS: readonly RegExp[] = [\n\t// PEM private-key blocks (RSA/EC/DSA/OpenSSH/PGP). Whole block, multiline.\n\t/-----BEGIN (?:RSA |EC |DSA |OPENSSH |PGP )?PRIVATE KEY-----[\\s\\S]*?-----END (?:RSA |EC |DSA |OPENSSH |PGP )?PRIVATE KEY-----/g,\n\t// JWTs: `eyJ<header>.eyJ<payload>.<signature>` (both leading segments are\n\t// base64url of a `{\"` object, which makes this highly distinctive).\n\t/\\beyJ[A-Za-z0-9_-]+\\.eyJ[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+/g,\n\t// Authorization-header substrings: `Bearer <token>`, `Basic <token>`, `Token <token>`\n\t/\\b(?:Bearer|Basic|Token)\\s+[A-Za-z0-9._~+/=-]{12,}/gi,\n\t// OpenAI / Anthropic API keys\n\t/\\bsk-(?:ant-|proj-)?[A-Za-z0-9_-]{16,}/g,\n\t// Stripe secret/restricted/publishable keys (`sk_live_…`, `rk_test_…`, …)\n\t/\\b(?:sk|rk|pk)_(?:live|test)_[A-Za-z0-9]{16,}/g,\n\t// Google API keys\n\t/\\bAIza[0-9A-Za-z_-]{35}\\b/g,\n\t// Slack tokens (xoxb, xoxp, xoxa, xoxr, xoxs, xoxo)\n\t/\\bxox[abprso]-[A-Za-z0-9-]{10,}/g,\n\t// GitHub tokens (ghp, ghs, gho, ghr, ghu)\n\t/\\bgh[psoru]_[A-Za-z0-9]{20,}/g,\n\t// GitHub fine-grained personal access tokens\n\t/\\bgithub_pat_[A-Za-z0-9_]{22,}/g,\n\t// AWS access key id\n\t/\\bAKIA[0-9A-Z]{16}\\b/g,\n\t// Telegram bot token (`<bot id>:<35-char secret>`, also inside `/bot…/` URLs)\n\t/\\b(?:bot)?\\d{8,10}:[A-Za-z0-9_-]{35}\\b/g,\n\t// Credentials embedded in a URL: `scheme://user:password@` — redact the userinfo.\n\t/(?<=:\\/\\/)[^\\s:/@]+:[^\\s:/@]+(?=@)/g,\n\t// JSON-shaped `\"key\": \"value\"` — matches the quoted field as a whole.\n\t// Run before the loose pattern so nested objects like\n\t// `{\"credentials\": {\"apiKey\": \"...\"}}` don't have the outer key consume\n\t// the inner key on its way to a non-quoted (object) value. The value\n\t// body uses the unrolled JSON-string idiom `(?:[^\"\\\\\\r\\n]|\\\\.)*`: the\n\t// negated class excludes the backslash so a backslash can only be consumed\n\t// by the `\\\\.` escape branch. Keep the two alternatives disjoint (don't\n\t// fold `\\\\` back into the negated class) — that keeps every run of\n\t// backslashes to a single, unambiguous parse, so matching stays fast on any\n\t// input. An escaped quote inside the value (`\"abc\\\"def\"`) still doesn't end\n\t// the match early, via the escape branch. The negative lookahead skips\n\t// values that are already a `[redacted]` / `[REDACTED]` / typed\n\t// `[REDACTED:<type>:<index>]` placeholder so this stays idempotent when\n\t// chained behind upstream object-walking redaction (langsmith trace\n\t// payloads, mcp-browser markers).\n\tnew RegExp(\n\t\t`\"(?:${SECRET_KEYS})\"\\\\s*:\\\\s*\"(?!\\\\[(?:redacted|REDACTED)(?::[^\"\\\\]]*)?\\\\]\")(?:[^\"\\\\\\\\\\\\r\\\\n]|\\\\\\\\.)*\"`,\n\t\t'gi',\n\t),\n\t// JS-object-shaped `'key': 'value'`\n\tnew RegExp(\n\t\t`'(?:${SECRET_KEYS})'\\\\s*:\\\\s*'(?!\\\\[(?:redacted|REDACTED)(?::[^'\\\\]]*)?\\\\]')(?:[^'\\\\\\\\\\\\r\\\\n]|\\\\\\\\.)*'`,\n\t\t'gi',\n\t),\n\t// Generic `password=...` / `api_key=...` / `secret=...` style assignments.\n\t// The negative lookbehind skips a keyword sitting at the `<type>` position of\n\t// an upstream `[REDACTED:<type>:<index>]` marker (e.g. mcp-browser output), so\n\t// the `secret:1]` tail isn't re-matched into a nested `[REDACTED:[REDACTED]`.\n\t// Checking only the `[REDACTED:` prefix suffices: inside a marker a keyword can\n\t// only start a `\\b` match right after that prefix — every other keyword-shaped\n\t// substring is preceded by `_` (snake_case type slug) or a digit, so no word\n\t// boundary opens there. The value lookahead skips values that are already a\n\t// redaction placeholder (bracketed, typed, or URL-safe bare form) — the same\n\t// idempotency convention as the quoted forms.\n\tnew RegExp(\n\t\t`(?<!\\\\[(?:redacted|REDACTED):)\\\\b(?:${SECRET_KEYS})\\\\s*[:=]\\\\s*(?!\\\\[?(?:redacted|REDACTED)\\\\b)\\\\S+`,\n\t\t'gi',\n\t),\n];\n\nexport function scrubSecretsInText(input: string): string {\n\tlet out = input;\n\tfor (const pattern of SECRET_VALUE_PATTERNS) {\n\t\tout = out.replace(pattern, '[REDACTED]');\n\t}\n\treturn out;\n}\n"],"mappings":";;;;;;;;;;;;;;;AAcA,MAAa,cACZ;AAED,MAAa,wBAA2C;CAEvD;CAGA;CAEA;CAEA;CAEA;CAEA;CAEA;CAEA;CAEA;CAEA;CAEA;CAEA;CAgBA,IAAI,OACH,OAAO,YAAY,uFACnB,IACD;CAEA,IAAI,OACH,OAAO,YAAY,uFACnB,IACD;CAWA,IAAI,OACH,uCAAuC,YAAY,oDACnD,IACD;AACD;AAEA,SAAgB,mBAAmB,OAAuB;CACzD,IAAI,MAAM;CACV,KAAK,MAAM,WAAW,uBACrB,MAAM,IAAI,QAAQ,SAAS,YAAY;CAExC,OAAO;AACR"}
@@ -1,4 +1,4 @@
1
-
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  //#region src/search/re-rank-search-results.ts
3
3
  function reRankSearchResults(searchResults, additionalFactors) {
4
4
  return searchResults.map(({ score, item }) => {
@@ -14,7 +14,7 @@ function reRankSearchResults(searchResults, additionalFactors) {
14
14
  return b.score - a.score;
15
15
  });
16
16
  }
17
-
18
17
  //#endregion
19
18
  exports.reRankSearchResults = reRankSearchResults;
19
+
20
20
  //# sourceMappingURL=re-rank-search-results.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"re-rank-search-results.cjs","names":[],"sources":["../../src/search/re-rank-search-results.ts"],"sourcesContent":["export function reRankSearchResults<T extends { key: string }>(\n\tsearchResults: Array<{ score: number; item: T }>,\n\tadditionalFactors: Record<string, Record<string, number>>,\n): Array<{ score: number; item: T }> {\n\treturn searchResults\n\t\t.map(({ score, item }) => {\n\t\t\t// For each additional factor, we check if it exists for the item and type,\n\t\t\t// and if so, we add the score to the item's score.\n\t\t\tconst additionalScore = Object.entries(additionalFactors).reduce((acc, [_, factorScores]) => {\n\t\t\t\tconst factorScore = factorScores[item.key];\n\t\t\t\tif (factorScore) {\n\t\t\t\t\treturn acc + factorScore;\n\t\t\t\t}\n\n\t\t\t\treturn acc;\n\t\t\t}, 0);\n\n\t\t\treturn {\n\t\t\t\tscore: score + additionalScore,\n\t\t\t\titem,\n\t\t\t};\n\t\t})\n\t\t.sort((a, b) => {\n\t\t\treturn b.score - a.score;\n\t\t});\n}\n"],"mappings":";;AAAA,SAAgB,oBACf,eACA,mBACoC;AACpC,QAAO,cACL,KAAK,EAAE,OAAO,WAAW;AAYzB,SAAO;GACN,OAAO,QAVgB,OAAO,QAAQ,kBAAkB,CAAC,QAAQ,KAAK,CAAC,GAAG,kBAAkB;IAC5F,MAAM,cAAc,aAAa,KAAK;AACtC,QAAI,YACH,QAAO,MAAM;AAGd,WAAO;MACL,EAAE;GAIJ;GACA;GACA,CACD,MAAM,GAAG,MAAM;AACf,SAAO,EAAE,QAAQ,EAAE;GAClB"}
1
+ {"version":3,"file":"re-rank-search-results.cjs","names":[],"sources":["../../src/search/re-rank-search-results.ts"],"sourcesContent":["export function reRankSearchResults<T extends { key: string }>(\n\tsearchResults: Array<{ score: number; item: T }>,\n\tadditionalFactors: Record<string, Record<string, number>>,\n): Array<{ score: number; item: T }> {\n\treturn searchResults\n\t\t.map(({ score, item }) => {\n\t\t\t// For each additional factor, we check if it exists for the item and type,\n\t\t\t// and if so, we add the score to the item's score.\n\t\t\tconst additionalScore = Object.entries(additionalFactors).reduce((acc, [_, factorScores]) => {\n\t\t\t\tconst factorScore = factorScores[item.key];\n\t\t\t\tif (factorScore) {\n\t\t\t\t\treturn acc + factorScore;\n\t\t\t\t}\n\n\t\t\t\treturn acc;\n\t\t\t}, 0);\n\n\t\t\treturn {\n\t\t\t\tscore: score + additionalScore,\n\t\t\t\titem,\n\t\t\t};\n\t\t})\n\t\t.sort((a, b) => {\n\t\t\treturn b.score - a.score;\n\t\t});\n}\n"],"mappings":";;AAAA,SAAgB,oBACf,eACA,mBACoC;CACpC,OAAO,cACL,KAAK,EAAE,OAAO,WAAW;EAYzB,OAAO;GACN,OAAO,QAVgB,OAAO,QAAQ,iBAAiB,CAAC,CAAC,QAAQ,KAAK,CAAC,GAAG,kBAAkB;IAC5F,MAAM,cAAc,aAAa,KAAK;IACtC,IAAI,aACH,OAAO,MAAM;IAGd,OAAO;GACR,GAAG,CAG2B;GAC7B;EACD;CACD,CAAC,CAAC,CACD,MAAM,GAAG,MAAM;EACf,OAAO,EAAE,QAAQ,EAAE;CACpB,CAAC;AACH"}
@@ -13,7 +13,7 @@ function reRankSearchResults(searchResults, additionalFactors) {
13
13
  return b.score - a.score;
14
14
  });
15
15
  }
16
-
17
16
  //#endregion
18
17
  export { reRankSearchResults };
18
+
19
19
  //# sourceMappingURL=re-rank-search-results.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"re-rank-search-results.mjs","names":[],"sources":["../../src/search/re-rank-search-results.ts"],"sourcesContent":["export function reRankSearchResults<T extends { key: string }>(\n\tsearchResults: Array<{ score: number; item: T }>,\n\tadditionalFactors: Record<string, Record<string, number>>,\n): Array<{ score: number; item: T }> {\n\treturn searchResults\n\t\t.map(({ score, item }) => {\n\t\t\t// For each additional factor, we check if it exists for the item and type,\n\t\t\t// and if so, we add the score to the item's score.\n\t\t\tconst additionalScore = Object.entries(additionalFactors).reduce((acc, [_, factorScores]) => {\n\t\t\t\tconst factorScore = factorScores[item.key];\n\t\t\t\tif (factorScore) {\n\t\t\t\t\treturn acc + factorScore;\n\t\t\t\t}\n\n\t\t\t\treturn acc;\n\t\t\t}, 0);\n\n\t\t\treturn {\n\t\t\t\tscore: score + additionalScore,\n\t\t\t\titem,\n\t\t\t};\n\t\t})\n\t\t.sort((a, b) => {\n\t\t\treturn b.score - a.score;\n\t\t});\n}\n"],"mappings":";AAAA,SAAgB,oBACf,eACA,mBACoC;AACpC,QAAO,cACL,KAAK,EAAE,OAAO,WAAW;AAYzB,SAAO;GACN,OAAO,QAVgB,OAAO,QAAQ,kBAAkB,CAAC,QAAQ,KAAK,CAAC,GAAG,kBAAkB;IAC5F,MAAM,cAAc,aAAa,KAAK;AACtC,QAAI,YACH,QAAO,MAAM;AAGd,WAAO;MACL,EAAE;GAIJ;GACA;GACA,CACD,MAAM,GAAG,MAAM;AACf,SAAO,EAAE,QAAQ,EAAE;GAClB"}
1
+ {"version":3,"file":"re-rank-search-results.mjs","names":[],"sources":["../../src/search/re-rank-search-results.ts"],"sourcesContent":["export function reRankSearchResults<T extends { key: string }>(\n\tsearchResults: Array<{ score: number; item: T }>,\n\tadditionalFactors: Record<string, Record<string, number>>,\n): Array<{ score: number; item: T }> {\n\treturn searchResults\n\t\t.map(({ score, item }) => {\n\t\t\t// For each additional factor, we check if it exists for the item and type,\n\t\t\t// and if so, we add the score to the item's score.\n\t\t\tconst additionalScore = Object.entries(additionalFactors).reduce((acc, [_, factorScores]) => {\n\t\t\t\tconst factorScore = factorScores[item.key];\n\t\t\t\tif (factorScore) {\n\t\t\t\t\treturn acc + factorScore;\n\t\t\t\t}\n\n\t\t\t\treturn acc;\n\t\t\t}, 0);\n\n\t\t\treturn {\n\t\t\t\tscore: score + additionalScore,\n\t\t\t\titem,\n\t\t\t};\n\t\t})\n\t\t.sort((a, b) => {\n\t\t\treturn b.score - a.score;\n\t\t});\n}\n"],"mappings":";AAAA,SAAgB,oBACf,eACA,mBACoC;CACpC,OAAO,cACL,KAAK,EAAE,OAAO,WAAW;EAYzB,OAAO;GACN,OAAO,QAVgB,OAAO,QAAQ,iBAAiB,CAAC,CAAC,QAAQ,KAAK,CAAC,GAAG,kBAAkB;IAC5F,MAAM,cAAc,aAAa,KAAK;IACtC,IAAI,aACH,OAAO,MAAM;IAGd,OAAO;GACR,GAAG,CAG2B;GAC7B;EACD;CACD,CAAC,CAAC,CACD,MAAM,GAAG,MAAM;EACf,OAAO,EAAE,QAAQ,EAAE;CACpB,CAAC;AACH"}
@@ -1,4 +1,4 @@
1
-
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  //#region src/search/sublime-search.ts
3
3
  const SEQUENTIAL_BONUS = 60;
4
4
  const SEPARATOR_BONUS = 38;
@@ -176,8 +176,8 @@ function sublimeSearch(filter, data, keys = DEFAULT_KEYS, limit) {
176
176
  });
177
177
  return results;
178
178
  }
179
-
180
179
  //#endregion
181
180
  exports.DEFAULT_KEYS = DEFAULT_KEYS;
182
181
  exports.sublimeSearch = sublimeSearch;
182
+
183
183
  //# sourceMappingURL=sublime-search.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"sublime-search.cjs","names":["bestRecursiveMatches: number[]","recursiveMatches: number[]","results: Array<{ score: number; item: T }>","itemMatchScore: number | undefined","result: { score: number; item: T }"],"sources":["../../src/search/sublime-search.ts"],"sourcesContent":["/*\n * Constants and utility functions used for searching for node types in node creator component\n * based on https://github.com/forrestthewoods/lib_fts/blob/master/code/fts_fuzzy_match.js\n */\n\nconst SEQUENTIAL_BONUS = 60; // bonus for adjacent matches\nconst SEPARATOR_BONUS = 38; // bonus if match occurs after a separator\nconst CAMEL_BONUS = 30; // bonus if match is uppercase and prev is lower\nconst FIRST_LETTER_BONUS = 15; // bonus if the first letter is matched\n\nconst LEADING_LETTER_PENALTY = -20; // penalty applied for every letter in str before the first match\nconst MAX_LEADING_LETTER_PENALTY = -200; // maximum penalty for leading letters\nconst UNMATCHED_LETTER_PENALTY = -2.5;\n\nexport const DEFAULT_KEYS = [\n\t{ key: 'properties.displayName', weight: 1.3 },\n\t{ key: 'properties.codex.alias', weight: 1 },\n];\n\n/**\n * Returns true if each character in pattern is found sequentially within target\n * @param {*} pattern string\n * @param {*} target string\n */\nfunction fuzzyMatchSimple(pattern: string, target: string): boolean {\n\tlet patternIdx = 0;\n\tlet strIdx = 0;\n\n\twhile (patternIdx < pattern.length && strIdx < target.length) {\n\t\tconst patternChar = pattern.charAt(patternIdx).toLowerCase();\n\t\tconst targetChar = target.charAt(strIdx).toLowerCase();\n\t\tif (patternChar === targetChar) {\n\t\t\tpatternIdx++;\n\t\t}\n\t\t++strIdx;\n\t}\n\n\treturn pattern.length !== 0 && target.length !== 0 && patternIdx === pattern.length;\n}\n\nfunction fuzzyMatchRecursive(\n\tpattern: string,\n\ttarget: string,\n\tpatternCurIndex: number,\n\ttargetCurrIndex: number,\n\ttargetMatches: null | number[],\n\tmatches: number[],\n\tmaxMatches: number,\n\tnextMatch: number,\n\trecursionCount: number,\n\trecursionLimit: number,\n): { matched: boolean; outScore: number } {\n\tlet outScore = 0;\n\n\t// Return if recursion limit is reached.\n\tif (++recursionCount >= recursionLimit) {\n\t\treturn { matched: false, outScore };\n\t}\n\n\t// Return if we reached ends of strings.\n\tif (patternCurIndex === pattern.length || targetCurrIndex === target.length) {\n\t\treturn { matched: false, outScore };\n\t}\n\n\t// Recursion params\n\tlet recursiveMatch = false;\n\tlet bestRecursiveMatches: number[] = [];\n\tlet bestRecursiveScore = 0;\n\n\t// Loop through pattern and str looking for a match.\n\tlet firstMatch = true;\n\twhile (patternCurIndex < pattern.length && targetCurrIndex < target.length) {\n\t\t// Match found.\n\t\tif (pattern[patternCurIndex].toLowerCase() === target[targetCurrIndex].toLowerCase()) {\n\t\t\tif (nextMatch >= maxMatches) {\n\t\t\t\treturn { matched: false, outScore };\n\t\t\t}\n\n\t\t\tif (firstMatch && targetMatches) {\n\t\t\t\tmatches = [...targetMatches];\n\t\t\t\tfirstMatch = false;\n\t\t\t}\n\n\t\t\tconst recursiveMatches: number[] = [];\n\t\t\tconst recursiveResult = fuzzyMatchRecursive(\n\t\t\t\tpattern,\n\t\t\t\ttarget,\n\t\t\t\tpatternCurIndex,\n\t\t\t\ttargetCurrIndex + 1,\n\t\t\t\tmatches,\n\t\t\t\trecursiveMatches,\n\t\t\t\tmaxMatches,\n\t\t\t\tnextMatch,\n\t\t\t\trecursionCount,\n\t\t\t\trecursionLimit,\n\t\t\t);\n\n\t\t\tconst recursiveScore = recursiveResult.outScore;\n\t\t\tif (recursiveResult.matched) {\n\t\t\t\t// Pick best recursive score.\n\t\t\t\tif (!recursiveMatch || recursiveScore > bestRecursiveScore) {\n\t\t\t\t\tbestRecursiveMatches = [...recursiveMatches];\n\t\t\t\t\tbestRecursiveScore = recursiveScore;\n\t\t\t\t}\n\t\t\t\trecursiveMatch = true;\n\t\t\t}\n\n\t\t\tmatches[nextMatch++] = targetCurrIndex;\n\t\t\t++patternCurIndex;\n\t\t}\n\t\t++targetCurrIndex;\n\t}\n\n\tconst matched = patternCurIndex === pattern.length;\n\n\tif (matched) {\n\t\toutScore = 100;\n\n\t\t// Apply leading letter penalty (if not n8n-prefixed)\n\t\tif (!target.toLowerCase().startsWith('n8n')) {\n\t\t\tlet penalty = LEADING_LETTER_PENALTY * matches[0];\n\t\t\tpenalty = penalty < MAX_LEADING_LETTER_PENALTY ? MAX_LEADING_LETTER_PENALTY : penalty;\n\t\t\toutScore += penalty;\n\t\t}\n\n\t\t//Apply unmatched penalty\n\t\tconst unmatched = target.length - nextMatch;\n\t\toutScore += UNMATCHED_LETTER_PENALTY * unmatched;\n\n\t\t// Apply ordering bonuses\n\t\tfor (let i = 0; i < nextMatch; i++) {\n\t\t\tconst currIdx = matches[i];\n\n\t\t\tif (i > 0) {\n\t\t\t\tconst prevIdx = matches[i - 1];\n\t\t\t\tif (currIdx === prevIdx + 1) {\n\t\t\t\t\toutScore += SEQUENTIAL_BONUS;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Check for bonuses based on neighbor character value.\n\t\t\tif (currIdx > 0) {\n\t\t\t\t// Camel case\n\t\t\t\tconst neighbor = target[currIdx - 1];\n\t\t\t\tconst curr = target[currIdx];\n\t\t\t\tif (neighbor !== neighbor.toUpperCase() && curr !== curr.toLowerCase()) {\n\t\t\t\t\toutScore += CAMEL_BONUS;\n\t\t\t\t}\n\t\t\t\tconst isNeighbourSeparator = neighbor === '_' || neighbor === ' ';\n\t\t\t\tif (isNeighbourSeparator) {\n\t\t\t\t\toutScore += SEPARATOR_BONUS;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// First letter\n\t\t\t\toutScore += FIRST_LETTER_BONUS;\n\t\t\t}\n\t\t}\n\n\t\t// Return best result\n\t\tif (recursiveMatch && (!matched || bestRecursiveScore > outScore)) {\n\t\t\t// Recursive score is better than \"this\"\n\t\t\tmatches = [...bestRecursiveMatches];\n\t\t\toutScore = bestRecursiveScore;\n\t\t\treturn { matched: true, outScore };\n\t\t} else if (matched) {\n\t\t\t// \"this\" score is better than recursive\n\t\t\treturn { matched: true, outScore };\n\t\t} else {\n\t\t\treturn { matched: false, outScore };\n\t\t}\n\t}\n\treturn { matched: false, outScore };\n}\n\n/**\n * Does a fuzzy search to find pattern inside a string.\n * @param {*} pattern string pattern to search for\n * @param {*} target string string which is being searched\n * @returns [boolean, number] a boolean which tells if pattern was\n * found or not and a search score\n */\nfunction fuzzyMatch(pattern: string, target: string): { matched: boolean; outScore: number } {\n\tconst recursionCount = 0;\n\tconst recursionLimit = 5;\n\tconst matches: number[] = [];\n\tconst maxMatches = 256;\n\n\treturn fuzzyMatchRecursive(\n\t\tpattern,\n\t\ttarget,\n\t\t0 /* patternCurIndex */,\n\t\t0 /* strCurrIndex */,\n\t\tnull /* srcMatces */,\n\t\tmatches,\n\t\tmaxMatches,\n\t\t0 /* nextMatch */,\n\t\trecursionCount,\n\t\trecursionLimit,\n\t);\n}\n\n// prop = 'key'\n// prop = 'key1.key2'\n// prop = ['key1', 'key2']\nfunction getValue<T extends object>(obj: T, prop: string): unknown {\n\tif (obj.hasOwnProperty(prop)) {\n\t\treturn obj[prop as keyof T];\n\t}\n\n\tconst segments = prop.split('.');\n\n\tlet result = obj;\n\tlet i = 0;\n\twhile (result && i < segments.length) {\n\t\tconst key = segments[i] as keyof T;\n\t\tresult = result[key] as T;\n\t\ti++;\n\t}\n\treturn result;\n}\n\nfunction scoreSearchValue(filter: string, value: string, weight: number): number | undefined {\n\tif (!fuzzyMatchSimple(filter, value)) return undefined;\n\n\tconst match = fuzzyMatch(filter, value);\n\tif (!match.matched) return undefined;\n\n\treturn match.outScore * weight;\n}\n\nexport function sublimeSearch<T extends object>(\n\tfilter: string,\n\tdata: readonly T[],\n\tkeys: Array<{ key: string; weight: number }> = DEFAULT_KEYS,\n\tlimit?: number,\n): Array<{ score: number; item: T }> {\n\tconst results: Array<{ score: number; item: T }> = [];\n\n\tfor (const item of data) {\n\t\tlet itemMatchScore: number | undefined;\n\n\t\tfor (const { key, weight } of keys) {\n\t\t\tconst value = getValue(item, key);\n\t\t\tif (Array.isArray(value)) {\n\t\t\t\tfor (const entry of value) {\n\t\t\t\t\tif (typeof entry !== 'string') continue;\n\n\t\t\t\t\tconst score = scoreSearchValue(filter, entry, weight);\n\t\t\t\t\tif (score !== undefined && (itemMatchScore === undefined || score > itemMatchScore)) {\n\t\t\t\t\t\titemMatchScore = score;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else if (typeof value === 'string') {\n\t\t\t\tconst score = scoreSearchValue(filter, value, weight);\n\t\t\t\tif (score !== undefined && (itemMatchScore === undefined || score > itemMatchScore)) {\n\t\t\t\t\titemMatchScore = score;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (itemMatchScore !== undefined) {\n\t\t\tconst result: { score: number; item: T } = {\n\t\t\t\tscore: itemMatchScore,\n\t\t\t\titem,\n\t\t\t};\n\n\t\t\tif (limit === undefined || results.length < limit) {\n\t\t\t\tresults.push(result);\n\t\t\t} else {\n\t\t\t\tlet lowestIndex = 0;\n\t\t\t\tlet lowestScore = results[0].score;\n\t\t\t\tfor (let i = 1; i < results.length; i++) {\n\t\t\t\t\tif (results[i].score < lowestScore) {\n\t\t\t\t\t\tlowestIndex = i;\n\t\t\t\t\t\tlowestScore = results[i].score;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (result.score > lowestScore) {\n\t\t\t\t\tresults[lowestIndex] = result;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tresults.sort((a, b) => {\n\t\treturn b.score - a.score;\n\t});\n\n\treturn results;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"sublime-search.cjs","names":[],"sources":["../../src/search/sublime-search.ts"],"sourcesContent":["/*\n * Constants and utility functions used for searching for node types in node creator component\n * based on https://github.com/forrestthewoods/lib_fts/blob/master/code/fts_fuzzy_match.js\n */\n\nconst SEQUENTIAL_BONUS = 60; // bonus for adjacent matches\nconst SEPARATOR_BONUS = 38; // bonus if match occurs after a separator\nconst CAMEL_BONUS = 30; // bonus if match is uppercase and prev is lower\nconst FIRST_LETTER_BONUS = 15; // bonus if the first letter is matched\n\nconst LEADING_LETTER_PENALTY = -20; // penalty applied for every letter in str before the first match\nconst MAX_LEADING_LETTER_PENALTY = -200; // maximum penalty for leading letters\nconst UNMATCHED_LETTER_PENALTY = -2.5;\n\nexport const DEFAULT_KEYS = [\n\t{ key: 'properties.displayName', weight: 1.3 },\n\t{ key: 'properties.codex.alias', weight: 1 },\n];\n\n/**\n * Returns true if each character in pattern is found sequentially within target\n * @param {*} pattern string\n * @param {*} target string\n */\nfunction fuzzyMatchSimple(pattern: string, target: string): boolean {\n\tlet patternIdx = 0;\n\tlet strIdx = 0;\n\n\twhile (patternIdx < pattern.length && strIdx < target.length) {\n\t\tconst patternChar = pattern.charAt(patternIdx).toLowerCase();\n\t\tconst targetChar = target.charAt(strIdx).toLowerCase();\n\t\tif (patternChar === targetChar) {\n\t\t\tpatternIdx++;\n\t\t}\n\t\t++strIdx;\n\t}\n\n\treturn pattern.length !== 0 && target.length !== 0 && patternIdx === pattern.length;\n}\n\nfunction fuzzyMatchRecursive(\n\tpattern: string,\n\ttarget: string,\n\tpatternCurIndex: number,\n\ttargetCurrIndex: number,\n\ttargetMatches: null | number[],\n\tmatches: number[],\n\tmaxMatches: number,\n\tnextMatch: number,\n\trecursionCount: number,\n\trecursionLimit: number,\n): { matched: boolean; outScore: number } {\n\tlet outScore = 0;\n\n\t// Return if recursion limit is reached.\n\tif (++recursionCount >= recursionLimit) {\n\t\treturn { matched: false, outScore };\n\t}\n\n\t// Return if we reached ends of strings.\n\tif (patternCurIndex === pattern.length || targetCurrIndex === target.length) {\n\t\treturn { matched: false, outScore };\n\t}\n\n\t// Recursion params\n\tlet recursiveMatch = false;\n\tlet bestRecursiveMatches: number[] = [];\n\tlet bestRecursiveScore = 0;\n\n\t// Loop through pattern and str looking for a match.\n\tlet firstMatch = true;\n\twhile (patternCurIndex < pattern.length && targetCurrIndex < target.length) {\n\t\t// Match found.\n\t\tif (pattern[patternCurIndex].toLowerCase() === target[targetCurrIndex].toLowerCase()) {\n\t\t\tif (nextMatch >= maxMatches) {\n\t\t\t\treturn { matched: false, outScore };\n\t\t\t}\n\n\t\t\tif (firstMatch && targetMatches) {\n\t\t\t\tmatches = [...targetMatches];\n\t\t\t\tfirstMatch = false;\n\t\t\t}\n\n\t\t\tconst recursiveMatches: number[] = [];\n\t\t\tconst recursiveResult = fuzzyMatchRecursive(\n\t\t\t\tpattern,\n\t\t\t\ttarget,\n\t\t\t\tpatternCurIndex,\n\t\t\t\ttargetCurrIndex + 1,\n\t\t\t\tmatches,\n\t\t\t\trecursiveMatches,\n\t\t\t\tmaxMatches,\n\t\t\t\tnextMatch,\n\t\t\t\trecursionCount,\n\t\t\t\trecursionLimit,\n\t\t\t);\n\n\t\t\tconst recursiveScore = recursiveResult.outScore;\n\t\t\tif (recursiveResult.matched) {\n\t\t\t\t// Pick best recursive score.\n\t\t\t\tif (!recursiveMatch || recursiveScore > bestRecursiveScore) {\n\t\t\t\t\tbestRecursiveMatches = [...recursiveMatches];\n\t\t\t\t\tbestRecursiveScore = recursiveScore;\n\t\t\t\t}\n\t\t\t\trecursiveMatch = true;\n\t\t\t}\n\n\t\t\tmatches[nextMatch++] = targetCurrIndex;\n\t\t\t++patternCurIndex;\n\t\t}\n\t\t++targetCurrIndex;\n\t}\n\n\tconst matched = patternCurIndex === pattern.length;\n\n\tif (matched) {\n\t\toutScore = 100;\n\n\t\t// Apply leading letter penalty (if not n8n-prefixed)\n\t\tif (!target.toLowerCase().startsWith('n8n')) {\n\t\t\tlet penalty = LEADING_LETTER_PENALTY * matches[0];\n\t\t\tpenalty = penalty < MAX_LEADING_LETTER_PENALTY ? MAX_LEADING_LETTER_PENALTY : penalty;\n\t\t\toutScore += penalty;\n\t\t}\n\n\t\t//Apply unmatched penalty\n\t\tconst unmatched = target.length - nextMatch;\n\t\toutScore += UNMATCHED_LETTER_PENALTY * unmatched;\n\n\t\t// Apply ordering bonuses\n\t\tfor (let i = 0; i < nextMatch; i++) {\n\t\t\tconst currIdx = matches[i];\n\n\t\t\tif (i > 0) {\n\t\t\t\tconst prevIdx = matches[i - 1];\n\t\t\t\tif (currIdx === prevIdx + 1) {\n\t\t\t\t\toutScore += SEQUENTIAL_BONUS;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Check for bonuses based on neighbor character value.\n\t\t\tif (currIdx > 0) {\n\t\t\t\t// Camel case\n\t\t\t\tconst neighbor = target[currIdx - 1];\n\t\t\t\tconst curr = target[currIdx];\n\t\t\t\tif (neighbor !== neighbor.toUpperCase() && curr !== curr.toLowerCase()) {\n\t\t\t\t\toutScore += CAMEL_BONUS;\n\t\t\t\t}\n\t\t\t\tconst isNeighbourSeparator = neighbor === '_' || neighbor === ' ';\n\t\t\t\tif (isNeighbourSeparator) {\n\t\t\t\t\toutScore += SEPARATOR_BONUS;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// First letter\n\t\t\t\toutScore += FIRST_LETTER_BONUS;\n\t\t\t}\n\t\t}\n\n\t\t// Return best result\n\t\tif (recursiveMatch && (!matched || bestRecursiveScore > outScore)) {\n\t\t\t// Recursive score is better than \"this\"\n\t\t\tmatches = [...bestRecursiveMatches];\n\t\t\toutScore = bestRecursiveScore;\n\t\t\treturn { matched: true, outScore };\n\t\t} else if (matched) {\n\t\t\t// \"this\" score is better than recursive\n\t\t\treturn { matched: true, outScore };\n\t\t} else {\n\t\t\treturn { matched: false, outScore };\n\t\t}\n\t}\n\treturn { matched: false, outScore };\n}\n\n/**\n * Does a fuzzy search to find pattern inside a string.\n * @param {*} pattern string pattern to search for\n * @param {*} target string string which is being searched\n * @returns [boolean, number] a boolean which tells if pattern was\n * found or not and a search score\n */\nfunction fuzzyMatch(pattern: string, target: string): { matched: boolean; outScore: number } {\n\tconst recursionCount = 0;\n\tconst recursionLimit = 5;\n\tconst matches: number[] = [];\n\tconst maxMatches = 256;\n\n\treturn fuzzyMatchRecursive(\n\t\tpattern,\n\t\ttarget,\n\t\t0 /* patternCurIndex */,\n\t\t0 /* strCurrIndex */,\n\t\tnull /* srcMatces */,\n\t\tmatches,\n\t\tmaxMatches,\n\t\t0 /* nextMatch */,\n\t\trecursionCount,\n\t\trecursionLimit,\n\t);\n}\n\n// prop = 'key'\n// prop = 'key1.key2'\n// prop = ['key1', 'key2']\nfunction getValue<T extends object>(obj: T, prop: string): unknown {\n\tif (obj.hasOwnProperty(prop)) {\n\t\treturn obj[prop as keyof T];\n\t}\n\n\tconst segments = prop.split('.');\n\n\tlet result = obj;\n\tlet i = 0;\n\twhile (result && i < segments.length) {\n\t\tconst key = segments[i] as keyof T;\n\t\tresult = result[key] as T;\n\t\ti++;\n\t}\n\treturn result;\n}\n\nfunction scoreSearchValue(filter: string, value: string, weight: number): number | undefined {\n\tif (!fuzzyMatchSimple(filter, value)) return undefined;\n\n\tconst match = fuzzyMatch(filter, value);\n\tif (!match.matched) return undefined;\n\n\treturn match.outScore * weight;\n}\n\nexport function sublimeSearch<T extends object>(\n\tfilter: string,\n\tdata: readonly T[],\n\tkeys: Array<{ key: string; weight: number }> = DEFAULT_KEYS,\n\tlimit?: number,\n): Array<{ score: number; item: T }> {\n\tconst results: Array<{ score: number; item: T }> = [];\n\n\tfor (const item of data) {\n\t\tlet itemMatchScore: number | undefined;\n\n\t\tfor (const { key, weight } of keys) {\n\t\t\tconst value = getValue(item, key);\n\t\t\tif (Array.isArray(value)) {\n\t\t\t\tfor (const entry of value) {\n\t\t\t\t\tif (typeof entry !== 'string') continue;\n\n\t\t\t\t\tconst score = scoreSearchValue(filter, entry, weight);\n\t\t\t\t\tif (score !== undefined && (itemMatchScore === undefined || score > itemMatchScore)) {\n\t\t\t\t\t\titemMatchScore = score;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else if (typeof value === 'string') {\n\t\t\t\tconst score = scoreSearchValue(filter, value, weight);\n\t\t\t\tif (score !== undefined && (itemMatchScore === undefined || score > itemMatchScore)) {\n\t\t\t\t\titemMatchScore = score;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (itemMatchScore !== undefined) {\n\t\t\tconst result: { score: number; item: T } = {\n\t\t\t\tscore: itemMatchScore,\n\t\t\t\titem,\n\t\t\t};\n\n\t\t\tif (limit === undefined || results.length < limit) {\n\t\t\t\tresults.push(result);\n\t\t\t} else {\n\t\t\t\tlet lowestIndex = 0;\n\t\t\t\tlet lowestScore = results[0].score;\n\t\t\t\tfor (let i = 1; i < results.length; i++) {\n\t\t\t\t\tif (results[i].score < lowestScore) {\n\t\t\t\t\t\tlowestIndex = i;\n\t\t\t\t\t\tlowestScore = results[i].score;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (result.score > lowestScore) {\n\t\t\t\t\tresults[lowestIndex] = result;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tresults.sort((a, b) => {\n\t\treturn b.score - a.score;\n\t});\n\n\treturn results;\n}\n"],"mappings":"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"}
@@ -175,7 +175,7 @@ function sublimeSearch(filter, data, keys = DEFAULT_KEYS, limit) {
175
175
  });
176
176
  return results;
177
177
  }
178
-
179
178
  //#endregion
180
179
  export { DEFAULT_KEYS, sublimeSearch };
180
+
181
181
  //# sourceMappingURL=sublime-search.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"sublime-search.mjs","names":["bestRecursiveMatches: number[]","recursiveMatches: number[]","results: Array<{ score: number; item: T }>","itemMatchScore: number | undefined","result: { score: number; item: T }"],"sources":["../../src/search/sublime-search.ts"],"sourcesContent":["/*\n * Constants and utility functions used for searching for node types in node creator component\n * based on https://github.com/forrestthewoods/lib_fts/blob/master/code/fts_fuzzy_match.js\n */\n\nconst SEQUENTIAL_BONUS = 60; // bonus for adjacent matches\nconst SEPARATOR_BONUS = 38; // bonus if match occurs after a separator\nconst CAMEL_BONUS = 30; // bonus if match is uppercase and prev is lower\nconst FIRST_LETTER_BONUS = 15; // bonus if the first letter is matched\n\nconst LEADING_LETTER_PENALTY = -20; // penalty applied for every letter in str before the first match\nconst MAX_LEADING_LETTER_PENALTY = -200; // maximum penalty for leading letters\nconst UNMATCHED_LETTER_PENALTY = -2.5;\n\nexport const DEFAULT_KEYS = [\n\t{ key: 'properties.displayName', weight: 1.3 },\n\t{ key: 'properties.codex.alias', weight: 1 },\n];\n\n/**\n * Returns true if each character in pattern is found sequentially within target\n * @param {*} pattern string\n * @param {*} target string\n */\nfunction fuzzyMatchSimple(pattern: string, target: string): boolean {\n\tlet patternIdx = 0;\n\tlet strIdx = 0;\n\n\twhile (patternIdx < pattern.length && strIdx < target.length) {\n\t\tconst patternChar = pattern.charAt(patternIdx).toLowerCase();\n\t\tconst targetChar = target.charAt(strIdx).toLowerCase();\n\t\tif (patternChar === targetChar) {\n\t\t\tpatternIdx++;\n\t\t}\n\t\t++strIdx;\n\t}\n\n\treturn pattern.length !== 0 && target.length !== 0 && patternIdx === pattern.length;\n}\n\nfunction fuzzyMatchRecursive(\n\tpattern: string,\n\ttarget: string,\n\tpatternCurIndex: number,\n\ttargetCurrIndex: number,\n\ttargetMatches: null | number[],\n\tmatches: number[],\n\tmaxMatches: number,\n\tnextMatch: number,\n\trecursionCount: number,\n\trecursionLimit: number,\n): { matched: boolean; outScore: number } {\n\tlet outScore = 0;\n\n\t// Return if recursion limit is reached.\n\tif (++recursionCount >= recursionLimit) {\n\t\treturn { matched: false, outScore };\n\t}\n\n\t// Return if we reached ends of strings.\n\tif (patternCurIndex === pattern.length || targetCurrIndex === target.length) {\n\t\treturn { matched: false, outScore };\n\t}\n\n\t// Recursion params\n\tlet recursiveMatch = false;\n\tlet bestRecursiveMatches: number[] = [];\n\tlet bestRecursiveScore = 0;\n\n\t// Loop through pattern and str looking for a match.\n\tlet firstMatch = true;\n\twhile (patternCurIndex < pattern.length && targetCurrIndex < target.length) {\n\t\t// Match found.\n\t\tif (pattern[patternCurIndex].toLowerCase() === target[targetCurrIndex].toLowerCase()) {\n\t\t\tif (nextMatch >= maxMatches) {\n\t\t\t\treturn { matched: false, outScore };\n\t\t\t}\n\n\t\t\tif (firstMatch && targetMatches) {\n\t\t\t\tmatches = [...targetMatches];\n\t\t\t\tfirstMatch = false;\n\t\t\t}\n\n\t\t\tconst recursiveMatches: number[] = [];\n\t\t\tconst recursiveResult = fuzzyMatchRecursive(\n\t\t\t\tpattern,\n\t\t\t\ttarget,\n\t\t\t\tpatternCurIndex,\n\t\t\t\ttargetCurrIndex + 1,\n\t\t\t\tmatches,\n\t\t\t\trecursiveMatches,\n\t\t\t\tmaxMatches,\n\t\t\t\tnextMatch,\n\t\t\t\trecursionCount,\n\t\t\t\trecursionLimit,\n\t\t\t);\n\n\t\t\tconst recursiveScore = recursiveResult.outScore;\n\t\t\tif (recursiveResult.matched) {\n\t\t\t\t// Pick best recursive score.\n\t\t\t\tif (!recursiveMatch || recursiveScore > bestRecursiveScore) {\n\t\t\t\t\tbestRecursiveMatches = [...recursiveMatches];\n\t\t\t\t\tbestRecursiveScore = recursiveScore;\n\t\t\t\t}\n\t\t\t\trecursiveMatch = true;\n\t\t\t}\n\n\t\t\tmatches[nextMatch++] = targetCurrIndex;\n\t\t\t++patternCurIndex;\n\t\t}\n\t\t++targetCurrIndex;\n\t}\n\n\tconst matched = patternCurIndex === pattern.length;\n\n\tif (matched) {\n\t\toutScore = 100;\n\n\t\t// Apply leading letter penalty (if not n8n-prefixed)\n\t\tif (!target.toLowerCase().startsWith('n8n')) {\n\t\t\tlet penalty = LEADING_LETTER_PENALTY * matches[0];\n\t\t\tpenalty = penalty < MAX_LEADING_LETTER_PENALTY ? MAX_LEADING_LETTER_PENALTY : penalty;\n\t\t\toutScore += penalty;\n\t\t}\n\n\t\t//Apply unmatched penalty\n\t\tconst unmatched = target.length - nextMatch;\n\t\toutScore += UNMATCHED_LETTER_PENALTY * unmatched;\n\n\t\t// Apply ordering bonuses\n\t\tfor (let i = 0; i < nextMatch; i++) {\n\t\t\tconst currIdx = matches[i];\n\n\t\t\tif (i > 0) {\n\t\t\t\tconst prevIdx = matches[i - 1];\n\t\t\t\tif (currIdx === prevIdx + 1) {\n\t\t\t\t\toutScore += SEQUENTIAL_BONUS;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Check for bonuses based on neighbor character value.\n\t\t\tif (currIdx > 0) {\n\t\t\t\t// Camel case\n\t\t\t\tconst neighbor = target[currIdx - 1];\n\t\t\t\tconst curr = target[currIdx];\n\t\t\t\tif (neighbor !== neighbor.toUpperCase() && curr !== curr.toLowerCase()) {\n\t\t\t\t\toutScore += CAMEL_BONUS;\n\t\t\t\t}\n\t\t\t\tconst isNeighbourSeparator = neighbor === '_' || neighbor === ' ';\n\t\t\t\tif (isNeighbourSeparator) {\n\t\t\t\t\toutScore += SEPARATOR_BONUS;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// First letter\n\t\t\t\toutScore += FIRST_LETTER_BONUS;\n\t\t\t}\n\t\t}\n\n\t\t// Return best result\n\t\tif (recursiveMatch && (!matched || bestRecursiveScore > outScore)) {\n\t\t\t// Recursive score is better than \"this\"\n\t\t\tmatches = [...bestRecursiveMatches];\n\t\t\toutScore = bestRecursiveScore;\n\t\t\treturn { matched: true, outScore };\n\t\t} else if (matched) {\n\t\t\t// \"this\" score is better than recursive\n\t\t\treturn { matched: true, outScore };\n\t\t} else {\n\t\t\treturn { matched: false, outScore };\n\t\t}\n\t}\n\treturn { matched: false, outScore };\n}\n\n/**\n * Does a fuzzy search to find pattern inside a string.\n * @param {*} pattern string pattern to search for\n * @param {*} target string string which is being searched\n * @returns [boolean, number] a boolean which tells if pattern was\n * found or not and a search score\n */\nfunction fuzzyMatch(pattern: string, target: string): { matched: boolean; outScore: number } {\n\tconst recursionCount = 0;\n\tconst recursionLimit = 5;\n\tconst matches: number[] = [];\n\tconst maxMatches = 256;\n\n\treturn fuzzyMatchRecursive(\n\t\tpattern,\n\t\ttarget,\n\t\t0 /* patternCurIndex */,\n\t\t0 /* strCurrIndex */,\n\t\tnull /* srcMatces */,\n\t\tmatches,\n\t\tmaxMatches,\n\t\t0 /* nextMatch */,\n\t\trecursionCount,\n\t\trecursionLimit,\n\t);\n}\n\n// prop = 'key'\n// prop = 'key1.key2'\n// prop = ['key1', 'key2']\nfunction getValue<T extends object>(obj: T, prop: string): unknown {\n\tif (obj.hasOwnProperty(prop)) {\n\t\treturn obj[prop as keyof T];\n\t}\n\n\tconst segments = prop.split('.');\n\n\tlet result = obj;\n\tlet i = 0;\n\twhile (result && i < segments.length) {\n\t\tconst key = segments[i] as keyof T;\n\t\tresult = result[key] as T;\n\t\ti++;\n\t}\n\treturn result;\n}\n\nfunction scoreSearchValue(filter: string, value: string, weight: number): number | undefined {\n\tif (!fuzzyMatchSimple(filter, value)) return undefined;\n\n\tconst match = fuzzyMatch(filter, value);\n\tif (!match.matched) return undefined;\n\n\treturn match.outScore * weight;\n}\n\nexport function sublimeSearch<T extends object>(\n\tfilter: string,\n\tdata: readonly T[],\n\tkeys: Array<{ key: string; weight: number }> = DEFAULT_KEYS,\n\tlimit?: number,\n): Array<{ score: number; item: T }> {\n\tconst results: Array<{ score: number; item: T }> = [];\n\n\tfor (const item of data) {\n\t\tlet itemMatchScore: number | undefined;\n\n\t\tfor (const { key, weight } of keys) {\n\t\t\tconst value = getValue(item, key);\n\t\t\tif (Array.isArray(value)) {\n\t\t\t\tfor (const entry of value) {\n\t\t\t\t\tif (typeof entry !== 'string') continue;\n\n\t\t\t\t\tconst score = scoreSearchValue(filter, entry, weight);\n\t\t\t\t\tif (score !== undefined && (itemMatchScore === undefined || score > itemMatchScore)) {\n\t\t\t\t\t\titemMatchScore = score;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else if (typeof value === 'string') {\n\t\t\t\tconst score = scoreSearchValue(filter, value, weight);\n\t\t\t\tif (score !== undefined && (itemMatchScore === undefined || score > itemMatchScore)) {\n\t\t\t\t\titemMatchScore = score;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (itemMatchScore !== undefined) {\n\t\t\tconst result: { score: number; item: T } = {\n\t\t\t\tscore: itemMatchScore,\n\t\t\t\titem,\n\t\t\t};\n\n\t\t\tif (limit === undefined || results.length < limit) {\n\t\t\t\tresults.push(result);\n\t\t\t} else {\n\t\t\t\tlet lowestIndex = 0;\n\t\t\t\tlet lowestScore = results[0].score;\n\t\t\t\tfor (let i = 1; i < results.length; i++) {\n\t\t\t\t\tif (results[i].score < lowestScore) {\n\t\t\t\t\t\tlowestIndex = i;\n\t\t\t\t\t\tlowestScore = results[i].score;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (result.score > lowestScore) {\n\t\t\t\t\tresults[lowestIndex] = result;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tresults.sort((a, b) => {\n\t\treturn b.score - a.score;\n\t});\n\n\treturn results;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"sublime-search.mjs","names":[],"sources":["../../src/search/sublime-search.ts"],"sourcesContent":["/*\n * Constants and utility functions used for searching for node types in node creator component\n * based on https://github.com/forrestthewoods/lib_fts/blob/master/code/fts_fuzzy_match.js\n */\n\nconst SEQUENTIAL_BONUS = 60; // bonus for adjacent matches\nconst SEPARATOR_BONUS = 38; // bonus if match occurs after a separator\nconst CAMEL_BONUS = 30; // bonus if match is uppercase and prev is lower\nconst FIRST_LETTER_BONUS = 15; // bonus if the first letter is matched\n\nconst LEADING_LETTER_PENALTY = -20; // penalty applied for every letter in str before the first match\nconst MAX_LEADING_LETTER_PENALTY = -200; // maximum penalty for leading letters\nconst UNMATCHED_LETTER_PENALTY = -2.5;\n\nexport const DEFAULT_KEYS = [\n\t{ key: 'properties.displayName', weight: 1.3 },\n\t{ key: 'properties.codex.alias', weight: 1 },\n];\n\n/**\n * Returns true if each character in pattern is found sequentially within target\n * @param {*} pattern string\n * @param {*} target string\n */\nfunction fuzzyMatchSimple(pattern: string, target: string): boolean {\n\tlet patternIdx = 0;\n\tlet strIdx = 0;\n\n\twhile (patternIdx < pattern.length && strIdx < target.length) {\n\t\tconst patternChar = pattern.charAt(patternIdx).toLowerCase();\n\t\tconst targetChar = target.charAt(strIdx).toLowerCase();\n\t\tif (patternChar === targetChar) {\n\t\t\tpatternIdx++;\n\t\t}\n\t\t++strIdx;\n\t}\n\n\treturn pattern.length !== 0 && target.length !== 0 && patternIdx === pattern.length;\n}\n\nfunction fuzzyMatchRecursive(\n\tpattern: string,\n\ttarget: string,\n\tpatternCurIndex: number,\n\ttargetCurrIndex: number,\n\ttargetMatches: null | number[],\n\tmatches: number[],\n\tmaxMatches: number,\n\tnextMatch: number,\n\trecursionCount: number,\n\trecursionLimit: number,\n): { matched: boolean; outScore: number } {\n\tlet outScore = 0;\n\n\t// Return if recursion limit is reached.\n\tif (++recursionCount >= recursionLimit) {\n\t\treturn { matched: false, outScore };\n\t}\n\n\t// Return if we reached ends of strings.\n\tif (patternCurIndex === pattern.length || targetCurrIndex === target.length) {\n\t\treturn { matched: false, outScore };\n\t}\n\n\t// Recursion params\n\tlet recursiveMatch = false;\n\tlet bestRecursiveMatches: number[] = [];\n\tlet bestRecursiveScore = 0;\n\n\t// Loop through pattern and str looking for a match.\n\tlet firstMatch = true;\n\twhile (patternCurIndex < pattern.length && targetCurrIndex < target.length) {\n\t\t// Match found.\n\t\tif (pattern[patternCurIndex].toLowerCase() === target[targetCurrIndex].toLowerCase()) {\n\t\t\tif (nextMatch >= maxMatches) {\n\t\t\t\treturn { matched: false, outScore };\n\t\t\t}\n\n\t\t\tif (firstMatch && targetMatches) {\n\t\t\t\tmatches = [...targetMatches];\n\t\t\t\tfirstMatch = false;\n\t\t\t}\n\n\t\t\tconst recursiveMatches: number[] = [];\n\t\t\tconst recursiveResult = fuzzyMatchRecursive(\n\t\t\t\tpattern,\n\t\t\t\ttarget,\n\t\t\t\tpatternCurIndex,\n\t\t\t\ttargetCurrIndex + 1,\n\t\t\t\tmatches,\n\t\t\t\trecursiveMatches,\n\t\t\t\tmaxMatches,\n\t\t\t\tnextMatch,\n\t\t\t\trecursionCount,\n\t\t\t\trecursionLimit,\n\t\t\t);\n\n\t\t\tconst recursiveScore = recursiveResult.outScore;\n\t\t\tif (recursiveResult.matched) {\n\t\t\t\t// Pick best recursive score.\n\t\t\t\tif (!recursiveMatch || recursiveScore > bestRecursiveScore) {\n\t\t\t\t\tbestRecursiveMatches = [...recursiveMatches];\n\t\t\t\t\tbestRecursiveScore = recursiveScore;\n\t\t\t\t}\n\t\t\t\trecursiveMatch = true;\n\t\t\t}\n\n\t\t\tmatches[nextMatch++] = targetCurrIndex;\n\t\t\t++patternCurIndex;\n\t\t}\n\t\t++targetCurrIndex;\n\t}\n\n\tconst matched = patternCurIndex === pattern.length;\n\n\tif (matched) {\n\t\toutScore = 100;\n\n\t\t// Apply leading letter penalty (if not n8n-prefixed)\n\t\tif (!target.toLowerCase().startsWith('n8n')) {\n\t\t\tlet penalty = LEADING_LETTER_PENALTY * matches[0];\n\t\t\tpenalty = penalty < MAX_LEADING_LETTER_PENALTY ? MAX_LEADING_LETTER_PENALTY : penalty;\n\t\t\toutScore += penalty;\n\t\t}\n\n\t\t//Apply unmatched penalty\n\t\tconst unmatched = target.length - nextMatch;\n\t\toutScore += UNMATCHED_LETTER_PENALTY * unmatched;\n\n\t\t// Apply ordering bonuses\n\t\tfor (let i = 0; i < nextMatch; i++) {\n\t\t\tconst currIdx = matches[i];\n\n\t\t\tif (i > 0) {\n\t\t\t\tconst prevIdx = matches[i - 1];\n\t\t\t\tif (currIdx === prevIdx + 1) {\n\t\t\t\t\toutScore += SEQUENTIAL_BONUS;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Check for bonuses based on neighbor character value.\n\t\t\tif (currIdx > 0) {\n\t\t\t\t// Camel case\n\t\t\t\tconst neighbor = target[currIdx - 1];\n\t\t\t\tconst curr = target[currIdx];\n\t\t\t\tif (neighbor !== neighbor.toUpperCase() && curr !== curr.toLowerCase()) {\n\t\t\t\t\toutScore += CAMEL_BONUS;\n\t\t\t\t}\n\t\t\t\tconst isNeighbourSeparator = neighbor === '_' || neighbor === ' ';\n\t\t\t\tif (isNeighbourSeparator) {\n\t\t\t\t\toutScore += SEPARATOR_BONUS;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\t// First letter\n\t\t\t\toutScore += FIRST_LETTER_BONUS;\n\t\t\t}\n\t\t}\n\n\t\t// Return best result\n\t\tif (recursiveMatch && (!matched || bestRecursiveScore > outScore)) {\n\t\t\t// Recursive score is better than \"this\"\n\t\t\tmatches = [...bestRecursiveMatches];\n\t\t\toutScore = bestRecursiveScore;\n\t\t\treturn { matched: true, outScore };\n\t\t} else if (matched) {\n\t\t\t// \"this\" score is better than recursive\n\t\t\treturn { matched: true, outScore };\n\t\t} else {\n\t\t\treturn { matched: false, outScore };\n\t\t}\n\t}\n\treturn { matched: false, outScore };\n}\n\n/**\n * Does a fuzzy search to find pattern inside a string.\n * @param {*} pattern string pattern to search for\n * @param {*} target string string which is being searched\n * @returns [boolean, number] a boolean which tells if pattern was\n * found or not and a search score\n */\nfunction fuzzyMatch(pattern: string, target: string): { matched: boolean; outScore: number } {\n\tconst recursionCount = 0;\n\tconst recursionLimit = 5;\n\tconst matches: number[] = [];\n\tconst maxMatches = 256;\n\n\treturn fuzzyMatchRecursive(\n\t\tpattern,\n\t\ttarget,\n\t\t0 /* patternCurIndex */,\n\t\t0 /* strCurrIndex */,\n\t\tnull /* srcMatces */,\n\t\tmatches,\n\t\tmaxMatches,\n\t\t0 /* nextMatch */,\n\t\trecursionCount,\n\t\trecursionLimit,\n\t);\n}\n\n// prop = 'key'\n// prop = 'key1.key2'\n// prop = ['key1', 'key2']\nfunction getValue<T extends object>(obj: T, prop: string): unknown {\n\tif (obj.hasOwnProperty(prop)) {\n\t\treturn obj[prop as keyof T];\n\t}\n\n\tconst segments = prop.split('.');\n\n\tlet result = obj;\n\tlet i = 0;\n\twhile (result && i < segments.length) {\n\t\tconst key = segments[i] as keyof T;\n\t\tresult = result[key] as T;\n\t\ti++;\n\t}\n\treturn result;\n}\n\nfunction scoreSearchValue(filter: string, value: string, weight: number): number | undefined {\n\tif (!fuzzyMatchSimple(filter, value)) return undefined;\n\n\tconst match = fuzzyMatch(filter, value);\n\tif (!match.matched) return undefined;\n\n\treturn match.outScore * weight;\n}\n\nexport function sublimeSearch<T extends object>(\n\tfilter: string,\n\tdata: readonly T[],\n\tkeys: Array<{ key: string; weight: number }> = DEFAULT_KEYS,\n\tlimit?: number,\n): Array<{ score: number; item: T }> {\n\tconst results: Array<{ score: number; item: T }> = [];\n\n\tfor (const item of data) {\n\t\tlet itemMatchScore: number | undefined;\n\n\t\tfor (const { key, weight } of keys) {\n\t\t\tconst value = getValue(item, key);\n\t\t\tif (Array.isArray(value)) {\n\t\t\t\tfor (const entry of value) {\n\t\t\t\t\tif (typeof entry !== 'string') continue;\n\n\t\t\t\t\tconst score = scoreSearchValue(filter, entry, weight);\n\t\t\t\t\tif (score !== undefined && (itemMatchScore === undefined || score > itemMatchScore)) {\n\t\t\t\t\t\titemMatchScore = score;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t} else if (typeof value === 'string') {\n\t\t\t\tconst score = scoreSearchValue(filter, value, weight);\n\t\t\t\tif (score !== undefined && (itemMatchScore === undefined || score > itemMatchScore)) {\n\t\t\t\t\titemMatchScore = score;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (itemMatchScore !== undefined) {\n\t\t\tconst result: { score: number; item: T } = {\n\t\t\t\tscore: itemMatchScore,\n\t\t\t\titem,\n\t\t\t};\n\n\t\t\tif (limit === undefined || results.length < limit) {\n\t\t\t\tresults.push(result);\n\t\t\t} else {\n\t\t\t\tlet lowestIndex = 0;\n\t\t\t\tlet lowestScore = results[0].score;\n\t\t\t\tfor (let i = 1; i < results.length; i++) {\n\t\t\t\t\tif (results[i].score < lowestScore) {\n\t\t\t\t\t\tlowestIndex = i;\n\t\t\t\t\t\tlowestScore = results[i].score;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (result.score > lowestScore) {\n\t\t\t\t\tresults[lowestIndex] = result;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tresults.sort((a, b) => {\n\t\treturn b.score - a.score;\n\t});\n\n\treturn results;\n}\n"],"mappings":"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"}
@@ -1,4 +1,4 @@
1
-
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  //#region src/sort/sort-by-property.ts
3
3
  const sortByProperty = (property, arr, order = "asc") => arr.sort((a, b) => {
4
4
  const result = String(a[property]).localeCompare(String(b[property]), void 0, {
@@ -7,7 +7,7 @@ const sortByProperty = (property, arr, order = "asc") => arr.sort((a, b) => {
7
7
  });
8
8
  return order === "asc" ? result : -result;
9
9
  });
10
-
11
10
  //#endregion
12
11
  exports.sortByProperty = sortByProperty;
12
+
13
13
  //# sourceMappingURL=sort-by-property.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"sort-by-property.cjs","names":[],"sources":["../../src/sort/sort-by-property.ts"],"sourcesContent":["export const sortByProperty = <T>(\n\tproperty: keyof T,\n\tarr: T[],\n\torder: 'asc' | 'desc' = 'asc',\n): T[] =>\n\tarr.sort((a, b) => {\n\t\tconst result = String(a[property]).localeCompare(String(b[property]), undefined, {\n\t\t\tnumeric: true,\n\t\t\tsensitivity: 'base',\n\t\t});\n\t\treturn order === 'asc' ? result : -result;\n\t});\n"],"mappings":";;AAAA,MAAa,kBACZ,UACA,KACA,QAAwB,UAExB,IAAI,MAAM,GAAG,MAAM;CAClB,MAAM,SAAS,OAAO,EAAE,UAAU,CAAC,cAAc,OAAO,EAAE,UAAU,EAAE,QAAW;EAChF,SAAS;EACT,aAAa;EACb,CAAC;AACF,QAAO,UAAU,QAAQ,SAAS,CAAC;EAClC"}
1
+ {"version":3,"file":"sort-by-property.cjs","names":[],"sources":["../../src/sort/sort-by-property.ts"],"sourcesContent":["export const sortByProperty = <T>(\n\tproperty: keyof T,\n\tarr: T[],\n\torder: 'asc' | 'desc' = 'asc',\n): T[] =>\n\tarr.sort((a, b) => {\n\t\tconst result = String(a[property]).localeCompare(String(b[property]), undefined, {\n\t\t\tnumeric: true,\n\t\t\tsensitivity: 'base',\n\t\t});\n\t\treturn order === 'asc' ? result : -result;\n\t});\n"],"mappings":";;AAAA,MAAa,kBACZ,UACA,KACA,QAAwB,UAExB,IAAI,MAAM,GAAG,MAAM;CAClB,MAAM,SAAS,OAAO,EAAE,SAAS,CAAC,CAAC,cAAc,OAAO,EAAE,SAAS,GAAG,KAAA,GAAW;EAChF,SAAS;EACT,aAAa;CACd,CAAC;CACD,OAAO,UAAU,QAAQ,SAAS,CAAC;AACpC,CAAC"}
@@ -1,5 +1,5 @@
1
1
  //#region src/sort/sort-by-property.d.ts
2
- declare const sortByProperty: <T>(property: keyof T, arr: T[], order?: "asc" | "desc") => T[];
2
+ declare const sortByProperty: <T>(property: keyof T, arr: T[], order?: 'asc' | 'desc') => T[];
3
3
  //#endregion
4
4
  export { sortByProperty };
5
5
  //# sourceMappingURL=sort-by-property.d.cts.map
@@ -1,5 +1,5 @@
1
1
  //#region src/sort/sort-by-property.d.ts
2
- declare const sortByProperty: <T>(property: keyof T, arr: T[], order?: "asc" | "desc") => T[];
2
+ declare const sortByProperty: <T>(property: keyof T, arr: T[], order?: 'asc' | 'desc') => T[];
3
3
  //#endregion
4
4
  export { sortByProperty };
5
5
  //# sourceMappingURL=sort-by-property.d.mts.map
@@ -6,7 +6,7 @@ const sortByProperty = (property, arr, order = "asc") => arr.sort((a, b) => {
6
6
  });
7
7
  return order === "asc" ? result : -result;
8
8
  });
9
-
10
9
  //#endregion
11
10
  export { sortByProperty };
11
+
12
12
  //# sourceMappingURL=sort-by-property.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"sort-by-property.mjs","names":[],"sources":["../../src/sort/sort-by-property.ts"],"sourcesContent":["export const sortByProperty = <T>(\n\tproperty: keyof T,\n\tarr: T[],\n\torder: 'asc' | 'desc' = 'asc',\n): T[] =>\n\tarr.sort((a, b) => {\n\t\tconst result = String(a[property]).localeCompare(String(b[property]), undefined, {\n\t\t\tnumeric: true,\n\t\t\tsensitivity: 'base',\n\t\t});\n\t\treturn order === 'asc' ? result : -result;\n\t});\n"],"mappings":";AAAA,MAAa,kBACZ,UACA,KACA,QAAwB,UAExB,IAAI,MAAM,GAAG,MAAM;CAClB,MAAM,SAAS,OAAO,EAAE,UAAU,CAAC,cAAc,OAAO,EAAE,UAAU,EAAE,QAAW;EAChF,SAAS;EACT,aAAa;EACb,CAAC;AACF,QAAO,UAAU,QAAQ,SAAS,CAAC;EAClC"}
1
+ {"version":3,"file":"sort-by-property.mjs","names":[],"sources":["../../src/sort/sort-by-property.ts"],"sourcesContent":["export const sortByProperty = <T>(\n\tproperty: keyof T,\n\tarr: T[],\n\torder: 'asc' | 'desc' = 'asc',\n): T[] =>\n\tarr.sort((a, b) => {\n\t\tconst result = String(a[property]).localeCompare(String(b[property]), undefined, {\n\t\t\tnumeric: true,\n\t\t\tsensitivity: 'base',\n\t\t});\n\t\treturn order === 'asc' ? result : -result;\n\t});\n"],"mappings":";AAAA,MAAa,kBACZ,UACA,KACA,QAAwB,UAExB,IAAI,MAAM,GAAG,MAAM;CAClB,MAAM,SAAS,OAAO,EAAE,SAAS,CAAC,CAAC,cAAc,OAAO,EAAE,SAAS,GAAG,KAAA,GAAW;EAChF,SAAS;EACT,aAAa;CACd,CAAC;CACD,OAAO,UAAU,QAAQ,SAAS,CAAC;AACpC,CAAC"}
@@ -1,4 +1,4 @@
1
-
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  //#region src/string/truncate.ts
3
3
  const truncate = (text, length = 30) => text.length > length ? text.slice(0, length) + "..." : text;
4
4
  /**
@@ -26,8 +26,8 @@ function truncateBeforeLast(text, maxLength, lastCharsLength = 5, minLastWordLen
26
26
  if (lastCharsLength < 1) return chars.slice(0, maxLength).join("") + ellipsis;
27
27
  return chars.slice(0, maxLength - lastCharsLength - ellipsisLength).join("") + ellipsis + chars.slice(-lastCharsLength).join("");
28
28
  }
29
-
30
29
  //#endregion
31
30
  exports.truncate = truncate;
32
31
  exports.truncateBeforeLast = truncateBeforeLast;
32
+
33
33
  //# sourceMappingURL=truncate.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"truncate.cjs","names":["chars: string[]"],"sources":["../../src/string/truncate.ts"],"sourcesContent":["export const truncate = (text: string, length = 30): string =>\n\ttext.length > length ? text.slice(0, length) + '...' : text;\n\n/**\n * Replace part of given text with ellipsis following the rules below:\n *\n * - Remove chars just before the last word, as long as the last word is between\n * minLastWordLength and 15 chars\n * - Otherwise preserve the last `lastCharsLength` chars and remove chars before that\n */\nexport function truncateBeforeLast(\n\ttext: string,\n\tmaxLength: number,\n\tlastCharsLength: number = 5,\n\tminLastWordLength: number = 1,\n): string {\n\tconst chars: string[] = [];\n\n\tconst segmenter = new Intl.Segmenter(undefined, { granularity: 'grapheme' });\n\n\tfor (const { segment } of segmenter.segment(text)) {\n\t\tchars.push(segment);\n\t}\n\n\tif (chars.length <= maxLength) {\n\t\treturn text;\n\t}\n\n\tconst lastWhitespaceIndex = chars.findLastIndex((ch) => ch.match(/^\\s+$/));\n\tconst lastWordIndex = lastWhitespaceIndex + 1;\n\tconst lastWord = chars.slice(lastWordIndex);\n\tconst ellipsis = '…';\n\tconst ellipsisLength = ellipsis.length;\n\n\tif (lastWord.length >= minLastWordLength && lastWord.length < 15) {\n\t\tconst charsToRemove = chars.length - maxLength + ellipsisLength;\n\t\tconst indexBeforeLastWord = lastWordIndex;\n\t\tconst keepLength = indexBeforeLastWord - charsToRemove;\n\n\t\tif (keepLength > 0) {\n\t\t\treturn (\n\t\t\t\tchars.slice(0, keepLength).join('') + ellipsis + chars.slice(indexBeforeLastWord).join('')\n\t\t\t);\n\t\t}\n\t}\n\n\tif (lastCharsLength < 1) {\n\t\treturn chars.slice(0, maxLength).join('') + ellipsis;\n\t}\n\n\treturn (\n\t\tchars.slice(0, maxLength - lastCharsLength - ellipsisLength).join('') +\n\t\tellipsis +\n\t\tchars.slice(-lastCharsLength).join('')\n\t);\n}\n"],"mappings":";;AAAA,MAAa,YAAY,MAAc,SAAS,OAC/C,KAAK,SAAS,SAAS,KAAK,MAAM,GAAG,OAAO,GAAG,QAAQ;;;;;;;;AASxD,SAAgB,mBACf,MACA,WACA,kBAA0B,GAC1B,oBAA4B,GACnB;CACT,MAAMA,QAAkB,EAAE;CAE1B,MAAM,YAAY,IAAI,KAAK,UAAU,QAAW,EAAE,aAAa,YAAY,CAAC;AAE5E,MAAK,MAAM,EAAE,aAAa,UAAU,QAAQ,KAAK,CAChD,OAAM,KAAK,QAAQ;AAGpB,KAAI,MAAM,UAAU,UACnB,QAAO;CAIR,MAAM,gBADsB,MAAM,eAAe,OAAO,GAAG,MAAM,QAAQ,CAAC,GAC9B;CAC5C,MAAM,WAAW,MAAM,MAAM,cAAc;CAC3C,MAAM,WAAW;CACjB,MAAM,iBAAiB;AAEvB,KAAI,SAAS,UAAU,qBAAqB,SAAS,SAAS,IAAI;EACjE,MAAM,gBAAgB,MAAM,SAAS,YAAY;EACjD,MAAM,sBAAsB;EAC5B,MAAM,aAAa,sBAAsB;AAEzC,MAAI,aAAa,EAChB,QACC,MAAM,MAAM,GAAG,WAAW,CAAC,KAAK,GAAG,GAAG,WAAW,MAAM,MAAM,oBAAoB,CAAC,KAAK,GAAG;;AAK7F,KAAI,kBAAkB,EACrB,QAAO,MAAM,MAAM,GAAG,UAAU,CAAC,KAAK,GAAG,GAAG;AAG7C,QACC,MAAM,MAAM,GAAG,YAAY,kBAAkB,eAAe,CAAC,KAAK,GAAG,GACrE,WACA,MAAM,MAAM,CAAC,gBAAgB,CAAC,KAAK,GAAG"}
1
+ {"version":3,"file":"truncate.cjs","names":[],"sources":["../../src/string/truncate.ts"],"sourcesContent":["export const truncate = (text: string, length = 30): string =>\n\ttext.length > length ? text.slice(0, length) + '...' : text;\n\n/**\n * Replace part of given text with ellipsis following the rules below:\n *\n * - Remove chars just before the last word, as long as the last word is between\n * minLastWordLength and 15 chars\n * - Otherwise preserve the last `lastCharsLength` chars and remove chars before that\n */\nexport function truncateBeforeLast(\n\ttext: string,\n\tmaxLength: number,\n\tlastCharsLength: number = 5,\n\tminLastWordLength: number = 1,\n): string {\n\tconst chars: string[] = [];\n\n\tconst segmenter = new Intl.Segmenter(undefined, { granularity: 'grapheme' });\n\n\tfor (const { segment } of segmenter.segment(text)) {\n\t\tchars.push(segment);\n\t}\n\n\tif (chars.length <= maxLength) {\n\t\treturn text;\n\t}\n\n\tconst lastWhitespaceIndex = chars.findLastIndex((ch) => ch.match(/^\\s+$/));\n\tconst lastWordIndex = lastWhitespaceIndex + 1;\n\tconst lastWord = chars.slice(lastWordIndex);\n\tconst ellipsis = '…';\n\tconst ellipsisLength = ellipsis.length;\n\n\tif (lastWord.length >= minLastWordLength && lastWord.length < 15) {\n\t\tconst charsToRemove = chars.length - maxLength + ellipsisLength;\n\t\tconst indexBeforeLastWord = lastWordIndex;\n\t\tconst keepLength = indexBeforeLastWord - charsToRemove;\n\n\t\tif (keepLength > 0) {\n\t\t\treturn (\n\t\t\t\tchars.slice(0, keepLength).join('') + ellipsis + chars.slice(indexBeforeLastWord).join('')\n\t\t\t);\n\t\t}\n\t}\n\n\tif (lastCharsLength < 1) {\n\t\treturn chars.slice(0, maxLength).join('') + ellipsis;\n\t}\n\n\treturn (\n\t\tchars.slice(0, maxLength - lastCharsLength - ellipsisLength).join('') +\n\t\tellipsis +\n\t\tchars.slice(-lastCharsLength).join('')\n\t);\n}\n"],"mappings":";;AAAA,MAAa,YAAY,MAAc,SAAS,OAC/C,KAAK,SAAS,SAAS,KAAK,MAAM,GAAG,MAAM,IAAI,QAAQ;;;;;;;;AASxD,SAAgB,mBACf,MACA,WACA,kBAA0B,GAC1B,oBAA4B,GACnB;CACT,MAAM,QAAkB,CAAC;CAEzB,MAAM,YAAY,IAAI,KAAK,UAAU,KAAA,GAAW,EAAE,aAAa,WAAW,CAAC;CAE3E,KAAK,MAAM,EAAE,aAAa,UAAU,QAAQ,IAAI,GAC/C,MAAM,KAAK,OAAO;CAGnB,IAAI,MAAM,UAAU,WACnB,OAAO;CAIR,MAAM,gBADsB,MAAM,eAAe,OAAO,GAAG,MAAM,OAAO,CAChC,IAAI;CAC5C,MAAM,WAAW,MAAM,MAAM,aAAa;CAC1C,MAAM,WAAW;CACjB,MAAM,iBAAiB;CAEvB,IAAI,SAAS,UAAU,qBAAqB,SAAS,SAAS,IAAI;EACjE,MAAM,gBAAgB,MAAM,SAAS,YAAY;EACjD,MAAM,sBAAsB;EAC5B,MAAM,aAAa,sBAAsB;EAEzC,IAAI,aAAa,GAChB,OACC,MAAM,MAAM,GAAG,UAAU,CAAC,CAAC,KAAK,EAAE,IAAI,WAAW,MAAM,MAAM,mBAAmB,CAAC,CAAC,KAAK,EAAE;CAG5F;CAEA,IAAI,kBAAkB,GACrB,OAAO,MAAM,MAAM,GAAG,SAAS,CAAC,CAAC,KAAK,EAAE,IAAI;CAG7C,OACC,MAAM,MAAM,GAAG,YAAY,kBAAkB,cAAc,CAAC,CAAC,KAAK,EAAE,IACpE,WACA,MAAM,MAAM,CAAC,eAAe,CAAC,CAAC,KAAK,EAAE;AAEvC"}
@@ -25,7 +25,7 @@ function truncateBeforeLast(text, maxLength, lastCharsLength = 5, minLastWordLen
25
25
  if (lastCharsLength < 1) return chars.slice(0, maxLength).join("") + ellipsis;
26
26
  return chars.slice(0, maxLength - lastCharsLength - ellipsisLength).join("") + ellipsis + chars.slice(-lastCharsLength).join("");
27
27
  }
28
-
29
28
  //#endregion
30
29
  export { truncate, truncateBeforeLast };
30
+
31
31
  //# sourceMappingURL=truncate.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"truncate.mjs","names":["chars: string[]"],"sources":["../../src/string/truncate.ts"],"sourcesContent":["export const truncate = (text: string, length = 30): string =>\n\ttext.length > length ? text.slice(0, length) + '...' : text;\n\n/**\n * Replace part of given text with ellipsis following the rules below:\n *\n * - Remove chars just before the last word, as long as the last word is between\n * minLastWordLength and 15 chars\n * - Otherwise preserve the last `lastCharsLength` chars and remove chars before that\n */\nexport function truncateBeforeLast(\n\ttext: string,\n\tmaxLength: number,\n\tlastCharsLength: number = 5,\n\tminLastWordLength: number = 1,\n): string {\n\tconst chars: string[] = [];\n\n\tconst segmenter = new Intl.Segmenter(undefined, { granularity: 'grapheme' });\n\n\tfor (const { segment } of segmenter.segment(text)) {\n\t\tchars.push(segment);\n\t}\n\n\tif (chars.length <= maxLength) {\n\t\treturn text;\n\t}\n\n\tconst lastWhitespaceIndex = chars.findLastIndex((ch) => ch.match(/^\\s+$/));\n\tconst lastWordIndex = lastWhitespaceIndex + 1;\n\tconst lastWord = chars.slice(lastWordIndex);\n\tconst ellipsis = '…';\n\tconst ellipsisLength = ellipsis.length;\n\n\tif (lastWord.length >= minLastWordLength && lastWord.length < 15) {\n\t\tconst charsToRemove = chars.length - maxLength + ellipsisLength;\n\t\tconst indexBeforeLastWord = lastWordIndex;\n\t\tconst keepLength = indexBeforeLastWord - charsToRemove;\n\n\t\tif (keepLength > 0) {\n\t\t\treturn (\n\t\t\t\tchars.slice(0, keepLength).join('') + ellipsis + chars.slice(indexBeforeLastWord).join('')\n\t\t\t);\n\t\t}\n\t}\n\n\tif (lastCharsLength < 1) {\n\t\treturn chars.slice(0, maxLength).join('') + ellipsis;\n\t}\n\n\treturn (\n\t\tchars.slice(0, maxLength - lastCharsLength - ellipsisLength).join('') +\n\t\tellipsis +\n\t\tchars.slice(-lastCharsLength).join('')\n\t);\n}\n"],"mappings":";AAAA,MAAa,YAAY,MAAc,SAAS,OAC/C,KAAK,SAAS,SAAS,KAAK,MAAM,GAAG,OAAO,GAAG,QAAQ;;;;;;;;AASxD,SAAgB,mBACf,MACA,WACA,kBAA0B,GAC1B,oBAA4B,GACnB;CACT,MAAMA,QAAkB,EAAE;CAE1B,MAAM,YAAY,IAAI,KAAK,UAAU,QAAW,EAAE,aAAa,YAAY,CAAC;AAE5E,MAAK,MAAM,EAAE,aAAa,UAAU,QAAQ,KAAK,CAChD,OAAM,KAAK,QAAQ;AAGpB,KAAI,MAAM,UAAU,UACnB,QAAO;CAIR,MAAM,gBADsB,MAAM,eAAe,OAAO,GAAG,MAAM,QAAQ,CAAC,GAC9B;CAC5C,MAAM,WAAW,MAAM,MAAM,cAAc;CAC3C,MAAM,WAAW;CACjB,MAAM,iBAAiB;AAEvB,KAAI,SAAS,UAAU,qBAAqB,SAAS,SAAS,IAAI;EACjE,MAAM,gBAAgB,MAAM,SAAS,YAAY;EACjD,MAAM,sBAAsB;EAC5B,MAAM,aAAa,sBAAsB;AAEzC,MAAI,aAAa,EAChB,QACC,MAAM,MAAM,GAAG,WAAW,CAAC,KAAK,GAAG,GAAG,WAAW,MAAM,MAAM,oBAAoB,CAAC,KAAK,GAAG;;AAK7F,KAAI,kBAAkB,EACrB,QAAO,MAAM,MAAM,GAAG,UAAU,CAAC,KAAK,GAAG,GAAG;AAG7C,QACC,MAAM,MAAM,GAAG,YAAY,kBAAkB,eAAe,CAAC,KAAK,GAAG,GACrE,WACA,MAAM,MAAM,CAAC,gBAAgB,CAAC,KAAK,GAAG"}
1
+ {"version":3,"file":"truncate.mjs","names":[],"sources":["../../src/string/truncate.ts"],"sourcesContent":["export const truncate = (text: string, length = 30): string =>\n\ttext.length > length ? text.slice(0, length) + '...' : text;\n\n/**\n * Replace part of given text with ellipsis following the rules below:\n *\n * - Remove chars just before the last word, as long as the last word is between\n * minLastWordLength and 15 chars\n * - Otherwise preserve the last `lastCharsLength` chars and remove chars before that\n */\nexport function truncateBeforeLast(\n\ttext: string,\n\tmaxLength: number,\n\tlastCharsLength: number = 5,\n\tminLastWordLength: number = 1,\n): string {\n\tconst chars: string[] = [];\n\n\tconst segmenter = new Intl.Segmenter(undefined, { granularity: 'grapheme' });\n\n\tfor (const { segment } of segmenter.segment(text)) {\n\t\tchars.push(segment);\n\t}\n\n\tif (chars.length <= maxLength) {\n\t\treturn text;\n\t}\n\n\tconst lastWhitespaceIndex = chars.findLastIndex((ch) => ch.match(/^\\s+$/));\n\tconst lastWordIndex = lastWhitespaceIndex + 1;\n\tconst lastWord = chars.slice(lastWordIndex);\n\tconst ellipsis = '…';\n\tconst ellipsisLength = ellipsis.length;\n\n\tif (lastWord.length >= minLastWordLength && lastWord.length < 15) {\n\t\tconst charsToRemove = chars.length - maxLength + ellipsisLength;\n\t\tconst indexBeforeLastWord = lastWordIndex;\n\t\tconst keepLength = indexBeforeLastWord - charsToRemove;\n\n\t\tif (keepLength > 0) {\n\t\t\treturn (\n\t\t\t\tchars.slice(0, keepLength).join('') + ellipsis + chars.slice(indexBeforeLastWord).join('')\n\t\t\t);\n\t\t}\n\t}\n\n\tif (lastCharsLength < 1) {\n\t\treturn chars.slice(0, maxLength).join('') + ellipsis;\n\t}\n\n\treturn (\n\t\tchars.slice(0, maxLength - lastCharsLength - ellipsisLength).join('') +\n\t\tellipsis +\n\t\tchars.slice(-lastCharsLength).join('')\n\t);\n}\n"],"mappings":";AAAA,MAAa,YAAY,MAAc,SAAS,OAC/C,KAAK,SAAS,SAAS,KAAK,MAAM,GAAG,MAAM,IAAI,QAAQ;;;;;;;;AASxD,SAAgB,mBACf,MACA,WACA,kBAA0B,GAC1B,oBAA4B,GACnB;CACT,MAAM,QAAkB,CAAC;CAEzB,MAAM,YAAY,IAAI,KAAK,UAAU,KAAA,GAAW,EAAE,aAAa,WAAW,CAAC;CAE3E,KAAK,MAAM,EAAE,aAAa,UAAU,QAAQ,IAAI,GAC/C,MAAM,KAAK,OAAO;CAGnB,IAAI,MAAM,UAAU,WACnB,OAAO;CAIR,MAAM,gBADsB,MAAM,eAAe,OAAO,GAAG,MAAM,OAAO,CAChC,IAAI;CAC5C,MAAM,WAAW,MAAM,MAAM,aAAa;CAC1C,MAAM,WAAW;CACjB,MAAM,iBAAiB;CAEvB,IAAI,SAAS,UAAU,qBAAqB,SAAS,SAAS,IAAI;EACjE,MAAM,gBAAgB,MAAM,SAAS,YAAY;EACjD,MAAM,sBAAsB;EAC5B,MAAM,aAAa,sBAAsB;EAEzC,IAAI,aAAa,GAChB,OACC,MAAM,MAAM,GAAG,UAAU,CAAC,CAAC,KAAK,EAAE,IAAI,WAAW,MAAM,MAAM,mBAAmB,CAAC,CAAC,KAAK,EAAE;CAG5F;CAEA,IAAI,kBAAkB,GACrB,OAAO,MAAM,MAAM,GAAG,SAAS,CAAC,CAAC,KAAK,EAAE,IAAI;CAG7C,OACC,MAAM,MAAM,GAAG,YAAY,kBAAkB,cAAc,CAAC,CAAC,KAAK,EAAE,IACpE,WACA,MAAM,MAAM,CAAC,eAAe,CAAC,CAAC,KAAK,EAAE;AAEvC"}
package/dist/types.mjs CHANGED
@@ -1 +1 @@
1
- export { };
1
+ export {};
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "@n8n/utils",
3
3
  "type": "module",
4
- "version": "1.39.0",
4
+ "version": "1.41.0",
5
5
  "files": [
6
6
  "dist",
7
- "LICENSE_EE.md",
8
- "LICENSE.md"
7
+ "LICENSE.md",
8
+ "LICENSE_EE.md"
9
9
  ],
10
10
  "exports": {
11
11
  "./dist/*": {
@@ -28,18 +28,18 @@
28
28
  },
29
29
  "dependencies": {
30
30
  "nanoid": "3.3.8",
31
- "@n8n/constants": "0.31.0"
31
+ "@n8n/constants": "0.32.0"
32
32
  },
33
33
  "devDependencies": {
34
34
  "@testing-library/jest-dom": "^6.6.3",
35
35
  "@testing-library/user-event": "^14.6.1",
36
- "tsdown": "^0.16.5",
37
- "typescript": "6.0.2",
36
+ "tsdown": "^0.22.8",
37
+ "typescript": "7.0.2",
38
38
  "vite": "^8.0.2",
39
39
  "vitest": "^4.1.9",
40
+ "@n8n/typescript-config": "1.9.0",
40
41
  "@n8n/eslint-config": "0.0.1",
41
- "@n8n/vitest-config": "1.18.0",
42
- "@n8n/typescript-config": "1.9.0"
42
+ "@n8n/vitest-config": "1.19.0"
43
43
  },
44
44
  "license": "SEE LICENSE IN LICENSE.md",
45
45
  "homepage": "https://n8n.io",
@@ -1,15 +0,0 @@
1
-
2
- //#region src/errors/ensure-error.ts
3
- /** Ensures `error` is an `Error */
4
- function ensureError(error) {
5
- return error instanceof Error ? error : new Error("Error that was not an instance of Error was thrown", { cause: error });
6
- }
7
-
8
- //#endregion
9
- Object.defineProperty(exports, 'ensureError', {
10
- enumerable: true,
11
- get: function () {
12
- return ensureError;
13
- }
14
- });
15
- //# sourceMappingURL=ensure-error.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ensure-error.cjs","names":[],"sources":["../src/errors/ensure-error.ts"],"sourcesContent":["/** Ensures `error` is an `Error */\nexport function ensureError(error: unknown): Error {\n\treturn error instanceof Error\n\t\t? error\n\t\t: new Error('Error that was not an instance of Error was thrown', {\n\t\t\t\t// We should never throw anything except something that derives from Error\n\t\t\t\tcause: error,\n\t\t\t});\n}\n"],"mappings":";;;AACA,SAAgB,YAAY,OAAuB;AAClD,QAAO,iBAAiB,QACrB,QACA,IAAI,MAAM,sDAAsD,EAEhE,OAAO,OACP,CAAC"}
@@ -1,9 +0,0 @@
1
- //#region src/errors/ensure-error.ts
2
- /** Ensures `error` is an `Error */
3
- function ensureError(error) {
4
- return error instanceof Error ? error : new Error("Error that was not an instance of Error was thrown", { cause: error });
5
- }
6
-
7
- //#endregion
8
- export { ensureError as t };
9
- //# sourceMappingURL=ensure-error.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ensure-error.mjs","names":[],"sources":["../src/errors/ensure-error.ts"],"sourcesContent":["/** Ensures `error` is an `Error */\nexport function ensureError(error: unknown): Error {\n\treturn error instanceof Error\n\t\t? error\n\t\t: new Error('Error that was not an instance of Error was thrown', {\n\t\t\t\t// We should never throw anything except something that derives from Error\n\t\t\t\tcause: error,\n\t\t\t});\n}\n"],"mappings":";;AACA,SAAgB,YAAY,OAAuB;AAClD,QAAO,iBAAiB,QACrB,QACA,IAAI,MAAM,sDAAsD,EAEhE,OAAO,OACP,CAAC"}
@@ -1,47 +0,0 @@
1
-
2
- //#region src/format-pem-block.ts
3
- const PEM_BODY_LINE_LENGTH = 64;
4
- function formatCompactPem(pem, isPublic) {
5
- const trimmed = pem.trim();
6
- if ((trimmed.match(/-----BEGIN /g) ?? []).length !== 1) return void 0;
7
- const labelPattern = isPublic ? "[A-Z0-9 ]*PUBLIC KEY" : "[A-Z0-9 ]*PRIVATE KEY|CERTIFICATE";
8
- const pemMatch = trimmed.match(/* @__PURE__ */ new RegExp(`^-----BEGIN (${labelPattern})-----([\\s\\S]*?)-----END \\1-----$`));
9
- if (!pemMatch) return void 0;
10
- const [, label, body] = pemMatch;
11
- const normalizedBody = body.replace(/\\n/g, "\n").trim();
12
- return `-----BEGIN ${label}-----\n${/\s/.test(normalizedBody) ? normalizedBody.replace(/:\s+/g, ":").replace(/\s+/g, "\n") : (normalizedBody.match(new RegExp(`.{1,${PEM_BODY_LINE_LENGTH}}`, "g")) ?? []).join("\n")}\n-----END ${label}-----`;
13
- }
14
- /**
15
- * Normalize a single PEM-encoded block (private key, public key, or certificate)
16
- * by collapsing whitespace and wrapping the body at 64 chars. Multi-block PEM
17
- * chains are returned unchanged.
18
- *
19
- * @param pem - The PEM-encoded block to format.
20
- * @param isPublic - When true, match `PUBLIC KEY` labels instead of the default `PRIVATE KEY` / `CERTIFICATE`.
21
- * @returns The formatted PEM block.
22
- */
23
- function formatPemBlock(pem, isPublic = false) {
24
- let regex = /(PRIVATE KEY|CERTIFICATE)/;
25
- if (isPublic) regex = /(PUBLIC KEY)/;
26
- if (!pem || /\n/.test(pem)) return pem;
27
- const compactPem = formatCompactPem(pem, isPublic);
28
- if (compactPem !== void 0) return compactPem;
29
- let formattedPem = "";
30
- pem.split("-----").filter((item) => item !== "").forEach((part) => {
31
- if (regex.test(part)) formattedPem += `-----${part}-----`;
32
- else if (/Proc-Type|DEK-Info/.test(part)) {
33
- part = part.replace(/:\s+/g, ":");
34
- formattedPem += part.replace(/\\n/g, "\n").replace(/\s+/g, "\n");
35
- } else formattedPem += part.replace(/\\n/g, "\n").replace(/\s+/g, "\n");
36
- });
37
- return formattedPem;
38
- }
39
-
40
- //#endregion
41
- Object.defineProperty(exports, 'formatPemBlock', {
42
- enumerable: true,
43
- get: function () {
44
- return formatPemBlock;
45
- }
46
- });
47
- //# sourceMappingURL=format-pem-block2.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"format-pem-block2.cjs","names":[],"sources":["../src/format-pem-block.ts"],"sourcesContent":["const PEM_BODY_LINE_LENGTH = 64;\n\nfunction formatCompactPem(pem: string, isPublic: boolean): string | undefined {\n\tconst trimmed = pem.trim();\n\tif ((trimmed.match(/-----BEGIN /g) ?? []).length !== 1) return undefined;\n\n\tconst labelPattern = isPublic ? '[A-Z0-9 ]*PUBLIC KEY' : '[A-Z0-9 ]*PRIVATE KEY|CERTIFICATE';\n\tconst pemMatch = trimmed.match(\n\t\tnew RegExp(`^-----BEGIN (${labelPattern})-----([\\\\s\\\\S]*?)-----END \\\\1-----$`),\n\t);\n\n\tif (!pemMatch) return undefined;\n\n\tconst [, label, body] = pemMatch;\n\tconst normalizedBody = body.replace(/\\\\n/g, '\\n').trim();\n\tconst formattedBody = /\\s/.test(normalizedBody)\n\t\t? normalizedBody.replace(/:\\s+/g, ':').replace(/\\s+/g, '\\n')\n\t\t: (normalizedBody.match(new RegExp(`.{1,${PEM_BODY_LINE_LENGTH}}`, 'g')) ?? []).join('\\n');\n\n\treturn `-----BEGIN ${label}-----\\n${formattedBody}\\n-----END ${label}-----`;\n}\n\n/**\n * Normalize a single PEM-encoded block (private key, public key, or certificate)\n * by collapsing whitespace and wrapping the body at 64 chars. Multi-block PEM\n * chains are returned unchanged.\n *\n * @param pem - The PEM-encoded block to format.\n * @param isPublic - When true, match `PUBLIC KEY` labels instead of the default `PRIVATE KEY` / `CERTIFICATE`.\n * @returns The formatted PEM block.\n */\nexport function formatPemBlock(pem: string, isPublic = false): string {\n\tlet regex = /(PRIVATE KEY|CERTIFICATE)/;\n\tif (isPublic) {\n\t\tregex = /(PUBLIC KEY)/;\n\t}\n\tif (!pem || /\\n/.test(pem)) {\n\t\treturn pem;\n\t}\n\tconst compactPem = formatCompactPem(pem, isPublic);\n\tif (compactPem !== undefined) {\n\t\treturn compactPem;\n\t}\n\n\tlet formattedPem = '';\n\tconst parts = pem.split('-----').filter((item) => item !== '');\n\tparts.forEach((part) => {\n\t\tif (regex.test(part)) {\n\t\t\tformattedPem += `-----${part}-----`;\n\t\t} else {\n\t\t\tconst passRegex = /Proc-Type|DEK-Info/;\n\t\t\tif (passRegex.test(part)) {\n\t\t\t\tpart = part.replace(/:\\s+/g, ':');\n\t\t\t\tformattedPem += part.replace(/\\\\n/g, '\\n').replace(/\\s+/g, '\\n');\n\t\t\t} else {\n\t\t\t\tformattedPem += part.replace(/\\\\n/g, '\\n').replace(/\\s+/g, '\\n');\n\t\t\t}\n\t\t}\n\t});\n\treturn formattedPem;\n}\n"],"mappings":";;AAAA,MAAM,uBAAuB;AAE7B,SAAS,iBAAiB,KAAa,UAAuC;CAC7E,MAAM,UAAU,IAAI,MAAM;AAC1B,MAAK,QAAQ,MAAM,eAAe,IAAI,EAAE,EAAE,WAAW,EAAG,QAAO;CAE/D,MAAM,eAAe,WAAW,yBAAyB;CACzD,MAAM,WAAW,QAAQ,sBACxB,IAAI,OAAO,gBAAgB,aAAa,sCAAsC,CAC9E;AAED,KAAI,CAAC,SAAU,QAAO;CAEtB,MAAM,GAAG,OAAO,QAAQ;CACxB,MAAM,iBAAiB,KAAK,QAAQ,QAAQ,KAAK,CAAC,MAAM;AAKxD,QAAO,cAAc,MAAM,SAJL,KAAK,KAAK,eAAe,GAC5C,eAAe,QAAQ,SAAS,IAAI,CAAC,QAAQ,QAAQ,KAAK,IACzD,eAAe,MAAM,IAAI,OAAO,OAAO,qBAAqB,IAAI,IAAI,CAAC,IAAI,EAAE,EAAE,KAAK,KAAK,CAEzC,aAAa,MAAM;;;;;;;;;;;AAYtE,SAAgB,eAAe,KAAa,WAAW,OAAe;CACrE,IAAI,QAAQ;AACZ,KAAI,SACH,SAAQ;AAET,KAAI,CAAC,OAAO,KAAK,KAAK,IAAI,CACzB,QAAO;CAER,MAAM,aAAa,iBAAiB,KAAK,SAAS;AAClD,KAAI,eAAe,OAClB,QAAO;CAGR,IAAI,eAAe;AAEnB,CADc,IAAI,MAAM,QAAQ,CAAC,QAAQ,SAAS,SAAS,GAAG,CACxD,SAAS,SAAS;AACvB,MAAI,MAAM,KAAK,KAAK,CACnB,iBAAgB,QAAQ,KAAK;WAEX,qBACJ,KAAK,KAAK,EAAE;AACzB,UAAO,KAAK,QAAQ,SAAS,IAAI;AACjC,mBAAgB,KAAK,QAAQ,QAAQ,KAAK,CAAC,QAAQ,QAAQ,KAAK;QAEhE,iBAAgB,KAAK,QAAQ,QAAQ,KAAK,CAAC,QAAQ,QAAQ,KAAK;GAGjE;AACF,QAAO"}
@@ -1,41 +0,0 @@
1
- //#region src/format-pem-block.ts
2
- const PEM_BODY_LINE_LENGTH = 64;
3
- function formatCompactPem(pem, isPublic) {
4
- const trimmed = pem.trim();
5
- if ((trimmed.match(/-----BEGIN /g) ?? []).length !== 1) return void 0;
6
- const labelPattern = isPublic ? "[A-Z0-9 ]*PUBLIC KEY" : "[A-Z0-9 ]*PRIVATE KEY|CERTIFICATE";
7
- const pemMatch = trimmed.match(/* @__PURE__ */ new RegExp(`^-----BEGIN (${labelPattern})-----([\\s\\S]*?)-----END \\1-----$`));
8
- if (!pemMatch) return void 0;
9
- const [, label, body] = pemMatch;
10
- const normalizedBody = body.replace(/\\n/g, "\n").trim();
11
- return `-----BEGIN ${label}-----\n${/\s/.test(normalizedBody) ? normalizedBody.replace(/:\s+/g, ":").replace(/\s+/g, "\n") : (normalizedBody.match(new RegExp(`.{1,${PEM_BODY_LINE_LENGTH}}`, "g")) ?? []).join("\n")}\n-----END ${label}-----`;
12
- }
13
- /**
14
- * Normalize a single PEM-encoded block (private key, public key, or certificate)
15
- * by collapsing whitespace and wrapping the body at 64 chars. Multi-block PEM
16
- * chains are returned unchanged.
17
- *
18
- * @param pem - The PEM-encoded block to format.
19
- * @param isPublic - When true, match `PUBLIC KEY` labels instead of the default `PRIVATE KEY` / `CERTIFICATE`.
20
- * @returns The formatted PEM block.
21
- */
22
- function formatPemBlock(pem, isPublic = false) {
23
- let regex = /(PRIVATE KEY|CERTIFICATE)/;
24
- if (isPublic) regex = /(PUBLIC KEY)/;
25
- if (!pem || /\n/.test(pem)) return pem;
26
- const compactPem = formatCompactPem(pem, isPublic);
27
- if (compactPem !== void 0) return compactPem;
28
- let formattedPem = "";
29
- pem.split("-----").filter((item) => item !== "").forEach((part) => {
30
- if (regex.test(part)) formattedPem += `-----${part}-----`;
31
- else if (/Proc-Type|DEK-Info/.test(part)) {
32
- part = part.replace(/:\s+/g, ":");
33
- formattedPem += part.replace(/\\n/g, "\n").replace(/\s+/g, "\n");
34
- } else formattedPem += part.replace(/\\n/g, "\n").replace(/\s+/g, "\n");
35
- });
36
- return formattedPem;
37
- }
38
-
39
- //#endregion
40
- export { formatPemBlock as t };
41
- //# sourceMappingURL=format-pem-block2.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"format-pem-block2.mjs","names":[],"sources":["../src/format-pem-block.ts"],"sourcesContent":["const PEM_BODY_LINE_LENGTH = 64;\n\nfunction formatCompactPem(pem: string, isPublic: boolean): string | undefined {\n\tconst trimmed = pem.trim();\n\tif ((trimmed.match(/-----BEGIN /g) ?? []).length !== 1) return undefined;\n\n\tconst labelPattern = isPublic ? '[A-Z0-9 ]*PUBLIC KEY' : '[A-Z0-9 ]*PRIVATE KEY|CERTIFICATE';\n\tconst pemMatch = trimmed.match(\n\t\tnew RegExp(`^-----BEGIN (${labelPattern})-----([\\\\s\\\\S]*?)-----END \\\\1-----$`),\n\t);\n\n\tif (!pemMatch) return undefined;\n\n\tconst [, label, body] = pemMatch;\n\tconst normalizedBody = body.replace(/\\\\n/g, '\\n').trim();\n\tconst formattedBody = /\\s/.test(normalizedBody)\n\t\t? normalizedBody.replace(/:\\s+/g, ':').replace(/\\s+/g, '\\n')\n\t\t: (normalizedBody.match(new RegExp(`.{1,${PEM_BODY_LINE_LENGTH}}`, 'g')) ?? []).join('\\n');\n\n\treturn `-----BEGIN ${label}-----\\n${formattedBody}\\n-----END ${label}-----`;\n}\n\n/**\n * Normalize a single PEM-encoded block (private key, public key, or certificate)\n * by collapsing whitespace and wrapping the body at 64 chars. Multi-block PEM\n * chains are returned unchanged.\n *\n * @param pem - The PEM-encoded block to format.\n * @param isPublic - When true, match `PUBLIC KEY` labels instead of the default `PRIVATE KEY` / `CERTIFICATE`.\n * @returns The formatted PEM block.\n */\nexport function formatPemBlock(pem: string, isPublic = false): string {\n\tlet regex = /(PRIVATE KEY|CERTIFICATE)/;\n\tif (isPublic) {\n\t\tregex = /(PUBLIC KEY)/;\n\t}\n\tif (!pem || /\\n/.test(pem)) {\n\t\treturn pem;\n\t}\n\tconst compactPem = formatCompactPem(pem, isPublic);\n\tif (compactPem !== undefined) {\n\t\treturn compactPem;\n\t}\n\n\tlet formattedPem = '';\n\tconst parts = pem.split('-----').filter((item) => item !== '');\n\tparts.forEach((part) => {\n\t\tif (regex.test(part)) {\n\t\t\tformattedPem += `-----${part}-----`;\n\t\t} else {\n\t\t\tconst passRegex = /Proc-Type|DEK-Info/;\n\t\t\tif (passRegex.test(part)) {\n\t\t\t\tpart = part.replace(/:\\s+/g, ':');\n\t\t\t\tformattedPem += part.replace(/\\\\n/g, '\\n').replace(/\\s+/g, '\\n');\n\t\t\t} else {\n\t\t\t\tformattedPem += part.replace(/\\\\n/g, '\\n').replace(/\\s+/g, '\\n');\n\t\t\t}\n\t\t}\n\t});\n\treturn formattedPem;\n}\n"],"mappings":";AAAA,MAAM,uBAAuB;AAE7B,SAAS,iBAAiB,KAAa,UAAuC;CAC7E,MAAM,UAAU,IAAI,MAAM;AAC1B,MAAK,QAAQ,MAAM,eAAe,IAAI,EAAE,EAAE,WAAW,EAAG,QAAO;CAE/D,MAAM,eAAe,WAAW,yBAAyB;CACzD,MAAM,WAAW,QAAQ,sBACxB,IAAI,OAAO,gBAAgB,aAAa,sCAAsC,CAC9E;AAED,KAAI,CAAC,SAAU,QAAO;CAEtB,MAAM,GAAG,OAAO,QAAQ;CACxB,MAAM,iBAAiB,KAAK,QAAQ,QAAQ,KAAK,CAAC,MAAM;AAKxD,QAAO,cAAc,MAAM,SAJL,KAAK,KAAK,eAAe,GAC5C,eAAe,QAAQ,SAAS,IAAI,CAAC,QAAQ,QAAQ,KAAK,IACzD,eAAe,MAAM,IAAI,OAAO,OAAO,qBAAqB,IAAI,IAAI,CAAC,IAAI,EAAE,EAAE,KAAK,KAAK,CAEzC,aAAa,MAAM;;;;;;;;;;;AAYtE,SAAgB,eAAe,KAAa,WAAW,OAAe;CACrE,IAAI,QAAQ;AACZ,KAAI,SACH,SAAQ;AAET,KAAI,CAAC,OAAO,KAAK,KAAK,IAAI,CACzB,QAAO;CAER,MAAM,aAAa,iBAAiB,KAAK,SAAS;AAClD,KAAI,eAAe,OAClB,QAAO;CAGR,IAAI,eAAe;AAEnB,CADc,IAAI,MAAM,QAAQ,CAAC,QAAQ,SAAS,SAAS,GAAG,CACxD,SAAS,SAAS;AACvB,MAAI,MAAM,KAAK,KAAK,CACnB,iBAAgB,QAAQ,KAAK;WAEX,qBACJ,KAAK,KAAK,EAAE;AACzB,UAAO,KAAK,QAAQ,SAAS,IAAI;AACjC,mBAAgB,KAAK,QAAQ,QAAQ,KAAK,CAAC,QAAQ,QAAQ,KAAK;QAEhE,iBAAgB,KAAK,QAAQ,QAAQ,KAAK,CAAC,QAAQ,QAAQ,KAAK;GAGjE;AACF,QAAO"}