diff --git a/node_modules/.package-lock.json b/node_modules/.package-lock.json index 750044d8..f386dad9 100644 --- a/node_modules/.package-lock.json +++ b/node_modules/.package-lock.json @@ -58,9 +58,9 @@ } }, "node_modules/brace-expansion": { - "version": "5.0.9", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.9.tgz", - "integrity": "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==", + "version": "5.0.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz", + "integrity": "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==", "license": "MIT", "dependencies": { "balanced-match": "^4.0.2" @@ -94,9 +94,9 @@ } }, "node_modules/nodemailer": { - "version": "10.0.10", - "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-10.0.10.tgz", - "integrity": "sha512-He9XskOFms62SyAKkLu8CcGcYHAo+BSHSsORI8s4PJH8qZgZY4L4lDfvyN0twvmbpyG+eGrxpyBlskj9d9rJ8A==", + "version": "10.0.11", + "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-10.0.11.tgz", + "integrity": "sha512-/c4P7U7aGpiNu2Rl08q525q2zECkUpSaf2zQPgIStCcAjHAkkQQKwD4sTyi3l91mGcLQrKzL1syXPHymo+Ogtw==", "license": "MIT-0", "engines": { "node": ">=20.0.0" diff --git a/node_modules/brace-expansion/dist/commonjs/index.d.ts b/node_modules/brace-expansion/dist/commonjs/index.d.ts index f3e2de9d..1d86e5ec 100644 --- a/node_modules/brace-expansion/dist/commonjs/index.d.ts +++ b/node_modules/brace-expansion/dist/commonjs/index.d.ts @@ -1,8 +1,12 @@ export declare const EXPANSION_MAX = 100000; export declare const EXPANSION_MAX_LENGTH = 4000000; +export declare const EXPANSION_MAX_DEPTH = 1000; +export declare const EXPANSION_MAX_REWRITES = 1000; export type BraceExpansionOptions = { max?: number; maxLength?: number; + maxDepth?: number; + maxRewrites?: number; }; export declare function expand(str: string, options?: BraceExpansionOptions): string[]; //# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/node_modules/brace-expansion/dist/commonjs/index.d.ts.map b/node_modules/brace-expansion/dist/commonjs/index.d.ts.map index c0ff8dc1..58141150 100644 --- a/node_modules/brace-expansion/dist/commonjs/index.d.ts.map +++ b/node_modules/brace-expansion/dist/commonjs/index.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAkBA,eAAO,MAAM,aAAa,SAAU,CAAA;AAYpC,eAAO,MAAM,oBAAoB,UAAY,CAAA;AAwD7C,MAAM,MAAM,qBAAqB,GAAG;IAClC,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,CAAA;AAED,wBAAgB,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,GAAE,qBAA0B,YAkBtE"} \ No newline at end of file +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAkBA,eAAO,MAAM,aAAa,SAAU,CAAA;AAYpC,eAAO,MAAM,oBAAoB,UAAY,CAAA;AAU7C,eAAO,MAAM,mBAAmB,OAAQ,CAAA;AAUxC,eAAO,MAAM,sBAAsB,OAAQ,CAAA;AAyE3C,MAAM,MAAM,qBAAqB,GAAG;IAClC,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB,CAAA;AAED,wBAAgB,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,GAAE,qBAA0B,YA+BtE"} \ No newline at end of file diff --git a/node_modules/brace-expansion/dist/commonjs/index.js b/node_modules/brace-expansion/dist/commonjs/index.js index 869a6bee..48cf0d3d 100644 --- a/node_modules/brace-expansion/dist/commonjs/index.js +++ b/node_modules/brace-expansion/dist/commonjs/index.js @@ -1,6 +1,6 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -exports.EXPANSION_MAX_LENGTH = exports.EXPANSION_MAX = void 0; +exports.EXPANSION_MAX_REWRITES = exports.EXPANSION_MAX_DEPTH = exports.EXPANSION_MAX_LENGTH = exports.EXPANSION_MAX = void 0; exports.expand = expand; const balanced_match_1 = require("balanced-match"); const escSlash = '\0SLASH' + Math.random() + '\0'; @@ -30,6 +30,24 @@ exports.EXPANSION_MAX = 100_000; // realistic expansion (100k results hitting `EXPANSION_MAX` measure ~1M // characters) so legitimate input is unaffected. exports.EXPANSION_MAX_LENGTH = 4_000_000; +// `expand_` recurses once per level of brace *nesting* - both when expanding a +// set's comma members and when re-wrapping a set whose body is a single part. +// The CVE-2026-14257 fix made the *tail* iterative (recursion on `m.post`, one +// level per chained group), which left nesting depth unbounded: about 3,100 +// levels of `{{{...a,b...}}}` - only ~6KB of input - exhausted the native stack +// and crashed the process. `EXPANSION_MAX_DEPTH` bounds how deep the parser +// will follow nesting. It sits far above any realistic pattern and well below +// the depth at which the stack runs out. +exports.EXPANSION_MAX_DEPTH = 1_000; +// Bash keeps a quirk where a brace group followed by a comma set still expands +// (`{a},b}`). The parser implements it by rewriting the string and restarting +// the scan, absorbing one `}` per pass. `n` trailing braces therefore cost `n` +// full passes over a string that itself grows by one `escClose` sentinel each +// time - quadratic in `n`, with a ~26x constant from the sentinel's length. +// 128KB of `'{a}' + '}'.repeat(n) + ',z}'` blocked the event loop for 27 +// seconds to produce two results. `EXPANSION_MAX_REWRITES` bounds how many +// times the scan may restart. Real `{a},b}` input needs a handful. +exports.EXPANSION_MAX_REWRITES = 1_000; function numeric(str) { return !isNaN(str) ? parseInt(str, 10) : str.charCodeAt(0); } @@ -49,37 +67,52 @@ function unescapeBraces(str) { .replace(escCommaPattern, ',') .replace(escPeriodPattern, '.'); } +// Like `target.push(...items)` but doesn't overflow the stack +function pushAll(target, items) { + for (let i = 0; i < items.length; i++) { + target.push(items[i]); + } +} /** * Basically just str.split(","), but handling cases * where we have nested braced sections, which should be * treated as individual members, like {a,{b,c},d} */ function parseCommaParts(str) { - if (!str) { - return ['']; - } const parts = []; - const m = (0, balanced_match_1.balanced)('{', '}', str); - if (!m) { - return str.split(','); + // Walk the brace groups iteratively. Recursing on `post` once per group let a + // chain of them exhaust the stack - the parsing-side counterpart to + // the `expand_` overflow fixed for CVE-2026-14257, and not something `max` or + // `maxLength` can bound, since it happens before expansion. + // + // The part the next chunk continues + let carry = ''; + for (;;) { + const m = (0, balanced_match_1.balanced)('{', '}', str); + if (!m) { + const tail = str.split(','); + tail[0] = carry + tail[0]; + pushAll(parts, tail); + return parts; + } + const { pre, body, post } = m; + const p = pre.split(','); + p[0] = carry + p[0]; + p[p.length - 1] += '{' + body + '}'; + if (!post.length) { + pushAll(parts, p); + return parts; + } + carry = p.pop(); + pushAll(parts, p); + str = post; } - const { pre, body, post } = m; - const p = pre.split(','); - p[p.length - 1] += '{' + body + '}'; - const postParts = parseCommaParts(post); - if (post.length) { - ; - p[p.length - 1] += postParts.shift(); - p.push.apply(p, postParts); - } - parts.push.apply(parts, p); - return parts; } function expand(str, options = {}) { if (!str) { return []; } - const { max = exports.EXPANSION_MAX, maxLength = exports.EXPANSION_MAX_LENGTH } = options; + const { max = exports.EXPANSION_MAX, maxLength = exports.EXPANSION_MAX_LENGTH, maxDepth = exports.EXPANSION_MAX_DEPTH, maxRewrites = exports.EXPANSION_MAX_REWRITES, } = options; // I don't know why Bash 4.3 does this, but it does. // Anything starting with {} will have the first two bytes preserved // but *only* at the top level, so {},a}b will not expand to anything, @@ -89,7 +122,7 @@ function expand(str, options = {}) { if (str.slice(0, 2) === '{}') { str = '\\{\\}' + str.slice(2); } - return expand_(escapeBraces(str), max, maxLength, true).map(unescapeBraces); + return expand_(escapeBraces(str), max, maxLength, maxDepth, 0, maxRewrites, true).map(unescapeBraces); } function embrace(str) { return '{' + str + '}'; @@ -184,7 +217,13 @@ function expandSequence(body, isAlphaSequence, max, maxLength) { } return N; } -function expand_(str, max, maxLength, isTop) { +function expand_(str, max, maxLength, maxDepth, depth, maxRewrites, isTop) { + // Too deeply nested to keep following: treat the rest as literal, the same + // way a group that cannot expand is already handled. Truncating rather than + // throwing keeps `expand` total, matching `max` and `maxLength`. + if (depth > maxDepth) { + return [str]; + } // Consume the string's top-level brace groups left to right, threading a // running set of combined prefixes (`acc`). Expanding the tail iteratively - // rather than recursing on `m.post` once per group - keeps the native stack @@ -196,6 +235,9 @@ function expand_(str, max, maxLength, isTop) { // comma set - a sequence like `{a..\}` may legitimately yield ''. The drop // is on the final strings, so it is applied to whichever `combine` produces // them (the one with no brace set left in the tail). + // How many times the `{a},b}` rewrite below has restarted the scan. Each pass + // re-reads the whole string, so leaving this unbounded is quadratic. + let rewrites = 0; let dropEmpties = false; let firstGroup = true; for (;;) { @@ -220,7 +262,8 @@ function expand_(str, max, maxLength, isTop) { const isOptions = m.body.indexOf(',') >= 0; if (!isSequence && !isOptions) { // {a},b} - if (m.post.match(/,(?!,).*\}/)) { + if (rewrites < maxRewrites && m.post.match(/,(?!,).*\}/)) { + rewrites++; str = m.pre + '{' + m.body + escClose + m.post; isTop = true; continue; @@ -240,7 +283,7 @@ function expand_(str, max, maxLength, isTop) { let n = parseCommaParts(m.body); if (n.length === 1 && n[0] !== undefined) { // x{{a,b}}y ==> x{a}y x{b}y - n = expand_(n[0], max, maxLength, false).map(embrace); + n = expand_(n[0], max, maxLength, maxDepth, depth + 1, maxRewrites, false).map(embrace); //XXX is this necessary? Can't seem to hit it in tests. /* c8 ignore start */ if (n.length === 1) { @@ -266,12 +309,13 @@ function expand_(str, max, maxLength, isTop) { values = []; let valuesLength = 0; outer: for (let j = 0; j < n.length; j++) { - const expanded = expand_(n[j], max, maxLength, false); + const expanded = expand_(n[j], max, maxLength, maxDepth, depth + 1, maxRewrites, false); for (let k = 0; k < expanded.length; k++) { const v = expanded[k]; if (dropsEmpties && !v) continue; - if (values.length >= max || valuesLength + v.length > maxLength) { + if (values.length >= max || + valuesLength + v.length > maxLength) { break outer; } values.push(v); diff --git a/node_modules/brace-expansion/dist/commonjs/index.js.map b/node_modules/brace-expansion/dist/commonjs/index.js.map index 658bba38..1009b3ac 100644 --- a/node_modules/brace-expansion/dist/commonjs/index.js.map +++ b/node_modules/brace-expansion/dist/commonjs/index.js.map @@ -1 +1 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["import { balanced } from 'balanced-match'\n\nconst escSlash = '\\0SLASH' + Math.random() + '\\0'\nconst escOpen = '\\0OPEN' + Math.random() + '\\0'\nconst escClose = '\\0CLOSE' + Math.random() + '\\0'\nconst escComma = '\\0COMMA' + Math.random() + '\\0'\nconst escPeriod = '\\0PERIOD' + Math.random() + '\\0'\nconst escSlashPattern = new RegExp(escSlash, 'g')\nconst escOpenPattern = new RegExp(escOpen, 'g')\nconst escClosePattern = new RegExp(escClose, 'g')\nconst escCommaPattern = new RegExp(escComma, 'g')\nconst escPeriodPattern = new RegExp(escPeriod, 'g')\nconst slashPattern = /\\\\\\\\/g\nconst openPattern = /\\\\{/g\nconst closePattern = /\\\\}/g\nconst commaPattern = /\\\\,/g\nconst periodPattern = /\\\\\\./g\n\nexport const EXPANSION_MAX = 100_000\n\n// `EXPANSION_MAX` caps the *number* of expansions, but not their length. An\n// input like `'{a,b}'.repeat(1500)` stays under that count - its output is\n// truncated to 100k results - while making every result ~1500 characters\n// long. The result set, and the intermediate arrays built while combining\n// brace sets, then grow large enough to exhaust memory and crash the process\n// (CVE-2026-14257). `EXPANSION_MAX_LENGTH` bounds the total number of\n// characters the accumulator may hold at any point, so memory stays flat no\n// matter how many brace groups are chained. The limit sits well above any\n// realistic expansion (100k results hitting `EXPANSION_MAX` measure ~1M\n// characters) so legitimate input is unaffected.\nexport const EXPANSION_MAX_LENGTH = 4_000_000\n\nfunction numeric(str: string) {\n return !isNaN(str as any) ? parseInt(str, 10) : str.charCodeAt(0)\n}\n\nfunction escapeBraces(str: string) {\n return str\n .replace(slashPattern, escSlash)\n .replace(openPattern, escOpen)\n .replace(closePattern, escClose)\n .replace(commaPattern, escComma)\n .replace(periodPattern, escPeriod)\n}\n\nfunction unescapeBraces(str: string) {\n return str\n .replace(escSlashPattern, '\\\\')\n .replace(escOpenPattern, '{')\n .replace(escClosePattern, '}')\n .replace(escCommaPattern, ',')\n .replace(escPeriodPattern, '.')\n}\n\n/**\n * Basically just str.split(\",\"), but handling cases\n * where we have nested braced sections, which should be\n * treated as individual members, like {a,{b,c},d}\n */\nfunction parseCommaParts(str: string) {\n if (!str) {\n return ['']\n }\n\n const parts: string[] = []\n const m = balanced('{', '}', str)\n\n if (!m) {\n return str.split(',')\n }\n\n const { pre, body, post } = m\n const p = pre.split(',')\n\n p[p.length - 1] += '{' + body + '}'\n const postParts = parseCommaParts(post)\n if (post.length) {\n ;(p[p.length - 1] as string) += postParts.shift()\n p.push.apply(p, postParts)\n }\n\n parts.push.apply(parts, p)\n\n return parts\n}\n\nexport type BraceExpansionOptions = {\n max?: number\n maxLength?: number\n}\n\nexport function expand(str: string, options: BraceExpansionOptions = {}) {\n if (!str) {\n return []\n }\n\n const { max = EXPANSION_MAX, maxLength = EXPANSION_MAX_LENGTH } = options\n\n // I don't know why Bash 4.3 does this, but it does.\n // Anything starting with {} will have the first two bytes preserved\n // but *only* at the top level, so {},a}b will not expand to anything,\n // but a{},b}c will be expanded to [a}c,abc].\n // One could argue that this is a bug in Bash, but since the goal of\n // this module is to match Bash's rules, we escape a leading {}\n if (str.slice(0, 2) === '{}') {\n str = '\\\\{\\\\}' + str.slice(2)\n }\n\n return expand_(escapeBraces(str), max, maxLength, true).map(unescapeBraces)\n}\n\nfunction embrace(str: string) {\n return '{' + str + '}'\n}\n\nfunction isPadded(el: string) {\n return /^-?0\\d/.test(el)\n}\n\nfunction lte(i: number, y: number) {\n return i <= y\n}\n\nfunction gte(i: number, y: number) {\n return i >= y\n}\n\n// Build `{ acc[a] + pre + values[v] }` for every combination, capping the\n// number of results at `max` and the total number of characters at `maxLength`.\n// This is the one place output grows, so bounding it here keeps the single\n// accumulator - and therefore memory - flat regardless of how many brace groups\n// are combined (CVE-2026-14257).\nfunction combine(\n acc: string[],\n pre: string,\n values: string[],\n max: number,\n maxLength: number,\n dropEmpties: boolean,\n): string[] {\n const out: string[] = []\n let length = 0\n for (let a = 0; a < acc.length; a++) {\n for (let v = 0; v < values.length; v++) {\n if (out.length >= max) return out\n const expansion = (acc[a] as string) + pre + values[v]\n // Bash drops empty results at the top level. Skip them before they count\n // against `max`, so `max` bounds the number of *kept* results.\n if (dropEmpties && !expansion) continue\n if (length + expansion.length > maxLength) return out\n out.push(expansion)\n length += expansion.length\n }\n }\n return out\n}\n\n// The expansion values of a single numeric (`1..5`) or alphabetic (`a..e..2`)\n// sequence body.\nfunction expandSequence(\n body: string,\n isAlphaSequence: boolean,\n max: number,\n maxLength: number,\n): string[] {\n const n = body.split(/\\.\\./)\n const N: string[] = []\n // A sequence body always splits into two or three parts, but the compiler\n // can't know that.\n /* c8 ignore start */\n if (n[0] === undefined || n[1] === undefined) {\n return N\n }\n /* c8 ignore stop */\n const x = numeric(n[0])\n const y = numeric(n[1])\n const width = Math.max(n[0].length, n[1].length)\n let incr =\n n.length === 3 && n[2] !== undefined ?\n Math.max(Math.abs(numeric(n[2])), 1)\n : 1\n let test = lte\n const reverse = y < x\n if (reverse) {\n incr *= -1\n test = gte\n }\n const pad = n.some(isPadded)\n\n let length = 0\n for (let i = x; test(i, y) && N.length < max; i += incr) {\n let c\n if (isAlphaSequence) {\n c = String.fromCharCode(i)\n if (c === '\\\\') {\n c = ''\n }\n } else {\n c = String(i)\n if (pad) {\n const need = width - c.length\n if (need > 0) {\n const z = new Array(need + 1).join('0')\n if (i < 0) {\n c = '-' + z + c.slice(1)\n } else {\n c = z + c\n }\n }\n }\n }\n if (length + c.length > maxLength) break\n N.push(c)\n length += c.length\n }\n return N\n}\n\nfunction expand_(\n str: string,\n max: number,\n maxLength: number,\n isTop: boolean,\n): string[] {\n // Consume the string's top-level brace groups left to right, threading a\n // running set of combined prefixes (`acc`). Expanding the tail iteratively -\n // rather than recursing on `m.post` once per group - keeps the native stack\n // depth constant, so deeply chained input (`'{a,b}'.repeat(3000)`) can no\n // longer overflow the stack, and leaves a single accumulator whose size\n // `maxLength` bounds directly (CVE-2026-14257).\n let acc: string[] = ['']\n\n // Bash drops empty results, but only when the *first* top-level group is a\n // comma set - a sequence like `{a..\\}` may legitimately yield ''. The drop\n // is on the final strings, so it is applied to whichever `combine` produces\n // them (the one with no brace set left in the tail).\n let dropEmpties = false\n let firstGroup = true\n\n for (;;) {\n const m = balanced('{', '}', str)\n\n // No brace set left: the rest of the string is literal.\n if (!m) {\n return combine(acc, str, [''], max, maxLength, dropEmpties)\n }\n\n // no need to expand pre, since it is guaranteed to be free of brace-sets\n const pre = m.pre\n\n if (/\\$$/.test(pre)) {\n acc = combine(\n acc,\n pre + '{' + m.body + '}',\n [''],\n max,\n maxLength,\n dropEmpties && !m.post.length,\n )\n firstGroup = false\n if (!m.post.length) break\n str = m.post\n continue\n }\n\n const isNumericSequence = /^-?\\d+\\.\\.-?\\d+(?:\\.\\.-?\\d+)?$/.test(m.body)\n const isAlphaSequence = /^[a-zA-Z]\\.\\.[a-zA-Z](?:\\.\\.-?\\d+)?$/.test(\n m.body,\n )\n const isSequence = isNumericSequence || isAlphaSequence\n const isOptions = m.body.indexOf(',') >= 0\n if (!isSequence && !isOptions) {\n // {a},b}\n if (m.post.match(/,(?!,).*\\}/)) {\n str = m.pre + '{' + m.body + escClose + m.post\n isTop = true\n continue\n }\n // Nothing here expands, so the whole remaining string is literal.\n return combine(\n acc,\n pre + '{' + m.body + '}' + m.post,\n [''],\n max,\n maxLength,\n dropEmpties,\n )\n }\n\n if (firstGroup) {\n dropEmpties = isTop && !isSequence\n firstGroup = false\n }\n\n let values: string[]\n if (isSequence) {\n values = expandSequence(m.body, isAlphaSequence, max, maxLength)\n } else {\n let n = parseCommaParts(m.body)\n if (n.length === 1 && n[0] !== undefined) {\n // x{{a,b}}y ==> x{a}y x{b}y\n n = expand_(n[0], max, maxLength, false).map(embrace)\n //XXX is this necessary? Can't seem to hit it in tests.\n /* c8 ignore start */\n if (n.length === 1) {\n acc = combine(\n acc,\n pre + n[0],\n [''],\n max,\n maxLength,\n dropEmpties && !m.post.length,\n )\n if (!m.post.length) break\n str = m.post\n continue\n }\n /* c8 ignore stop */\n }\n\n // Values that `combine` is going to drop as empty produce no result, so\n // they must not count against `max` - otherwise `{a,,b}` with `max: 2`\n // would stop at `['a', '']` and yield one result instead of two. Skipping\n // them outright keeps `values` bounded while leaving `max` a bound on\n // *kept* results.\n let dropsEmpties = dropEmpties && !m.post.length && !pre\n for (let d = 0; dropsEmpties && d < acc.length; d++) {\n if (acc[d]) {\n dropsEmpties = false\n }\n }\n\n values = []\n let valuesLength = 0\n outer: for (let j = 0; j < n.length; j++) {\n const expanded = expand_(n[j] as string, max, maxLength, false)\n for (let k = 0; k < expanded.length; k++) {\n const v = expanded[k] as string\n if (dropsEmpties && !v) continue\n if (values.length >= max || valuesLength + v.length > maxLength) {\n break outer\n }\n values.push(v)\n valuesLength += v.length\n }\n }\n }\n\n acc = combine(acc, pre, values, max, maxLength, dropEmpties && !m.post.length)\n if (!m.post.length) break\n str = m.post\n }\n\n return acc\n}\n"]} \ No newline at end of file +{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["import { balanced } from 'balanced-match'\n\nconst escSlash = '\\0SLASH' + Math.random() + '\\0'\nconst escOpen = '\\0OPEN' + Math.random() + '\\0'\nconst escClose = '\\0CLOSE' + Math.random() + '\\0'\nconst escComma = '\\0COMMA' + Math.random() + '\\0'\nconst escPeriod = '\\0PERIOD' + Math.random() + '\\0'\nconst escSlashPattern = new RegExp(escSlash, 'g')\nconst escOpenPattern = new RegExp(escOpen, 'g')\nconst escClosePattern = new RegExp(escClose, 'g')\nconst escCommaPattern = new RegExp(escComma, 'g')\nconst escPeriodPattern = new RegExp(escPeriod, 'g')\nconst slashPattern = /\\\\\\\\/g\nconst openPattern = /\\\\{/g\nconst closePattern = /\\\\}/g\nconst commaPattern = /\\\\,/g\nconst periodPattern = /\\\\\\./g\n\nexport const EXPANSION_MAX = 100_000\n\n// `EXPANSION_MAX` caps the *number* of expansions, but not their length. An\n// input like `'{a,b}'.repeat(1500)` stays under that count - its output is\n// truncated to 100k results - while making every result ~1500 characters\n// long. The result set, and the intermediate arrays built while combining\n// brace sets, then grow large enough to exhaust memory and crash the process\n// (CVE-2026-14257). `EXPANSION_MAX_LENGTH` bounds the total number of\n// characters the accumulator may hold at any point, so memory stays flat no\n// matter how many brace groups are chained. The limit sits well above any\n// realistic expansion (100k results hitting `EXPANSION_MAX` measure ~1M\n// characters) so legitimate input is unaffected.\nexport const EXPANSION_MAX_LENGTH = 4_000_000\n\n// `expand_` recurses once per level of brace *nesting* - both when expanding a\n// set's comma members and when re-wrapping a set whose body is a single part.\n// The CVE-2026-14257 fix made the *tail* iterative (recursion on `m.post`, one\n// level per chained group), which left nesting depth unbounded: about 3,100\n// levels of `{{{...a,b...}}}` - only ~6KB of input - exhausted the native stack\n// and crashed the process. `EXPANSION_MAX_DEPTH` bounds how deep the parser\n// will follow nesting. It sits far above any realistic pattern and well below\n// the depth at which the stack runs out.\nexport const EXPANSION_MAX_DEPTH = 1_000\n\n// Bash keeps a quirk where a brace group followed by a comma set still expands\n// (`{a},b}`). The parser implements it by rewriting the string and restarting\n// the scan, absorbing one `}` per pass. `n` trailing braces therefore cost `n`\n// full passes over a string that itself grows by one `escClose` sentinel each\n// time - quadratic in `n`, with a ~26x constant from the sentinel's length.\n// 128KB of `'{a}' + '}'.repeat(n) + ',z}'` blocked the event loop for 27\n// seconds to produce two results. `EXPANSION_MAX_REWRITES` bounds how many\n// times the scan may restart. Real `{a},b}` input needs a handful.\nexport const EXPANSION_MAX_REWRITES = 1_000\n\nfunction numeric(str: string) {\n return !isNaN(str as any) ? parseInt(str, 10) : str.charCodeAt(0)\n}\n\nfunction escapeBraces(str: string) {\n return str\n .replace(slashPattern, escSlash)\n .replace(openPattern, escOpen)\n .replace(closePattern, escClose)\n .replace(commaPattern, escComma)\n .replace(periodPattern, escPeriod)\n}\n\nfunction unescapeBraces(str: string) {\n return str\n .replace(escSlashPattern, '\\\\')\n .replace(escOpenPattern, '{')\n .replace(escClosePattern, '}')\n .replace(escCommaPattern, ',')\n .replace(escPeriodPattern, '.')\n}\n\n// Like `target.push(...items)` but doesn't overflow the stack\nfunction pushAll(target: string[], items: string[]) {\n for (let i = 0; i < items.length; i++) {\n target.push(items[i] as string)\n }\n}\n\n/**\n * Basically just str.split(\",\"), but handling cases\n * where we have nested braced sections, which should be\n * treated as individual members, like {a,{b,c},d}\n */\nfunction parseCommaParts(str: string) {\n const parts: string[] = []\n\n // Walk the brace groups iteratively. Recursing on `post` once per group let a\n // chain of them exhaust the stack - the parsing-side counterpart to\n // the `expand_` overflow fixed for CVE-2026-14257, and not something `max` or\n // `maxLength` can bound, since it happens before expansion.\n //\n // The part the next chunk continues\n let carry = ''\n\n for (;;) {\n const m = balanced('{', '}', str)\n\n if (!m) {\n const tail = str.split(',')\n tail[0] = carry + (tail[0] as string)\n pushAll(parts, tail)\n return parts\n }\n\n const { pre, body, post } = m\n const p = pre.split(',')\n p[0] = carry + (p[0] as string)\n p[p.length - 1] += '{' + body + '}'\n\n if (!post.length) {\n pushAll(parts, p)\n return parts\n }\n\n carry = p.pop() as string\n pushAll(parts, p)\n str = post\n }\n}\n\nexport type BraceExpansionOptions = {\n max?: number\n maxLength?: number\n maxDepth?: number\n maxRewrites?: number\n}\n\nexport function expand(str: string, options: BraceExpansionOptions = {}) {\n if (!str) {\n return []\n }\n\n const {\n max = EXPANSION_MAX,\n maxLength = EXPANSION_MAX_LENGTH,\n maxDepth = EXPANSION_MAX_DEPTH,\n maxRewrites = EXPANSION_MAX_REWRITES,\n } = options\n\n // I don't know why Bash 4.3 does this, but it does.\n // Anything starting with {} will have the first two bytes preserved\n // but *only* at the top level, so {},a}b will not expand to anything,\n // but a{},b}c will be expanded to [a}c,abc].\n // One could argue that this is a bug in Bash, but since the goal of\n // this module is to match Bash's rules, we escape a leading {}\n if (str.slice(0, 2) === '{}') {\n str = '\\\\{\\\\}' + str.slice(2)\n }\n\n return expand_(\n escapeBraces(str),\n max,\n maxLength,\n maxDepth,\n 0,\n maxRewrites,\n true,\n ).map(unescapeBraces)\n}\n\nfunction embrace(str: string) {\n return '{' + str + '}'\n}\n\nfunction isPadded(el: string) {\n return /^-?0\\d/.test(el)\n}\n\nfunction lte(i: number, y: number) {\n return i <= y\n}\n\nfunction gte(i: number, y: number) {\n return i >= y\n}\n\n// Build `{ acc[a] + pre + values[v] }` for every combination, capping the\n// number of results at `max` and the total number of characters at `maxLength`.\n// This is the one place output grows, so bounding it here keeps the single\n// accumulator - and therefore memory - flat regardless of how many brace groups\n// are combined (CVE-2026-14257).\nfunction combine(\n acc: string[],\n pre: string,\n values: string[],\n max: number,\n maxLength: number,\n dropEmpties: boolean,\n): string[] {\n const out: string[] = []\n let length = 0\n for (let a = 0; a < acc.length; a++) {\n for (let v = 0; v < values.length; v++) {\n if (out.length >= max) return out\n const expansion = (acc[a] as string) + pre + values[v]\n // Bash drops empty results at the top level. Skip them before they count\n // against `max`, so `max` bounds the number of *kept* results.\n if (dropEmpties && !expansion) continue\n if (length + expansion.length > maxLength) return out\n out.push(expansion)\n length += expansion.length\n }\n }\n return out\n}\n\n// The expansion values of a single numeric (`1..5`) or alphabetic (`a..e..2`)\n// sequence body.\nfunction expandSequence(\n body: string,\n isAlphaSequence: boolean,\n max: number,\n maxLength: number,\n): string[] {\n const n = body.split(/\\.\\./)\n const N: string[] = []\n // A sequence body always splits into two or three parts, but the compiler\n // can't know that.\n /* c8 ignore start */\n if (n[0] === undefined || n[1] === undefined) {\n return N\n }\n /* c8 ignore stop */\n const x = numeric(n[0])\n const y = numeric(n[1])\n const width = Math.max(n[0].length, n[1].length)\n let incr =\n n.length === 3 && n[2] !== undefined ?\n Math.max(Math.abs(numeric(n[2])), 1)\n : 1\n let test = lte\n const reverse = y < x\n if (reverse) {\n incr *= -1\n test = gte\n }\n const pad = n.some(isPadded)\n\n let length = 0\n for (let i = x; test(i, y) && N.length < max; i += incr) {\n let c\n if (isAlphaSequence) {\n c = String.fromCharCode(i)\n if (c === '\\\\') {\n c = ''\n }\n } else {\n c = String(i)\n if (pad) {\n const need = width - c.length\n if (need > 0) {\n const z = new Array(need + 1).join('0')\n if (i < 0) {\n c = '-' + z + c.slice(1)\n } else {\n c = z + c\n }\n }\n }\n }\n if (length + c.length > maxLength) break\n N.push(c)\n length += c.length\n }\n return N\n}\n\nfunction expand_(\n str: string,\n max: number,\n maxLength: number,\n maxDepth: number,\n depth: number,\n maxRewrites: number,\n isTop: boolean,\n): string[] {\n // Too deeply nested to keep following: treat the rest as literal, the same\n // way a group that cannot expand is already handled. Truncating rather than\n // throwing keeps `expand` total, matching `max` and `maxLength`.\n if (depth > maxDepth) {\n return [str]\n }\n\n // Consume the string's top-level brace groups left to right, threading a\n // running set of combined prefixes (`acc`). Expanding the tail iteratively -\n // rather than recursing on `m.post` once per group - keeps the native stack\n // depth constant, so deeply chained input (`'{a,b}'.repeat(3000)`) can no\n // longer overflow the stack, and leaves a single accumulator whose size\n // `maxLength` bounds directly (CVE-2026-14257).\n let acc: string[] = ['']\n\n // Bash drops empty results, but only when the *first* top-level group is a\n // comma set - a sequence like `{a..\\}` may legitimately yield ''. The drop\n // is on the final strings, so it is applied to whichever `combine` produces\n // them (the one with no brace set left in the tail).\n // How many times the `{a},b}` rewrite below has restarted the scan. Each pass\n // re-reads the whole string, so leaving this unbounded is quadratic.\n let rewrites = 0\n let dropEmpties = false\n let firstGroup = true\n\n for (;;) {\n const m = balanced('{', '}', str)\n\n // No brace set left: the rest of the string is literal.\n if (!m) {\n return combine(acc, str, [''], max, maxLength, dropEmpties)\n }\n\n // no need to expand pre, since it is guaranteed to be free of brace-sets\n const pre = m.pre\n\n if (/\\$$/.test(pre)) {\n acc = combine(\n acc,\n pre + '{' + m.body + '}',\n [''],\n max,\n maxLength,\n dropEmpties && !m.post.length,\n )\n firstGroup = false\n if (!m.post.length) break\n str = m.post\n continue\n }\n\n const isNumericSequence = /^-?\\d+\\.\\.-?\\d+(?:\\.\\.-?\\d+)?$/.test(m.body)\n const isAlphaSequence = /^[a-zA-Z]\\.\\.[a-zA-Z](?:\\.\\.-?\\d+)?$/.test(\n m.body,\n )\n const isSequence = isNumericSequence || isAlphaSequence\n const isOptions = m.body.indexOf(',') >= 0\n if (!isSequence && !isOptions) {\n // {a},b}\n if (rewrites < maxRewrites && m.post.match(/,(?!,).*\\}/)) {\n rewrites++\n str = m.pre + '{' + m.body + escClose + m.post\n isTop = true\n continue\n }\n // Nothing here expands, so the whole remaining string is literal.\n return combine(\n acc,\n pre + '{' + m.body + '}' + m.post,\n [''],\n max,\n maxLength,\n dropEmpties,\n )\n }\n\n if (firstGroup) {\n dropEmpties = isTop && !isSequence\n firstGroup = false\n }\n\n let values: string[]\n if (isSequence) {\n values = expandSequence(m.body, isAlphaSequence, max, maxLength)\n } else {\n let n = parseCommaParts(m.body)\n if (n.length === 1 && n[0] !== undefined) {\n // x{{a,b}}y ==> x{a}y x{b}y\n n = expand_(\n n[0],\n max,\n maxLength,\n maxDepth,\n depth + 1,\n maxRewrites,\n false,\n ).map(embrace)\n //XXX is this necessary? Can't seem to hit it in tests.\n /* c8 ignore start */\n if (n.length === 1) {\n acc = combine(\n acc,\n pre + n[0],\n [''],\n max,\n maxLength,\n dropEmpties && !m.post.length,\n )\n if (!m.post.length) break\n str = m.post\n continue\n }\n /* c8 ignore stop */\n }\n\n // Values that `combine` is going to drop as empty produce no result, so\n // they must not count against `max` - otherwise `{a,,b}` with `max: 2`\n // would stop at `['a', '']` and yield one result instead of two. Skipping\n // them outright keeps `values` bounded while leaving `max` a bound on\n // *kept* results.\n let dropsEmpties = dropEmpties && !m.post.length && !pre\n for (let d = 0; dropsEmpties && d < acc.length; d++) {\n if (acc[d]) {\n dropsEmpties = false\n }\n }\n\n values = []\n let valuesLength = 0\n outer: for (let j = 0; j < n.length; j++) {\n const expanded = expand_(\n n[j] as string,\n max,\n maxLength,\n maxDepth,\n depth + 1,\n maxRewrites,\n false,\n )\n for (let k = 0; k < expanded.length; k++) {\n const v = expanded[k] as string\n if (dropsEmpties && !v) continue\n if (\n values.length >= max ||\n valuesLength + v.length > maxLength\n ) {\n break outer\n }\n values.push(v)\n valuesLength += v.length\n }\n }\n }\n\n acc = combine(\n acc,\n pre,\n values,\n max,\n maxLength,\n dropEmpties && !m.post.length,\n )\n if (!m.post.length) break\n str = m.post\n }\n\n return acc\n}\n"]} \ No newline at end of file diff --git a/node_modules/brace-expansion/dist/esm/index.d.ts b/node_modules/brace-expansion/dist/esm/index.d.ts index f3e2de9d..1d86e5ec 100644 --- a/node_modules/brace-expansion/dist/esm/index.d.ts +++ b/node_modules/brace-expansion/dist/esm/index.d.ts @@ -1,8 +1,12 @@ export declare const EXPANSION_MAX = 100000; export declare const EXPANSION_MAX_LENGTH = 4000000; +export declare const EXPANSION_MAX_DEPTH = 1000; +export declare const EXPANSION_MAX_REWRITES = 1000; export type BraceExpansionOptions = { max?: number; maxLength?: number; + maxDepth?: number; + maxRewrites?: number; }; export declare function expand(str: string, options?: BraceExpansionOptions): string[]; //# sourceMappingURL=index.d.ts.map \ No newline at end of file diff --git a/node_modules/brace-expansion/dist/esm/index.d.ts.map b/node_modules/brace-expansion/dist/esm/index.d.ts.map index c0ff8dc1..58141150 100644 --- a/node_modules/brace-expansion/dist/esm/index.d.ts.map +++ b/node_modules/brace-expansion/dist/esm/index.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAkBA,eAAO,MAAM,aAAa,SAAU,CAAA;AAYpC,eAAO,MAAM,oBAAoB,UAAY,CAAA;AAwD7C,MAAM,MAAM,qBAAqB,GAAG;IAClC,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB,CAAA;AAED,wBAAgB,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,GAAE,qBAA0B,YAkBtE"} \ No newline at end of file +{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAkBA,eAAO,MAAM,aAAa,SAAU,CAAA;AAYpC,eAAO,MAAM,oBAAoB,UAAY,CAAA;AAU7C,eAAO,MAAM,mBAAmB,OAAQ,CAAA;AAUxC,eAAO,MAAM,sBAAsB,OAAQ,CAAA;AAyE3C,MAAM,MAAM,qBAAqB,GAAG;IAClC,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB,CAAA;AAED,wBAAgB,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,GAAE,qBAA0B,YA+BtE"} \ No newline at end of file diff --git a/node_modules/brace-expansion/dist/esm/index.js b/node_modules/brace-expansion/dist/esm/index.js index fd68f570..0e0cc962 100644 --- a/node_modules/brace-expansion/dist/esm/index.js +++ b/node_modules/brace-expansion/dist/esm/index.js @@ -26,6 +26,24 @@ export const EXPANSION_MAX = 100_000; // realistic expansion (100k results hitting `EXPANSION_MAX` measure ~1M // characters) so legitimate input is unaffected. export const EXPANSION_MAX_LENGTH = 4_000_000; +// `expand_` recurses once per level of brace *nesting* - both when expanding a +// set's comma members and when re-wrapping a set whose body is a single part. +// The CVE-2026-14257 fix made the *tail* iterative (recursion on `m.post`, one +// level per chained group), which left nesting depth unbounded: about 3,100 +// levels of `{{{...a,b...}}}` - only ~6KB of input - exhausted the native stack +// and crashed the process. `EXPANSION_MAX_DEPTH` bounds how deep the parser +// will follow nesting. It sits far above any realistic pattern and well below +// the depth at which the stack runs out. +export const EXPANSION_MAX_DEPTH = 1_000; +// Bash keeps a quirk where a brace group followed by a comma set still expands +// (`{a},b}`). The parser implements it by rewriting the string and restarting +// the scan, absorbing one `}` per pass. `n` trailing braces therefore cost `n` +// full passes over a string that itself grows by one `escClose` sentinel each +// time - quadratic in `n`, with a ~26x constant from the sentinel's length. +// 128KB of `'{a}' + '}'.repeat(n) + ',z}'` blocked the event loop for 27 +// seconds to produce two results. `EXPANSION_MAX_REWRITES` bounds how many +// times the scan may restart. Real `{a},b}` input needs a handful. +export const EXPANSION_MAX_REWRITES = 1_000; function numeric(str) { return !isNaN(str) ? parseInt(str, 10) : str.charCodeAt(0); } @@ -45,37 +63,52 @@ function unescapeBraces(str) { .replace(escCommaPattern, ',') .replace(escPeriodPattern, '.'); } +// Like `target.push(...items)` but doesn't overflow the stack +function pushAll(target, items) { + for (let i = 0; i < items.length; i++) { + target.push(items[i]); + } +} /** * Basically just str.split(","), but handling cases * where we have nested braced sections, which should be * treated as individual members, like {a,{b,c},d} */ function parseCommaParts(str) { - if (!str) { - return ['']; - } const parts = []; - const m = balanced('{', '}', str); - if (!m) { - return str.split(','); + // Walk the brace groups iteratively. Recursing on `post` once per group let a + // chain of them exhaust the stack - the parsing-side counterpart to + // the `expand_` overflow fixed for CVE-2026-14257, and not something `max` or + // `maxLength` can bound, since it happens before expansion. + // + // The part the next chunk continues + let carry = ''; + for (;;) { + const m = balanced('{', '}', str); + if (!m) { + const tail = str.split(','); + tail[0] = carry + tail[0]; + pushAll(parts, tail); + return parts; + } + const { pre, body, post } = m; + const p = pre.split(','); + p[0] = carry + p[0]; + p[p.length - 1] += '{' + body + '}'; + if (!post.length) { + pushAll(parts, p); + return parts; + } + carry = p.pop(); + pushAll(parts, p); + str = post; } - const { pre, body, post } = m; - const p = pre.split(','); - p[p.length - 1] += '{' + body + '}'; - const postParts = parseCommaParts(post); - if (post.length) { - ; - p[p.length - 1] += postParts.shift(); - p.push.apply(p, postParts); - } - parts.push.apply(parts, p); - return parts; } export function expand(str, options = {}) { if (!str) { return []; } - const { max = EXPANSION_MAX, maxLength = EXPANSION_MAX_LENGTH } = options; + const { max = EXPANSION_MAX, maxLength = EXPANSION_MAX_LENGTH, maxDepth = EXPANSION_MAX_DEPTH, maxRewrites = EXPANSION_MAX_REWRITES, } = options; // I don't know why Bash 4.3 does this, but it does. // Anything starting with {} will have the first two bytes preserved // but *only* at the top level, so {},a}b will not expand to anything, @@ -85,7 +118,7 @@ export function expand(str, options = {}) { if (str.slice(0, 2) === '{}') { str = '\\{\\}' + str.slice(2); } - return expand_(escapeBraces(str), max, maxLength, true).map(unescapeBraces); + return expand_(escapeBraces(str), max, maxLength, maxDepth, 0, maxRewrites, true).map(unescapeBraces); } function embrace(str) { return '{' + str + '}'; @@ -180,7 +213,13 @@ function expandSequence(body, isAlphaSequence, max, maxLength) { } return N; } -function expand_(str, max, maxLength, isTop) { +function expand_(str, max, maxLength, maxDepth, depth, maxRewrites, isTop) { + // Too deeply nested to keep following: treat the rest as literal, the same + // way a group that cannot expand is already handled. Truncating rather than + // throwing keeps `expand` total, matching `max` and `maxLength`. + if (depth > maxDepth) { + return [str]; + } // Consume the string's top-level brace groups left to right, threading a // running set of combined prefixes (`acc`). Expanding the tail iteratively - // rather than recursing on `m.post` once per group - keeps the native stack @@ -192,6 +231,9 @@ function expand_(str, max, maxLength, isTop) { // comma set - a sequence like `{a..\}` may legitimately yield ''. The drop // is on the final strings, so it is applied to whichever `combine` produces // them (the one with no brace set left in the tail). + // How many times the `{a},b}` rewrite below has restarted the scan. Each pass + // re-reads the whole string, so leaving this unbounded is quadratic. + let rewrites = 0; let dropEmpties = false; let firstGroup = true; for (;;) { @@ -216,7 +258,8 @@ function expand_(str, max, maxLength, isTop) { const isOptions = m.body.indexOf(',') >= 0; if (!isSequence && !isOptions) { // {a},b} - if (m.post.match(/,(?!,).*\}/)) { + if (rewrites < maxRewrites && m.post.match(/,(?!,).*\}/)) { + rewrites++; str = m.pre + '{' + m.body + escClose + m.post; isTop = true; continue; @@ -236,7 +279,7 @@ function expand_(str, max, maxLength, isTop) { let n = parseCommaParts(m.body); if (n.length === 1 && n[0] !== undefined) { // x{{a,b}}y ==> x{a}y x{b}y - n = expand_(n[0], max, maxLength, false).map(embrace); + n = expand_(n[0], max, maxLength, maxDepth, depth + 1, maxRewrites, false).map(embrace); //XXX is this necessary? Can't seem to hit it in tests. /* c8 ignore start */ if (n.length === 1) { @@ -262,12 +305,13 @@ function expand_(str, max, maxLength, isTop) { values = []; let valuesLength = 0; outer: for (let j = 0; j < n.length; j++) { - const expanded = expand_(n[j], max, maxLength, false); + const expanded = expand_(n[j], max, maxLength, maxDepth, depth + 1, maxRewrites, false); for (let k = 0; k < expanded.length; k++) { const v = expanded[k]; if (dropsEmpties && !v) continue; - if (values.length >= max || valuesLength + v.length > maxLength) { + if (values.length >= max || + valuesLength + v.length > maxLength) { break outer; } values.push(v); diff --git a/node_modules/brace-expansion/dist/esm/index.js.map b/node_modules/brace-expansion/dist/esm/index.js.map index 17b5e434..28919351 100644 --- a/node_modules/brace-expansion/dist/esm/index.js.map +++ b/node_modules/brace-expansion/dist/esm/index.js.map @@ -1 +1 @@ -{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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","sourcesContent":["import { balanced } from 'balanced-match'\n\nconst escSlash = '\\0SLASH' + Math.random() + '\\0'\nconst escOpen = '\\0OPEN' + Math.random() + '\\0'\nconst escClose = '\\0CLOSE' + Math.random() + '\\0'\nconst escComma = '\\0COMMA' + Math.random() + '\\0'\nconst escPeriod = '\\0PERIOD' + Math.random() + '\\0'\nconst escSlashPattern = new RegExp(escSlash, 'g')\nconst escOpenPattern = new RegExp(escOpen, 'g')\nconst escClosePattern = new RegExp(escClose, 'g')\nconst escCommaPattern = new RegExp(escComma, 'g')\nconst escPeriodPattern = new RegExp(escPeriod, 'g')\nconst slashPattern = /\\\\\\\\/g\nconst openPattern = /\\\\{/g\nconst closePattern = /\\\\}/g\nconst commaPattern = /\\\\,/g\nconst periodPattern = /\\\\\\./g\n\nexport const EXPANSION_MAX = 100_000\n\n// `EXPANSION_MAX` caps the *number* of expansions, but not their length. An\n// input like `'{a,b}'.repeat(1500)` stays under that count - its output is\n// truncated to 100k results - while making every result ~1500 characters\n// long. The result set, and the intermediate arrays built while combining\n// brace sets, then grow large enough to exhaust memory and crash the process\n// (CVE-2026-14257). `EXPANSION_MAX_LENGTH` bounds the total number of\n// characters the accumulator may hold at any point, so memory stays flat no\n// matter how many brace groups are chained. The limit sits well above any\n// realistic expansion (100k results hitting `EXPANSION_MAX` measure ~1M\n// characters) so legitimate input is unaffected.\nexport const EXPANSION_MAX_LENGTH = 4_000_000\n\nfunction numeric(str: string) {\n return !isNaN(str as any) ? parseInt(str, 10) : str.charCodeAt(0)\n}\n\nfunction escapeBraces(str: string) {\n return str\n .replace(slashPattern, escSlash)\n .replace(openPattern, escOpen)\n .replace(closePattern, escClose)\n .replace(commaPattern, escComma)\n .replace(periodPattern, escPeriod)\n}\n\nfunction unescapeBraces(str: string) {\n return str\n .replace(escSlashPattern, '\\\\')\n .replace(escOpenPattern, '{')\n .replace(escClosePattern, '}')\n .replace(escCommaPattern, ',')\n .replace(escPeriodPattern, '.')\n}\n\n/**\n * Basically just str.split(\",\"), but handling cases\n * where we have nested braced sections, which should be\n * treated as individual members, like {a,{b,c},d}\n */\nfunction parseCommaParts(str: string) {\n if (!str) {\n return ['']\n }\n\n const parts: string[] = []\n const m = balanced('{', '}', str)\n\n if (!m) {\n return str.split(',')\n }\n\n const { pre, body, post } = m\n const p = pre.split(',')\n\n p[p.length - 1] += '{' + body + '}'\n const postParts = parseCommaParts(post)\n if (post.length) {\n ;(p[p.length - 1] as string) += postParts.shift()\n p.push.apply(p, postParts)\n }\n\n parts.push.apply(parts, p)\n\n return parts\n}\n\nexport type BraceExpansionOptions = {\n max?: number\n maxLength?: number\n}\n\nexport function expand(str: string, options: BraceExpansionOptions = {}) {\n if (!str) {\n return []\n }\n\n const { max = EXPANSION_MAX, maxLength = EXPANSION_MAX_LENGTH } = options\n\n // I don't know why Bash 4.3 does this, but it does.\n // Anything starting with {} will have the first two bytes preserved\n // but *only* at the top level, so {},a}b will not expand to anything,\n // but a{},b}c will be expanded to [a}c,abc].\n // One could argue that this is a bug in Bash, but since the goal of\n // this module is to match Bash's rules, we escape a leading {}\n if (str.slice(0, 2) === '{}') {\n str = '\\\\{\\\\}' + str.slice(2)\n }\n\n return expand_(escapeBraces(str), max, maxLength, true).map(unescapeBraces)\n}\n\nfunction embrace(str: string) {\n return '{' + str + '}'\n}\n\nfunction isPadded(el: string) {\n return /^-?0\\d/.test(el)\n}\n\nfunction lte(i: number, y: number) {\n return i <= y\n}\n\nfunction gte(i: number, y: number) {\n return i >= y\n}\n\n// Build `{ acc[a] + pre + values[v] }` for every combination, capping the\n// number of results at `max` and the total number of characters at `maxLength`.\n// This is the one place output grows, so bounding it here keeps the single\n// accumulator - and therefore memory - flat regardless of how many brace groups\n// are combined (CVE-2026-14257).\nfunction combine(\n acc: string[],\n pre: string,\n values: string[],\n max: number,\n maxLength: number,\n dropEmpties: boolean,\n): string[] {\n const out: string[] = []\n let length = 0\n for (let a = 0; a < acc.length; a++) {\n for (let v = 0; v < values.length; v++) {\n if (out.length >= max) return out\n const expansion = (acc[a] as string) + pre + values[v]\n // Bash drops empty results at the top level. Skip them before they count\n // against `max`, so `max` bounds the number of *kept* results.\n if (dropEmpties && !expansion) continue\n if (length + expansion.length > maxLength) return out\n out.push(expansion)\n length += expansion.length\n }\n }\n return out\n}\n\n// The expansion values of a single numeric (`1..5`) or alphabetic (`a..e..2`)\n// sequence body.\nfunction expandSequence(\n body: string,\n isAlphaSequence: boolean,\n max: number,\n maxLength: number,\n): string[] {\n const n = body.split(/\\.\\./)\n const N: string[] = []\n // A sequence body always splits into two or three parts, but the compiler\n // can't know that.\n /* c8 ignore start */\n if (n[0] === undefined || n[1] === undefined) {\n return N\n }\n /* c8 ignore stop */\n const x = numeric(n[0])\n const y = numeric(n[1])\n const width = Math.max(n[0].length, n[1].length)\n let incr =\n n.length === 3 && n[2] !== undefined ?\n Math.max(Math.abs(numeric(n[2])), 1)\n : 1\n let test = lte\n const reverse = y < x\n if (reverse) {\n incr *= -1\n test = gte\n }\n const pad = n.some(isPadded)\n\n let length = 0\n for (let i = x; test(i, y) && N.length < max; i += incr) {\n let c\n if (isAlphaSequence) {\n c = String.fromCharCode(i)\n if (c === '\\\\') {\n c = ''\n }\n } else {\n c = String(i)\n if (pad) {\n const need = width - c.length\n if (need > 0) {\n const z = new Array(need + 1).join('0')\n if (i < 0) {\n c = '-' + z + c.slice(1)\n } else {\n c = z + c\n }\n }\n }\n }\n if (length + c.length > maxLength) break\n N.push(c)\n length += c.length\n }\n return N\n}\n\nfunction expand_(\n str: string,\n max: number,\n maxLength: number,\n isTop: boolean,\n): string[] {\n // Consume the string's top-level brace groups left to right, threading a\n // running set of combined prefixes (`acc`). Expanding the tail iteratively -\n // rather than recursing on `m.post` once per group - keeps the native stack\n // depth constant, so deeply chained input (`'{a,b}'.repeat(3000)`) can no\n // longer overflow the stack, and leaves a single accumulator whose size\n // `maxLength` bounds directly (CVE-2026-14257).\n let acc: string[] = ['']\n\n // Bash drops empty results, but only when the *first* top-level group is a\n // comma set - a sequence like `{a..\\}` may legitimately yield ''. The drop\n // is on the final strings, so it is applied to whichever `combine` produces\n // them (the one with no brace set left in the tail).\n let dropEmpties = false\n let firstGroup = true\n\n for (;;) {\n const m = balanced('{', '}', str)\n\n // No brace set left: the rest of the string is literal.\n if (!m) {\n return combine(acc, str, [''], max, maxLength, dropEmpties)\n }\n\n // no need to expand pre, since it is guaranteed to be free of brace-sets\n const pre = m.pre\n\n if (/\\$$/.test(pre)) {\n acc = combine(\n acc,\n pre + '{' + m.body + '}',\n [''],\n max,\n maxLength,\n dropEmpties && !m.post.length,\n )\n firstGroup = false\n if (!m.post.length) break\n str = m.post\n continue\n }\n\n const isNumericSequence = /^-?\\d+\\.\\.-?\\d+(?:\\.\\.-?\\d+)?$/.test(m.body)\n const isAlphaSequence = /^[a-zA-Z]\\.\\.[a-zA-Z](?:\\.\\.-?\\d+)?$/.test(\n m.body,\n )\n const isSequence = isNumericSequence || isAlphaSequence\n const isOptions = m.body.indexOf(',') >= 0\n if (!isSequence && !isOptions) {\n // {a},b}\n if (m.post.match(/,(?!,).*\\}/)) {\n str = m.pre + '{' + m.body + escClose + m.post\n isTop = true\n continue\n }\n // Nothing here expands, so the whole remaining string is literal.\n return combine(\n acc,\n pre + '{' + m.body + '}' + m.post,\n [''],\n max,\n maxLength,\n dropEmpties,\n )\n }\n\n if (firstGroup) {\n dropEmpties = isTop && !isSequence\n firstGroup = false\n }\n\n let values: string[]\n if (isSequence) {\n values = expandSequence(m.body, isAlphaSequence, max, maxLength)\n } else {\n let n = parseCommaParts(m.body)\n if (n.length === 1 && n[0] !== undefined) {\n // x{{a,b}}y ==> x{a}y x{b}y\n n = expand_(n[0], max, maxLength, false).map(embrace)\n //XXX is this necessary? Can't seem to hit it in tests.\n /* c8 ignore start */\n if (n.length === 1) {\n acc = combine(\n acc,\n pre + n[0],\n [''],\n max,\n maxLength,\n dropEmpties && !m.post.length,\n )\n if (!m.post.length) break\n str = m.post\n continue\n }\n /* c8 ignore stop */\n }\n\n // Values that `combine` is going to drop as empty produce no result, so\n // they must not count against `max` - otherwise `{a,,b}` with `max: 2`\n // would stop at `['a', '']` and yield one result instead of two. Skipping\n // them outright keeps `values` bounded while leaving `max` a bound on\n // *kept* results.\n let dropsEmpties = dropEmpties && !m.post.length && !pre\n for (let d = 0; dropsEmpties && d < acc.length; d++) {\n if (acc[d]) {\n dropsEmpties = false\n }\n }\n\n values = []\n let valuesLength = 0\n outer: for (let j = 0; j < n.length; j++) {\n const expanded = expand_(n[j] as string, max, maxLength, false)\n for (let k = 0; k < expanded.length; k++) {\n const v = expanded[k] as string\n if (dropsEmpties && !v) continue\n if (values.length >= max || valuesLength + v.length > maxLength) {\n break outer\n }\n values.push(v)\n valuesLength += v.length\n }\n }\n }\n\n acc = combine(acc, pre, values, max, maxLength, dropEmpties && !m.post.length)\n if (!m.post.length) break\n str = m.post\n }\n\n return acc\n}\n"]} \ No newline at end of file +{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAEzC,MAAM,QAAQ,GAAG,SAAS,GAAG,IAAI,CAAC,MAAM,EAAE,GAAG,IAAI,CAAA;AACjD,MAAM,OAAO,GAAG,QAAQ,GAAG,IAAI,CAAC,MAAM,EAAE,GAAG,IAAI,CAAA;AAC/C,MAAM,QAAQ,GAAG,SAAS,GAAG,IAAI,CAAC,MAAM,EAAE,GAAG,IAAI,CAAA;AACjD,MAAM,QAAQ,GAAG,SAAS,GAAG,IAAI,CAAC,MAAM,EAAE,GAAG,IAAI,CAAA;AACjD,MAAM,SAAS,GAAG,UAAU,GAAG,IAAI,CAAC,MAAM,EAAE,GAAG,IAAI,CAAA;AACnD,MAAM,eAAe,GAAG,IAAI,MAAM,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAA;AACjD,MAAM,cAAc,GAAG,IAAI,MAAM,CAAC,OAAO,EAAE,GAAG,CAAC,CAAA;AAC/C,MAAM,eAAe,GAAG,IAAI,MAAM,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAA;AACjD,MAAM,eAAe,GAAG,IAAI,MAAM,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAA;AACjD,MAAM,gBAAgB,GAAG,IAAI,MAAM,CAAC,SAAS,EAAE,GAAG,CAAC,CAAA;AACnD,MAAM,YAAY,GAAG,OAAO,CAAA;AAC5B,MAAM,WAAW,GAAG,MAAM,CAAA;AAC1B,MAAM,YAAY,GAAG,MAAM,CAAA;AAC3B,MAAM,YAAY,GAAG,MAAM,CAAA;AAC3B,MAAM,aAAa,GAAG,OAAO,CAAA;AAE7B,MAAM,CAAC,MAAM,aAAa,GAAG,OAAO,CAAA;AAEpC,4EAA4E;AAC5E,2EAA2E;AAC3E,yEAAyE;AACzE,0EAA0E;AAC1E,6EAA6E;AAC7E,sEAAsE;AACtE,4EAA4E;AAC5E,0EAA0E;AAC1E,wEAAwE;AACxE,iDAAiD;AACjD,MAAM,CAAC,MAAM,oBAAoB,GAAG,SAAS,CAAA;AAE7C,+EAA+E;AAC/E,8EAA8E;AAC9E,+EAA+E;AAC/E,4EAA4E;AAC5E,gFAAgF;AAChF,4EAA4E;AAC5E,8EAA8E;AAC9E,yCAAyC;AACzC,MAAM,CAAC,MAAM,mBAAmB,GAAG,KAAK,CAAA;AAExC,+EAA+E;AAC/E,8EAA8E;AAC9E,+EAA+E;AAC/E,8EAA8E;AAC9E,4EAA4E;AAC5E,yEAAyE;AACzE,2EAA2E;AAC3E,mEAAmE;AACnE,MAAM,CAAC,MAAM,sBAAsB,GAAG,KAAK,CAAA;AAE3C,SAAS,OAAO,CAAC,GAAW;IAC1B,OAAO,CAAC,KAAK,CAAC,GAAU,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,CAAA;AACnE,CAAC;AAED,SAAS,YAAY,CAAC,GAAW;IAC/B,OAAO,GAAG;SACP,OAAO,CAAC,YAAY,EAAE,QAAQ,CAAC;SAC/B,OAAO,CAAC,WAAW,EAAE,OAAO,CAAC;SAC7B,OAAO,CAAC,YAAY,EAAE,QAAQ,CAAC;SAC/B,OAAO,CAAC,YAAY,EAAE,QAAQ,CAAC;SAC/B,OAAO,CAAC,aAAa,EAAE,SAAS,CAAC,CAAA;AACtC,CAAC;AAED,SAAS,cAAc,CAAC,GAAW;IACjC,OAAO,GAAG;SACP,OAAO,CAAC,eAAe,EAAE,IAAI,CAAC;SAC9B,OAAO,CAAC,cAAc,EAAE,GAAG,CAAC;SAC5B,OAAO,CAAC,eAAe,EAAE,GAAG,CAAC;SAC7B,OAAO,CAAC,eAAe,EAAE,GAAG,CAAC;SAC7B,OAAO,CAAC,gBAAgB,EAAE,GAAG,CAAC,CAAA;AACnC,CAAC;AAED,8DAA8D;AAC9D,SAAS,OAAO,CAAC,MAAgB,EAAE,KAAe;IAChD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAW,CAAC,CAAA;IACjC,CAAC;AACH,CAAC;AAED;;;;GAIG;AACH,SAAS,eAAe,CAAC,GAAW;IAClC,MAAM,KAAK,GAAa,EAAE,CAAA;IAE1B,8EAA8E;IAC9E,oEAAoE;IACpE,8EAA8E;IAC9E,4DAA4D;IAC5D,EAAE;IACF,oCAAoC;IACpC,IAAI,KAAK,GAAG,EAAE,CAAA;IAEd,SAAS,CAAC;QACR,MAAM,CAAC,GAAG,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAA;QAEjC,IAAI,CAAC,CAAC,EAAE,CAAC;YACP,MAAM,IAAI,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;YAC3B,IAAI,CAAC,CAAC,CAAC,GAAG,KAAK,GAAI,IAAI,CAAC,CAAC,CAAY,CAAA;YACrC,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,CAAA;YACpB,OAAO,KAAK,CAAA;QACd,CAAC;QAED,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,GAAG,CAAC,CAAA;QAC7B,MAAM,CAAC,GAAG,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;QACxB,CAAC,CAAC,CAAC,CAAC,GAAG,KAAK,GAAI,CAAC,CAAC,CAAC,CAAY,CAAA;QAC/B,CAAC,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,GAAG,GAAG,IAAI,GAAG,GAAG,CAAA;QAEnC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;YACjB,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC,CAAA;YACjB,OAAO,KAAK,CAAA;QACd,CAAC;QAED,KAAK,GAAG,CAAC,CAAC,GAAG,EAAY,CAAA;QACzB,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC,CAAA;QACjB,GAAG,GAAG,IAAI,CAAA;IACZ,CAAC;AACH,CAAC;AASD,MAAM,UAAU,MAAM,CAAC,GAAW,EAAE,UAAiC,EAAE;IACrE,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,OAAO,EAAE,CAAA;IACX,CAAC;IAED,MAAM,EACJ,GAAG,GAAG,aAAa,EACnB,SAAS,GAAG,oBAAoB,EAChC,QAAQ,GAAG,mBAAmB,EAC9B,WAAW,GAAG,sBAAsB,GACrC,GAAG,OAAO,CAAA;IAEX,oDAAoD;IACpD,oEAAoE;IACpE,sEAAsE;IACtE,6CAA6C;IAC7C,oEAAoE;IACpE,+DAA+D;IAC/D,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,IAAI,EAAE,CAAC;QAC7B,GAAG,GAAG,QAAQ,GAAG,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;IAC/B,CAAC;IAED,OAAO,OAAO,CACZ,YAAY,CAAC,GAAG,CAAC,EACjB,GAAG,EACH,SAAS,EACT,QAAQ,EACR,CAAC,EACD,WAAW,EACX,IAAI,CACL,CAAC,GAAG,CAAC,cAAc,CAAC,CAAA;AACvB,CAAC;AAED,SAAS,OAAO,CAAC,GAAW;IAC1B,OAAO,GAAG,GAAG,GAAG,GAAG,GAAG,CAAA;AACxB,CAAC;AAED,SAAS,QAAQ,CAAC,EAAU;IAC1B,OAAO,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;AAC1B,CAAC;AAED,SAAS,GAAG,CAAC,CAAS,EAAE,CAAS;IAC/B,OAAO,CAAC,IAAI,CAAC,CAAA;AACf,CAAC;AAED,SAAS,GAAG,CAAC,CAAS,EAAE,CAAS;IAC/B,OAAO,CAAC,IAAI,CAAC,CAAA;AACf,CAAC;AAED,0EAA0E;AAC1E,gFAAgF;AAChF,2EAA2E;AAC3E,gFAAgF;AAChF,iCAAiC;AACjC,SAAS,OAAO,CACd,GAAa,EACb,GAAW,EACX,MAAgB,EAChB,GAAW,EACX,SAAiB,EACjB,WAAoB;IAEpB,MAAM,GAAG,GAAa,EAAE,CAAA;IACxB,IAAI,MAAM,GAAG,CAAC,CAAA;IACd,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACpC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACvC,IAAI,GAAG,CAAC,MAAM,IAAI,GAAG;gBAAE,OAAO,GAAG,CAAA;YACjC,MAAM,SAAS,GAAI,GAAG,CAAC,CAAC,CAAY,GAAG,GAAG,GAAG,MAAM,CAAC,CAAC,CAAC,CAAA;YACtD,yEAAyE;YACzE,+DAA+D;YAC/D,IAAI,WAAW,IAAI,CAAC,SAAS;gBAAE,SAAQ;YACvC,IAAI,MAAM,GAAG,SAAS,CAAC,MAAM,GAAG,SAAS;gBAAE,OAAO,GAAG,CAAA;YACrD,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;YACnB,MAAM,IAAI,SAAS,CAAC,MAAM,CAAA;QAC5B,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAA;AACZ,CAAC;AAED,8EAA8E;AAC9E,iBAAiB;AACjB,SAAS,cAAc,CACrB,IAAY,EACZ,eAAwB,EACxB,GAAW,EACX,SAAiB;IAEjB,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAA;IAC5B,MAAM,CAAC,GAAa,EAAE,CAAA;IACtB,0EAA0E;IAC1E,mBAAmB;IACnB,qBAAqB;IACrB,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,SAAS,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,SAAS,EAAE,CAAC;QAC7C,OAAO,CAAC,CAAA;IACV,CAAC;IACD,oBAAoB;IACpB,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;IACvB,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAA;IACvB,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAA;IAChD,IAAI,IAAI,GACN,CAAC,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC;QACpC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QACtC,CAAC,CAAC,CAAC,CAAA;IACL,IAAI,IAAI,GAAG,GAAG,CAAA;IACd,MAAM,OAAO,GAAG,CAAC,GAAG,CAAC,CAAA;IACrB,IAAI,OAAO,EAAE,CAAC;QACZ,IAAI,IAAI,CAAC,CAAC,CAAA;QACV,IAAI,GAAG,GAAG,CAAA;IACZ,CAAC;IACD,MAAM,GAAG,GAAG,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;IAE5B,IAAI,MAAM,GAAG,CAAC,CAAA;IACd,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,GAAG,GAAG,EAAE,CAAC,IAAI,IAAI,EAAE,CAAC;QACxD,IAAI,CAAC,CAAA;QACL,IAAI,eAAe,EAAE,CAAC;YACpB,CAAC,GAAG,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,CAAA;YAC1B,IAAI,CAAC,KAAK,IAAI,EAAE,CAAC;gBACf,CAAC,GAAG,EAAE,CAAA;YACR,CAAC;QACH,CAAC;aAAM,CAAC;YACN,CAAC,GAAG,MAAM,CAAC,CAAC,CAAC,CAAA;YACb,IAAI,GAAG,EAAE,CAAC;gBACR,MAAM,IAAI,GAAG,KAAK,GAAG,CAAC,CAAC,MAAM,CAAA;gBAC7B,IAAI,IAAI,GAAG,CAAC,EAAE,CAAC;oBACb,MAAM,CAAC,GAAG,IAAI,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;oBACvC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;wBACV,CAAC,GAAG,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAA;oBAC1B,CAAC;yBAAM,CAAC;wBACN,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;oBACX,CAAC;gBACH,CAAC;YACH,CAAC;QACH,CAAC;QACD,IAAI,MAAM,GAAG,CAAC,CAAC,MAAM,GAAG,SAAS;YAAE,MAAK;QACxC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;QACT,MAAM,IAAI,CAAC,CAAC,MAAM,CAAA;IACpB,CAAC;IACD,OAAO,CAAC,CAAA;AACV,CAAC;AAED,SAAS,OAAO,CACd,GAAW,EACX,GAAW,EACX,SAAiB,EACjB,QAAgB,EAChB,KAAa,EACb,WAAmB,EACnB,KAAc;IAEd,2EAA2E;IAC3E,4EAA4E;IAC5E,iEAAiE;IACjE,IAAI,KAAK,GAAG,QAAQ,EAAE,CAAC;QACrB,OAAO,CAAC,GAAG,CAAC,CAAA;IACd,CAAC;IAED,yEAAyE;IACzE,6EAA6E;IAC7E,4EAA4E;IAC5E,0EAA0E;IAC1E,wEAAwE;IACxE,gDAAgD;IAChD,IAAI,GAAG,GAAa,CAAC,EAAE,CAAC,CAAA;IAExB,2EAA2E;IAC3E,2EAA2E;IAC3E,4EAA4E;IAC5E,qDAAqD;IACrD,8EAA8E;IAC9E,qEAAqE;IACrE,IAAI,QAAQ,GAAG,CAAC,CAAA;IAChB,IAAI,WAAW,GAAG,KAAK,CAAA;IACvB,IAAI,UAAU,GAAG,IAAI,CAAA;IAErB,SAAS,CAAC;QACR,MAAM,CAAC,GAAG,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,CAAA;QAEjC,wDAAwD;QACxD,IAAI,CAAC,CAAC,EAAE,CAAC;YACP,OAAO,OAAO,CAAC,GAAG,EAAE,GAAG,EAAE,CAAC,EAAE,CAAC,EAAE,GAAG,EAAE,SAAS,EAAE,WAAW,CAAC,CAAA;QAC7D,CAAC;QAED,yEAAyE;QACzE,MAAM,GAAG,GAAG,CAAC,CAAC,GAAG,CAAA;QAEjB,IAAI,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;YACpB,GAAG,GAAG,OAAO,CACX,GAAG,EACH,GAAG,GAAG,GAAG,GAAG,CAAC,CAAC,IAAI,GAAG,GAAG,EACxB,CAAC,EAAE,CAAC,EACJ,GAAG,EACH,SAAS,EACT,WAAW,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAC9B,CAAA;YACD,UAAU,GAAG,KAAK,CAAA;YAClB,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM;gBAAE,MAAK;YACzB,GAAG,GAAG,CAAC,CAAC,IAAI,CAAA;YACZ,SAAQ;QACV,CAAC;QAED,MAAM,iBAAiB,GAAG,gCAAgC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,CAAA;QACvE,MAAM,eAAe,GAAG,sCAAsC,CAAC,IAAI,CACjE,CAAC,CAAC,IAAI,CACP,CAAA;QACD,MAAM,UAAU,GAAG,iBAAiB,IAAI,eAAe,CAAA;QACvD,MAAM,SAAS,GAAG,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;QAC1C,IAAI,CAAC,UAAU,IAAI,CAAC,SAAS,EAAE,CAAC;YAC9B,SAAS;YACT,IAAI,QAAQ,GAAG,WAAW,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,EAAE,CAAC;gBACzD,QAAQ,EAAE,CAAA;gBACV,GAAG,GAAG,CAAC,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,CAAC,IAAI,GAAG,QAAQ,GAAG,CAAC,CAAC,IAAI,CAAA;gBAC9C,KAAK,GAAG,IAAI,CAAA;gBACZ,SAAQ;YACV,CAAC;YACD,kEAAkE;YAClE,OAAO,OAAO,CACZ,GAAG,EACH,GAAG,GAAG,GAAG,GAAG,CAAC,CAAC,IAAI,GAAG,GAAG,GAAG,CAAC,CAAC,IAAI,EACjC,CAAC,EAAE,CAAC,EACJ,GAAG,EACH,SAAS,EACT,WAAW,CACZ,CAAA;QACH,CAAC;QAED,IAAI,UAAU,EAAE,CAAC;YACf,WAAW,GAAG,KAAK,IAAI,CAAC,UAAU,CAAA;YAClC,UAAU,GAAG,KAAK,CAAA;QACpB,CAAC;QAED,IAAI,MAAgB,CAAA;QACpB,IAAI,UAAU,EAAE,CAAC;YACf,MAAM,GAAG,cAAc,CAAC,CAAC,CAAC,IAAI,EAAE,eAAe,EAAE,GAAG,EAAE,SAAS,CAAC,CAAA;QAClE,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,GAAG,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC,CAAA;YAC/B,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,SAAS,EAAE,CAAC;gBACzC,4BAA4B;gBAC5B,CAAC,GAAG,OAAO,CACT,CAAC,CAAC,CAAC,CAAC,EACJ,GAAG,EACH,SAAS,EACT,QAAQ,EACR,KAAK,GAAG,CAAC,EACT,WAAW,EACX,KAAK,CACN,CAAC,GAAG,CAAC,OAAO,CAAC,CAAA;gBACd,uDAAuD;gBACvD,qBAAqB;gBACrB,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;oBACnB,GAAG,GAAG,OAAO,CACX,GAAG,EACH,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC,EACV,CAAC,EAAE,CAAC,EACJ,GAAG,EACH,SAAS,EACT,WAAW,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAC9B,CAAA;oBACD,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM;wBAAE,MAAK;oBACzB,GAAG,GAAG,CAAC,CAAC,IAAI,CAAA;oBACZ,SAAQ;gBACV,CAAC;gBACD,oBAAoB;YACtB,CAAC;YAED,wEAAwE;YACxE,uEAAuE;YACvE,0EAA0E;YAC1E,sEAAsE;YACtE,kBAAkB;YAClB,IAAI,YAAY,GAAG,WAAW,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,IAAI,CAAC,GAAG,CAAA;YACxD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,YAAY,IAAI,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBACpD,IAAI,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;oBACX,YAAY,GAAG,KAAK,CAAA;gBACtB,CAAC;YACH,CAAC;YAED,MAAM,GAAG,EAAE,CAAA;YACX,IAAI,YAAY,GAAG,CAAC,CAAA;YACpB,KAAK,EAAE,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;gBACzC,MAAM,QAAQ,GAAG,OAAO,CACtB,CAAC,CAAC,CAAC,CAAW,EACd,GAAG,EACH,SAAS,EACT,QAAQ,EACR,KAAK,GAAG,CAAC,EACT,WAAW,EACX,KAAK,CACN,CAAA;gBACD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;oBACzC,MAAM,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAW,CAAA;oBAC/B,IAAI,YAAY,IAAI,CAAC,CAAC;wBAAE,SAAQ;oBAChC,IACE,MAAM,CAAC,MAAM,IAAI,GAAG;wBACpB,YAAY,GAAG,CAAC,CAAC,MAAM,GAAG,SAAS,EACnC,CAAC;wBACD,MAAM,KAAK,CAAA;oBACb,CAAC;oBACD,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;oBACd,YAAY,IAAI,CAAC,CAAC,MAAM,CAAA;gBAC1B,CAAC;YACH,CAAC;QACH,CAAC;QAED,GAAG,GAAG,OAAO,CACX,GAAG,EACH,GAAG,EACH,MAAM,EACN,GAAG,EACH,SAAS,EACT,WAAW,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAC9B,CAAA;QACD,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM;YAAE,MAAK;QACzB,GAAG,GAAG,CAAC,CAAC,IAAI,CAAA;IACd,CAAC;IAED,OAAO,GAAG,CAAA;AACZ,CAAC","sourcesContent":["import { balanced } from 'balanced-match'\n\nconst escSlash = '\\0SLASH' + Math.random() + '\\0'\nconst escOpen = '\\0OPEN' + Math.random() + '\\0'\nconst escClose = '\\0CLOSE' + Math.random() + '\\0'\nconst escComma = '\\0COMMA' + Math.random() + '\\0'\nconst escPeriod = '\\0PERIOD' + Math.random() + '\\0'\nconst escSlashPattern = new RegExp(escSlash, 'g')\nconst escOpenPattern = new RegExp(escOpen, 'g')\nconst escClosePattern = new RegExp(escClose, 'g')\nconst escCommaPattern = new RegExp(escComma, 'g')\nconst escPeriodPattern = new RegExp(escPeriod, 'g')\nconst slashPattern = /\\\\\\\\/g\nconst openPattern = /\\\\{/g\nconst closePattern = /\\\\}/g\nconst commaPattern = /\\\\,/g\nconst periodPattern = /\\\\\\./g\n\nexport const EXPANSION_MAX = 100_000\n\n// `EXPANSION_MAX` caps the *number* of expansions, but not their length. An\n// input like `'{a,b}'.repeat(1500)` stays under that count - its output is\n// truncated to 100k results - while making every result ~1500 characters\n// long. The result set, and the intermediate arrays built while combining\n// brace sets, then grow large enough to exhaust memory and crash the process\n// (CVE-2026-14257). `EXPANSION_MAX_LENGTH` bounds the total number of\n// characters the accumulator may hold at any point, so memory stays flat no\n// matter how many brace groups are chained. The limit sits well above any\n// realistic expansion (100k results hitting `EXPANSION_MAX` measure ~1M\n// characters) so legitimate input is unaffected.\nexport const EXPANSION_MAX_LENGTH = 4_000_000\n\n// `expand_` recurses once per level of brace *nesting* - both when expanding a\n// set's comma members and when re-wrapping a set whose body is a single part.\n// The CVE-2026-14257 fix made the *tail* iterative (recursion on `m.post`, one\n// level per chained group), which left nesting depth unbounded: about 3,100\n// levels of `{{{...a,b...}}}` - only ~6KB of input - exhausted the native stack\n// and crashed the process. `EXPANSION_MAX_DEPTH` bounds how deep the parser\n// will follow nesting. It sits far above any realistic pattern and well below\n// the depth at which the stack runs out.\nexport const EXPANSION_MAX_DEPTH = 1_000\n\n// Bash keeps a quirk where a brace group followed by a comma set still expands\n// (`{a},b}`). The parser implements it by rewriting the string and restarting\n// the scan, absorbing one `}` per pass. `n` trailing braces therefore cost `n`\n// full passes over a string that itself grows by one `escClose` sentinel each\n// time - quadratic in `n`, with a ~26x constant from the sentinel's length.\n// 128KB of `'{a}' + '}'.repeat(n) + ',z}'` blocked the event loop for 27\n// seconds to produce two results. `EXPANSION_MAX_REWRITES` bounds how many\n// times the scan may restart. Real `{a},b}` input needs a handful.\nexport const EXPANSION_MAX_REWRITES = 1_000\n\nfunction numeric(str: string) {\n return !isNaN(str as any) ? parseInt(str, 10) : str.charCodeAt(0)\n}\n\nfunction escapeBraces(str: string) {\n return str\n .replace(slashPattern, escSlash)\n .replace(openPattern, escOpen)\n .replace(closePattern, escClose)\n .replace(commaPattern, escComma)\n .replace(periodPattern, escPeriod)\n}\n\nfunction unescapeBraces(str: string) {\n return str\n .replace(escSlashPattern, '\\\\')\n .replace(escOpenPattern, '{')\n .replace(escClosePattern, '}')\n .replace(escCommaPattern, ',')\n .replace(escPeriodPattern, '.')\n}\n\n// Like `target.push(...items)` but doesn't overflow the stack\nfunction pushAll(target: string[], items: string[]) {\n for (let i = 0; i < items.length; i++) {\n target.push(items[i] as string)\n }\n}\n\n/**\n * Basically just str.split(\",\"), but handling cases\n * where we have nested braced sections, which should be\n * treated as individual members, like {a,{b,c},d}\n */\nfunction parseCommaParts(str: string) {\n const parts: string[] = []\n\n // Walk the brace groups iteratively. Recursing on `post` once per group let a\n // chain of them exhaust the stack - the parsing-side counterpart to\n // the `expand_` overflow fixed for CVE-2026-14257, and not something `max` or\n // `maxLength` can bound, since it happens before expansion.\n //\n // The part the next chunk continues\n let carry = ''\n\n for (;;) {\n const m = balanced('{', '}', str)\n\n if (!m) {\n const tail = str.split(',')\n tail[0] = carry + (tail[0] as string)\n pushAll(parts, tail)\n return parts\n }\n\n const { pre, body, post } = m\n const p = pre.split(',')\n p[0] = carry + (p[0] as string)\n p[p.length - 1] += '{' + body + '}'\n\n if (!post.length) {\n pushAll(parts, p)\n return parts\n }\n\n carry = p.pop() as string\n pushAll(parts, p)\n str = post\n }\n}\n\nexport type BraceExpansionOptions = {\n max?: number\n maxLength?: number\n maxDepth?: number\n maxRewrites?: number\n}\n\nexport function expand(str: string, options: BraceExpansionOptions = {}) {\n if (!str) {\n return []\n }\n\n const {\n max = EXPANSION_MAX,\n maxLength = EXPANSION_MAX_LENGTH,\n maxDepth = EXPANSION_MAX_DEPTH,\n maxRewrites = EXPANSION_MAX_REWRITES,\n } = options\n\n // I don't know why Bash 4.3 does this, but it does.\n // Anything starting with {} will have the first two bytes preserved\n // but *only* at the top level, so {},a}b will not expand to anything,\n // but a{},b}c will be expanded to [a}c,abc].\n // One could argue that this is a bug in Bash, but since the goal of\n // this module is to match Bash's rules, we escape a leading {}\n if (str.slice(0, 2) === '{}') {\n str = '\\\\{\\\\}' + str.slice(2)\n }\n\n return expand_(\n escapeBraces(str),\n max,\n maxLength,\n maxDepth,\n 0,\n maxRewrites,\n true,\n ).map(unescapeBraces)\n}\n\nfunction embrace(str: string) {\n return '{' + str + '}'\n}\n\nfunction isPadded(el: string) {\n return /^-?0\\d/.test(el)\n}\n\nfunction lte(i: number, y: number) {\n return i <= y\n}\n\nfunction gte(i: number, y: number) {\n return i >= y\n}\n\n// Build `{ acc[a] + pre + values[v] }` for every combination, capping the\n// number of results at `max` and the total number of characters at `maxLength`.\n// This is the one place output grows, so bounding it here keeps the single\n// accumulator - and therefore memory - flat regardless of how many brace groups\n// are combined (CVE-2026-14257).\nfunction combine(\n acc: string[],\n pre: string,\n values: string[],\n max: number,\n maxLength: number,\n dropEmpties: boolean,\n): string[] {\n const out: string[] = []\n let length = 0\n for (let a = 0; a < acc.length; a++) {\n for (let v = 0; v < values.length; v++) {\n if (out.length >= max) return out\n const expansion = (acc[a] as string) + pre + values[v]\n // Bash drops empty results at the top level. Skip them before they count\n // against `max`, so `max` bounds the number of *kept* results.\n if (dropEmpties && !expansion) continue\n if (length + expansion.length > maxLength) return out\n out.push(expansion)\n length += expansion.length\n }\n }\n return out\n}\n\n// The expansion values of a single numeric (`1..5`) or alphabetic (`a..e..2`)\n// sequence body.\nfunction expandSequence(\n body: string,\n isAlphaSequence: boolean,\n max: number,\n maxLength: number,\n): string[] {\n const n = body.split(/\\.\\./)\n const N: string[] = []\n // A sequence body always splits into two or three parts, but the compiler\n // can't know that.\n /* c8 ignore start */\n if (n[0] === undefined || n[1] === undefined) {\n return N\n }\n /* c8 ignore stop */\n const x = numeric(n[0])\n const y = numeric(n[1])\n const width = Math.max(n[0].length, n[1].length)\n let incr =\n n.length === 3 && n[2] !== undefined ?\n Math.max(Math.abs(numeric(n[2])), 1)\n : 1\n let test = lte\n const reverse = y < x\n if (reverse) {\n incr *= -1\n test = gte\n }\n const pad = n.some(isPadded)\n\n let length = 0\n for (let i = x; test(i, y) && N.length < max; i += incr) {\n let c\n if (isAlphaSequence) {\n c = String.fromCharCode(i)\n if (c === '\\\\') {\n c = ''\n }\n } else {\n c = String(i)\n if (pad) {\n const need = width - c.length\n if (need > 0) {\n const z = new Array(need + 1).join('0')\n if (i < 0) {\n c = '-' + z + c.slice(1)\n } else {\n c = z + c\n }\n }\n }\n }\n if (length + c.length > maxLength) break\n N.push(c)\n length += c.length\n }\n return N\n}\n\nfunction expand_(\n str: string,\n max: number,\n maxLength: number,\n maxDepth: number,\n depth: number,\n maxRewrites: number,\n isTop: boolean,\n): string[] {\n // Too deeply nested to keep following: treat the rest as literal, the same\n // way a group that cannot expand is already handled. Truncating rather than\n // throwing keeps `expand` total, matching `max` and `maxLength`.\n if (depth > maxDepth) {\n return [str]\n }\n\n // Consume the string's top-level brace groups left to right, threading a\n // running set of combined prefixes (`acc`). Expanding the tail iteratively -\n // rather than recursing on `m.post` once per group - keeps the native stack\n // depth constant, so deeply chained input (`'{a,b}'.repeat(3000)`) can no\n // longer overflow the stack, and leaves a single accumulator whose size\n // `maxLength` bounds directly (CVE-2026-14257).\n let acc: string[] = ['']\n\n // Bash drops empty results, but only when the *first* top-level group is a\n // comma set - a sequence like `{a..\\}` may legitimately yield ''. The drop\n // is on the final strings, so it is applied to whichever `combine` produces\n // them (the one with no brace set left in the tail).\n // How many times the `{a},b}` rewrite below has restarted the scan. Each pass\n // re-reads the whole string, so leaving this unbounded is quadratic.\n let rewrites = 0\n let dropEmpties = false\n let firstGroup = true\n\n for (;;) {\n const m = balanced('{', '}', str)\n\n // No brace set left: the rest of the string is literal.\n if (!m) {\n return combine(acc, str, [''], max, maxLength, dropEmpties)\n }\n\n // no need to expand pre, since it is guaranteed to be free of brace-sets\n const pre = m.pre\n\n if (/\\$$/.test(pre)) {\n acc = combine(\n acc,\n pre + '{' + m.body + '}',\n [''],\n max,\n maxLength,\n dropEmpties && !m.post.length,\n )\n firstGroup = false\n if (!m.post.length) break\n str = m.post\n continue\n }\n\n const isNumericSequence = /^-?\\d+\\.\\.-?\\d+(?:\\.\\.-?\\d+)?$/.test(m.body)\n const isAlphaSequence = /^[a-zA-Z]\\.\\.[a-zA-Z](?:\\.\\.-?\\d+)?$/.test(\n m.body,\n )\n const isSequence = isNumericSequence || isAlphaSequence\n const isOptions = m.body.indexOf(',') >= 0\n if (!isSequence && !isOptions) {\n // {a},b}\n if (rewrites < maxRewrites && m.post.match(/,(?!,).*\\}/)) {\n rewrites++\n str = m.pre + '{' + m.body + escClose + m.post\n isTop = true\n continue\n }\n // Nothing here expands, so the whole remaining string is literal.\n return combine(\n acc,\n pre + '{' + m.body + '}' + m.post,\n [''],\n max,\n maxLength,\n dropEmpties,\n )\n }\n\n if (firstGroup) {\n dropEmpties = isTop && !isSequence\n firstGroup = false\n }\n\n let values: string[]\n if (isSequence) {\n values = expandSequence(m.body, isAlphaSequence, max, maxLength)\n } else {\n let n = parseCommaParts(m.body)\n if (n.length === 1 && n[0] !== undefined) {\n // x{{a,b}}y ==> x{a}y x{b}y\n n = expand_(\n n[0],\n max,\n maxLength,\n maxDepth,\n depth + 1,\n maxRewrites,\n false,\n ).map(embrace)\n //XXX is this necessary? Can't seem to hit it in tests.\n /* c8 ignore start */\n if (n.length === 1) {\n acc = combine(\n acc,\n pre + n[0],\n [''],\n max,\n maxLength,\n dropEmpties && !m.post.length,\n )\n if (!m.post.length) break\n str = m.post\n continue\n }\n /* c8 ignore stop */\n }\n\n // Values that `combine` is going to drop as empty produce no result, so\n // they must not count against `max` - otherwise `{a,,b}` with `max: 2`\n // would stop at `['a', '']` and yield one result instead of two. Skipping\n // them outright keeps `values` bounded while leaving `max` a bound on\n // *kept* results.\n let dropsEmpties = dropEmpties && !m.post.length && !pre\n for (let d = 0; dropsEmpties && d < acc.length; d++) {\n if (acc[d]) {\n dropsEmpties = false\n }\n }\n\n values = []\n let valuesLength = 0\n outer: for (let j = 0; j < n.length; j++) {\n const expanded = expand_(\n n[j] as string,\n max,\n maxLength,\n maxDepth,\n depth + 1,\n maxRewrites,\n false,\n )\n for (let k = 0; k < expanded.length; k++) {\n const v = expanded[k] as string\n if (dropsEmpties && !v) continue\n if (\n values.length >= max ||\n valuesLength + v.length > maxLength\n ) {\n break outer\n }\n values.push(v)\n valuesLength += v.length\n }\n }\n }\n\n acc = combine(\n acc,\n pre,\n values,\n max,\n maxLength,\n dropEmpties && !m.post.length,\n )\n if (!m.post.length) break\n str = m.post\n }\n\n return acc\n}\n"]} \ No newline at end of file diff --git a/node_modules/brace-expansion/package.json b/node_modules/brace-expansion/package.json index 43764007..a5c96ebe 100644 --- a/node_modules/brace-expansion/package.json +++ b/node_modules/brace-expansion/package.json @@ -1,7 +1,7 @@ { "name": "brace-expansion", "description": "Brace expansion as known from sh/bash", - "version": "5.0.9", + "version": "5.0.12", "files": [ "dist" ], @@ -29,6 +29,7 @@ "test": "tap", "snap": "tap", "format": "prettier --write .", + "format:check": "prettier --check .", "benchmark": "node benchmark/index.js", "typedoc": "typedoc --tsconfig .tshy/esm.json ./src/*.ts" }, diff --git a/node_modules/nodemailer/CHANGELOG.md b/node_modules/nodemailer/CHANGELOG.md index b1d1c9cb..3f258d10 100644 --- a/node_modules/nodemailer/CHANGELOG.md +++ b/node_modules/nodemailer/CHANGELOG.md @@ -1,5 +1,16 @@ # CHANGELOG +## [10.0.11](https://github.com/nodemailer/nodemailer/compare/v10.0.10...v10.0.11) (2026-09-27) + + +### Bug Fixes + +* **fetch:** report a form body that can not be encoded through the returned stream ([74d40bf](https://github.com/nodemailer/nodemailer/commit/74d40bf1e4553bc0568b471250a9251bcb569b00)) +* keep the CommonJS entry point and the services subpath compatible with the pre-TypeScript build ([52901ef](https://github.com/nodemailer/nodemailer/commit/52901ef3725ad179aa56276495a60f53b2c83516)) +* **qp:** keep wrap() terminating for short line lengths and a trailing incomplete escape ([8fa140b](https://github.com/nodemailer/nodemailer/commit/8fa140b11c62cb1202eac84d35bb3ba28bc3b1a1)) +* **smtp-connection:** fail a password login cleanly when the server offers only XOAUTH2 ([90abf7d](https://github.com/nodemailer/nodemailer/commit/90abf7d11db5ebfeb4292b62c1fff969741c7d33)) +* **types:** restore the layout of @types/nodemailer in the bundled declarations ([ac2e40f](https://github.com/nodemailer/nodemailer/commit/ac2e40ffc69427e0eb33ce3945fae76c4c828c8d)) + ## [10.0.10](https://github.com/nodemailer/nodemailer/compare/v10.0.9...v10.0.10) (2026-09-14) diff --git a/node_modules/nodemailer/README.md b/node_modules/nodemailer/README.md index b8194387..59c56e6b 100644 --- a/node_modules/nodemailer/README.md +++ b/node_modules/nodemailer/README.md @@ -72,7 +72,7 @@ let configOptions = { #### I have an issue with TypeScript types -Nodemailer 10 and later are written in TypeScript and ship their own type definitions, so `@types/nodemailer` is no longer needed and should be removed from your project to avoid conflicting declarations. The type names follow the layout of the old definitions, so references such as `Mail.Options`, `SMTPTransport.Options` or `Transporter` keep compiling, and the most used types (`SendMailOptions`, `Transporter`, `SentMessageInfo`, `Attachment`, `Address`) are exported from the package root. For older Nodemailer versions, the community maintained [type definitions](https://www.npmjs.com/package/@types/nodemailer) still apply. +Nodemailer 10 and later are written in TypeScript and ship their own type definitions, so `@types/nodemailer` is no longer needed and should be removed from your project to avoid conflicting declarations. The type names follow the layout of the old definitions, so references such as `Mail.Options`, `SMTPTransport.Options` or `Transporter` keep compiling, and the most used types (`SendMailOptions`, `Transporter`, `SentMessageInfo`, `Attachment`, `Address`) are exported from the package root. The modules under `nodemailer/lib/` are declared with a default export, so import a class as `import SMTPTransport from 'nodemailer/lib/smtp-transport'` (with `esModuleInterop` in a CommonJS project). The `import SMTPTransport = require(...)` and `import * as SMTPTransport from ...` forms still resolve the type aliases such as `SMTPTransport.Options`, but they refer to the module rather than to the class, so the class itself has to be imported with a default import. For older Nodemailer versions, the community maintained [type definitions](https://www.npmjs.com/package/@types/nodemailer) still apply. #### I have a different problem diff --git a/node_modules/nodemailer/dist/cjs/addressparser/index.d.ts b/node_modules/nodemailer/dist/cjs/addressparser/index.d.ts index adc98336..583c45b7 100644 --- a/node_modules/nodemailer/dist/cjs/addressparser/index.d.ts +++ b/node_modules/nodemailer/dist/cjs/addressparser/index.d.ts @@ -42,4 +42,19 @@ export type Address = MailboxAddress | GroupAddress; * @param options._depth Internal recursion depth counter (do not set manually) * @return An array of address objects */ -export default function addressparser(str?: string | null, options?: AddressParserOptions): Address[]; +declare function addressparser(str: string | null | undefined, options: AddressParserOptions & { + flatten: true; +}): MailboxAddress[]; +declare function addressparser(str?: string | null, options?: AddressParserOptions): Address[]; +/** + * Type aliases in the layout of @types/nodemailer, so `addressparser.Address` style references keep working + */ +type AddressEntry = Address; +declare namespace addressparser { + type Address = MailboxAddress; + type Group = GroupAddress; + type AddressOrGroup = AddressEntry; +} +/** The names @types/nodemailer used for the group entry and for the union of both entry types */ +export type { GroupAddress as Group, Address as AddressOrGroup }; +export default addressparser; diff --git a/node_modules/nodemailer/dist/cjs/addressparser/index.js b/node_modules/nodemailer/dist/cjs/addressparser/index.js index ae807012..0f71ee1d 100644 --- a/node_modules/nodemailer/dist/cjs/addressparser/index.js +++ b/node_modules/nodemailer/dist/cjs/addressparser/index.js @@ -1,6 +1,5 @@ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); -exports.default = addressparser; /** * Restores the quoting of a local part that was read out of a quoted string. * @@ -583,22 +582,6 @@ class Tokenizer { * malicious input that could cause stack overflow. */ const MAX_NESTED_GROUP_DEPTH = 50; -/** - * Parses structured e-mail addresses from an address field - * - * Example: - * - * 'Name ' - * - * will be converted to - * - * [{name: 'Name', address: 'address@domain'}] - * - * @param str Address field - * @param options Optional options object - * @param options._depth Internal recursion depth counter (do not set manually) - * @return An array of address objects - */ function addressparser(str, options) { options = options || {}; const depth = options._depth || 0; @@ -667,5 +650,6 @@ function addressparser(str, options) { } return parsedAddresses; } +exports.default = addressparser; module.exports = exports.default; Object.defineProperty(module.exports, 'default', { value: exports.default, enumerable: false, writable: true, configurable: true }); diff --git a/node_modules/nodemailer/dist/cjs/base64/index.js b/node_modules/nodemailer/dist/cjs/base64/index.js index 4d5a3887..4e9e2193 100644 --- a/node_modules/nodemailer/dist/cjs/base64/index.js +++ b/node_modules/nodemailer/dist/cjs/base64/index.js @@ -25,7 +25,8 @@ function encode(buffer) { */ function wrap(str, lineLength) { str = (str || '').toString(); - lineLength = lineLength || 76; + // a negative length would step backwards through the input and never finish + lineLength = Math.max(Number(lineLength) || 76, 1); if (str.length <= lineLength) { return str; } diff --git a/node_modules/nodemailer/dist/cjs/dkim/index.d.ts b/node_modules/nodemailer/dist/cjs/dkim/index.d.ts index 78a4b673..dd3df3a6 100644 --- a/node_modules/nodemailer/dist/cjs/dkim/index.d.ts +++ b/node_modules/nodemailer/dist/cjs/dkim/index.d.ts @@ -30,11 +30,23 @@ declare class DKIM { constructor(options: DKIMOptions); sign(input: Readable | Buffer | string, extraOptions?: DKIMOptions): DKIMSignedStream; } +/** The signer options without any key material */ +export type DKIMOptionalOptions = Omit; +/** The signer options for a single key given as domainName, keySelector and privateKey */ +export type DKIMSingleKeyOptions = Omit; +/** The signer options for one or more keys given through `keys` */ +export type DKIMMultipleKeysOptions = DKIMOptionalOptions & { + keys: DKIMKey | DKIMKey[]; +}; /** * Type aliases in the layout of @types/nodemailer, so `DKIM.Options` style references keep working */ declare namespace DKIM { type Options = DKIMOptions; - type SingleKeyOptions = Omit; + type OptionalOptions = DKIMOptionalOptions; + type SingleKeyOptions = DKIMSingleKeyOptions; + type MultipleKeysOptions = DKIMMultipleKeysOptions; } +/** The same aliases as module level exports, for `import * as DKIM` and `import DKIM = require()` */ +export type { DKIMOptions as Options, DKIMOptionalOptions as OptionalOptions, DKIMSingleKeyOptions as SingleKeyOptions, DKIMMultipleKeysOptions as MultipleKeysOptions }; export default DKIM; diff --git a/node_modules/nodemailer/dist/cjs/dkim/message-parser.d.ts b/node_modules/nodemailer/dist/cjs/dkim/message-parser.d.ts index 21e061b1..d17ab5ea 100644 --- a/node_modules/nodemailer/dist/cjs/dkim/message-parser.d.ts +++ b/node_modules/nodemailer/dist/cjs/dkim/message-parser.d.ts @@ -13,7 +13,7 @@ export interface MessageParserHeaderLine { * from the rest of the body. Headers are emitted with the 'headers' event. Message * body is passed on as the resulting stream. */ -export default class MessageParser extends Transform { +declare class MessageParser extends Transform { lastBytes: Buffer; headersParsed: boolean; headerBytes: number; @@ -37,3 +37,12 @@ export default class MessageParser extends Transform { checkHeaders(data: Buffer): boolean; parseHeaders(): MessageParserHeaderLine[]; } +/** + * Type aliases in the layout of @types/nodemailer, so `MessageParser.Header` style references keep working + */ +declare namespace MessageParser { + type Header = MessageParserHeaderLine; +} +/** The same alias as a module level export, for `import * as MessageParser` and `import MessageParser = require()` */ +export type { MessageParserHeaderLine as Header }; +export default MessageParser; diff --git a/node_modules/nodemailer/dist/cjs/dkim/relaxed-body.d.ts b/node_modules/nodemailer/dist/cjs/dkim/relaxed-body.d.ts index c5985a4f..d8fb0e24 100644 --- a/node_modules/nodemailer/dist/cjs/dkim/relaxed-body.d.ts +++ b/node_modules/nodemailer/dist/cjs/dkim/relaxed-body.d.ts @@ -17,7 +17,7 @@ export interface RelaxedBodyOptions { * a non-empty body always ends with CRLF. Bytes are canonicalized as they arrive, * so a line of any length costs constant memory. */ -export default class RelaxedBody extends Transform { +declare class RelaxedBody extends Transform { bodyHash: crypto.Hash; /** Bytes of the original body seen so far */ byteLength: number; @@ -25,3 +25,12 @@ export default class RelaxedBody extends Transform { constructor(options?: RelaxedBodyOptions); updateHash(chunk: Buffer, final?: boolean): void; } +/** + * Type aliases in the layout of @types/nodemailer, so `RelaxedBody.Options` style references keep working + */ +declare namespace RelaxedBody { + type Options = RelaxedBodyOptions; +} +/** The same alias as a module level export, for `import * as RelaxedBody` and `import RelaxedBody = require()` */ +export type { RelaxedBodyOptions as Options }; +export default RelaxedBody; diff --git a/node_modules/nodemailer/dist/cjs/errors.d.ts b/node_modules/nodemailer/dist/cjs/errors.d.ts index c85653cc..93a74257 100644 --- a/node_modules/nodemailer/dist/cjs/errors.d.ts +++ b/node_modules/nodemailer/dist/cjs/errors.d.ts @@ -64,9 +64,10 @@ export declare const EFETCH = "EFETCH"; /** * An Error together with the properties Nodemailer attaches to the errors it * hands to callers. Every property is optional, the set that is present - * depends on where the error originated. + * depends on where the error originated. Socket level errors keep the errno + * and syscall fields Node.js sets on them. */ -export interface NodemailerError extends Error { +export interface NodemailerError extends NodeJS.ErrnoException { /** Nodemailer error code, see ERROR_CODES */ code?: string | undefined; /** SMTP command that was in flight when the server replied with an error */ diff --git a/node_modules/nodemailer/dist/cjs/fetch/cookies.d.ts b/node_modules/nodemailer/dist/cjs/fetch/cookies.d.ts index 3d631296..4e694d6a 100644 --- a/node_modules/nodemailer/dist/cjs/fetch/cookies.d.ts +++ b/node_modules/nodemailer/dist/cjs/fetch/cookies.d.ts @@ -17,13 +17,14 @@ export interface Cookie { secure?: boolean | undefined; httponly?: boolean | undefined; } +type CookieEntry = Cookie; /** * Creates a biskviit cookie jar for managing cookie values in memory * * @constructor * @param [options] Optional options object */ -export default class Cookies { +declare class Cookies { options: CookiesOptions; cookies: Cookie[]; constructor(options?: CookiesOptions); @@ -94,3 +95,13 @@ export default class Cookies { */ getPath(pathname?: string | null): string; } +/** + * Type aliases in the layout of @types/nodemailer, so `Cookies.Cookie` style references keep working + */ +declare namespace Cookies { + type Options = CookiesOptions; + type Cookie = CookieEntry; +} +/** The same alias as a module level export, for `import * as Cookies` and `import Cookies = require()` */ +export type { CookiesOptions as Options }; +export default Cookies; diff --git a/node_modules/nodemailer/dist/cjs/fetch/index.d.ts b/node_modules/nodemailer/dist/cjs/fetch/index.d.ts index 0490e708..4f0cc61c 100644 --- a/node_modules/nodemailer/dist/cjs/fetch/index.d.ts +++ b/node_modules/nodemailer/dist/cjs/fetch/index.d.ts @@ -48,4 +48,15 @@ declare function nmfetch(url: string, options?: FetchOptions): FetchResponse; declare namespace nmfetch { var Cookies: typeof import("./cookies.js").default; } +type CookiesJar = Cookies; +/** + * Type aliases in the layout of @types/nodemailer, so `fetch.Options` style references keep working + */ +declare namespace nmfetch { + type Options = FetchOptions; + type WritableResponse = FetchResponse; + type Cookies = CookiesJar; +} +/** The same aliases as module level exports, for `import * as fetch` and `import fetch = require()` */ +export type { FetchOptions as Options, FetchResponse as WritableResponse, Cookies }; export default nmfetch; diff --git a/node_modules/nodemailer/dist/cjs/fetch/index.js b/node_modules/nodemailer/dist/cjs/fetch/index.js index b05b5b28..7da06315 100644 --- a/node_modules/nodemailer/dist/cjs/fetch/index.js +++ b/node_modules/nodemailer/dist/cjs/fetch/index.js @@ -193,14 +193,14 @@ function nmfetch(url, options) { .join('&')); } catch (E) { - if (finished) { - return undefined; - } + // the caller attaches its error listener once nmfetch has returned, so + // the error is emitted on the next tick and the stream is handed back + // the way every other failure is reported finished = true; E.code = errors.EFETCH; E.sourceUrl = url; - fetchRes.emit('error', E); - return undefined; + setImmediate(() => fetchRes.emit('error', E)); + return fetchRes; } } else { diff --git a/node_modules/nodemailer/dist/cjs/json-transport/index.d.ts b/node_modules/nodemailer/dist/cjs/json-transport/index.d.ts index 5adc73af..5160aa8e 100644 --- a/node_modules/nodemailer/dist/cjs/json-transport/index.d.ts +++ b/node_modules/nodemailer/dist/cjs/json-transport/index.d.ts @@ -1,6 +1,6 @@ import type { Logger } from '../shared/index.js'; import type { MimeNodeEnvelope } from '../mime-node/index.js'; -import type { default as MailMessage, MailMessageData } from '../mailer/mail-message.js'; +import type MailMessage from '../mailer/mail-message.js'; import type { default as Mail, SentMessageInfo, SendMailOptions, TransportOptions } from '../mailer/index.js'; /** * Options for the JSON transport @@ -12,16 +12,23 @@ export interface JSONTransportOptions extends TransportOptions { skipEncoding?: boolean | undefined; } /** - * The value the JSON transport hands to the send callback + * The value the JSON transport hands to the send callback. M is the type of the message + * field: a JSON string by default, the message object itself when skipEncoding is set */ -export interface JSONSentMessageInfo extends SentMessageInfo { +export interface JSONSentMessageInfo extends SentMessageInfo { /** The envelope the message was generated with */ envelope: MimeNodeEnvelope; /** Message-ID value of the message */ messageId: string; /** The normalized message as a JSON string, or as the object itself when skipEncoding is set */ - message: string | MailMessageData; + message: M; } +/** + * The value the JSON transport hands to the send callback when skipEncoding is set: the + * message field holds the message object. Typed loosely so that a transporter created with + * skipEncoding still fits a variable declared with the plain result type + */ +export type JSONSentMessageObjectInfo = JSONSentMessageInfo; /** * Generates a Transport object to generate JSON output * @@ -50,5 +57,8 @@ declare namespace JSONTransport { type Options = JSONTransportOptions; type MailOptions = SendMailOptions; type SentMessageInfo = JSONSentMessageInfo; + type SentMessageObjectInfo = JSONSentMessageObjectInfo; } +/** The same aliases as module level exports, for `import * as JSONTransport` and `import JSONTransport = require()` */ +export type { JSONTransportOptions as Options, SendMailOptions as MailOptions, JSONSentMessageInfo as SentMessageInfo, JSONSentMessageObjectInfo as SentMessageObjectInfo }; export default JSONTransport; diff --git a/node_modules/nodemailer/dist/cjs/json-transport/index.js b/node_modules/nodemailer/dist/cjs/json-transport/index.js index 97acc91a..70726bf9 100644 --- a/node_modules/nodemailer/dist/cjs/json-transport/index.js +++ b/node_modules/nodemailer/dist/cjs/json-transport/index.js @@ -83,6 +83,8 @@ class JSONTransport { } delete data.envelope; delete data.normalizedHeaders; + // the message field is the object itself with skipEncoding, the + // createTransport overload for that option types the result accordingly return done(null, { envelope, messageId, diff --git a/node_modules/nodemailer/dist/cjs/mail-composer/index.d.ts b/node_modules/nodemailer/dist/cjs/mail-composer/index.d.ts index c076115d..817d5fdc 100644 --- a/node_modules/nodemailer/dist/cjs/mail-composer/index.d.ts +++ b/node_modules/nodemailer/dist/cjs/mail-composer/index.d.ts @@ -72,6 +72,11 @@ export type MailComposerListHeaderEntry = string | { export interface MailComposerListHeaders { [key: string]: MailComposerListHeaderEntry | (MailComposerListHeaderEntry | MailComposerListHeaderEntry[])[]; } +/** + * Encoding for the non-ascii header values: quoted-printable ('Q', the default) or base64 + * ('B'). Only the first letter is read, so the short forms work as well + */ +export type MailComposerTextEncoding = 'quoted-printable' | 'base64' | 'Q' | 'B'; /** * Mail options, the message data MailComposer builds the MIME tree from. The address * fields, subject, messageId, date, inReplyTo and references become headers of the root @@ -114,7 +119,7 @@ export interface MailComposerOptions { /** Content-Transfer-Encoding to force for the text/* nodes that do not set their own */ encoding?: string | undefined; /** Header string encoding, 'Q' (the default) or 'B', 'quoted-printable' and 'base64' are accepted as well */ - textEncoding?: string | undefined; + textEncoding?: MailComposerTextEncoding | undefined; /** Pregenerated rfc822 message, used as is instead of building one */ raw?: MimeNodeContent | undefined; /** Reject content that points to a URL */ @@ -129,8 +134,6 @@ export interface MailComposerOptions { baseBoundary?: string | undefined; /** 'win' for CRLF and 'linux' for LF line breaks in the generated message, kept as is when not set */ newline?: string | undefined; - /** Keep the Bcc header in the generated message, listed for completeness, the transports set it on the message directly */ - keepBcc?: boolean | undefined; /** Method to normalize header keys for custom caseing */ normalizeHeaderKey?: MimeNodeOptions['normalizeHeaderKey'] | undefined; /** 'high', 'normal' or 'low', sets the priority headers, read by the mailer */ @@ -166,4 +169,6 @@ declare class MailComposer { declare namespace MailComposer { type Options = MailComposerOptions; } +/** The same alias as a module level export, for `import * as MailComposer` and `import MailComposer = require()` */ +export type { MailComposerOptions as Options }; export default MailComposer; diff --git a/node_modules/nodemailer/dist/cjs/mailer/index.d.ts b/node_modules/nodemailer/dist/cjs/mailer/index.d.ts index 300d8050..58684f49 100644 --- a/node_modules/nodemailer/dist/cjs/mailer/index.d.ts +++ b/node_modules/nodemailer/dist/cjs/mailer/index.d.ts @@ -4,8 +4,8 @@ import DKIM, { type DKIMOptions } from '../dkim/index.js'; import MailMessage, { type MailDefaults, type SendMailOptions } from './mail-message.js'; import net from 'node:net'; import type { ConnectionOptions } from 'node:tls'; -import type { MailComposerAlternative, MailComposerAttachment, MailComposerIcalEvent, MailComposerListHeaderEntry, MailComposerListHeaders } from '../mail-composer/index.js'; -import type { NodemailerError, ResultCallback } from '../errors.js'; +import type { MailComposerAlternative, MailComposerAttachment, MailComposerIcalEvent, MailComposerListHeaderEntry, MailComposerListHeaders, MailComposerTextEncoding } from '../mail-composer/index.js'; +import type { Callback, NodemailerError, ResultCallback } from '../errors.js'; import type { ParsedUrl } from '../shared/url.js'; import type { MimeNodeAddress, MimeNodeEnvelope, MimeNodeEnvelopeInput, MimeNodeHeaders, MimeNodeOptions } from '../mime-node/index.js'; import type { XOAuth2ProvisionCallback } from '../xoauth2/index.js'; @@ -15,9 +15,10 @@ export type { default as MailMessage } from './mail-message.js'; * The base shape of the object a transport hands back for a sent message. Every bundled * transport sets the envelope and the Message-ID, the rest depends on the transport. * - * The index signature keeps a transport specific field readable through this type, and it - * is also what a result type has to inherit to stay assignable to it, so the result type - * of a transport outside this package has to extend this interface rather than restate it + * The index signature keeps a transport specific field readable through this type, the way + * the `any` typed result of @types/nodemailer was, and it is also what a result type has + * to inherit to stay assignable to it, so the result type of a transport outside this + * package has to extend this interface rather than restate it */ export interface SentMessageInfo { /** The envelope the message was sent with */ @@ -33,9 +34,9 @@ export interface SentMessageInfo { /** Last response from the server */ response?: string | undefined; /** The generated message, for the transports that hand it back instead of sending it */ - message?: unknown; + message?: any; /** Transport specific fields */ - [key: string]: unknown; + [key: string]: any; } /** * Callback for sendMail, receives the transport result once the transport has taken the @@ -43,9 +44,11 @@ export interface SentMessageInfo { */ export type SendMailCallback = (err: NodemailerError | null, info: T) => void; /** - * Callback for verify(), success is true once the transport accepted the configuration + * Callback for verify(), success is true once the transport accepted the configuration. + * Declared with a required success value, the way @types/nodemailer declared it, the + * error path hands over the error alone */ -export type VerifyCallback = (err: NodemailerError | null, success?: true) => void; +export type VerifyCallback = Callback; /** * Callback a plugin calls once it is done, an error aborts the send */ @@ -60,21 +63,23 @@ export type PluginFunction = (mail: MailMessage, callbac */ export interface GetSocketOptions { host?: string | undefined; - port?: number | string | undefined; + port?: number | undefined; [key: string]: any; } /** - * The result of a getSocket handler, the socket to use for the connection + * The result of a getSocket handler, the socket to use for the connection. The object is + * merged into the connection options, so it may carry any of those as well */ export interface SocketOptions { /** An established socket, the proxied connection */ connection?: net.Socket | undefined; + [key: string]: any; } /** - * Receives the socket options from a getSocket handler, or the error that prevented the - * connection + * Receives the socket options from a getSocket handler, false when a new socket should be + * opened, or the error that prevented the connection */ -export type GetSocketCallback = (err: NodemailerError | null, socketOptions?: SocketOptions) => void; +export type GetSocketCallback = (err: Error | null, socketOptions?: SocketOptions | false) => void; /** * A socket handler. Mail sets one on the transport as getSocket when a proxy is configured, * the SMTP transports call it to get a proxied socket instead of connecting directly @@ -101,9 +106,12 @@ export interface MailMeta { /** * A transport as consumed by Mail: any object with a name, a version and a send method * works, the rest is optional. Mail forwards its close, isIdle and verify calls to the - * methods of the same name as they are, so their arguments are up to the transport + * methods of the same name as they are, so their arguments are up to the transport. + * + * D is the options type of the transport, the second type parameter @types/nodemailer + * declared on Transport, Transporter and Mail */ -export interface Transport { +export interface Transport { /** Transport name, used for logging */ name: string; /** Transport version, used for logging */ @@ -119,7 +127,7 @@ export interface Transport { /** Registers an event listener, the transport may emit 'log', 'error', 'idle' and 'clear' */ on?(event: string | symbol, listener: (...args: any[]) => void): this; /** The Mail object the transport belongs to, set by Mail */ - mailer?: Mail | undefined; + mailer?: Mail | undefined; /** Socket handler for a proxied connection, set by Mail when a proxy is configured */ getSocket?: GetSocketHandler | undefined; } @@ -150,22 +158,23 @@ export interface TransportOptions { attachDataUrls?: boolean | undefined; } /** - * The transporter object createTransport returns, a Mail instance wrapping a transport + * The transporter object createTransport returns, a Mail instance wrapping a transport. D + * is the options type of the transport, it types the options field of the transporter */ -export type Transporter = Mail; +export type Transporter = Mail; /** * Creates an object for exposing the Mail API * * @constructor * @param transporter Transport object instance to pass the mails to */ -declare class Mail extends EventEmitter { - options: TransportOptions; +declare class Mail extends EventEmitter { + options: D; /** Message defaults given to createTransport, kept public because the DefinitelyTyped typings declared it */ _defaults: MailDefaults; meta: Map; dkim: DKIM | false; - transporter: Transport; + transporter: Transport; logger: shared.Logger; /** Closes the transport, the pooled SMTP transport closes its connections */ close: () => void; @@ -178,7 +187,7 @@ declare class Mail extends EventEmitter { }; /** Socket handler for a proxied connection, set by setupProxy and handed to the transport on the next send */ getSocket?: GetSocketHandler | false | undefined; - constructor(transporter: Transport, options?: TransportOptions, defaults?: MailDefaults); + constructor(transporter: Transport, options?: D, defaults?: MailDefaults); use(step: string, plugin: PluginFunction): this; /** * Sends an email using the preselected transport object @@ -213,7 +222,10 @@ declare namespace Mail { type ListHeader = MailComposerListHeaderEntry; type ListHeaders = MailComposerListHeaders; type Envelope = MimeNodeEnvelopeInput; - type TextEncoding = NonNullable; + type Connection = SocketOptions; + type TextEncoding = MailComposerTextEncoding; type PluginFunction = MailPluginFunction; } +/** The same aliases as module level exports, for `import * as Mail` and `import Mail = require()` */ +export type { SendMailOptions as Options, MimeNodeAddress as Address, MailComposerAttachment as Attachment, MailComposerAlternative as AttachmentLike, MailComposerAlternative as AmpAttachment, MailComposerIcalEvent as IcalAttachment, MimeNodeHeaders as Headers, MailComposerListHeaderEntry as ListHeader, MailComposerListHeaders as ListHeaders, MimeNodeEnvelopeInput as Envelope, SocketOptions as Connection, MailComposerTextEncoding as TextEncoding }; export default Mail; diff --git a/node_modules/nodemailer/dist/cjs/mailer/mail-message.d.ts b/node_modules/nodemailer/dist/cjs/mailer/mail-message.d.ts index 4db9dd31..6c20de37 100644 --- a/node_modules/nodemailer/dist/cjs/mailer/mail-message.d.ts +++ b/node_modules/nodemailer/dist/cjs/mailer/mail-message.d.ts @@ -3,6 +3,7 @@ import type { MailComposerOptions } from '../mail-composer/index.js'; import type { DKIMOptions } from '../dkim/index.js'; import type { SMTPEnvelopeDsn } from '../smtp-connection/index.js'; import type { SMTPTransportAuthOptions } from '../smtp-transport/index.js'; +import type { SESSendEmailRequest } from '../ses-transport/index.js'; import type { NodemailerError } from '../errors.js'; import type { ResolveContentOptions } from '../shared/index.js'; import type Mail from './index.js'; @@ -14,6 +15,8 @@ import type { SentMessageInfo } from './index.js'; export interface SendMailOptions extends MailComposerOptions { /** DKIM signing options for this message, used instead of the ones of the transporter */ dkim?: DKIMOptions | undefined; + /** Extra DKIM options for this message, merged over the options of the signer. The SES transport sets skipFields here, the option is not meant for callers */ + _dkim?: DKIMOptions | undefined; /** Recipients allowed on this message, 0 disables the limit, defaults to 100000 */ maxRecipients?: number | undefined; /** SMTP transports: DSN parameters for the envelope, sent when the server supports the DSN extension */ @@ -23,9 +26,7 @@ export interface SendMailOptions extends MailComposerOptions { /** SMTP transports: per-message authentication settings, used instead of the transport level auth */ auth?: SMTPTransportAuthOptions | undefined; /** SES transport: extra SendEmailCommand parameters merged into the API call */ - ses?: { - [key: string]: unknown; - } | undefined; + ses?: SESSendEmailRequest | undefined; } /** * Default message fields, the third argument of createTransport. Applied to every message @@ -71,7 +72,13 @@ export interface MailMessageListHeader { export default class MailMessage { mailer: Mail; data: MailMessageData; - message: MimeNode | null; + /** + * The compiled MIME tree. Set once the compile step is done, so it is null while the + * 'compile' plugins run and set by the time the 'stream' plugins and the transport see + * the message. Declared as always set, the way @types/nodemailer declared it, since the + * plugins that read it are the ones that run after it is set + */ + message: MimeNode; constructor(mailer: Mail, data?: SendMailOptions); resolveContent(data: { [key: string]: any; diff --git a/node_modules/nodemailer/dist/cjs/mime-funcs/index.d.ts b/node_modules/nodemailer/dist/cjs/mime-funcs/index.d.ts index 3c7b2793..a9a79e72 100644 --- a/node_modules/nodemailer/dist/cjs/mime-funcs/index.d.ts +++ b/node_modules/nodemailer/dist/cjs/mime-funcs/index.d.ts @@ -2,8 +2,8 @@ * A header value split into the value token and its parameters, the result of parseHeaderValue */ export interface ParsedHeaderValue { - /** The value ahead of the parameters, for example the content type */ - value: string | false; + /** The value ahead of the parameters, for example the content type, an empty string when there is none */ + value: string; /** Parameter values keyed by lowercase parameter name */ params: Record; } @@ -25,6 +25,9 @@ export interface EncodedHeaderParam { /** Parameter value of this part */ value: string; } +/** The names @types/nodemailer used for the two types above */ +export type HeaderValue = StructuredHeaderValue; +export type ParsedHeaderParam = EncodedHeaderParam; /** * Checks if a value is plaintext string (uses only printable 7bit chars) * diff --git a/node_modules/nodemailer/dist/cjs/mime-funcs/index.js b/node_modules/nodemailer/dist/cjs/mime-funcs/index.js index 3433ef0a..6a66aa67 100644 --- a/node_modules/nodemailer/dist/cjs/mime-funcs/index.js +++ b/node_modules/nodemailer/dist/cjs/mime-funcs/index.js @@ -402,7 +402,7 @@ function buildHeaderParam(key, data, maxLength) { */ function parseHeaderValue(str) { const response = { - value: false, + value: '', params: {} }; // Parameter names come from a caller supplied contentType/contentDisposition. A diff --git a/node_modules/nodemailer/dist/cjs/mime-node/index.d.ts b/node_modules/nodemailer/dist/cjs/mime-node/index.d.ts index 2030d14d..03d7603b 100644 --- a/node_modules/nodemailer/dist/cjs/mime-node/index.d.ts +++ b/node_modules/nodemailer/dist/cjs/mime-node/index.d.ts @@ -108,10 +108,11 @@ export interface MimeNodeEnvelope { } /** * Envelope as accepted by setEnvelope. Recipients are collected from to, cc and bcc, any - * other field is copied to the envelope as is + * other field is copied to the envelope as is. A `from` of false is the null sender of a + * bounce message, it is sent as MAIL FROM:<> */ export interface MimeNodeEnvelopeInput { - from?: MimeNodeAddressInput | undefined; + from?: MimeNodeAddressInput | false | undefined; to?: MimeNodeAddressInput | undefined; cc?: MimeNodeAddressInput | undefined; bcc?: MimeNodeAddressInput | undefined; @@ -327,4 +328,6 @@ declare namespace MimeNode { type Addresses = MimeNodeAddresses; type Envelope = MimeNodeEnvelope; } +/** The same aliases as module level exports, for `import * as MimeNode` and `import MimeNode = require()` */ +export type { MimeNodeOptions as Options, MimeNodeAddresses as Addresses, MimeNodeEnvelope as Envelope }; export default MimeNode; diff --git a/node_modules/nodemailer/dist/cjs/nodemailer.d.ts b/node_modules/nodemailer/dist/cjs/nodemailer.d.ts index 3dd14427..8552d000 100644 --- a/node_modules/nodemailer/dist/cjs/nodemailer.d.ts +++ b/node_modules/nodemailer/dist/cjs/nodemailer.d.ts @@ -1,10 +1,16 @@ import Mail from './mailer/index.js'; import type { MailDefaults, SentMessageInfo, Transport, TransportOptions } from './mailer/index.js'; +import SMTPPool from './smtp-pool/index.js'; import type { SMTPPoolOptions, SMTPPoolSentMessageInfo } from './smtp-pool/index.js'; +import SMTPTransport from './smtp-transport/index.js'; import type { SMTPTransportOptions, SMTPSentMessageInfo } from './smtp-transport/index.js'; +import SendmailTransport from './sendmail-transport/index.js'; import type { SendmailTransportOptions, SendmailSentMessageInfo } from './sendmail-transport/index.js'; +import StreamTransport from './stream-transport/index.js'; import type { StreamTransportOptions, StreamSentMessageInfo } from './stream-transport/index.js'; -import type { JSONTransportOptions, JSONSentMessageInfo } from './json-transport/index.js'; +import JSONTransport from './json-transport/index.js'; +import type { JSONTransportOptions, JSONSentMessageInfo, JSONSentMessageObjectInfo } from './json-transport/index.js'; +import SESTransport from './ses-transport/index.js'; import type { SESTransportOptions, SESSentMessageInfo } from './ses-transport/index.js'; /** * Connection details of a service endpoint of an Ethereal test account @@ -43,24 +49,29 @@ export type TransportConfig = SMTPTransportOptions | SMTPPoolOptions | SendmailT * @param defaults Default message fields that are merged into every message * @returns Mail instance wrapping the transport */ -export declare function createTransport(transporter: SMTPPoolOptions & { +export declare function createTransport(transporter: SMTPPool | (SMTPPoolOptions & { pool: true; -}, defaults?: MailDefaults): Mail; -export declare function createTransport(transporter: SendmailTransportOptions & { +}), defaults?: MailDefaults): Mail; +export declare function createTransport(transporter: SendmailTransport | (SendmailTransportOptions & { sendmail: true | string; -}, defaults?: MailDefaults): Mail; -export declare function createTransport(transporter: StreamTransportOptions & { +}), defaults?: MailDefaults): Mail; +export declare function createTransport(transporter: StreamTransport | (StreamTransportOptions & { streamTransport: true; -}, defaults?: MailDefaults): Mail; +}), defaults?: MailDefaults): Mail; export declare function createTransport(transporter: JSONTransportOptions & { jsonTransport: true; -}, defaults?: MailDefaults): Mail; -export declare function createTransport(transporter: SESTransportOptions & { + skipEncoding: true; +}, defaults?: MailDefaults): Mail; +export declare function createTransport(transporter: JSONTransport | (JSONTransportOptions & { + jsonTransport: true; +}), defaults?: MailDefaults): Mail; +export declare function createTransport(transporter: SESTransport | (SESTransportOptions & { SES: object; -}, defaults?: MailDefaults): Mail; -export declare function createTransport(transporter: Transport, defaults?: MailDefaults): Mail; -export declare function createTransport(transporter?: SMTPTransportOptions | string, defaults?: MailDefaults): Mail; -export declare function createTransport(transporter?: TransportConfig | Transport | string, defaults?: MailDefaults): Mail; +}), defaults?: MailDefaults): Mail; +export declare function createTransport(transporter: SMTPTransport, defaults?: MailDefaults): Mail; +export declare function createTransport(transporter: Transport, defaults?: MailDefaults): Mail; +export declare function createTransport(transporter?: SMTPTransportOptions | string, defaults?: MailDefaults): Mail; +export declare function createTransport(transporter?: TransportConfig | Transport | string, defaults?: MailDefaults): Mail; /** * Creates a test account from the Ethereal service (https://ethereal.email) * @@ -98,5 +109,5 @@ export type { SMTPTransportOptions, SMTPSentMessageInfo }; export type { SMTPPoolOptions, SMTPPoolSentMessageInfo }; export type { SendmailTransportOptions, SendmailSentMessageInfo }; export type { StreamTransportOptions, StreamSentMessageInfo }; -export type { JSONTransportOptions, JSONSentMessageInfo }; +export type { JSONTransportOptions, JSONSentMessageInfo, JSONSentMessageObjectInfo }; export type { SESTransportOptions, SESSentMessageInfo }; diff --git a/node_modules/nodemailer/dist/cjs/nodemailer.js b/node_modules/nodemailer/dist/cjs/nodemailer.js index 04d68d9a..f2213f16 100644 --- a/node_modules/nodemailer/dist/cjs/nodemailer.js +++ b/node_modules/nodemailer/dist/cjs/nodemailer.js @@ -205,3 +205,4 @@ const nodemailer = { getTestMessageUrl }; exports.default = nodemailer; +Object.defineProperty(exports, 'default', { value: exports, enumerable: false, writable: true, configurable: true }); diff --git a/node_modules/nodemailer/dist/cjs/package-info.d.ts b/node_modules/nodemailer/dist/cjs/package-info.d.ts index 4e7cec12..5f166c65 100644 --- a/node_modules/nodemailer/dist/cjs/package-info.d.ts +++ b/node_modules/nodemailer/dist/cjs/package-info.d.ts @@ -1,3 +1,3 @@ export declare const name = "nodemailer"; -export declare const version = "10.0.10"; +export declare const version = "10.0.11"; export declare const homepage = "https://nodemailer.com/"; diff --git a/node_modules/nodemailer/dist/cjs/package-info.js b/node_modules/nodemailer/dist/cjs/package-info.js index 018f7634..98d7f778 100644 --- a/node_modules/nodemailer/dist/cjs/package-info.js +++ b/node_modules/nodemailer/dist/cjs/package-info.js @@ -3,5 +3,5 @@ Object.defineProperty(exports, "__esModule", { value: true }); exports.homepage = exports.version = exports.name = void 0; exports.name = 'nodemailer'; -exports.version = '10.0.10'; +exports.version = '10.0.11'; exports.homepage = 'https://nodemailer.com/'; diff --git a/node_modules/nodemailer/dist/cjs/qp/index.d.ts b/node_modules/nodemailer/dist/cjs/qp/index.d.ts index 92eb8b9b..6253dbf6 100644 --- a/node_modules/nodemailer/dist/cjs/qp/index.d.ts +++ b/node_modules/nodemailer/dist/cjs/qp/index.d.ts @@ -15,6 +15,8 @@ export interface QPEncoderOptions { /** Maximum length for lines, set to false to disable wrapping */ lineLength?: number | false | undefined; } +/** The name @types/nodemailer used for QPEncoderOptions */ +export type EncoderOptions = QPEncoderOptions; /** * Creates a transform stream for encoding data to Quoted-Printable encoding * diff --git a/node_modules/nodemailer/dist/cjs/qp/index.js b/node_modules/nodemailer/dist/cjs/qp/index.js index f4da4a6f..70f43668 100644 --- a/node_modules/nodemailer/dist/cjs/qp/index.js +++ b/node_modules/nodemailer/dist/cjs/qp/index.js @@ -10,6 +10,8 @@ const node_stream_1 = require("node:stream"); * @param buffer Buffer to convert * @returns Quoted-Printable encoded string */ +// the shortest line wrap() can make progress with: a complete =XX sequence and the soft break +const MIN_LINE_LENGTH = 4; // usable characters that do not need encoding // https://tools.ietf.org/html/rfc2045#section-6.7 const QP_RANGES = [ @@ -46,7 +48,9 @@ function encode(buffer) { */ function wrap(str, lineLength) { str = (str || '').toString(); - lineLength = lineLength || 76; + // a line has to hold a complete =XX sequence plus the soft break, shorter lengths + // (or a negative one) would loop without consuming input + lineLength = Math.max(Number(lineLength) || 76, MIN_LINE_LENGTH); if (str.length <= lineLength) { return str; } @@ -100,6 +104,11 @@ function wrap(str, lineLength) { } } } + if (!line.length) { + // the trimming above emptied the line, which only happens for an incomplete + // escape at the very end of the input. Take it as is rather than loop on it + line = str.substr(pos, lineLength); + } if (pos + line.length < len && line.substr(-1) !== '\n') { if (line.length === lineLength && line.match(/[=][\da-f]{2}$/i)) { line = line.substr(0, line.length - 3); diff --git a/node_modules/nodemailer/dist/cjs/sendmail-transport/index.d.ts b/node_modules/nodemailer/dist/cjs/sendmail-transport/index.d.ts index e71c0268..28f2c7c4 100644 --- a/node_modules/nodemailer/dist/cjs/sendmail-transport/index.d.ts +++ b/node_modules/nodemailer/dist/cjs/sendmail-transport/index.d.ts @@ -64,4 +64,6 @@ declare namespace SendmailTransport { type MailOptions = SendMailOptions; type SentMessageInfo = SendmailSentMessageInfo; } +/** The same aliases as module level exports, for `import * as SendmailTransport` and `import SendmailTransport = require()` */ +export type { SendmailTransportOptions as Options, SendMailOptions as MailOptions, SendmailSentMessageInfo as SentMessageInfo }; export default SendmailTransport; diff --git a/node_modules/nodemailer/dist/cjs/ses-transport/index.d.ts b/node_modules/nodemailer/dist/cjs/ses-transport/index.d.ts index e3f6358a..26432d54 100644 --- a/node_modules/nodemailer/dist/cjs/ses-transport/index.d.ts +++ b/node_modules/nodemailer/dist/cjs/ses-transport/index.d.ts @@ -21,6 +21,32 @@ export interface SESTransportOptions extends TransportOptions { SendEmailCommand: new (input: any) => unknown; }; } +/** The SESv2Client shape the transport needs */ +export type SESTransportClient = SESTransportOptions['SES']['sesClient']; +/** The SendEmailCommand constructor shape the transport needs */ +export type SESTransportSendEmailCommand = SESTransportOptions['SES']['SendEmailCommand']; +/** + * SendEmailCommand parameters, the shape of the `ses` message option that is merged into + * the API call. Any further SendEmailCommandInput field is accepted as well + */ +export interface SESSendEmailRequest { + FromEmailAddress?: string | undefined; + Destination?: { + ToAddresses?: string[] | undefined; + CcAddresses?: string[] | undefined; + BccAddresses?: string[] | undefined; + } | undefined; + ReplyToAddresses?: string[] | undefined; + Content?: unknown; + EmailTags?: Array<{ + Name?: string | undefined; + Value?: string | undefined; + }> | undefined; + ConfigurationSetName?: string | undefined; + ListManagementOptions?: unknown; + FeedbackForwardingEmailAddress?: string | undefined; + [key: string]: unknown; +} /** * The value the SES transport hands to the send callback */ @@ -47,7 +73,7 @@ declare class SESTransport extends EventEmitter { name: string; version: string; logger: Logger; - constructor(options?: SESTransportOptions); + constructor(options: SESTransportOptions); getRegion(cb: (err: Error | null, region?: string | false) => void): void; /** * Compiles a mailcomposer message and forwards it to SES @@ -71,5 +97,11 @@ declare namespace SESTransport { type Options = SESTransportOptions; type MailOptions = SendMailOptions; type SentMessageInfo = SESSentMessageInfo; + type SESv2ClientLike = SESTransportClient; + type SendEmailCommandConstructorLike = SESTransportSendEmailCommand; + type SendEmailRequestLike = SESSendEmailRequest; + type MailSesOptions = SESSendEmailRequest; } +/** The same aliases as module level exports, for `import * as SESTransport` and `import SESTransport = require()` */ +export type { SESTransportOptions as Options, SendMailOptions as MailOptions, SESSentMessageInfo as SentMessageInfo, SESTransportClient as SESv2ClientLike, SESTransportSendEmailCommand as SendEmailCommandConstructorLike, SESSendEmailRequest as SendEmailRequestLike, SESSendEmailRequest as MailSesOptions }; export default SESTransport; diff --git a/node_modules/nodemailer/dist/cjs/shared/index.d.ts b/node_modules/nodemailer/dist/cjs/shared/index.d.ts index e6e5077c..3aeb3e79 100644 --- a/node_modules/nodemailer/dist/cjs/shared/index.d.ts +++ b/node_modules/nodemailer/dist/cjs/shared/index.d.ts @@ -34,6 +34,8 @@ export interface ResolvedHostname { /** The resolver error when a cached value was used because of it */ error?: Error | undefined; } +/** The name @types/nodemailer used for ResolvedHostname */ +export type ResolveHostnameValue = ResolvedHostname; /** * Resolved addresses as stored in the DNS cache */ @@ -83,6 +85,8 @@ export interface LogEntry { [key: string]: any; } export type LogLevel = 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'fatal'; +/** The name @types/nodemailer used for LogLevel */ +export type LoggerLevel = LogLevel; /** * A logger supplied by the caller, bunyan style. Any object works, a level it does not * implement is routed to one it does, see _logFunc @@ -104,16 +108,24 @@ export interface GetLoggerOptions { /** A bunyan compatible logger, true for the default console logger, false or unset for no logging */ logger?: ExternalLogger | boolean | undefined; } +/** + * A bunyan style log method: a data object followed by a printf style message, or the + * message alone + */ +export interface LogMethod { + (data: LogEntry | undefined, message?: string, ...args: any[]): void; + (message?: string, ...args: any[]): void; +} /** * The bunyan compatible logger interface returned by getLogger */ export interface Logger { - trace(data?: LogEntry, message?: string, ...args: any[]): void; - debug(data?: LogEntry, message?: string, ...args: any[]): void; - info(data?: LogEntry, message?: string, ...args: any[]): void; - warn(data?: LogEntry, message?: string, ...args: any[]): void; - error(data?: LogEntry, message?: string, ...args: any[]): void; - fatal(data?: LogEntry, message?: string, ...args: any[]): void; + trace: LogMethod; + debug: LogMethod; + info: LogMethod; + warn: LogMethod; + error: LogMethod; + fatal: LogMethod; } /** * A parsed data URI diff --git a/node_modules/nodemailer/dist/cjs/shared/index.js b/node_modules/nodemailer/dist/cjs/shared/index.js index 9d513bb8..2f987f0e 100644 --- a/node_modules/nodemailer/dist/cjs/shared/index.js +++ b/node_modules/nodemailer/dist/cjs/shared/index.js @@ -377,8 +377,10 @@ const getLogger = (options, defaults) => { } const logger = options.logger === true ? createDefaultLogger(levels) : options.logger; levels.forEach(level => { - response[level] = (data, message, ...args) => { - (0, exports._logFunc)(logger, level, defaults, data, message, ...args); + response[level] = (...args) => { + // the bunyan forms: a data object first, or the message alone + const data = typeof args[0] === 'string' ? undefined : args.shift(); + (0, exports._logFunc)(logger, level, defaults, data, ...args); }; }); return response; diff --git a/node_modules/nodemailer/dist/cjs/smtp-connection/http-proxy-client.d.ts b/node_modules/nodemailer/dist/cjs/smtp-connection/http-proxy-client.d.ts index 5483cdc1..f0f9a481 100644 --- a/node_modules/nodemailer/dist/cjs/smtp-connection/http-proxy-client.d.ts +++ b/node_modules/nodemailer/dist/cjs/smtp-connection/http-proxy-client.d.ts @@ -2,7 +2,7 @@ * Minimal HTTP/S proxy client */ import net from 'node:net'; -import type { NodemailerError } from '../errors.js'; +import type { Callback } from '../errors.js'; /** * TLS options for connecting to an HTTPS proxy */ @@ -13,7 +13,7 @@ export interface HttpProxyClientOptions { /** * Receives the proxied socket once the CONNECT handshake has succeeded, or the error that prevented it */ -export type HttpProxyClientCallback = (err: NodemailerError | null, socket?: net.Socket) => void; +export type HttpProxyClientCallback = Callback; /** * Establishes proxied connection to destinationPort * diff --git a/node_modules/nodemailer/dist/cjs/smtp-connection/http-proxy-client.js b/node_modules/nodemailer/dist/cjs/smtp-connection/http-proxy-client.js index aace90b8..05da36f9 100644 --- a/node_modules/nodemailer/dist/cjs/smtp-connection/http-proxy-client.js +++ b/node_modules/nodemailer/dist/cjs/smtp-connection/http-proxy-client.js @@ -52,6 +52,8 @@ function httpProxyClient(proxyUrl, destinationPort, destinationHost, tlsOptions, tlsOptions = {}; } tlsOptions = tlsOptions || {}; + // the error paths hand over the error alone + const done = callback; // Reject CRLF in the destination before it reaches the CONNECT request line // and Host header. A tainted host/port could otherwise inject additional // request headers into the proxy connection (HTTP request splitting). @@ -59,7 +61,7 @@ function httpProxyClient(proxyUrl, destinationPort, destinationHost, tlsOptions, if (!destinationPort || /[\r\n]/.test(destinationHost)) { const err = new Error('Invalid proxy destination'); err.code = errors.EPROXY; - setImmediate(() => callback(err)); + setImmediate(() => done(err)); return; } const proxy = urllib.parse(proxyUrl); @@ -93,7 +95,7 @@ function httpProxyClient(proxyUrl, destinationPort, destinationHost, tlsOptions, catch (_E) { // ignore } - callback(err); + done(err); }; const timeoutErr = () => { const err = new Error('Proxy socket timed out'); @@ -152,12 +154,12 @@ function httpProxyClient(proxyUrl, destinationPort, destinationHost, tlsOptions, } const err = new Error('Invalid response from proxy' + ((match && ': ' + match[1]) || '')); err.code = errors.EPROXY; - return callback(err); + return done(err); } socket.removeListener('error', tempSocketErr); socket.removeListener('timeout', timeoutErr); socket.setTimeout(0); - return callback(null, socket); + return done(null, socket); } if (headers.length > MAX_RESPONSE_HEADER_BYTES) { socket.removeListener('data', onSocketData); diff --git a/node_modules/nodemailer/dist/cjs/smtp-connection/index.d.ts b/node_modules/nodemailer/dist/cjs/smtp-connection/index.d.ts index d8f1d34d..498af745 100644 --- a/node_modules/nodemailer/dist/cjs/smtp-connection/index.d.ts +++ b/node_modules/nodemailer/dist/cjs/smtp-connection/index.d.ts @@ -3,8 +3,9 @@ import net from 'node:net'; import tls from 'node:tls'; import { type Readable } from 'node:stream'; import * as shared from '../shared/index.js'; -import type { NodemailerError } from '../errors.js'; +import type { Callback, NodemailerError } from '../errors.js'; import type XOAuth2 from '../xoauth2/index.js'; +import type { XOAuth2Options } from '../xoauth2/index.js'; /** * Custom authentication handlers keyed by (case insensitive) SASL method name */ @@ -117,12 +118,23 @@ export interface SMTPConnectionCustomAuthResponse { * Callback for a command sent by a custom authentication handler */ export type SMTPConnectionCustomAuthCommandCallback = (err: Error | null, data: SMTPConnectionCustomAuthResponse) => void; +/** + * The auth object as a custom authentication handler sees it: the object handed to login() + * with the credentials filled in from its user and pass values + */ +export interface SMTPConnectionCustomAuthData extends SMTPConnectionAuth { + /** The user and pass values of the auth object, the way @types/nodemailer declared them */ + credentials: SMTPConnectionCredentials & { + user: string; + pass: string; + }; +} /** * The object a custom authentication handler is run with */ export interface SMTPConnectionCustomAuthContext { - /** The auth object handed to login() */ - auth: SMTPConnectionAuth; + /** The auth object handed to login(), with the credentials filled in */ + auth: SMTPConnectionCustomAuthData; /** Selected authentication method name */ method: string; /** SMTP extensions the server advertised */ @@ -131,17 +143,20 @@ export interface SMTPConnectionCustomAuthContext { authMethods: string[]; /** Maximum message size the server accepts, false when not advertised */ maxAllowedSize: number | false; - /** Sends a command to the server. Returns a promise when no callback is given */ - sendCommand(cmd: string, done?: SMTPConnectionCustomAuthCommandCallback): Promise | undefined; + /** Sends a command to the server and resolves with the parsed reply */ + sendCommand(cmd: string): Promise; + /** Sends a command to the server and hands the parsed reply to the callback */ + sendCommand(cmd: string, done: SMTPConnectionCustomAuthCommandCallback): void; /** Marks the user as authenticated */ resolve(): void; /** Fails the authentication with an error */ reject(err: Error | string): void; } /** - * A custom authentication handler. Calls resolve() or reject() on the context, or returns a promise + * A custom authentication handler. Calls resolve() or reject() on the context, or returns a + * promise that settles the authentication. Any other return value is ignored */ -export type SMTPConnectionCustomAuthHandler = (ctx: SMTPConnectionCustomAuthContext) => void | Promise; +export type SMTPConnectionCustomAuthHandler = (ctx: SMTPConnectionCustomAuthContext) => unknown; /** * An envelope address, either a plain string or an object with an address property */ @@ -168,12 +183,16 @@ export interface SMTPEnvelopeDsn { /** Alias of recipient, in the 'rfc822;address' form */ orcpt?: string | null | undefined; } +/** + * A single DSN notify value + */ +export type SMTPEnvelopeDsnNotify = 'NEVER' | 'SUCCESS' | 'FAILURE' | 'DELAY'; /** * Envelope object accepted by send() */ export interface SMTPEnvelope { - /** Sender address */ - from?: string | SMTPEnvelopeAddress | undefined; + /** Sender address, false for the null sender of a bounce message (MAIL FROM:<>) */ + from?: string | SMTPEnvelopeAddress | false | undefined; /** Recipient address or addresses */ to?: string | SMTPEnvelopeAddress | Array | undefined; /** Message size in bytes, sent as the SIZE parameter when the server supports it */ @@ -202,9 +221,9 @@ export interface SMTPConnectionEnvelope extends SMTPEnvelope { accepted: string[]; } /** - * Result of a sent message + * The recipient bookkeeping of a sent message, known once the envelope is accepted */ -export interface SMTPConnectionSendInfo { +export interface SMTPConnectionEnvelopeInfo { /** Recipients the server accepted */ accepted: string[]; /** Recipients the server rejected */ @@ -213,19 +232,25 @@ export interface SMTPConnectionSendInfo { ehlo?: string[] | undefined; /** Errors for the rejected recipients */ rejectedErrors?: NodemailerError[] | undefined; - /** Time in ms spent on the envelope commands */ - envelopeTime?: number | undefined; - /** Time in ms spent on streaming the message */ - messageTime?: number | undefined; - /** Size of the encoded message in bytes */ - messageSize?: number | undefined; - /** Final server response for the message */ - response?: string | undefined; } /** - * Callback for send() + * Result of a sent message */ -export type SMTPConnectionSendCallback = (err: NodemailerError | null, info?: SMTPConnectionSendInfo) => void; +export interface SMTPConnectionSendInfo extends SMTPConnectionEnvelopeInfo { + /** Time in ms spent on the envelope commands */ + envelopeTime: number; + /** Time in ms spent on streaming the message */ + messageTime: number; + /** Size of the encoded message in bytes */ + messageSize: number; + /** Final server response for the message */ + response: string; +} +/** + * Callback for send(), receives the result once the server accepted the message. The error + * path hands over the error alone + */ +export type SMTPConnectionSendCallback = Callback; /** * Callback for login() and reset(), the result is true on success */ @@ -285,7 +310,7 @@ export type SMTPConnectionResponseAction = (str: string) => void; */ declare class SMTPConnection extends EventEmitter { id: string; - stage: string; + stage: 'init' | 'connected'; options: SMTPConnectionOptions; secureConnection: boolean; alreadySecured: boolean; @@ -370,12 +395,22 @@ declare class SMTPConnection extends EventEmitter { declare namespace SMTPConnection { type Options = SMTPConnectionOptions; type AuthenticationType = SMTPConnectionAuth; + type AuthenticationTypeLogin = SMTPConnectionAuth; + type AuthenticationTypeOAuth2 = SMTPConnectionAuth; + type AuthenticationTypeCustom = SMTPConnectionAuth; + type AuthenticationCredentials = SMTPConnectionAuth; + type AuthenticationOAuth2 = SMTPConnectionAuth; type Credentials = SMTPConnectionCredentials; + type OAuth2 = XOAuth2Options; type Envelope = SMTPEnvelope; type DSNOptions = SMTPEnvelopeDsn; + type DSNOption = SMTPEnvelopeDsnNotify; type SentMessageInfo = SMTPConnectionSendInfo; + type SMTPError = NodemailerError; type CustomAuthenticationContext = SMTPConnectionCustomAuthContext; type CustomAuthenticationResponse = SMTPConnectionCustomAuthResponse; type CustomAuthenticationHandlers = SMTPConnectionCustomAuthHandlers; } +/** The same aliases as module level exports, for `import * as SMTPConnection` and `import SMTPConnection = require()` */ +export type { SMTPConnectionOptions as Options, SMTPConnectionAuth as AuthenticationType, SMTPConnectionAuth as AuthenticationTypeLogin, SMTPConnectionAuth as AuthenticationTypeOAuth2, SMTPConnectionAuth as AuthenticationTypeCustom, SMTPConnectionAuth as AuthenticationCredentials, SMTPConnectionAuth as AuthenticationOAuth2, SMTPConnectionCredentials as Credentials, XOAuth2Options as OAuth2, SMTPEnvelope as Envelope, SMTPEnvelopeDsn as DSNOptions, SMTPEnvelopeDsnNotify as DSNOption, SMTPConnectionSendInfo as SentMessageInfo, NodemailerError as SMTPError, SMTPConnectionCustomAuthContext as CustomAuthenticationContext, SMTPConnectionCustomAuthResponse as CustomAuthenticationResponse, SMTPConnectionCustomAuthHandlers as CustomAuthenticationHandlers }; export default SMTPConnection; diff --git a/node_modules/nodemailer/dist/cjs/smtp-connection/index.js b/node_modules/nodemailer/dist/cjs/smtp-connection/index.js index ed494e41..0d2db5f2 100644 --- a/node_modules/nodemailer/dist/cjs/smtp-connection/index.js +++ b/node_modules/nodemailer/dist/cjs/smtp-connection/index.js @@ -452,14 +452,21 @@ class SMTPConnection extends node_events_1.EventEmitter { this._auth = authData || {}; // Select SASL authentication method this._authMethod = (this._auth.method || '').toString().trim().toUpperCase() || false; + // XOAUTH2 needs a token generator or a custom handler, without either the method + // can not be run even when it is the only one the server advertised + const canUseXOAuth2 = !!this._auth.oauth2 || this.customAuth.has('XOAUTH2'); if (!this._authMethod && this._auth.oauth2 && !this._auth.credentials) { this._authMethod = 'XOAUTH2'; } else if (!this._authMethod || (this._authMethod === 'XOAUTH2' && !this._auth.oauth2)) { - // use first supported - this._authMethod = (this._supportedAuth[0] || 'PLAIN').toUpperCase().trim(); + // use the first supported method that can be run + const supported = this._supportedAuth.find(method => method !== 'XOAUTH2' || canUseXOAuth2); + this._authMethod = (supported || 'PLAIN').toUpperCase().trim(); } - if (this._authMethod !== 'XOAUTH2' && (!this._auth.credentials || !this._auth.credentials.user || !this._auth.credentials.pass)) { + // a token login needs no credentials, every other method and every custom handler + // gets them filled in from the user and pass values + if ((this._authMethod !== 'XOAUTH2' || this.customAuth.has('XOAUTH2')) && + (!this._auth.credentials || !this._auth.credentials.user || !this._auth.credentials.pass)) { if ((this._auth.user && this._auth.pass) || this.customAuth.has(this._authMethod)) { this._auth.credentials = { user: this._auth.user, @@ -496,42 +503,45 @@ class SMTPConnection extends node_events_1.EventEmitter { returned = true; callback(this._formatError(err, 'EAUTH', lastResponse, 'AUTH ' + this._authMethod)); }; + // one implementation serves both sendCommand overloads, the promise is returned + // exactly when no callback was given + const sendCommand = (cmd, done) => { + let promise; + if (!done) { + promise = new Promise((resolve, reject) => { + done = shared.callbackPromise(resolve, reject); + }); + } + this._responseActions.push(str => { + lastResponse = str; + let codes = str.match(/^(\d+)(?:\s(\d+\.\d+\.\d+))?\s/); + let data = { + command: cmd, + response: str + }; + if (codes) { + data.status = Number(codes[1]) || 0; + if (codes[2]) { + data.code = codes[2]; + } + data.text = str.substr(codes[0].length); + } + else { + data.text = str; + data.status = 0; // just in case we need to perform numeric comparisons + } + done(null, data); + }); + setImmediate(() => this._sendCommand(cmd)); + return promise; + }; const handlerResponse = handler({ auth: this._auth, method: this._authMethod, extensions: [].concat(this._supportedExtensions), authMethods: [].concat(this._supportedAuth), maxAllowedSize: this._maxAllowedSize || false, - sendCommand: (cmd, done) => { - let promise; - if (!done) { - promise = new Promise((resolve, reject) => { - done = shared.callbackPromise(resolve, reject); - }); - } - this._responseActions.push(str => { - lastResponse = str; - let codes = str.match(/^(\d+)(?:\s(\d+\.\d+\.\d+))?\s/); - let data = { - command: cmd, - response: str - }; - if (codes) { - data.status = Number(codes[1]) || 0; - if (codes[2]) { - data.code = codes[2]; - } - data.text = str.substr(codes[0].length); - } - else { - data.text = str; - data.status = 0; // just in case we need to perform numeric comparisons - } - done(null, data); - }); - setImmediate(() => this._sendCommand(cmd)); - return promise; - }, + sendCommand: sendCommand, resolve, reject }); @@ -588,29 +598,30 @@ class SMTPConnection extends node_events_1.EventEmitter { * @param callback Callback to return once sending is completed */ send(envelope, message, done) { - if (!message) { - return done(this._formatError('Empty message', 'EMESSAGE', false, 'API')); - } - const isDestroyedMessage = this._isDestroyedMessage('send message'); - if (isDestroyedMessage) { - return done(this._formatError(isDestroyedMessage, 'ECONNECTION', false, 'API')); - } - // reject larger messages than allowed - if (this._maxAllowedSize && envelope.size > this._maxAllowedSize) { - setImmediate(() => { - done(this._formatError('Message size larger than allowed ' + this._maxAllowedSize, 'EMESSAGE', false, 'MAIL FROM')); - }); - return; - } - // ensure that callback is only called once + // ensure that the callback is only called once. The public callback type has a + // required result, the error paths hand over the error alone let returned = false; - const callback = function (...args) { + const callback = (err, info) => { if (returned) { return; } returned = true; - done(...args); + done(err, info); }; + if (!message) { + return callback(this._formatError('Empty message', 'EMESSAGE', false, 'API')); + } + const isDestroyedMessage = this._isDestroyedMessage('send message'); + if (isDestroyedMessage) { + return callback(this._formatError(isDestroyedMessage, 'ECONNECTION', false, 'API')); + } + // reject larger messages than allowed + if (this._maxAllowedSize && envelope.size > this._maxAllowedSize) { + setImmediate(() => { + callback(this._formatError('Message size larger than allowed ' + this._maxAllowedSize, 'EMESSAGE', false, 'MAIL FROM')); + }); + return; + } if (typeof message.on === 'function') { message.on('error', err => callback(this._formatError(err, 'ESTREAM', false, 'API'))); } @@ -633,11 +644,13 @@ class SMTPConnection extends node_events_1.EventEmitter { if (err) { return callback(err); } - info.envelopeTime = envelopeTime - startTime; - info.messageTime = Date.now() - envelopeTime; - info.messageSize = stream.outByteCount; - info.response = str; - return callback(null, info); + // the envelope info becomes the send result once the timings are on it + const result = info; + result.envelopeTime = envelopeTime - startTime; + result.messageTime = Date.now() - envelopeTime; + result.messageSize = stream.outByteCount; + result.response = str; + return callback(null, result); }); if (typeof message.pipe === 'function') { message.pipe(stream); diff --git a/node_modules/nodemailer/dist/cjs/smtp-pool/index.d.ts b/node_modules/nodemailer/dist/cjs/smtp-pool/index.d.ts index 2e5b488d..9646cd50 100644 --- a/node_modules/nodemailer/dist/cjs/smtp-pool/index.d.ts +++ b/node_modules/nodemailer/dist/cjs/smtp-pool/index.d.ts @@ -80,7 +80,7 @@ declare class SMTPPool extends EventEmitter { /** * The Mail instance using this transport, assigned by Mail */ - mailer?: Mail | undefined; + mailer?: Mail | undefined; constructor(options?: SMTPPoolOptions | string); /** * Placeholder function for creating proxy sockets. This method immediatelly returns @@ -96,7 +96,7 @@ declare class SMTPPool extends EventEmitter { * @param mail Mail object * @param callback Callback function */ - send(mail: MailMessage, callback: SMTPPoolSendCallback): boolean; + send(mail: MailMessage, callback: SMTPPoolSendCallback): boolean; /** * Closes all connections in the pool. If there is a message being sent, the connection * is closed later @@ -122,4 +122,6 @@ declare namespace SMTPPool { type MailOptions = SendMailOptions; type SentMessageInfo = SMTPPoolSentMessageInfo; } +/** The same aliases as module level exports, for `import * as SMTPPool` and `import SMTPPool = require()` */ +export type { SMTPPoolOptions as Options, SendMailOptions as MailOptions, SMTPPoolSentMessageInfo as SentMessageInfo }; export default SMTPPool; diff --git a/node_modules/nodemailer/dist/cjs/smtp-pool/index.js b/node_modules/nodemailer/dist/cjs/smtp-pool/index.js index 363fc258..818cc4ce 100644 --- a/node_modules/nodemailer/dist/cjs/smtp-pool/index.js +++ b/node_modules/nodemailer/dist/cjs/smtp-pool/index.js @@ -462,10 +462,12 @@ class SMTPPool extends node_events_1.EventEmitter { callback = shared.callbackPromise(resolve, reject); }); } + // the error paths hand over the error alone + const done = callback; const auth = new pool_resource_js_1.default(this).auth; this.getSocket(this.options, (err, socketOptions) => { if (err) { - return callback(err); + return done(err); } let options = this.options; if (socketOptions && socketOptions.connection) { @@ -487,14 +489,14 @@ class SMTPPool extends node_events_1.EventEmitter { } returned = true; connection.close(); - return callback(err); + return done(err); }); connection.once('end', () => { if (returned) { return; } returned = true; - return callback(new Error('Connection closed')); + return done(new Error('Connection closed')); }); const finalize = () => { if (returned) { @@ -502,7 +504,7 @@ class SMTPPool extends node_events_1.EventEmitter { } returned = true; connection.quit(); - return callback(null, true); + return done(null, true); }; connection.connect(() => { if (returned) { @@ -516,7 +518,7 @@ class SMTPPool extends node_events_1.EventEmitter { if (err) { returned = true; connection.close(); - return callback(err); + return done(err); } finalize(); }); @@ -526,7 +528,7 @@ class SMTPPool extends node_events_1.EventEmitter { err.code = errors.ENOAUTH; returned = true; connection.close(); - return callback(err); + return done(err); } else { finalize(); diff --git a/node_modules/nodemailer/dist/cjs/smtp-pool/pool-resource.js b/node_modules/nodemailer/dist/cjs/smtp-pool/pool-resource.js index 97ddf5c6..6374a5f4 100644 --- a/node_modules/nodemailer/dist/cjs/smtp-pool/pool-resource.js +++ b/node_modules/nodemailer/dist/cjs/smtp-pool/pool-resource.js @@ -138,9 +138,7 @@ class PoolResource extends node_events_1.EventEmitter { } // still have not returned, this means we have an unexpected connection close const err = new Error('Unexpected socket close'); - if (this.connection && - this.connection._socket && - this.connection._socket.upgrading) { + if (this.connection && this.connection.upgrading) { // starttls connection errors err.code = errors.ETLS; } diff --git a/node_modules/nodemailer/dist/cjs/smtp-transport/index.d.ts b/node_modules/nodemailer/dist/cjs/smtp-transport/index.d.ts index c3011ced..11bbb3c9 100644 --- a/node_modules/nodemailer/dist/cjs/smtp-transport/index.d.ts +++ b/node_modules/nodemailer/dist/cjs/smtp-transport/index.d.ts @@ -4,7 +4,7 @@ import * as shared from '../shared/index.js'; import { type XOAuth2Options } from '../xoauth2/index.js'; import type { ResultCallback } from '../errors.js'; import type MailMessage from '../mailer/mail-message.js'; -import type { default as Mail, SentMessageInfo, SendMailOptions, TransportOptions, VerifyCallback } from '../mailer/index.js'; +import type { default as Mail, GetSocketCallback, SentMessageInfo, SendMailOptions, TransportOptions, VerifyCallback } from '../mailer/index.js'; import type { MimeNodeEnvelope } from '../mime-node/index.js'; /** * Authentication settings, either from the transport options or from the message data. @@ -38,9 +38,10 @@ export interface SMTPTransportAuth extends SMTPConnectionAuth { /** * Receives the socket details from getSocket, false when a new socket should be opened. The * object is merged into the connection options, a proxy handler provides the connected socket - * as `connection` + * as `connection`. The same callback type Mail hands to a transport, so that the SMTP + * transports stay assignable to the Transport interface */ -export type SMTPTransportGetSocketCallback = (err: Error | null, socketOptions?: SMTPConnectionOptions | false) => void; +export type SMTPTransportGetSocketCallback = GetSocketCallback; /** * Custom socket provider, replaces the getSocket method of the transport */ @@ -78,6 +79,8 @@ export interface SMTPSentMessageInfo extends SMTPConnectionSendInfo, SentMessage accepted: string[]; /** Recipients the server rejected */ rejected: string[]; + /** Final server response for the message */ + response: string; } /** * Callback for send() @@ -101,7 +104,7 @@ declare class SMTPTransport extends EventEmitter { /** * The Mail instance using this transport, assigned by Mail */ - mailer?: Mail | undefined; + mailer?: Mail | undefined; constructor(options?: SMTPTransportOptions | string); /** * Placeholder function for creating proxy sockets. This method immediatelly returns @@ -118,7 +121,7 @@ declare class SMTPTransport extends EventEmitter { * @param mail Mail object * @param callback Callback function */ - send(mail: MailMessage, callback: SMTPTransportSendCallback): void; + send(mail: MailMessage, callback: SMTPTransportSendCallback): void; /** * Verifies SMTP configuration * @@ -139,5 +142,10 @@ declare namespace SMTPTransport { type MailOptions = SendMailOptions; type SentMessageInfo = SMTPSentMessageInfo; type AuthenticationType = SMTPTransportAuth; + type AuthenticationTypeLogin = SMTPTransportAuth; + type AuthenticationTypeOAuth2 = SMTPTransportAuth; + type AuthenticationTypeCustom = SMTPTransportAuth; } +/** The same aliases as module level exports, for `import * as SMTPTransport` and `import SMTPTransport = require()` */ +export type { SMTPTransportOptions as Options, SendMailOptions as MailOptions, SMTPSentMessageInfo as SentMessageInfo, SMTPTransportAuth as AuthenticationType, SMTPTransportAuth as AuthenticationTypeLogin, SMTPTransportAuth as AuthenticationTypeOAuth2, SMTPTransportAuth as AuthenticationTypeCustom }; export default SMTPTransport; diff --git a/node_modules/nodemailer/dist/cjs/smtp-transport/index.js b/node_modules/nodemailer/dist/cjs/smtp-transport/index.js index e98a5c9a..b341b8f0 100644 --- a/node_modules/nodemailer/dist/cjs/smtp-transport/index.js +++ b/node_modules/nodemailer/dist/cjs/smtp-transport/index.js @@ -189,7 +189,7 @@ class SMTPTransport extends node_events_1.EventEmitter { cleanupPerCallAuth(); // still have not returned, this means we have an unexpected connection close const err = new Error('Unexpected socket close'); - if (connection && connection._socket && connection._socket.upgrading) { + if (connection && connection.upgrading) { // starttls connection errors err.code = errors.ETLS; } @@ -279,9 +279,11 @@ class SMTPTransport extends node_events_1.EventEmitter { callback = shared.callbackPromise(resolve, reject); }); } + // the error paths hand over the error alone + const done = callback; this.getSocket(this.options, (err, socketOptions) => { if (err) { - return callback(err); + return done(err); } let options = this.options; if (socketOptions && socketOptions.connection) { @@ -311,7 +313,7 @@ class SMTPTransport extends node_events_1.EventEmitter { returned = true; cleanupPerCallAuth(); connection.close(); - return callback(err); + return done(err); }); connection.once('end', () => { if (returned) { @@ -319,7 +321,7 @@ class SMTPTransport extends node_events_1.EventEmitter { } returned = true; cleanupPerCallAuth(); - return callback(new Error('Connection closed')); + return done(new Error('Connection closed')); }); const finalize = () => { if (returned) { @@ -328,7 +330,7 @@ class SMTPTransport extends node_events_1.EventEmitter { returned = true; cleanupPerCallAuth(); connection.quit(); - return callback(null, true); + return done(null, true); }; connection.connect(() => { if (returned) { @@ -344,7 +346,7 @@ class SMTPTransport extends node_events_1.EventEmitter { if (err) { returned = true; connection.close(); - return callback(err); + return done(err); } finalize(); }); @@ -355,7 +357,7 @@ class SMTPTransport extends node_events_1.EventEmitter { returned = true; cleanupPerCallAuth(); connection.close(); - return callback(err); + return done(err); } else { finalize(); diff --git a/node_modules/nodemailer/dist/cjs/stream-transport/index.d.ts b/node_modules/nodemailer/dist/cjs/stream-transport/index.d.ts index 0f305476..11a326c4 100644 --- a/node_modules/nodemailer/dist/cjs/stream-transport/index.d.ts +++ b/node_modules/nodemailer/dist/cjs/stream-transport/index.d.ts @@ -60,4 +60,6 @@ declare namespace StreamTransport { type MailOptions = SendMailOptions; type SentMessageInfo = StreamSentMessageInfo; } +/** The same aliases as module level exports, for `import * as StreamTransport` and `import StreamTransport = require()` */ +export type { StreamTransportOptions as Options, SendMailOptions as MailOptions, StreamSentMessageInfo as SentMessageInfo }; export default StreamTransport; diff --git a/node_modules/nodemailer/dist/cjs/xoauth2/index.d.ts b/node_modules/nodemailer/dist/cjs/xoauth2/index.d.ts index b02f26c6..4538d712 100644 --- a/node_modules/nodemailer/dist/cjs/xoauth2/index.d.ts +++ b/node_modules/nodemailer/dist/cjs/xoauth2/index.d.ts @@ -1,6 +1,7 @@ import { Stream } from 'node:stream'; import crypto from 'node:crypto'; import * as shared from '../shared/index.js'; +import type { ResultCallback } from '../errors.js'; import type { OutgoingHttpHeaders } from 'node:http'; /** * Receives the result of a provisionCallback run: an error, or the new access token and @@ -13,9 +14,11 @@ export type XOAuth2ProvisionResultCallback = (err: Error | null, accessToken?: s */ export type XOAuth2ProvisionCallback = (user: string, renew: boolean, callback: XOAuth2ProvisionResultCallback) => void; /** - * Receives an access token, or the error that prevented generating one + * Receives an access token, or the error that prevented generating one. Declared with a + * required token, the way @types/nodemailer declared it, the error path hands over the + * error alone */ -export type XOAuth2TokenCallback = (err: Error | null, accessToken?: string) => void; +export type XOAuth2TokenCallback = (err: Error | null, accessToken: string) => void; /** * A private key accepted by crypto.createSign().sign() */ @@ -79,7 +82,7 @@ export interface XOAuth2Token { */ export interface XOAuth2QueuedRequest { renew: boolean; - callback: XOAuth2TokenCallback; + callback: ResultCallback; } /** * XOAUTH2 access_token generator for Gmail. @@ -181,11 +184,16 @@ declare class XOAuth2 extends Stream { [key: string]: any; }): string; } +/** The extra request settings of the token request, the customHeaders and customParams options */ +export type XOAuth2RequestParams = Pick; /** * Type aliases in the layout of @types/nodemailer, so `XOAuth2.Options` style references keep working */ declare namespace XOAuth2 { type Options = XOAuth2Options; type Token = XOAuth2Token; + type RequestParams = XOAuth2RequestParams; } +/** The same aliases as module level exports, for `import * as XOAuth2` and `import XOAuth2 = require()` */ +export type { XOAuth2Options as Options, XOAuth2Token as Token, XOAuth2RequestParams as RequestParams }; export default XOAuth2; diff --git a/node_modules/nodemailer/dist/cjs/xoauth2/index.js b/node_modules/nodemailer/dist/cjs/xoauth2/index.js index 40671b49..a6477be0 100644 --- a/node_modules/nodemailer/dist/cjs/xoauth2/index.js +++ b/node_modules/nodemailer/dist/cjs/xoauth2/index.js @@ -111,6 +111,8 @@ class XOAuth2 extends node_stream_1.Stream { * @param callback Callback function with error object and token string */ getToken(renew, callback) { + // the error paths hand over the error alone + const done = callback; if (!renew && this.accessToken && (!this.expires || this.expires > Date.now())) { this.logger.debug({ tnx: 'OAUTH2', @@ -136,11 +138,11 @@ class XOAuth2 extends node_stream_1.Stream { }, 'Cannot renew access token for %s: No refresh mechanism available', this.options.user); const err = new Error("Can't create new access token for user"); err.code = errors.EOAUTH2; - return callback(err); + return done(err); } // If renewal already in progress, queue this request instead of starting another if (this.renewing) { - this.renewalQueue.push({ renew, callback }); + this.renewalQueue.push({ renew, callback: done }); return; } this.renewing = true; @@ -165,7 +167,7 @@ class XOAuth2 extends node_stream_1.Stream { }, 'Generated new Access Token for %s', this.options.user); } // Complete original request - callback(err, accessToken); + done(err, accessToken); }; if (this.provisionCallback) { this.provisionCallback(this.options.user, !!renew, (err, accessToken, expires) => { @@ -204,6 +206,8 @@ class XOAuth2 extends node_stream_1.Stream { * @param callback Callback function with error object and token string */ generateToken(callback) { + // the error paths hand over the error alone + const done = callback; let urlOptions; let loggedUrlOptions; if (this.options.serviceClient) { @@ -224,7 +228,7 @@ class XOAuth2 extends node_stream_1.Stream { catch (_err) { const err = new Error("Can't generate token. Check your auth options"); err.code = errors.EOAUTH2; - return callback(err); + return done(err); } urlOptions = { grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer', @@ -239,7 +243,7 @@ class XOAuth2 extends node_stream_1.Stream { if (!this.options.refreshToken) { const err = new Error("Can't create new access token for user"); err.code = errors.EOAUTH2; - return callback(err); + return done(err); } // web app - https://developers.google.com/identity/protocols/OAuth2WebServer urlOptions = { @@ -265,13 +269,13 @@ class XOAuth2 extends node_stream_1.Stream { this.postRequest(this.options.accessUrl, urlOptions, this.options, (error, body) => { let data; if (error) { - return callback(error); + return done(error); } try { data = JSON.parse(body.toString()); } catch (E) { - return callback(E); + return done(E); } if (!data || typeof data !== 'object') { this.logger.debug({ @@ -281,7 +285,7 @@ class XOAuth2 extends node_stream_1.Stream { }, 'Response: %s', (body || '').toString()); const err = new Error('Invalid authentication response'); err.code = errors.EOAUTH2; - return callback(err); + return done(err); } const logData = Object.assign({}, data); if (logData.access_token) { @@ -303,7 +307,7 @@ class XOAuth2 extends node_stream_1.Stream { } const err = new Error(errorMessage); err.code = errors.EOAUTH2; - return callback(err); + return done(err); } if (data.access_token) { this.updateToken(data.access_token, data.expires_in); @@ -311,7 +315,7 @@ class XOAuth2 extends node_stream_1.Stream { } const err = new Error('No access token'); err.code = errors.EOAUTH2; - return callback(err); + return done(err); }); } /** diff --git a/node_modules/nodemailer/dist/esm/addressparser/index.d.ts b/node_modules/nodemailer/dist/esm/addressparser/index.d.ts index adc98336..583c45b7 100644 --- a/node_modules/nodemailer/dist/esm/addressparser/index.d.ts +++ b/node_modules/nodemailer/dist/esm/addressparser/index.d.ts @@ -42,4 +42,19 @@ export type Address = MailboxAddress | GroupAddress; * @param options._depth Internal recursion depth counter (do not set manually) * @return An array of address objects */ -export default function addressparser(str?: string | null, options?: AddressParserOptions): Address[]; +declare function addressparser(str: string | null | undefined, options: AddressParserOptions & { + flatten: true; +}): MailboxAddress[]; +declare function addressparser(str?: string | null, options?: AddressParserOptions): Address[]; +/** + * Type aliases in the layout of @types/nodemailer, so `addressparser.Address` style references keep working + */ +type AddressEntry = Address; +declare namespace addressparser { + type Address = MailboxAddress; + type Group = GroupAddress; + type AddressOrGroup = AddressEntry; +} +/** The names @types/nodemailer used for the group entry and for the union of both entry types */ +export type { GroupAddress as Group, Address as AddressOrGroup }; +export default addressparser; diff --git a/node_modules/nodemailer/dist/esm/addressparser/index.js b/node_modules/nodemailer/dist/esm/addressparser/index.js index 9babfc61..7afa44ff 100644 --- a/node_modules/nodemailer/dist/esm/addressparser/index.js +++ b/node_modules/nodemailer/dist/esm/addressparser/index.js @@ -580,23 +580,7 @@ class Tokenizer { * malicious input that could cause stack overflow. */ const MAX_NESTED_GROUP_DEPTH = 50; -/** - * Parses structured e-mail addresses from an address field - * - * Example: - * - * 'Name ' - * - * will be converted to - * - * [{name: 'Name', address: 'address@domain'}] - * - * @param str Address field - * @param options Optional options object - * @param options._depth Internal recursion depth counter (do not set manually) - * @return An array of address objects - */ -export default function addressparser(str, options) { +function addressparser(str, options) { options = options || {}; const depth = options._depth || 0; // Prevent stack overflow from deeply nested groups (DoS protection) @@ -664,3 +648,4 @@ export default function addressparser(str, options) { } return parsedAddresses; } +export default addressparser; diff --git a/node_modules/nodemailer/dist/esm/base64/index.js b/node_modules/nodemailer/dist/esm/base64/index.js index 48f69cc3..75165fd9 100644 --- a/node_modules/nodemailer/dist/esm/base64/index.js +++ b/node_modules/nodemailer/dist/esm/base64/index.js @@ -20,7 +20,8 @@ export function encode(buffer) { */ export function wrap(str, lineLength) { str = (str || '').toString(); - lineLength = lineLength || 76; + // a negative length would step backwards through the input and never finish + lineLength = Math.max(Number(lineLength) || 76, 1); if (str.length <= lineLength) { return str; } diff --git a/node_modules/nodemailer/dist/esm/dkim/index.d.ts b/node_modules/nodemailer/dist/esm/dkim/index.d.ts index 78a4b673..dd3df3a6 100644 --- a/node_modules/nodemailer/dist/esm/dkim/index.d.ts +++ b/node_modules/nodemailer/dist/esm/dkim/index.d.ts @@ -30,11 +30,23 @@ declare class DKIM { constructor(options: DKIMOptions); sign(input: Readable | Buffer | string, extraOptions?: DKIMOptions): DKIMSignedStream; } +/** The signer options without any key material */ +export type DKIMOptionalOptions = Omit; +/** The signer options for a single key given as domainName, keySelector and privateKey */ +export type DKIMSingleKeyOptions = Omit; +/** The signer options for one or more keys given through `keys` */ +export type DKIMMultipleKeysOptions = DKIMOptionalOptions & { + keys: DKIMKey | DKIMKey[]; +}; /** * Type aliases in the layout of @types/nodemailer, so `DKIM.Options` style references keep working */ declare namespace DKIM { type Options = DKIMOptions; - type SingleKeyOptions = Omit; + type OptionalOptions = DKIMOptionalOptions; + type SingleKeyOptions = DKIMSingleKeyOptions; + type MultipleKeysOptions = DKIMMultipleKeysOptions; } +/** The same aliases as module level exports, for `import * as DKIM` and `import DKIM = require()` */ +export type { DKIMOptions as Options, DKIMOptionalOptions as OptionalOptions, DKIMSingleKeyOptions as SingleKeyOptions, DKIMMultipleKeysOptions as MultipleKeysOptions }; export default DKIM; diff --git a/node_modules/nodemailer/dist/esm/dkim/message-parser.d.ts b/node_modules/nodemailer/dist/esm/dkim/message-parser.d.ts index 21e061b1..d17ab5ea 100644 --- a/node_modules/nodemailer/dist/esm/dkim/message-parser.d.ts +++ b/node_modules/nodemailer/dist/esm/dkim/message-parser.d.ts @@ -13,7 +13,7 @@ export interface MessageParserHeaderLine { * from the rest of the body. Headers are emitted with the 'headers' event. Message * body is passed on as the resulting stream. */ -export default class MessageParser extends Transform { +declare class MessageParser extends Transform { lastBytes: Buffer; headersParsed: boolean; headerBytes: number; @@ -37,3 +37,12 @@ export default class MessageParser extends Transform { checkHeaders(data: Buffer): boolean; parseHeaders(): MessageParserHeaderLine[]; } +/** + * Type aliases in the layout of @types/nodemailer, so `MessageParser.Header` style references keep working + */ +declare namespace MessageParser { + type Header = MessageParserHeaderLine; +} +/** The same alias as a module level export, for `import * as MessageParser` and `import MessageParser = require()` */ +export type { MessageParserHeaderLine as Header }; +export default MessageParser; diff --git a/node_modules/nodemailer/dist/esm/dkim/message-parser.js b/node_modules/nodemailer/dist/esm/dkim/message-parser.js index 53316417..eccc1b16 100644 --- a/node_modules/nodemailer/dist/esm/dkim/message-parser.js +++ b/node_modules/nodemailer/dist/esm/dkim/message-parser.js @@ -4,7 +4,7 @@ import { Transform } from 'node:stream'; * from the rest of the body. Headers are emitted with the 'headers' event. Message * body is passed on as the resulting stream. */ -export default class MessageParser extends Transform { +class MessageParser extends Transform { constructor(options) { super(options); this.lastBytes = Buffer.alloc(4); @@ -149,3 +149,4 @@ export default class MessageParser extends Transform { })); } } +export default MessageParser; diff --git a/node_modules/nodemailer/dist/esm/dkim/relaxed-body.d.ts b/node_modules/nodemailer/dist/esm/dkim/relaxed-body.d.ts index c5985a4f..d8fb0e24 100644 --- a/node_modules/nodemailer/dist/esm/dkim/relaxed-body.d.ts +++ b/node_modules/nodemailer/dist/esm/dkim/relaxed-body.d.ts @@ -17,7 +17,7 @@ export interface RelaxedBodyOptions { * a non-empty body always ends with CRLF. Bytes are canonicalized as they arrive, * so a line of any length costs constant memory. */ -export default class RelaxedBody extends Transform { +declare class RelaxedBody extends Transform { bodyHash: crypto.Hash; /** Bytes of the original body seen so far */ byteLength: number; @@ -25,3 +25,12 @@ export default class RelaxedBody extends Transform { constructor(options?: RelaxedBodyOptions); updateHash(chunk: Buffer, final?: boolean): void; } +/** + * Type aliases in the layout of @types/nodemailer, so `RelaxedBody.Options` style references keep working + */ +declare namespace RelaxedBody { + type Options = RelaxedBodyOptions; +} +/** The same alias as a module level export, for `import * as RelaxedBody` and `import RelaxedBody = require()` */ +export type { RelaxedBodyOptions as Options }; +export default RelaxedBody; diff --git a/node_modules/nodemailer/dist/esm/dkim/relaxed-body.js b/node_modules/nodemailer/dist/esm/dkim/relaxed-body.js index 50c40ef5..1e085bb3 100644 --- a/node_modules/nodemailer/dist/esm/dkim/relaxed-body.js +++ b/node_modules/nodemailer/dist/esm/dkim/relaxed-body.js @@ -16,7 +16,7 @@ const EMPTY_LINES = Buffer.alloc(4096, CRLF); * a non-empty body always ends with CRLF. Bytes are canonicalized as they arrive, * so a line of any length costs constant memory. */ -export default class RelaxedBody extends Transform { +class RelaxedBody extends Transform { constructor(options) { super(); options = options || {}; @@ -138,3 +138,4 @@ export default class RelaxedBody extends Transform { callback(); } } +export default RelaxedBody; diff --git a/node_modules/nodemailer/dist/esm/errors.d.ts b/node_modules/nodemailer/dist/esm/errors.d.ts index c85653cc..93a74257 100644 --- a/node_modules/nodemailer/dist/esm/errors.d.ts +++ b/node_modules/nodemailer/dist/esm/errors.d.ts @@ -64,9 +64,10 @@ export declare const EFETCH = "EFETCH"; /** * An Error together with the properties Nodemailer attaches to the errors it * hands to callers. Every property is optional, the set that is present - * depends on where the error originated. + * depends on where the error originated. Socket level errors keep the errno + * and syscall fields Node.js sets on them. */ -export interface NodemailerError extends Error { +export interface NodemailerError extends NodeJS.ErrnoException { /** Nodemailer error code, see ERROR_CODES */ code?: string | undefined; /** SMTP command that was in flight when the server replied with an error */ diff --git a/node_modules/nodemailer/dist/esm/fetch/cookies.d.ts b/node_modules/nodemailer/dist/esm/fetch/cookies.d.ts index 3d631296..4e694d6a 100644 --- a/node_modules/nodemailer/dist/esm/fetch/cookies.d.ts +++ b/node_modules/nodemailer/dist/esm/fetch/cookies.d.ts @@ -17,13 +17,14 @@ export interface Cookie { secure?: boolean | undefined; httponly?: boolean | undefined; } +type CookieEntry = Cookie; /** * Creates a biskviit cookie jar for managing cookie values in memory * * @constructor * @param [options] Optional options object */ -export default class Cookies { +declare class Cookies { options: CookiesOptions; cookies: Cookie[]; constructor(options?: CookiesOptions); @@ -94,3 +95,13 @@ export default class Cookies { */ getPath(pathname?: string | null): string; } +/** + * Type aliases in the layout of @types/nodemailer, so `Cookies.Cookie` style references keep working + */ +declare namespace Cookies { + type Options = CookiesOptions; + type Cookie = CookieEntry; +} +/** The same alias as a module level export, for `import * as Cookies` and `import Cookies = require()` */ +export type { CookiesOptions as Options }; +export default Cookies; diff --git a/node_modules/nodemailer/dist/esm/fetch/cookies.js b/node_modules/nodemailer/dist/esm/fetch/cookies.js index 0a6322de..15edd60f 100644 --- a/node_modules/nodemailer/dist/esm/fetch/cookies.js +++ b/node_modules/nodemailer/dist/esm/fetch/cookies.js @@ -8,7 +8,7 @@ const SESSION_TIMEOUT = 1800; // 30 min * @constructor * @param [options] Optional options object */ -export default class Cookies { +class Cookies { constructor(options) { this.options = options || {}; this.cookies = []; @@ -239,3 +239,4 @@ export default class Cookies { return path; } } +export default Cookies; diff --git a/node_modules/nodemailer/dist/esm/fetch/index.d.ts b/node_modules/nodemailer/dist/esm/fetch/index.d.ts index 0490e708..4f0cc61c 100644 --- a/node_modules/nodemailer/dist/esm/fetch/index.d.ts +++ b/node_modules/nodemailer/dist/esm/fetch/index.d.ts @@ -48,4 +48,15 @@ declare function nmfetch(url: string, options?: FetchOptions): FetchResponse; declare namespace nmfetch { var Cookies: typeof import("./cookies.js").default; } +type CookiesJar = Cookies; +/** + * Type aliases in the layout of @types/nodemailer, so `fetch.Options` style references keep working + */ +declare namespace nmfetch { + type Options = FetchOptions; + type WritableResponse = FetchResponse; + type Cookies = CookiesJar; +} +/** The same aliases as module level exports, for `import * as fetch` and `import fetch = require()` */ +export type { FetchOptions as Options, FetchResponse as WritableResponse, Cookies }; export default nmfetch; diff --git a/node_modules/nodemailer/dist/esm/fetch/index.js b/node_modules/nodemailer/dist/esm/fetch/index.js index 7dcb67c9..a38e44cd 100644 --- a/node_modules/nodemailer/dist/esm/fetch/index.js +++ b/node_modules/nodemailer/dist/esm/fetch/index.js @@ -155,14 +155,14 @@ function nmfetch(url, options) { .join('&')); } catch (E) { - if (finished) { - return undefined; - } + // the caller attaches its error listener once nmfetch has returned, so + // the error is emitted on the next tick and the stream is handed back + // the way every other failure is reported finished = true; E.code = errors.EFETCH; E.sourceUrl = url; - fetchRes.emit('error', E); - return undefined; + setImmediate(() => fetchRes.emit('error', E)); + return fetchRes; } } else { diff --git a/node_modules/nodemailer/dist/esm/json-transport/index.d.ts b/node_modules/nodemailer/dist/esm/json-transport/index.d.ts index 5adc73af..5160aa8e 100644 --- a/node_modules/nodemailer/dist/esm/json-transport/index.d.ts +++ b/node_modules/nodemailer/dist/esm/json-transport/index.d.ts @@ -1,6 +1,6 @@ import type { Logger } from '../shared/index.js'; import type { MimeNodeEnvelope } from '../mime-node/index.js'; -import type { default as MailMessage, MailMessageData } from '../mailer/mail-message.js'; +import type MailMessage from '../mailer/mail-message.js'; import type { default as Mail, SentMessageInfo, SendMailOptions, TransportOptions } from '../mailer/index.js'; /** * Options for the JSON transport @@ -12,16 +12,23 @@ export interface JSONTransportOptions extends TransportOptions { skipEncoding?: boolean | undefined; } /** - * The value the JSON transport hands to the send callback + * The value the JSON transport hands to the send callback. M is the type of the message + * field: a JSON string by default, the message object itself when skipEncoding is set */ -export interface JSONSentMessageInfo extends SentMessageInfo { +export interface JSONSentMessageInfo extends SentMessageInfo { /** The envelope the message was generated with */ envelope: MimeNodeEnvelope; /** Message-ID value of the message */ messageId: string; /** The normalized message as a JSON string, or as the object itself when skipEncoding is set */ - message: string | MailMessageData; + message: M; } +/** + * The value the JSON transport hands to the send callback when skipEncoding is set: the + * message field holds the message object. Typed loosely so that a transporter created with + * skipEncoding still fits a variable declared with the plain result type + */ +export type JSONSentMessageObjectInfo = JSONSentMessageInfo; /** * Generates a Transport object to generate JSON output * @@ -50,5 +57,8 @@ declare namespace JSONTransport { type Options = JSONTransportOptions; type MailOptions = SendMailOptions; type SentMessageInfo = JSONSentMessageInfo; + type SentMessageObjectInfo = JSONSentMessageObjectInfo; } +/** The same aliases as module level exports, for `import * as JSONTransport` and `import JSONTransport = require()` */ +export type { JSONTransportOptions as Options, SendMailOptions as MailOptions, JSONSentMessageInfo as SentMessageInfo, JSONSentMessageObjectInfo as SentMessageObjectInfo }; export default JSONTransport; diff --git a/node_modules/nodemailer/dist/esm/json-transport/index.js b/node_modules/nodemailer/dist/esm/json-transport/index.js index 027c1daf..d0d1db31 100644 --- a/node_modules/nodemailer/dist/esm/json-transport/index.js +++ b/node_modules/nodemailer/dist/esm/json-transport/index.js @@ -48,6 +48,8 @@ class JSONTransport { } delete data.envelope; delete data.normalizedHeaders; + // the message field is the object itself with skipEncoding, the + // createTransport overload for that option types the result accordingly return done(null, { envelope, messageId, diff --git a/node_modules/nodemailer/dist/esm/mail-composer/index.d.ts b/node_modules/nodemailer/dist/esm/mail-composer/index.d.ts index c076115d..817d5fdc 100644 --- a/node_modules/nodemailer/dist/esm/mail-composer/index.d.ts +++ b/node_modules/nodemailer/dist/esm/mail-composer/index.d.ts @@ -72,6 +72,11 @@ export type MailComposerListHeaderEntry = string | { export interface MailComposerListHeaders { [key: string]: MailComposerListHeaderEntry | (MailComposerListHeaderEntry | MailComposerListHeaderEntry[])[]; } +/** + * Encoding for the non-ascii header values: quoted-printable ('Q', the default) or base64 + * ('B'). Only the first letter is read, so the short forms work as well + */ +export type MailComposerTextEncoding = 'quoted-printable' | 'base64' | 'Q' | 'B'; /** * Mail options, the message data MailComposer builds the MIME tree from. The address * fields, subject, messageId, date, inReplyTo and references become headers of the root @@ -114,7 +119,7 @@ export interface MailComposerOptions { /** Content-Transfer-Encoding to force for the text/* nodes that do not set their own */ encoding?: string | undefined; /** Header string encoding, 'Q' (the default) or 'B', 'quoted-printable' and 'base64' are accepted as well */ - textEncoding?: string | undefined; + textEncoding?: MailComposerTextEncoding | undefined; /** Pregenerated rfc822 message, used as is instead of building one */ raw?: MimeNodeContent | undefined; /** Reject content that points to a URL */ @@ -129,8 +134,6 @@ export interface MailComposerOptions { baseBoundary?: string | undefined; /** 'win' for CRLF and 'linux' for LF line breaks in the generated message, kept as is when not set */ newline?: string | undefined; - /** Keep the Bcc header in the generated message, listed for completeness, the transports set it on the message directly */ - keepBcc?: boolean | undefined; /** Method to normalize header keys for custom caseing */ normalizeHeaderKey?: MimeNodeOptions['normalizeHeaderKey'] | undefined; /** 'high', 'normal' or 'low', sets the priority headers, read by the mailer */ @@ -166,4 +169,6 @@ declare class MailComposer { declare namespace MailComposer { type Options = MailComposerOptions; } +/** The same alias as a module level export, for `import * as MailComposer` and `import MailComposer = require()` */ +export type { MailComposerOptions as Options }; export default MailComposer; diff --git a/node_modules/nodemailer/dist/esm/mailer/index.d.ts b/node_modules/nodemailer/dist/esm/mailer/index.d.ts index 300d8050..58684f49 100644 --- a/node_modules/nodemailer/dist/esm/mailer/index.d.ts +++ b/node_modules/nodemailer/dist/esm/mailer/index.d.ts @@ -4,8 +4,8 @@ import DKIM, { type DKIMOptions } from '../dkim/index.js'; import MailMessage, { type MailDefaults, type SendMailOptions } from './mail-message.js'; import net from 'node:net'; import type { ConnectionOptions } from 'node:tls'; -import type { MailComposerAlternative, MailComposerAttachment, MailComposerIcalEvent, MailComposerListHeaderEntry, MailComposerListHeaders } from '../mail-composer/index.js'; -import type { NodemailerError, ResultCallback } from '../errors.js'; +import type { MailComposerAlternative, MailComposerAttachment, MailComposerIcalEvent, MailComposerListHeaderEntry, MailComposerListHeaders, MailComposerTextEncoding } from '../mail-composer/index.js'; +import type { Callback, NodemailerError, ResultCallback } from '../errors.js'; import type { ParsedUrl } from '../shared/url.js'; import type { MimeNodeAddress, MimeNodeEnvelope, MimeNodeEnvelopeInput, MimeNodeHeaders, MimeNodeOptions } from '../mime-node/index.js'; import type { XOAuth2ProvisionCallback } from '../xoauth2/index.js'; @@ -15,9 +15,10 @@ export type { default as MailMessage } from './mail-message.js'; * The base shape of the object a transport hands back for a sent message. Every bundled * transport sets the envelope and the Message-ID, the rest depends on the transport. * - * The index signature keeps a transport specific field readable through this type, and it - * is also what a result type has to inherit to stay assignable to it, so the result type - * of a transport outside this package has to extend this interface rather than restate it + * The index signature keeps a transport specific field readable through this type, the way + * the `any` typed result of @types/nodemailer was, and it is also what a result type has + * to inherit to stay assignable to it, so the result type of a transport outside this + * package has to extend this interface rather than restate it */ export interface SentMessageInfo { /** The envelope the message was sent with */ @@ -33,9 +34,9 @@ export interface SentMessageInfo { /** Last response from the server */ response?: string | undefined; /** The generated message, for the transports that hand it back instead of sending it */ - message?: unknown; + message?: any; /** Transport specific fields */ - [key: string]: unknown; + [key: string]: any; } /** * Callback for sendMail, receives the transport result once the transport has taken the @@ -43,9 +44,11 @@ export interface SentMessageInfo { */ export type SendMailCallback = (err: NodemailerError | null, info: T) => void; /** - * Callback for verify(), success is true once the transport accepted the configuration + * Callback for verify(), success is true once the transport accepted the configuration. + * Declared with a required success value, the way @types/nodemailer declared it, the + * error path hands over the error alone */ -export type VerifyCallback = (err: NodemailerError | null, success?: true) => void; +export type VerifyCallback = Callback; /** * Callback a plugin calls once it is done, an error aborts the send */ @@ -60,21 +63,23 @@ export type PluginFunction = (mail: MailMessage, callbac */ export interface GetSocketOptions { host?: string | undefined; - port?: number | string | undefined; + port?: number | undefined; [key: string]: any; } /** - * The result of a getSocket handler, the socket to use for the connection + * The result of a getSocket handler, the socket to use for the connection. The object is + * merged into the connection options, so it may carry any of those as well */ export interface SocketOptions { /** An established socket, the proxied connection */ connection?: net.Socket | undefined; + [key: string]: any; } /** - * Receives the socket options from a getSocket handler, or the error that prevented the - * connection + * Receives the socket options from a getSocket handler, false when a new socket should be + * opened, or the error that prevented the connection */ -export type GetSocketCallback = (err: NodemailerError | null, socketOptions?: SocketOptions) => void; +export type GetSocketCallback = (err: Error | null, socketOptions?: SocketOptions | false) => void; /** * A socket handler. Mail sets one on the transport as getSocket when a proxy is configured, * the SMTP transports call it to get a proxied socket instead of connecting directly @@ -101,9 +106,12 @@ export interface MailMeta { /** * A transport as consumed by Mail: any object with a name, a version and a send method * works, the rest is optional. Mail forwards its close, isIdle and verify calls to the - * methods of the same name as they are, so their arguments are up to the transport + * methods of the same name as they are, so their arguments are up to the transport. + * + * D is the options type of the transport, the second type parameter @types/nodemailer + * declared on Transport, Transporter and Mail */ -export interface Transport { +export interface Transport { /** Transport name, used for logging */ name: string; /** Transport version, used for logging */ @@ -119,7 +127,7 @@ export interface Transport { /** Registers an event listener, the transport may emit 'log', 'error', 'idle' and 'clear' */ on?(event: string | symbol, listener: (...args: any[]) => void): this; /** The Mail object the transport belongs to, set by Mail */ - mailer?: Mail | undefined; + mailer?: Mail | undefined; /** Socket handler for a proxied connection, set by Mail when a proxy is configured */ getSocket?: GetSocketHandler | undefined; } @@ -150,22 +158,23 @@ export interface TransportOptions { attachDataUrls?: boolean | undefined; } /** - * The transporter object createTransport returns, a Mail instance wrapping a transport + * The transporter object createTransport returns, a Mail instance wrapping a transport. D + * is the options type of the transport, it types the options field of the transporter */ -export type Transporter = Mail; +export type Transporter = Mail; /** * Creates an object for exposing the Mail API * * @constructor * @param transporter Transport object instance to pass the mails to */ -declare class Mail extends EventEmitter { - options: TransportOptions; +declare class Mail extends EventEmitter { + options: D; /** Message defaults given to createTransport, kept public because the DefinitelyTyped typings declared it */ _defaults: MailDefaults; meta: Map; dkim: DKIM | false; - transporter: Transport; + transporter: Transport; logger: shared.Logger; /** Closes the transport, the pooled SMTP transport closes its connections */ close: () => void; @@ -178,7 +187,7 @@ declare class Mail extends EventEmitter { }; /** Socket handler for a proxied connection, set by setupProxy and handed to the transport on the next send */ getSocket?: GetSocketHandler | false | undefined; - constructor(transporter: Transport, options?: TransportOptions, defaults?: MailDefaults); + constructor(transporter: Transport, options?: D, defaults?: MailDefaults); use(step: string, plugin: PluginFunction): this; /** * Sends an email using the preselected transport object @@ -213,7 +222,10 @@ declare namespace Mail { type ListHeader = MailComposerListHeaderEntry; type ListHeaders = MailComposerListHeaders; type Envelope = MimeNodeEnvelopeInput; - type TextEncoding = NonNullable; + type Connection = SocketOptions; + type TextEncoding = MailComposerTextEncoding; type PluginFunction = MailPluginFunction; } +/** The same aliases as module level exports, for `import * as Mail` and `import Mail = require()` */ +export type { SendMailOptions as Options, MimeNodeAddress as Address, MailComposerAttachment as Attachment, MailComposerAlternative as AttachmentLike, MailComposerAlternative as AmpAttachment, MailComposerIcalEvent as IcalAttachment, MimeNodeHeaders as Headers, MailComposerListHeaderEntry as ListHeader, MailComposerListHeaders as ListHeaders, MimeNodeEnvelopeInput as Envelope, SocketOptions as Connection, MailComposerTextEncoding as TextEncoding }; export default Mail; diff --git a/node_modules/nodemailer/dist/esm/mailer/mail-message.d.ts b/node_modules/nodemailer/dist/esm/mailer/mail-message.d.ts index 4db9dd31..6c20de37 100644 --- a/node_modules/nodemailer/dist/esm/mailer/mail-message.d.ts +++ b/node_modules/nodemailer/dist/esm/mailer/mail-message.d.ts @@ -3,6 +3,7 @@ import type { MailComposerOptions } from '../mail-composer/index.js'; import type { DKIMOptions } from '../dkim/index.js'; import type { SMTPEnvelopeDsn } from '../smtp-connection/index.js'; import type { SMTPTransportAuthOptions } from '../smtp-transport/index.js'; +import type { SESSendEmailRequest } from '../ses-transport/index.js'; import type { NodemailerError } from '../errors.js'; import type { ResolveContentOptions } from '../shared/index.js'; import type Mail from './index.js'; @@ -14,6 +15,8 @@ import type { SentMessageInfo } from './index.js'; export interface SendMailOptions extends MailComposerOptions { /** DKIM signing options for this message, used instead of the ones of the transporter */ dkim?: DKIMOptions | undefined; + /** Extra DKIM options for this message, merged over the options of the signer. The SES transport sets skipFields here, the option is not meant for callers */ + _dkim?: DKIMOptions | undefined; /** Recipients allowed on this message, 0 disables the limit, defaults to 100000 */ maxRecipients?: number | undefined; /** SMTP transports: DSN parameters for the envelope, sent when the server supports the DSN extension */ @@ -23,9 +26,7 @@ export interface SendMailOptions extends MailComposerOptions { /** SMTP transports: per-message authentication settings, used instead of the transport level auth */ auth?: SMTPTransportAuthOptions | undefined; /** SES transport: extra SendEmailCommand parameters merged into the API call */ - ses?: { - [key: string]: unknown; - } | undefined; + ses?: SESSendEmailRequest | undefined; } /** * Default message fields, the third argument of createTransport. Applied to every message @@ -71,7 +72,13 @@ export interface MailMessageListHeader { export default class MailMessage { mailer: Mail; data: MailMessageData; - message: MimeNode | null; + /** + * The compiled MIME tree. Set once the compile step is done, so it is null while the + * 'compile' plugins run and set by the time the 'stream' plugins and the transport see + * the message. Declared as always set, the way @types/nodemailer declared it, since the + * plugins that read it are the ones that run after it is set + */ + message: MimeNode; constructor(mailer: Mail, data?: SendMailOptions); resolveContent(data: { [key: string]: any; diff --git a/node_modules/nodemailer/dist/esm/mime-funcs/index.d.ts b/node_modules/nodemailer/dist/esm/mime-funcs/index.d.ts index 3c7b2793..a9a79e72 100644 --- a/node_modules/nodemailer/dist/esm/mime-funcs/index.d.ts +++ b/node_modules/nodemailer/dist/esm/mime-funcs/index.d.ts @@ -2,8 +2,8 @@ * A header value split into the value token and its parameters, the result of parseHeaderValue */ export interface ParsedHeaderValue { - /** The value ahead of the parameters, for example the content type */ - value: string | false; + /** The value ahead of the parameters, for example the content type, an empty string when there is none */ + value: string; /** Parameter values keyed by lowercase parameter name */ params: Record; } @@ -25,6 +25,9 @@ export interface EncodedHeaderParam { /** Parameter value of this part */ value: string; } +/** The names @types/nodemailer used for the two types above */ +export type HeaderValue = StructuredHeaderValue; +export type ParsedHeaderParam = EncodedHeaderParam; /** * Checks if a value is plaintext string (uses only printable 7bit chars) * diff --git a/node_modules/nodemailer/dist/esm/mime-funcs/index.js b/node_modules/nodemailer/dist/esm/mime-funcs/index.js index 835f3556..ef1a5556 100644 --- a/node_modules/nodemailer/dist/esm/mime-funcs/index.js +++ b/node_modules/nodemailer/dist/esm/mime-funcs/index.js @@ -353,7 +353,7 @@ export function buildHeaderParam(key, data, maxLength) { */ export function parseHeaderValue(str) { const response = { - value: false, + value: '', params: {} }; // Parameter names come from a caller supplied contentType/contentDisposition. A diff --git a/node_modules/nodemailer/dist/esm/mime-node/index.d.ts b/node_modules/nodemailer/dist/esm/mime-node/index.d.ts index 2030d14d..03d7603b 100644 --- a/node_modules/nodemailer/dist/esm/mime-node/index.d.ts +++ b/node_modules/nodemailer/dist/esm/mime-node/index.d.ts @@ -108,10 +108,11 @@ export interface MimeNodeEnvelope { } /** * Envelope as accepted by setEnvelope. Recipients are collected from to, cc and bcc, any - * other field is copied to the envelope as is + * other field is copied to the envelope as is. A `from` of false is the null sender of a + * bounce message, it is sent as MAIL FROM:<> */ export interface MimeNodeEnvelopeInput { - from?: MimeNodeAddressInput | undefined; + from?: MimeNodeAddressInput | false | undefined; to?: MimeNodeAddressInput | undefined; cc?: MimeNodeAddressInput | undefined; bcc?: MimeNodeAddressInput | undefined; @@ -327,4 +328,6 @@ declare namespace MimeNode { type Addresses = MimeNodeAddresses; type Envelope = MimeNodeEnvelope; } +/** The same aliases as module level exports, for `import * as MimeNode` and `import MimeNode = require()` */ +export type { MimeNodeOptions as Options, MimeNodeAddresses as Addresses, MimeNodeEnvelope as Envelope }; export default MimeNode; diff --git a/node_modules/nodemailer/dist/esm/nodemailer.d.ts b/node_modules/nodemailer/dist/esm/nodemailer.d.ts index 3dd14427..8552d000 100644 --- a/node_modules/nodemailer/dist/esm/nodemailer.d.ts +++ b/node_modules/nodemailer/dist/esm/nodemailer.d.ts @@ -1,10 +1,16 @@ import Mail from './mailer/index.js'; import type { MailDefaults, SentMessageInfo, Transport, TransportOptions } from './mailer/index.js'; +import SMTPPool from './smtp-pool/index.js'; import type { SMTPPoolOptions, SMTPPoolSentMessageInfo } from './smtp-pool/index.js'; +import SMTPTransport from './smtp-transport/index.js'; import type { SMTPTransportOptions, SMTPSentMessageInfo } from './smtp-transport/index.js'; +import SendmailTransport from './sendmail-transport/index.js'; import type { SendmailTransportOptions, SendmailSentMessageInfo } from './sendmail-transport/index.js'; +import StreamTransport from './stream-transport/index.js'; import type { StreamTransportOptions, StreamSentMessageInfo } from './stream-transport/index.js'; -import type { JSONTransportOptions, JSONSentMessageInfo } from './json-transport/index.js'; +import JSONTransport from './json-transport/index.js'; +import type { JSONTransportOptions, JSONSentMessageInfo, JSONSentMessageObjectInfo } from './json-transport/index.js'; +import SESTransport from './ses-transport/index.js'; import type { SESTransportOptions, SESSentMessageInfo } from './ses-transport/index.js'; /** * Connection details of a service endpoint of an Ethereal test account @@ -43,24 +49,29 @@ export type TransportConfig = SMTPTransportOptions | SMTPPoolOptions | SendmailT * @param defaults Default message fields that are merged into every message * @returns Mail instance wrapping the transport */ -export declare function createTransport(transporter: SMTPPoolOptions & { +export declare function createTransport(transporter: SMTPPool | (SMTPPoolOptions & { pool: true; -}, defaults?: MailDefaults): Mail; -export declare function createTransport(transporter: SendmailTransportOptions & { +}), defaults?: MailDefaults): Mail; +export declare function createTransport(transporter: SendmailTransport | (SendmailTransportOptions & { sendmail: true | string; -}, defaults?: MailDefaults): Mail; -export declare function createTransport(transporter: StreamTransportOptions & { +}), defaults?: MailDefaults): Mail; +export declare function createTransport(transporter: StreamTransport | (StreamTransportOptions & { streamTransport: true; -}, defaults?: MailDefaults): Mail; +}), defaults?: MailDefaults): Mail; export declare function createTransport(transporter: JSONTransportOptions & { jsonTransport: true; -}, defaults?: MailDefaults): Mail; -export declare function createTransport(transporter: SESTransportOptions & { + skipEncoding: true; +}, defaults?: MailDefaults): Mail; +export declare function createTransport(transporter: JSONTransport | (JSONTransportOptions & { + jsonTransport: true; +}), defaults?: MailDefaults): Mail; +export declare function createTransport(transporter: SESTransport | (SESTransportOptions & { SES: object; -}, defaults?: MailDefaults): Mail; -export declare function createTransport(transporter: Transport, defaults?: MailDefaults): Mail; -export declare function createTransport(transporter?: SMTPTransportOptions | string, defaults?: MailDefaults): Mail; -export declare function createTransport(transporter?: TransportConfig | Transport | string, defaults?: MailDefaults): Mail; +}), defaults?: MailDefaults): Mail; +export declare function createTransport(transporter: SMTPTransport, defaults?: MailDefaults): Mail; +export declare function createTransport(transporter: Transport, defaults?: MailDefaults): Mail; +export declare function createTransport(transporter?: SMTPTransportOptions | string, defaults?: MailDefaults): Mail; +export declare function createTransport(transporter?: TransportConfig | Transport | string, defaults?: MailDefaults): Mail; /** * Creates a test account from the Ethereal service (https://ethereal.email) * @@ -98,5 +109,5 @@ export type { SMTPTransportOptions, SMTPSentMessageInfo }; export type { SMTPPoolOptions, SMTPPoolSentMessageInfo }; export type { SendmailTransportOptions, SendmailSentMessageInfo }; export type { StreamTransportOptions, StreamSentMessageInfo }; -export type { JSONTransportOptions, JSONSentMessageInfo }; +export type { JSONTransportOptions, JSONSentMessageInfo, JSONSentMessageObjectInfo }; export type { SESTransportOptions, SESSentMessageInfo }; diff --git a/node_modules/nodemailer/dist/esm/package-info.d.ts b/node_modules/nodemailer/dist/esm/package-info.d.ts index 4e7cec12..5f166c65 100644 --- a/node_modules/nodemailer/dist/esm/package-info.d.ts +++ b/node_modules/nodemailer/dist/esm/package-info.d.ts @@ -1,3 +1,3 @@ export declare const name = "nodemailer"; -export declare const version = "10.0.10"; +export declare const version = "10.0.11"; export declare const homepage = "https://nodemailer.com/"; diff --git a/node_modules/nodemailer/dist/esm/package-info.js b/node_modules/nodemailer/dist/esm/package-info.js index bdb2ae43..6816d685 100644 --- a/node_modules/nodemailer/dist/esm/package-info.js +++ b/node_modules/nodemailer/dist/esm/package-info.js @@ -1,4 +1,4 @@ // Generated by scripts/build.js from package.json. Do not edit by hand. export const name = 'nodemailer'; -export const version = '10.0.10'; +export const version = '10.0.11'; export const homepage = 'https://nodemailer.com/'; diff --git a/node_modules/nodemailer/dist/esm/qp/index.d.ts b/node_modules/nodemailer/dist/esm/qp/index.d.ts index 92eb8b9b..6253dbf6 100644 --- a/node_modules/nodemailer/dist/esm/qp/index.d.ts +++ b/node_modules/nodemailer/dist/esm/qp/index.d.ts @@ -15,6 +15,8 @@ export interface QPEncoderOptions { /** Maximum length for lines, set to false to disable wrapping */ lineLength?: number | false | undefined; } +/** The name @types/nodemailer used for QPEncoderOptions */ +export type EncoderOptions = QPEncoderOptions; /** * Creates a transform stream for encoding data to Quoted-Printable encoding * diff --git a/node_modules/nodemailer/dist/esm/qp/index.js b/node_modules/nodemailer/dist/esm/qp/index.js index 83d700e8..506ce3d7 100644 --- a/node_modules/nodemailer/dist/esm/qp/index.js +++ b/node_modules/nodemailer/dist/esm/qp/index.js @@ -5,6 +5,8 @@ import { Transform } from 'node:stream'; * @param buffer Buffer to convert * @returns Quoted-Printable encoded string */ +// the shortest line wrap() can make progress with: a complete =XX sequence and the soft break +const MIN_LINE_LENGTH = 4; // usable characters that do not need encoding // https://tools.ietf.org/html/rfc2045#section-6.7 const QP_RANGES = [ @@ -41,7 +43,9 @@ export function encode(buffer) { */ export function wrap(str, lineLength) { str = (str || '').toString(); - lineLength = lineLength || 76; + // a line has to hold a complete =XX sequence plus the soft break, shorter lengths + // (or a negative one) would loop without consuming input + lineLength = Math.max(Number(lineLength) || 76, MIN_LINE_LENGTH); if (str.length <= lineLength) { return str; } @@ -95,6 +99,11 @@ export function wrap(str, lineLength) { } } } + if (!line.length) { + // the trimming above emptied the line, which only happens for an incomplete + // escape at the very end of the input. Take it as is rather than loop on it + line = str.substr(pos, lineLength); + } if (pos + line.length < len && line.substr(-1) !== '\n') { if (line.length === lineLength && line.match(/[=][\da-f]{2}$/i)) { line = line.substr(0, line.length - 3); diff --git a/node_modules/nodemailer/dist/esm/sendmail-transport/index.d.ts b/node_modules/nodemailer/dist/esm/sendmail-transport/index.d.ts index e71c0268..28f2c7c4 100644 --- a/node_modules/nodemailer/dist/esm/sendmail-transport/index.d.ts +++ b/node_modules/nodemailer/dist/esm/sendmail-transport/index.d.ts @@ -64,4 +64,6 @@ declare namespace SendmailTransport { type MailOptions = SendMailOptions; type SentMessageInfo = SendmailSentMessageInfo; } +/** The same aliases as module level exports, for `import * as SendmailTransport` and `import SendmailTransport = require()` */ +export type { SendmailTransportOptions as Options, SendMailOptions as MailOptions, SendmailSentMessageInfo as SentMessageInfo }; export default SendmailTransport; diff --git a/node_modules/nodemailer/dist/esm/ses-transport/index.d.ts b/node_modules/nodemailer/dist/esm/ses-transport/index.d.ts index e3f6358a..26432d54 100644 --- a/node_modules/nodemailer/dist/esm/ses-transport/index.d.ts +++ b/node_modules/nodemailer/dist/esm/ses-transport/index.d.ts @@ -21,6 +21,32 @@ export interface SESTransportOptions extends TransportOptions { SendEmailCommand: new (input: any) => unknown; }; } +/** The SESv2Client shape the transport needs */ +export type SESTransportClient = SESTransportOptions['SES']['sesClient']; +/** The SendEmailCommand constructor shape the transport needs */ +export type SESTransportSendEmailCommand = SESTransportOptions['SES']['SendEmailCommand']; +/** + * SendEmailCommand parameters, the shape of the `ses` message option that is merged into + * the API call. Any further SendEmailCommandInput field is accepted as well + */ +export interface SESSendEmailRequest { + FromEmailAddress?: string | undefined; + Destination?: { + ToAddresses?: string[] | undefined; + CcAddresses?: string[] | undefined; + BccAddresses?: string[] | undefined; + } | undefined; + ReplyToAddresses?: string[] | undefined; + Content?: unknown; + EmailTags?: Array<{ + Name?: string | undefined; + Value?: string | undefined; + }> | undefined; + ConfigurationSetName?: string | undefined; + ListManagementOptions?: unknown; + FeedbackForwardingEmailAddress?: string | undefined; + [key: string]: unknown; +} /** * The value the SES transport hands to the send callback */ @@ -47,7 +73,7 @@ declare class SESTransport extends EventEmitter { name: string; version: string; logger: Logger; - constructor(options?: SESTransportOptions); + constructor(options: SESTransportOptions); getRegion(cb: (err: Error | null, region?: string | false) => void): void; /** * Compiles a mailcomposer message and forwards it to SES @@ -71,5 +97,11 @@ declare namespace SESTransport { type Options = SESTransportOptions; type MailOptions = SendMailOptions; type SentMessageInfo = SESSentMessageInfo; + type SESv2ClientLike = SESTransportClient; + type SendEmailCommandConstructorLike = SESTransportSendEmailCommand; + type SendEmailRequestLike = SESSendEmailRequest; + type MailSesOptions = SESSendEmailRequest; } +/** The same aliases as module level exports, for `import * as SESTransport` and `import SESTransport = require()` */ +export type { SESTransportOptions as Options, SendMailOptions as MailOptions, SESSentMessageInfo as SentMessageInfo, SESTransportClient as SESv2ClientLike, SESTransportSendEmailCommand as SendEmailCommandConstructorLike, SESSendEmailRequest as SendEmailRequestLike, SESSendEmailRequest as MailSesOptions }; export default SESTransport; diff --git a/node_modules/nodemailer/dist/esm/shared/index.d.ts b/node_modules/nodemailer/dist/esm/shared/index.d.ts index e6e5077c..3aeb3e79 100644 --- a/node_modules/nodemailer/dist/esm/shared/index.d.ts +++ b/node_modules/nodemailer/dist/esm/shared/index.d.ts @@ -34,6 +34,8 @@ export interface ResolvedHostname { /** The resolver error when a cached value was used because of it */ error?: Error | undefined; } +/** The name @types/nodemailer used for ResolvedHostname */ +export type ResolveHostnameValue = ResolvedHostname; /** * Resolved addresses as stored in the DNS cache */ @@ -83,6 +85,8 @@ export interface LogEntry { [key: string]: any; } export type LogLevel = 'trace' | 'debug' | 'info' | 'warn' | 'error' | 'fatal'; +/** The name @types/nodemailer used for LogLevel */ +export type LoggerLevel = LogLevel; /** * A logger supplied by the caller, bunyan style. Any object works, a level it does not * implement is routed to one it does, see _logFunc @@ -104,16 +108,24 @@ export interface GetLoggerOptions { /** A bunyan compatible logger, true for the default console logger, false or unset for no logging */ logger?: ExternalLogger | boolean | undefined; } +/** + * A bunyan style log method: a data object followed by a printf style message, or the + * message alone + */ +export interface LogMethod { + (data: LogEntry | undefined, message?: string, ...args: any[]): void; + (message?: string, ...args: any[]): void; +} /** * The bunyan compatible logger interface returned by getLogger */ export interface Logger { - trace(data?: LogEntry, message?: string, ...args: any[]): void; - debug(data?: LogEntry, message?: string, ...args: any[]): void; - info(data?: LogEntry, message?: string, ...args: any[]): void; - warn(data?: LogEntry, message?: string, ...args: any[]): void; - error(data?: LogEntry, message?: string, ...args: any[]): void; - fatal(data?: LogEntry, message?: string, ...args: any[]): void; + trace: LogMethod; + debug: LogMethod; + info: LogMethod; + warn: LogMethod; + error: LogMethod; + fatal: LogMethod; } /** * A parsed data URI diff --git a/node_modules/nodemailer/dist/esm/shared/index.js b/node_modules/nodemailer/dist/esm/shared/index.js index 4039d042..6e01921f 100644 --- a/node_modules/nodemailer/dist/esm/shared/index.js +++ b/node_modules/nodemailer/dist/esm/shared/index.js @@ -333,8 +333,10 @@ export const getLogger = (options, defaults) => { } const logger = options.logger === true ? createDefaultLogger(levels) : options.logger; levels.forEach(level => { - response[level] = (data, message, ...args) => { - _logFunc(logger, level, defaults, data, message, ...args); + response[level] = (...args) => { + // the bunyan forms: a data object first, or the message alone + const data = typeof args[0] === 'string' ? undefined : args.shift(); + _logFunc(logger, level, defaults, data, ...args); }; }); return response; diff --git a/node_modules/nodemailer/dist/esm/smtp-connection/http-proxy-client.d.ts b/node_modules/nodemailer/dist/esm/smtp-connection/http-proxy-client.d.ts index 5483cdc1..f0f9a481 100644 --- a/node_modules/nodemailer/dist/esm/smtp-connection/http-proxy-client.d.ts +++ b/node_modules/nodemailer/dist/esm/smtp-connection/http-proxy-client.d.ts @@ -2,7 +2,7 @@ * Minimal HTTP/S proxy client */ import net from 'node:net'; -import type { NodemailerError } from '../errors.js'; +import type { Callback } from '../errors.js'; /** * TLS options for connecting to an HTTPS proxy */ @@ -13,7 +13,7 @@ export interface HttpProxyClientOptions { /** * Receives the proxied socket once the CONNECT handshake has succeeded, or the error that prevented it */ -export type HttpProxyClientCallback = (err: NodemailerError | null, socket?: net.Socket) => void; +export type HttpProxyClientCallback = Callback; /** * Establishes proxied connection to destinationPort * diff --git a/node_modules/nodemailer/dist/esm/smtp-connection/http-proxy-client.js b/node_modules/nodemailer/dist/esm/smtp-connection/http-proxy-client.js index cae47eec..3b23374b 100644 --- a/node_modules/nodemailer/dist/esm/smtp-connection/http-proxy-client.js +++ b/node_modules/nodemailer/dist/esm/smtp-connection/http-proxy-client.js @@ -14,6 +14,8 @@ function httpProxyClient(proxyUrl, destinationPort, destinationHost, tlsOptions, tlsOptions = {}; } tlsOptions = tlsOptions || {}; + // the error paths hand over the error alone + const done = callback; // Reject CRLF in the destination before it reaches the CONNECT request line // and Host header. A tainted host/port could otherwise inject additional // request headers into the proxy connection (HTTP request splitting). @@ -21,7 +23,7 @@ function httpProxyClient(proxyUrl, destinationPort, destinationHost, tlsOptions, if (!destinationPort || /[\r\n]/.test(destinationHost)) { const err = new Error('Invalid proxy destination'); err.code = errors.EPROXY; - setImmediate(() => callback(err)); + setImmediate(() => done(err)); return; } const proxy = urllib.parse(proxyUrl); @@ -55,7 +57,7 @@ function httpProxyClient(proxyUrl, destinationPort, destinationHost, tlsOptions, catch (_E) { // ignore } - callback(err); + done(err); }; const timeoutErr = () => { const err = new Error('Proxy socket timed out'); @@ -114,12 +116,12 @@ function httpProxyClient(proxyUrl, destinationPort, destinationHost, tlsOptions, } const err = new Error('Invalid response from proxy' + ((match && ': ' + match[1]) || '')); err.code = errors.EPROXY; - return callback(err); + return done(err); } socket.removeListener('error', tempSocketErr); socket.removeListener('timeout', timeoutErr); socket.setTimeout(0); - return callback(null, socket); + return done(null, socket); } if (headers.length > MAX_RESPONSE_HEADER_BYTES) { socket.removeListener('data', onSocketData); diff --git a/node_modules/nodemailer/dist/esm/smtp-connection/index.d.ts b/node_modules/nodemailer/dist/esm/smtp-connection/index.d.ts index d8f1d34d..498af745 100644 --- a/node_modules/nodemailer/dist/esm/smtp-connection/index.d.ts +++ b/node_modules/nodemailer/dist/esm/smtp-connection/index.d.ts @@ -3,8 +3,9 @@ import net from 'node:net'; import tls from 'node:tls'; import { type Readable } from 'node:stream'; import * as shared from '../shared/index.js'; -import type { NodemailerError } from '../errors.js'; +import type { Callback, NodemailerError } from '../errors.js'; import type XOAuth2 from '../xoauth2/index.js'; +import type { XOAuth2Options } from '../xoauth2/index.js'; /** * Custom authentication handlers keyed by (case insensitive) SASL method name */ @@ -117,12 +118,23 @@ export interface SMTPConnectionCustomAuthResponse { * Callback for a command sent by a custom authentication handler */ export type SMTPConnectionCustomAuthCommandCallback = (err: Error | null, data: SMTPConnectionCustomAuthResponse) => void; +/** + * The auth object as a custom authentication handler sees it: the object handed to login() + * with the credentials filled in from its user and pass values + */ +export interface SMTPConnectionCustomAuthData extends SMTPConnectionAuth { + /** The user and pass values of the auth object, the way @types/nodemailer declared them */ + credentials: SMTPConnectionCredentials & { + user: string; + pass: string; + }; +} /** * The object a custom authentication handler is run with */ export interface SMTPConnectionCustomAuthContext { - /** The auth object handed to login() */ - auth: SMTPConnectionAuth; + /** The auth object handed to login(), with the credentials filled in */ + auth: SMTPConnectionCustomAuthData; /** Selected authentication method name */ method: string; /** SMTP extensions the server advertised */ @@ -131,17 +143,20 @@ export interface SMTPConnectionCustomAuthContext { authMethods: string[]; /** Maximum message size the server accepts, false when not advertised */ maxAllowedSize: number | false; - /** Sends a command to the server. Returns a promise when no callback is given */ - sendCommand(cmd: string, done?: SMTPConnectionCustomAuthCommandCallback): Promise | undefined; + /** Sends a command to the server and resolves with the parsed reply */ + sendCommand(cmd: string): Promise; + /** Sends a command to the server and hands the parsed reply to the callback */ + sendCommand(cmd: string, done: SMTPConnectionCustomAuthCommandCallback): void; /** Marks the user as authenticated */ resolve(): void; /** Fails the authentication with an error */ reject(err: Error | string): void; } /** - * A custom authentication handler. Calls resolve() or reject() on the context, or returns a promise + * A custom authentication handler. Calls resolve() or reject() on the context, or returns a + * promise that settles the authentication. Any other return value is ignored */ -export type SMTPConnectionCustomAuthHandler = (ctx: SMTPConnectionCustomAuthContext) => void | Promise; +export type SMTPConnectionCustomAuthHandler = (ctx: SMTPConnectionCustomAuthContext) => unknown; /** * An envelope address, either a plain string or an object with an address property */ @@ -168,12 +183,16 @@ export interface SMTPEnvelopeDsn { /** Alias of recipient, in the 'rfc822;address' form */ orcpt?: string | null | undefined; } +/** + * A single DSN notify value + */ +export type SMTPEnvelopeDsnNotify = 'NEVER' | 'SUCCESS' | 'FAILURE' | 'DELAY'; /** * Envelope object accepted by send() */ export interface SMTPEnvelope { - /** Sender address */ - from?: string | SMTPEnvelopeAddress | undefined; + /** Sender address, false for the null sender of a bounce message (MAIL FROM:<>) */ + from?: string | SMTPEnvelopeAddress | false | undefined; /** Recipient address or addresses */ to?: string | SMTPEnvelopeAddress | Array | undefined; /** Message size in bytes, sent as the SIZE parameter when the server supports it */ @@ -202,9 +221,9 @@ export interface SMTPConnectionEnvelope extends SMTPEnvelope { accepted: string[]; } /** - * Result of a sent message + * The recipient bookkeeping of a sent message, known once the envelope is accepted */ -export interface SMTPConnectionSendInfo { +export interface SMTPConnectionEnvelopeInfo { /** Recipients the server accepted */ accepted: string[]; /** Recipients the server rejected */ @@ -213,19 +232,25 @@ export interface SMTPConnectionSendInfo { ehlo?: string[] | undefined; /** Errors for the rejected recipients */ rejectedErrors?: NodemailerError[] | undefined; - /** Time in ms spent on the envelope commands */ - envelopeTime?: number | undefined; - /** Time in ms spent on streaming the message */ - messageTime?: number | undefined; - /** Size of the encoded message in bytes */ - messageSize?: number | undefined; - /** Final server response for the message */ - response?: string | undefined; } /** - * Callback for send() + * Result of a sent message */ -export type SMTPConnectionSendCallback = (err: NodemailerError | null, info?: SMTPConnectionSendInfo) => void; +export interface SMTPConnectionSendInfo extends SMTPConnectionEnvelopeInfo { + /** Time in ms spent on the envelope commands */ + envelopeTime: number; + /** Time in ms spent on streaming the message */ + messageTime: number; + /** Size of the encoded message in bytes */ + messageSize: number; + /** Final server response for the message */ + response: string; +} +/** + * Callback for send(), receives the result once the server accepted the message. The error + * path hands over the error alone + */ +export type SMTPConnectionSendCallback = Callback; /** * Callback for login() and reset(), the result is true on success */ @@ -285,7 +310,7 @@ export type SMTPConnectionResponseAction = (str: string) => void; */ declare class SMTPConnection extends EventEmitter { id: string; - stage: string; + stage: 'init' | 'connected'; options: SMTPConnectionOptions; secureConnection: boolean; alreadySecured: boolean; @@ -370,12 +395,22 @@ declare class SMTPConnection extends EventEmitter { declare namespace SMTPConnection { type Options = SMTPConnectionOptions; type AuthenticationType = SMTPConnectionAuth; + type AuthenticationTypeLogin = SMTPConnectionAuth; + type AuthenticationTypeOAuth2 = SMTPConnectionAuth; + type AuthenticationTypeCustom = SMTPConnectionAuth; + type AuthenticationCredentials = SMTPConnectionAuth; + type AuthenticationOAuth2 = SMTPConnectionAuth; type Credentials = SMTPConnectionCredentials; + type OAuth2 = XOAuth2Options; type Envelope = SMTPEnvelope; type DSNOptions = SMTPEnvelopeDsn; + type DSNOption = SMTPEnvelopeDsnNotify; type SentMessageInfo = SMTPConnectionSendInfo; + type SMTPError = NodemailerError; type CustomAuthenticationContext = SMTPConnectionCustomAuthContext; type CustomAuthenticationResponse = SMTPConnectionCustomAuthResponse; type CustomAuthenticationHandlers = SMTPConnectionCustomAuthHandlers; } +/** The same aliases as module level exports, for `import * as SMTPConnection` and `import SMTPConnection = require()` */ +export type { SMTPConnectionOptions as Options, SMTPConnectionAuth as AuthenticationType, SMTPConnectionAuth as AuthenticationTypeLogin, SMTPConnectionAuth as AuthenticationTypeOAuth2, SMTPConnectionAuth as AuthenticationTypeCustom, SMTPConnectionAuth as AuthenticationCredentials, SMTPConnectionAuth as AuthenticationOAuth2, SMTPConnectionCredentials as Credentials, XOAuth2Options as OAuth2, SMTPEnvelope as Envelope, SMTPEnvelopeDsn as DSNOptions, SMTPEnvelopeDsnNotify as DSNOption, SMTPConnectionSendInfo as SentMessageInfo, NodemailerError as SMTPError, SMTPConnectionCustomAuthContext as CustomAuthenticationContext, SMTPConnectionCustomAuthResponse as CustomAuthenticationResponse, SMTPConnectionCustomAuthHandlers as CustomAuthenticationHandlers }; export default SMTPConnection; diff --git a/node_modules/nodemailer/dist/esm/smtp-connection/index.js b/node_modules/nodemailer/dist/esm/smtp-connection/index.js index b7e00cb4..83cbd18e 100644 --- a/node_modules/nodemailer/dist/esm/smtp-connection/index.js +++ b/node_modules/nodemailer/dist/esm/smtp-connection/index.js @@ -414,14 +414,21 @@ class SMTPConnection extends EventEmitter { this._auth = authData || {}; // Select SASL authentication method this._authMethod = (this._auth.method || '').toString().trim().toUpperCase() || false; + // XOAUTH2 needs a token generator or a custom handler, without either the method + // can not be run even when it is the only one the server advertised + const canUseXOAuth2 = !!this._auth.oauth2 || this.customAuth.has('XOAUTH2'); if (!this._authMethod && this._auth.oauth2 && !this._auth.credentials) { this._authMethod = 'XOAUTH2'; } else if (!this._authMethod || (this._authMethod === 'XOAUTH2' && !this._auth.oauth2)) { - // use first supported - this._authMethod = (this._supportedAuth[0] || 'PLAIN').toUpperCase().trim(); + // use the first supported method that can be run + const supported = this._supportedAuth.find(method => method !== 'XOAUTH2' || canUseXOAuth2); + this._authMethod = (supported || 'PLAIN').toUpperCase().trim(); } - if (this._authMethod !== 'XOAUTH2' && (!this._auth.credentials || !this._auth.credentials.user || !this._auth.credentials.pass)) { + // a token login needs no credentials, every other method and every custom handler + // gets them filled in from the user and pass values + if ((this._authMethod !== 'XOAUTH2' || this.customAuth.has('XOAUTH2')) && + (!this._auth.credentials || !this._auth.credentials.user || !this._auth.credentials.pass)) { if ((this._auth.user && this._auth.pass) || this.customAuth.has(this._authMethod)) { this._auth.credentials = { user: this._auth.user, @@ -458,42 +465,45 @@ class SMTPConnection extends EventEmitter { returned = true; callback(this._formatError(err, 'EAUTH', lastResponse, 'AUTH ' + this._authMethod)); }; + // one implementation serves both sendCommand overloads, the promise is returned + // exactly when no callback was given + const sendCommand = (cmd, done) => { + let promise; + if (!done) { + promise = new Promise((resolve, reject) => { + done = shared.callbackPromise(resolve, reject); + }); + } + this._responseActions.push(str => { + lastResponse = str; + let codes = str.match(/^(\d+)(?:\s(\d+\.\d+\.\d+))?\s/); + let data = { + command: cmd, + response: str + }; + if (codes) { + data.status = Number(codes[1]) || 0; + if (codes[2]) { + data.code = codes[2]; + } + data.text = str.substr(codes[0].length); + } + else { + data.text = str; + data.status = 0; // just in case we need to perform numeric comparisons + } + done(null, data); + }); + setImmediate(() => this._sendCommand(cmd)); + return promise; + }; const handlerResponse = handler({ auth: this._auth, method: this._authMethod, extensions: [].concat(this._supportedExtensions), authMethods: [].concat(this._supportedAuth), maxAllowedSize: this._maxAllowedSize || false, - sendCommand: (cmd, done) => { - let promise; - if (!done) { - promise = new Promise((resolve, reject) => { - done = shared.callbackPromise(resolve, reject); - }); - } - this._responseActions.push(str => { - lastResponse = str; - let codes = str.match(/^(\d+)(?:\s(\d+\.\d+\.\d+))?\s/); - let data = { - command: cmd, - response: str - }; - if (codes) { - data.status = Number(codes[1]) || 0; - if (codes[2]) { - data.code = codes[2]; - } - data.text = str.substr(codes[0].length); - } - else { - data.text = str; - data.status = 0; // just in case we need to perform numeric comparisons - } - done(null, data); - }); - setImmediate(() => this._sendCommand(cmd)); - return promise; - }, + sendCommand: sendCommand, resolve, reject }); @@ -550,29 +560,30 @@ class SMTPConnection extends EventEmitter { * @param callback Callback to return once sending is completed */ send(envelope, message, done) { - if (!message) { - return done(this._formatError('Empty message', 'EMESSAGE', false, 'API')); - } - const isDestroyedMessage = this._isDestroyedMessage('send message'); - if (isDestroyedMessage) { - return done(this._formatError(isDestroyedMessage, 'ECONNECTION', false, 'API')); - } - // reject larger messages than allowed - if (this._maxAllowedSize && envelope.size > this._maxAllowedSize) { - setImmediate(() => { - done(this._formatError('Message size larger than allowed ' + this._maxAllowedSize, 'EMESSAGE', false, 'MAIL FROM')); - }); - return; - } - // ensure that callback is only called once + // ensure that the callback is only called once. The public callback type has a + // required result, the error paths hand over the error alone let returned = false; - const callback = function (...args) { + const callback = (err, info) => { if (returned) { return; } returned = true; - done(...args); + done(err, info); }; + if (!message) { + return callback(this._formatError('Empty message', 'EMESSAGE', false, 'API')); + } + const isDestroyedMessage = this._isDestroyedMessage('send message'); + if (isDestroyedMessage) { + return callback(this._formatError(isDestroyedMessage, 'ECONNECTION', false, 'API')); + } + // reject larger messages than allowed + if (this._maxAllowedSize && envelope.size > this._maxAllowedSize) { + setImmediate(() => { + callback(this._formatError('Message size larger than allowed ' + this._maxAllowedSize, 'EMESSAGE', false, 'MAIL FROM')); + }); + return; + } if (typeof message.on === 'function') { message.on('error', err => callback(this._formatError(err, 'ESTREAM', false, 'API'))); } @@ -595,11 +606,13 @@ class SMTPConnection extends EventEmitter { if (err) { return callback(err); } - info.envelopeTime = envelopeTime - startTime; - info.messageTime = Date.now() - envelopeTime; - info.messageSize = stream.outByteCount; - info.response = str; - return callback(null, info); + // the envelope info becomes the send result once the timings are on it + const result = info; + result.envelopeTime = envelopeTime - startTime; + result.messageTime = Date.now() - envelopeTime; + result.messageSize = stream.outByteCount; + result.response = str; + return callback(null, result); }); if (typeof message.pipe === 'function') { message.pipe(stream); diff --git a/node_modules/nodemailer/dist/esm/smtp-pool/index.d.ts b/node_modules/nodemailer/dist/esm/smtp-pool/index.d.ts index 2e5b488d..9646cd50 100644 --- a/node_modules/nodemailer/dist/esm/smtp-pool/index.d.ts +++ b/node_modules/nodemailer/dist/esm/smtp-pool/index.d.ts @@ -80,7 +80,7 @@ declare class SMTPPool extends EventEmitter { /** * The Mail instance using this transport, assigned by Mail */ - mailer?: Mail | undefined; + mailer?: Mail | undefined; constructor(options?: SMTPPoolOptions | string); /** * Placeholder function for creating proxy sockets. This method immediatelly returns @@ -96,7 +96,7 @@ declare class SMTPPool extends EventEmitter { * @param mail Mail object * @param callback Callback function */ - send(mail: MailMessage, callback: SMTPPoolSendCallback): boolean; + send(mail: MailMessage, callback: SMTPPoolSendCallback): boolean; /** * Closes all connections in the pool. If there is a message being sent, the connection * is closed later @@ -122,4 +122,6 @@ declare namespace SMTPPool { type MailOptions = SendMailOptions; type SentMessageInfo = SMTPPoolSentMessageInfo; } +/** The same aliases as module level exports, for `import * as SMTPPool` and `import SMTPPool = require()` */ +export type { SMTPPoolOptions as Options, SendMailOptions as MailOptions, SMTPPoolSentMessageInfo as SentMessageInfo }; export default SMTPPool; diff --git a/node_modules/nodemailer/dist/esm/smtp-pool/index.js b/node_modules/nodemailer/dist/esm/smtp-pool/index.js index 798e627a..918b59d9 100644 --- a/node_modules/nodemailer/dist/esm/smtp-pool/index.js +++ b/node_modules/nodemailer/dist/esm/smtp-pool/index.js @@ -424,10 +424,12 @@ class SMTPPool extends EventEmitter { callback = shared.callbackPromise(resolve, reject); }); } + // the error paths hand over the error alone + const done = callback; const auth = new PoolResource(this).auth; this.getSocket(this.options, (err, socketOptions) => { if (err) { - return callback(err); + return done(err); } let options = this.options; if (socketOptions && socketOptions.connection) { @@ -449,14 +451,14 @@ class SMTPPool extends EventEmitter { } returned = true; connection.close(); - return callback(err); + return done(err); }); connection.once('end', () => { if (returned) { return; } returned = true; - return callback(new Error('Connection closed')); + return done(new Error('Connection closed')); }); const finalize = () => { if (returned) { @@ -464,7 +466,7 @@ class SMTPPool extends EventEmitter { } returned = true; connection.quit(); - return callback(null, true); + return done(null, true); }; connection.connect(() => { if (returned) { @@ -478,7 +480,7 @@ class SMTPPool extends EventEmitter { if (err) { returned = true; connection.close(); - return callback(err); + return done(err); } finalize(); }); @@ -488,7 +490,7 @@ class SMTPPool extends EventEmitter { err.code = errors.ENOAUTH; returned = true; connection.close(); - return callback(err); + return done(err); } else { finalize(); diff --git a/node_modules/nodemailer/dist/esm/smtp-pool/pool-resource.js b/node_modules/nodemailer/dist/esm/smtp-pool/pool-resource.js index 12ba9c41..5a8738ea 100644 --- a/node_modules/nodemailer/dist/esm/smtp-pool/pool-resource.js +++ b/node_modules/nodemailer/dist/esm/smtp-pool/pool-resource.js @@ -100,9 +100,7 @@ export default class PoolResource extends EventEmitter { } // still have not returned, this means we have an unexpected connection close const err = new Error('Unexpected socket close'); - if (this.connection && - this.connection._socket && - this.connection._socket.upgrading) { + if (this.connection && this.connection.upgrading) { // starttls connection errors err.code = errors.ETLS; } diff --git a/node_modules/nodemailer/dist/esm/smtp-transport/index.d.ts b/node_modules/nodemailer/dist/esm/smtp-transport/index.d.ts index c3011ced..11bbb3c9 100644 --- a/node_modules/nodemailer/dist/esm/smtp-transport/index.d.ts +++ b/node_modules/nodemailer/dist/esm/smtp-transport/index.d.ts @@ -4,7 +4,7 @@ import * as shared from '../shared/index.js'; import { type XOAuth2Options } from '../xoauth2/index.js'; import type { ResultCallback } from '../errors.js'; import type MailMessage from '../mailer/mail-message.js'; -import type { default as Mail, SentMessageInfo, SendMailOptions, TransportOptions, VerifyCallback } from '../mailer/index.js'; +import type { default as Mail, GetSocketCallback, SentMessageInfo, SendMailOptions, TransportOptions, VerifyCallback } from '../mailer/index.js'; import type { MimeNodeEnvelope } from '../mime-node/index.js'; /** * Authentication settings, either from the transport options or from the message data. @@ -38,9 +38,10 @@ export interface SMTPTransportAuth extends SMTPConnectionAuth { /** * Receives the socket details from getSocket, false when a new socket should be opened. The * object is merged into the connection options, a proxy handler provides the connected socket - * as `connection` + * as `connection`. The same callback type Mail hands to a transport, so that the SMTP + * transports stay assignable to the Transport interface */ -export type SMTPTransportGetSocketCallback = (err: Error | null, socketOptions?: SMTPConnectionOptions | false) => void; +export type SMTPTransportGetSocketCallback = GetSocketCallback; /** * Custom socket provider, replaces the getSocket method of the transport */ @@ -78,6 +79,8 @@ export interface SMTPSentMessageInfo extends SMTPConnectionSendInfo, SentMessage accepted: string[]; /** Recipients the server rejected */ rejected: string[]; + /** Final server response for the message */ + response: string; } /** * Callback for send() @@ -101,7 +104,7 @@ declare class SMTPTransport extends EventEmitter { /** * The Mail instance using this transport, assigned by Mail */ - mailer?: Mail | undefined; + mailer?: Mail | undefined; constructor(options?: SMTPTransportOptions | string); /** * Placeholder function for creating proxy sockets. This method immediatelly returns @@ -118,7 +121,7 @@ declare class SMTPTransport extends EventEmitter { * @param mail Mail object * @param callback Callback function */ - send(mail: MailMessage, callback: SMTPTransportSendCallback): void; + send(mail: MailMessage, callback: SMTPTransportSendCallback): void; /** * Verifies SMTP configuration * @@ -139,5 +142,10 @@ declare namespace SMTPTransport { type MailOptions = SendMailOptions; type SentMessageInfo = SMTPSentMessageInfo; type AuthenticationType = SMTPTransportAuth; + type AuthenticationTypeLogin = SMTPTransportAuth; + type AuthenticationTypeOAuth2 = SMTPTransportAuth; + type AuthenticationTypeCustom = SMTPTransportAuth; } +/** The same aliases as module level exports, for `import * as SMTPTransport` and `import SMTPTransport = require()` */ +export type { SMTPTransportOptions as Options, SendMailOptions as MailOptions, SMTPSentMessageInfo as SentMessageInfo, SMTPTransportAuth as AuthenticationType, SMTPTransportAuth as AuthenticationTypeLogin, SMTPTransportAuth as AuthenticationTypeOAuth2, SMTPTransportAuth as AuthenticationTypeCustom }; export default SMTPTransport; diff --git a/node_modules/nodemailer/dist/esm/smtp-transport/index.js b/node_modules/nodemailer/dist/esm/smtp-transport/index.js index 0cd4e470..1ec9d1d9 100644 --- a/node_modules/nodemailer/dist/esm/smtp-transport/index.js +++ b/node_modules/nodemailer/dist/esm/smtp-transport/index.js @@ -151,7 +151,7 @@ class SMTPTransport extends EventEmitter { cleanupPerCallAuth(); // still have not returned, this means we have an unexpected connection close const err = new Error('Unexpected socket close'); - if (connection && connection._socket && connection._socket.upgrading) { + if (connection && connection.upgrading) { // starttls connection errors err.code = errors.ETLS; } @@ -241,9 +241,11 @@ class SMTPTransport extends EventEmitter { callback = shared.callbackPromise(resolve, reject); }); } + // the error paths hand over the error alone + const done = callback; this.getSocket(this.options, (err, socketOptions) => { if (err) { - return callback(err); + return done(err); } let options = this.options; if (socketOptions && socketOptions.connection) { @@ -273,7 +275,7 @@ class SMTPTransport extends EventEmitter { returned = true; cleanupPerCallAuth(); connection.close(); - return callback(err); + return done(err); }); connection.once('end', () => { if (returned) { @@ -281,7 +283,7 @@ class SMTPTransport extends EventEmitter { } returned = true; cleanupPerCallAuth(); - return callback(new Error('Connection closed')); + return done(new Error('Connection closed')); }); const finalize = () => { if (returned) { @@ -290,7 +292,7 @@ class SMTPTransport extends EventEmitter { returned = true; cleanupPerCallAuth(); connection.quit(); - return callback(null, true); + return done(null, true); }; connection.connect(() => { if (returned) { @@ -306,7 +308,7 @@ class SMTPTransport extends EventEmitter { if (err) { returned = true; connection.close(); - return callback(err); + return done(err); } finalize(); }); @@ -317,7 +319,7 @@ class SMTPTransport extends EventEmitter { returned = true; cleanupPerCallAuth(); connection.close(); - return callback(err); + return done(err); } else { finalize(); diff --git a/node_modules/nodemailer/dist/esm/stream-transport/index.d.ts b/node_modules/nodemailer/dist/esm/stream-transport/index.d.ts index 0f305476..11a326c4 100644 --- a/node_modules/nodemailer/dist/esm/stream-transport/index.d.ts +++ b/node_modules/nodemailer/dist/esm/stream-transport/index.d.ts @@ -60,4 +60,6 @@ declare namespace StreamTransport { type MailOptions = SendMailOptions; type SentMessageInfo = StreamSentMessageInfo; } +/** The same aliases as module level exports, for `import * as StreamTransport` and `import StreamTransport = require()` */ +export type { StreamTransportOptions as Options, SendMailOptions as MailOptions, StreamSentMessageInfo as SentMessageInfo }; export default StreamTransport; diff --git a/node_modules/nodemailer/dist/esm/xoauth2/index.d.ts b/node_modules/nodemailer/dist/esm/xoauth2/index.d.ts index b02f26c6..4538d712 100644 --- a/node_modules/nodemailer/dist/esm/xoauth2/index.d.ts +++ b/node_modules/nodemailer/dist/esm/xoauth2/index.d.ts @@ -1,6 +1,7 @@ import { Stream } from 'node:stream'; import crypto from 'node:crypto'; import * as shared from '../shared/index.js'; +import type { ResultCallback } from '../errors.js'; import type { OutgoingHttpHeaders } from 'node:http'; /** * Receives the result of a provisionCallback run: an error, or the new access token and @@ -13,9 +14,11 @@ export type XOAuth2ProvisionResultCallback = (err: Error | null, accessToken?: s */ export type XOAuth2ProvisionCallback = (user: string, renew: boolean, callback: XOAuth2ProvisionResultCallback) => void; /** - * Receives an access token, or the error that prevented generating one + * Receives an access token, or the error that prevented generating one. Declared with a + * required token, the way @types/nodemailer declared it, the error path hands over the + * error alone */ -export type XOAuth2TokenCallback = (err: Error | null, accessToken?: string) => void; +export type XOAuth2TokenCallback = (err: Error | null, accessToken: string) => void; /** * A private key accepted by crypto.createSign().sign() */ @@ -79,7 +82,7 @@ export interface XOAuth2Token { */ export interface XOAuth2QueuedRequest { renew: boolean; - callback: XOAuth2TokenCallback; + callback: ResultCallback; } /** * XOAUTH2 access_token generator for Gmail. @@ -181,11 +184,16 @@ declare class XOAuth2 extends Stream { [key: string]: any; }): string; } +/** The extra request settings of the token request, the customHeaders and customParams options */ +export type XOAuth2RequestParams = Pick; /** * Type aliases in the layout of @types/nodemailer, so `XOAuth2.Options` style references keep working */ declare namespace XOAuth2 { type Options = XOAuth2Options; type Token = XOAuth2Token; + type RequestParams = XOAuth2RequestParams; } +/** The same aliases as module level exports, for `import * as XOAuth2` and `import XOAuth2 = require()` */ +export type { XOAuth2Options as Options, XOAuth2Token as Token, XOAuth2RequestParams as RequestParams }; export default XOAuth2; diff --git a/node_modules/nodemailer/dist/esm/xoauth2/index.js b/node_modules/nodemailer/dist/esm/xoauth2/index.js index 27f19901..f8cbacb3 100644 --- a/node_modules/nodemailer/dist/esm/xoauth2/index.js +++ b/node_modules/nodemailer/dist/esm/xoauth2/index.js @@ -73,6 +73,8 @@ class XOAuth2 extends Stream { * @param callback Callback function with error object and token string */ getToken(renew, callback) { + // the error paths hand over the error alone + const done = callback; if (!renew && this.accessToken && (!this.expires || this.expires > Date.now())) { this.logger.debug({ tnx: 'OAUTH2', @@ -98,11 +100,11 @@ class XOAuth2 extends Stream { }, 'Cannot renew access token for %s: No refresh mechanism available', this.options.user); const err = new Error("Can't create new access token for user"); err.code = errors.EOAUTH2; - return callback(err); + return done(err); } // If renewal already in progress, queue this request instead of starting another if (this.renewing) { - this.renewalQueue.push({ renew, callback }); + this.renewalQueue.push({ renew, callback: done }); return; } this.renewing = true; @@ -127,7 +129,7 @@ class XOAuth2 extends Stream { }, 'Generated new Access Token for %s', this.options.user); } // Complete original request - callback(err, accessToken); + done(err, accessToken); }; if (this.provisionCallback) { this.provisionCallback(this.options.user, !!renew, (err, accessToken, expires) => { @@ -166,6 +168,8 @@ class XOAuth2 extends Stream { * @param callback Callback function with error object and token string */ generateToken(callback) { + // the error paths hand over the error alone + const done = callback; let urlOptions; let loggedUrlOptions; if (this.options.serviceClient) { @@ -186,7 +190,7 @@ class XOAuth2 extends Stream { catch (_err) { const err = new Error("Can't generate token. Check your auth options"); err.code = errors.EOAUTH2; - return callback(err); + return done(err); } urlOptions = { grant_type: 'urn:ietf:params:oauth:grant-type:jwt-bearer', @@ -201,7 +205,7 @@ class XOAuth2 extends Stream { if (!this.options.refreshToken) { const err = new Error("Can't create new access token for user"); err.code = errors.EOAUTH2; - return callback(err); + return done(err); } // web app - https://developers.google.com/identity/protocols/OAuth2WebServer urlOptions = { @@ -227,13 +231,13 @@ class XOAuth2 extends Stream { this.postRequest(this.options.accessUrl, urlOptions, this.options, (error, body) => { let data; if (error) { - return callback(error); + return done(error); } try { data = JSON.parse(body.toString()); } catch (E) { - return callback(E); + return done(E); } if (!data || typeof data !== 'object') { this.logger.debug({ @@ -243,7 +247,7 @@ class XOAuth2 extends Stream { }, 'Response: %s', (body || '').toString()); const err = new Error('Invalid authentication response'); err.code = errors.EOAUTH2; - return callback(err); + return done(err); } const logData = Object.assign({}, data); if (logData.access_token) { @@ -265,7 +269,7 @@ class XOAuth2 extends Stream { } const err = new Error(errorMessage); err.code = errors.EOAUTH2; - return callback(err); + return done(err); } if (data.access_token) { this.updateToken(data.access_token, data.expires_in); @@ -273,7 +277,7 @@ class XOAuth2 extends Stream { } const err = new Error('No access token'); err.code = errors.EOAUTH2; - return callback(err); + return done(err); }); } /** diff --git a/node_modules/nodemailer/package.json b/node_modules/nodemailer/package.json index 3524e2c9..9b8103ec 100644 --- a/node_modules/nodemailer/package.json +++ b/node_modules/nodemailer/package.json @@ -1,6 +1,6 @@ { "name": "nodemailer", - "version": "10.0.10", + "version": "10.0.11", "description": "Easy as cake e-mail sending from your Node.js applications", "type": "module", "main": "./dist/cjs/nodemailer.js", @@ -9,6 +9,9 @@ "lib/well-known/services.json": [ "dist/well-known/services.json" ], + "lib/well-known/services": [ + "dist/well-known/services.json" + ], "lib/*": [ "dist/cjs/*/index.d.ts", "dist/cjs/*.d.ts" @@ -97,6 +100,7 @@ "require": "./dist/cjs/well-known/index.js" }, "./lib/well-known/services.json": "./dist/well-known/services.json", + "./lib/well-known/services": "./dist/well-known/services.json", "./lib/xoauth2": { "import": "./dist/esm/xoauth2/index.js", "require": "./dist/cjs/xoauth2/index.js" @@ -147,24 +151,24 @@ }, "homepage": "https://nodemailer.com/", "devDependencies": { - "@aws-sdk/client-sesv2": "3.1131.0", + "@aws-sdk/client-sesv2": "3.1141.0", "@types/node": "20.19.43", "bunyan": "1.8.15", "c8": "12.0.0", - "eslint": "10.10.0", + "eslint": "10.11.0", "eslint-config-prettier": "10.1.8", "globals": "17.12.0", "libbase64": "1.3.0", - "libmime": "5.4.3", + "libmime": "5.4.4", "libqp": "2.1.1", - "mailauth": "5.0.3", - "prettier": "3.9.6", + "mailauth": "7.1.0", + "prettier": "3.9.9", "proxy": "1.0.2", "proxy-test-server": "1.0.0", - "smtp-server": "3.19.11", - "tsx": "4.23.13", + "smtp-server": "3.19.13", + "tsx": "4.23.15", "typescript": "6.0.3", - "typescript-eslint": "8.70.0" + "typescript-eslint": "8.70.1" }, "engines": { "node": ">=20.0.0"