@zone-eu/mailsplit 5.4.26 → 5.4.27

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 (3) hide show
  1. package/README.md +43 -54
  2. package/lib/mime-node.js +7 -3
  3. package/package.json +20 -15
package/README.md CHANGED
@@ -29,9 +29,9 @@ let splitter = new Splitter(options);
29
29
 
30
30
  Where
31
31
 
32
- - **options** is an optional options object
33
- - **options.ignoreEmbedded** (boolean, defaults to false) if true then treat message/rfc822 node as normal leaf node and do not try to parse it
34
- - **options.maxHeadSize** (number, defaults to 1 MiB) limits the header size of a MIME node in bytes, every header line counting for at least 64 bytes
32
+ - **options** is an optional options object
33
+ - **options.ignoreEmbedded** (boolean, defaults to false) if true then treat message/rfc822 node as normal leaf node and do not try to parse it
34
+ - **options.maxHeadSize** (number, defaults to 1 MiB) limits the header size of a MIME node in bytes, every header line counting for at least 64 bytes
35
35
 
36
36
  #### Events
37
37
 
@@ -39,13 +39,13 @@ Where
39
39
 
40
40
  #### Data objects
41
41
 
42
- - **type**
43
- - `'node'` means that we reached the next mime node and the previous one is completely processed
44
- - `'data'` provides us multipart body parts, including boundaries. This data is not directly related to any specific multipart node, basically it includes everything between the end of one normal node and the header of next node
45
- - `'body'` provides us next chunk for the last seen `'node'` element
46
- - **value** is a buffer value for `'body'` and `'data'` parts
47
- - **getDecoder()** is a function that returns a stream object you can use to decode node contents. Write data from 'body' to decoder and read decoded Buffer value out from it
48
- - **getEncoder()** is a function that returns a stream object you can use to encode node contents. Write buffer data to encoder and read encoded object value out that you can pass to a Joiner
42
+ - **type**
43
+ - `'node'` means that we reached the next mime node and the previous one is completely processed
44
+ - `'data'` provides us multipart body parts, including boundaries. This data is not directly related to any specific multipart node, basically it includes everything between the end of one normal node and the header of next node
45
+ - `'body'` provides us next chunk for the last seen `'node'` element
46
+ - **value** is a buffer value for `'body'` and `'data'` parts
47
+ - **getDecoder()** is a function that returns a stream object you can use to decode node contents. Write data from 'body' to decoder and read decoded Buffer value out from it
48
+ - **getEncoder()** is a function that returns a stream object you can use to encode node contents. Write buffer data to encoder and read encoded object value out that you can pass to a Joiner
49
49
 
50
50
  Element with type `'node'` has a bunch of header related methods and properties, see [below](#manipulating-headers).
51
51
 
@@ -82,31 +82,31 @@ someMessagStream.pipe(splitter);
82
82
 
83
83
  If the data object has `type='node'` then you can modify headers for that node (headers can be modified until the data object is passed over to a `Joiner`)
84
84
 
85
- - **node.getHeaders()** returns a Buffer value with generated headers. If you have not modified the headers object in any way then you should get the exact copy of the original. In case you have done something (for example removed a key, or added a new header key), then all linebreaks are forced to <CR><LF> even if the original headers used just <LF>
86
- - **node.setContentType(contentType)** sets or updates mime type for the node
87
- - **node.setCharset(charset)** sets or updates character set in the Content-Type header
88
- - **node.setFilename(filename)** sets or updates filename in the Content-Disposition header (unicode allowed)
85
+ - **node.getHeaders()** returns a Buffer value with generated headers. If you have not modified the headers object in any way then you should get the exact copy of the original. In case you have done something (for example removed a key, or added a new header key), then all linebreaks are forced to <CR><LF> even if the original headers used just <LF>
86
+ - **node.setContentType(contentType)** sets or updates mime type for the node
87
+ - **node.setCharset(charset)** sets or updates character set in the Content-Type header
88
+ - **node.setFilename(filename)** sets or updates filename in the Content-Disposition header (unicode allowed)
89
89
 
90
90
  You can manipulate specific header keys as well using the `headers` object
91
91
 
92
- - **node.headers.get(key)** returns an array of strings with all header rows for the selected key (these are full header lines, so key name is part of the row string, eg `["Subject: This is subject line"]`)
93
- - **node.headers.getFirst(key)** returns string value of the specified header key (eg `"This is subject line"`)
94
- - **node.headers.hasHeader(key)** returns boolean value if the specified header key exists
95
- - **node.headers.add(key, value [,index])** adds a new header value to the specified index or to the top of the header block if index is not specified
96
- - **node.headers.update(key, value, [,relativeKeyIndex])** replaces a header value to the specified relative key index (note that relative key index means relative to the same header key, eg if multiple exist and you specify `1` as the value, then it will update the second) or if no relative key index is specified, then it will remove all header value matches found for the key and append one at the last matching key index found with the specified value. If a relative key index is specified and it does not exist then it will be replaced (eg if there are two headers of `X-Foo-Bar` and you pass `2`, meaning it will update the third, no updates will be made since the third did not exist)
97
- - **node.headers.remove(key)** remove header value
98
- - **node.headers.mbox** If this is a MBOX formatted message then this value holds the prefix line (eg. "From MAILER-DAEMON Fri Jul 8 12:08:34 2011")
99
- - **node.headers.mbox** If this is a POST form-data then this value holds the HTTP prefix line (eg. "POST /upload.php HTTP/1.1")
92
+ - **node.headers.get(key)** returns an array of strings with all header rows for the selected key (these are full header lines, so key name is part of the row string, eg `["Subject: This is subject line"]`)
93
+ - **node.headers.getFirst(key)** returns string value of the specified header key (eg `"This is subject line"`)
94
+ - **node.headers.hasHeader(key)** returns boolean value if the specified header key exists
95
+ - **node.headers.add(key, value [,index])** adds a new header value to the specified index or to the top of the header block if index is not specified
96
+ - **node.headers.update(key, value, [,relativeKeyIndex])** replaces a header value to the specified relative key index (note that relative key index means relative to the same header key, eg if multiple exist and you specify `1` as the value, then it will update the second) or if no relative key index is specified, then it will remove all header value matches found for the key and append one at the last matching key index found with the specified value. If a relative key index is specified and it does not exist then it will be replaced (eg if there are two headers of `X-Foo-Bar` and you pass `2`, meaning it will update the third, no updates will be made since the third did not exist)
97
+ - **node.headers.remove(key)** remove header value
98
+ - **node.headers.mbox** If this is a MBOX formatted message then this value holds the prefix line (eg. "From MAILER-DAEMON Fri Jul 8 12:08:34 2011")
99
+ - **node.headers.mbox** If this is a POST form-data then this value holds the HTTP prefix line (eg. "POST /upload.php HTTP/1.1")
100
100
 
101
101
  Additionally you can check the details of the node with the following properties automatically parsed from the headers:
102
102
 
103
- - **node.root** if true then it means this is the message root, so this node should contain Subject, From, To etc. headers
104
- - **node.contentType** returns the mime type of the node (eg. 'text/html')
105
- - **node.disposition** either `'attachment'`, `'inline'` or `false` if not set
106
- - **node.charset** returns the charset of the node as defined in 'Content-Type' header (eg. 'UTF-8') or false if not defined
107
- - **node.encoding** returns the Transfer-Encoding value (eg. 'base64' or 'quoted-printable') or false if not defined
108
- - **node.multipart** if has value, then this is a multipart node (does not have 'body' parts)
109
- - **node.filename** is set if the headers contain a filename value. This is decoded to unicode, so it is a normal string or false if not found
103
+ - **node.root** if true then it means this is the message root, so this node should contain Subject, From, To etc. headers
104
+ - **node.contentType** returns the mime type of the node (eg. 'text/html')
105
+ - **node.disposition** either `'attachment'`, `'inline'` or `false` if not set
106
+ - **node.charset** returns the charset of the node as defined in 'Content-Type' header (eg. 'UTF-8') or false if not defined
107
+ - **node.encoding** returns the Transfer-Encoding value (eg. 'base64' or 'quoted-printable') or false if not defined
108
+ - **node.multipart** if has value, then this is a multipart node (does not have 'body' parts)
109
+ - **node.filename** is set if the headers contain a filename value. This is decoded to unicode, so it is a normal string or false if not found
110
110
 
111
111
  ### Join parsed message stream
112
112
 
@@ -118,10 +118,7 @@ let Joiner = require('mailsplit').Joiner;
118
118
  let splitter = new Splitter();
119
119
  let joiner = new Joiner();
120
120
  // pipe a message source to splitter, then joiner and finally to stdout
121
- someMessagStream
122
- .pipe(splitter)
123
- .pipe(joiner)
124
- .pipe(process.stdout);
121
+ someMessagStream.pipe(splitter).pipe(joiner).pipe(process.stdout);
125
122
  ```
126
123
 
127
124
  ### Rewrite specific nodes
@@ -130,14 +127,14 @@ someMessagStream
130
127
 
131
128
  Rewriter takes the following argument:
132
129
 
133
- - **filterFunc** gets the current node as argument and starts processing it if `filterFunc` returns true
130
+ - **filterFunc** gets the current node as argument and starts processing it if `filterFunc` returns true
134
131
 
135
132
  Once Rewriter finds a matching node, it emits the following event:
136
133
 
137
- - _'node'_ with an object argument `data`
138
- - `data.node` includes the current node with headers
139
- - `data.decoder` is the decoder stream that you can read data from
140
- - `data.encoder` is the encoder stream that you can write data to. Whatever you write into that stream will be encoded properly and inserted as the content of the current node
134
+ - _'node'_ with an object argument `data`
135
+ - `data.node` includes the current node with headers
136
+ - `data.decoder` is the decoder stream that you can read data from
137
+ - `data.encoder` is the encoder stream that you can write data to. Whatever you write into that stream will be encoded properly and inserted as the content of the current node
141
138
 
142
139
  ```javascript
143
140
  let Splitter = require('mailsplit').Splitter;
@@ -153,11 +150,7 @@ rewriter.on('node', data => {
153
150
  data.decoder.pipe(data.encoder);
154
151
  });
155
152
  // pipe a message source to splitter, then rewriter, then joiner and finally to stdout
156
- someMessagStream
157
- .pipe(splitter)
158
- .pipe(rewriter)
159
- .pipe(joiner)
160
- .pipe(process.stdout);
153
+ someMessagStream.pipe(splitter).pipe(rewriter).pipe(joiner).pipe(process.stdout);
161
154
  ```
162
155
 
163
156
  ### Stream specific nodes
@@ -166,14 +159,14 @@ someMessagStream
166
159
 
167
160
  Streamer takes the following argument:
168
161
 
169
- - **filterFunc** gets the current node as argument and starts processing it if `filterFunc` returns true
162
+ - **filterFunc** gets the current node as argument and starts processing it if `filterFunc` returns true
170
163
 
171
164
  Once Streamer finds a matching node, it emits the following event:
172
165
 
173
- - _'node'_ with an object argument `data`
174
- - `data.node` includes the current node with headers (informational only, you can't modify it)
175
- - `data.decoder` is the decoder stream that you can read data from
176
- - `data.done` is a function you must call once you have processed the stream
166
+ - _'node'_ with an object argument `data`
167
+ - `data.node` includes the current node with headers (informational only, you can't modify it)
168
+ - `data.decoder` is the decoder stream that you can read data from
169
+ - `data.done` is a function you must call once you have processed the stream
177
170
 
178
171
  ```javascript
179
172
  let Splitter = require('mailsplit').Splitter;
@@ -189,11 +182,7 @@ streamer.on('node', data => {
189
182
  data.done();
190
183
  });
191
184
  // pipe a message source to splitter, then streamer, then joiner and finally to stdout
192
- someMessagStream
193
- .pipe(splitter)
194
- .pipe(streamer)
195
- .pipe(joiner)
196
- .pipe(process.stdout);
185
+ someMessagStream.pipe(splitter).pipe(streamer).pipe(joiner).pipe(process.stdout);
197
186
  ```
198
187
 
199
188
  ### Benchmark
@@ -211,4 +200,4 @@ Done. 20000 messages [1244 MB] processed in 55.882 s. with average of 358 messag
211
200
 
212
201
  Dual licensed under **MIT** or **EUPLv1.1+**
213
202
 
214
- > `mailsplit` is part of the Zone Mail Suite (ZMS). Suite of programs and modules for an efficient, fast and modern email server.
203
+ > `mailsplit` is part of the Zone Mail Suite (ZMS). Suite of programs and modules for an efficient, fast and modern email server.
package/lib/mime-node.js CHANGED
@@ -73,7 +73,11 @@ function rfc2231ParamNames(value) {
73
73
  if (eq < 0) {
74
74
  return;
75
75
  }
76
- let match = segment.substring(0, eq).trim().toLowerCase().match(/^(.+?)\*(\d+\*?)?$/);
76
+ let match = segment
77
+ .substring(0, eq)
78
+ .trim()
79
+ .toLowerCase()
80
+ .match(/^(.+?)\*(\d+\*?)?$/);
77
81
  if (match) {
78
82
  names.add(match[1]);
79
83
  }
@@ -248,7 +252,7 @@ class MimeNode {
248
252
  if (this.disposition) {
249
253
  try {
250
254
  this.disposition = this.libmime.decodeWords(this.disposition);
251
- } catch (E) {
255
+ } catch (_E) {
252
256
  // failed to parse disposition, keep as is (most probably an unknown charset is used)
253
257
  }
254
258
  }
@@ -270,7 +274,7 @@ class MimeNode {
270
274
  if (!decoded) {
271
275
  try {
272
276
  this.filename = this.libmime.decodeWords(this.filename);
273
- } catch (E) {
277
+ } catch (_E) {
274
278
  // failed to parse filename, keep as is (most probably an unknown charset is used)
275
279
  }
276
280
  }
package/package.json CHANGED
@@ -1,38 +1,43 @@
1
1
  {
2
2
  "name": "@zone-eu/mailsplit",
3
- "version": "5.4.26",
3
+ "version": "5.4.27",
4
4
  "description": "Split email messages into an object stream",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
7
+ "engines": {
8
+ "node": ">=20.0.0"
9
+ },
7
10
  "directories": {
8
11
  "test": "test"
9
12
  },
10
13
  "scripts": {
11
- "test": "grunt",
12
- "update": "rm -rf node_modules package-lock.json && ncu -u && npm install",
13
- "typecheck": "tsc -p tsconfig.json"
14
+ "test": "node --test test/*-test.js",
15
+ "test:cjs": "NODE_OPTIONS=--no-experimental-require-module npm test",
16
+ "test:coverage": "c8 npm test",
17
+ "lint": "npm run typecheck && eslint .",
18
+ "lint:fix": "eslint . --fix",
19
+ "format": "prettier --write .",
20
+ "format:check": "prettier --check .",
21
+ "typecheck": "tsc -p tsconfig.json",
22
+ "update": "rm -rf node_modules package-lock.json && ncu -u && npm install"
14
23
  },
15
24
  "author": "Andris Reinman",
16
25
  "license": "(MIT OR EUPL-1.1+)",
17
26
  "dependencies": {
18
27
  "libbase64": "1.4.1",
19
- "libmime": "5.5.1",
28
+ "libmime": "5.5.2",
20
29
  "libqp": "3.0.1"
21
30
  },
22
31
  "devDependencies": {
23
- "@types/eslint": "9.6.1",
24
- "@types/eslint-config-prettier": "6.11.3",
25
- "@types/grunt": "0.4.32",
32
+ "@eslint/js": "10.0.1",
26
33
  "@types/libmime": "5.3.0",
27
34
  "@types/libqp": "1.1.3",
28
35
  "@types/node": "26.6.5",
29
- "eslint": "8.29.0",
30
- "eslint-config-nodemailer": "1.2.0",
31
- "eslint-config-prettier": "9.1.0",
32
- "grunt": "1.6.3",
33
- "grunt-cli": "1.5.0",
34
- "grunt-contrib-nodeunit": "5.0.0",
35
- "grunt-eslint": "24.0.1",
36
+ "c8": "12.0.0",
37
+ "eslint": "10.13.0",
38
+ "eslint-config-prettier": "10.1.8",
39
+ "globals": "17.13.0",
40
+ "prettier": "3.9.10",
36
41
  "random-message": "1.1.0",
37
42
  "typescript": "7.0.2"
38
43
  },