@postalsys/email-text-tools 2.4.24 → 2.4.26

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.
@@ -28,10 +28,11 @@ jobs:
28
28
  contents: read
29
29
  id-token: write
30
30
  steps:
31
- - uses: actions/checkout@v6
32
- - uses: actions/setup-node@v6
31
+ - uses: actions/checkout@v7
32
+ - uses: actions/setup-node@v7
33
33
  with:
34
34
  node-version: 24
35
+ package-manager-cache: false
35
36
  registry-url: 'https://registry.npmjs.org'
36
37
  - run: npm ci
37
38
  - run: npm publish --provenance --access public
@@ -15,17 +15,21 @@ jobs:
15
15
  test:
16
16
  strategy:
17
17
  matrix:
18
- node: [22.x, 24.x]
18
+ node: [20.x, 22.x, 24.x, latest]
19
19
  os: [ubuntu-latest]
20
20
  runs-on: ${{ matrix.os }}
21
21
  timeout-minutes: 10
22
22
  steps:
23
- - uses: actions/checkout@v6
23
+ - uses: actions/checkout@v7
24
24
  - name: Use Node.js ${{ matrix.node }}
25
- uses: actions/setup-node@v6
25
+ uses: actions/setup-node@v7
26
26
  with:
27
27
  node-version: ${{ matrix.node }}
28
28
  cache: npm
29
- - run: npm install
29
+ - run: npm ci
30
30
  - run: npm run lint
31
+ - run: npm run format:check
31
32
  - run: npm test
33
+ - name: CommonJS dependency graph (require(esm) disabled)
34
+ if: matrix.node != '20.x'
35
+ run: npm run test:cjs
package/.ncurc.js CHANGED
@@ -1,3 +1,5 @@
1
+ 'use strict';
2
+
1
3
  module.exports = {
2
4
  upgrade: true,
3
5
  reject: [
@@ -17,6 +19,10 @@ module.exports = {
17
19
  // 2.0.0 is ESM-only (exports only src/he.mjs) and requires Node >=22, so require('he') throws
18
20
  // and pkg cannot bundle it. 1.2.0 is the last CommonJS release; EmailEngine and mailparser
19
21
  // hold it there too, and a different copy here would be a second he in their trees
20
- 'he'
22
+ 'he',
23
+ // @asamuzakjp/css-color >=4.1.2 pulls in @csstools/* which are pure ESM, so require(jsdom) fails
24
+ // without require(esm) (jsdom -> cssstyle -> @asamuzakjp/css-color). Held at 4.1.1 through
25
+ // package.json "overrides"; overrides do not propagate to consumers, EmailEngine carries its own.
26
+ '@asamuzakjp/css-color'
21
27
  ]
22
28
  };
package/.prettierrc.js CHANGED
@@ -1,3 +1,5 @@
1
+ 'use strict';
2
+
1
3
  module.exports = {
2
4
  printWidth: 160,
3
5
  tabWidth: 4,
@@ -1,3 +1,3 @@
1
1
  {
2
- ".": "2.4.24"
2
+ ".": "2.4.26"
3
3
  }
package/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # Changelog
2
2
 
3
+ ## [2.4.26](https://github.com/postalsys/email-text-tools/compare/v2.4.25...v2.4.26) (2026-10-19)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * bump email-content to 0.1.17 and node-html-parser to 9.0.5 ([e95e4a8](https://github.com/postalsys/email-text-tools/commit/e95e4a840a5d343004c022ccaeaf4caec1d4e142))
9
+
10
+ ## [2.4.25](https://github.com/postalsys/email-text-tools/compare/v2.4.24...v2.4.25) (2026-10-18)
11
+
12
+
13
+ ### Bug Fixes
14
+
15
+ * bump @postalsys/email-content to 0.1.16 ([2c31e98](https://github.com/postalsys/email-text-tools/commit/2c31e98d087937e677c1a2f7d6f066d18148d788))
16
+
3
17
  ## [2.4.24](https://github.com/postalsys/email-text-tools/compare/v2.4.23...v2.4.24) (2026-10-18)
4
18
 
5
19
 
package/CLAUDE.md ADDED
@@ -0,0 +1,105 @@
1
+ # CLAUDE.md
2
+
3
+ This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4
+
5
+ ## Commands
6
+
7
+ ```bash
8
+ npm test # run the full suite (node --test test/*.test.js)
9
+ npm run test:cjs # the suite with require(esm) disabled (CommonJS graph guard)
10
+ npm run test:coverage # with experimental coverage
11
+ npm run test:watch # watch mode
12
+ npm run lint # eslint .
13
+ npm run lint:fix # eslint . --fix
14
+ npm run format # prettier --write .
15
+ npm run format:check # prettier --check .
16
+ npm run update # rm -rf node_modules package-lock.json && ncu -u && npm install
17
+ ```
18
+
19
+ Run a single test file or a single test by name (uses Node's built-in test runner):
20
+
21
+ ```bash
22
+ node --test test/mime-html.test.js
23
+ node --test --test-name-pattern="should process HTML in worker thread"
24
+ ```
25
+
26
+ Benchmarks are not wired into npm scripts; run them directly, e.g. `node benchmark/benchmark.js` (see `benchmark/` and `docs/PERFORMANCE.md`).
27
+
28
+ ## Critical constraints
29
+
30
+ - **CommonJS only, Node 20 minimum.** See Platform constraints below. All source uses `require`/`module.exports` with a global `'use strict'` (ESLint enforces `sourceType: 'commonjs'`). The constraint is about the module format, not the syntax level: ESLint parses `ecmaVersion: 2022`, which every supported Node (>=20) and pkg target runs natively. The `require('juice').default || require('juice')` idiom at the require sites is a deliberate CJS-interop fallback, not dead code.
31
+ - **Releases are automated via release-please.** Version in `package.json` and `CHANGELOG.md` are owned by the bot, do not bump them by hand. Conventional Commits drive it (`fix:` -> patch, `feat:` -> minor); `fix:`/`feat:` commits land directly on `main` and release-please opens the release PR. See Conventions below for the full commit rules.
32
+ - **ESLint uses the shared flat config** (`eslint.config.js`, ESLint 10). It is the CommonJS template shared across the Postal Systems / Nodemailer packages (eslint:recommended plus the retired eslint-config-nodemailer rules, eslint-config-prettier last); keep it identical to the other repos except for the "Repo-specific" block at the end, where each override carries a one-line reason. The only override here turns `no-await-in-loop` off for `benchmark/`, which awaits sequentially on purpose. CI (`.github/workflows/test.yaml`) runs lint, `format:check` and the tests on Node 20, 22 and 24, plus `npm run test:cjs` on 22 and 24.
33
+
34
+ ## Platform constraints
35
+
36
+ - **Node.js 20 is the minimum supported version** (`engines.node` is `>=20.0.0`). Runtime code, tests and tooling must work on Node 20, 22 and 24.
37
+ - **Everything that reaches runtime must be genuinely CommonJS-loadable.** EmailEngine consumes this library and ships as a single-file binary built with [`@yao-pkg/pkg`](https://github.com/yao-pkg/pkg), which snapshots a CommonJS module graph and cannot load ES modules. `require()` of this package and of every runtime dependency must work with `--no-experimental-require-module`: Node 22+ (and 20.19) enable require(esm) by default, which hides an ESM-only dependency until the pkg binary fails. A CommonJS entry that only wraps a dynamic `import()` of ESM code does not count.
38
+ - **How to check:** `npm run test:cjs` runs the whole suite under `NODE_OPTIONS=--no-experimental-require-module`; CI runs it on Node 22 and 24.
39
+ - **Pins:** never add or upgrade to an ESM-only dependency. Hold the last CommonJS major in `.ncurc.js` (`reject` or `target`) with a one-line reason; `npm run update` honors it. Currently rejected: `nanoid`, `jsdom` (27.0.1 pulls an ESM-only parse5), `juice` (12+ is pure ESM and needs Node >=22.12), `linkify-it` (6.0.0 changed exports and stopped linkifying bare domains), `he` (2.0.0 is ESM-only), `@asamuzakjp/css-color`.
40
+ - **The jsdom chain:** jsdom -> cssstyle -> `@asamuzakjp/css-color` >=4.1.2 pulls in `@csstools/*` v4, which are pure ESM. `package.json` `"overrides"` holds `@asamuzakjp/css-color` at 4.1.1 so this repo's own tests and CI exercise the CommonJS graph. Overrides do not propagate to consumers: an app installing this package resolves css-color itself, and EmailEngine carries its own identical override and `.ncurc.js` reject.
41
+
42
+ ## Conventions
43
+
44
+ These mirror the conventions used across Postal Systems projects (see `../emailengine`).
45
+
46
+ **Git commits**
47
+
48
+ - Use Conventional Commits: `fix:` (patch release), `feat:` (minor release), and `chore:`/`build:`/`ci:`/`docs:`/`refactor:`/`style:`/`test:` for changes that should not trigger a release. release-please derives the version and changelog from these prefixes.
49
+ - Do **not** list Claude or any AI assistant as a co-author / co-contributor in commit messages or PR descriptions (no `Co-Authored-By` trailer).
50
+ - Append `[skip ci]` to commits that do not change runtime behavior (docs, comments, CI/workflow tweaks, formatting) to avoid spending CI minutes. Exception: never add `[skip ci]` to a `fix:` or `feat:` commit, those must run so the release workflow triggers.
51
+
52
+ **Code & docs style**
53
+
54
+ - No emojis anywhere in code or documentation, printable ASCII only.
55
+ - Use a single hyphen-minus (`-`) as a dash in user-facing strings and docs. Never use double hyphens (`--`), em dashes, or en dashes.
56
+
57
+ **Before committing code changes**
58
+
59
+ 1. `npm run format` and `npm run lint`
60
+ 2. `npm test`
61
+ 3. For non-trivial changes, consider `/simplify` (quality cleanup) and `/security-review`. This library sanitizes untrusted HTML, so anything touching the `mimeHtml` pipeline is security-sensitive.
62
+
63
+ **After pushing**
64
+
65
+ - Check the workflow runs for the push (`gh run list --branch <branch>`) and report their status. If a run fails for an unrelated/infrastructure reason (checkout reporting "account suspended", HTTP 403, other auth errors), check <https://www.githubstatus.com/> for an active GitHub incident before assuming the change caused it.
66
+
67
+ ## Architecture
68
+
69
+ A small CommonJS library exposing five text-transformation functions for email content, all re-exported from `index.js` (`mimeHtml` through a lazy getter, so jsdom only loads on first use):
70
+
71
+ | Export | File | Purpose |
72
+ | ------------ | --------------------- | ----------------------------------------------------------- |
73
+ | `textToHtml` | `lib/text-to-html.js` | plain text -> HTML (linkified, quote-aware) |
74
+ | `htmlToText` | `lib/html-to-text.js` | HTML -> plain text |
75
+ | `inlineHtml` | `lib/inline-html.js` | build reply/forward HTML body with quoted original |
76
+ | `inlineText` | `lib/inline-text.js` | build reply/forward plain-text body with quoted original |
77
+ | `mimeHtml` | `lib/mime-html.js` | sanitize + inline-CSS arbitrary email HTML for safe display |
78
+
79
+ `lib/html-guard.js` holds what `mimeHtml` and `inlineHtml` share before they parse anything: the nesting-depth estimate (`exceedsNestingDepth`, `MAX_NESTING_DEPTH`) and the plain-text fallback projection (`fallbackText`). It does not load jsdom, so `inline-html.js` can require it eagerly.
80
+
81
+ ### `mimeHtml`: the core, and where the complexity lives
82
+
83
+ Pipeline (same for sync and async): **DOMPurify sanitize (whole document)** -> **pre-filter problematic CSS** -> **juice (inline `<style>` into element `style=` attributes)** -> **DOMPurify sanitize again (return DOM body)** -> strip forbidden style properties / size constraints, force `target="_blank"` on links, wrap in a styled `<div>`. When the input has only `text` (no `html`), it is first run through `textToHtml` and given a default `<style>` block (`INLINE_STYLE_BLOCK`).
84
+
85
+ The non-obvious part is **juice hang protection**. Certain modern CSS selectors (`:is()`, `:where()`, `:has()`, `:not(... : ...)`) can make `juice` hang. Two layers defend against this:
86
+
87
+ 1. A linear pre-filter (`filterCss()`, split on `}`, never a regex: the old regex backtracked catastrophically) strips rules using those selectors from head `<style>` tags before juice runs, after capping style text at 256 KB. Input nested deeper than `MAX_NESTING_DEPTH` is not parsed (jsdom tree building is quadratic in depth) and, like any pipeline error, renders the escaped-text `fallbackHtml()`.
88
+ 2. The async path additionally runs juice inside a **worker thread with a timeout** as a safety net for unknown edge cases. On timeout/failure it falls back to returning the HTML without inlined CSS (unless `fallbackOnError: false`).
89
+
90
+ `mimeHtml` exposes three forms. Note the default is sync for backward compatibility, but only the async form is fully hang-protected:
91
+
92
+ - `mimeHtml(message)` / `mimeHtml.sync(message)`: synchronous, runs juice in-process (can still hang on unknown selectors).
93
+ - `mimeHtml.async(message, options)`: async, juice in a worker pool with timeout. Options: `timeout`, `useWorkerPool`, `fallbackOnError`, `minWorkers`/`maxWorkers`/`idleTimeout`.
94
+ - `mimeHtml.closeWorkerPool()` / `mimeHtml.getWorkerPoolStats()`: manage the lazily-created global worker pool.
95
+
96
+ `lib/worker-pool.js` (`WorkerPool`) manages a min/max pool of `lib/juice-worker.js` workers with task queueing, per-task timeouts, worker replacement on error/timeout, and idle-worker reaping. `lib/juice-worker.js` is a tiny worker entry that just runs `juice(html)` and posts the result back.
97
+
98
+ ### Other modules
99
+
100
+ - `text-to-html.js` parses plain text into a nested tree of `text`/`quote` nodes (by `>` prefixes) so multi-level email quotes become nested `<blockquote class="ee-block-N">`. Linkification uses `linkify-it` + full `tlds` list (plus `.onion` and a `git:` alias).
101
+ - `inline-html.js` / `inline-text.js` produce Apple-Mail-style reply/forward bodies, formatting From/Subject/Date/To/Cc/Bcc headers and quoting the original (HTML via `<blockquote>`, text via `> ` prefixes). Dates use `Intl.DateTimeFormat` via `lib/format-date.js`, honoring `options.locale` (unsupported -> 'en') and `options.tz` (unknown -> UTC).
102
+
103
+ ### Testing notes
104
+
105
+ Tests use Node's built-in `node:test` runner. Suites that exercise `mimeHtml.async` or `WorkerPool` **must call `await mimeHtml.closeWorkerPool()` (or close the pool) in an `after()` hook**, otherwise live workers keep the process alive and the run hangs.
@@ -281,22 +281,14 @@ class Benchmark {
281
281
  };
282
282
 
283
283
  // Test sync version
284
- results.tests.push(
285
- await this.runTest(
286
- 'Sync',
287
- () => {
288
- return Promise.resolve(mimeHtml.sync({ html: testCase.html }));
289
- },
290
- 100
291
- )
292
- );
284
+ results.tests.push(await this.runTest('Sync', () => Promise.resolve(mimeHtml.sync({ html: testCase.html })), 100));
293
285
 
294
286
  // Test async version with pool
295
287
  results.tests.push(
296
288
  await this.runTest(
297
289
  'Async (with pool)',
298
- async () => {
299
- return await mimeHtml.async(
290
+ async () =>
291
+ await mimeHtml.async(
300
292
  { html: testCase.html },
301
293
  {
302
294
  useWorkerPool: true,
@@ -304,8 +296,7 @@ class Benchmark {
304
296
  minWorkers: 2,
305
297
  maxWorkers: 4
306
298
  }
307
- );
308
- },
299
+ ),
309
300
  100
310
301
  )
311
302
  );
@@ -314,15 +305,14 @@ class Benchmark {
314
305
  results.tests.push(
315
306
  await this.runTest(
316
307
  'Async (no pool)',
317
- async () => {
318
- return await mimeHtml.async(
308
+ async () =>
309
+ await mimeHtml.async(
319
310
  { html: testCase.html },
320
311
  {
321
312
  useWorkerPool: false,
322
313
  timeout: 5000
323
314
  }
324
- );
325
- },
315
+ ),
326
316
  100
327
317
  )
328
318
  );
@@ -142,10 +142,10 @@ async function concurrencyBenchmark() {
142
142
  console.log('-'.repeat(40));
143
143
 
144
144
  const asyncResults = results.filter(r => r.method === 'Async (pool)');
145
- const maxThroughput = Math.max(...asyncResults.map(r => parseInt(r.reqPerSec)));
145
+ const maxThroughput = Math.max(...asyncResults.map(r => parseInt(r.reqPerSec, 10)));
146
146
 
147
147
  asyncResults.forEach(r => {
148
- const barLength = Math.round((parseInt(r.reqPerSec) / maxThroughput) * 30);
148
+ const barLength = Math.round((parseInt(r.reqPerSec, 10) / maxThroughput) * 30);
149
149
  const bar = '█'.repeat(barLength);
150
150
  console.log(` ${String(r.concurrency).padStart(2)}: ${bar} ${r.reqPerSec} req/s`);
151
151
  });
@@ -117,15 +117,7 @@ class RealWorldBenchmark {
117
117
  // Test 1: Sync version
118
118
  console.log('Test 1: Sync Version');
119
119
  console.log('-'.repeat(40));
120
- results.push(
121
- await this.runTest(
122
- 'Sync',
123
- () => {
124
- return Promise.resolve(mimeHtml.sync({ html: realWorldHtml }));
125
- },
126
- 50
127
- )
128
- );
120
+ results.push(await this.runTest('Sync', () => Promise.resolve(mimeHtml.sync({ html: realWorldHtml })), 50));
129
121
 
130
122
  // Test 2: Async with worker pool
131
123
  console.log('\nTest 2: Async with Worker Pool');
@@ -133,8 +125,8 @@ class RealWorldBenchmark {
133
125
  results.push(
134
126
  await this.runTest(
135
127
  'Async (pool)',
136
- async () => {
137
- return await mimeHtml.async(
128
+ async () =>
129
+ await mimeHtml.async(
138
130
  { html: realWorldHtml },
139
131
  {
140
132
  useWorkerPool: true,
@@ -143,8 +135,7 @@ class RealWorldBenchmark {
143
135
  maxWorkers: 4,
144
136
  logErrors: false
145
137
  }
146
- );
147
- },
138
+ ),
148
139
  50
149
140
  )
150
141
  );
@@ -155,16 +146,15 @@ class RealWorldBenchmark {
155
146
  results.push(
156
147
  await this.runTest(
157
148
  'Async (no pool)',
158
- async () => {
159
- return await mimeHtml.async(
149
+ async () =>
150
+ await mimeHtml.async(
160
151
  { html: realWorldHtml },
161
152
  {
162
153
  useWorkerPool: false,
163
154
  timeout: 5000,
164
155
  logErrors: false
165
156
  }
166
- );
167
- },
157
+ ),
168
158
  10
169
159
  )
170
160
  );
package/eslint.config.js CHANGED
@@ -1,52 +1,71 @@
1
+ 'use strict';
2
+
3
+ // Shared lint baseline for the Postal Systems / Nodemailer packages: eslint:recommended
4
+ // plus the rules of the retired eslint-config-nodemailer, with formatting left to Prettier.
5
+ // Keep this file identical across repos except for the "Repo-specific" block at the end.
6
+
1
7
  const js = require('@eslint/js');
2
8
  const prettier = require('eslint-config-prettier');
9
+ const globals = require('globals');
3
10
 
4
11
  module.exports = [
12
+ {
13
+ ignores: ['node_modules/**', 'coverage/**', 'dist/**']
14
+ },
5
15
  js.configs.recommended,
6
- prettier,
7
16
  {
8
- files: ['**/*.js'],
17
+ files: ['**/*.js', '**/*.cjs'],
9
18
  languageOptions: {
10
- ecmaVersion: 2018,
11
- sourceType: 'script',
12
- globals: {
13
- BigInt: true,
14
- Buffer: 'readonly',
15
- console: 'readonly',
16
- global: 'readonly',
17
- process: 'readonly',
18
- require: 'readonly',
19
- module: 'readonly',
20
- exports: 'writable',
21
- __dirname: 'readonly',
22
- __filename: 'readonly',
23
- setTimeout: 'readonly',
24
- clearTimeout: 'readonly',
25
- setInterval: 'readonly',
26
- clearInterval: 'readonly',
27
- setImmediate: 'readonly',
28
- clearImmediate: 'readonly'
29
- }
19
+ ecmaVersion: 2022,
20
+ sourceType: 'commonjs',
21
+ globals: { ...globals.node }
30
22
  },
31
23
  rules: {
32
- 'no-await-in-loop': 'off',
33
- 'require-atomic-updates': 'off',
34
- 'no-unused-vars': [
35
- 'error',
36
- {
37
- argsIgnorePattern: '^_',
38
- varsIgnorePattern: '^_',
39
- caughtErrorsIgnorePattern: '^_'
40
- }
41
- ],
42
- 'no-console': 'off',
43
- 'no-constant-condition': ['error', { checkLoops: false }],
44
- 'no-empty': ['error', { allowEmptyCatch: true }],
45
- 'no-useless-escape': 'warn',
24
+ 'no-await-in-loop': 'error',
25
+ 'no-div-regex': 'error',
26
+ strict: ['error', 'global'],
27
+ eqeqeq: 'error',
28
+ 'dot-notation': 'error',
29
+ curly: 'error',
30
+ 'no-unused-expressions': ['error', { allowShortCircuit: true }],
31
+ 'no-unused-vars': ['error', { varsIgnorePattern: '^_', argsIgnorePattern: '^_', caughtErrorsIgnorePattern: '^_' }],
32
+ 'handle-callback-err': 'error',
33
+ 'no-new': 'error',
34
+ 'new-cap': 'error',
35
+ 'no-eval': 'error',
36
+ 'no-invalid-this': 'error',
37
+ radix: ['error', 'always'],
38
+ 'no-use-before-define': ['error', 'nofunc'],
39
+ 'callback-return': ['error', ['callback', 'cb', 'done']],
40
+ 'no-redeclare': 'error',
41
+ 'block-scoped-var': 'error',
42
+ 'no-sequences': 'error',
43
+ 'no-throw-literal': 'error',
44
+ 'no-useless-call': 'error',
45
+ 'no-useless-concat': 'error',
46
+ 'no-void': 'error',
47
+ yoda: 'error',
48
+ 'no-var': 'error',
49
+ 'no-bitwise': 'error',
50
+ 'no-lonely-if': 'error',
51
+ 'arrow-body-style': ['error', 'as-needed'],
52
+ 'prefer-arrow-callback': 'error',
53
+ 'object-shorthand': 'error',
54
+ 'prefer-spread': 'error',
46
55
  'no-prototype-builtins': 'off'
47
56
  }
48
57
  },
49
58
  {
50
- ignores: ['node_modules/**', 'coverage/**', '.git/**', '*.log', 'test-*.js', 'dist/**', 'build/**']
51
- }
59
+ files: ['test/**'],
60
+ languageOptions: {
61
+ globals: { ...globals.node, ...globals.mocha }
62
+ }
63
+ },
64
+ // Repo-specific: overrides go here, each with a one-line reason
65
+ {
66
+ // Benchmarks time each iteration sequentially on purpose (9 violations, all in benchmark/)
67
+ files: ['benchmark/**'],
68
+ rules: { 'no-await-in-loop': 'off' }
69
+ },
70
+ prettier
52
71
  ];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@postalsys/email-text-tools",
3
- "version": "2.4.24",
3
+ "version": "2.4.26",
4
4
  "description": "Email text tools",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -11,7 +11,8 @@
11
11
  "lint:fix": "eslint . --fix",
12
12
  "format": "prettier --write .",
13
13
  "format:check": "prettier --check .",
14
- "update": "rm -rf node_modules package-lock.json && ncu -u && npm install"
14
+ "update": "rm -rf node_modules package-lock.json && ncu -u && npm install",
15
+ "test:cjs": "NODE_OPTIONS=--no-experimental-require-module npm test"
15
16
  },
16
17
  "repository": {
17
18
  "type": "git",
@@ -31,17 +32,21 @@
31
32
  "@eslint/js": "10.0.1",
32
33
  "eslint": "10.13.0",
33
34
  "eslint-config-prettier": "10.1.8",
35
+ "globals": "17.13.0",
34
36
  "prettier": "3.9.10"
35
37
  },
36
38
  "dependencies": {
37
- "@postalsys/email-content": "0.1.15",
39
+ "@postalsys/email-content": "0.1.17",
38
40
  "dompurify": "3.4.17",
39
41
  "he": "1.2.0",
40
42
  "html-to-text": "10.0.1",
41
43
  "jsdom": "27.0.0",
42
44
  "juice": "11.1.1",
43
45
  "linkify-it": "5.0.2",
44
- "node-html-parser": "9.0.4",
46
+ "node-html-parser": "9.0.5",
45
47
  "tlds": "1.261.0"
48
+ },
49
+ "overrides": {
50
+ "@asamuzakjp/css-color": "4.1.1"
46
51
  }
47
52
  }
package/.eslintrc DELETED
@@ -1,15 +0,0 @@
1
- {
2
- "rules": {
3
- "indent": 0,
4
- "no-await-in-loop": 0,
5
- "require-atomic-updates": 0
6
- },
7
- "globals": {
8
- "BigInt": true
9
- },
10
- "extends": ["nodemailer", "prettier"],
11
- "parserOptions": {
12
- "ecmaVersion": 2018,
13
- "sourceType": "script"
14
- }
15
- }