pino-testkit 10.4.5

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 (196) hide show
  1. package/.nojekyll +0 -0
  2. package/.prettierignore +1 -0
  3. package/CNAME +1 -0
  4. package/CONTRIBUTING.md +30 -0
  5. package/LICENSE +21 -0
  6. package/README.md +175 -0
  7. package/SECURITY.md +87 -0
  8. package/benchmarks/basic.bench.js +95 -0
  9. package/benchmarks/child-child.bench.js +52 -0
  10. package/benchmarks/child-creation.bench.js +73 -0
  11. package/benchmarks/child.bench.js +62 -0
  12. package/benchmarks/deep-object.bench.js +88 -0
  13. package/benchmarks/formatters.bench.js +50 -0
  14. package/benchmarks/internal/custom-levels.js +67 -0
  15. package/benchmarks/internal/just-pino-heavy.bench.js +76 -0
  16. package/benchmarks/internal/just-pino.bench.js +182 -0
  17. package/benchmarks/internal/parent-vs-child.bench.js +75 -0
  18. package/benchmarks/internal/redact.bench.js +86 -0
  19. package/benchmarks/long-string.bench.js +81 -0
  20. package/benchmarks/multi-arg.bench.js +193 -0
  21. package/benchmarks/multistream.js +98 -0
  22. package/benchmarks/object.bench.js +82 -0
  23. package/benchmarks/utils/generate-benchmark-doc.js +36 -0
  24. package/benchmarks/utils/runbench.js +138 -0
  25. package/benchmarks/utils/wrap-log-level.js +55 -0
  26. package/bin.js +6 -0
  27. package/browser.js +547 -0
  28. package/build/sync-version.js +25 -0
  29. package/docs/api.md +1593 -0
  30. package/docs/asynchronous.md +40 -0
  31. package/docs/benchmarks.md +55 -0
  32. package/docs/browser.md +278 -0
  33. package/docs/bundling.md +40 -0
  34. package/docs/child-loggers.md +95 -0
  35. package/docs/diagnostics.md +16 -0
  36. package/docs/ecosystem.md +86 -0
  37. package/docs/help.md +345 -0
  38. package/docs/lts.md +64 -0
  39. package/docs/pretty.md +35 -0
  40. package/docs/redaction.md +135 -0
  41. package/docs/transports.md +1376 -0
  42. package/docs/web.md +309 -0
  43. package/eslint.config.js +28 -0
  44. package/examples/basic.js +43 -0
  45. package/examples/transport.js +68 -0
  46. package/favicon.ico +0 -0
  47. package/file.js +12 -0
  48. package/inc-version.sh +42 -0
  49. package/index.html +55 -0
  50. package/lib/caller.js +30 -0
  51. package/lib/constants.js +28 -0
  52. package/lib/contract.js +8 -0
  53. package/lib/deprecations.js +8 -0
  54. package/lib/levels.js +241 -0
  55. package/lib/meta.js +3 -0
  56. package/lib/multistream.js +203 -0
  57. package/lib/proto.js +256 -0
  58. package/lib/redaction.js +114 -0
  59. package/lib/symbols.js +74 -0
  60. package/lib/time.js +39 -0
  61. package/lib/tools.js +427 -0
  62. package/lib/transport-stream.js +56 -0
  63. package/lib/transport.js +289 -0
  64. package/lib/worker.js +194 -0
  65. package/package.json +119 -0
  66. package/pino.d.ts +908 -0
  67. package/pino.js +240 -0
  68. package/test/basic.test.js +886 -0
  69. package/test/broken-pipe.test.js +59 -0
  70. package/test/browser-child.test.js +132 -0
  71. package/test/browser-disabled.test.js +87 -0
  72. package/test/browser-early-console-freeze.test.js +12 -0
  73. package/test/browser-is-level-enabled.test.js +101 -0
  74. package/test/browser-levels.test.js +241 -0
  75. package/test/browser-serializers.test.js +352 -0
  76. package/test/browser-timestamp.test.js +88 -0
  77. package/test/browser-transmit.test.js +417 -0
  78. package/test/browser.test.js +698 -0
  79. package/test/complex-objects.test.js +36 -0
  80. package/test/crlf.test.js +34 -0
  81. package/test/custom-levels.test.js +267 -0
  82. package/test/diagnostics.test.js +107 -0
  83. package/test/error-key.test.js +37 -0
  84. package/test/error.test.js +403 -0
  85. package/test/escaping.test.js +93 -0
  86. package/test/esm/esm.mjs +14 -0
  87. package/test/esm/index.test.js +21 -0
  88. package/test/esm/named-exports.mjs +29 -0
  89. package/test/exit.test.js +79 -0
  90. package/test/fixtures/broken-pipe/basic.js +9 -0
  91. package/test/fixtures/broken-pipe/destination.js +10 -0
  92. package/test/fixtures/broken-pipe/syncfalse.js +12 -0
  93. package/test/fixtures/console-transport.js +13 -0
  94. package/test/fixtures/crashing-transport.js +13 -0
  95. package/test/fixtures/default-exit.js +8 -0
  96. package/test/fixtures/destination-exit.js +8 -0
  97. package/test/fixtures/eval/index.js +13 -0
  98. package/test/fixtures/eval/node_modules/14-files.js +3 -0
  99. package/test/fixtures/eval/node_modules/2-files.js +3 -0
  100. package/test/fixtures/eval/node_modules/file1.js +5 -0
  101. package/test/fixtures/eval/node_modules/file10.js +5 -0
  102. package/test/fixtures/eval/node_modules/file11.js +5 -0
  103. package/test/fixtures/eval/node_modules/file12.js +5 -0
  104. package/test/fixtures/eval/node_modules/file13.js +5 -0
  105. package/test/fixtures/eval/node_modules/file14.js +11 -0
  106. package/test/fixtures/eval/node_modules/file2.js +5 -0
  107. package/test/fixtures/eval/node_modules/file3.js +5 -0
  108. package/test/fixtures/eval/node_modules/file4.js +5 -0
  109. package/test/fixtures/eval/node_modules/file5.js +5 -0
  110. package/test/fixtures/eval/node_modules/file6.js +5 -0
  111. package/test/fixtures/eval/node_modules/file7.js +5 -0
  112. package/test/fixtures/eval/node_modules/file8.js +5 -0
  113. package/test/fixtures/eval/node_modules/file9.js +5 -0
  114. package/test/fixtures/noop-transport.js +10 -0
  115. package/test/fixtures/pretty/null-prototype.js +8 -0
  116. package/test/fixtures/stdout-hack-protection.js +11 -0
  117. package/test/fixtures/syncfalse-child.js +6 -0
  118. package/test/fixtures/syncfalse-exit.js +9 -0
  119. package/test/fixtures/syncfalse-flush-exit.js +10 -0
  120. package/test/fixtures/syncfalse.js +6 -0
  121. package/test/fixtures/syntax-error-esm.mjs +2 -0
  122. package/test/fixtures/to-file-transport-with-transform.js +20 -0
  123. package/test/fixtures/to-file-transport.js +13 -0
  124. package/test/fixtures/to-file-transport.mjs +8 -0
  125. package/test/fixtures/transport/index.js +12 -0
  126. package/test/fixtures/transport/package.json +5 -0
  127. package/test/fixtures/transport-exit-immediately-with-async-dest.js +16 -0
  128. package/test/fixtures/transport-exit-immediately.js +11 -0
  129. package/test/fixtures/transport-exit-on-ready.js +12 -0
  130. package/test/fixtures/transport-invalid-node-options.js +26 -0
  131. package/test/fixtures/transport-main.js +9 -0
  132. package/test/fixtures/transport-many-lines.js +29 -0
  133. package/test/fixtures/transport-preload-main.mjs +13 -0
  134. package/test/fixtures/transport-preload.mjs +13 -0
  135. package/test/fixtures/transport-string-stdout.js +9 -0
  136. package/test/fixtures/transport-transform.js +21 -0
  137. package/test/fixtures/transport-uses-pino-config.js +33 -0
  138. package/test/fixtures/transport-with-on-exit.js +12 -0
  139. package/test/fixtures/transport-worker-data.js +19 -0
  140. package/test/fixtures/transport-worker-name.js +24 -0
  141. package/test/fixtures/transport-worker.js +15 -0
  142. package/test/fixtures/transport-wrong-export-type.js +3 -0
  143. package/test/fixtures/ts/to-file-transport-native.mts +15 -0
  144. package/test/fixtures/ts/to-file-transport-with-transform.ts +18 -0
  145. package/test/fixtures/ts/to-file-transport.ts +11 -0
  146. package/test/fixtures/ts/transpile.cjs +36 -0
  147. package/test/fixtures/ts/transport-exit-immediately-with-async-dest.ts +15 -0
  148. package/test/fixtures/ts/transport-exit-immediately.ts +10 -0
  149. package/test/fixtures/ts/transport-exit-on-ready.ts +11 -0
  150. package/test/fixtures/ts/transport-main.ts +8 -0
  151. package/test/fixtures/ts/transport-string-stdout.ts +8 -0
  152. package/test/fixtures/ts/transport-worker.ts +14 -0
  153. package/test/formatters.test.js +364 -0
  154. package/test/helper.d.ts +4 -0
  155. package/test/helper.js +155 -0
  156. package/test/hooks.test.js +114 -0
  157. package/test/http.test.js +214 -0
  158. package/test/internals/version.test.js +17 -0
  159. package/test/is-level-enabled.test.js +179 -0
  160. package/test/jest/basic.spec.js +10 -0
  161. package/test/levels.test.js +810 -0
  162. package/test/metadata.test.js +120 -0
  163. package/test/mixin-merge-strategy.test.js +57 -0
  164. package/test/mixin.test.js +241 -0
  165. package/test/multistream.test.js +729 -0
  166. package/test/redact.test.js +893 -0
  167. package/test/serializers.test.js +257 -0
  168. package/test/stdout-protection.test.js +41 -0
  169. package/test/syncfalse.test.js +186 -0
  170. package/test/timestamp-nano.test.js +37 -0
  171. package/test/timestamp.test.js +124 -0
  172. package/test/transport/big.test.js +42 -0
  173. package/test/transport/bundlers-support.test.js +99 -0
  174. package/test/transport/caller.test.js +24 -0
  175. package/test/transport/core.test.js +733 -0
  176. package/test/transport/core.transpiled.test.ts +114 -0
  177. package/test/transport/crash.test.js +36 -0
  178. package/test/transport/module-link.test.js +241 -0
  179. package/test/transport/native-type-stripping.test.mjs +151 -0
  180. package/test/transport/node-options.test.js +116 -0
  181. package/test/transport/pipeline.test.js +137 -0
  182. package/test/transport/preload.test.js +54 -0
  183. package/test/transport/repl.test.js +15 -0
  184. package/test/transport/sync-false.test.js +67 -0
  185. package/test/transport/sync-true.test.js +57 -0
  186. package/test/transport/targets.test.js +48 -0
  187. package/test/transport/uses-pino-config.test.js +166 -0
  188. package/test/transport-stream.test.js +40 -0
  189. package/test/types/pino-import.test-d.cts +30 -0
  190. package/test/types/pino-multistream.test-d.ts +28 -0
  191. package/test/types/pino-top-export.test-d.ts +34 -0
  192. package/test/types/pino-transport.test-d.ts +156 -0
  193. package/test/types/pino-type-only.test-d.ts +75 -0
  194. package/test/types/pino.test-d.ts +683 -0
  195. package/test/types/pino.ts +91 -0
  196. package/tsconfig.json +14 -0
@@ -0,0 +1,114 @@
1
+ import test from 'node:test'
2
+ import assert from 'node:assert'
3
+ import * as os from 'node:os'
4
+ import { join } from 'node:path'
5
+ import fs from 'node:fs'
6
+ import * as url from 'node:url'
7
+
8
+ import { watchFileCreated } from '../helper'
9
+ import pino from '../../'
10
+
11
+ const readFile = fs.promises.readFile
12
+
13
+ const { pid } = process
14
+ const hostname = os.hostname()
15
+
16
+ // A subset of the test from core.test.js, we don't need all of them to check for compatibility
17
+ function runTests (esVersion: string): void {
18
+ test(`(ts -> ${esVersion}) pino.transport with file`, async (t) => {
19
+ const destination = join(
20
+ os.tmpdir(),
21
+ '_' + Math.random().toString(36).substr(2, 9)
22
+ )
23
+ const transport = pino.transport({
24
+ target: join(__dirname, '..', 'fixtures', 'ts', `to-file-transport.${esVersion}.cjs`),
25
+ options: { destination }
26
+ })
27
+ t.after(transport.end.bind(transport))
28
+ const instance = pino(transport)
29
+ instance.info('hello')
30
+ await watchFileCreated(destination)
31
+ const result = JSON.parse(await readFile(destination, { encoding: 'utf8' }))
32
+ delete result.time
33
+ assert.deepEqual(result, {
34
+ pid,
35
+ hostname,
36
+ level: 30,
37
+ msg: 'hello'
38
+ })
39
+ })
40
+
41
+ test(`(ts -> ${esVersion}) pino.transport with file URL`, async (t) => {
42
+ const destination = join(
43
+ os.tmpdir(),
44
+ '_' + Math.random().toString(36).substr(2, 9)
45
+ )
46
+ const transport = pino.transport({
47
+ target: url.pathToFileURL(join(__dirname, '..', 'fixtures', 'ts', `to-file-transport.${esVersion}.cjs`)).href,
48
+ options: { destination }
49
+ })
50
+ t.after(transport.end.bind(transport))
51
+ const instance = pino(transport)
52
+ instance.info('hello')
53
+ await watchFileCreated(destination)
54
+ const result = JSON.parse(await readFile(destination, { encoding: 'utf8' }))
55
+ delete result.time
56
+ assert.deepEqual(result, {
57
+ pid,
58
+ hostname,
59
+ level: 30,
60
+ msg: 'hello'
61
+ })
62
+ })
63
+
64
+ test(`(ts -> ${esVersion}) pino.transport with two files`, async (t) => {
65
+ const dest1 = join(
66
+ os.tmpdir(),
67
+ '_' + Math.random().toString(36).substr(2, 9)
68
+ )
69
+ const dest2 = join(
70
+ os.tmpdir(),
71
+ '_' + Math.random().toString(36).substr(2, 9)
72
+ )
73
+ const transport = pino.transport({
74
+ targets: [{
75
+ level: 'info',
76
+ target: join(__dirname, '..', 'fixtures', 'ts', `to-file-transport.${esVersion}.cjs`),
77
+ options: { destination: dest1 }
78
+ }, {
79
+ level: 'info',
80
+ target: join(__dirname, '..', 'fixtures', 'ts', `to-file-transport.${esVersion}.cjs`),
81
+ options: { destination: dest2 }
82
+ }]
83
+ })
84
+
85
+ t.after(transport.end.bind(transport))
86
+
87
+ const instance = pino(transport)
88
+ instance.info('hello')
89
+
90
+ await Promise.all([watchFileCreated(dest1), watchFileCreated(dest2)])
91
+
92
+ const result1 = JSON.parse(await readFile(dest1, { encoding: 'utf8' }))
93
+ delete result1.time
94
+ assert.deepEqual(result1, {
95
+ pid,
96
+ hostname,
97
+ level: 30,
98
+ msg: 'hello'
99
+ })
100
+ const result2 = JSON.parse(await readFile(dest2, { encoding: 'utf8' }))
101
+ delete result2.time
102
+ assert.deepEqual(result2, {
103
+ pid,
104
+ hostname,
105
+ level: 30,
106
+ msg: 'hello'
107
+ })
108
+ })
109
+ }
110
+
111
+ runTests('es5')
112
+ runTests('es6')
113
+ runTests('es2017')
114
+ runTests('esnext')
@@ -0,0 +1,36 @@
1
+ 'use strict'
2
+
3
+ const test = require('node:test')
4
+ const assert = require('node:assert')
5
+ const { join } = require('node:path')
6
+ const { once } = require('node:events')
7
+ const { setImmediate: immediate } = require('node:timers/promises')
8
+
9
+ const pino = require('../../')
10
+
11
+ test('pino.transport emits error if the worker exits with 0 unexpectably', async (t) => {
12
+ // This test will take 10s, because flushSync waits for 10s
13
+ const transport = pino.transport({
14
+ target: join(__dirname, '..', 'fixtures', 'crashing-transport.js'),
15
+ sync: true
16
+ })
17
+ t.after(transport.end.bind(transport))
18
+
19
+ await once(transport, 'ready')
20
+
21
+ let maybeError
22
+ transport.on('error', (err) => {
23
+ maybeError = err
24
+ })
25
+
26
+ const logger = pino(transport)
27
+ for (let i = 0; i < 100000; i++) {
28
+ logger.info('hello')
29
+ }
30
+
31
+ await once(transport.worker, 'exit')
32
+
33
+ await immediate()
34
+
35
+ assert.equal(maybeError.message, 'the worker has exited')
36
+ })
@@ -0,0 +1,241 @@
1
+ 'use strict'
2
+
3
+ const test = require('node:test')
4
+ const assert = require('node:assert')
5
+ const os = require('node:os')
6
+ const { join } = require('node:path')
7
+ const { readFile, symlink, unlink, mkdir, writeFile } = require('node:fs').promises
8
+ const { once } = require('node:events')
9
+ const execa = require('execa')
10
+ const rimraf = require('rimraf')
11
+
12
+ const { isWin, isYarnPnp, watchFileCreated, file } = require('../helper')
13
+ const pino = require('../../')
14
+
15
+ const { pid } = process
16
+ const hostname = os.hostname()
17
+
18
+ async function installTransportModule (target) {
19
+ if (isYarnPnp) {
20
+ return
21
+ }
22
+ try {
23
+ await uninstallTransportModule()
24
+ } catch {}
25
+
26
+ if (!target) {
27
+ target = join(__dirname, '..', '..')
28
+ }
29
+
30
+ await symlink(
31
+ join(__dirname, '..', 'fixtures', 'transport'),
32
+ join(target, 'node_modules', 'transport')
33
+ )
34
+ }
35
+
36
+ async function uninstallTransportModule () {
37
+ if (isYarnPnp) {
38
+ return
39
+ }
40
+ await unlink(join(__dirname, '..', '..', 'node_modules', 'transport'))
41
+ }
42
+
43
+ // TODO make this test pass on Windows
44
+ test('pino.transport with package', { skip: isWin }, async (t) => {
45
+ const destination = file()
46
+
47
+ await installTransportModule()
48
+
49
+ const transport = pino.transport({
50
+ target: 'transport',
51
+ options: { destination }
52
+ })
53
+
54
+ t.after(async () => {
55
+ await uninstallTransportModule()
56
+ transport.end()
57
+ })
58
+ const instance = pino(transport)
59
+ instance.info('hello')
60
+ await watchFileCreated(destination)
61
+ const result = JSON.parse(await readFile(destination))
62
+ delete result.time
63
+ assert.deepEqual(result, {
64
+ pid,
65
+ hostname,
66
+ level: 30,
67
+ msg: 'hello'
68
+ })
69
+ })
70
+
71
+ // TODO make this test pass on Windows
72
+ test('pino.transport with package as a target', { skip: isWin }, async (t) => {
73
+ const destination = file()
74
+
75
+ await installTransportModule()
76
+
77
+ const transport = pino.transport({
78
+ targets: [{
79
+ target: 'transport',
80
+ options: { destination }
81
+ }]
82
+ })
83
+ t.after(async () => {
84
+ await uninstallTransportModule()
85
+ transport.end()
86
+ })
87
+ const instance = pino(transport)
88
+ instance.info('hello')
89
+ await watchFileCreated(destination)
90
+ const result = JSON.parse(await readFile(destination))
91
+ delete result.time
92
+ assert.deepEqual(result, {
93
+ pid,
94
+ hostname,
95
+ level: 30,
96
+ msg: 'hello'
97
+ })
98
+ })
99
+
100
+ // TODO make this test pass on Windows
101
+ test('pino({ transport })', { skip: isWin || isYarnPnp }, async (t) => {
102
+ const folder = join(
103
+ os.tmpdir(),
104
+ '_' + Math.random().toString(36).substr(2, 9)
105
+ )
106
+
107
+ t.after(() => {
108
+ rimraf.sync(folder)
109
+ })
110
+
111
+ const destination = join(folder, 'output')
112
+
113
+ await mkdir(join(folder, 'node_modules'), { recursive: true })
114
+
115
+ // Link pino
116
+ await symlink(
117
+ join(__dirname, '..', '..'),
118
+ join(folder, 'node_modules', 'pino')
119
+ )
120
+
121
+ await installTransportModule(folder)
122
+
123
+ const toRun = join(folder, 'index.js')
124
+
125
+ const toRunContent = `
126
+ const pino = require('pino')
127
+ const logger = pino({
128
+ transport: {
129
+ target: 'transport',
130
+ options: { destination: '${destination}' }
131
+ }
132
+ })
133
+ logger.info('hello')
134
+ `
135
+
136
+ await writeFile(toRun, toRunContent)
137
+
138
+ const child = execa(process.argv[0], [toRun])
139
+
140
+ await once(child, 'close')
141
+
142
+ const result = JSON.parse(await readFile(destination))
143
+ delete result.time
144
+ assert.deepEqual(result, {
145
+ pid: child.pid,
146
+ hostname,
147
+ level: 30,
148
+ msg: 'hello'
149
+ })
150
+ })
151
+
152
+ // TODO make this test pass on Windows
153
+ test('pino({ transport }) from a wrapped dependency', { skip: isWin || isYarnPnp }, async (t) => {
154
+ const folder = join(
155
+ os.tmpdir(),
156
+ '_' + Math.random().toString(36).substr(2, 9)
157
+ )
158
+
159
+ const wrappedFolder = join(
160
+ os.tmpdir(),
161
+ '_' + Math.random().toString(36).substr(2, 9)
162
+ )
163
+
164
+ const destination = join(folder, 'output')
165
+
166
+ await mkdir(join(folder, 'node_modules'), { recursive: true })
167
+ await mkdir(join(wrappedFolder, 'node_modules'), { recursive: true })
168
+
169
+ t.after(() => {
170
+ rimraf.sync(wrappedFolder)
171
+ rimraf.sync(folder)
172
+ })
173
+
174
+ // Link pino
175
+ await symlink(
176
+ join(__dirname, '..', '..'),
177
+ join(wrappedFolder, 'node_modules', 'pino')
178
+ )
179
+
180
+ // Link get-caller-file
181
+ await symlink(
182
+ join(__dirname, '..', '..', 'node_modules', 'get-caller-file'),
183
+ join(wrappedFolder, 'node_modules', 'get-caller-file')
184
+ )
185
+
186
+ // Link wrapped
187
+ await symlink(
188
+ wrappedFolder,
189
+ join(folder, 'node_modules', 'wrapped')
190
+ )
191
+
192
+ await installTransportModule(folder)
193
+
194
+ const pkgjsonContent = {
195
+ name: 'pino'
196
+ }
197
+
198
+ await writeFile(join(wrappedFolder, 'package.json'), JSON.stringify(pkgjsonContent))
199
+
200
+ const wrapped = join(wrappedFolder, 'index.js')
201
+
202
+ const wrappedContent = `
203
+ const pino = require('pino')
204
+ const getCaller = require('get-caller-file')
205
+
206
+ module.exports = function build () {
207
+ const logger = pino({
208
+ transport: {
209
+ caller: getCaller(),
210
+ target: 'transport',
211
+ options: { destination: '${destination}' }
212
+ }
213
+ })
214
+ return logger
215
+ }
216
+ `
217
+
218
+ await writeFile(wrapped, wrappedContent)
219
+
220
+ const toRun = join(folder, 'index.js')
221
+
222
+ const toRunContent = `
223
+ const logger = require('wrapped')()
224
+ logger.info('hello')
225
+ `
226
+
227
+ await writeFile(toRun, toRunContent)
228
+
229
+ const child = execa(process.argv[0], [toRun])
230
+
231
+ await once(child, 'close')
232
+
233
+ const result = JSON.parse(await readFile(destination))
234
+ delete result.time
235
+ assert.deepEqual(result, {
236
+ pid: child.pid,
237
+ hostname,
238
+ level: 30,
239
+ msg: 'hello'
240
+ })
241
+ })
@@ -0,0 +1,151 @@
1
+ import test from 'node:test'
2
+ import assert from 'node:assert'
3
+ import * as os from 'node:os'
4
+ import { join } from 'node:path'
5
+ import fs from 'node:fs'
6
+ import * as url from 'node:url'
7
+
8
+ import { watchFileCreated } from '../helper.js'
9
+
10
+ const readFile = fs.promises.readFile
11
+
12
+ const { pid } = process
13
+ const hostname = os.hostname()
14
+
15
+ // Check if Node.js supports native type stripping (Node.js 22+)
16
+ function supportsTypeStripping () {
17
+ const major = parseInt(process.versions.node.split('.')[0], 10)
18
+ return major >= 22
19
+ }
20
+
21
+ // Only run these tests on Node.js 22+
22
+ const skipTests = !supportsTypeStripping()
23
+ const skipMessage = 'Native TypeScript type stripping not supported (requires Node.js 22+)'
24
+
25
+ test('pino.transport with native TypeScript file', { skip: skipTests ? skipMessage : false }, async (t) => {
26
+ const destination = join(
27
+ os.tmpdir(),
28
+ '_' + Math.random().toString(36).substr(2, 9)
29
+ )
30
+
31
+ // We need to dynamically import pino to ensure worker thread inherits flags
32
+ const { default: pino } = await import('../../pino.js')
33
+
34
+ const transport = pino.transport({
35
+ target: join(import.meta.dirname || url.fileURLToPath(new URL('.', import.meta.url)), '..', 'fixtures', 'ts', 'to-file-transport-native.mts'),
36
+ options: { destination }
37
+ })
38
+
39
+ t.after(() => {
40
+ transport.end()
41
+ try {
42
+ fs.unlinkSync(destination)
43
+ } catch {}
44
+ })
45
+
46
+ const instance = pino(transport)
47
+ instance.info('hello from native TypeScript transport')
48
+
49
+ await watchFileCreated(destination)
50
+ const result = JSON.parse(await readFile(destination, { encoding: 'utf8' }))
51
+ delete result.time
52
+
53
+ assert.deepEqual(result, {
54
+ pid,
55
+ hostname,
56
+ level: 30,
57
+ msg: 'hello from native TypeScript transport'
58
+ })
59
+ })
60
+
61
+ test('pino.transport with native TypeScript file URL', { skip: skipTests ? skipMessage : false }, async (t) => {
62
+ const destination = join(
63
+ os.tmpdir(),
64
+ '_' + Math.random().toString(36).substr(2, 9)
65
+ )
66
+
67
+ const { default: pino } = await import('../../pino.js')
68
+
69
+ const transport = pino.transport({
70
+ target: url.pathToFileURL(join(import.meta.dirname || url.fileURLToPath(new URL('.', import.meta.url)), '..', 'fixtures', 'ts', 'to-file-transport-native.mts')).href,
71
+ options: { destination }
72
+ })
73
+
74
+ t.after(() => {
75
+ transport.end()
76
+ try {
77
+ fs.unlinkSync(destination)
78
+ } catch {}
79
+ })
80
+
81
+ const instance = pino(transport)
82
+ instance.info('hello from file URL transport')
83
+
84
+ await watchFileCreated(destination)
85
+ const result = JSON.parse(await readFile(destination, { encoding: 'utf8' }))
86
+ delete result.time
87
+
88
+ assert.deepEqual(result, {
89
+ pid,
90
+ hostname,
91
+ level: 30,
92
+ msg: 'hello from file URL transport'
93
+ })
94
+ })
95
+
96
+ test('pino.transport with multiple native TypeScript targets', { skip: skipTests ? skipMessage : false }, async (t) => {
97
+ const dest1 = join(
98
+ os.tmpdir(),
99
+ '_' + Math.random().toString(36).substr(2, 9)
100
+ )
101
+ const dest2 = join(
102
+ os.tmpdir(),
103
+ '_' + Math.random().toString(36).substr(2, 9)
104
+ )
105
+
106
+ const { default: pino } = await import('../../pino.js')
107
+ const fixtureDir = join(import.meta.dirname || url.fileURLToPath(new URL('.', import.meta.url)), '..', 'fixtures', 'ts')
108
+
109
+ const transport = pino.transport({
110
+ targets: [{
111
+ level: 'info',
112
+ target: join(fixtureDir, 'to-file-transport-native.mts'),
113
+ options: { destination: dest1 }
114
+ }, {
115
+ level: 'info',
116
+ target: join(fixtureDir, 'to-file-transport-native.mts'),
117
+ options: { destination: dest2 }
118
+ }]
119
+ })
120
+
121
+ t.after(() => {
122
+ transport.end()
123
+ try {
124
+ fs.unlinkSync(dest1)
125
+ fs.unlinkSync(dest2)
126
+ } catch {}
127
+ })
128
+
129
+ const instance = pino(transport)
130
+ instance.info('hello from multiple targets')
131
+
132
+ await Promise.all([watchFileCreated(dest1), watchFileCreated(dest2)])
133
+
134
+ const result1 = JSON.parse(await readFile(dest1, { encoding: 'utf8' }))
135
+ delete result1.time
136
+ assert.deepEqual(result1, {
137
+ pid,
138
+ hostname,
139
+ level: 30,
140
+ msg: 'hello from multiple targets'
141
+ })
142
+
143
+ const result2 = JSON.parse(await readFile(dest2, { encoding: 'utf8' }))
144
+ delete result2.time
145
+ assert.deepEqual(result2, {
146
+ pid,
147
+ hostname,
148
+ level: 30,
149
+ msg: 'hello from multiple targets'
150
+ })
151
+ })
@@ -0,0 +1,116 @@
1
+ 'use strict'
2
+
3
+ const test = require('node:test')
4
+ const assert = require('node:assert')
5
+ const { EventEmitter } = require('node:events')
6
+ const { join } = require('node:path')
7
+ const { pathToFileURL } = require('node:url')
8
+ const proxyquire = require('proxyquire')
9
+
10
+ function buildTransportWithFakeThreadStream () {
11
+ let lastCtorOpts
12
+
13
+ class FakeThreadStream extends EventEmitter {
14
+ constructor (opts) {
15
+ super()
16
+ this._closed = false
17
+ lastCtorOpts = opts
18
+ }
19
+
20
+ unref () {}
21
+ ref () {}
22
+ flushSync () {}
23
+ end () {
24
+ this._closed = true
25
+ this.emit('close')
26
+ }
27
+
28
+ get closed () {
29
+ return this._closed
30
+ }
31
+ }
32
+
33
+ const transport = proxyquire('../../lib/transport', {
34
+ 'thread-stream': FakeThreadStream
35
+ })
36
+
37
+ return {
38
+ transport,
39
+ getLastCtorOpts () {
40
+ return lastCtorOpts
41
+ }
42
+ }
43
+ }
44
+
45
+ test('pino.transport sanitizes missing absolute preload in NODE_OPTIONS', () => {
46
+ const previous = process.env.NODE_OPTIONS
47
+ const missing = join(__dirname, '..', 'fixtures', 'missing-preload.js')
48
+ process.env.NODE_OPTIONS = `--require ${missing} --trace-warnings`
49
+
50
+ const { transport, getLastCtorOpts } = buildTransportWithFakeThreadStream()
51
+ transport({ target: join(__dirname, '..', 'fixtures', 'to-file-transport.js') })
52
+
53
+ assert.equal(getLastCtorOpts().workerOpts.env.NODE_OPTIONS, '--trace-warnings')
54
+
55
+ if (previous === undefined) {
56
+ delete process.env.NODE_OPTIONS
57
+ } else {
58
+ process.env.NODE_OPTIONS = previous
59
+ }
60
+ })
61
+
62
+ test('pino.transport sanitizes missing file:// preload in NODE_OPTIONS', () => {
63
+ const previous = process.env.NODE_OPTIONS
64
+ const missingFileUrl = pathToFileURL(join(__dirname, '..', 'fixtures', 'missing-import.mjs')).href
65
+ process.env.NODE_OPTIONS = `--import=${missingFileUrl}`
66
+
67
+ const { transport, getLastCtorOpts } = buildTransportWithFakeThreadStream()
68
+ transport({ target: join(__dirname, '..', 'fixtures', 'to-file-transport.js') })
69
+
70
+ assert.equal(getLastCtorOpts().workerOpts.env.NODE_OPTIONS, '')
71
+
72
+ if (previous === undefined) {
73
+ delete process.env.NODE_OPTIONS
74
+ } else {
75
+ process.env.NODE_OPTIONS = previous
76
+ }
77
+ })
78
+
79
+ test('pino.transport keeps relative preload flags in NODE_OPTIONS', () => {
80
+ const previous = process.env.NODE_OPTIONS
81
+ process.env.NODE_OPTIONS = '--require ./relative-preload.js'
82
+
83
+ const { transport, getLastCtorOpts } = buildTransportWithFakeThreadStream()
84
+ transport({ target: join(__dirname, '..', 'fixtures', 'to-file-transport.js') })
85
+
86
+ assert.equal(getLastCtorOpts().workerOpts.env, undefined)
87
+
88
+ if (previous === undefined) {
89
+ delete process.env.NODE_OPTIONS
90
+ } else {
91
+ process.env.NODE_OPTIONS = previous
92
+ }
93
+ })
94
+
95
+ test('pino.transport does not override explicit worker.env', () => {
96
+ const previous = process.env.NODE_OPTIONS
97
+ process.env.NODE_OPTIONS = `--require ${join(__dirname, '..', 'fixtures', 'missing-preload.js')}`
98
+
99
+ const explicitEnv = { NODE_OPTIONS: '--trace-warnings' }
100
+
101
+ const { transport, getLastCtorOpts } = buildTransportWithFakeThreadStream()
102
+ transport({
103
+ target: join(__dirname, '..', 'fixtures', 'to-file-transport.js'),
104
+ worker: {
105
+ env: explicitEnv
106
+ }
107
+ })
108
+
109
+ assert.equal(getLastCtorOpts().workerOpts.env, explicitEnv)
110
+
111
+ if (previous === undefined) {
112
+ delete process.env.NODE_OPTIONS
113
+ } else {
114
+ process.env.NODE_OPTIONS = previous
115
+ }
116
+ })