@n8n/n8n-nodes-langchain 1.122.46 → 1.122.48

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -21,6 +21,7 @@ __export(keywords_exports, {
21
21
  createKeywordsCheckFn: () => createKeywordsCheckFn
22
22
  });
23
23
  module.exports = __toCommonJS(keywords_exports);
24
+ var import_n8n_workflow = require("n8n-workflow");
24
25
  const keywordsCheck = (text, config) => {
25
26
  const { keywords } = config;
26
27
  const sanitizedKeywords = keywords.map((k) => k.replace(/[.,!?;:]+$/, ""));
@@ -38,11 +39,9 @@ const keywordsCheck = (text, config) => {
38
39
  (k) => k.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")
39
40
  );
40
41
  const patternText = `\\b(?:${escapedKeywords.join("|")})\\b`;
41
- const pattern = new RegExp(patternText, "gi");
42
42
  const matches = [];
43
- let match;
44
43
  const seen = /* @__PURE__ */ new Set();
45
- while ((match = pattern.exec(text)) !== null) {
44
+ for (const match of import_n8n_workflow.safeRegex.matchAll(patternText, text, "gi")) {
46
45
  const matchedText = match[0];
47
46
  if (!seen.has(matchedText.toLowerCase())) {
48
47
  matches.push(matchedText);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../nodes/Guardrails/actions/checks/keywords.ts"],"sourcesContent":["// Source: https://github.com/openai/openai-guardrails-js/blob/b9b99b4fb454f02a362c2836aec6285176ec40a8/src/checks/keywords.ts\nimport type { CreateCheckFn, GuardrailResult } from '../types';\n\ninterface KeywordsConfig {\n\tkeywords: string[];\n}\n\n/**\n * Keywords-based content filtering guardrail.\n *\n * Checks if any of the configured keywords appear in the input text.\n * Can be configured to trigger tripwires on matches or just report them.\n *\n * @param text Input text to check\n * @param config Configuration specifying keywords and behavior\n * @returns GuardrailResult indicating if tripwire was triggered\n */\nconst keywordsCheck = (text: string, config: KeywordsConfig): GuardrailResult => {\n\tconst { keywords } = config;\n\n\t// Sanitize keywords by stripping trailing punctuation\n\tconst sanitizedKeywords = keywords.map((k: string) => k.replace(/[.,!?;:]+$/, ''));\n\n\tconst validKeywords = sanitizedKeywords.filter((k: string) => k.length > 0);\n\n\tif (validKeywords.length === 0) {\n\t\treturn {\n\t\t\tguardrailName: 'keywords',\n\t\t\ttripwireTriggered: false,\n\t\t\tinfo: {\n\t\t\t\tmatchedKeywords: [],\n\t\t\t},\n\t\t};\n\t}\n\n\t// Create regex pattern with word boundaries\n\t// Escape special regex characters and join with word boundaries\n\tconst escapedKeywords = validKeywords.map((k: string) =>\n\t\tk.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&'),\n\t);\n\tconst patternText = `\\\\b(?:${escapedKeywords.join('|')})\\\\b`;\n\tconst pattern = new RegExp(patternText, 'gi'); // case-insensitive, global\n\n\tconst matches: string[] = [];\n\tlet match;\n\tconst seen = new Set<string>();\n\n\t// Find all matches and collect unique ones (case-insensitive)\n\twhile ((match = pattern.exec(text)) !== null) {\n\t\tconst matchedText = match[0];\n\t\tif (!seen.has(matchedText.toLowerCase())) {\n\t\t\tmatches.push(matchedText);\n\t\t\tseen.add(matchedText.toLowerCase());\n\t\t}\n\t}\n\n\tconst tripwireTriggered = matches.length > 0;\n\n\treturn {\n\t\tguardrailName: 'keywords',\n\t\ttripwireTriggered,\n\t\tinfo: {\n\t\t\tmatchedKeywords: matches,\n\t\t},\n\t};\n};\n\nexport const createKeywordsCheckFn: CreateCheckFn<KeywordsConfig> = (config) => (input: string) =>\n\tkeywordsCheck(input, config);\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAiBA,MAAM,gBAAgB,CAAC,MAAc,WAA4C;AAChF,QAAM,EAAE,SAAS,IAAI;AAGrB,QAAM,oBAAoB,SAAS,IAAI,CAAC,MAAc,EAAE,QAAQ,cAAc,EAAE,CAAC;AAEjF,QAAM,gBAAgB,kBAAkB,OAAO,CAAC,MAAc,EAAE,SAAS,CAAC;AAE1E,MAAI,cAAc,WAAW,GAAG;AAC/B,WAAO;AAAA,MACN,eAAe;AAAA,MACf,mBAAmB;AAAA,MACnB,MAAM;AAAA,QACL,iBAAiB,CAAC;AAAA,MACnB;AAAA,IACD;AAAA,EACD;AAIA,QAAM,kBAAkB,cAAc;AAAA,IAAI,CAAC,MAC1C,EAAE,QAAQ,uBAAuB,MAAM;AAAA,EACxC;AACA,QAAM,cAAc,SAAS,gBAAgB,KAAK,GAAG,CAAC;AACtD,QAAM,UAAU,IAAI,OAAO,aAAa,IAAI;AAE5C,QAAM,UAAoB,CAAC;AAC3B,MAAI;AACJ,QAAM,OAAO,oBAAI,IAAY;AAG7B,UAAQ,QAAQ,QAAQ,KAAK,IAAI,OAAO,MAAM;AAC7C,UAAM,cAAc,MAAM,CAAC;AAC3B,QAAI,CAAC,KAAK,IAAI,YAAY,YAAY,CAAC,GAAG;AACzC,cAAQ,KAAK,WAAW;AACxB,WAAK,IAAI,YAAY,YAAY,CAAC;AAAA,IACnC;AAAA,EACD;AAEA,QAAM,oBAAoB,QAAQ,SAAS;AAE3C,SAAO;AAAA,IACN,eAAe;AAAA,IACf;AAAA,IACA,MAAM;AAAA,MACL,iBAAiB;AAAA,IAClB;AAAA,EACD;AACD;AAEO,MAAM,wBAAuD,CAAC,WAAW,CAAC,UAChF,cAAc,OAAO,MAAM;","names":[]}
1
+ {"version":3,"sources":["../../../../../nodes/Guardrails/actions/checks/keywords.ts"],"sourcesContent":["// Source: https://github.com/openai/openai-guardrails-js/blob/b9b99b4fb454f02a362c2836aec6285176ec40a8/src/checks/keywords.ts\nimport { safeRegex } from 'n8n-workflow';\n\nimport type { CreateCheckFn, GuardrailResult } from '../types';\n\ninterface KeywordsConfig {\n\tkeywords: string[];\n}\n\n/**\n * Keywords-based content filtering guardrail.\n *\n * Checks if any of the configured keywords appear in the input text.\n * Can be configured to trigger tripwires on matches or just report them.\n *\n * @param text Input text to check\n * @param config Configuration specifying keywords and behavior\n * @returns GuardrailResult indicating if tripwire was triggered\n */\nconst keywordsCheck = (text: string, config: KeywordsConfig): GuardrailResult => {\n\tconst { keywords } = config;\n\n\t// Sanitize keywords by stripping trailing punctuation\n\tconst sanitizedKeywords = keywords.map((k: string) => k.replace(/[.,!?;:]+$/, ''));\n\n\tconst validKeywords = sanitizedKeywords.filter((k: string) => k.length > 0);\n\n\tif (validKeywords.length === 0) {\n\t\treturn {\n\t\t\tguardrailName: 'keywords',\n\t\t\ttripwireTriggered: false,\n\t\t\tinfo: {\n\t\t\t\tmatchedKeywords: [],\n\t\t\t},\n\t\t};\n\t}\n\n\t// Create regex pattern with word boundaries\n\t// Escape special regex characters and join with word boundaries\n\tconst escapedKeywords = validKeywords.map((k: string) =>\n\t\tk.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&'),\n\t);\n\tconst patternText = `\\\\b(?:${escapedKeywords.join('|')})\\\\b`;\n\n\tconst matches: string[] = [];\n\tconst seen = new Set<string>();\n\n\t// Find all matches and collect unique ones (case-insensitive)\n\tfor (const match of safeRegex.matchAll(patternText, text, 'gi')) {\n\t\tconst matchedText = match[0];\n\t\tif (!seen.has(matchedText.toLowerCase())) {\n\t\t\tmatches.push(matchedText);\n\t\t\tseen.add(matchedText.toLowerCase());\n\t\t}\n\t}\n\n\tconst tripwireTriggered = matches.length > 0;\n\n\treturn {\n\t\tguardrailName: 'keywords',\n\t\ttripwireTriggered,\n\t\tinfo: {\n\t\t\tmatchedKeywords: matches,\n\t\t},\n\t};\n};\n\nexport const createKeywordsCheckFn: CreateCheckFn<KeywordsConfig> = (config) => (input: string) =>\n\tkeywordsCheck(input, config);\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AACA,0BAA0B;AAkB1B,MAAM,gBAAgB,CAAC,MAAc,WAA4C;AAChF,QAAM,EAAE,SAAS,IAAI;AAGrB,QAAM,oBAAoB,SAAS,IAAI,CAAC,MAAc,EAAE,QAAQ,cAAc,EAAE,CAAC;AAEjF,QAAM,gBAAgB,kBAAkB,OAAO,CAAC,MAAc,EAAE,SAAS,CAAC;AAE1E,MAAI,cAAc,WAAW,GAAG;AAC/B,WAAO;AAAA,MACN,eAAe;AAAA,MACf,mBAAmB;AAAA,MACnB,MAAM;AAAA,QACL,iBAAiB,CAAC;AAAA,MACnB;AAAA,IACD;AAAA,EACD;AAIA,QAAM,kBAAkB,cAAc;AAAA,IAAI,CAAC,MAC1C,EAAE,QAAQ,uBAAuB,MAAM;AAAA,EACxC;AACA,QAAM,cAAc,SAAS,gBAAgB,KAAK,GAAG,CAAC;AAEtD,QAAM,UAAoB,CAAC;AAC3B,QAAM,OAAO,oBAAI,IAAY;AAG7B,aAAW,SAAS,8BAAU,SAAS,aAAa,MAAM,IAAI,GAAG;AAChE,UAAM,cAAc,MAAM,CAAC;AAC3B,QAAI,CAAC,KAAK,IAAI,YAAY,YAAY,CAAC,GAAG;AACzC,cAAQ,KAAK,WAAW;AACxB,WAAK,IAAI,YAAY,YAAY,CAAC;AAAA,IACnC;AAAA,EACD;AAEA,QAAM,oBAAoB,QAAQ,SAAS;AAE3C,SAAO;AAAA,IACN,eAAe;AAAA,IACf;AAAA,IACA,MAAM;AAAA,MACL,iBAAiB;AAAA,IAClB;AAAA,EACD;AACD;AAEO,MAAM,wBAAuD,CAAC,WAAW,CAAC,UAChF,cAAc,OAAO,MAAM;","names":[]}
@@ -24,6 +24,7 @@ __export(pii_exports, {
24
24
  createPiiCheckFn: () => createPiiCheckFn
25
25
  });
26
26
  module.exports = __toCommonJS(pii_exports);
27
+ var import_n8n_workflow = require("n8n-workflow");
27
28
  var import_common = require("../../helpers/common");
28
29
  var PIIEntity = /* @__PURE__ */ ((PIIEntity2) => {
29
30
  PIIEntity2["CREDIT_CARD"] = "CREDIT_CARD";
@@ -159,11 +160,11 @@ function detectPii(text, config) {
159
160
  }
160
161
  const grouped = {};
161
162
  const analyzerResults = [];
162
- const matchAgainstPattern = (name, pattern) => {
163
- const flags = pattern.flags.includes("g") ? pattern.flags : pattern.flags + "g";
164
- const regex = new RegExp(pattern.source, flags);
165
- let match;
166
- while ((match = regex.exec(text)) !== null) {
163
+ const matchAgainstPattern = (name, literal) => {
164
+ const flags = literal.flags.includes("g") ? literal.flags : literal.flags + "g";
165
+ const matches = import_n8n_workflow.safeRegex.matchAll(literal.source, text, flags);
166
+ for (const match of matches) {
167
+ if (match.index === void 0) continue;
167
168
  const entityType = name;
168
169
  const start = match.index;
169
170
  const end = match.index + match[0].length;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../nodes/Guardrails/actions/checks/pii.ts"],"sourcesContent":["// Source: https://github.com/openai/openai-guardrails-js/blob/b9b99b4fb454f02a362c2836aec6285176ec40a8/src/checks/pii.ts\n/**\n * PII detection guardrail for sensitive text content.\n *\n * This module implements a guardrail for detecting Personally Identifiable\n * Information (PII) in text using regex patterns. It defines the config\n * schema for entity selection, output/result structures, and the async guardrail\n * check_fn for runtime enforcement.\n */\n\nimport { parseRegex } from '../../helpers/common';\nimport type { CreateCheckFn, CustomRegex } from '../types';\n\n/**\n * Supported PII entity types for detection.\n *\n * Includes global and region-specific types (US, UK, Spain, Italy, etc.).\n * These map to regex patterns for detection.\n */\n// eslint-disable-next-line no-restricted-syntax\nexport enum PIIEntity {\n\t// Global\n\tCREDIT_CARD = 'CREDIT_CARD',\n\tCRYPTO = 'CRYPTO',\n\tDATE_TIME = 'DATE_TIME',\n\tEMAIL_ADDRESS = 'EMAIL_ADDRESS',\n\tIBAN_CODE = 'IBAN_CODE',\n\tIP_ADDRESS = 'IP_ADDRESS',\n\tLOCATION = 'LOCATION',\n\tPHONE_NUMBER = 'PHONE_NUMBER',\n\tMEDICAL_LICENSE = 'MEDICAL_LICENSE',\n\n\t// USA\n\tUS_BANK_NUMBER = 'US_BANK_NUMBER',\n\tUS_DRIVER_LICENSE = 'US_DRIVER_LICENSE',\n\tUS_ITIN = 'US_ITIN',\n\tUS_PASSPORT = 'US_PASSPORT',\n\tUS_SSN = 'US_SSN',\n\n\t// UK\n\tUK_NHS = 'UK_NHS',\n\tUK_NINO = 'UK_NINO',\n\n\t// Spain\n\tES_NIF = 'ES_NIF',\n\tES_NIE = 'ES_NIE',\n\n\t// Italy\n\tIT_FISCAL_CODE = 'IT_FISCAL_CODE',\n\tIT_DRIVER_LICENSE = 'IT_DRIVER_LICENSE',\n\tIT_VAT_CODE = 'IT_VAT_CODE',\n\tIT_PASSPORT = 'IT_PASSPORT',\n\tIT_IDENTITY_CARD = 'IT_IDENTITY_CARD',\n\n\t// Poland\n\tPL_PESEL = 'PL_PESEL',\n\n\t// Singapore\n\tSG_NRIC_FIN = 'SG_NRIC_FIN',\n\tSG_UEN = 'SG_UEN',\n\n\t// Australia\n\tAU_ABN = 'AU_ABN',\n\tAU_ACN = 'AU_ACN',\n\tAU_TFN = 'AU_TFN',\n\tAU_MEDICARE = 'AU_MEDICARE',\n\n\t// India\n\tIN_PAN = 'IN_PAN',\n\tIN_AADHAAR = 'IN_AADHAAR',\n\tIN_VEHICLE_REGISTRATION = 'IN_VEHICLE_REGISTRATION',\n\tIN_VOTER = 'IN_VOTER',\n\tIN_PASSPORT = 'IN_PASSPORT',\n\n\t// Finland\n\tFI_PERSONAL_IDENTITY_CODE = 'FI_PERSONAL_IDENTITY_CODE',\n}\n\nconst allEntities = Object.values(PIIEntity);\n\nexport type PIIConfig = {\n\tentities?: PIIEntity[];\n\tcustomRegex?: CustomRegex[];\n};\n\nexport type CustomRegexConfig = {\n\tcustomRegex: CustomRegex[];\n};\n\n/**\n * Internal result structure for PII detection.\n */\ninterface PiiDetectionResult {\n\tmapping: Record<string, string[]>;\n\tanalyzerResults: PiiAnalyzerResult[];\n}\n\n/**\n * PII analyzer result structure.\n */\ninterface PiiAnalyzerResult {\n\tentityType: string;\n\ttext: string;\n}\n\nexport const PII_NAME_MAP: Record<PIIEntity, string> = {\n\t[PIIEntity.CREDIT_CARD]: 'Credit Card',\n\t[PIIEntity.CRYPTO]: 'Crypto',\n\t[PIIEntity.DATE_TIME]: 'Date Time',\n\t[PIIEntity.EMAIL_ADDRESS]: 'Email Address',\n\t[PIIEntity.IBAN_CODE]: 'IBAN Code',\n\t[PIIEntity.IP_ADDRESS]: 'IP Address',\n\t[PIIEntity.LOCATION]: 'Location',\n\t[PIIEntity.PHONE_NUMBER]: 'Phone Number',\n\t[PIIEntity.MEDICAL_LICENSE]: 'Medical License',\n\t[PIIEntity.US_BANK_NUMBER]: 'US Bank Number',\n\t[PIIEntity.US_DRIVER_LICENSE]: 'US Driver License',\n\t[PIIEntity.US_ITIN]: 'US ITIN',\n\t[PIIEntity.US_PASSPORT]: 'US Passport',\n\t[PIIEntity.US_SSN]: 'US SSN',\n\t[PIIEntity.UK_NHS]: 'UK NHS',\n\t[PIIEntity.UK_NINO]: 'UK NINO',\n\t[PIIEntity.ES_NIF]: 'ES NIF',\n\t[PIIEntity.ES_NIE]: 'ES NIE',\n\t[PIIEntity.IT_FISCAL_CODE]: 'IT Fiscal Code',\n\t[PIIEntity.IT_DRIVER_LICENSE]: 'IT Driver License',\n\t[PIIEntity.IT_VAT_CODE]: 'IT VAT Code',\n\t[PIIEntity.IT_PASSPORT]: 'IT Passport',\n\t[PIIEntity.IT_IDENTITY_CARD]: 'IT Identity Card',\n\t[PIIEntity.PL_PESEL]: 'PL PESEL',\n\t[PIIEntity.SG_NRIC_FIN]: 'SG NRIC FIN',\n\t[PIIEntity.SG_UEN]: 'SG UEN',\n\t[PIIEntity.AU_ABN]: 'AU ABN',\n\t[PIIEntity.AU_ACN]: 'AU ACN',\n\t[PIIEntity.AU_TFN]: 'AU TFN',\n\t[PIIEntity.AU_MEDICARE]: 'AU Medicare',\n\t[PIIEntity.IN_PAN]: 'IN PAN',\n\t[PIIEntity.IN_AADHAAR]: 'IN AADHAAR',\n\t[PIIEntity.IN_VEHICLE_REGISTRATION]: 'IN Vehicle Registration',\n\t[PIIEntity.IN_VOTER]: 'IN Voter',\n\t[PIIEntity.IN_PASSPORT]: 'IN Passport',\n\t[PIIEntity.FI_PERSONAL_IDENTITY_CODE]: 'FI Personal Identity Code',\n};\n\n/**\n * Default regex patterns for PII entity types.\n */\nconst DEFAULT_PII_PATTERNS: Record<PIIEntity, RegExp> = {\n\t[PIIEntity.CREDIT_CARD]: /\\b\\d{4}[-\\s]?\\d{4}[-\\s]?\\d{4}[-\\s]?\\d{4}\\b/g,\n\t[PIIEntity.CRYPTO]: /\\b[13][a-km-zA-HJ-NP-Z1-9]{25,34}\\b/g,\n\t[PIIEntity.DATE_TIME]: /\\b(0[1-9]|1[0-2])[\\/\\-](0[1-9]|[12]\\d|3[01])[\\/\\-](19|20)\\d{2}\\b/g,\n\t[PIIEntity.EMAIL_ADDRESS]: /\\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Z|a-z]{2,}\\b/g,\n\t[PIIEntity.IBAN_CODE]: /\\b[A-Z]{2}[0-9]{2}[A-Z0-9]{4}[0-9]{7}([A-Z0-9]?){0,16}\\b/g,\n\t[PIIEntity.IP_ADDRESS]: /\\b(?:[0-9]{1,3}\\.){3}[0-9]{1,3}\\b/g,\n\t[PIIEntity.LOCATION]:\n\t\t/\\b[A-Za-z\\s]+(?:Street|St|Avenue|Ave|Road|Rd|Boulevard|Blvd|Drive|Dr|Lane|Ln|Place|Pl|Court|Ct|Way|Highway|Hwy)\\b/g,\n\t[PIIEntity.PHONE_NUMBER]: /\\b[\\+]?[(]?[0-9]{3}[)]?[-\\s\\.]?[0-9]{3}[-\\s\\.]?[0-9]{4,6}\\b/g,\n\t[PIIEntity.MEDICAL_LICENSE]: /\\b[A-Z]{2}\\d{6}\\b/g,\n\n\t// USA\n\t[PIIEntity.US_BANK_NUMBER]: /\\b\\d{8,17}\\b/g,\n\t[PIIEntity.US_DRIVER_LICENSE]: /\\b[A-Z]\\d{7}\\b/g,\n\t[PIIEntity.US_ITIN]: /\\b9\\d{2}-\\d{2}-\\d{4}\\b/g,\n\t[PIIEntity.US_PASSPORT]: /\\b[A-Z]\\d{8}\\b/g,\n\t[PIIEntity.US_SSN]: /\\b\\d{3}-\\d{2}-\\d{4}\\b|\\b\\d{9}\\b/g,\n\n\t// UK\n\t[PIIEntity.UK_NHS]: /\\b\\d{3} \\d{3} \\d{4}\\b/g,\n\t[PIIEntity.UK_NINO]: /\\b[A-Z]{2}\\d{6}[A-Z]\\b/g,\n\n\t// Spain\n\t[PIIEntity.ES_NIF]: /\\b[A-Z]\\d{8}\\b/g,\n\t[PIIEntity.ES_NIE]: /\\b[A-Z]\\d{8}\\b/g,\n\n\t// Italy\n\t[PIIEntity.IT_FISCAL_CODE]: /\\b[A-Z]{6}\\d{2}[A-Z]\\d{2}[A-Z]\\d{3}[A-Z]\\b/g,\n\t[PIIEntity.IT_DRIVER_LICENSE]: /\\b[A-Z]{2}\\d{7}\\b/g,\n\t[PIIEntity.IT_VAT_CODE]: /\\bIT\\d{11}\\b/g,\n\t[PIIEntity.IT_PASSPORT]: /\\b[A-Z]{2}\\d{7}\\b/g,\n\t[PIIEntity.IT_IDENTITY_CARD]: /\\b[A-Z]{2}\\d{7}\\b/g,\n\n\t// Poland\n\t[PIIEntity.PL_PESEL]: /\\b\\d{11}\\b/g,\n\n\t// Singapore\n\t[PIIEntity.SG_NRIC_FIN]: /\\b[A-Z]\\d{7}[A-Z]\\b/g,\n\t[PIIEntity.SG_UEN]: /\\b\\d{8}[A-Z]\\b|\\b\\d{9}[A-Z]\\b/g,\n\n\t// Australia\n\t[PIIEntity.AU_ABN]: /\\b\\d{2} \\d{3} \\d{3} \\d{3}\\b/g,\n\t[PIIEntity.AU_ACN]: /\\b\\d{3} \\d{3} \\d{3}\\b/g,\n\t[PIIEntity.AU_TFN]: /\\b\\d{9}\\b/g,\n\t[PIIEntity.AU_MEDICARE]: /\\b\\d{4} \\d{5} \\d{1}\\b/g,\n\n\t// India\n\t[PIIEntity.IN_PAN]: /\\b[A-Z]{5}\\d{4}[A-Z]\\b/g,\n\t[PIIEntity.IN_AADHAAR]: /\\b\\d{4} \\d{4} \\d{4}\\b/g,\n\t[PIIEntity.IN_VEHICLE_REGISTRATION]: /\\b[A-Z]{2}\\d{2}[A-Z]{2}\\d{4}\\b/g,\n\t[PIIEntity.IN_VOTER]: /\\b[A-Z]{3}\\d{7}\\b/g,\n\t[PIIEntity.IN_PASSPORT]: /\\b[A-Z]\\d{7}\\b/g,\n\n\t// Finland\n\t[PIIEntity.FI_PERSONAL_IDENTITY_CODE]: /\\b\\d{6}[+-A]\\d{3}[A-Z0-9]\\b/g,\n};\n\n/**\n * Run regex analysis and collect findings by entity type.\n *\n * @param text The text to analyze for PII\n * @param config PII detection configuration\n * @returns Object containing mapping of entities to detected snippets\n * @throws Error if text is empty or null\n */\nfunction detectPii(text: string, config: PIIConfig): PiiDetectionResult {\n\tif (!text) {\n\t\treturn {\n\t\t\tmapping: {},\n\t\t\tanalyzerResults: [],\n\t\t};\n\t}\n\n\tconst grouped: Record<string, string[]> = {};\n\tconst analyzerResults: PiiAnalyzerResult[] = [];\n\n\tconst matchAgainstPattern = (name: string, pattern: RegExp) => {\n\t\t// make sure to add the global flag to the regex, otherwise while() will never end\n\t\tconst flags = pattern.flags.includes('g') ? pattern.flags : pattern.flags + 'g';\n\t\tconst regex = new RegExp(pattern.source, flags);\n\t\tlet match;\n\t\twhile ((match = regex.exec(text)) !== null) {\n\t\t\tconst entityType = name;\n\t\t\tconst start = match.index;\n\t\t\tconst end = match.index + match[0].length;\n\n\t\t\tif (!grouped[entityType]) {\n\t\t\t\tgrouped[entityType] = [];\n\t\t\t}\n\t\t\tgrouped[entityType].push(text.substring(start, end));\n\n\t\t\tanalyzerResults.push({\n\t\t\t\tentityType,\n\t\t\t\ttext: text.substring(start, end),\n\t\t\t});\n\t\t}\n\t};\n\n\t// Check each configured entity type\n\tconst entities = config.entities ?? allEntities;\n\tfor (const entity of entities) {\n\t\tconst pattern = DEFAULT_PII_PATTERNS[entity];\n\t\tif (pattern) {\n\t\t\tmatchAgainstPattern(entity, pattern);\n\t\t}\n\t}\n\tif (config.customRegex?.length) {\n\t\tfor (const regex of config.customRegex) {\n\t\t\tmatchAgainstPattern(regex.name, parseRegex(regex.value));\n\t\t}\n\t}\n\n\treturn {\n\t\tmapping: grouped,\n\t\tanalyzerResults,\n\t};\n}\n\nexport const createPiiCheckFn: CreateCheckFn<PIIConfig> = (config) => {\n\treturn (input: string) => {\n\t\tconst detection = detectPii(input, config);\n\t\tconst piiFound = detection.mapping && Object.keys(detection.mapping).length > 0;\n\t\treturn {\n\t\t\tguardrailName: 'personalData',\n\t\t\ttripwireTriggered: piiFound,\n\t\t\tinfo: {\n\t\t\t\tmaskEntities: detection.mapping,\n\t\t\t\tanalyzerResults: detection.analyzerResults,\n\t\t\t},\n\t\t};\n\t};\n};\n\nexport const createCustomRegexCheckFn: CreateCheckFn<CustomRegexConfig> = (config) => {\n\treturn (input: string) => {\n\t\tconst detection = detectPii(input, { customRegex: config.customRegex, entities: [] });\n\t\tconst customRegexFound = detection.mapping && Object.keys(detection.mapping).length > 0;\n\t\treturn {\n\t\t\tguardrailName: 'customRegex',\n\t\t\ttripwireTriggered: customRegexFound,\n\t\t\tinfo: {\n\t\t\t\tmaskEntities: detection.mapping,\n\t\t\t\tanalyzerResults: detection.analyzerResults,\n\t\t\t},\n\t\t};\n\t};\n};\n"],"mappings":"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","names":["PIIEntity"]}
1
+ {"version":3,"sources":["../../../../../nodes/Guardrails/actions/checks/pii.ts"],"sourcesContent":["// Source: https://github.com/openai/openai-guardrails-js/blob/b9b99b4fb454f02a362c2836aec6285176ec40a8/src/checks/pii.ts\n/**\n * PII detection guardrail for sensitive text content.\n *\n * This module implements a guardrail for detecting Personally Identifiable\n * Information (PII) in text using regex patterns. It defines the config\n * schema for entity selection, output/result structures, and the async guardrail\n * check_fn for runtime enforcement.\n */\nimport { safeRegex } from 'n8n-workflow';\n\nimport { parseRegex } from '../../helpers/common';\nimport type { CreateCheckFn, CustomRegex } from '../types';\n\n/**\n * Supported PII entity types for detection.\n *\n * Includes global and region-specific types (US, UK, Spain, Italy, etc.).\n * These map to regex patterns for detection.\n */\n// eslint-disable-next-line no-restricted-syntax\nexport enum PIIEntity {\n\t// Global\n\tCREDIT_CARD = 'CREDIT_CARD',\n\tCRYPTO = 'CRYPTO',\n\tDATE_TIME = 'DATE_TIME',\n\tEMAIL_ADDRESS = 'EMAIL_ADDRESS',\n\tIBAN_CODE = 'IBAN_CODE',\n\tIP_ADDRESS = 'IP_ADDRESS',\n\tLOCATION = 'LOCATION',\n\tPHONE_NUMBER = 'PHONE_NUMBER',\n\tMEDICAL_LICENSE = 'MEDICAL_LICENSE',\n\n\t// USA\n\tUS_BANK_NUMBER = 'US_BANK_NUMBER',\n\tUS_DRIVER_LICENSE = 'US_DRIVER_LICENSE',\n\tUS_ITIN = 'US_ITIN',\n\tUS_PASSPORT = 'US_PASSPORT',\n\tUS_SSN = 'US_SSN',\n\n\t// UK\n\tUK_NHS = 'UK_NHS',\n\tUK_NINO = 'UK_NINO',\n\n\t// Spain\n\tES_NIF = 'ES_NIF',\n\tES_NIE = 'ES_NIE',\n\n\t// Italy\n\tIT_FISCAL_CODE = 'IT_FISCAL_CODE',\n\tIT_DRIVER_LICENSE = 'IT_DRIVER_LICENSE',\n\tIT_VAT_CODE = 'IT_VAT_CODE',\n\tIT_PASSPORT = 'IT_PASSPORT',\n\tIT_IDENTITY_CARD = 'IT_IDENTITY_CARD',\n\n\t// Poland\n\tPL_PESEL = 'PL_PESEL',\n\n\t// Singapore\n\tSG_NRIC_FIN = 'SG_NRIC_FIN',\n\tSG_UEN = 'SG_UEN',\n\n\t// Australia\n\tAU_ABN = 'AU_ABN',\n\tAU_ACN = 'AU_ACN',\n\tAU_TFN = 'AU_TFN',\n\tAU_MEDICARE = 'AU_MEDICARE',\n\n\t// India\n\tIN_PAN = 'IN_PAN',\n\tIN_AADHAAR = 'IN_AADHAAR',\n\tIN_VEHICLE_REGISTRATION = 'IN_VEHICLE_REGISTRATION',\n\tIN_VOTER = 'IN_VOTER',\n\tIN_PASSPORT = 'IN_PASSPORT',\n\n\t// Finland\n\tFI_PERSONAL_IDENTITY_CODE = 'FI_PERSONAL_IDENTITY_CODE',\n}\n\nconst allEntities = Object.values(PIIEntity);\n\nexport type PIIConfig = {\n\tentities?: PIIEntity[];\n\tcustomRegex?: CustomRegex[];\n};\n\nexport type CustomRegexConfig = {\n\tcustomRegex: CustomRegex[];\n};\n\n/**\n * Internal result structure for PII detection.\n */\ninterface PiiDetectionResult {\n\tmapping: Record<string, string[]>;\n\tanalyzerResults: PiiAnalyzerResult[];\n}\n\n/**\n * PII analyzer result structure.\n */\ninterface PiiAnalyzerResult {\n\tentityType: string;\n\ttext: string;\n}\n\nexport const PII_NAME_MAP: Record<PIIEntity, string> = {\n\t[PIIEntity.CREDIT_CARD]: 'Credit Card',\n\t[PIIEntity.CRYPTO]: 'Crypto',\n\t[PIIEntity.DATE_TIME]: 'Date Time',\n\t[PIIEntity.EMAIL_ADDRESS]: 'Email Address',\n\t[PIIEntity.IBAN_CODE]: 'IBAN Code',\n\t[PIIEntity.IP_ADDRESS]: 'IP Address',\n\t[PIIEntity.LOCATION]: 'Location',\n\t[PIIEntity.PHONE_NUMBER]: 'Phone Number',\n\t[PIIEntity.MEDICAL_LICENSE]: 'Medical License',\n\t[PIIEntity.US_BANK_NUMBER]: 'US Bank Number',\n\t[PIIEntity.US_DRIVER_LICENSE]: 'US Driver License',\n\t[PIIEntity.US_ITIN]: 'US ITIN',\n\t[PIIEntity.US_PASSPORT]: 'US Passport',\n\t[PIIEntity.US_SSN]: 'US SSN',\n\t[PIIEntity.UK_NHS]: 'UK NHS',\n\t[PIIEntity.UK_NINO]: 'UK NINO',\n\t[PIIEntity.ES_NIF]: 'ES NIF',\n\t[PIIEntity.ES_NIE]: 'ES NIE',\n\t[PIIEntity.IT_FISCAL_CODE]: 'IT Fiscal Code',\n\t[PIIEntity.IT_DRIVER_LICENSE]: 'IT Driver License',\n\t[PIIEntity.IT_VAT_CODE]: 'IT VAT Code',\n\t[PIIEntity.IT_PASSPORT]: 'IT Passport',\n\t[PIIEntity.IT_IDENTITY_CARD]: 'IT Identity Card',\n\t[PIIEntity.PL_PESEL]: 'PL PESEL',\n\t[PIIEntity.SG_NRIC_FIN]: 'SG NRIC FIN',\n\t[PIIEntity.SG_UEN]: 'SG UEN',\n\t[PIIEntity.AU_ABN]: 'AU ABN',\n\t[PIIEntity.AU_ACN]: 'AU ACN',\n\t[PIIEntity.AU_TFN]: 'AU TFN',\n\t[PIIEntity.AU_MEDICARE]: 'AU Medicare',\n\t[PIIEntity.IN_PAN]: 'IN PAN',\n\t[PIIEntity.IN_AADHAAR]: 'IN AADHAAR',\n\t[PIIEntity.IN_VEHICLE_REGISTRATION]: 'IN Vehicle Registration',\n\t[PIIEntity.IN_VOTER]: 'IN Voter',\n\t[PIIEntity.IN_PASSPORT]: 'IN Passport',\n\t[PIIEntity.FI_PERSONAL_IDENTITY_CODE]: 'FI Personal Identity Code',\n};\n\n/**\n * Default regex patterns for PII entity types.\n */\nconst DEFAULT_PII_PATTERNS: Record<PIIEntity, RegExp> = {\n\t[PIIEntity.CREDIT_CARD]: /\\b\\d{4}[-\\s]?\\d{4}[-\\s]?\\d{4}[-\\s]?\\d{4}\\b/g,\n\t[PIIEntity.CRYPTO]: /\\b[13][a-km-zA-HJ-NP-Z1-9]{25,34}\\b/g,\n\t[PIIEntity.DATE_TIME]: /\\b(0[1-9]|1[0-2])[\\/\\-](0[1-9]|[12]\\d|3[01])[\\/\\-](19|20)\\d{2}\\b/g,\n\t[PIIEntity.EMAIL_ADDRESS]: /\\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Z|a-z]{2,}\\b/g,\n\t[PIIEntity.IBAN_CODE]: /\\b[A-Z]{2}[0-9]{2}[A-Z0-9]{4}[0-9]{7}([A-Z0-9]?){0,16}\\b/g,\n\t[PIIEntity.IP_ADDRESS]: /\\b(?:[0-9]{1,3}\\.){3}[0-9]{1,3}\\b/g,\n\t[PIIEntity.LOCATION]:\n\t\t/\\b[A-Za-z\\s]+(?:Street|St|Avenue|Ave|Road|Rd|Boulevard|Blvd|Drive|Dr|Lane|Ln|Place|Pl|Court|Ct|Way|Highway|Hwy)\\b/g,\n\t[PIIEntity.PHONE_NUMBER]: /\\b[\\+]?[(]?[0-9]{3}[)]?[-\\s\\.]?[0-9]{3}[-\\s\\.]?[0-9]{4,6}\\b/g,\n\t[PIIEntity.MEDICAL_LICENSE]: /\\b[A-Z]{2}\\d{6}\\b/g,\n\n\t// USA\n\t[PIIEntity.US_BANK_NUMBER]: /\\b\\d{8,17}\\b/g,\n\t[PIIEntity.US_DRIVER_LICENSE]: /\\b[A-Z]\\d{7}\\b/g,\n\t[PIIEntity.US_ITIN]: /\\b9\\d{2}-\\d{2}-\\d{4}\\b/g,\n\t[PIIEntity.US_PASSPORT]: /\\b[A-Z]\\d{8}\\b/g,\n\t[PIIEntity.US_SSN]: /\\b\\d{3}-\\d{2}-\\d{4}\\b|\\b\\d{9}\\b/g,\n\n\t// UK\n\t[PIIEntity.UK_NHS]: /\\b\\d{3} \\d{3} \\d{4}\\b/g,\n\t[PIIEntity.UK_NINO]: /\\b[A-Z]{2}\\d{6}[A-Z]\\b/g,\n\n\t// Spain\n\t[PIIEntity.ES_NIF]: /\\b[A-Z]\\d{8}\\b/g,\n\t[PIIEntity.ES_NIE]: /\\b[A-Z]\\d{8}\\b/g,\n\n\t// Italy\n\t[PIIEntity.IT_FISCAL_CODE]: /\\b[A-Z]{6}\\d{2}[A-Z]\\d{2}[A-Z]\\d{3}[A-Z]\\b/g,\n\t[PIIEntity.IT_DRIVER_LICENSE]: /\\b[A-Z]{2}\\d{7}\\b/g,\n\t[PIIEntity.IT_VAT_CODE]: /\\bIT\\d{11}\\b/g,\n\t[PIIEntity.IT_PASSPORT]: /\\b[A-Z]{2}\\d{7}\\b/g,\n\t[PIIEntity.IT_IDENTITY_CARD]: /\\b[A-Z]{2}\\d{7}\\b/g,\n\n\t// Poland\n\t[PIIEntity.PL_PESEL]: /\\b\\d{11}\\b/g,\n\n\t// Singapore\n\t[PIIEntity.SG_NRIC_FIN]: /\\b[A-Z]\\d{7}[A-Z]\\b/g,\n\t[PIIEntity.SG_UEN]: /\\b\\d{8}[A-Z]\\b|\\b\\d{9}[A-Z]\\b/g,\n\n\t// Australia\n\t[PIIEntity.AU_ABN]: /\\b\\d{2} \\d{3} \\d{3} \\d{3}\\b/g,\n\t[PIIEntity.AU_ACN]: /\\b\\d{3} \\d{3} \\d{3}\\b/g,\n\t[PIIEntity.AU_TFN]: /\\b\\d{9}\\b/g,\n\t[PIIEntity.AU_MEDICARE]: /\\b\\d{4} \\d{5} \\d{1}\\b/g,\n\n\t// India\n\t[PIIEntity.IN_PAN]: /\\b[A-Z]{5}\\d{4}[A-Z]\\b/g,\n\t[PIIEntity.IN_AADHAAR]: /\\b\\d{4} \\d{4} \\d{4}\\b/g,\n\t[PIIEntity.IN_VEHICLE_REGISTRATION]: /\\b[A-Z]{2}\\d{2}[A-Z]{2}\\d{4}\\b/g,\n\t[PIIEntity.IN_VOTER]: /\\b[A-Z]{3}\\d{7}\\b/g,\n\t[PIIEntity.IN_PASSPORT]: /\\b[A-Z]\\d{7}\\b/g,\n\n\t// Finland\n\t[PIIEntity.FI_PERSONAL_IDENTITY_CODE]: /\\b\\d{6}[+-A]\\d{3}[A-Z0-9]\\b/g,\n};\n\n/**\n * Run regex analysis and collect findings by entity type.\n *\n * @param text The text to analyze for PII\n * @param config PII detection configuration\n * @returns Object containing mapping of entities to detected snippets\n * @throws Error if text is empty or null\n */\nfunction detectPii(text: string, config: PIIConfig): PiiDetectionResult {\n\tif (!text) {\n\t\treturn {\n\t\t\tmapping: {},\n\t\t\tanalyzerResults: [],\n\t\t};\n\t}\n\n\tconst grouped: Record<string, string[]> = {};\n\tconst analyzerResults: PiiAnalyzerResult[] = [];\n\n\tconst matchAgainstPattern = (name: string, literal: { source: string; flags: string }) => {\n\t\t// make sure to add the global flag to the regex, otherwise while() will never end\n\t\tconst flags = literal.flags.includes('g') ? literal.flags : literal.flags + 'g';\n\t\tconst matches = safeRegex.matchAll(literal.source, text, flags);\n\t\tfor (const match of matches) {\n\t\t\tif (match.index === undefined) continue;\n\n\t\t\tconst entityType = name;\n\t\t\tconst start = match.index;\n\t\t\tconst end = match.index + match[0].length;\n\n\t\t\tif (!grouped[entityType]) {\n\t\t\t\tgrouped[entityType] = [];\n\t\t\t}\n\t\t\tgrouped[entityType].push(text.substring(start, end));\n\n\t\t\tanalyzerResults.push({\n\t\t\t\tentityType,\n\t\t\t\ttext: text.substring(start, end),\n\t\t\t});\n\t\t}\n\t};\n\n\t// Check each configured entity type\n\tconst entities = config.entities ?? allEntities;\n\tfor (const entity of entities) {\n\t\tconst pattern = DEFAULT_PII_PATTERNS[entity];\n\t\tif (pattern) {\n\t\t\tmatchAgainstPattern(entity, pattern);\n\t\t}\n\t}\n\tif (config.customRegex?.length) {\n\t\tfor (const regex of config.customRegex) {\n\t\t\tmatchAgainstPattern(regex.name, parseRegex(regex.value));\n\t\t}\n\t}\n\n\treturn {\n\t\tmapping: grouped,\n\t\tanalyzerResults,\n\t};\n}\n\nexport const createPiiCheckFn: CreateCheckFn<PIIConfig> = (config) => {\n\treturn (input: string) => {\n\t\tconst detection = detectPii(input, config);\n\t\tconst piiFound = detection.mapping && Object.keys(detection.mapping).length > 0;\n\t\treturn {\n\t\t\tguardrailName: 'personalData',\n\t\t\ttripwireTriggered: piiFound,\n\t\t\tinfo: {\n\t\t\t\tmaskEntities: detection.mapping,\n\t\t\t\tanalyzerResults: detection.analyzerResults,\n\t\t\t},\n\t\t};\n\t};\n};\n\nexport const createCustomRegexCheckFn: CreateCheckFn<CustomRegexConfig> = (config) => {\n\treturn (input: string) => {\n\t\tconst detection = detectPii(input, { customRegex: config.customRegex, entities: [] });\n\t\tconst customRegexFound = detection.mapping && Object.keys(detection.mapping).length > 0;\n\t\treturn {\n\t\t\tguardrailName: 'customRegex',\n\t\t\ttripwireTriggered: customRegexFound,\n\t\t\tinfo: {\n\t\t\t\tmaskEntities: detection.mapping,\n\t\t\t\tanalyzerResults: detection.analyzerResults,\n\t\t\t},\n\t\t};\n\t};\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AASA,0BAA0B;AAE1B,oBAA2B;AAUpB,IAAK,YAAL,kBAAKA,eAAL;AAEN,EAAAA,WAAA,iBAAc;AACd,EAAAA,WAAA,YAAS;AACT,EAAAA,WAAA,eAAY;AACZ,EAAAA,WAAA,mBAAgB;AAChB,EAAAA,WAAA,eAAY;AACZ,EAAAA,WAAA,gBAAa;AACb,EAAAA,WAAA,cAAW;AACX,EAAAA,WAAA,kBAAe;AACf,EAAAA,WAAA,qBAAkB;AAGlB,EAAAA,WAAA,oBAAiB;AACjB,EAAAA,WAAA,uBAAoB;AACpB,EAAAA,WAAA,aAAU;AACV,EAAAA,WAAA,iBAAc;AACd,EAAAA,WAAA,YAAS;AAGT,EAAAA,WAAA,YAAS;AACT,EAAAA,WAAA,aAAU;AAGV,EAAAA,WAAA,YAAS;AACT,EAAAA,WAAA,YAAS;AAGT,EAAAA,WAAA,oBAAiB;AACjB,EAAAA,WAAA,uBAAoB;AACpB,EAAAA,WAAA,iBAAc;AACd,EAAAA,WAAA,iBAAc;AACd,EAAAA,WAAA,sBAAmB;AAGnB,EAAAA,WAAA,cAAW;AAGX,EAAAA,WAAA,iBAAc;AACd,EAAAA,WAAA,YAAS;AAGT,EAAAA,WAAA,YAAS;AACT,EAAAA,WAAA,YAAS;AACT,EAAAA,WAAA,YAAS;AACT,EAAAA,WAAA,iBAAc;AAGd,EAAAA,WAAA,YAAS;AACT,EAAAA,WAAA,gBAAa;AACb,EAAAA,WAAA,6BAA0B;AAC1B,EAAAA,WAAA,cAAW;AACX,EAAAA,WAAA,iBAAc;AAGd,EAAAA,WAAA,+BAA4B;AAvDjB,SAAAA;AAAA,GAAA;AA0DZ,MAAM,cAAc,OAAO,OAAO,SAAS;AA2BpC,MAAM,eAA0C;AAAA,EACtD,CAAC,+BAAqB,GAAG;AAAA,EACzB,CAAC,qBAAgB,GAAG;AAAA,EACpB,CAAC,2BAAmB,GAAG;AAAA,EACvB,CAAC,mCAAuB,GAAG;AAAA,EAC3B,CAAC,2BAAmB,GAAG;AAAA,EACvB,CAAC,6BAAoB,GAAG;AAAA,EACxB,CAAC,yBAAkB,GAAG;AAAA,EACtB,CAAC,iCAAsB,GAAG;AAAA,EAC1B,CAAC,uCAAyB,GAAG;AAAA,EAC7B,CAAC,qCAAwB,GAAG;AAAA,EAC5B,CAAC,2CAA2B,GAAG;AAAA,EAC/B,CAAC,uBAAiB,GAAG;AAAA,EACrB,CAAC,+BAAqB,GAAG;AAAA,EACzB,CAAC,qBAAgB,GAAG;AAAA,EACpB,CAAC,qBAAgB,GAAG;AAAA,EACpB,CAAC,uBAAiB,GAAG;AAAA,EACrB,CAAC,qBAAgB,GAAG;AAAA,EACpB,CAAC,qBAAgB,GAAG;AAAA,EACpB,CAAC,qCAAwB,GAAG;AAAA,EAC5B,CAAC,2CAA2B,GAAG;AAAA,EAC/B,CAAC,+BAAqB,GAAG;AAAA,EACzB,CAAC,+BAAqB,GAAG;AAAA,EACzB,CAAC,yCAA0B,GAAG;AAAA,EAC9B,CAAC,yBAAkB,GAAG;AAAA,EACtB,CAAC,+BAAqB,GAAG;AAAA,EACzB,CAAC,qBAAgB,GAAG;AAAA,EACpB,CAAC,qBAAgB,GAAG;AAAA,EACpB,CAAC,qBAAgB,GAAG;AAAA,EACpB,CAAC,qBAAgB,GAAG;AAAA,EACpB,CAAC,+BAAqB,GAAG;AAAA,EACzB,CAAC,qBAAgB,GAAG;AAAA,EACpB,CAAC,6BAAoB,GAAG;AAAA,EACxB,CAAC,uDAAiC,GAAG;AAAA,EACrC,CAAC,yBAAkB,GAAG;AAAA,EACtB,CAAC,+BAAqB,GAAG;AAAA,EACzB,CAAC,2DAAmC,GAAG;AACxC;AAKA,MAAM,uBAAkD;AAAA,EACvD,CAAC,+BAAqB,GAAG;AAAA,EACzB,CAAC,qBAAgB,GAAG;AAAA,EACpB,CAAC,2BAAmB,GAAG;AAAA,EACvB,CAAC,mCAAuB,GAAG;AAAA,EAC3B,CAAC,2BAAmB,GAAG;AAAA,EACvB,CAAC,6BAAoB,GAAG;AAAA,EACxB,CAAC,yBAAkB,GAClB;AAAA,EACD,CAAC,iCAAsB,GAAG;AAAA,EAC1B,CAAC,uCAAyB,GAAG;AAAA;AAAA,EAG7B,CAAC,qCAAwB,GAAG;AAAA,EAC5B,CAAC,2CAA2B,GAAG;AAAA,EAC/B,CAAC,uBAAiB,GAAG;AAAA,EACrB,CAAC,+BAAqB,GAAG;AAAA,EACzB,CAAC,qBAAgB,GAAG;AAAA;AAAA,EAGpB,CAAC,qBAAgB,GAAG;AAAA,EACpB,CAAC,uBAAiB,GAAG;AAAA;AAAA,EAGrB,CAAC,qBAAgB,GAAG;AAAA,EACpB,CAAC,qBAAgB,GAAG;AAAA;AAAA,EAGpB,CAAC,qCAAwB,GAAG;AAAA,EAC5B,CAAC,2CAA2B,GAAG;AAAA,EAC/B,CAAC,+BAAqB,GAAG;AAAA,EACzB,CAAC,+BAAqB,GAAG;AAAA,EACzB,CAAC,yCAA0B,GAAG;AAAA;AAAA,EAG9B,CAAC,yBAAkB,GAAG;AAAA;AAAA,EAGtB,CAAC,+BAAqB,GAAG;AAAA,EACzB,CAAC,qBAAgB,GAAG;AAAA;AAAA,EAGpB,CAAC,qBAAgB,GAAG;AAAA,EACpB,CAAC,qBAAgB,GAAG;AAAA,EACpB,CAAC,qBAAgB,GAAG;AAAA,EACpB,CAAC,+BAAqB,GAAG;AAAA;AAAA,EAGzB,CAAC,qBAAgB,GAAG;AAAA,EACpB,CAAC,6BAAoB,GAAG;AAAA,EACxB,CAAC,uDAAiC,GAAG;AAAA,EACrC,CAAC,yBAAkB,GAAG;AAAA,EACtB,CAAC,+BAAqB,GAAG;AAAA;AAAA,EAGzB,CAAC,2DAAmC,GAAG;AACxC;AAUA,SAAS,UAAU,MAAc,QAAuC;AACvE,MAAI,CAAC,MAAM;AACV,WAAO;AAAA,MACN,SAAS,CAAC;AAAA,MACV,iBAAiB,CAAC;AAAA,IACnB;AAAA,EACD;AAEA,QAAM,UAAoC,CAAC;AAC3C,QAAM,kBAAuC,CAAC;AAE9C,QAAM,sBAAsB,CAAC,MAAc,YAA+C;AAEzF,UAAM,QAAQ,QAAQ,MAAM,SAAS,GAAG,IAAI,QAAQ,QAAQ,QAAQ,QAAQ;AAC5E,UAAM,UAAU,8BAAU,SAAS,QAAQ,QAAQ,MAAM,KAAK;AAC9D,eAAW,SAAS,SAAS;AAC5B,UAAI,MAAM,UAAU,OAAW;AAE/B,YAAM,aAAa;AACnB,YAAM,QAAQ,MAAM;AACpB,YAAM,MAAM,MAAM,QAAQ,MAAM,CAAC,EAAE;AAEnC,UAAI,CAAC,QAAQ,UAAU,GAAG;AACzB,gBAAQ,UAAU,IAAI,CAAC;AAAA,MACxB;AACA,cAAQ,UAAU,EAAE,KAAK,KAAK,UAAU,OAAO,GAAG,CAAC;AAEnD,sBAAgB,KAAK;AAAA,QACpB;AAAA,QACA,MAAM,KAAK,UAAU,OAAO,GAAG;AAAA,MAChC,CAAC;AAAA,IACF;AAAA,EACD;AAGA,QAAM,WAAW,OAAO,YAAY;AACpC,aAAW,UAAU,UAAU;AAC9B,UAAM,UAAU,qBAAqB,MAAM;AAC3C,QAAI,SAAS;AACZ,0BAAoB,QAAQ,OAAO;AAAA,IACpC;AAAA,EACD;AACA,MAAI,OAAO,aAAa,QAAQ;AAC/B,eAAW,SAAS,OAAO,aAAa;AACvC,0BAAoB,MAAM,UAAM,0BAAW,MAAM,KAAK,CAAC;AAAA,IACxD;AAAA,EACD;AAEA,SAAO;AAAA,IACN,SAAS;AAAA,IACT;AAAA,EACD;AACD;AAEO,MAAM,mBAA6C,CAAC,WAAW;AACrE,SAAO,CAAC,UAAkB;AACzB,UAAM,YAAY,UAAU,OAAO,MAAM;AACzC,UAAM,WAAW,UAAU,WAAW,OAAO,KAAK,UAAU,OAAO,EAAE,SAAS;AAC9E,WAAO;AAAA,MACN,eAAe;AAAA,MACf,mBAAmB;AAAA,MACnB,MAAM;AAAA,QACL,cAAc,UAAU;AAAA,QACxB,iBAAiB,UAAU;AAAA,MAC5B;AAAA,IACD;AAAA,EACD;AACD;AAEO,MAAM,2BAA6D,CAAC,WAAW;AACrF,SAAO,CAAC,UAAkB;AACzB,UAAM,YAAY,UAAU,OAAO,EAAE,aAAa,OAAO,aAAa,UAAU,CAAC,EAAE,CAAC;AACpF,UAAM,mBAAmB,UAAU,WAAW,OAAO,KAAK,UAAU,OAAO,EAAE,SAAS;AACtF,WAAO;AAAA,MACN,eAAe;AAAA,MACf,mBAAmB;AAAA,MACnB,MAAM;AAAA,QACL,cAAc,UAAU;AAAA,QACxB,iBAAiB,UAAU;AAAA,MAC5B;AAAA,IACD;AAAA,EACD;AACD;","names":["PIIEntity"]}
@@ -22,6 +22,7 @@ __export(secretKeys_exports, {
22
22
  secretKeysCheck: () => secretKeysCheck
23
23
  });
24
24
  module.exports = __toCommonJS(secretKeys_exports);
25
+ var import_n8n_workflow = require("n8n-workflow");
25
26
  const COMMON_KEY_PREFIXES = [
26
27
  "key-",
27
28
  "sk-",
@@ -154,8 +155,7 @@ function isSecretCandidate(s, cfg, customRegex) {
154
155
  if (customRegex) {
155
156
  for (const pattern of customRegex) {
156
157
  try {
157
- const regex = new RegExp(pattern);
158
- if (regex.test(s)) {
158
+ if (import_n8n_workflow.safeRegex.test(pattern, s)) {
159
159
  return true;
160
160
  }
161
161
  } catch {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../nodes/Guardrails/actions/checks/secretKeys.ts"],"sourcesContent":["/**\n * Secret key detection guardrail module.\n *\n * This module provides functions and configuration for detecting potential API keys,\n * secrets, and credentials in text. It includes entropy and diversity checks, pattern\n * recognition, and a guardrail check_fn for runtime enforcement.\n */\n\nimport type { CreateCheckFn, GuardrailResult } from '../types';\n\nexport type SecretKeysConfig = {\n\tthreshold: 'strict' | 'balanced' | 'permissive';\n\tcustomRegex?: string[];\n};\n\n/**\n * Common key prefixes used in secret keys.\n */\nconst COMMON_KEY_PREFIXES = [\n\t'key-',\n\t'sk-',\n\t'sk_',\n\t'pk_',\n\t'pk-',\n\t'ghp_',\n\t'AKIA',\n\t'xox',\n\t'SG.',\n\t'hf_',\n\t'api-',\n\t'apikey-',\n\t'token-',\n\t'secret-',\n\t'SHA:',\n\t'Bearer ',\n];\n\n/**\n * File extensions to ignore when strict_mode is False.\n */\nconst ALLOWED_EXTENSIONS = [\n\t'.py',\n\t'.js',\n\t'.html',\n\t'.css',\n\t'.json',\n\t'.md',\n\t'.txt',\n\t'.csv',\n\t'.xml',\n\t'.yaml',\n\t'.yml',\n\t'.ini',\n\t'.conf',\n\t'.config',\n\t'.log',\n\t'.sql',\n\t'.sh',\n\t'.bat',\n\t'.dll',\n\t'.so',\n\t'.dylib',\n\t'.jar',\n\t'.war',\n\t'.php',\n\t'.rb',\n\t'.go',\n\t'.rs',\n\t'.ts',\n\t'.jsx',\n\t'.vue',\n\t'.cpp',\n\t'.c',\n\t'.h',\n\t'.cs',\n\t'.fs',\n\t'.vb',\n\t'.doc',\n\t'.docx',\n\t'.xls',\n\t'.xlsx',\n\t'.ppt',\n\t'.pptx',\n\t'.pdf',\n\t'.jpg',\n\t'.jpeg',\n\t'.png',\n];\n\n/**\n * Configuration presets for different sensitivity levels.\n */\nconst CONFIGS: Record<\n\tstring,\n\t{\n\t\tmin_length: number;\n\t\tmin_entropy: number;\n\t\tmin_diversity: number;\n\t\tstrict_mode: boolean;\n\t}\n> = {\n\tstrict: {\n\t\tmin_length: 10,\n\t\tmin_entropy: 3.0, // Lowered from 3.5 to be more reasonable\n\t\tmin_diversity: 2,\n\t\tstrict_mode: true,\n\t},\n\tbalanced: {\n\t\tmin_length: 10, // Lowered to catch more common keys\n\t\tmin_entropy: 3.8,\n\t\tmin_diversity: 3,\n\t\tstrict_mode: false,\n\t},\n\tpermissive: {\n\t\tmin_length: 30,\n\t\tmin_entropy: 4.0,\n\t\tmin_diversity: 2, // Lowered from 3 to be more reasonable\n\t\tstrict_mode: false,\n\t},\n};\n\n/**\n * Calculate the Shannon entropy of a string.\n */\nfunction entropy(s: string): number {\n\tif (s.length === 0) return 0;\n\n\tconst counts: Record<string, number> = {};\n\tfor (const c of s) {\n\t\tcounts[c] = (counts[c] || 0) + 1;\n\t}\n\n\tlet entropy = 0;\n\tfor (const count of Object.values(counts)) {\n\t\tconst probability = count / s.length;\n\t\tentropy -= probability * Math.log2(probability);\n\t}\n\n\treturn entropy;\n}\n\n/**\n * Count the number of character types present in a string.\n */\nfunction charDiversity(s: string): number {\n\treturn [\n\t\ts\n\t\t\t.split('')\n\t\t\t.some((c) => c === c.toLowerCase() && c !== c.toUpperCase()), // lowercase\n\t\ts\n\t\t\t.split('')\n\t\t\t.some((c) => c === c.toUpperCase() && c !== c.toLowerCase()), // uppercase\n\t\ts\n\t\t\t.split('')\n\t\t\t.some((c) => /\\d/.test(c)), // digits\n\t\ts\n\t\t\t.split('')\n\t\t\t.some((c) => !/\\w/.test(c)), // special characters\n\t].filter(Boolean).length;\n}\n\n/**\n * Check if text contains allowed URL or file extension patterns.\n */\nfunction containsAllowedPattern(text: string): boolean {\n\t// Check if it's a URL pattern\n\tconst urlPattern = /^https?:\\/\\/[a-zA-Z0-9.-]+\\/?[a-zA-Z0-9.\\/_-]*$/i;\n\tif (urlPattern.test(text)) {\n\t\t// If it's a URL, check if it contains any secret patterns\n\t\t// If it contains secrets, don't allow it\n\t\tif (COMMON_KEY_PREFIXES.some((prefix) => text.includes(prefix))) {\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t}\n\n\t// Regex for allowed file extensions - must end with the extension\n\tconst extPattern = new RegExp(\n\t\t`^[^\\\\s]*(${ALLOWED_EXTENSIONS.map((ext) => ext.replace('.', '\\\\.')).join('|')})$`,\n\t\t'i',\n\t);\n\treturn extPattern.test(text);\n}\n\n/**\n * Check if a string is a secret key using the specified criteria.\n */\nfunction isSecretCandidate(\n\ts: string,\n\tcfg: (typeof CONFIGS)[keyof typeof CONFIGS],\n\tcustomRegex?: string[],\n): boolean {\n\t// Check custom patterns first if provided\n\tif (customRegex) {\n\t\tfor (const pattern of customRegex) {\n\t\t\ttry {\n\t\t\t\tconst regex = new RegExp(pattern);\n\t\t\t\tif (regex.test(s)) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\t// Invalid regex pattern, skip\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\t}\n\n\tif (!cfg.strict_mode && containsAllowedPattern(s)) {\n\t\treturn false;\n\t}\n\n\tconst longEnough = s.length >= cfg.min_length;\n\tconst diverse = charDiversity(s) >= cfg.min_diversity;\n\n\t// Check common prefixes first - these should always be detected\n\tif (COMMON_KEY_PREFIXES.some((prefix) => s.startsWith(prefix))) {\n\t\treturn true;\n\t}\n\n\t// For other candidates, check length and diversity\n\tif (!(longEnough && diverse)) {\n\t\treturn false;\n\t}\n\n\treturn entropy(s) >= cfg.min_entropy;\n}\n\n/**\n * Detect potential secret keys in text.\n */\nfunction detectSecretKeys(\n\ttext: string,\n\tcfg: (typeof CONFIGS)[keyof typeof CONFIGS],\n\tconfig: SecretKeysConfig,\n): GuardrailResult {\n\tconst words = text.split(/\\s+/).map((w) => w.replace(/[*#]/g, ''));\n\tconst secrets = words.filter((w) => isSecretCandidate(w, cfg, config.customRegex));\n\n\treturn {\n\t\tguardrailName: 'secretKeys',\n\t\ttripwireTriggered: secrets.length > 0,\n\t\tinfo: {\n\t\t\tmaskEntities: { SECRET: secrets },\n\t\t\tdetectedSecrets: secrets,\n\t\t},\n\t};\n}\n\n/**\n * Async guardrail function for secret key and credential detection.\n *\n * Scans the input for likely secrets or credentials (e.g., API keys, tokens)\n * using entropy, diversity, and pattern rules.\n *\n * @param data Input text to scan.\n * @param config Configuration for secret detection.\n * @returns GuardrailResult indicating if secrets were detected, with findings in info.\n */\nexport const secretKeysCheck = (data: string, config: SecretKeysConfig): GuardrailResult => {\n\tconst cfg = CONFIGS[config.threshold];\n\treturn detectSecretKeys(data, cfg, config);\n};\n\nexport const createSecretKeysCheckFn: CreateCheckFn<SecretKeysConfig> =\n\t(config) => (input: string) =>\n\t\tsecretKeysCheck(input, config);\n"],"mappings":"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","names":["entropy"]}
1
+ {"version":3,"sources":["../../../../../nodes/Guardrails/actions/checks/secretKeys.ts"],"sourcesContent":["/**\n * Secret key detection guardrail module.\n *\n * This module provides functions and configuration for detecting potential API keys,\n * secrets, and credentials in text. It includes entropy and diversity checks, pattern\n * recognition, and a guardrail check_fn for runtime enforcement.\n */\n\nimport { safeRegex } from 'n8n-workflow';\n\nimport type { CreateCheckFn, GuardrailResult } from '../types';\n\nexport type SecretKeysConfig = {\n\tthreshold: 'strict' | 'balanced' | 'permissive';\n\tcustomRegex?: string[];\n};\n\n/**\n * Common key prefixes used in secret keys.\n */\nconst COMMON_KEY_PREFIXES = [\n\t'key-',\n\t'sk-',\n\t'sk_',\n\t'pk_',\n\t'pk-',\n\t'ghp_',\n\t'AKIA',\n\t'xox',\n\t'SG.',\n\t'hf_',\n\t'api-',\n\t'apikey-',\n\t'token-',\n\t'secret-',\n\t'SHA:',\n\t'Bearer ',\n];\n\n/**\n * File extensions to ignore when strict_mode is False.\n */\nconst ALLOWED_EXTENSIONS = [\n\t'.py',\n\t'.js',\n\t'.html',\n\t'.css',\n\t'.json',\n\t'.md',\n\t'.txt',\n\t'.csv',\n\t'.xml',\n\t'.yaml',\n\t'.yml',\n\t'.ini',\n\t'.conf',\n\t'.config',\n\t'.log',\n\t'.sql',\n\t'.sh',\n\t'.bat',\n\t'.dll',\n\t'.so',\n\t'.dylib',\n\t'.jar',\n\t'.war',\n\t'.php',\n\t'.rb',\n\t'.go',\n\t'.rs',\n\t'.ts',\n\t'.jsx',\n\t'.vue',\n\t'.cpp',\n\t'.c',\n\t'.h',\n\t'.cs',\n\t'.fs',\n\t'.vb',\n\t'.doc',\n\t'.docx',\n\t'.xls',\n\t'.xlsx',\n\t'.ppt',\n\t'.pptx',\n\t'.pdf',\n\t'.jpg',\n\t'.jpeg',\n\t'.png',\n];\n\n/**\n * Configuration presets for different sensitivity levels.\n */\nconst CONFIGS: Record<\n\tstring,\n\t{\n\t\tmin_length: number;\n\t\tmin_entropy: number;\n\t\tmin_diversity: number;\n\t\tstrict_mode: boolean;\n\t}\n> = {\n\tstrict: {\n\t\tmin_length: 10,\n\t\tmin_entropy: 3.0, // Lowered from 3.5 to be more reasonable\n\t\tmin_diversity: 2,\n\t\tstrict_mode: true,\n\t},\n\tbalanced: {\n\t\tmin_length: 10, // Lowered to catch more common keys\n\t\tmin_entropy: 3.8,\n\t\tmin_diversity: 3,\n\t\tstrict_mode: false,\n\t},\n\tpermissive: {\n\t\tmin_length: 30,\n\t\tmin_entropy: 4.0,\n\t\tmin_diversity: 2, // Lowered from 3 to be more reasonable\n\t\tstrict_mode: false,\n\t},\n};\n\n/**\n * Calculate the Shannon entropy of a string.\n */\nfunction entropy(s: string): number {\n\tif (s.length === 0) return 0;\n\n\tconst counts: Record<string, number> = {};\n\tfor (const c of s) {\n\t\tcounts[c] = (counts[c] || 0) + 1;\n\t}\n\n\tlet entropy = 0;\n\tfor (const count of Object.values(counts)) {\n\t\tconst probability = count / s.length;\n\t\tentropy -= probability * Math.log2(probability);\n\t}\n\n\treturn entropy;\n}\n\n/**\n * Count the number of character types present in a string.\n */\nfunction charDiversity(s: string): number {\n\treturn [\n\t\ts\n\t\t\t.split('')\n\t\t\t.some((c) => c === c.toLowerCase() && c !== c.toUpperCase()), // lowercase\n\t\ts\n\t\t\t.split('')\n\t\t\t.some((c) => c === c.toUpperCase() && c !== c.toLowerCase()), // uppercase\n\t\ts\n\t\t\t.split('')\n\t\t\t.some((c) => /\\d/.test(c)), // digits\n\t\ts\n\t\t\t.split('')\n\t\t\t.some((c) => !/\\w/.test(c)), // special characters\n\t].filter(Boolean).length;\n}\n\n/**\n * Check if text contains allowed URL or file extension patterns.\n */\nfunction containsAllowedPattern(text: string): boolean {\n\t// Check if it's a URL pattern\n\tconst urlPattern = /^https?:\\/\\/[a-zA-Z0-9.-]+\\/?[a-zA-Z0-9.\\/_-]*$/i;\n\tif (urlPattern.test(text)) {\n\t\t// If it's a URL, check if it contains any secret patterns\n\t\t// If it contains secrets, don't allow it\n\t\tif (COMMON_KEY_PREFIXES.some((prefix) => text.includes(prefix))) {\n\t\t\treturn false;\n\t\t}\n\t\treturn true;\n\t}\n\n\t// Regex for allowed file extensions - must end with the extension\n\tconst extPattern = new RegExp(\n\t\t`^[^\\\\s]*(${ALLOWED_EXTENSIONS.map((ext) => ext.replace('.', '\\\\.')).join('|')})$`,\n\t\t'i',\n\t);\n\treturn extPattern.test(text);\n}\n\n/**\n * Check if a string is a secret key using the specified criteria.\n */\nfunction isSecretCandidate(\n\ts: string,\n\tcfg: (typeof CONFIGS)[keyof typeof CONFIGS],\n\tcustomRegex?: string[],\n): boolean {\n\t// Check custom patterns first if provided\n\tif (customRegex) {\n\t\tfor (const pattern of customRegex) {\n\t\t\ttry {\n\t\t\t\tif (safeRegex.test(pattern, s)) {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\t// Invalid regex pattern, skip\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\t}\n\n\tif (!cfg.strict_mode && containsAllowedPattern(s)) {\n\t\treturn false;\n\t}\n\n\tconst longEnough = s.length >= cfg.min_length;\n\tconst diverse = charDiversity(s) >= cfg.min_diversity;\n\n\t// Check common prefixes first - these should always be detected\n\tif (COMMON_KEY_PREFIXES.some((prefix) => s.startsWith(prefix))) {\n\t\treturn true;\n\t}\n\n\t// For other candidates, check length and diversity\n\tif (!(longEnough && diverse)) {\n\t\treturn false;\n\t}\n\n\treturn entropy(s) >= cfg.min_entropy;\n}\n\n/**\n * Detect potential secret keys in text.\n */\nfunction detectSecretKeys(\n\ttext: string,\n\tcfg: (typeof CONFIGS)[keyof typeof CONFIGS],\n\tconfig: SecretKeysConfig,\n): GuardrailResult {\n\tconst words = text.split(/\\s+/).map((w) => w.replace(/[*#]/g, ''));\n\tconst secrets = words.filter((w) => isSecretCandidate(w, cfg, config.customRegex));\n\n\treturn {\n\t\tguardrailName: 'secretKeys',\n\t\ttripwireTriggered: secrets.length > 0,\n\t\tinfo: {\n\t\t\tmaskEntities: { SECRET: secrets },\n\t\t\tdetectedSecrets: secrets,\n\t\t},\n\t};\n}\n\n/**\n * Async guardrail function for secret key and credential detection.\n *\n * Scans the input for likely secrets or credentials (e.g., API keys, tokens)\n * using entropy, diversity, and pattern rules.\n *\n * @param data Input text to scan.\n * @param config Configuration for secret detection.\n * @returns GuardrailResult indicating if secrets were detected, with findings in info.\n */\nexport const secretKeysCheck = (data: string, config: SecretKeysConfig): GuardrailResult => {\n\tconst cfg = CONFIGS[config.threshold];\n\treturn detectSecretKeys(data, cfg, config);\n};\n\nexport const createSecretKeysCheckFn: CreateCheckFn<SecretKeysConfig> =\n\t(config) => (input: string) =>\n\t\tsecretKeysCheck(input, config);\n"],"mappings":"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","names":["entropy"]}
@@ -22,20 +22,12 @@ __export(common_exports, {
22
22
  splitByComma: () => splitByComma
23
23
  });
24
24
  module.exports = __toCommonJS(common_exports);
25
+ var import_n8n_workflow = require("n8n-workflow");
25
26
  const splitByComma = (str) => {
26
27
  return str.split(",").map((s) => s.trim()).filter((s) => s);
27
28
  };
28
29
  const parseRegex = (input) => {
29
- const regexMatch = (input || "").toString().match(new RegExp("^/(.*?)/([gimusy]*)$"));
30
- let regex;
31
- if (!regexMatch) {
32
- regex = new RegExp((input || "").toString());
33
- } else if (regexMatch.length === 1) {
34
- regex = new RegExp(regexMatch[1]);
35
- } else {
36
- regex = new RegExp(regexMatch[1], regexMatch[2]);
37
- }
38
- return regex;
30
+ return (0, import_n8n_workflow.parseRegexLiteral)((input || "").toString());
39
31
  };
40
32
  // Annotate the CommonJS export names for ESM import in node:
41
33
  0 && (module.exports = {
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../nodes/Guardrails/helpers/common.ts"],"sourcesContent":["export const splitByComma = (str: string) => {\n\treturn str\n\t\t.split(',')\n\t\t.map((s) => s.trim())\n\t\t.filter((s) => s);\n};\n\nexport const parseRegex = (input: string) => {\n\tconst regexMatch = (input || '').toString().match(new RegExp('^/(.*?)/([gimusy]*)$'));\n\n\tlet regex: RegExp;\n\tif (!regexMatch) {\n\t\tregex = new RegExp((input || '').toString());\n\t} else if (regexMatch.length === 1) {\n\t\tregex = new RegExp(regexMatch[1]);\n\t} else {\n\t\tregex = new RegExp(regexMatch[1], regexMatch[2]);\n\t}\n\n\treturn regex;\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAO,MAAM,eAAe,CAAC,QAAgB;AAC5C,SAAO,IACL,MAAM,GAAG,EACT,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,EACnB,OAAO,CAAC,MAAM,CAAC;AAClB;AAEO,MAAM,aAAa,CAAC,UAAkB;AAC5C,QAAM,cAAc,SAAS,IAAI,SAAS,EAAE,MAAM,IAAI,OAAO,sBAAsB,CAAC;AAEpF,MAAI;AACJ,MAAI,CAAC,YAAY;AAChB,YAAQ,IAAI,QAAQ,SAAS,IAAI,SAAS,CAAC;AAAA,EAC5C,WAAW,WAAW,WAAW,GAAG;AACnC,YAAQ,IAAI,OAAO,WAAW,CAAC,CAAC;AAAA,EACjC,OAAO;AACN,YAAQ,IAAI,OAAO,WAAW,CAAC,GAAG,WAAW,CAAC,CAAC;AAAA,EAChD;AAEA,SAAO;AACR;","names":[]}
1
+ {"version":3,"sources":["../../../../nodes/Guardrails/helpers/common.ts"],"sourcesContent":["import { parseRegexLiteral } from 'n8n-workflow';\n\nexport const splitByComma = (str: string) => {\n\treturn str\n\t\t.split(',')\n\t\t.map((s) => s.trim())\n\t\t.filter((s) => s);\n};\n\nexport const parseRegex = (input: string) => {\n\treturn parseRegexLiteral((input || '').toString());\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,0BAAkC;AAE3B,MAAM,eAAe,CAAC,QAAgB;AAC5C,SAAO,IACL,MAAM,GAAG,EACT,IAAI,CAAC,MAAM,EAAE,KAAK,CAAC,EACnB,OAAO,CAAC,MAAM,CAAC;AAClB;AAEO,MAAM,aAAa,CAAC,UAAkB;AAC5C,aAAO,wCAAmB,SAAS,IAAI,SAAS,CAAC;AAClD;","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@n8n/n8n-nodes-langchain",
3
- "version": "1.122.46",
3
+ "version": "1.122.48",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "files": [
@@ -159,7 +159,7 @@
159
159
  "fast-glob": "3.2.12",
160
160
  "jest-mock-extended": "^3.0.4",
161
161
  "tsup": "^8.5.1",
162
- "n8n-core": "1.122.38",
162
+ "n8n-core": "1.122.39",
163
163
  "@n8n/eslint-plugin-community-nodes": "0.7.0"
164
164
  },
165
165
  "dependencies": {
@@ -232,11 +232,11 @@
232
232
  "@n8n/client-oauth2": "0.33.6",
233
233
  "@n8n/config": "1.65.6",
234
234
  "@n8n/di": "0.10.0",
235
- "@n8n/json-schema-to-zod": "1.6.0",
236
235
  "@n8n/errors": "0.5.1",
237
- "@n8n/typescript-config": "1.3.1",
238
- "n8n-nodes-base": "1.121.42",
239
- "n8n-workflow": "1.120.22"
236
+ "@n8n/json-schema-to-zod": "1.6.0",
237
+ "n8n-nodes-base": "1.121.44",
238
+ "n8n-workflow": "1.120.23",
239
+ "@n8n/typescript-config": "1.3.1"
240
240
  },
241
241
  "license": "SEE LICENSE IN LICENSE.md",
242
242
  "homepage": "https://n8n.io",