thread-stream 3.0.2 → 4.0.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.
@@ -1,11 +1,11 @@
1
1
  'use strict'
2
2
 
3
- const { test } = require('tap')
3
+ const { test } = require('node:test')
4
+ const assert = require('node:assert')
4
5
  const indexes = require('../lib/indexes')
5
6
 
6
7
  for (const index of Object.keys(indexes)) {
7
- test(`${index} is lock free`, function (t) {
8
- t.equal(Atomics.isLockFree(indexes[index]), true)
9
- t.end()
8
+ test(`${index} is lock free`, function () {
9
+ assert.strictEqual(Atomics.isLockFree(indexes[index]), true)
10
10
  })
11
11
  }
@@ -1,11 +1,11 @@
1
- import { test } from 'tap'
1
+ import { test } from 'node:test'
2
+ import assert from 'node:assert'
2
3
  import { readFile } from 'fs'
3
4
  import ThreadStream from '../index.js'
4
5
  import { join } from 'desm'
5
6
  import { file } from './helper.js'
6
7
 
7
- test('break up utf8 multibyte (sync)', (t) => {
8
- t.plan(2)
8
+ test('break up utf8 multibyte (sync)', (t, done) => {
9
9
  const longString = '\u03A3'.repeat(16)
10
10
 
11
11
  const dest = file()
@@ -18,8 +18,9 @@ test('break up utf8 multibyte (sync)', (t) => {
18
18
 
19
19
  stream.on('finish', () => {
20
20
  readFile(dest, 'utf8', (err, data) => {
21
- t.error(err)
22
- t.equal(data, longString)
21
+ assert.ifError(err)
22
+ assert.strictEqual(data, longString)
23
+ done()
23
24
  })
24
25
  })
25
26
 
@@ -27,8 +28,7 @@ test('break up utf8 multibyte (sync)', (t) => {
27
28
  stream.end()
28
29
  })
29
30
 
30
- test('break up utf8 multibyte (async)', (t) => {
31
- t.plan(2)
31
+ test('break up utf8 multibyte (async)', (t, done) => {
32
32
  const longString = '\u03A3'.repeat(16)
33
33
 
34
34
  const dest = file()
@@ -41,8 +41,9 @@ test('break up utf8 multibyte (async)', (t) => {
41
41
 
42
42
  stream.on('finish', () => {
43
43
  readFile(dest, 'utf8', (err, data) => {
44
- t.error(err)
45
- t.equal(data, longString)
44
+ assert.ifError(err)
45
+ assert.strictEqual(data, longString)
46
+ done()
46
47
  })
47
48
  })
48
49
 
@@ -50,8 +51,7 @@ test('break up utf8 multibyte (async)', (t) => {
50
51
  stream.end()
51
52
  })
52
53
 
53
- test('break up utf8 multibyte several times bigger than write buffer', (t) => {
54
- t.plan(2)
54
+ test('break up utf8 multibyte several times bigger than write buffer', (t, done) => {
55
55
  const longString = '\u03A3'.repeat(32)
56
56
 
57
57
  const dest = file()
@@ -64,8 +64,9 @@ test('break up utf8 multibyte several times bigger than write buffer', (t) => {
64
64
 
65
65
  stream.on('finish', () => {
66
66
  readFile(dest, 'utf8', (err, data) => {
67
- t.error(err)
68
- t.equal(data, longString)
67
+ assert.ifError(err)
68
+ assert.strictEqual(data, longString)
69
+ done()
69
70
  })
70
71
  })
71
72
 
package/test/pkg/index.js CHANGED
@@ -1,37 +1,37 @@
1
1
  'use strict'
2
2
 
3
3
  /**
4
- * This file is packaged using pkg in order to test if worker.js works in that context
4
+ * This file is packaged using pkg in order to test if worker.js works in that context.
5
+ * Note: We can't use node:test here because it crashes inside pkg bundles due to V8 internals.
5
6
  */
6
7
 
7
- const { test } = require('tap')
8
+ const assert = require('node:assert')
8
9
  const { join } = require('path')
9
10
  const { file } = require('../helper')
10
11
  const ThreadStream = require('../..')
11
12
 
12
- test('bundlers support with .js file', function (t) {
13
- t.plan(1)
13
+ globalThis.__bundlerPathsOverrides = {
14
+ 'thread-stream-worker': join(__dirname, '..', 'custom-worker.js')
15
+ }
14
16
 
15
- globalThis.__bundlerPathsOverrides = {
16
- 'thread-stream-worker': join(__dirname, '..', 'custom-worker.js')
17
- }
17
+ const dest = file()
18
18
 
19
- const dest = file()
20
-
21
- process.on('uncaughtException', (error) => {
22
- console.log(error)
23
- })
24
-
25
- const stream = new ThreadStream({
26
- filename: join(__dirname, '..', 'to-file.js'),
27
- workerData: { dest },
28
- sync: true
29
- })
19
+ process.on('uncaughtException', (error) => {
20
+ console.error(error)
21
+ process.exit(1)
22
+ })
30
23
 
31
- stream.worker.removeAllListeners('message')
32
- stream.worker.once('message', (message) => {
33
- t.equal(message.code, 'CUSTOM-WORKER-CALLED')
34
- })
24
+ const stream = new ThreadStream({
25
+ filename: join(__dirname, '..', 'to-file.js'),
26
+ workerData: { dest },
27
+ sync: true
28
+ })
35
29
 
36
- stream.end()
30
+ stream.worker.removeAllListeners('message')
31
+ stream.worker.once('message', (message) => {
32
+ assert.strictEqual(message.code, 'CUSTOM-WORKER-CALLED')
33
+ console.log('pkg test passed')
34
+ process.exit(0)
37
35
  })
36
+
37
+ stream.end()
@@ -5,10 +5,9 @@
5
5
  "../to-file.js"
6
6
  ],
7
7
  "targets": [
8
- "node14",
9
- "node16",
10
- "node18",
11
- "node20"
8
+ "node20",
9
+ "node22",
10
+ "node24"
12
11
  ],
13
12
  "outputPath": "test/pkg"
14
13
  }
@@ -1,6 +1,7 @@
1
1
  'use strict'
2
2
 
3
- const { test } = require('tap')
3
+ const { test } = require('node:test')
4
+ const assert = require('node:assert')
4
5
  const config = require('./pkg.config.json')
5
6
  const { promisify } = require('util')
6
7
  const { unlink } = require('fs/promises')
@@ -8,7 +9,7 @@ const { join } = require('path')
8
9
  const { platform } = require('process')
9
10
  const exec = promisify(require('child_process').exec)
10
11
 
11
- test('worker test when packaged into executable using pkg', async (t) => {
12
+ test('worker test when packaged into executable using pkg', async () => {
12
13
  const packageName = 'index'
13
14
 
14
15
  // package the app into several node versions, check config for more info
@@ -19,7 +20,7 @@ test('worker test when packaged into executable using pkg', async (t) => {
19
20
  const { stderr } = await exec(`npx pkg ${filePath} --config ${configPath}`)
20
21
 
21
22
  // there should be no error when packaging
22
- t.equal(stderr, '')
23
+ assert.strictEqual(stderr, '')
23
24
 
24
25
  // pkg outputs files in the following format by default: {filename}-{node version}
25
26
  for (const target of config.pkg.targets) {
@@ -36,11 +37,9 @@ test('worker test when packaged into executable using pkg', async (t) => {
36
37
  const { stderr } = await exec(executablePath)
37
38
 
38
39
  // check if there were no errors
39
- t.equal(stderr, '')
40
+ assert.strictEqual(stderr, '')
40
41
 
41
42
  // clean up afterwards
42
43
  await unlink(executablePath)
43
44
  }
44
-
45
- t.end()
46
45
  })
@@ -1,24 +1,23 @@
1
1
  'use strict'
2
2
 
3
- const { test } = require('tap')
3
+ const { test } = require('node:test')
4
+ const assert = require('node:assert')
4
5
  const { join } = require('path')
5
6
  const { once } = require('events')
6
7
  const { MessageChannel } = require('worker_threads')
7
8
  const ThreadStream = require('..')
8
9
 
9
10
  test('message events emitted on the stream are posted to the worker', async function (t) {
10
- t.plan(1)
11
-
12
11
  const { port1, port2 } = new MessageChannel()
13
12
  const stream = new ThreadStream({
14
13
  filename: join(__dirname, 'on-message.js'),
15
14
  sync: false
16
15
  })
17
- t.teardown(() => {
16
+ t.after(() => {
18
17
  stream.end()
19
18
  })
20
19
 
21
20
  stream.emit('message', { text: 'hello', takeThisPortPlease: port1 }, [port1])
22
21
  const [confirmation] = await once(port2, 'message')
23
- t.equal(confirmation, 'received: hello')
22
+ assert.strictEqual(confirmation, 'received: hello')
24
23
  })
@@ -1,12 +1,7 @@
1
1
  'use strict'
2
2
 
3
- const t = require('tap')
4
-
5
- if (process.env.CI) {
6
- t.skip('skip on CI')
7
- process.exit(0)
8
- }
9
-
3
+ const { test } = require('node:test')
4
+ const assert = require('node:assert')
10
5
  const { join } = require('path')
11
6
  const { file } = require('./helper')
12
7
  const { createReadStream } = require('fs')
@@ -15,27 +10,26 @@ const buffer = require('buffer')
15
10
 
16
11
  const MAX_STRING = buffer.constants.MAX_STRING_LENGTH
17
12
 
18
- t.plan(1)
19
-
20
- const dest = file()
21
- const stream = new ThreadStream({
22
- filename: join(__dirname, 'to-file.js'),
23
- workerData: { dest },
24
- sync: false
25
- })
26
-
27
- stream.on('close', async () => {
28
- t.comment('close emitted')
29
- let buf
30
- for await (const chunk of createReadStream(dest)) {
31
- buf = chunk
32
- }
33
- t.equal('asd', buf.toString().slice(-3))
34
- })
35
-
36
- stream.on('ready', () => {
37
- t.comment('open emitted')
38
- stream.write('a'.repeat(MAX_STRING - 2))
39
- stream.write('asd')
40
- stream.end()
13
+ test('string limit 2', { skip: process.env.CI }, (t, done) => {
14
+ const dest = file()
15
+ const stream = new ThreadStream({
16
+ filename: join(__dirname, 'to-file.js'),
17
+ workerData: { dest },
18
+ sync: false
19
+ })
20
+
21
+ stream.on('close', async () => {
22
+ let buf
23
+ for await (const chunk of createReadStream(dest)) {
24
+ buf = chunk
25
+ }
26
+ assert.strictEqual('asd', buf.toString().slice(-3))
27
+ done()
28
+ })
29
+
30
+ stream.on('ready', () => {
31
+ stream.write('a'.repeat(MAX_STRING - 2))
32
+ stream.write('asd')
33
+ stream.end()
34
+ })
41
35
  })
@@ -1,42 +1,37 @@
1
1
  'use strict'
2
2
 
3
- const t = require('tap')
4
-
5
- if (process.env.CI) {
6
- t.skip('skip on CI')
7
- process.exit(0)
8
- }
9
-
3
+ const { test } = require('node:test')
4
+ const assert = require('node:assert')
10
5
  const { join } = require('path')
11
6
  const { file } = require('./helper')
12
7
  const { stat } = require('fs')
13
8
  const ThreadStream = require('..')
14
9
 
15
- t.setTimeout(30000)
16
-
17
- const dest = file()
18
- const stream = new ThreadStream({
19
- filename: join(__dirname, 'to-file.js'),
20
- workerData: { dest },
21
- sync: false
22
- })
10
+ test('string limit', { skip: process.env.CI, timeout: 30000 }, (t, done) => {
11
+ const dest = file()
12
+ const stream = new ThreadStream({
13
+ filename: join(__dirname, 'to-file.js'),
14
+ workerData: { dest },
15
+ sync: false
16
+ })
23
17
 
24
- let length = 0
18
+ let length = 0
25
19
 
26
- stream.on('close', () => {
27
- stat(dest, (err, f) => {
28
- t.error(err)
29
- t.equal(f.size, length)
30
- t.end()
20
+ stream.on('close', () => {
21
+ stat(dest, (err, f) => {
22
+ assert.ifError(err)
23
+ assert.strictEqual(f.size, length)
24
+ done()
25
+ })
31
26
  })
32
- })
33
27
 
34
- const buf = Buffer.alloc(1024).fill('x').toString() // 1 KB
28
+ const buf = Buffer.alloc(1024).fill('x').toString() // 1 KB
35
29
 
36
- // This writes 1 GB of data
37
- for (let i = 0; i < 1024 * 1024; i++) {
38
- length += buf.length
39
- stream.write(buf)
40
- }
30
+ // This writes 1 GB of data
31
+ for (let i = 0; i < 1024 * 1024; i++) {
32
+ length += buf.length
33
+ stream.write(buf)
34
+ }
41
35
 
42
- stream.end()
36
+ stream.end()
37
+ })
@@ -0,0 +1,2 @@
1
+ // this is a syntax error
2
+ import
@@ -1,6 +1,7 @@
1
1
  'use strict'
2
2
 
3
- const { test } = require('tap')
3
+ const { test } = require('node:test')
4
+ const assert = require('node:assert')
4
5
  const { fork } = require('child_process')
5
6
  const { join } = require('path')
6
7
  const { readFile } = require('fs').promises
@@ -13,10 +14,10 @@ test('exits with 0', async function (t) {
13
14
  const child = fork(join(__dirname, 'create-and-exit.js'), [dest])
14
15
 
15
16
  const [code] = await once(child, 'exit')
16
- t.equal(code, 0)
17
+ assert.strictEqual(code, 0)
17
18
 
18
19
  const data = await readFile(dest, 'utf8')
19
- t.equal(data, 'hello world\n')
20
+ assert.strictEqual(data, 'hello world\n')
20
21
  })
21
22
 
22
23
  test('emit error if thread exits', async function (t) {
@@ -25,20 +26,24 @@ test('emit error if thread exits', async function (t) {
25
26
  sync: true
26
27
  })
27
28
 
29
+ const closed = once(stream, 'close').catch(() => {})
30
+
28
31
  stream.on('ready', () => {
29
32
  stream.write('hello world\n')
30
33
  })
31
34
 
32
35
  let [err] = await once(stream, 'error')
33
- t.equal(err.message, 'the worker thread exited')
36
+ assert.strictEqual(err.message, 'the worker thread exited')
34
37
 
35
38
  stream.write('noop');
36
39
  [err] = await once(stream, 'error')
37
- t.equal(err.message, 'the worker has exited')
40
+ assert.strictEqual(err.message, 'the worker has exited')
38
41
 
39
42
  stream.write('noop');
40
43
  [err] = await once(stream, 'error')
41
- t.equal(err.message, 'the worker has exited')
44
+ assert.strictEqual(err.message, 'the worker has exited')
45
+
46
+ await closed
42
47
  })
43
48
 
44
49
  test('emit error if thread have unhandledRejection', async function (t) {
@@ -47,20 +52,24 @@ test('emit error if thread have unhandledRejection', async function (t) {
47
52
  sync: true
48
53
  })
49
54
 
55
+ const closed = once(stream, 'close').catch(() => {})
56
+
50
57
  stream.on('ready', () => {
51
58
  stream.write('hello world\n')
52
59
  })
53
60
 
54
61
  let [err] = await once(stream, 'error')
55
- t.equal(err.message, 'kaboom')
62
+ assert.strictEqual(err.message, 'kaboom')
56
63
 
57
64
  stream.write('noop');
58
65
  [err] = await once(stream, 'error')
59
- t.equal(err.message, 'the worker has exited')
66
+ assert.strictEqual(err.message, 'the worker has exited')
60
67
 
61
68
  stream.write('noop');
62
69
  [err] = await once(stream, 'error')
63
- t.equal(err.message, 'the worker has exited')
70
+ assert.strictEqual(err.message, 'the worker has exited')
71
+
72
+ await closed
64
73
  })
65
74
 
66
75
  test('emit error if worker stream emit error', async function (t) {
@@ -69,20 +78,24 @@ test('emit error if worker stream emit error', async function (t) {
69
78
  sync: true
70
79
  })
71
80
 
81
+ const closed = once(stream, 'close').catch(() => {})
82
+
72
83
  stream.on('ready', () => {
73
84
  stream.write('hello world\n')
74
85
  })
75
86
 
76
87
  let [err] = await once(stream, 'error')
77
- t.equal(err.message, 'kaboom')
88
+ assert.strictEqual(err.message, 'kaboom')
78
89
 
79
90
  stream.write('noop');
80
91
  [err] = await once(stream, 'error')
81
- t.equal(err.message, 'the worker has exited')
92
+ assert.strictEqual(err.message, 'the worker has exited')
82
93
 
83
94
  stream.write('noop');
84
95
  [err] = await once(stream, 'error')
85
- t.equal(err.message, 'the worker has exited')
96
+ assert.strictEqual(err.message, 'the worker has exited')
97
+
98
+ await closed
86
99
  })
87
100
 
88
101
  test('emit error if thread have uncaughtException', async function (t) {
@@ -91,20 +104,24 @@ test('emit error if thread have uncaughtException', async function (t) {
91
104
  sync: true
92
105
  })
93
106
 
107
+ const closed = once(stream, 'close').catch(() => {})
108
+
94
109
  stream.on('ready', () => {
95
110
  stream.write('hello world\n')
96
111
  })
97
112
 
98
113
  let [err] = await once(stream, 'error')
99
- t.equal(err.message, 'kaboom')
114
+ assert.strictEqual(err.message, 'kaboom')
100
115
 
101
116
  stream.write('noop');
102
117
  [err] = await once(stream, 'error')
103
- t.equal(err.message, 'the worker has exited')
118
+ assert.strictEqual(err.message, 'the worker has exited')
104
119
 
105
120
  stream.write('noop');
106
121
  [err] = await once(stream, 'error')
107
- t.equal(err.message, 'the worker has exited')
122
+ assert.strictEqual(err.message, 'the worker has exited')
123
+
124
+ await closed
108
125
  })
109
126
 
110
127
  test('close the work if out of scope on gc', { skip: !global.WeakRef }, async function (t) {
@@ -114,8 +131,8 @@ test('close the work if out of scope on gc', { skip: !global.WeakRef }, async fu
114
131
  })
115
132
 
116
133
  const [code] = await once(child, 'exit')
117
- t.equal(code, 0)
134
+ assert.strictEqual(code, 0)
118
135
 
119
136
  const data = await readFile(dest, 'utf8')
120
- t.equal(data, 'hello world\n')
137
+ assert.strictEqual(data, 'hello world\n')
121
138
  })
@@ -1,14 +1,13 @@
1
1
  'use strict'
2
2
 
3
- const { test } = require('tap')
3
+ const { test } = require('node:test')
4
+ const assert = require('node:assert')
4
5
  const { join } = require('path')
5
6
  const { file } = require('./helper')
6
7
  const ThreadStream = require('..')
7
8
 
8
9
  function basic (esVersion) {
9
- test(`transpiled-ts-to-${esVersion}`, function (t) {
10
- t.plan(2)
11
-
10
+ test(`transpiled-ts-to-${esVersion}`, function () {
12
11
  const dest = file()
13
12
  const stream = new ThreadStream({
14
13
  filename: join(__dirname, 'ts', `to-file.${esVersion}.cjs`),
@@ -18,9 +17,9 @@ function basic (esVersion) {
18
17
 
19
18
  // There are arbitrary checks, the important aspect of this test is to ensure
20
19
  // that we can properly load the transpiled file into our worker thread.
21
- t.same(stream.writableEnded, false)
20
+ assert.deepStrictEqual(stream.writableEnded, false)
22
21
  stream.end()
23
- t.same(stream.writableEnded, true)
22
+ assert.deepStrictEqual(stream.writableEnded, true)
24
23
  })
25
24
  }
26
25
 
@@ -0,0 +1,35 @@
1
+ import { test } from 'node:test'
2
+ import assert from 'node:assert'
3
+ import { readFile } from 'fs/promises'
4
+ import ThreadStream from '../index.js'
5
+ import { join } from 'desm'
6
+ import { file } from './helper.js'
7
+
8
+ const nodeVersion = parseInt(process.versions.node.split('.')[0], 10)
9
+
10
+ // Native TypeScript stripping (--experimental-strip-types) is only available in Node 22.6+
11
+ test('typescript module with native type stripping', { skip: nodeVersion < 22 }, async function (t) {
12
+ const dest = file()
13
+ const stream = new ThreadStream({
14
+ filename: join(import.meta.url, 'ts', 'to-file.ts'),
15
+ workerData: { dest },
16
+ workerOpts: {
17
+ execArgv: ['--experimental-strip-types', '--disable-warning=ExperimentalWarning']
18
+ },
19
+ sync: false
20
+ })
21
+
22
+ t.after(() => stream.end())
23
+
24
+ assert.ok(stream.write('hello world\n'))
25
+ assert.ok(stream.write('something else\n'))
26
+
27
+ stream.end()
28
+
29
+ await new Promise((resolve) => {
30
+ stream.on('close', resolve)
31
+ })
32
+
33
+ const data = await readFile(dest, 'utf8')
34
+ assert.strictEqual(data, 'hello world\nsomething else\n')
35
+ })
@@ -0,0 +1,35 @@
1
+ 'use strict'
2
+
3
+ const { test } = require('node:test')
4
+ const assert = require('node:assert')
5
+ const { readFile } = require('fs/promises')
6
+ const { join } = require('path')
7
+ const { file } = require('./helper')
8
+ const ThreadStream = require('..')
9
+
10
+ // This test verifies that TypeScript files can be loaded via ts-node
11
+ // when native type stripping is not enabled in the worker thread.
12
+ // Unlike ts.test.ts which passes --experimental-strip-types via execArgv,
13
+ // this test does NOT pass that flag, so the worker will fall back to ts-node.
14
+ test('typescript module with ts-node fallback', async function (t) {
15
+ const dest = file()
16
+ const stream = new ThreadStream({
17
+ filename: join(__dirname, 'ts', 'to-file.ts'),
18
+ workerData: { dest },
19
+ sync: false
20
+ })
21
+
22
+ t.after(() => stream.end())
23
+
24
+ assert.ok(stream.write('hello world\n'))
25
+ assert.ok(stream.write('something else\n'))
26
+
27
+ stream.end()
28
+
29
+ await new Promise((resolve) => {
30
+ stream.on('close', resolve)
31
+ })
32
+
33
+ const data = await readFile(dest, 'utf8')
34
+ assert.strictEqual(data, 'hello world\nsomething else\n')
35
+ })
package/.taprc DELETED
@@ -1,4 +0,0 @@
1
- jobs: 1
2
- check-coverage: false
3
- # in seconds
4
- timeout: 60
@@ -1,57 +0,0 @@
1
- const { test } = require('tap')
2
- const ThreadStream = require('../index')
3
- const { join } = require('path')
4
-
5
- function retryUntilTimeout (fn, timeout) {
6
- const start = Date.now()
7
- return new Promise((resolve, reject) => {
8
- async function run () {
9
- if (fn()) {
10
- resolve()
11
- return
12
- }
13
-
14
- if (Date.now() - start >= timeout) {
15
- reject(new Error('timeout'))
16
- return
17
- }
18
- setTimeout(run, 10)
19
- }
20
-
21
- run()
22
- })
23
- }
24
-
25
- const isNode18 = process.version.indexOf('v18') === 0
26
-
27
- test('emit warning when the worker gracefully exit without the stream ended', { skip: !isNode18 }, async function (t) {
28
- const expectedWarning = 'ThreadStream: process exited before destination stream was drained. this may indicate that the destination stream try to write to a another missing stream'
29
- const stream = new ThreadStream({
30
- filename: join(__dirname, 'to-next.js')
31
- })
32
- stream.unref()
33
-
34
- let streamWarning
35
- function saveWarning (e) {
36
- if (e.message === expectedWarning) {
37
- streamWarning = e
38
- }
39
- }
40
- process.on('warning', saveWarning)
41
-
42
- const data = 'hello'.repeat(10)
43
- for (let i = 0; i < 1000; i++) {
44
- if (streamWarning?.message === expectedWarning) {
45
- break
46
- }
47
- stream.write(data)
48
- await new Promise((resolve) => {
49
- setTimeout(resolve, 1)
50
- })
51
- }
52
-
53
- process.off('warning', saveWarning)
54
- t.equal(streamWarning?.message, expectedWarning)
55
-
56
- await retryUntilTimeout(() => stream.worker.exited === true, 3000)
57
- })