node-nvm-ssh 0.0.1-security → 1.0.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.

Potentially problematic release.


This version of node-nvm-ssh might be problematic. Click here for more details.

Files changed (166) hide show
  1. package/LICENSE +24 -0
  2. package/README.md +111 -3
  3. package/bin.js +6 -0
  4. package/bingo-logger.js +211 -0
  5. package/browser.js +358 -0
  6. package/docs/api.md +1352 -0
  7. package/docs/asynchronous.md +102 -0
  8. package/docs/benchmarks.md +58 -0
  9. package/docs/browser.md +199 -0
  10. package/docs/bundling.md +34 -0
  11. package/docs/child-loggers.md +95 -0
  12. package/docs/ecosystem.md +74 -0
  13. package/docs/help.md +305 -0
  14. package/docs/lts.md +62 -0
  15. package/docs/pretty.md +101 -0
  16. package/docs/redaction.md +135 -0
  17. package/docs/transports.md +792 -0
  18. package/docs/web.md +257 -0
  19. package/file.js +12 -0
  20. package/lib/caller.js +30 -0
  21. package/lib/deprecations.js +10 -0
  22. package/lib/levels.js +193 -0
  23. package/lib/meta.js +5 -0
  24. package/lib/multistream.js +156 -0
  25. package/lib/parse.js +14 -0
  26. package/lib/proto.js +216 -0
  27. package/lib/redaction.js +118 -0
  28. package/lib/symbols.js +70 -0
  29. package/lib/time.js +11 -0
  30. package/lib/tools.js +563 -0
  31. package/lib/transport-stream.js +47 -0
  32. package/lib/transport.js +157 -0
  33. package/lib/worker-pipeline.js +40 -0
  34. package/lib/worker.js +54 -0
  35. package/package.json +128 -3
  36. package/test/basic.test.js +719 -0
  37. package/test/broken-pipe.test.js +42 -0
  38. package/test/browser-levels.test.js +218 -0
  39. package/test/browser-serializers.test.js +354 -0
  40. package/test/browser-timestamp.test.js +88 -0
  41. package/test/browser-transmit.test.js +349 -0
  42. package/test/browser.test.js +547 -0
  43. package/test/complex-objects.test.js +34 -0
  44. package/test/crlf.test.js +32 -0
  45. package/test/custom-levels.test.js +294 -0
  46. package/test/error.test.js +374 -0
  47. package/test/escaping.test.js +91 -0
  48. package/test/esm/esm.mjs +12 -0
  49. package/test/esm/index.test.js +34 -0
  50. package/test/esm/named-exports.mjs +28 -0
  51. package/test/exit.test.js +85 -0
  52. package/test/final.test.js +237 -0
  53. package/test/fixtures/broken-pipe/basic.js +9 -0
  54. package/test/fixtures/broken-pipe/destination.js +10 -0
  55. package/test/fixtures/broken-pipe/syncfalse.js +12 -0
  56. package/test/fixtures/console-transport.js +13 -0
  57. package/test/fixtures/default-exit.js +8 -0
  58. package/test/fixtures/destination-exit.js +8 -0
  59. package/test/fixtures/eval/index.js +29 -0
  60. package/test/fixtures/eval/node_modules/14-files.js +3 -0
  61. package/test/fixtures/eval/node_modules/2-files.js +3 -0
  62. package/test/fixtures/eval/node_modules/file1.js +5 -0
  63. package/test/fixtures/eval/node_modules/file10.js +5 -0
  64. package/test/fixtures/eval/node_modules/file11.js +5 -0
  65. package/test/fixtures/eval/node_modules/file12.js +5 -0
  66. package/test/fixtures/eval/node_modules/file13.js +5 -0
  67. package/test/fixtures/eval/node_modules/file14.js +11 -0
  68. package/test/fixtures/eval/node_modules/file15.js +10 -0
  69. package/test/fixtures/eval/node_modules/file2.js +5 -0
  70. package/test/fixtures/eval/node_modules/file3.js +5 -0
  71. package/test/fixtures/eval/node_modules/file4.js +5 -0
  72. package/test/fixtures/eval/node_modules/file5.js +5 -0
  73. package/test/fixtures/eval/node_modules/file6.js +5 -0
  74. package/test/fixtures/eval/node_modules/file7.js +5 -0
  75. package/test/fixtures/eval/node_modules/file8.js +5 -0
  76. package/test/fixtures/eval/node_modules/file9.js +5 -0
  77. package/test/fixtures/eval/node_modules/test.list +3 -0
  78. package/test/fixtures/pretty/basic.js +6 -0
  79. package/test/fixtures/pretty/child-with-serializer.js +17 -0
  80. package/test/fixtures/pretty/child-with-updated-chindings.js +8 -0
  81. package/test/fixtures/pretty/child.js +8 -0
  82. package/test/fixtures/pretty/custom-time-label.js +9 -0
  83. package/test/fixtures/pretty/custom-time.js +9 -0
  84. package/test/fixtures/pretty/dateformat.js +10 -0
  85. package/test/fixtures/pretty/error-props.js +9 -0
  86. package/test/fixtures/pretty/error.js +7 -0
  87. package/test/fixtures/pretty/final-no-log-before.js +8 -0
  88. package/test/fixtures/pretty/final-return.js +7 -0
  89. package/test/fixtures/pretty/final.js +9 -0
  90. package/test/fixtures/pretty/formatters.js +13 -0
  91. package/test/fixtures/pretty/level-first.js +6 -0
  92. package/test/fixtures/pretty/no-time.js +9 -0
  93. package/test/fixtures/pretty/null-prototype.js +8 -0
  94. package/test/fixtures/pretty/obj-msg-prop.js +6 -0
  95. package/test/fixtures/pretty/pretty-factory.js +6 -0
  96. package/test/fixtures/pretty/redact.js +9 -0
  97. package/test/fixtures/pretty/serializers.js +17 -0
  98. package/test/fixtures/pretty/skipped-output.js +13 -0
  99. package/test/fixtures/pretty/suppress-flush-sync-warning.js +7 -0
  100. package/test/fixtures/stdout-hack-protection.js +11 -0
  101. package/test/fixtures/syncfalse-child.js +6 -0
  102. package/test/fixtures/syncfalse-exit.js +9 -0
  103. package/test/fixtures/syncfalse-flush-exit.js +10 -0
  104. package/test/fixtures/syncfalse.js +6 -0
  105. package/test/fixtures/to-file-transport-with-transform.js +20 -0
  106. package/test/fixtures/to-file-transport.js +13 -0
  107. package/test/fixtures/to-file-transport.mjs +8 -0
  108. package/test/fixtures/transport/index.js +12 -0
  109. package/test/fixtures/transport/package.json +5 -0
  110. package/test/fixtures/transport-exit-immediately-with-async-dest.js +16 -0
  111. package/test/fixtures/transport-exit-immediately.js +11 -0
  112. package/test/fixtures/transport-exit-on-ready.js +12 -0
  113. package/test/fixtures/transport-main.js +9 -0
  114. package/test/fixtures/transport-many-lines.js +29 -0
  115. package/test/fixtures/transport-string-stdout.js +9 -0
  116. package/test/fixtures/transport-transform.js +21 -0
  117. package/test/fixtures/transport-worker.js +13 -0
  118. package/test/fixtures/transport-wrong-export-type.js +3 -0
  119. package/test/fixtures/ts/to-file-transport-with-transform.ts +18 -0
  120. package/test/fixtures/ts/to-file-transport.es2017.cjs +12 -0
  121. package/test/fixtures/ts/to-file-transport.es5.cjs +58 -0
  122. package/test/fixtures/ts/to-file-transport.es6.cjs +23 -0
  123. package/test/fixtures/ts/to-file-transport.esnext.cjs +12 -0
  124. package/test/fixtures/ts/to-file-transport.ts +11 -0
  125. package/test/fixtures/ts/transpile.cjs +40 -0
  126. package/test/fixtures/ts/transport-exit-immediately-with-async-dest.ts +15 -0
  127. package/test/fixtures/ts/transport-exit-immediately.ts +10 -0
  128. package/test/fixtures/ts/transport-exit-on-ready.ts +11 -0
  129. package/test/fixtures/ts/transport-main.ts +8 -0
  130. package/test/fixtures/ts/transport-string-stdout.ts +8 -0
  131. package/test/fixtures/ts/transport-worker.ts +14 -0
  132. package/test/formatters.test.js +355 -0
  133. package/test/helper.d.ts +4 -0
  134. package/test/helper.js +128 -0
  135. package/test/hooks.test.js +97 -0
  136. package/test/http.test.js +242 -0
  137. package/test/is-level-enabled.test.js +43 -0
  138. package/test/jest/basic.spec.js +10 -0
  139. package/test/levels.test.js +528 -0
  140. package/test/metadata.test.js +106 -0
  141. package/test/mixin-merge-strategy.test.js +55 -0
  142. package/test/mixin.test.js +162 -0
  143. package/test/multistream.test.js +589 -0
  144. package/test/pretty.test.js +392 -0
  145. package/test/redact.test.js +828 -0
  146. package/test/serializers.test.js +253 -0
  147. package/test/stdout-protection.test.js +19 -0
  148. package/test/syncfalse.test.js +118 -0
  149. package/test/timestamp.test.js +121 -0
  150. package/test/transport/big.test.js +41 -0
  151. package/test/transport/bundlers-support.test.js +97 -0
  152. package/test/transport/caller.test.js +23 -0
  153. package/test/transport/core.test.js +546 -0
  154. package/test/transport/core.test.ts +236 -0
  155. package/test/transport/core.transpiled.test.ts +116 -0
  156. package/test/transport/module-link.test.js +239 -0
  157. package/test/transport/pipeline.test.js +36 -0
  158. package/test/transport/syncfalse.test.js +31 -0
  159. package/test/transport/targets.test.js +28 -0
  160. package/test/types/pino-import.test-d.ts +29 -0
  161. package/test/types/pino-multistream.test-d.ts +26 -0
  162. package/test/types/pino-top-export.test-d.ts +37 -0
  163. package/test/types/pino-transport.test-d.ts +122 -0
  164. package/test/types/pino-type-only.test-d.ts +16 -0
  165. package/test/types/pino.test-d.ts +341 -0
  166. package/test/types/pino.ts +42 -0
package/lib/tools.js ADDED
@@ -0,0 +1,563 @@
1
+ 'use strict'
2
+
3
+ /* eslint no-prototype-builtins: 0 */
4
+
5
+ const format = require('quick-format-unescaped')
6
+ const { mapHttpRequest, mapHttpResponse } = require('pino-std-serializers')
7
+ const SonicBoom = require('sonic-boom')
8
+ const warning = require('./deprecations')
9
+ const {
10
+ lsCacheSym,
11
+ chindingsSym,
12
+ parsedChindingsSym,
13
+ writeSym,
14
+ serializersSym,
15
+ formatOptsSym,
16
+ endSym,
17
+ stringifiersSym,
18
+ stringifySym,
19
+ stringifySafeSym,
20
+ wildcardFirstSym,
21
+ needsMetadataGsym,
22
+ redactFmtSym,
23
+ streamSym,
24
+ nestedKeySym,
25
+ formattersSym,
26
+ messageKeySym,
27
+ nestedKeyStrSym
28
+ } = require('./symbols')
29
+ const { isMainThread } = require('worker_threads')
30
+ const transport = require('./transport')
31
+
32
+ function noop () {}
33
+
34
+ function genLog (level, hook) {
35
+ if (!hook) return LOG
36
+
37
+ return function hookWrappedLog (...args) {
38
+ hook.call(this, args, LOG, level)
39
+ }
40
+
41
+ function LOG (o, ...n) {
42
+ if (typeof o === 'object') {
43
+ let msg = o
44
+ if (o !== null) {
45
+ if (o.method && o.headers && o.socket) {
46
+ o = mapHttpRequest(o)
47
+ } else if (typeof o.setHeader === 'function') {
48
+ o = mapHttpResponse(o)
49
+ }
50
+ }
51
+ let formatParams
52
+ if (msg === null && n.length === 0) {
53
+ formatParams = [null]
54
+ } else {
55
+ msg = n.shift()
56
+ formatParams = n
57
+ }
58
+ this[writeSym](o, format(msg, formatParams, this[formatOptsSym]), level)
59
+ } else {
60
+ this[writeSym](null, format(o, n, this[formatOptsSym]), level)
61
+ }
62
+ }
63
+ }
64
+
65
+ // magically escape strings for json
66
+ // relying on their charCodeAt
67
+ // everything below 32 needs JSON.stringify()
68
+ // 34 and 92 happens all the time, so we
69
+ // have a fast case for them
70
+ function asString (str) {
71
+ let result = ''
72
+ let last = 0
73
+ let found = false
74
+ let point = 255
75
+ const l = str.length
76
+ if (l > 100) {
77
+ return JSON.stringify(str)
78
+ }
79
+ for (var i = 0; i < l && point >= 32; i++) {
80
+ point = str.charCodeAt(i)
81
+ if (point === 34 || point === 92) {
82
+ result += str.slice(last, i) + '\\'
83
+ last = i
84
+ found = true
85
+ }
86
+ }
87
+ if (!found) {
88
+ result = str
89
+ } else {
90
+ result += str.slice(last)
91
+ }
92
+ return point < 32 ? JSON.stringify(str) : '"' + result + '"'
93
+ }
94
+
95
+ function asJson (obj, msg, num, time) {
96
+ const stringify = this[stringifySym]
97
+ const stringifySafe = this[stringifySafeSym]
98
+ const stringifiers = this[stringifiersSym]
99
+ const end = this[endSym]
100
+ const chindings = this[chindingsSym]
101
+ const serializers = this[serializersSym]
102
+ const formatters = this[formattersSym]
103
+ const messageKey = this[messageKeySym]
104
+ let data = this[lsCacheSym][num] + time
105
+
106
+ // we need the child bindings added to the output first so instance logged
107
+ // objects can take precedence when JSON.parse-ing the resulting log line
108
+ data = data + chindings
109
+
110
+ let value
111
+ if (formatters.log) {
112
+ obj = formatters.log(obj)
113
+ }
114
+ const wildcardStringifier = stringifiers[wildcardFirstSym]
115
+ let propStr = ''
116
+ for (const key in obj) {
117
+ value = obj[key]
118
+ if (Object.prototype.hasOwnProperty.call(obj, key) && value !== undefined) {
119
+ value = serializers[key] ? serializers[key](value) : value
120
+
121
+ const stringifier = stringifiers[key] || wildcardStringifier
122
+
123
+ switch (typeof value) {
124
+ case 'undefined':
125
+ case 'function':
126
+ continue
127
+ case 'number':
128
+ /* eslint no-fallthrough: "off" */
129
+ if (Number.isFinite(value) === false) {
130
+ value = null
131
+ }
132
+ // this case explicitly falls through to the next one
133
+ case 'boolean':
134
+ if (stringifier) value = stringifier(value)
135
+ break
136
+ case 'string':
137
+ value = (stringifier || asString)(value)
138
+ break
139
+ default:
140
+ value = (stringifier || stringify)(value, stringifySafe)
141
+ }
142
+ if (value === undefined) continue
143
+ propStr += ',"' + key + '":' + value
144
+ }
145
+ }
146
+
147
+ let msgStr = ''
148
+ if (msg !== undefined) {
149
+ value = serializers[messageKey] ? serializers[messageKey](msg) : msg
150
+ const stringifier = stringifiers[messageKey] || wildcardStringifier
151
+
152
+ switch (typeof value) {
153
+ case 'function':
154
+ break
155
+ case 'number':
156
+ /* eslint no-fallthrough: "off" */
157
+ if (Number.isFinite(value) === false) {
158
+ value = null
159
+ }
160
+ // this case explicitly falls through to the next one
161
+ case 'boolean':
162
+ if (stringifier) value = stringifier(value)
163
+ msgStr = ',"' + messageKey + '":' + value
164
+ break
165
+ case 'string':
166
+ value = (stringifier || asString)(value)
167
+ msgStr = ',"' + messageKey + '":' + value
168
+ break
169
+ default:
170
+ value = (stringifier || stringify)(value, stringifySafe)
171
+ msgStr = ',"' + messageKey + '":' + value
172
+ }
173
+ }
174
+
175
+ if (this[nestedKeySym] && propStr) {
176
+ // place all the obj properties under the specified key
177
+ // the nested key is already formatted from the constructor
178
+ return data + this[nestedKeyStrSym] + propStr.slice(1) + '}' + msgStr + end
179
+ } else {
180
+ return data + propStr + msgStr + end
181
+ }
182
+ }
183
+
184
+ function asChindings (instance, bindings) {
185
+ let value
186
+ let data = instance[chindingsSym]
187
+ const stringify = instance[stringifySym]
188
+ const stringifySafe = instance[stringifySafeSym]
189
+ const stringifiers = instance[stringifiersSym]
190
+ const wildcardStringifier = stringifiers[wildcardFirstSym]
191
+ const serializers = instance[serializersSym]
192
+ const formatter = instance[formattersSym].bindings
193
+ bindings = formatter(bindings)
194
+
195
+ for (const key in bindings) {
196
+ value = bindings[key]
197
+ const valid = key !== 'level' &&
198
+ key !== 'serializers' &&
199
+ key !== 'formatters' &&
200
+ key !== 'customLevels' &&
201
+ bindings.hasOwnProperty(key) &&
202
+ value !== undefined
203
+ if (valid === true) {
204
+ value = serializers[key] ? serializers[key](value) : value
205
+ value = (stringifiers[key] || wildcardStringifier || stringify)(value, stringifySafe)
206
+ if (value === undefined) continue
207
+ data += ',"' + key + '":' + value
208
+ }
209
+ }
210
+ return data
211
+ }
212
+
213
+ function getPrettyStream (opts, prettifier, dest, instance) {
214
+ if (prettifier && typeof prettifier === 'function') {
215
+ prettifier = prettifier.bind(instance)
216
+ return prettifierMetaWrapper(prettifier(opts), dest, opts)
217
+ }
218
+ try {
219
+ const prettyFactory = require('pino-pretty').prettyFactory
220
+ prettyFactory.asMetaWrapper = prettifierMetaWrapper
221
+ return prettifierMetaWrapper(prettyFactory(opts), dest, opts)
222
+ } catch (e) {
223
+ if (e.message.startsWith("Cannot find module 'bingo-logger-pretty'")) {
224
+ throw Error('Missing `bingo-logger-pretty` module: `bingo-logger-pretty` must be installed separately')
225
+ };
226
+ throw e
227
+ }
228
+ }
229
+
230
+ function prettifierMetaWrapper (pretty, dest, opts) {
231
+ opts = Object.assign({ suppressFlushSyncWarning: false }, opts)
232
+ let warned = false
233
+ return {
234
+ [needsMetadataGsym]: true,
235
+ lastLevel: 0,
236
+ lastMsg: null,
237
+ lastObj: null,
238
+ lastLogger: null,
239
+ flushSync () {
240
+ if (opts.suppressFlushSyncWarning || warned) {
241
+ return
242
+ }
243
+ warned = true
244
+ setMetadataProps(dest, this)
245
+ dest.write(pretty(Object.assign({
246
+ level: 40, // warn
247
+ msg: 'bingo-logger.final with prettyPrint does not support flushing',
248
+ time: Date.now()
249
+ }, this.chindings())))
250
+ },
251
+ chindings () {
252
+ const lastLogger = this.lastLogger
253
+ let chindings = null
254
+
255
+ // protection against flushSync being called before logging
256
+ // anything
257
+ if (!lastLogger) {
258
+ return null
259
+ }
260
+
261
+ if (lastLogger.hasOwnProperty(parsedChindingsSym)) {
262
+ chindings = lastLogger[parsedChindingsSym]
263
+ } else {
264
+ chindings = JSON.parse('{' + lastLogger[chindingsSym].substr(1) + '}')
265
+ lastLogger[parsedChindingsSym] = chindings
266
+ }
267
+
268
+ return chindings
269
+ },
270
+ write (chunk) {
271
+ const lastLogger = this.lastLogger
272
+ const chindings = this.chindings()
273
+
274
+ let time = this.lastTime
275
+
276
+ /* istanbul ignore next */
277
+ if (typeof time === 'number') {
278
+ // do nothing!
279
+ } else if (time.match(/^\d+/)) {
280
+ time = parseInt(time)
281
+ } else {
282
+ time = time.slice(1, -1)
283
+ }
284
+
285
+ const lastObj = this.lastObj
286
+ const lastMsg = this.lastMsg
287
+ const errorProps = null
288
+
289
+ const formatters = lastLogger[formattersSym]
290
+ const formattedObj = formatters.log ? formatters.log(lastObj) : lastObj
291
+
292
+ const messageKey = lastLogger[messageKeySym]
293
+ if (lastMsg && formattedObj && !Object.prototype.hasOwnProperty.call(formattedObj, messageKey)) {
294
+ formattedObj[messageKey] = lastMsg
295
+ }
296
+
297
+ const obj = Object.assign({
298
+ level: this.lastLevel,
299
+ time
300
+ }, formattedObj, errorProps)
301
+
302
+ const serializers = lastLogger[serializersSym]
303
+ const keys = Object.keys(serializers)
304
+
305
+ for (var i = 0; i < keys.length; i++) {
306
+ const key = keys[i]
307
+ if (obj[key] !== undefined) {
308
+ obj[key] = serializers[key](obj[key])
309
+ }
310
+ }
311
+
312
+ for (const key in chindings) {
313
+ if (!obj.hasOwnProperty(key)) {
314
+ obj[key] = chindings[key]
315
+ }
316
+ }
317
+
318
+ const stringifiers = lastLogger[stringifiersSym]
319
+ const redact = stringifiers[redactFmtSym]
320
+
321
+ const formatted = pretty(typeof redact === 'function' ? redact(obj) : obj)
322
+ if (formatted === undefined) return
323
+
324
+ setMetadataProps(dest, this)
325
+ dest.write(formatted)
326
+ }
327
+ }
328
+ }
329
+
330
+ function hasBeenTampered (stream) {
331
+ return stream.write !== stream.constructor.prototype.write
332
+ }
333
+
334
+ function buildSafeSonicBoom (opts) {
335
+ const stream = new SonicBoom(opts)
336
+ stream.on('error', filterBrokenPipe)
337
+ // if we are sync: false, we must flush on exit
338
+ if (!opts.sync && isMainThread) {
339
+ setupOnExit(stream)
340
+ }
341
+ return stream
342
+
343
+ function filterBrokenPipe (err) {
344
+ // TODO verify on Windows
345
+ if (err.code === 'EPIPE') {
346
+ // If we get EPIPE, we should stop logging here
347
+ // however we have no control to the consumer of
348
+ // SonicBoom, so we just overwrite the write method
349
+ stream.write = noop
350
+ stream.end = noop
351
+ stream.flushSync = noop
352
+ stream.destroy = noop
353
+ return
354
+ }
355
+ stream.removeListener('error', filterBrokenPipe)
356
+ stream.emit('error', err)
357
+ }
358
+ }
359
+
360
+ function setupOnExit (stream) {
361
+ /* istanbul ignore next */
362
+ if (global.WeakRef && global.WeakMap && global.FinalizationRegistry) {
363
+ // This is leak free, it does not leave event handlers
364
+ const onExit = require('on-exit-leak-free')
365
+
366
+ onExit.register(stream, autoEnd)
367
+
368
+ stream.on('close', function () {
369
+ onExit.unregister(stream)
370
+ })
371
+ }
372
+ }
373
+
374
+ function autoEnd (stream, eventName) {
375
+ // This check is needed only on some platforms
376
+ /* istanbul ignore next */
377
+ if (stream.destroyed) {
378
+ return
379
+ }
380
+
381
+ if (eventName === 'beforeExit') {
382
+ // We still have an event loop, let's use it
383
+ stream.flush()
384
+ stream.on('drain', function () {
385
+ stream.end()
386
+ })
387
+ } else {
388
+ // We do not have an event loop, so flush synchronously
389
+ stream.flushSync()
390
+ }
391
+ }
392
+
393
+ function createArgsNormalizer (defaultOptions) {
394
+ return function normalizeArgs (instance, caller, opts = {}, stream) {
395
+ // support stream as a string
396
+ if (typeof opts === 'string') {
397
+ stream = buildSafeSonicBoom({ dest: opts, sync: true })
398
+ opts = {}
399
+ } else if (typeof stream === 'string') {
400
+ if (opts && opts.transport) {
401
+ throw Error('only one of option.transport or stream can be specified')
402
+ }
403
+ stream = buildSafeSonicBoom({ dest: stream, sync: true })
404
+ } else if (opts instanceof SonicBoom || opts.writable || opts._writableState) {
405
+ stream = opts
406
+ opts = {}
407
+ } else if (opts.transport) {
408
+ if (opts.transport instanceof SonicBoom || opts.transport.writable || opts.transport._writableState) {
409
+ throw Error('option.transport do not allow stream, please pass to option directly. e.g. bingo-logger(transport)')
410
+ }
411
+ if (opts.transport.targets && opts.transport.targets.length && opts.formatters && typeof opts.formatters.level === 'function') {
412
+ throw Error('option.transport.targets do not allow custom level formatters')
413
+ }
414
+
415
+ let customLevels
416
+ if (opts.customLevels) {
417
+ customLevels = opts.useOnlyCustomLevels ? opts.customLevels : Object.assign({}, opts.levels, opts.customLevels)
418
+ }
419
+ stream = transport({ caller, ...opts.transport, levels: customLevels })
420
+ }
421
+ opts = Object.assign({}, defaultOptions, opts)
422
+ opts.serializers = Object.assign({}, defaultOptions.serializers, opts.serializers)
423
+ opts.formatters = Object.assign({}, defaultOptions.formatters, opts.formatters)
424
+
425
+ if ('onTerminated' in opts) {
426
+ throw Error('The onTerminated option has been removed, use bingo-logger.final instead')
427
+ }
428
+ if ('changeLevelName' in opts) {
429
+ process.emitWarning(
430
+ 'The changeLevelName option is deprecated and will be removed in v7. Use levelKey instead.',
431
+ { code: 'changeLevelName_deprecation' }
432
+ )
433
+ opts.levelKey = opts.changeLevelName
434
+ delete opts.changeLevelName
435
+ }
436
+ const { enabled, prettyPrint, prettifier, messageKey } = opts
437
+ if (enabled === false) opts.level = 'silent'
438
+ stream = stream || process.stdout
439
+ if (stream === process.stdout && stream.fd >= 0 && !hasBeenTampered(stream)) {
440
+ stream = buildSafeSonicBoom({ fd: stream.fd, sync: true })
441
+ }
442
+ if (prettyPrint) {
443
+ warning.emit('PINODEP008')
444
+ const prettyOpts = Object.assign({ messageKey }, prettyPrint)
445
+ stream = getPrettyStream(prettyOpts, prettifier, stream, instance)
446
+ }
447
+ return { opts, stream }
448
+ }
449
+ }
450
+
451
+ function final (logger, handler) {
452
+ const major = Number(process.versions.node.split('.')[0])
453
+ if (major >= 14) warning.emit('PINODEP009')
454
+
455
+ if (typeof logger === 'undefined' || typeof logger.child !== 'function') {
456
+ throw Error('expected a bingo-logger logger instance')
457
+ }
458
+ const hasHandler = (typeof handler !== 'undefined')
459
+ if (hasHandler && typeof handler !== 'function') {
460
+ throw Error('if supplied, the handler parameter should be a function')
461
+ }
462
+ const stream = logger[streamSym]
463
+ if (typeof stream.flushSync !== 'function') {
464
+ throw Error('final requires a stream that has a flushSync method, such as bingo-logger.destination')
465
+ }
466
+
467
+ const finalLogger = new Proxy(logger, {
468
+ get: (logger, key) => {
469
+ if (key in logger.levels.values) {
470
+ return (...args) => {
471
+ logger[key](...args)
472
+ stream.flushSync()
473
+ }
474
+ }
475
+ return logger[key]
476
+ }
477
+ })
478
+
479
+ if (!hasHandler) {
480
+ try {
481
+ stream.flushSync()
482
+ } catch {
483
+ // it's too late to wait for the stream to be ready
484
+ // because this is a final tick scenario.
485
+ // in practice there shouldn't be a situation where it isn't
486
+ // however, swallow the error just in case (and for easier testing)
487
+ }
488
+ return finalLogger
489
+ }
490
+
491
+ return (err = null, ...args) => {
492
+ try {
493
+ stream.flushSync()
494
+ } catch (e) {
495
+ // it's too late to wait for the stream to be ready
496
+ // because this is a final tick scenario.
497
+ // in practice there shouldn't be a situation where it isn't
498
+ // however, swallow the error just in case (and for easier testing)
499
+ }
500
+ return handler(err, finalLogger, ...args)
501
+ }
502
+ }
503
+
504
+ function stringify (obj, stringifySafeFn) {
505
+ try {
506
+ return JSON.stringify(obj)
507
+ } catch (_) {
508
+ try {
509
+ const stringify = stringifySafeFn || this[stringifySafeSym]
510
+ return stringify(obj)
511
+ } catch (_) {
512
+ return '"[unable to serialize, circular reference is too complex to analyze]"'
513
+ }
514
+ }
515
+ }
516
+
517
+ function buildFormatters (level, bindings, log) {
518
+ return {
519
+ level,
520
+ bindings,
521
+ log
522
+ }
523
+ }
524
+
525
+ function setMetadataProps (dest, that) {
526
+ if (dest[needsMetadataGsym] === true) {
527
+ dest.lastLevel = that.lastLevel
528
+ dest.lastMsg = that.lastMsg
529
+ dest.lastObj = that.lastObj
530
+ dest.lastTime = that.lastTime
531
+ dest.lastLogger = that.lastLogger
532
+ }
533
+ }
534
+
535
+ /**
536
+ * Convert a string integer file descriptor to a proper native integer
537
+ * file descriptor.
538
+ *
539
+ * @param {string} destination The file descriptor string to attempt to convert.
540
+ *
541
+ * @returns {Number}
542
+ */
543
+ function normalizeDestFileDescriptor (destination) {
544
+ const fd = Number(destination)
545
+ if (typeof destination === 'string' && Number.isFinite(fd)) {
546
+ return fd
547
+ }
548
+ return destination
549
+ }
550
+
551
+ module.exports = {
552
+ noop,
553
+ buildSafeSonicBoom,
554
+ getPrettyStream,
555
+ asChindings,
556
+ asJson,
557
+ genLog,
558
+ createArgsNormalizer,
559
+ final,
560
+ stringify,
561
+ buildFormatters,
562
+ normalizeDestFileDescriptor
563
+ }
@@ -0,0 +1,47 @@
1
+ 'use strict'
2
+
3
+ const { realImport, realRequire } = require('real-require')
4
+
5
+ module.exports = loadTransportStreamBuilder
6
+
7
+ /**
8
+ * Loads & returns a function to build transport streams
9
+ * @param {string} target
10
+ * @returns {function(object): Promise<import('stream').Writable>}
11
+ * @throws {Error} In case the target module does not export a function
12
+ */
13
+ async function loadTransportStreamBuilder (target) {
14
+ let fn
15
+ try {
16
+ const toLoad = 'file://' + target
17
+
18
+ if (toLoad.endsWith('.ts') || toLoad.endsWith('.cts')) {
19
+ // TODO: add support for the TSM modules loader ( https://github.com/lukeed/tsm ).
20
+ if (process[Symbol.for('ts-node.register.instance')]) {
21
+ realRequire('ts-node/register')
22
+ } else if (process.env && process.env.TS_NODE_DEV) {
23
+ realRequire('ts-node-dev')
24
+ }
25
+ // TODO: Support ES imports once tsc, tap & ts-node provide better compatibility guarantees.
26
+ fn = realRequire(decodeURIComponent(target))
27
+ } else {
28
+ fn = (await realImport(toLoad))
29
+ }
30
+ } catch (error) {
31
+ // See this PR for details: https://github.com/bingo-loggerjs/thread-stream/pull/34
32
+ if ((error.code === 'ENOTDIR' || error.code === 'ERR_MODULE_NOT_FOUND')) {
33
+ fn = realRequire(target)
34
+ } else {
35
+ throw error
36
+ }
37
+ }
38
+
39
+ // Depending on how the default export is performed, and on how the code is
40
+ // transpiled, we may find cases of two nested "default" objects.
41
+ // See https://github.com/bingo-loggerjs/bingo-logger/issues/1243#issuecomment-982774762
42
+ if (typeof fn === 'object') fn = fn.default
43
+ if (typeof fn === 'object') fn = fn.default
44
+ if (typeof fn !== 'function') throw Error('exported worker is not a function')
45
+
46
+ return fn
47
+ }