haraka 3.3.0 → 3.3.1

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 (74) hide show
  1. package/.prettierignore +1 -0
  2. package/CHANGELOG.md +8 -4
  3. package/bin/haraka +1 -1
  4. package/connection.js +4 -2
  5. package/contrib/bsd-rc.d/haraka +2 -0
  6. package/outbound/hmail.js +1 -1
  7. package/outbound/index.js +1 -1
  8. package/outbound/queue.js +1 -1
  9. package/package.json +22 -21
  10. package/plugins.js +4 -3
  11. package/test/connection.js +5 -2
  12. package/test/fixtures/util_hmailitem.js +1 -1
  13. package/test/outbound/index.js +2 -2
  14. package/test/plugins/auth/auth_base.js +1 -1
  15. package/test/plugins/queue/smtp_forward.js +1 -1
  16. package/test/plugins/rcpt_to.host_list_base.js +1 -1
  17. package/test/plugins/rcpt_to.in_host_list.js +1 -1
  18. package/test/plugins/toobusy.js +186 -9
  19. package/test/smtp_client.js +1 -1
  20. package/.claude/settings.local.json +0 -28
  21. package/CLAUDE.md +0 -40
  22. package/GEMINI.md +0 -38
  23. package/address.js +0 -53
  24. package/config/dhparams.pem +0 -8
  25. package/config/me +0 -1
  26. package/config/tls_cert.pem +0 -23
  27. package/config/tls_key.pem +0 -28
  28. package/coverage/coverage-final.json +0 -2
  29. package/coverage/coverage-summary.json +0 -33
  30. package/coverage/tmp/coverage-79131-1779241025146-0.json +0 -1
  31. package/coverage/tmp/coverage-79132-1779240999690-0.json +0 -1
  32. package/coverage/tmp/coverage-79172-1779241000095-0.json +0 -1
  33. package/coverage/tmp/coverage-79210-1779241000156-0.json +0 -1
  34. package/coverage/tmp/coverage-79211-1779241000209-0.json +0 -1
  35. package/coverage/tmp/coverage-79212-1779241000266-0.json +0 -1
  36. package/coverage/tmp/coverage-79213-1779241000441-0.json +0 -1
  37. package/coverage/tmp/coverage-79214-1779241000626-0.json +0 -1
  38. package/coverage/tmp/coverage-79215-1779241000795-0.json +0 -1
  39. package/coverage/tmp/coverage-79216-1779241000965-0.json +0 -1
  40. package/coverage/tmp/coverage-79218-1779241001013-0.json +0 -1
  41. package/coverage/tmp/coverage-79219-1779241001179-0.json +0 -1
  42. package/coverage/tmp/coverage-79220-1779241006249-0.json +0 -1
  43. package/coverage/tmp/coverage-79227-1779241011453-0.json +0 -1
  44. package/coverage/tmp/coverage-79229-1779241011537-0.json +0 -1
  45. package/coverage/tmp/coverage-79230-1779241011647-0.json +0 -1
  46. package/coverage/tmp/coverage-79231-1779241011765-0.json +0 -1
  47. package/coverage/tmp/coverage-79232-1779241011841-0.json +0 -1
  48. package/coverage/tmp/coverage-79233-1779241011909-0.json +0 -1
  49. package/coverage/tmp/coverage-79234-1779241011984-0.json +0 -1
  50. package/coverage/tmp/coverage-79235-1779241012055-0.json +0 -1
  51. package/coverage/tmp/coverage-79236-1779241012230-0.json +0 -1
  52. package/coverage/tmp/coverage-79237-1779241012300-0.json +0 -1
  53. package/coverage/tmp/coverage-79238-1779241012368-0.json +0 -1
  54. package/coverage/tmp/coverage-79239-1779241012438-0.json +0 -1
  55. package/coverage/tmp/coverage-79240-1779241012511-0.json +0 -1
  56. package/coverage/tmp/coverage-79241-1779241012582-0.json +0 -1
  57. package/coverage/tmp/coverage-79242-1779241012652-0.json +0 -1
  58. package/coverage/tmp/coverage-79243-1779241012814-0.json +0 -1
  59. package/coverage/tmp/coverage-79244-1779241012931-0.json +0 -1
  60. package/coverage/tmp/coverage-79245-1779241013007-0.json +0 -1
  61. package/coverage/tmp/coverage-79246-1779241013106-0.json +0 -1
  62. package/coverage/tmp/coverage-79247-1779241013178-0.json +0 -1
  63. package/coverage/tmp/coverage-79248-1779241013244-0.json +0 -1
  64. package/coverage/tmp/coverage-79249-1779241013409-0.json +0 -1
  65. package/coverage/tmp/coverage-79250-1779241013697-0.json +0 -1
  66. package/coverage/tmp/coverage-79251-1779241013847-0.json +0 -1
  67. package/coverage/tmp/coverage-79252-1779241014288-0.json +0 -1
  68. package/coverage/tmp/coverage-79253-1779241014378-0.json +0 -1
  69. package/coverage/tmp/coverage-79254-1779241014428-0.json +0 -1
  70. package/coverage/tmp/coverage-79255-1779241021774-0.json +0 -1
  71. package/coverage/tmp/coverage-80382-1779241021949-0.json +0 -1
  72. package/coverage/tmp/coverage-80383-1779241025019-0.json +0 -1
  73. package/coverage/tmp/coverage-80384-1779241025133-0.json +0 -1
  74. package/queue/1772642154987_1775581346001_4_82235_TGwgfd_2_mattbook-m3.home.simerson.net +0 -0
package/.prettierignore CHANGED
@@ -1,4 +1,5 @@
1
1
  docs/*.md
2
+ AGENTS.md
2
3
  CHANGELOG.md
3
4
  CONTRIBUTORS.md
4
5
  Plugins.md
package/CHANGELOG.md CHANGED
@@ -4,12 +4,16 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/).
4
4
 
5
5
  ### Unreleased
6
6
 
7
- ### [3.3.0] - 2026-06-03
7
+ ### [3.3.1] - 2026-06-12
8
8
 
9
- - fix(haraka): wrap util.createFile in a try
9
+ - fix(conn): flag soft queue denials in results
10
+ - feat: expose fetch to plugins
11
+ - change: remove @haraka/email-address wrapper #3598
12
+ - change: log when MFROM or RCPT fail to parse #3581
13
+ - fix: change package name from Haraka to haraka #3596
14
+ - fix(haraka): wrap util.createFile in a try #3595
10
15
  - fix(conn): update local and remote results after proxy #3593
11
16
  - feat(conn): add main.postel option #3592
12
- - change: log when MFROM or RCPT fail to parse #3581
13
17
  - feat: proxy support for smtps (465) #3577
14
18
  - refactor(auth_proxy): use net_utils.endpoint #3584
15
19
  - refactor: move endpoint, HostPool, LineSocket to net-utils #3583
@@ -1891,4 +1895,4 @@ config files.
1891
1895
  [3.1.7]: https://github.com/haraka/Haraka/releases/tag/v3.1.7
1892
1896
  [3.2.0]: https://github.com/haraka/Haraka/releases/tag/v3.2.0
1893
1897
  [3.2.1]: https://github.com/haraka/Haraka/releases/tag/v3.2.1
1894
- [3.3.0]: https://github.com/haraka/Haraka/releases/tag/v3.3.0
1898
+ [3.3.1]: https://github.com/haraka/Haraka/releases/tag/v3.3.1
package/bin/haraka CHANGED
@@ -414,7 +414,7 @@ if (parsed.version) {
414
414
  plugins.load_plugins(parsed.test && parsed.test[0] !== 'all' ? parsed.test : null)
415
415
  const Connection = require(path.join(base, 'connection'))
416
416
  // var Transaction = require(path.join(base, "transaction"));
417
- const Address = require('../address').Address
417
+ const Address = require('@haraka/email-address').Address
418
418
  const Notes = require('haraka-notes')
419
419
  const constants = require('haraka-constants')
420
420
  const client = {
package/connection.js CHANGED
@@ -11,7 +11,7 @@ const constants = require('haraka-constants')
11
11
  const net_utils = require('haraka-net-utils')
12
12
  const Notes = require('haraka-notes')
13
13
  const utils = require('haraka-utils')
14
- const { Address } = require('./address')
14
+ const { Address } = require('@haraka/email-address')
15
15
  const ResultStore = require('haraka-results')
16
16
 
17
17
  // Haraka libs
@@ -1698,9 +1698,11 @@ class Connection {
1698
1698
  break
1699
1699
  case constants.deny:
1700
1700
  case constants.denydisconnect:
1701
+ this.transaction.results.add(res_as, { fail: msg })
1702
+ break
1701
1703
  case constants.denysoft:
1702
1704
  case constants.denysoftdisconnect:
1703
- this.transaction.results.add(res_as, { fail: msg })
1705
+ this.transaction.results.add(res_as, { fail: msg, soft: true })
1704
1706
  break
1705
1707
  case constants.cont:
1706
1708
  break
@@ -6,6 +6,8 @@
6
6
  # REQUIRE: NETWORKING ldconfig
7
7
  # KEYWORD: shutdown
8
8
 
9
+ PATH="$PATH:/usr/local/bin"
10
+
9
11
  . /etc/rc.subr
10
12
 
11
13
  name="haraka"
package/outbound/hmail.js CHANGED
@@ -7,7 +7,7 @@ const dns = require('node:dns')
7
7
  const net = require('node:net')
8
8
  const path = require('node:path')
9
9
 
10
- const { Address } = require('../address')
10
+ const { Address } = require('@haraka/email-address')
11
11
  const config = require('haraka-config')
12
12
  const constants = require('haraka-constants')
13
13
  const DSN = require('haraka-dsn')
package/outbound/index.js CHANGED
@@ -3,7 +3,7 @@
3
3
  const fs = require('node:fs/promises')
4
4
  const path = require('node:path')
5
5
 
6
- const { Address } = require('../address')
6
+ const { Address } = require('@haraka/email-address')
7
7
  const config = require('haraka-config')
8
8
  const constants = require('haraka-constants')
9
9
  const net_utils = require('haraka-net-utils')
package/outbound/queue.js CHANGED
@@ -4,7 +4,7 @@ const child_process = require('node:child_process')
4
4
  const fs = require('node:fs/promises')
5
5
  const path = require('node:path')
6
6
 
7
- const { Address } = require('../address')
7
+ const { Address } = require('@haraka/email-address')
8
8
  const config = require('haraka-config')
9
9
  const utils = require('haraka-utils')
10
10
 
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "author": "Matt Sergeant <helpme@gmail.com> (http://baudehlo.com/)",
2
+ "author": "Matt Sergeant <helpme@gmail.com>",
3
3
  "name": "haraka",
4
4
  "license": "MIT",
5
5
  "description": "An SMTP Server project.",
@@ -9,7 +9,7 @@
9
9
  "server",
10
10
  "email"
11
11
  ],
12
- "version": "3.3.0",
12
+ "version": "3.3.1",
13
13
  "homepage": "http://haraka.github.io",
14
14
  "repository": {
15
15
  "type": "git",
@@ -20,22 +20,22 @@
20
20
  "node": ">=20"
21
21
  },
22
22
  "dependencies": {
23
- "@haraka/email-address": "~3.1.5",
24
- "haraka-config": "~1.6.2",
23
+ "@haraka/email-address": "~3.1.6",
24
+ "haraka-config": "~1.6.3",
25
25
  "haraka-constants": "~1.0.8",
26
26
  "haraka-dsn": "~1.2.0",
27
27
  "haraka-email-message": "~1.4.0",
28
- "haraka-net-utils": "~1.9.1",
28
+ "haraka-net-utils": "~1.9.2",
29
29
  "haraka-notes": "~1.1.3",
30
30
  "haraka-plugin-redis": "~2.1.0",
31
- "haraka-results": "~2.3.2",
32
- "haraka-tld": "~1.3.5",
33
- "haraka-utils": "~2.2.0",
31
+ "haraka-results": "~2.4.0",
32
+ "haraka-tld": "~1.3.6",
33
+ "haraka-utils": "~2.2.1",
34
34
  "ipaddr.js": "~2.4.0",
35
- "node-gyp": "~12.3.0",
36
- "nopt": "~10.0.0",
35
+ "node-gyp": "~12.4.0",
36
+ "nopt": "~10.0.1",
37
37
  "redis": "~6.0.0",
38
- "semver": "~7.8.1"
38
+ "semver": "~7.8.4"
39
39
  },
40
40
  "optionalDependencies": {
41
41
  "@haraka/ocsp": "~1.2.0",
@@ -43,7 +43,7 @@
43
43
  "haraka-plugin-aliases": "~1.1.0",
44
44
  "haraka-plugin-asn": "~2.2.0",
45
45
  "haraka-plugin-attachment": "~1.2.1",
46
- "haraka-plugin-bounce": "~2.2.0",
46
+ "haraka-plugin-bounce": "~2.2.1",
47
47
  "haraka-plugin-clamd": "~1.0.3",
48
48
  "haraka-plugin-dcc": "~1.0.3",
49
49
  "haraka-plugin-dkim": "~1.2.0",
@@ -53,10 +53,10 @@
53
53
  "haraka-plugin-geoip": "~1.1.2",
54
54
  "haraka-plugin-greylist": "~1.2.1",
55
55
  "haraka-plugin-headers": "~1.2.0",
56
- "haraka-plugin-helo.checks": "~1.1.1",
57
- "haraka-plugin-karma": "~2.5.1",
56
+ "haraka-plugin-helo.checks": "~1.1.3",
57
+ "haraka-plugin-karma": "~2.5.2",
58
58
  "haraka-plugin-known-senders": "~1.2.0",
59
- "haraka-plugin-limit": "~1.3.1",
59
+ "haraka-plugin-limit": "~1.3.2",
60
60
  "haraka-plugin-mail_from.is_resolvable": "~1.3.0",
61
61
  "haraka-plugin-messagesniffer": "~1.0.2",
62
62
  "haraka-plugin-qmail-deliverable": "~1.4.0",
@@ -64,21 +64,22 @@
64
64
  "haraka-plugin-rspamd": "~1.6.0",
65
65
  "haraka-plugin-spamassassin": "~1.1.0",
66
66
  "haraka-plugin-spf": "~1.3.0",
67
- "haraka-plugin-syslog": "~1.1.1",
67
+ "haraka-plugin-syslog": "~1.1.2",
68
68
  "haraka-plugin-uribl": "~2.0.0"
69
69
  },
70
70
  "devDependencies": {
71
71
  "@haraka/eslint-config": "~3.0.0",
72
72
  "haraka-test-fixtures": "^1.7.1",
73
- "mock-require": "~3.0.3"
73
+ "mock-require": "~3.0.3",
74
+ "toobusy-js": "^0.5.1"
74
75
  },
75
76
  "bugs": {
76
77
  "mail": "haraka.mail@gmail.com",
77
78
  "url": "https://github.com/haraka/Haraka/issues"
78
79
  },
79
80
  "bin": {
80
- "haraka": "./bin/haraka",
81
- "haraka_grep": "./bin/haraka_grep"
81
+ "haraka": "bin/haraka",
82
+ "haraka_grep": "bin/haraka_grep"
82
83
  },
83
84
  "scripts": {
84
85
  "prepare": "git rev-parse --git-dir >/dev/null 2>&1 && git config core.hooksPath .githooks || true",
@@ -89,8 +90,8 @@
89
90
  "prettier:fix": "npx prettier . --write --log-level=warn",
90
91
  "qlty": "qlty smells --all",
91
92
  "test": "sh ./run_tests",
92
- "test:coverage": "node --test --test-concurrency=1 --experimental-test-coverage",
93
- "test:coverage:lcov": "mkdir -p coverage && node --test --test-concurrency=1 --experimental-test-coverage --test-reporter=lcov --test-reporter-destination=coverage/lcov.info",
93
+ "test:coverage": "node --test --test-concurrency=1 --experimental-test-coverage --test-coverage-include=*.js --test-coverage-include=plugins/**/*.js --test-coverage-include=outbound/*.js",
94
+ "test:coverage:lcov": "mkdir -p coverage && node --test --test-concurrency=1 --experimental-test-coverage --test-reporter=lcov --test-reporter-destination=coverage/lcov.info --test-coverage-include=*.js --test-coverage-include=plugins/**/*.js --test-coverage-include=outbound/*.js",
94
95
  "versions": "npx npm-dep-mgr check",
95
96
  "versions:fix": "npx npm-dep-mgr update"
96
97
  },
package/plugins.js CHANGED
@@ -197,11 +197,12 @@ class Plugin {
197
197
  __filename: pp,
198
198
  __dirname: path.dirname(pp),
199
199
  exports: this,
200
- setTimeout,
200
+ fetch,
201
201
  clearTimeout,
202
- setInterval,
203
202
  clearInterval,
204
203
  process,
204
+ setInterval,
205
+ setTimeout,
205
206
  Buffer,
206
207
  Math,
207
208
  server: plugins.server,
@@ -585,7 +586,7 @@ function get_denyfn(object, hook, params, retval, msg, respond_method) {
585
586
  switch (deny_retval) {
586
587
  case constants.ok:
587
588
  // Override rejection
588
- object.loginfo(`deny(soft?) overriden by deny hook${deny_msg ? ': deny_msg' : ''}`)
589
+ object.loginfo(`deny(soft?) overridden by deny hook${deny_msg ? ': deny_msg' : ''}`)
589
590
  // Restore hooks_to_run with saved copy so that
590
591
  // any other plugins on this hook can also run.
591
592
  if (object.saved_hooks_to_run.length > 0) {
@@ -5,7 +5,7 @@ const assert = require('node:assert/strict')
5
5
 
6
6
  const constants = require('haraka-constants')
7
7
  const DSN = require('haraka-dsn')
8
- const { Address } = require('../address')
8
+ const { Address } = require('@haraka/email-address')
9
9
 
10
10
  const connection = require('../connection')
11
11
  const Server = require('../server')
@@ -508,7 +508,10 @@ describe('connection', () => {
508
508
  assert.equal(this.connection.msg_count.tempfail, 1)
509
509
  assert.equal(this.connection.transaction.msg_status, 'deferred')
510
510
  assert.equal(harness.calls.reset, 1)
511
- assert.deepEqual(harness.calls.results[0], { fail: 'Message denied temporarily' })
511
+ assert.deepEqual(harness.calls.results[0], {
512
+ fail: 'Message denied temporarily',
513
+ soft: true,
514
+ })
512
515
  } finally {
513
516
  harness.restore()
514
517
  }
@@ -2,7 +2,7 @@
2
2
 
3
3
  const assert = require('node:assert')
4
4
 
5
- const { Address } = require('../../address')
5
+ const { Address } = require('@haraka/email-address')
6
6
  const fixtures = require('haraka-test-fixtures')
7
7
 
8
8
  /**
@@ -210,7 +210,7 @@ describe('outbound', () => {
210
210
  it('yields to setImmediate before opening process_delivery pipes', async () => {
211
211
  const stream = require('node:stream')
212
212
  const Transaction = require('../../transaction')
213
- const Address = require('../../address').Address
213
+ const Address = require('@haraka/email-address').Address
214
214
  const outbound = require('../../outbound')
215
215
  const plugins = require('../../plugins')
216
216
 
@@ -270,7 +270,7 @@ describe('outbound', () => {
270
270
 
271
271
  it('adds missing Message-Id/Date and prepends Received before queueing', async () => {
272
272
  process.env.HARAKA_TEST_DIR = path.resolve('test')
273
- const Address = require('../../address').Address
273
+ const Address = require('@haraka/email-address').Address
274
274
  const outbound = require('../../outbound')
275
275
  const plugins = require('../../plugins')
276
276
 
@@ -2,7 +2,7 @@
2
2
  const assert = require('node:assert')
3
3
  const { describe, it, beforeEach } = require('node:test')
4
4
 
5
- const { Address } = require('../../../address')
5
+ const { Address } = require('@haraka/email-address')
6
6
  const { makeConnection, makePlugin } = require('haraka-test-fixtures')
7
7
  const utils = require('haraka-utils')
8
8
 
@@ -5,7 +5,7 @@ const assert = require('node:assert/strict')
5
5
  const { EventEmitter } = require('node:events')
6
6
  const path = require('node:path')
7
7
 
8
- const { Address } = require('../../../address')
8
+ const { Address } = require('@haraka/email-address')
9
9
  const { makeConnection, makePlugin } = require('haraka-test-fixtures')
10
10
  const Notes = require('haraka-notes')
11
11
 
@@ -2,7 +2,7 @@
2
2
  const assert = require('node:assert/strict')
3
3
  const { describe, it, beforeEach } = require('node:test')
4
4
 
5
- const { Address } = require('../../address')
5
+ const { Address } = require('@haraka/email-address')
6
6
  const { assertResult, makeConnection, makePlugin } = require('haraka-test-fixtures')
7
7
 
8
8
  const _set_up = () => {
@@ -2,7 +2,7 @@
2
2
  const assert = require('node:assert/strict')
3
3
  const { describe, it, beforeEach } = require('node:test')
4
4
 
5
- const { Address } = require('../../address')
5
+ const { Address } = require('@haraka/email-address')
6
6
  const fixtures = require('haraka-test-fixtures')
7
7
  const { assertResult, makeConnection, makePlugin } = fixtures
8
8
  require('haraka-constants').import(global)
@@ -1,21 +1,198 @@
1
1
  'use strict'
2
2
 
3
3
  const assert = require('node:assert/strict')
4
- const { describe, it } = require('node:test')
4
+ const { beforeEach, describe, it } = require('node:test')
5
5
 
6
- const { makePlugin } = require('haraka-test-fixtures')
6
+ const { makeConnection, makePlugin } = require('haraka-test-fixtures')
7
+ require('haraka-constants').import(global)
7
8
 
8
9
  describe('toobusy', () => {
10
+ let plugin
11
+
12
+ beforeEach(() => {
13
+ plugin = makePlugin('toobusy', { register: false })
14
+ })
15
+
9
16
  describe('register', () => {
10
- it('handles missing toobusy-js gracefully (does not throw)', () => {
11
- const plugin = makePlugin('toobusy', { register: false })
12
- // toobusy-js is not installed; register should catch the error and return
13
- let registered = false
14
- plugin.register_hook = () => {
15
- registered = true
17
+ it('registers connect hook with correct priority', () => {
18
+ const hooks = []
19
+ plugin.register_hook = function (hook, name, priority) {
20
+ hooks.push({ hook, name, priority })
16
21
  }
22
+
23
+ plugin.register()
24
+
25
+ assert.equal(hooks.length, 1, 'should register one hook')
26
+ assert.equal(hooks[0].hook, 'connect')
27
+ assert.equal(hooks[0].name, 'check_busy')
28
+ assert.equal(hooks[0].priority, -100)
29
+ })
30
+
31
+ it('loads config on register', () => {
32
+ let loadConfigCalled = false
33
+ const originalLoadConfig = plugin.loadConfig
34
+ plugin.loadConfig = function () {
35
+ loadConfigCalled = true
36
+ return originalLoadConfig.call(this)
37
+ }
38
+
39
+ plugin.register()
40
+
41
+ assert.equal(loadConfigCalled, true, 'loadConfig should be called')
42
+ })
43
+
44
+ it('handles missing toobusy-js gracefully', () => {
17
45
  assert.doesNotThrow(() => plugin.register())
18
- assert.equal(registered, false, 'hook should not be registered without toobusy-js')
46
+ })
47
+ })
48
+
49
+ describe('loadConfig', () => {
50
+ beforeEach(() => {
51
+ plugin.register()
52
+ })
53
+
54
+ it('gets toobusy.maxlag config value', () => {
55
+ let configArgs = []
56
+
57
+ plugin.config.get = function (key, type, callback) {
58
+ configArgs = [key, type]
59
+ return '70'
60
+ }
61
+
62
+ plugin.loadConfig()
63
+
64
+ assert.equal(configArgs[0], 'toobusy.maxlag')
65
+ assert.equal(configArgs[1], 'value')
66
+ })
67
+
68
+ it('passes callback to config.get for hot reload', () => {
69
+ let callbackProvided = false
70
+
71
+ plugin.config.get = function (key, type, callback) {
72
+ callbackProvided = typeof callback === 'function'
73
+ return '70'
74
+ }
75
+
76
+ plugin.loadConfig()
77
+
78
+ assert.equal(callbackProvided, true, 'callback should be provided for hot reload')
79
+ })
80
+
81
+ it('handles zero maxLag value', () => {
82
+ plugin.config.get = () => '0'
83
+
84
+ assert.doesNotThrow(() => {
85
+ plugin.loadConfig()
86
+ })
87
+ })
88
+
89
+ it('handles non-numeric maxLag value', () => {
90
+ plugin.config.get = () => 'notanumber'
91
+
92
+ assert.doesNotThrow(() => {
93
+ plugin.loadConfig()
94
+ })
95
+ })
96
+
97
+ it('handles empty string maxLag value', () => {
98
+ plugin.config.get = () => ''
99
+
100
+ assert.doesNotThrow(() => {
101
+ plugin.loadConfig()
102
+ })
103
+ })
104
+
105
+ it('parses numeric maxLag as integer', () => {
106
+ plugin.config.get = () => '100'
107
+
108
+ assert.doesNotThrow(() => {
109
+ plugin.loadConfig()
110
+ })
111
+ })
112
+
113
+ it('supports reload via callback', () => {
114
+ let callbackFn = null
115
+
116
+ plugin.config.get = function (key, type, callback) {
117
+ callbackFn = callback
118
+ return '70'
119
+ }
120
+
121
+ plugin.loadConfig()
122
+
123
+ assert.equal(typeof callbackFn, 'function', 'callback should be provided')
124
+ assert.doesNotThrow(() => {
125
+ if (callbackFn) callbackFn()
126
+ })
127
+ })
128
+ })
129
+
130
+ describe('check_busy', () => {
131
+ beforeEach(() => {
132
+ plugin.register()
133
+ })
134
+
135
+ it('calls next without args when not busy', (t, done) => {
136
+ plugin.config.get = () => '70'
137
+ plugin.loadConfig()
138
+
139
+ plugin.check_busy(function (...args) {
140
+ assert.equal(args.length, 0, 'should call next with no arguments')
141
+ done()
142
+ })
143
+ })
144
+
145
+ it('initializes was_busy state', (t, done) => {
146
+ plugin.config.get = () => '70'
147
+ plugin.loadConfig()
148
+
149
+ plugin.check_busy(function () {
150
+ done()
151
+ })
152
+ })
153
+
154
+ it('is a callable function', () => {
155
+ assert.equal(typeof plugin.check_busy, 'function')
156
+ })
157
+
158
+ it('does not log when not busy', (t, done) => {
159
+ plugin.config.get = () => '70'
160
+ plugin.loadConfig()
161
+
162
+ let logCount = 0
163
+ plugin.logcrit = function () {
164
+ logCount++
165
+ }
166
+
167
+ plugin.check_busy(function () {
168
+ plugin.check_busy(function () {
169
+ assert.equal(logCount, 0, 'should not log when not busy')
170
+ done()
171
+ })
172
+ })
173
+ })
174
+
175
+ it('accepts next callback', (t, done) => {
176
+ plugin.config.get = () => '70'
177
+ plugin.loadConfig()
178
+
179
+ const nextFn = function () {
180
+ done()
181
+ }
182
+
183
+ assert.doesNotThrow(() => {
184
+ plugin.check_busy(nextFn)
185
+ })
186
+ })
187
+
188
+ it('works with connection context', (t, done) => {
189
+ plugin.config.get = () => '70'
190
+ plugin.loadConfig()
191
+
192
+ const conn = makeConnection()
193
+ plugin.check_busy.call(conn, function () {
194
+ done()
195
+ })
19
196
  })
20
197
  })
21
198
  })
@@ -5,7 +5,7 @@ const assert = require('node:assert/strict')
5
5
  const { PassThrough } = require('node:stream')
6
6
  const path = require('node:path')
7
7
 
8
- const { Address } = require('../address')
8
+ const { Address } = require('@haraka/email-address')
9
9
  const fixtures = require('haraka-test-fixtures')
10
10
  const net_utils = require('haraka-net-utils')
11
11
  const message = require('haraka-email-message')
@@ -1,28 +0,0 @@
1
- {
2
- "permissions": {
3
- "allow": [
4
- "Bash(npm test:*)",
5
- "Bash(grep -r 3388 . --include=*.md --include=*.js)",
6
- "Bash(git show-ref:*)",
7
- "Bash(git symbolic-ref:*)",
8
- "Bash(curl -s https://api.github.com/repos/haraka/Haraka/issues/3388)",
9
- "WebFetch(domain:github.com)",
10
- "Bash(npx c8:*)",
11
- "Bash(node:*)",
12
- "Bash(npx mocha:*)",
13
- "Bash(npm run:*)",
14
- "Bash(gh issue *)",
15
- "Bash(git -C /Users/matt/git/haraka/Haraka log --oneline --all)",
16
- "Bash(git *)",
17
- "Bash(cat)",
18
- "Read(//tmp/**)",
19
- "Bash(bash /tmp/check_patterns.sh)",
20
- "Bash(npx prettier *)",
21
- "Bash(npx eslint *)",
22
- "Bash(perl -0pi -e 's/ const plugin = makePlugin\\\\\\(\\\\\\)\\\\n//g' test/plugins/prevent_credential_leaks.js)",
23
- "Bash(perl -0pi -e 's/makePlugin\\\\\\(\\\\\\)\\\\./plugin./g; s/ const plugin = makePlugin\\\\\\(\\\\\\)\\\\n//g' test/plugins/process_title.js)",
24
- "Bash(perl -0pi -e 's/ const plugin = makePlugin\\\\\\(\\\\\\)\\\\n//g; s/ const conn = fixtures\\\\.connection\\\\.createConnection\\\\\\(\\\\\\)\\\\n conn\\\\.transaction = null/ conn.transaction = null/g; s/ const conn = makeConnection\\\\\\(\\\\\\)\\\\n//g' test/plugins/delay_deny.js)",
25
- "Bash(gh pr *)"
26
- ]
27
- }
28
- }
package/CLAUDE.md DELETED
@@ -1,40 +0,0 @@
1
- This document provides foundational mandates and expert guidance. These instructions take precedence over general workflows.
2
-
3
- ## Technical Standards
4
-
5
- - Consistency: Compatibiilty is important, only break it for Good Cause.
6
- - Research: Identify the relevant RFC(s). Analyze existing implementation and verify conformance.
7
- - JS features: this project targets LTS versions of Node.js and/or modern web browsers.
8
- - ES2024 features should be preferred over legacy patterns.
9
- - When updating files, add `node:` prefixes to any Node.js built-in `require()` calls that lack them (e.g. `require('fs')` → `require('node:fs')`)
10
- - Use Conventional Commit format for all commit messages.
11
- - Prefer for..(of|in) iterators over forEach
12
- - Prefer node:readline for parsing files into lines
13
-
14
- ## Testing
15
-
16
- - Empirical Reproduction: For bug fixes, first create a failing test case in the corresponding test file.
17
- - Coverage: Every new feature MUST have a corresponding test file with high coverage.
18
- - Linting & Formatting: Adhere to the project's `eslint` and `prettier` configurations.
19
- - Migrate existing tests from mocha to `node --test`
20
- - when loading node:assert, load it as node:assert/strict
21
-
22
- ## Tooling Commands
23
-
24
- ```bash
25
- # Test
26
- npm run test # Run full test suite
27
- npm run test:coverage # Run tests with coverage
28
- node --test test/path/to/file.js # Run a single test file (node:test packages)
29
-
30
- # Lint & Format
31
- npm run lint # Check for linting errors.
32
- npm run lint:fix # Auto-fix lint issues
33
- npm run prettier # Check formatting
34
- npm run prettier:fix # Auto-format
35
- npm run format # prettier:fix + lint:fix (run before committing)
36
-
37
- # Dependency version management
38
- npm run versions # Check for version drift
39
- npm run versions:fix # Update versions
40
- ```
package/GEMINI.md DELETED
@@ -1,38 +0,0 @@
1
- This document provides foundational mandates and expert guidance. These instructions take precedence over general workflows.
2
-
3
- ## Technical Standards
4
- - Don't change the code unless specifically asked.
5
- - Consistency: Compatibiilty is important, only break it for Good Cause.
6
- - Research: Identify the relevant RFC(s). Analyze existing implementation and verify conformance.
7
- - JS features: this project targets LTS versions of Node.js and/or modern web browsers. Therefore, JS2024 features should be preferred over legacy patterns.
8
- - When updating files, add `node:` prefixes to any Node.js built-in `require()` calls that lack them (e.g. `require('fs')` → `require('node:fs')`)
9
- - Use Conventional Commit format for all commit messages.
10
- - Prefer for..(of|in) iterators over forEach
11
- - Prefer node:readline for parsing files into lines
12
-
13
- ## Testing
14
- - Empirical Reproduction: For bug fixes, first create a failing test case in the corresponding test file.
15
- - Coverage: Every new feature MUST have a corresponding test file with high coverage.
16
- - Linting & Formatting: Adhere to the project's `eslint` and `prettier` configurations.
17
- - Migrate existing tests from mocha to `node --test`
18
- - when loading node:assert, prefer to load it as node:assert/strict
19
-
20
- ## Tooling Commands
21
-
22
- ```bash
23
- # Test
24
- npm run test # Run full test suite
25
- npm run test:coverage # Run tests with coverage
26
- node --test test/path/to/file.js # Run a single test file (node:test packages)
27
-
28
- # Lint & Format
29
- npm run lint # Check for linting errors.
30
- npm run lint:fix # Auto-fix lint issues
31
- npm run prettier # Check formatting
32
- npm run prettier:fix # Auto-format
33
- npm run format # prettier:fix + lint:fix (run before committing)
34
-
35
- # Dependency version management
36
- npm run versions # Check for version drift
37
- npm run versions:fix # Update versions
38
- ```