@postalsys/email-text-tools 2.4.26 → 2.5.0

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 (84) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/README.md +10 -0
  3. package/dist/cjs/index.d.ts +18 -0
  4. package/dist/cjs/index.js +28 -0
  5. package/dist/cjs/lib/commonjs.cjs +17 -0
  6. package/dist/cjs/lib/commonjs.d.cts +4 -0
  7. package/dist/cjs/lib/format-date.d.ts +15 -0
  8. package/dist/cjs/lib/format-date.js +60 -0
  9. package/dist/cjs/lib/html-guard.d.ts +3 -0
  10. package/dist/cjs/lib/html-guard.js +119 -0
  11. package/dist/cjs/lib/html-to-text.d.ts +1 -0
  12. package/dist/cjs/lib/html-to-text.js +49 -0
  13. package/dist/cjs/lib/inline-html.d.ts +19 -0
  14. package/dist/cjs/lib/inline-html.js +150 -0
  15. package/dist/cjs/lib/inline-text.d.ts +3 -0
  16. package/dist/cjs/lib/inline-text.js +111 -0
  17. package/dist/cjs/lib/juice-worker.d.ts +1 -0
  18. package/dist/cjs/lib/juice-worker.js +19 -0
  19. package/dist/cjs/lib/mime-html.d.ts +34 -0
  20. package/dist/cjs/lib/mime-html.js +529 -0
  21. package/dist/cjs/lib/text-to-html.d.ts +1 -0
  22. package/dist/cjs/lib/text-to-html.js +182 -0
  23. package/dist/cjs/lib/worker-pool.d.ts +61 -0
  24. package/dist/cjs/lib/worker-pool.js +229 -0
  25. package/dist/cjs/package.json +3 -0
  26. package/dist/esm/index.d.ts +18 -0
  27. package/dist/esm/index.js +12 -0
  28. package/dist/esm/lib/commonjs.cjs +17 -0
  29. package/dist/esm/lib/commonjs.d.cts +4 -0
  30. package/dist/esm/lib/format-date.d.ts +15 -0
  31. package/{lib → dist/esm/lib}/format-date.js +8 -16
  32. package/dist/esm/lib/html-guard.d.ts +3 -0
  33. package/{lib → dist/esm/lib}/html-guard.js +8 -24
  34. package/dist/esm/lib/html-to-text.d.ts +1 -0
  35. package/{lib → dist/esm/lib}/html-to-text.js +2 -14
  36. package/dist/esm/lib/inline-html.d.ts +19 -0
  37. package/{lib → dist/esm/lib}/inline-html.js +17 -55
  38. package/dist/esm/lib/inline-text.d.ts +3 -0
  39. package/{lib → dist/esm/lib}/inline-text.js +8 -31
  40. package/dist/esm/lib/juice-worker.d.ts +1 -0
  41. package/{lib → dist/esm/lib}/juice-worker.js +7 -8
  42. package/dist/esm/lib/mime-html.d.ts +34 -0
  43. package/{lib → dist/esm/lib}/mime-html.js +79 -127
  44. package/dist/esm/lib/text-to-html.d.ts +1 -0
  45. package/{lib → dist/esm/lib}/text-to-html.js +35 -63
  46. package/dist/esm/lib/worker-pool.d.ts +61 -0
  47. package/{lib → dist/esm/lib}/worker-pool.js +18 -64
  48. package/dist/esm/package.json +3 -0
  49. package/package.json +67 -10
  50. package/.github/VULNERABILITY_REPORT.yml +0 -75
  51. package/.github/workflows/release.yaml +0 -38
  52. package/.github/workflows/test.yaml +0 -35
  53. package/.ncurc.js +0 -28
  54. package/.prettierignore +0 -14
  55. package/.prettierrc.js +0 -10
  56. package/.release-please-manifest.json +0 -3
  57. package/CLAUDE.md +0 -105
  58. package/benchmark/benchmark.js +0 -348
  59. package/benchmark/concurrency-benchmark.js +0 -176
  60. package/benchmark/quick-benchmark.js +0 -200
  61. package/benchmark/quick-concurrency.js +0 -64
  62. package/benchmark/real-world-benchmark.js +0 -257
  63. package/docs/PERFORMANCE.md +0 -262
  64. package/eslint.config.js +0 -71
  65. package/examples/failing.html +0 -617
  66. package/examples/fixtures/message-1.json +0 -74
  67. package/examples/inline-html.js +0 -24
  68. package/examples/inline-text.js +0 -24
  69. package/examples/mime-html.js +0 -284
  70. package/index.js +0 -22
  71. package/release-please-config.json +0 -10
  72. package/test/comprehensive.test.js +0 -358
  73. package/test/containment.test.js +0 -128
  74. package/test/edge-cases.test.js +0 -62
  75. package/test/hardening.test.js +0 -504
  76. package/test/html-to-text.test.js +0 -253
  77. package/test/inline-html.test.js +0 -230
  78. package/test/inline-text.test.js +0 -204
  79. package/test/mime-html-extra.test.js +0 -39
  80. package/test/mime-html.test.js +0 -302
  81. package/test/text-to-html-extra.test.js +0 -42
  82. package/test/worker-pool-extra.test.js +0 -132
  83. package/test/worker-pool-regression.test.js +0 -128
  84. package/test/worker-pool.test.js +0 -282
@@ -1,282 +0,0 @@
1
- 'use strict';
2
-
3
- const { describe, it, before, after, beforeEach, afterEach } = require('node:test');
4
- const assert = require('node:assert/strict');
5
- const WorkerPool = require('../lib/worker-pool');
6
- const path = require('path');
7
-
8
- // Create a simple test worker
9
- const testWorkerCode = `
10
- const { parentPort } = require('worker_threads');
11
-
12
- parentPort.on('message', (data) => {
13
- // Simulate some processing
14
- setTimeout(() => {
15
- if (data === 'error') {
16
- parentPort.postMessage({ success: false, error: 'Test error' });
17
- } else if (data === 'slow') {
18
- // Simulate slow processing
19
- setTimeout(() => {
20
- parentPort.postMessage({ success: true, result: 'slow result' });
21
- }, 1000);
22
- } else {
23
- parentPort.postMessage({ success: true, result: 'processed: ' + data });
24
- }
25
- }, 10);
26
- });
27
- `;
28
-
29
- describe('WorkerPool', () => {
30
- let pool;
31
-
32
- before(async () => {
33
- // Create test worker file
34
- const fs = require('fs');
35
- const workerPath = path.join(__dirname, 'test-worker.js');
36
- fs.writeFileSync(workerPath, testWorkerCode);
37
- });
38
-
39
- after(async () => {
40
- // Clean up test worker file
41
- const fs = require('fs');
42
- const workerPath = path.join(__dirname, 'test-worker.js');
43
- try {
44
- fs.unlinkSync(workerPath);
45
- } catch (_err) {
46
- // Ignore cleanup errors
47
- }
48
- });
49
-
50
- afterEach(async () => {
51
- // Close pool after each test
52
- if (pool) {
53
- await pool.close();
54
- pool = null;
55
- }
56
- });
57
-
58
- describe('initialization', () => {
59
- it('should create pool with default options', () => {
60
- pool = new WorkerPool({
61
- workerPath: path.join(__dirname, 'test-worker.js')
62
- });
63
-
64
- const stats = pool.getStats();
65
- assert.equal(stats.minWorkers, 2);
66
- assert.equal(stats.maxWorkers, 4);
67
- assert.equal(stats.totalWorkers, 2);
68
- });
69
-
70
- it('should create pool with custom options', () => {
71
- pool = new WorkerPool({
72
- workerPath: path.join(__dirname, 'test-worker.js'),
73
- minWorkers: 1,
74
- maxWorkers: 3,
75
- workerTimeout: 500,
76
- maxQueueSize: 50
77
- });
78
-
79
- const stats = pool.getStats();
80
- assert.equal(stats.minWorkers, 1);
81
- assert.equal(stats.maxWorkers, 3);
82
- assert.equal(stats.totalWorkers, 1);
83
- });
84
- });
85
-
86
- describe('task processing', () => {
87
- beforeEach(() => {
88
- pool = new WorkerPool({
89
- workerPath: path.join(__dirname, 'test-worker.js'),
90
- minWorkers: 2,
91
- maxWorkers: 4
92
- });
93
- });
94
-
95
- it('should process a single task', async () => {
96
- const result = await pool.process('test data');
97
- assert.equal(result, 'processed: test data');
98
- });
99
-
100
- it('should process multiple tasks sequentially', async () => {
101
- const result1 = await pool.process('task 1');
102
- const result2 = await pool.process('task 2');
103
- const result3 = await pool.process('task 3');
104
-
105
- assert.equal(result1, 'processed: task 1');
106
- assert.equal(result2, 'processed: task 2');
107
- assert.equal(result3, 'processed: task 3');
108
- });
109
-
110
- it('should process multiple tasks concurrently', async () => {
111
- const promises = [];
112
- for (let i = 0; i < 10; i++) {
113
- promises.push(pool.process(`task ${i}`));
114
- }
115
-
116
- const results = await Promise.all(promises);
117
-
118
- assert.equal(results.length, 10);
119
- results.forEach((result, i) => {
120
- assert.equal(result, `processed: task ${i}`);
121
- });
122
- });
123
-
124
- it('should handle worker errors', async () => {
125
- try {
126
- await pool.process('error');
127
- assert.fail('Should have thrown an error');
128
- } catch (err) {
129
- assert.equal(err.message, 'Test error');
130
- }
131
- });
132
-
133
- it('should timeout long-running tasks', async () => {
134
- try {
135
- await pool.process('slow', { timeout: 100 });
136
- assert.fail('Should have timed out');
137
- } catch (err) {
138
- assert.ok(err.message.includes('timed out'));
139
- }
140
- });
141
- });
142
-
143
- describe('worker management', () => {
144
- beforeEach(() => {
145
- pool = new WorkerPool({
146
- workerPath: path.join(__dirname, 'test-worker.js'),
147
- minWorkers: 2,
148
- maxWorkers: 4
149
- });
150
- });
151
-
152
- it('should scale up workers under load', async () => {
153
- const initialStats = pool.getStats();
154
- assert.equal(initialStats.totalWorkers, 2);
155
-
156
- // Create enough concurrent tasks to trigger scaling
157
- const promises = [];
158
- for (let i = 0; i < 6; i++) {
159
- promises.push(pool.process(`task ${i}`));
160
- }
161
-
162
- // Check stats while processing
163
- await new Promise(resolve => setTimeout(resolve, 50));
164
- const midStats = pool.getStats();
165
- assert.ok(midStats.totalWorkers > 2);
166
- assert.ok(midStats.totalWorkers <= 4);
167
-
168
- await Promise.all(promises);
169
- });
170
-
171
- it('should reuse workers efficiently', async () => {
172
- const stats1 = pool.getStats();
173
- const _initialWorkers = stats1.totalWorkers;
174
-
175
- // Process tasks that complete quickly
176
- const promises = [];
177
- for (let i = 0; i < 20; i++) {
178
- promises.push(pool.process(`quick ${i}`));
179
- }
180
-
181
- await Promise.all(promises);
182
-
183
- const stats2 = pool.getStats();
184
- // Should not have created too many workers
185
- assert.ok(stats2.totalWorkers <= 4);
186
- });
187
-
188
- it('should handle queue when at max workers', async () => {
189
- // Fill up all workers with slow tasks
190
- const slowPromises = [];
191
- for (let i = 0; i < 4; i++) {
192
- slowPromises.push(pool.process('slow'));
193
- }
194
-
195
- // These should queue
196
- const queuedPromises = [];
197
- for (let i = 0; i < 3; i++) {
198
- queuedPromises.push(pool.process(`queued ${i}`));
199
- }
200
-
201
- // Check that tasks are queued
202
- await new Promise(resolve => setTimeout(resolve, 50));
203
- const stats = pool.getStats();
204
- assert.ok(stats.queuedTasks > 0);
205
-
206
- // Wait for all to complete
207
- await Promise.all([...slowPromises, ...queuedPromises]);
208
- });
209
- });
210
-
211
- describe('pool lifecycle', () => {
212
- it('should close pool gracefully', async () => {
213
- pool = new WorkerPool({
214
- workerPath: path.join(__dirname, 'test-worker.js')
215
- });
216
-
217
- // Process some tasks
218
- await pool.process('test 1');
219
- await pool.process('test 2');
220
-
221
- // Close pool
222
- await pool.close();
223
-
224
- // Should not be able to process after closing
225
- try {
226
- await pool.process('after close');
227
- assert.fail('Should not process after closing');
228
- } catch (err) {
229
- assert.ok(err.message.includes('closing'));
230
- }
231
- });
232
-
233
- it('should handle closing with pending tasks', async () => {
234
- pool = new WorkerPool({
235
- workerPath: path.join(__dirname, 'test-worker.js')
236
- });
237
-
238
- // Start some tasks but don't wait
239
- const promises = [];
240
- for (let i = 0; i < 5; i++) {
241
- promises.push(pool.process(`task ${i}`).catch(() => {}));
242
- }
243
-
244
- // Close immediately
245
- await pool.close();
246
-
247
- // Some tasks might fail, but close should complete
248
- assert.ok(true, 'Pool closed successfully');
249
- });
250
- });
251
-
252
- describe('statistics', () => {
253
- it('should provide accurate statistics', async () => {
254
- pool = new WorkerPool({
255
- workerPath: path.join(__dirname, 'test-worker.js'),
256
- minWorkers: 2,
257
- maxWorkers: 4
258
- });
259
-
260
- const stats1 = pool.getStats();
261
- assert.equal(stats1.totalWorkers, 2);
262
- assert.equal(stats1.busyWorkers, 0);
263
- assert.equal(stats1.freeWorkers, 2);
264
- assert.equal(stats1.queuedTasks, 0);
265
-
266
- // Start processing
267
- const promise = pool.process('test');
268
-
269
- // Check stats while processing
270
- await new Promise(resolve => setTimeout(resolve, 5));
271
- const stats2 = pool.getStats();
272
- assert.ok(stats2.busyWorkers > 0);
273
-
274
- await promise;
275
-
276
- // Check stats after completion
277
- const stats3 = pool.getStats();
278
- assert.equal(stats3.busyWorkers, 0);
279
- assert.equal(stats3.freeWorkers, stats3.totalWorkers);
280
- });
281
- });
282
- });