aiplang 2.0.0 → 2.1.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 (53) hide show
  1. package/bin/aiplang.js +7 -7
  2. package/package.json +7 -5
  3. package/server/node_modules/.package-lock.json +9 -0
  4. package/server/node_modules/nodemailer/.gitattributes +6 -0
  5. package/server/node_modules/nodemailer/.ncurc.js +9 -0
  6. package/server/node_modules/nodemailer/.prettierignore +8 -0
  7. package/server/node_modules/nodemailer/.prettierrc +12 -0
  8. package/server/node_modules/nodemailer/.prettierrc.js +10 -0
  9. package/server/node_modules/nodemailer/.release-please-config.json +9 -0
  10. package/server/node_modules/nodemailer/CHANGELOG.md +976 -0
  11. package/server/node_modules/nodemailer/CODE_OF_CONDUCT.md +76 -0
  12. package/server/node_modules/nodemailer/LICENSE +16 -0
  13. package/server/node_modules/nodemailer/README.md +86 -0
  14. package/server/node_modules/nodemailer/SECURITY.txt +22 -0
  15. package/server/node_modules/nodemailer/eslint.config.js +88 -0
  16. package/server/node_modules/nodemailer/lib/addressparser/index.js +382 -0
  17. package/server/node_modules/nodemailer/lib/base64/index.js +140 -0
  18. package/server/node_modules/nodemailer/lib/dkim/index.js +245 -0
  19. package/server/node_modules/nodemailer/lib/dkim/message-parser.js +154 -0
  20. package/server/node_modules/nodemailer/lib/dkim/relaxed-body.js +154 -0
  21. package/server/node_modules/nodemailer/lib/dkim/sign.js +116 -0
  22. package/server/node_modules/nodemailer/lib/errors.js +58 -0
  23. package/server/node_modules/nodemailer/lib/fetch/cookies.js +276 -0
  24. package/server/node_modules/nodemailer/lib/fetch/index.js +278 -0
  25. package/server/node_modules/nodemailer/lib/json-transport/index.js +82 -0
  26. package/server/node_modules/nodemailer/lib/mail-composer/index.js +599 -0
  27. package/server/node_modules/nodemailer/lib/mailer/index.js +446 -0
  28. package/server/node_modules/nodemailer/lib/mailer/mail-message.js +312 -0
  29. package/server/node_modules/nodemailer/lib/mime-funcs/index.js +610 -0
  30. package/server/node_modules/nodemailer/lib/mime-funcs/mime-types.js +2109 -0
  31. package/server/node_modules/nodemailer/lib/mime-node/index.js +1334 -0
  32. package/server/node_modules/nodemailer/lib/mime-node/last-newline.js +33 -0
  33. package/server/node_modules/nodemailer/lib/mime-node/le-unix.js +40 -0
  34. package/server/node_modules/nodemailer/lib/mime-node/le-windows.js +49 -0
  35. package/server/node_modules/nodemailer/lib/nodemailer.js +151 -0
  36. package/server/node_modules/nodemailer/lib/punycode/index.js +460 -0
  37. package/server/node_modules/nodemailer/lib/qp/index.js +230 -0
  38. package/server/node_modules/nodemailer/lib/sendmail-transport/index.js +205 -0
  39. package/server/node_modules/nodemailer/lib/ses-transport/index.js +223 -0
  40. package/server/node_modules/nodemailer/lib/shared/index.js +698 -0
  41. package/server/node_modules/nodemailer/lib/smtp-connection/data-stream.js +105 -0
  42. package/server/node_modules/nodemailer/lib/smtp-connection/http-proxy-client.js +144 -0
  43. package/server/node_modules/nodemailer/lib/smtp-connection/index.js +1903 -0
  44. package/server/node_modules/nodemailer/lib/smtp-pool/index.js +641 -0
  45. package/server/node_modules/nodemailer/lib/smtp-pool/pool-resource.js +256 -0
  46. package/server/node_modules/nodemailer/lib/smtp-transport/index.js +402 -0
  47. package/server/node_modules/nodemailer/lib/stream-transport/index.js +135 -0
  48. package/server/node_modules/nodemailer/lib/well-known/index.js +47 -0
  49. package/server/node_modules/nodemailer/lib/well-known/services.json +619 -0
  50. package/server/node_modules/nodemailer/lib/xoauth2/index.js +436 -0
  51. package/server/node_modules/nodemailer/package.json +48 -0
  52. package/server/server.js +686 -865
  53. /package/{FLUX-PROJECT-KNOWLEDGE.md → aiplang-knowledge.md} +0 -0
@@ -0,0 +1,641 @@
1
+ 'use strict';
2
+
3
+ const EventEmitter = require('events');
4
+ const PoolResource = require('./pool-resource');
5
+ const SMTPConnection = require('../smtp-connection');
6
+ const wellKnown = require('../well-known');
7
+ const shared = require('../shared');
8
+ const errors = require('../errors');
9
+ const packageData = require('../../package.json');
10
+
11
+ /**
12
+ * Creates a SMTP pool transport object for Nodemailer
13
+ *
14
+ * @constructor
15
+ * @param {Object} options SMTP Connection options
16
+ */
17
+ class SMTPPool extends EventEmitter {
18
+ constructor(options) {
19
+ super();
20
+
21
+ options = options || {};
22
+ if (typeof options === 'string') {
23
+ options = {
24
+ url: options
25
+ };
26
+ }
27
+
28
+ let urlData;
29
+ let service = options.service;
30
+
31
+ if (typeof options.getSocket === 'function') {
32
+ this.getSocket = options.getSocket;
33
+ }
34
+
35
+ if (options.url) {
36
+ urlData = shared.parseConnectionUrl(options.url);
37
+ service = service || urlData.service;
38
+ }
39
+
40
+ this.options = shared.assign(
41
+ false, // create new object
42
+ options, // regular options
43
+ urlData, // url options
44
+ service && wellKnown(service) // wellknown options
45
+ );
46
+
47
+ this.options.maxConnections = this.options.maxConnections || 5;
48
+ this.options.maxMessages = this.options.maxMessages || 100;
49
+
50
+ this.logger = shared.getLogger(this.options, {
51
+ component: this.options.component || 'smtp-pool'
52
+ });
53
+
54
+ this.name = 'SMTP (pool)';
55
+ this.version = packageData.version + '[client:' + packageData.version + ']';
56
+
57
+ this._rateLimit = {
58
+ counter: 0,
59
+ timeout: null,
60
+ waiting: [],
61
+ checkpoint: false,
62
+ delta: Number(this.options.rateDelta) || 1000,
63
+ limit: Number(this.options.rateLimit) || 0
64
+ };
65
+ this._closed = false;
66
+ this._queue = [];
67
+ this._connections = [];
68
+ this._connectionCounter = 0;
69
+
70
+ this.idling = true;
71
+
72
+ setImmediate(() => {
73
+ if (this.idling) {
74
+ this.emit('idle');
75
+ }
76
+ });
77
+ }
78
+
79
+ /**
80
+ * Placeholder function for creating proxy sockets. This method immediatelly returns
81
+ * without a socket
82
+ *
83
+ * @param {Object} options Connection options
84
+ * @param {Function} callback Callback function to run with the socket keys
85
+ */
86
+ getSocket(options, callback) {
87
+ // return immediatelly
88
+ return setImmediate(() => callback(null, false));
89
+ }
90
+
91
+ /**
92
+ * Queues an e-mail to be sent using the selected settings
93
+ *
94
+ * @param {Object} mail Mail object
95
+ * @param {Function} callback Callback function
96
+ */
97
+ send(mail, callback) {
98
+ if (this._closed) {
99
+ return false;
100
+ }
101
+
102
+ this._queue.push({
103
+ mail,
104
+ requeueAttempts: 0,
105
+ callback
106
+ });
107
+
108
+ if (this.idling && this._queue.length >= this.options.maxConnections) {
109
+ this.idling = false;
110
+ }
111
+
112
+ setImmediate(() => this._processMessages());
113
+
114
+ return true;
115
+ }
116
+
117
+ /**
118
+ * Closes all connections in the pool. If there is a message being sent, the connection
119
+ * is closed later
120
+ */
121
+ close() {
122
+ let connection;
123
+ const len = this._connections.length;
124
+ this._closed = true;
125
+
126
+ // clear rate limit timer if it exists
127
+ clearTimeout(this._rateLimit.timeout);
128
+
129
+ if (!len && !this._queue.length) {
130
+ return;
131
+ }
132
+
133
+ // remove all available connections
134
+ for (let i = len - 1; i >= 0; i--) {
135
+ if (this._connections[i] && this._connections[i].available) {
136
+ connection = this._connections[i];
137
+ connection.close();
138
+ this.logger.info(
139
+ {
140
+ tnx: 'connection',
141
+ cid: connection.id,
142
+ action: 'removed'
143
+ },
144
+ 'Connection #%s removed',
145
+ connection.id
146
+ );
147
+ }
148
+ }
149
+
150
+ if (len && !this._connections.length) {
151
+ this.logger.debug(
152
+ {
153
+ tnx: 'connection'
154
+ },
155
+ 'All connections removed'
156
+ );
157
+ }
158
+
159
+ if (!this._queue.length) {
160
+ return;
161
+ }
162
+
163
+ // make sure that entire queue would be cleaned
164
+ const invokeCallbacks = () => {
165
+ if (!this._queue.length) {
166
+ this.logger.debug(
167
+ {
168
+ tnx: 'connection'
169
+ },
170
+ 'Pending queue entries cleared'
171
+ );
172
+ return;
173
+ }
174
+ const entry = this._queue.shift();
175
+ if (entry && typeof entry.callback === 'function') {
176
+ try {
177
+ entry.callback(new Error('Connection pool was closed'));
178
+ } catch (E) {
179
+ this.logger.error(
180
+ {
181
+ err: E,
182
+ tnx: 'callback',
183
+ cid: connection.id
184
+ },
185
+ 'Callback error for #%s: %s',
186
+ connection.id,
187
+ E.message
188
+ );
189
+ }
190
+ }
191
+ setImmediate(invokeCallbacks);
192
+ };
193
+ setImmediate(invokeCallbacks);
194
+ }
195
+
196
+ /**
197
+ * Check the queue and available connections. If there is a message to be sent and there is
198
+ * an available connection, then use this connection to send the mail
199
+ */
200
+ _processMessages() {
201
+ // do nothing if already closed
202
+ if (this._closed) {
203
+ return;
204
+ }
205
+
206
+ // do nothing if queue is empty
207
+ if (!this._queue.length) {
208
+ if (!this.idling) {
209
+ // no pending jobs
210
+ this.idling = true;
211
+ this.emit('idle');
212
+ }
213
+ return;
214
+ }
215
+
216
+ // find first available connection
217
+ let connection = this._connections.find(c => c.available);
218
+
219
+ if (!connection && this._connections.length < this.options.maxConnections) {
220
+ connection = this._createConnection();
221
+ }
222
+
223
+ if (!connection) {
224
+ // no more free connection slots available
225
+ this.idling = false;
226
+ return;
227
+ }
228
+
229
+ // check if there is free space in the processing queue
230
+ if (!this.idling && this._queue.length < this.options.maxConnections) {
231
+ this.idling = true;
232
+ this.emit('idle');
233
+ }
234
+
235
+ const entry = (connection.queueEntry = this._queue.shift());
236
+ entry.messageId = (connection.queueEntry.mail.message.getHeader('message-id') || '').replace(/[<>\s]/g, '');
237
+
238
+ connection.available = false;
239
+
240
+ this.logger.debug(
241
+ {
242
+ tnx: 'pool',
243
+ cid: connection.id,
244
+ messageId: entry.messageId,
245
+ action: 'assign'
246
+ },
247
+ 'Assigned message <%s> to #%s (%s)',
248
+ entry.messageId,
249
+ connection.id,
250
+ connection.messages + 1
251
+ );
252
+
253
+ if (this._rateLimit.limit) {
254
+ this._rateLimit.counter++;
255
+ if (!this._rateLimit.checkpoint) {
256
+ this._rateLimit.checkpoint = Date.now();
257
+ }
258
+ }
259
+
260
+ connection.send(entry.mail, (err, info) => {
261
+ // only process callback if current handler is not changed
262
+ if (entry === connection.queueEntry) {
263
+ try {
264
+ entry.callback(err, info);
265
+ } catch (E) {
266
+ this.logger.error(
267
+ {
268
+ err: E,
269
+ tnx: 'callback',
270
+ cid: connection.id
271
+ },
272
+ 'Callback error for #%s: %s',
273
+ connection.id,
274
+ E.message
275
+ );
276
+ }
277
+ connection.queueEntry = false;
278
+ }
279
+ });
280
+ }
281
+
282
+ /**
283
+ * Creates a new pool resource
284
+ */
285
+ _createConnection() {
286
+ const connection = new PoolResource(this);
287
+
288
+ connection.id = ++this._connectionCounter;
289
+
290
+ this.logger.info(
291
+ {
292
+ tnx: 'pool',
293
+ cid: connection.id,
294
+ action: 'conection'
295
+ },
296
+ 'Created new pool resource #%s',
297
+ connection.id
298
+ );
299
+
300
+ // resource comes available
301
+ connection.on('available', () => {
302
+ this.logger.debug(
303
+ {
304
+ tnx: 'connection',
305
+ cid: connection.id,
306
+ action: 'available'
307
+ },
308
+ 'Connection #%s became available',
309
+ connection.id
310
+ );
311
+
312
+ if (this._closed) {
313
+ // if already closed run close() that will remove this connections from connections list
314
+ this.close();
315
+ } else {
316
+ // check if there's anything else to send
317
+ this._processMessages();
318
+ }
319
+ });
320
+
321
+ // resource is terminated with an error
322
+ connection.once('error', err => {
323
+ if (err.code !== errors.EMAXLIMIT) {
324
+ this.logger.warn(
325
+ {
326
+ err,
327
+ tnx: 'pool',
328
+ cid: connection.id
329
+ },
330
+ 'Pool Error for #%s: %s',
331
+ connection.id,
332
+ err.message
333
+ );
334
+ } else {
335
+ this.logger.debug(
336
+ {
337
+ tnx: 'pool',
338
+ cid: connection.id,
339
+ action: 'maxlimit'
340
+ },
341
+ 'Max messages limit exchausted for #%s',
342
+ connection.id
343
+ );
344
+ }
345
+
346
+ if (connection.queueEntry) {
347
+ try {
348
+ connection.queueEntry.callback(err);
349
+ } catch (E) {
350
+ this.logger.error(
351
+ {
352
+ err: E,
353
+ tnx: 'callback',
354
+ cid: connection.id
355
+ },
356
+ 'Callback error for #%s: %s',
357
+ connection.id,
358
+ E.message
359
+ );
360
+ }
361
+ connection.queueEntry = false;
362
+ }
363
+
364
+ // remove the erroneus connection from connections list
365
+ this._removeConnection(connection);
366
+
367
+ this._continueProcessing();
368
+ });
369
+
370
+ connection.once('close', () => {
371
+ this.logger.info(
372
+ {
373
+ tnx: 'connection',
374
+ cid: connection.id,
375
+ action: 'closed'
376
+ },
377
+ 'Connection #%s was closed',
378
+ connection.id
379
+ );
380
+
381
+ this._removeConnection(connection);
382
+
383
+ if (connection.queueEntry) {
384
+ // If the connection closed when sending, add the message to the queue again
385
+ // if max number of requeues is not reached yet
386
+ // Note that we must wait a bit.. because the callback of the 'error' handler might be called
387
+ // in the next event loop
388
+ setTimeout(() => {
389
+ if (connection.queueEntry) {
390
+ if (this._shouldRequeuOnConnectionClose(connection.queueEntry)) {
391
+ this._requeueEntryOnConnectionClose(connection);
392
+ } else {
393
+ this._failDeliveryOnConnectionClose(connection);
394
+ }
395
+ }
396
+ this._continueProcessing();
397
+ }, 50);
398
+ } else {
399
+ if (!this._closed && this.idling && !this._connections.length) {
400
+ this.emit('clear');
401
+ }
402
+
403
+ this._continueProcessing();
404
+ }
405
+ });
406
+
407
+ this._connections.push(connection);
408
+
409
+ return connection;
410
+ }
411
+
412
+ _shouldRequeuOnConnectionClose(queueEntry) {
413
+ if (this.options.maxRequeues === undefined || this.options.maxRequeues < 0) {
414
+ return true;
415
+ }
416
+
417
+ return queueEntry.requeueAttempts < this.options.maxRequeues;
418
+ }
419
+
420
+ _failDeliveryOnConnectionClose(connection) {
421
+ if (connection.queueEntry && connection.queueEntry.callback) {
422
+ try {
423
+ connection.queueEntry.callback(new Error('Reached maximum number of retries after connection was closed'));
424
+ } catch (E) {
425
+ this.logger.error(
426
+ {
427
+ err: E,
428
+ tnx: 'callback',
429
+ messageId: connection.queueEntry.messageId,
430
+ cid: connection.id
431
+ },
432
+ 'Callback error for #%s: %s',
433
+ connection.id,
434
+ E.message
435
+ );
436
+ }
437
+ connection.queueEntry = false;
438
+ }
439
+ }
440
+
441
+ _requeueEntryOnConnectionClose(connection) {
442
+ connection.queueEntry.requeueAttempts += 1;
443
+ this.logger.debug(
444
+ {
445
+ tnx: 'pool',
446
+ cid: connection.id,
447
+ messageId: connection.queueEntry.messageId,
448
+ action: 'requeue'
449
+ },
450
+ 'Re-queued message <%s> for #%s. Attempt: #%s',
451
+ connection.queueEntry.messageId,
452
+ connection.id,
453
+ connection.queueEntry.requeueAttempts
454
+ );
455
+ this._queue.unshift(connection.queueEntry);
456
+ connection.queueEntry = false;
457
+ }
458
+
459
+ /**
460
+ * Continue to process message if the pool hasn't closed
461
+ */
462
+ _continueProcessing() {
463
+ if (this._closed) {
464
+ this.close();
465
+ } else {
466
+ setTimeout(() => this._processMessages(), 100);
467
+ }
468
+ }
469
+
470
+ /**
471
+ * Remove resource from pool
472
+ *
473
+ * @param {Object} connection The PoolResource to remove
474
+ */
475
+ _removeConnection(connection) {
476
+ const index = this._connections.indexOf(connection);
477
+
478
+ if (index !== -1) {
479
+ this._connections.splice(index, 1);
480
+ }
481
+ }
482
+
483
+ /**
484
+ * Checks if connections have hit current rate limit and if so, queues the availability callback
485
+ *
486
+ * @param {Function} callback Callback function to run once rate limiter has been cleared
487
+ */
488
+ _checkRateLimit(callback) {
489
+ if (!this._rateLimit.limit) {
490
+ return callback();
491
+ }
492
+
493
+ const now = Date.now();
494
+
495
+ if (this._rateLimit.counter < this._rateLimit.limit) {
496
+ return callback();
497
+ }
498
+
499
+ this._rateLimit.waiting.push(callback);
500
+
501
+ if (this._rateLimit.checkpoint <= now - this._rateLimit.delta) {
502
+ return this._clearRateLimit();
503
+ }
504
+
505
+ if (!this._rateLimit.timeout) {
506
+ this._rateLimit.timeout = setTimeout(() => this._clearRateLimit(), this._rateLimit.delta - (now - this._rateLimit.checkpoint));
507
+ this._rateLimit.checkpoint = now;
508
+ }
509
+ }
510
+
511
+ /**
512
+ * Clears current rate limit limitation and runs paused callback
513
+ */
514
+ _clearRateLimit() {
515
+ clearTimeout(this._rateLimit.timeout);
516
+ this._rateLimit.timeout = null;
517
+ this._rateLimit.counter = 0;
518
+ this._rateLimit.checkpoint = false;
519
+
520
+ // resume all paused connections
521
+ while (this._rateLimit.waiting.length) {
522
+ const cb = this._rateLimit.waiting.shift();
523
+ setImmediate(cb);
524
+ }
525
+ }
526
+
527
+ /**
528
+ * Returns true if there are free slots in the queue
529
+ */
530
+ isIdle() {
531
+ return this.idling;
532
+ }
533
+
534
+ /**
535
+ * Verifies SMTP configuration
536
+ *
537
+ * @param {Function} callback Callback function
538
+ */
539
+ verify(callback) {
540
+ let promise;
541
+
542
+ if (!callback) {
543
+ promise = new Promise((resolve, reject) => {
544
+ callback = shared.callbackPromise(resolve, reject);
545
+ });
546
+ }
547
+
548
+ const auth = new PoolResource(this).auth;
549
+
550
+ this.getSocket(this.options, (err, socketOptions) => {
551
+ if (err) {
552
+ return callback(err);
553
+ }
554
+
555
+ let options = this.options;
556
+ if (socketOptions && socketOptions.connection) {
557
+ this.logger.info(
558
+ {
559
+ tnx: 'proxy',
560
+ remoteAddress: socketOptions.connection.remoteAddress,
561
+ remotePort: socketOptions.connection.remotePort,
562
+ destHost: options.host || '',
563
+ destPort: options.port || '',
564
+ action: 'connected'
565
+ },
566
+ 'Using proxied socket from %s:%s to %s:%s',
567
+ socketOptions.connection.remoteAddress,
568
+ socketOptions.connection.remotePort,
569
+ options.host || '',
570
+ options.port || ''
571
+ );
572
+ options = Object.assign(shared.assign(false, options), socketOptions);
573
+ }
574
+
575
+ const connection = new SMTPConnection(options);
576
+ let returned = false;
577
+
578
+ connection.once('error', err => {
579
+ if (returned) {
580
+ return;
581
+ }
582
+ returned = true;
583
+ connection.close();
584
+ return callback(err);
585
+ });
586
+
587
+ connection.once('end', () => {
588
+ if (returned) {
589
+ return;
590
+ }
591
+ returned = true;
592
+ return callback(new Error('Connection closed'));
593
+ });
594
+
595
+ const finalize = () => {
596
+ if (returned) {
597
+ return;
598
+ }
599
+ returned = true;
600
+ connection.quit();
601
+ return callback(null, true);
602
+ };
603
+
604
+ connection.connect(() => {
605
+ if (returned) {
606
+ return;
607
+ }
608
+
609
+ if (auth && (connection.allowsAuth || options.forceAuth)) {
610
+ connection.login(auth, err => {
611
+ if (returned) {
612
+ return;
613
+ }
614
+
615
+ if (err) {
616
+ returned = true;
617
+ connection.close();
618
+ return callback(err);
619
+ }
620
+
621
+ finalize();
622
+ });
623
+ } else if (!auth && connection.allowsAuth && options.forceAuth) {
624
+ const err = new Error('Authentication info was not provided');
625
+ err.code = errors.ENOAUTH;
626
+
627
+ returned = true;
628
+ connection.close();
629
+ return callback(err);
630
+ } else {
631
+ finalize();
632
+ }
633
+ });
634
+ });
635
+
636
+ return promise;
637
+ }
638
+ }
639
+
640
+ // expose to the world
641
+ module.exports = SMTPPool;