@nocobase/plugin-workflow-mailer 2.3.0-beta.9 → 2.4.0-alpha.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (187) hide show
  1. package/dist/externalVersion.js +6 -6
  2. package/dist/node_modules/joi/dist/joi-browser.min.js +1 -1
  3. package/dist/node_modules/joi/lib/index.js +1 -1
  4. package/dist/node_modules/joi/lib/messages.js +35 -6
  5. package/dist/node_modules/joi/lib/types/keys.js +18 -1
  6. package/dist/node_modules/joi/lib/types/link.js +18 -2
  7. package/dist/node_modules/joi/lib/types/string.js +2 -2
  8. package/dist/node_modules/joi/package.json +1 -1
  9. package/dist/node_modules/nodemailer/dist/cjs/addressparser/index.d.ts +59 -0
  10. package/dist/node_modules/nodemailer/dist/cjs/addressparser/index.js +790 -0
  11. package/dist/node_modules/nodemailer/dist/cjs/base64/index.d.ts +36 -0
  12. package/dist/node_modules/nodemailer/dist/cjs/base64/index.js +119 -0
  13. package/dist/node_modules/nodemailer/dist/cjs/dkim/index.d.ts +52 -0
  14. package/dist/node_modules/nodemailer/dist/cjs/dkim/index.js +228 -0
  15. package/dist/node_modules/nodemailer/dist/cjs/dkim/message-parser.d.ts +48 -0
  16. package/dist/node_modules/nodemailer/dist/cjs/dkim/message-parser.js +180 -0
  17. package/dist/node_modules/nodemailer/dist/cjs/dkim/relaxed-body.d.ts +36 -0
  18. package/dist/node_modules/nodemailer/dist/cjs/dkim/relaxed-body.js +148 -0
  19. package/dist/node_modules/nodemailer/dist/cjs/dkim/sign.d.ts +52 -0
  20. package/dist/node_modules/nodemailer/dist/cjs/dkim/sign.js +165 -0
  21. package/dist/node_modules/nodemailer/dist/cjs/errors.d.ts +96 -0
  22. package/dist/node_modules/nodemailer/dist/cjs/errors.js +70 -0
  23. package/dist/node_modules/nodemailer/dist/cjs/fetch/cookies.d.ts +107 -0
  24. package/dist/node_modules/nodemailer/dist/cjs/fetch/cookies.js +282 -0
  25. package/dist/node_modules/nodemailer/dist/cjs/fetch/index.d.ts +65 -0
  26. package/dist/node_modules/nodemailer/dist/cjs/fetch/index.js +384 -0
  27. package/dist/node_modules/nodemailer/dist/cjs/json-transport/index.d.ts +64 -0
  28. package/dist/node_modules/nodemailer/dist/cjs/json-transport/index.js +99 -0
  29. package/dist/node_modules/nodemailer/dist/cjs/mail-composer/index.d.ts +174 -0
  30. package/dist/node_modules/nodemailer/dist/cjs/mail-composer/index.js +613 -0
  31. package/dist/node_modules/nodemailer/dist/cjs/mailer/index.d.ts +237 -0
  32. package/dist/node_modules/nodemailer/dist/cjs/mailer/index.js +415 -0
  33. package/dist/node_modules/nodemailer/dist/cjs/mailer/mail-message.d.ts +97 -0
  34. package/dist/node_modules/nodemailer/dist/cjs/mailer/mail-message.js +342 -0
  35. package/dist/node_modules/nodemailer/dist/cjs/mime-funcs/index.d.ts +161 -0
  36. package/dist/node_modules/nodemailer/dist/cjs/mime-funcs/index.js +787 -0
  37. package/dist/node_modules/nodemailer/dist/cjs/mime-funcs/mime-types.d.ts +2 -0
  38. package/dist/node_modules/nodemailer/dist/cjs/mime-funcs/mime-types.js +2103 -0
  39. package/dist/node_modules/nodemailer/dist/cjs/mime-node/index.d.ts +333 -0
  40. package/dist/node_modules/nodemailer/dist/cjs/mime-node/index.js +1493 -0
  41. package/dist/node_modules/nodemailer/dist/cjs/mime-node/last-newline.d.ts +5 -0
  42. package/dist/node_modules/nodemailer/dist/cjs/mime-node/last-newline.js +32 -0
  43. package/dist/node_modules/nodemailer/dist/cjs/mime-node/le-unix.d.ts +9 -0
  44. package/dist/node_modules/nodemailer/dist/cjs/mime-node/le-unix.js +40 -0
  45. package/dist/node_modules/nodemailer/dist/cjs/mime-node/le-windows.d.ts +10 -0
  46. package/dist/node_modules/nodemailer/dist/cjs/mime-node/le-windows.js +47 -0
  47. package/dist/node_modules/nodemailer/dist/cjs/nodemailer.d.ts +124 -0
  48. package/dist/node_modules/nodemailer/dist/cjs/nodemailer.js +1 -0
  49. package/dist/node_modules/nodemailer/dist/cjs/package-info.d.ts +3 -0
  50. package/dist/node_modules/nodemailer/dist/cjs/package-info.js +7 -0
  51. package/dist/node_modules/nodemailer/dist/cjs/package.json +3 -0
  52. package/dist/node_modules/nodemailer/dist/cjs/punycode/index.d.ts +73 -0
  53. package/dist/node_modules/nodemailer/{lib → dist/cjs}/punycode/index.js +63 -112
  54. package/dist/node_modules/nodemailer/dist/cjs/qp/index.d.ts +32 -0
  55. package/dist/node_modules/nodemailer/dist/cjs/qp/index.js +207 -0
  56. package/dist/node_modules/nodemailer/dist/cjs/sendmail-transport/index.d.ts +69 -0
  57. package/dist/node_modules/nodemailer/dist/cjs/sendmail-transport/index.js +210 -0
  58. package/dist/node_modules/nodemailer/dist/cjs/ses-transport/index.d.ts +112 -0
  59. package/dist/node_modules/nodemailer/dist/cjs/ses-transport/index.js +252 -0
  60. package/dist/node_modules/nodemailer/dist/cjs/shared/index.d.ts +260 -0
  61. package/dist/node_modules/nodemailer/dist/cjs/shared/index.js +680 -0
  62. package/dist/node_modules/nodemailer/dist/cjs/shared/objects.d.ts +23 -0
  63. package/dist/node_modules/nodemailer/dist/cjs/shared/objects.js +43 -0
  64. package/dist/node_modules/nodemailer/dist/cjs/shared/url.d.ts +21 -0
  65. package/dist/node_modules/nodemailer/dist/cjs/shared/url.js +255 -0
  66. package/dist/node_modules/nodemailer/dist/cjs/smtp-connection/data-stream.d.ts +15 -0
  67. package/dist/node_modules/nodemailer/dist/cjs/smtp-connection/data-stream.js +108 -0
  68. package/dist/node_modules/nodemailer/dist/cjs/smtp-connection/http-proxy-client.d.ts +47 -0
  69. package/dist/node_modules/nodemailer/dist/cjs/smtp-connection/http-proxy-client.js +189 -0
  70. package/dist/node_modules/nodemailer/dist/cjs/smtp-connection/index.d.ts +416 -0
  71. package/dist/node_modules/nodemailer/dist/cjs/smtp-connection/index.js +1837 -0
  72. package/dist/node_modules/nodemailer/dist/cjs/smtp-pool/index.d.ts +133 -0
  73. package/dist/node_modules/nodemailer/dist/cjs/smtp-pool/index.js +569 -0
  74. package/dist/node_modules/nodemailer/dist/cjs/smtp-pool/pool-resource.d.ts +62 -0
  75. package/dist/node_modules/nodemailer/dist/cjs/smtp-pool/pool-resource.js +257 -0
  76. package/dist/node_modules/nodemailer/dist/cjs/smtp-transport/index.d.ts +156 -0
  77. package/dist/node_modules/nodemailer/dist/cjs/smtp-transport/index.js +371 -0
  78. package/dist/node_modules/nodemailer/dist/cjs/stream-transport/index.d.ts +65 -0
  79. package/dist/node_modules/nodemailer/dist/cjs/stream-transport/index.js +146 -0
  80. package/dist/node_modules/nodemailer/dist/cjs/well-known/index.d.ts +35 -0
  81. package/dist/node_modules/nodemailer/dist/cjs/well-known/index.js +41 -0
  82. package/dist/node_modules/nodemailer/dist/cjs/well-known/services.d.ts +2 -0
  83. package/dist/node_modules/nodemailer/dist/cjs/well-known/services.js +674 -0
  84. package/dist/node_modules/nodemailer/dist/cjs/xoauth2/index.d.ts +201 -0
  85. package/dist/node_modules/nodemailer/dist/cjs/xoauth2/index.js +426 -0
  86. package/dist/node_modules/nodemailer/dist/esm/addressparser/index.d.ts +59 -0
  87. package/dist/node_modules/nodemailer/dist/esm/addressparser/index.js +786 -0
  88. package/dist/node_modules/nodemailer/dist/esm/base64/index.d.ts +36 -0
  89. package/dist/node_modules/nodemailer/{lib → dist/esm}/base64/index.js +39 -68
  90. package/dist/node_modules/nodemailer/dist/esm/dkim/index.d.ts +52 -0
  91. package/dist/node_modules/nodemailer/{lib → dist/esm}/dkim/index.js +62 -92
  92. package/dist/node_modules/nodemailer/dist/esm/dkim/message-parser.d.ts +48 -0
  93. package/dist/node_modules/nodemailer/dist/esm/dkim/message-parser.js +176 -0
  94. package/dist/node_modules/nodemailer/dist/esm/dkim/relaxed-body.d.ts +36 -0
  95. package/dist/node_modules/nodemailer/dist/esm/dkim/relaxed-body.js +141 -0
  96. package/dist/node_modules/nodemailer/dist/esm/dkim/sign.d.ts +52 -0
  97. package/dist/node_modules/nodemailer/dist/esm/dkim/sign.js +125 -0
  98. package/dist/node_modules/nodemailer/dist/esm/errors.d.ts +96 -0
  99. package/dist/node_modules/nodemailer/dist/esm/errors.js +67 -0
  100. package/dist/node_modules/nodemailer/dist/esm/fetch/cookies.d.ts +107 -0
  101. package/dist/node_modules/nodemailer/dist/esm/fetch/cookies.js +242 -0
  102. package/dist/node_modules/nodemailer/dist/esm/fetch/index.d.ts +65 -0
  103. package/dist/node_modules/nodemailer/dist/esm/fetch/index.js +344 -0
  104. package/dist/node_modules/nodemailer/dist/esm/json-transport/index.d.ts +64 -0
  105. package/dist/node_modules/nodemailer/dist/esm/json-transport/index.js +62 -0
  106. package/dist/node_modules/nodemailer/dist/esm/mail-composer/index.d.ts +174 -0
  107. package/dist/node_modules/nodemailer/{lib → dist/esm}/mail-composer/index.js +283 -275
  108. package/dist/node_modules/nodemailer/dist/esm/mailer/index.d.ts +237 -0
  109. package/dist/node_modules/nodemailer/{lib → dist/esm}/mailer/index.js +151 -205
  110. package/dist/node_modules/nodemailer/dist/esm/mailer/mail-message.d.ts +97 -0
  111. package/dist/node_modules/nodemailer/{lib → dist/esm}/mailer/mail-message.js +111 -125
  112. package/dist/node_modules/nodemailer/dist/esm/mime-funcs/index.d.ts +161 -0
  113. package/dist/node_modules/nodemailer/dist/esm/mime-funcs/index.js +738 -0
  114. package/dist/node_modules/nodemailer/dist/esm/mime-funcs/mime-types.d.ts +2 -0
  115. package/dist/node_modules/nodemailer/{lib → dist/esm}/mime-funcs/mime-types.js +43 -49
  116. package/dist/node_modules/nodemailer/dist/esm/mime-node/index.d.ts +333 -0
  117. package/dist/node_modules/nodemailer/{lib → dist/esm}/mime-node/index.js +576 -437
  118. package/dist/node_modules/nodemailer/dist/esm/mime-node/last-newline.d.ts +5 -0
  119. package/dist/node_modules/nodemailer/{lib → dist/esm}/mime-node/last-newline.js +4 -10
  120. package/dist/node_modules/nodemailer/dist/esm/mime-node/le-unix.d.ts +9 -0
  121. package/dist/node_modules/nodemailer/{lib → dist/esm}/mime-node/le-unix.js +7 -15
  122. package/dist/node_modules/nodemailer/dist/esm/mime-node/le-windows.d.ts +10 -0
  123. package/dist/node_modules/nodemailer/{lib → dist/esm}/mime-node/le-windows.js +6 -16
  124. package/dist/node_modules/nodemailer/dist/esm/nodemailer.d.ts +124 -0
  125. package/dist/node_modules/nodemailer/dist/esm/nodemailer.js +166 -0
  126. package/dist/node_modules/nodemailer/dist/esm/package-info.d.ts +3 -0
  127. package/dist/node_modules/nodemailer/dist/esm/package-info.js +4 -0
  128. package/dist/node_modules/nodemailer/dist/esm/package.json +3 -0
  129. package/dist/node_modules/nodemailer/dist/esm/punycode/index.d.ts +73 -0
  130. package/dist/node_modules/nodemailer/dist/esm/punycode/index.js +405 -0
  131. package/dist/node_modules/nodemailer/dist/esm/qp/index.d.ts +32 -0
  132. package/dist/node_modules/nodemailer/{lib → dist/esm}/qp/index.js +59 -77
  133. package/dist/node_modules/nodemailer/dist/esm/sendmail-transport/index.d.ts +69 -0
  134. package/dist/node_modules/nodemailer/dist/esm/sendmail-transport/index.js +170 -0
  135. package/dist/node_modules/nodemailer/dist/esm/ses-transport/index.d.ts +112 -0
  136. package/dist/node_modules/nodemailer/dist/esm/ses-transport/index.js +212 -0
  137. package/dist/node_modules/nodemailer/dist/esm/shared/index.d.ts +260 -0
  138. package/dist/node_modules/nodemailer/dist/esm/shared/index.js +631 -0
  139. package/dist/node_modules/nodemailer/dist/esm/shared/objects.d.ts +23 -0
  140. package/dist/node_modules/nodemailer/dist/esm/shared/objects.js +38 -0
  141. package/dist/node_modules/nodemailer/dist/esm/shared/url.d.ts +21 -0
  142. package/dist/node_modules/nodemailer/dist/esm/shared/url.js +214 -0
  143. package/dist/node_modules/nodemailer/dist/esm/smtp-connection/data-stream.d.ts +15 -0
  144. package/dist/node_modules/nodemailer/dist/esm/smtp-connection/data-stream.js +103 -0
  145. package/dist/node_modules/nodemailer/dist/esm/smtp-connection/http-proxy-client.d.ts +47 -0
  146. package/dist/node_modules/nodemailer/dist/esm/smtp-connection/http-proxy-client.js +149 -0
  147. package/dist/node_modules/nodemailer/dist/esm/smtp-connection/index.d.ts +416 -0
  148. package/dist/node_modules/nodemailer/dist/esm/smtp-connection/index.js +1797 -0
  149. package/dist/node_modules/nodemailer/dist/esm/smtp-pool/index.d.ts +133 -0
  150. package/dist/node_modules/nodemailer/{lib → dist/esm}/smtp-pool/index.js +195 -314
  151. package/dist/node_modules/nodemailer/dist/esm/smtp-pool/pool-resource.d.ts +62 -0
  152. package/dist/node_modules/nodemailer/{lib → dist/esm}/smtp-pool/pool-resource.js +70 -107
  153. package/dist/node_modules/nodemailer/dist/esm/smtp-transport/index.d.ts +156 -0
  154. package/dist/node_modules/nodemailer/dist/esm/smtp-transport/index.js +331 -0
  155. package/dist/node_modules/nodemailer/dist/esm/stream-transport/index.d.ts +65 -0
  156. package/dist/node_modules/nodemailer/dist/esm/stream-transport/index.js +106 -0
  157. package/dist/node_modules/nodemailer/dist/esm/well-known/index.d.ts +35 -0
  158. package/dist/node_modules/nodemailer/{lib → dist/esm}/well-known/index.js +12 -23
  159. package/dist/node_modules/nodemailer/dist/esm/well-known/services.d.ts +2 -0
  160. package/dist/node_modules/nodemailer/dist/esm/well-known/services.js +671 -0
  161. package/dist/node_modules/nodemailer/dist/esm/xoauth2/index.d.ts +201 -0
  162. package/dist/node_modules/nodemailer/dist/esm/xoauth2/index.js +386 -0
  163. package/dist/node_modules/nodemailer/dist/well-known/services.json +640 -0
  164. package/dist/node_modules/nodemailer/package.json +1 -1
  165. package/package.json +4 -4
  166. package/dist/node_modules/nodemailer/.gitattributes +0 -6
  167. package/dist/node_modules/nodemailer/.ncurc.js +0 -7
  168. package/dist/node_modules/nodemailer/.prettierrc.js +0 -8
  169. package/dist/node_modules/nodemailer/lib/addressparser/index.js +0 -313
  170. package/dist/node_modules/nodemailer/lib/dkim/message-parser.js +0 -155
  171. package/dist/node_modules/nodemailer/lib/dkim/relaxed-body.js +0 -154
  172. package/dist/node_modules/nodemailer/lib/dkim/sign.js +0 -117
  173. package/dist/node_modules/nodemailer/lib/fetch/cookies.js +0 -281
  174. package/dist/node_modules/nodemailer/lib/fetch/index.js +0 -274
  175. package/dist/node_modules/nodemailer/lib/json-transport/index.js +0 -82
  176. package/dist/node_modules/nodemailer/lib/mime-funcs/index.js +0 -625
  177. package/dist/node_modules/nodemailer/lib/nodemailer.js +0 -1
  178. package/dist/node_modules/nodemailer/lib/sendmail-transport/index.js +0 -210
  179. package/dist/node_modules/nodemailer/lib/ses-transport/index.js +0 -349
  180. package/dist/node_modules/nodemailer/lib/shared/index.js +0 -688
  181. package/dist/node_modules/nodemailer/lib/smtp-connection/data-stream.js +0 -108
  182. package/dist/node_modules/nodemailer/lib/smtp-connection/http-proxy-client.js +0 -143
  183. package/dist/node_modules/nodemailer/lib/smtp-connection/index.js +0 -1825
  184. package/dist/node_modules/nodemailer/lib/smtp-transport/index.js +0 -416
  185. package/dist/node_modules/nodemailer/lib/stream-transport/index.js +0 -135
  186. package/dist/node_modules/nodemailer/lib/well-known/services.json +0 -343
  187. package/dist/node_modules/nodemailer/lib/xoauth2/index.js +0 -376
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Parsed URL in the shape of the legacy `url.parse()` result
3
+ */
4
+ export interface ParsedUrl {
5
+ protocol: string | null;
6
+ host: string | null;
7
+ hostname: string | null;
8
+ port: string | null;
9
+ pathname: string | null;
10
+ search: string | null;
11
+ path: string | null;
12
+ href: string;
13
+ auth: string | null;
14
+ /** Decoded user name, null when the URL carries no credentials */
15
+ username: string | null;
16
+ /** Decoded password, null when the URL carries none */
17
+ password: string | null;
18
+ query: string | null | Record<string, string | string[]>;
19
+ }
20
+ export declare const parse: (input?: string | null, parseQueryString?: boolean) => ParsedUrl;
21
+ export declare const resolve: (from: string, to: string) => string;
@@ -0,0 +1,214 @@
1
+ // URL parsing wrapper around the WHATWG `URL` class. It only falls back to the
2
+ // legacy, deprecation-warning-emitting `url.parse()` / `url.resolve()` for input
3
+ // the WHATWG parser rejects.
4
+ //
5
+ // The WHATWG `URL` exposes a different shape than the legacy parser, so results
6
+ // are normalized back into the legacy field names the rest of the codebase reads
7
+ // (`protocol`, `hostname`, `port`, `pathname`, `path`, `search`, `auth`, `query`,
8
+ // `href`). This keeps every existing call site unchanged.
9
+ //
10
+ // Known, accepted divergences from the legacy parser:
11
+ // - non-special schemes (smtp:/smtps:/direct:) are not host-lowercased by
12
+ // WHATWG; cosmetic only, SMTP/DNS hosts are case-insensitive. (IDNA mapping
13
+ // and IPv6 brackets are normalized back by normalizeHostname below.)
14
+ // - a literal unescaped ':' inside a password is percent-encoded by WHATWG;
15
+ // such passwords should be percent-encoded by the caller anyway.
16
+ import net from 'node:net';
17
+ import urllib from 'node:url';
18
+ import * as punycode from '../punycode/index.js';
19
+ // Matches a "scheme:" not followed by "//" (and with something after it), used
20
+ // to re-insert the authority separator the legacy parser did not require.
21
+ const SLASHLESS_AUTHORITY = /^([a-zA-Z][a-zA-Z0-9+.-]*:)(?!\/\/)([\s\S]+)$/;
22
+ // Leading and trailing C0 controls and spaces, which the WHATWG parser strips before it
23
+ // looks at the input. Stripped up front so that the slash-less form is recognized in a
24
+ // value read from a file with a trailing newline as well.
25
+ const SURROUNDING_WHITESPACE = /^[\x00-\x20]+|[\x00-\x20]+$/g;
26
+ // Leading characters legacy url.parse() skips before it reads the scheme
27
+ const LEGACY_TRIM = /^[\x00-\x20\u00a0\ufeff]+/;
28
+ // The authority of a "scheme://authority/..." or a scheme-relative "//authority/..."
29
+ // string: the scheme, if any (anything the legacy parser takes for one, it is less strict
30
+ // than WHATWG about the first character), and what the legacy parser has to report as the
31
+ // host once the userinfo is removed, see legacyParse. The legacy parser treats a backslash
32
+ // as a slash.
33
+ const AUTHORITY = /^([a-zA-Z0-9+.-]+:)?[\\/]{2}([^\\/?#]*)/;
34
+ // The WHATWG forbidden domain code points, except '%' which an opaque host may carry: the
35
+ // C0 control characters, space, DEL and the URL delimiters. CONTROL_CHARS is the C0 and DEL
36
+ // subset, checked on its own in legacyParse where the host string still carries the port
37
+ // and IPv6 brackets.
38
+ const FORBIDDEN_HOST_CHARS = /[\x00-\x20#/:<>?@[\\\]^|\x7f]/;
39
+ const CONTROL_CHARS = /[\x00-\x1f\x7f]/;
40
+ // The error the WHATWG parser throws, for a host that only fails the checks in this module
41
+ function invalidUrl(input) {
42
+ const err = new TypeError('Invalid URL');
43
+ err.code = 'ERR_INVALID_URL';
44
+ err.input = input;
45
+ return err;
46
+ }
47
+ // Legacy url.parse() for input the WHATWG parser refused. The legacy parser does not
48
+ // reject a host it can not represent: a NUL byte, a percent-encoded byte, a space or a
49
+ // '<' inside the host ends the host early and the rest becomes the path, so
50
+ // 'localhost%00.example.com' silently turns into a request to 'localhost'. When the
51
+ // input has an authority that the legacy parser reads as the host (always for
52
+ // "scheme://", for "//host" only when slashesDenoteHost is set, as url.resolve() does
53
+ // for its target), the legacy result is accepted only if that host is the whole written
54
+ // authority, lowercased and IDNA mapped the way the legacy parser does it, and carries
55
+ // no control character. A legacy result with a host (an empty one included, 'http:///x'
56
+ // is a request to localhost) that no such authority accounts for is refused as well.
57
+ // Otherwise the WHATWG error is reported. Relative input has no authority to check and
58
+ // keeps the legacy behavior.
59
+ function legacyParse(input, parseQueryString, whatwgError, slashesDenoteHost) {
60
+ const parsed = urllib.parse(input, parseQueryString, slashesDenoteHost);
61
+ const authority = AUTHORITY.exec(input.replace(LEGACY_TRIM, ''));
62
+ if (authority && (authority[1] || parsed.hostname !== null)) {
63
+ const written = authority[2].slice(authority[2].lastIndexOf('@') + 1);
64
+ if (!written || CONTROL_CHARS.test(written) || (parsed.host || '').toLowerCase() !== punycode.toASCII(written.toLowerCase())) {
65
+ throw whatwgError;
66
+ }
67
+ // the legacy parser takes any bracketed value for an IPv6 literal
68
+ if (written.charAt(0) === '[' && !net.isIPv6(written.slice(1, written.indexOf(']')))) {
69
+ throw whatwgError;
70
+ }
71
+ }
72
+ else if (parsed.hostname !== null) {
73
+ throw whatwgError;
74
+ }
75
+ // the legacy parser only offers the joined form, split it on the first colon
76
+ const legacyAuth = parsed.auth === null || parsed.auth === undefined ? null : parsed.auth.split(':');
77
+ const result = parsed;
78
+ result.username = legacyAuth ? legacyAuth.shift() : null;
79
+ result.password = legacyAuth && legacyAuth.length ? legacyAuth.join(':') : null;
80
+ return result;
81
+ }
82
+ // decodeURIComponent that never throws. Legacy url.parse() decodes the auth
83
+ // component but tolerates malformed percent sequences, so mirror that.
84
+ function safeDecode(str) {
85
+ try {
86
+ return decodeURIComponent(str);
87
+ }
88
+ catch (_err) {
89
+ return str;
90
+ }
91
+ }
92
+ // Derives the legacy-shaped bare hostname from a WHATWG URL. WHATWG keeps IPv6
93
+ // literals bracketed ('[::1]') and, for non-special schemes (smtp:/smtps:/socks:),
94
+ // percent-encodes a non-ASCII host instead of IDNA-mapping it. Both forms are
95
+ // un-resolvable when handed to net/dns/http.request, which is what every call
96
+ // site does, so map them back to what legacy url.parse() returned: the bare
97
+ // address and the IDNA mapped (lowercased, punycode) form. Idempotent on plain
98
+ // ASCII and already-punycode hosts, so special-scheme hosts (already IDNA-mapped
99
+ // by WHATWG) pass through.
100
+ function normalizeHostname(raw, href) {
101
+ const hostname = raw || '';
102
+ if (!hostname) {
103
+ // Host-less URL (e.g. 'direct:'): legacy returned '' here, not null;
104
+ // consumers do `hostname.length` / `'.' + hostname`, so keep it a string.
105
+ return '';
106
+ }
107
+ if (hostname.charAt(0) === '[' && hostname.charAt(hostname.length - 1) === ']') {
108
+ return hostname.slice(1, -1);
109
+ }
110
+ const decoded = safeDecode(hostname);
111
+ // domainToASCII applies the WHATWG host rules (IDNA mapping included) and returns an
112
+ // empty string for a host it refuses, the forbidden characters among them
113
+ const mapped = FORBIDDEN_HOST_CHARS.test(decoded) ? '' : urllib.domainToASCII(decoded);
114
+ if (!mapped) {
115
+ throw invalidUrl(href);
116
+ }
117
+ return mapped;
118
+ }
119
+ export const parse = (input, parseQueryString) => {
120
+ input = (input || '').replace(SURROUNDING_WHITESPACE, '');
121
+ // Legacy url.parse() parses a "user:pass@host:port" authority that follows
122
+ // the scheme even without the "//" separator, for schemes outside its
123
+ // built-in slashed-protocol list (smtp:/smtps:/socks:/...). The WHATWG
124
+ // parser instead treats a scheme not followed by "//" as an opaque path.
125
+ // Re-insert the "//" so slash-less connection/proxy URLs keep resolving to
126
+ // an authority, as they did before. This assumes a slash-authority scheme,
127
+ // which every consumer here uses (http/https/smtp/smtps/socks/direct); an
128
+ // opaque scheme like mailto:/data:/tel: would be mis-split, but none reach
129
+ // this module.
130
+ const slashless = SLASHLESS_AUTHORITY.exec(input);
131
+ const normalized = slashless ? slashless[1] + '//' + slashless[2] : input;
132
+ let u;
133
+ try {
134
+ u = new URL(normalized);
135
+ }
136
+ catch (err) {
137
+ // WHATWG rejects some input the legacy parser tolerated (empty/relative
138
+ // strings, scheme-relative '//host/path', out-of-range ports, ...). Fall
139
+ // back to the legacy parser so behavior, including the downstream errors
140
+ // callers rely on, is preserved. This is the only path that can still
141
+ // emit a deprecation warning; it fires for anything WHATWG cannot
142
+ // represent, including legitimate relative URLs, not just malformed input.
143
+ return legacyParse(normalized, parseQueryString, err);
144
+ }
145
+ const hostname = normalizeHostname(u.hostname, u.href);
146
+ const port = u.port || null;
147
+ const pathname = u.pathname || null;
148
+ const search = u.search || null;
149
+ // Legacy `.auth` is the decoded "user[:pass]" string; WHATWG keeps the
150
+ // username/password percent-encoded, so decode to stay byte-compatible with
151
+ // existing consumers (parseConnectionUrl, Basic/Proxy-Authorization headers).
152
+ let auth = null;
153
+ let username = null;
154
+ let password = null;
155
+ if (u.username || u.password) {
156
+ // Gate on password too: legacy url.parse('smtps://:pass@host').auth was
157
+ // ':pass'. Dropping it would silently connect unauthenticated.
158
+ username = safeDecode(u.username);
159
+ password = u.password ? safeDecode(u.password) : null;
160
+ // the joined form is ambiguous once the user name contains a colon, so
161
+ // consumers that need the parts read username and password instead
162
+ auth = username + (password !== null ? ':' + password : '');
163
+ }
164
+ let query;
165
+ if (parseQueryString) {
166
+ // Mirror querystring.parse(): null-prototype object, repeated keys become an array.
167
+ const parsed = Object.create(null);
168
+ u.searchParams.forEach((value, key) => {
169
+ if (Object.prototype.hasOwnProperty.call(parsed, key)) {
170
+ const existing = parsed[key];
171
+ if (Array.isArray(existing)) {
172
+ existing.push(value);
173
+ }
174
+ else {
175
+ parsed[key] = [existing, value];
176
+ }
177
+ }
178
+ else {
179
+ parsed[key] = value;
180
+ }
181
+ });
182
+ query = parsed;
183
+ }
184
+ else {
185
+ query = search ? search.slice(1) : null;
186
+ }
187
+ return {
188
+ protocol: u.protocol || null,
189
+ host: u.host || null,
190
+ hostname,
191
+ port,
192
+ pathname,
193
+ search,
194
+ path: (pathname || '') + (search || '') || null,
195
+ href: u.href,
196
+ auth,
197
+ username,
198
+ password,
199
+ query
200
+ };
201
+ };
202
+ export const resolve = (from, to) => {
203
+ try {
204
+ return new URL(to, from).href;
205
+ }
206
+ catch (err) {
207
+ // Malformed target, fall back to the legacy resolver, but only when the legacy
208
+ // parser reads the same host out of both inputs that was written. The target
209
+ // decides the host when it is absolute or scheme-relative, the base otherwise
210
+ legacyParse(from, false, err, true);
211
+ legacyParse(to, false, err, true);
212
+ return urllib.resolve(from, to);
213
+ }
214
+ };
@@ -0,0 +1,15 @@
1
+ import { Transform, type TransformOptions } from 'node:stream';
2
+ /**
3
+ * Escapes dots in the beginning of lines. Ends the stream with <CR><LF>.<CR><LF>
4
+ * Also makes sure that only <CR><LF> sequences are used for linebreaks, bare CR and bare LF
5
+ * are both turned into <CR><LF>
6
+ *
7
+ * @param options Stream options
8
+ */
9
+ export default class DataStream extends Transform {
10
+ options: TransformOptions;
11
+ inByteCount: number;
12
+ outByteCount: number;
13
+ lastByte: number | false;
14
+ constructor(options?: TransformOptions);
15
+ }
@@ -0,0 +1,103 @@
1
+ import { Transform } from 'node:stream';
2
+ // bytes inserted into the output, shared as they are only ever copied by Buffer.concat
3
+ const INSERT_LF = Buffer.from('\n');
4
+ const INSERT_LF_DOT = Buffer.from('\n.');
5
+ const INSERT_CR = Buffer.from('\r');
6
+ const INSERT_DOT = Buffer.from('.');
7
+ /**
8
+ * Escapes dots in the beginning of lines. Ends the stream with <CR><LF>.<CR><LF>
9
+ * Also makes sure that only <CR><LF> sequences are used for linebreaks, bare CR and bare LF
10
+ * are both turned into <CR><LF>
11
+ *
12
+ * @param options Stream options
13
+ */
14
+ export default class DataStream extends Transform {
15
+ constructor(options) {
16
+ super(options);
17
+ this.options = options || {};
18
+ this.inByteCount = 0;
19
+ this.outByteCount = 0;
20
+ this.lastByte = false;
21
+ }
22
+ /**
23
+ * Escapes dots
24
+ * @internal
25
+ */
26
+ _transform(chunk, encoding, done) {
27
+ const chunks = [];
28
+ let chunklen = 0;
29
+ let i, len, lastPos = 0;
30
+ let buf;
31
+ if (!chunk || !chunk.length) {
32
+ return done();
33
+ }
34
+ if (typeof chunk === 'string') {
35
+ chunk = Buffer.from(chunk);
36
+ }
37
+ this.inByteCount += chunk.length;
38
+ for (i = 0, len = chunk.length; i < len; i++) {
39
+ const byte = chunk[i];
40
+ const prev = i ? chunk[i - 1] : this.lastByte;
41
+ let insert = false;
42
+ if (prev === 0x0d && byte !== 0x0a) {
43
+ // a bare CR becomes CRLF. A receiver that treats a lone CR as a line end would
44
+ // otherwise see "\r.\r" as the end of the data (SMTP smuggling), so a dot
45
+ // following it is stuffed like at the start of any other line
46
+ insert = byte === 0x2e ? INSERT_LF_DOT : INSERT_LF;
47
+ }
48
+ else if (byte === 0x0a && prev !== 0x0d) {
49
+ // a bare LF becomes CRLF
50
+ insert = INSERT_CR;
51
+ }
52
+ else if (byte === 0x2e && (prev === 0x0a || prev === false)) {
53
+ // a dot at the start of a line
54
+ insert = INSERT_DOT;
55
+ }
56
+ if (insert) {
57
+ if (i > lastPos) {
58
+ buf = chunk.slice(lastPos, i);
59
+ chunks.push(buf);
60
+ chunklen += buf.length;
61
+ }
62
+ chunks.push(insert);
63
+ chunklen += insert.length;
64
+ lastPos = i;
65
+ }
66
+ }
67
+ if (chunks.length) {
68
+ // add last piece
69
+ if (lastPos < chunk.length) {
70
+ buf = chunk.slice(lastPos);
71
+ chunks.push(buf);
72
+ chunklen += buf.length;
73
+ }
74
+ this.outByteCount += chunklen;
75
+ this.push(Buffer.concat(chunks, chunklen));
76
+ }
77
+ else {
78
+ this.outByteCount += chunk.length;
79
+ this.push(chunk);
80
+ }
81
+ this.lastByte = chunk[chunk.length - 1];
82
+ done();
83
+ }
84
+ /**
85
+ * Finalizes the stream with a dot on a single line
86
+ * @internal
87
+ */
88
+ _flush(done) {
89
+ let buf;
90
+ if (this.lastByte === 0x0a) {
91
+ buf = Buffer.from('.\r\n');
92
+ }
93
+ else if (this.lastByte === 0x0d) {
94
+ buf = Buffer.from('\n.\r\n');
95
+ }
96
+ else {
97
+ buf = Buffer.from('\r\n.\r\n');
98
+ }
99
+ this.outByteCount += buf.length;
100
+ this.push(buf);
101
+ done();
102
+ }
103
+ }
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Minimal HTTP/S proxy client
3
+ */
4
+ import net from 'node:net';
5
+ import type { Callback } from '../errors.js';
6
+ /**
7
+ * TLS options for connecting to an HTTPS proxy
8
+ */
9
+ export interface HttpProxyClientOptions {
10
+ /** Set to false to accept a proxy certificate that fails validation (e.g. self-signed) */
11
+ rejectUnauthorized?: boolean | undefined;
12
+ }
13
+ /**
14
+ * Receives the proxied socket once the CONNECT handshake has succeeded, or the error that prevented it
15
+ */
16
+ export type HttpProxyClientCallback = Callback<net.Socket>;
17
+ /**
18
+ * Establishes proxied connection to destinationPort
19
+ *
20
+ * httpProxyClient("http://localhost:3128/", 80, "google.com", function(err, socket){
21
+ * socket.write("GET / HTTP/1.0\r\n\r\n");
22
+ * });
23
+ *
24
+ * @param proxyUrl proxy configuration, e.g. "http://proxy.host:3128/"
25
+ * @param destinationPort Port to open in destination host
26
+ * @param destinationHost Destination hostname
27
+ * @param callback Callback to run with the socket object once connection is established
28
+ */
29
+ declare function httpProxyClient(proxyUrl: string, destinationPort: number | string, destinationHost: string, callback: HttpProxyClientCallback): void;
30
+ /**
31
+ * Establishes proxied connection to destinationPort through an HTTPS proxy
32
+ *
33
+ * @param proxyUrl proxy configuration, e.g. "https://proxy.host:3128/"
34
+ * @param destinationPort Port to open in destination host
35
+ * @param destinationHost Destination hostname
36
+ * @param tlsOptions TLS options for the proxy connection (e.g. { rejectUnauthorized: false })
37
+ * @param callback Callback to run with the socket object once connection is established
38
+ */
39
+ declare function httpProxyClient(proxyUrl: string, destinationPort: number | string, destinationHost: string, tlsOptions: HttpProxyClientOptions | undefined, callback: HttpProxyClientCallback): void;
40
+ /**
41
+ * Socket timeout in milliseconds while the CONNECT handshake is in progress, defaults to 30 seconds.
42
+ * Settable on the function itself, the same way the CommonJS module exposed it.
43
+ */
44
+ declare namespace httpProxyClient {
45
+ let timeout: number | undefined;
46
+ }
47
+ export default httpProxyClient;
@@ -0,0 +1,149 @@
1
+ /**
2
+ * Minimal HTTP/S proxy client
3
+ */
4
+ import net from 'node:net';
5
+ import tls from 'node:tls';
6
+ import * as urllib from '../shared/url.js';
7
+ import * as errors from '../errors.js';
8
+ // Cap the CONNECT response we buffer before the header terminator, so a proxy that
9
+ // never sends \r\n\r\n cannot grow memory unboundedly before the socket times out.
10
+ const MAX_RESPONSE_HEADER_BYTES = 64 * 1024;
11
+ function httpProxyClient(proxyUrl, destinationPort, destinationHost, tlsOptions, callback) {
12
+ if (typeof tlsOptions === 'function') {
13
+ callback = tlsOptions;
14
+ tlsOptions = {};
15
+ }
16
+ tlsOptions = tlsOptions || {};
17
+ // the error paths hand over the error alone
18
+ const done = callback;
19
+ // Reject CRLF in the destination before it reaches the CONNECT request line
20
+ // and Host header. A tainted host/port could otherwise inject additional
21
+ // request headers into the proxy connection (HTTP request splitting).
22
+ destinationPort = Number(destinationPort) || 0;
23
+ if (!destinationPort || /[\r\n]/.test(destinationHost)) {
24
+ const err = new Error('Invalid proxy destination');
25
+ err.code = errors.EPROXY;
26
+ setImmediate(() => done(err));
27
+ return;
28
+ }
29
+ const proxy = urllib.parse(proxyUrl);
30
+ const connectOptions = {
31
+ host: proxy.hostname,
32
+ port: Number(proxy.port) ? Number(proxy.port) : proxy.protocol === 'https:' ? 443 : 80
33
+ };
34
+ let connect;
35
+ if (proxy.protocol === 'https:') {
36
+ // Validate the proxy's TLS certificate by default. A caller that uses a
37
+ // self-signed proxy (e.g. integration tests) opts out explicitly with
38
+ // tls.rejectUnauthorized === false.
39
+ connectOptions.rejectUnauthorized = tlsOptions.rejectUnauthorized !== false;
40
+ connect = tls.connect.bind(tls);
41
+ }
42
+ else {
43
+ connect = net.connect.bind(net);
44
+ }
45
+ let socket;
46
+ // Error harness for initial connection. Once connection is established, the responsibility
47
+ // to handle errors is passed to whoever uses this socket
48
+ let finished = false;
49
+ const tempSocketErr = (err) => {
50
+ if (finished) {
51
+ return;
52
+ }
53
+ finished = true;
54
+ try {
55
+ socket.destroy();
56
+ }
57
+ catch (_E) {
58
+ // ignore
59
+ }
60
+ done(err);
61
+ };
62
+ const timeoutErr = () => {
63
+ const err = new Error('Proxy socket timed out');
64
+ err.code = 'ETIMEDOUT';
65
+ tempSocketErr(err);
66
+ };
67
+ socket = connect(connectOptions, () => {
68
+ if (finished) {
69
+ return;
70
+ }
71
+ const reqHeaders = {
72
+ Host: destinationHost + ':' + destinationPort,
73
+ Connection: 'close'
74
+ };
75
+ if (proxy.auth) {
76
+ reqHeaders['Proxy-Authorization'] = 'Basic ' + Buffer.from(proxy.auth).toString('base64');
77
+ }
78
+ socket.write(
79
+ // HTTP method
80
+ 'CONNECT ' +
81
+ destinationHost +
82
+ ':' +
83
+ destinationPort +
84
+ ' HTTP/1.1\r\n' +
85
+ // HTTP request headers
86
+ Object.keys(reqHeaders)
87
+ .map(key => key + ': ' + reqHeaders[key])
88
+ .join('\r\n') +
89
+ // End request
90
+ '\r\n\r\n');
91
+ // The response is collected as chunks and only the bytes that just arrived, together
92
+ // with the three before them, are searched for the end of the headers. Appending to a
93
+ // string and searching all of it again re-read the whole response on every chunk.
94
+ const chunks = [];
95
+ let received = 0;
96
+ let tail = '';
97
+ const onSocketData = (chunk) => {
98
+ let match;
99
+ if (finished) {
100
+ return;
101
+ }
102
+ const window = tail + chunk.toString('binary');
103
+ const windowEnd = window.indexOf('\r\n\r\n');
104
+ chunks.push(chunk);
105
+ received += chunk.length;
106
+ tail = window.slice(-3);
107
+ if (windowEnd >= 0) {
108
+ socket.removeListener('data', onSocketData);
109
+ const headerEnd = received - window.length + windowEnd;
110
+ const response = Buffer.concat(chunks, received).toString('binary');
111
+ const headers = response.substr(0, headerEnd);
112
+ const remainder = response.substr(headerEnd + 4);
113
+ if (remainder) {
114
+ socket.unshift(Buffer.from(remainder, 'binary'));
115
+ }
116
+ // proxy connection is now established
117
+ finished = true;
118
+ // check response code
119
+ match = headers.match(/^HTTP\/\d+\.\d+ (\d+)/i);
120
+ if (!match || (match[1] || '').charAt(0) !== '2') {
121
+ try {
122
+ socket.destroy();
123
+ }
124
+ catch (_E) {
125
+ // ignore
126
+ }
127
+ const err = new Error('Invalid response from proxy' + ((match && ': ' + match[1]) || ''));
128
+ err.code = errors.EPROXY;
129
+ return done(err);
130
+ }
131
+ socket.removeListener('error', tempSocketErr);
132
+ socket.removeListener('timeout', timeoutErr);
133
+ socket.setTimeout(0);
134
+ return done(null, socket);
135
+ }
136
+ if (received > MAX_RESPONSE_HEADER_BYTES) {
137
+ socket.removeListener('data', onSocketData);
138
+ const err = new Error('Proxy response headers too large');
139
+ err.code = errors.EPROXY;
140
+ return tempSocketErr(err);
141
+ }
142
+ };
143
+ socket.on('data', onSocketData);
144
+ });
145
+ socket.setTimeout(httpProxyClient.timeout || 30 * 1000);
146
+ socket.on('timeout', timeoutErr);
147
+ socket.once('error', tempSocketErr);
148
+ }
149
+ export default httpProxyClient;