vite-plugin-purify 0.0.1-security → 2.3.4
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 vite-plugin-purify might be problematic. Click here for more details.
- package/.eslintignore +2 -0
- package/.eslintrc +8 -0
- package/.github/dependabot.yml +13 -0
- package/.github/workflows/bench.yml +61 -0
- package/.github/workflows/ci.yml +88 -0
- package/.github/workflows/lock-threads.yml +30 -0
- package/.github/workflows/target-main.yml +23 -0
- package/.nojekyll +0 -0
- package/.prettierignore +1 -0
- package/.taprc.yaml +8 -0
- package/CNAME +1 -0
- package/CONTRIBUTING.md +30 -0
- package/LICENSE +21 -0
- package/README.md +159 -3
- package/SECURITY.md +68 -0
- package/benchmarks/basic.bench.js +95 -0
- package/benchmarks/child-child.bench.js +52 -0
- package/benchmarks/child-creation.bench.js +73 -0
- package/benchmarks/child.bench.js +62 -0
- package/benchmarks/deep-object.bench.js +88 -0
- package/benchmarks/formatters.bench.js +50 -0
- package/benchmarks/internal/custom-levels.js +67 -0
- package/benchmarks/internal/just-pino-heavy.bench.js +76 -0
- package/benchmarks/internal/just-pino.bench.js +182 -0
- package/benchmarks/internal/parent-vs-child.bench.js +75 -0
- package/benchmarks/internal/redact.bench.js +86 -0
- package/benchmarks/long-string.bench.js +81 -0
- package/benchmarks/multi-arg.bench.js +193 -0
- package/benchmarks/multistream.js +98 -0
- package/benchmarks/object.bench.js +82 -0
- package/benchmarks/utils/generate-benchmark-doc.js +36 -0
- package/benchmarks/utils/runbench.js +138 -0
- package/benchmarks/utils/wrap-log-level.js +55 -0
- package/bin.js +6 -0
- package/browser.js +484 -0
- package/build/sync-version.js +10 -0
- package/docs/api.md +1487 -0
- package/docs/asynchronous.md +40 -0
- package/docs/benchmarks.md +55 -0
- package/docs/browser.md +227 -0
- package/docs/bundling.md +40 -0
- package/docs/child-loggers.md +95 -0
- package/docs/ecosystem.md +84 -0
- package/docs/help.md +345 -0
- package/docs/lts.md +64 -0
- package/docs/pretty.md +35 -0
- package/docs/redaction.md +135 -0
- package/docs/transports.md +1238 -0
- package/docs/web.md +269 -0
- package/docsify/sidebar.md +26 -0
- package/examples/basic.js +43 -0
- package/examples/transport.js +68 -0
- package/favicon-16x16.png +0 -0
- package/favicon-32x32.png +0 -0
- package/favicon.ico +0 -0
- package/file.js +12 -0
- package/inc-version.sh +42 -0
- package/index.html +55 -0
- package/lib/caller.js +30 -0
- package/lib/constants.js +28 -0
- package/lib/deprecations.js +8 -0
- package/lib/levels.js +241 -0
- package/lib/meta.js +3 -0
- package/lib/multistream.js +188 -0
- package/lib/proto.js +234 -0
- package/lib/redaction.js +118 -0
- package/lib/symbols.js +74 -0
- package/lib/time.js +11 -0
- package/lib/tools.js +394 -0
- package/lib/transport-stream.js +56 -0
- package/lib/transport.js +167 -0
- package/lib/worker.js +194 -0
- package/lib/writer.js +42 -0
- package/logs-buffer - Shortcut.lnk +0 -0
- package/package.json +117 -3
- package/pino-banner.png +0 -0
- package/pino-logo-hire.png +0 -0
- package/pino-tree.png +0 -0
- package/pino.d.ts +889 -0
- package/pino.js +236 -0
- package/pretty-demo.png +0 -0
- package/test/basic.test.js +874 -0
- package/test/broken-pipe.test.js +57 -0
- package/test/browser-child.test.js +132 -0
- package/test/browser-disabled.test.js +87 -0
- package/test/browser-early-console-freeze.test.js +12 -0
- package/test/browser-levels.test.js +241 -0
- package/test/browser-serializers.test.js +352 -0
- package/test/browser-timestamp.test.js +88 -0
- package/test/browser-transmit.test.js +417 -0
- package/test/browser.test.js +659 -0
- package/test/complex-objects.test.js +34 -0
- package/test/crlf.test.js +32 -0
- package/test/custom-levels.test.js +253 -0
- package/test/error.test.js +398 -0
- package/test/errorKey.test.js +34 -0
- package/test/escaping.test.js +91 -0
- package/test/esm/esm.mjs +12 -0
- package/test/esm/index.test.js +34 -0
- package/test/esm/named-exports.mjs +27 -0
- package/test/exit.test.js +77 -0
- package/test/fixtures/broken-pipe/basic.js +9 -0
- package/test/fixtures/broken-pipe/destination.js +10 -0
- package/test/fixtures/broken-pipe/syncfalse.js +12 -0
- package/test/fixtures/console-transport.js +13 -0
- package/test/fixtures/default-exit.js +8 -0
- package/test/fixtures/destination-exit.js +8 -0
- package/test/fixtures/eval/index.js +13 -0
- package/test/fixtures/eval/node_modules/14-files.js +3 -0
- package/test/fixtures/eval/node_modules/2-files.js +3 -0
- package/test/fixtures/eval/node_modules/file1.js +5 -0
- package/test/fixtures/eval/node_modules/file10.js +5 -0
- package/test/fixtures/eval/node_modules/file11.js +5 -0
- package/test/fixtures/eval/node_modules/file12.js +5 -0
- package/test/fixtures/eval/node_modules/file13.js +5 -0
- package/test/fixtures/eval/node_modules/file14.js +11 -0
- package/test/fixtures/eval/node_modules/file2.js +5 -0
- package/test/fixtures/eval/node_modules/file3.js +5 -0
- package/test/fixtures/eval/node_modules/file4.js +5 -0
- package/test/fixtures/eval/node_modules/file5.js +5 -0
- package/test/fixtures/eval/node_modules/file6.js +5 -0
- package/test/fixtures/eval/node_modules/file7.js +5 -0
- package/test/fixtures/eval/node_modules/file8.js +5 -0
- package/test/fixtures/eval/node_modules/file9.js +5 -0
- package/test/fixtures/noop-transport.js +10 -0
- package/test/fixtures/pretty/null-prototype.js +8 -0
- package/test/fixtures/stdout-hack-protection.js +11 -0
- package/test/fixtures/syncfalse-child.js +6 -0
- package/test/fixtures/syncfalse-exit.js +9 -0
- package/test/fixtures/syncfalse-flush-exit.js +10 -0
- package/test/fixtures/syncfalse.js +6 -0
- package/test/fixtures/syntax-error-esm.mjs +2 -0
- package/test/fixtures/to-file-transport-with-transform.js +20 -0
- package/test/fixtures/to-file-transport.js +13 -0
- package/test/fixtures/to-file-transport.mjs +8 -0
- package/test/fixtures/transport/index.js +12 -0
- package/test/fixtures/transport/package.json +5 -0
- package/test/fixtures/transport-exit-immediately-with-async-dest.js +16 -0
- package/test/fixtures/transport-exit-immediately.js +11 -0
- package/test/fixtures/transport-exit-on-ready.js +12 -0
- package/test/fixtures/transport-main.js +9 -0
- package/test/fixtures/transport-many-lines.js +29 -0
- package/test/fixtures/transport-string-stdout.js +9 -0
- package/test/fixtures/transport-transform.js +21 -0
- package/test/fixtures/transport-uses-pino-config.js +33 -0
- package/test/fixtures/transport-with-on-exit.js +12 -0
- package/test/fixtures/transport-worker-data.js +19 -0
- package/test/fixtures/transport-worker.js +15 -0
- package/test/fixtures/transport-wrong-export-type.js +3 -0
- package/test/fixtures/ts/to-file-transport-with-transform.ts +18 -0
- package/test/fixtures/ts/to-file-transport.ts +11 -0
- package/test/fixtures/ts/transpile.cjs +36 -0
- package/test/fixtures/ts/transport-exit-immediately-with-async-dest.ts +15 -0
- package/test/fixtures/ts/transport-exit-immediately.ts +10 -0
- package/test/fixtures/ts/transport-exit-on-ready.ts +11 -0
- package/test/fixtures/ts/transport-main.ts +8 -0
- package/test/fixtures/ts/transport-string-stdout.ts +8 -0
- package/test/fixtures/ts/transport-worker.ts +14 -0
- package/test/formatters.test.js +355 -0
- package/test/helper.d.ts +4 -0
- package/test/helper.js +128 -0
- package/test/hooks.test.js +118 -0
- package/test/http.test.js +242 -0
- package/test/internals/version.test.js +15 -0
- package/test/is-level-enabled.test.js +185 -0
- package/test/jest/basic.spec.js +10 -0
- package/test/levels.test.js +772 -0
- package/test/metadata.test.js +106 -0
- package/test/mixin-merge-strategy.test.js +55 -0
- package/test/mixin.test.js +218 -0
- package/test/multistream.test.js +673 -0
- package/test/pkg/index.js +46 -0
- package/test/pkg/pkg.config.json +17 -0
- package/test/pkg/pkg.test.js +56 -0
- package/test/redact.test.js +847 -0
- package/test/serializers.test.js +253 -0
- package/test/stdout-protection.test.js +39 -0
- package/test/syncfalse.test.js +188 -0
- package/test/timestamp.test.js +121 -0
- package/test/transport/big.test.js +43 -0
- package/test/transport/bundlers-support.test.js +97 -0
- package/test/transport/caller.test.js +23 -0
- package/test/transport/core.test.js +644 -0
- package/test/transport/core.test.ts +236 -0
- package/test/transport/core.transpiled.test.ts +112 -0
- package/test/transport/module-link.test.js +239 -0
- package/test/transport/pipeline.test.js +135 -0
- package/test/transport/repl.test.js +14 -0
- package/test/transport/syncTrue.test.js +55 -0
- package/test/transport/syncfalse.test.js +68 -0
- package/test/transport/targets.test.js +44 -0
- package/test/transport/uses-pino-config.test.js +167 -0
- package/test/transport-stream.test.js +26 -0
- package/test/types/pino-import.test-d.ts +29 -0
- package/test/types/pino-multistream.test-d.ts +28 -0
- package/test/types/pino-top-export.test-d.ts +35 -0
- package/test/types/pino-transport.test-d.ts +145 -0
- package/test/types/pino-type-only.test-d.ts +64 -0
- package/test/types/pino.test-d.ts +468 -0
- package/test/types/pino.ts +78 -0
- package/tsconfig.json +14 -0
package/lib/redaction.js
ADDED
@@ -0,0 +1,118 @@
|
|
1
|
+
'use strict'
|
2
|
+
|
3
|
+
const fastRedact = require('fast-redact')
|
4
|
+
const { redactFmtSym, wildcardFirstSym } = require('./symbols')
|
5
|
+
const { rx, validator } = fastRedact
|
6
|
+
|
7
|
+
const validate = validator({
|
8
|
+
ERR_PATHS_MUST_BE_STRINGS: () => 'pino – redacted paths must be strings',
|
9
|
+
ERR_INVALID_PATH: (s) => `pino – redact paths array contains an invalid path (${s})`
|
10
|
+
})
|
11
|
+
|
12
|
+
const CENSOR = '[Redacted]'
|
13
|
+
const strict = false // TODO should this be configurable?
|
14
|
+
|
15
|
+
function redaction (opts, serialize) {
|
16
|
+
const { paths, censor } = handle(opts)
|
17
|
+
|
18
|
+
const shape = paths.reduce((o, str) => {
|
19
|
+
rx.lastIndex = 0
|
20
|
+
const first = rx.exec(str)
|
21
|
+
const next = rx.exec(str)
|
22
|
+
|
23
|
+
// ns is the top-level path segment, brackets + quoting removed.
|
24
|
+
let ns = first[1] !== undefined
|
25
|
+
? first[1].replace(/^(?:"|'|`)(.*)(?:"|'|`)$/, '$1')
|
26
|
+
: first[0]
|
27
|
+
|
28
|
+
if (ns === '*') {
|
29
|
+
ns = wildcardFirstSym
|
30
|
+
}
|
31
|
+
|
32
|
+
// top level key:
|
33
|
+
if (next === null) {
|
34
|
+
o[ns] = null
|
35
|
+
return o
|
36
|
+
}
|
37
|
+
|
38
|
+
// path with at least two segments:
|
39
|
+
// if ns is already redacted at the top level, ignore lower level redactions
|
40
|
+
if (o[ns] === null) {
|
41
|
+
return o
|
42
|
+
}
|
43
|
+
|
44
|
+
const { index } = next
|
45
|
+
const nextPath = `${str.substr(index, str.length - 1)}`
|
46
|
+
|
47
|
+
o[ns] = o[ns] || []
|
48
|
+
|
49
|
+
// shape is a mix of paths beginning with literal values and wildcard
|
50
|
+
// paths [ "a.b.c", "*.b.z" ] should reduce to a shape of
|
51
|
+
// { "a": [ "b.c", "b.z" ], *: [ "b.z" ] }
|
52
|
+
// note: "b.z" is in both "a" and * arrays because "a" matches the wildcard.
|
53
|
+
// (* entry has wildcardFirstSym as key)
|
54
|
+
if (ns !== wildcardFirstSym && o[ns].length === 0) {
|
55
|
+
// first time ns's get all '*' redactions so far
|
56
|
+
o[ns].push(...(o[wildcardFirstSym] || []))
|
57
|
+
}
|
58
|
+
|
59
|
+
if (ns === wildcardFirstSym) {
|
60
|
+
// new * path gets added to all previously registered literal ns's.
|
61
|
+
Object.keys(o).forEach(function (k) {
|
62
|
+
if (o[k]) {
|
63
|
+
o[k].push(nextPath)
|
64
|
+
}
|
65
|
+
})
|
66
|
+
}
|
67
|
+
|
68
|
+
o[ns].push(nextPath)
|
69
|
+
return o
|
70
|
+
}, {})
|
71
|
+
|
72
|
+
// the redactor assigned to the format symbol key
|
73
|
+
// provides top level redaction for instances where
|
74
|
+
// an object is interpolated into the msg string
|
75
|
+
const result = {
|
76
|
+
[redactFmtSym]: fastRedact({ paths, censor, serialize, strict })
|
77
|
+
}
|
78
|
+
|
79
|
+
const topCensor = (...args) => {
|
80
|
+
return typeof censor === 'function' ? serialize(censor(...args)) : serialize(censor)
|
81
|
+
}
|
82
|
+
|
83
|
+
return [...Object.keys(shape), ...Object.getOwnPropertySymbols(shape)].reduce((o, k) => {
|
84
|
+
// top level key:
|
85
|
+
if (shape[k] === null) {
|
86
|
+
o[k] = (value) => topCensor(value, [k])
|
87
|
+
} else {
|
88
|
+
const wrappedCensor = typeof censor === 'function'
|
89
|
+
? (value, path) => {
|
90
|
+
return censor(value, [k, ...path])
|
91
|
+
}
|
92
|
+
: censor
|
93
|
+
o[k] = fastRedact({
|
94
|
+
paths: shape[k],
|
95
|
+
censor: wrappedCensor,
|
96
|
+
serialize,
|
97
|
+
strict
|
98
|
+
})
|
99
|
+
}
|
100
|
+
return o
|
101
|
+
}, result)
|
102
|
+
}
|
103
|
+
|
104
|
+
function handle (opts) {
|
105
|
+
if (Array.isArray(opts)) {
|
106
|
+
opts = { paths: opts, censor: CENSOR }
|
107
|
+
validate(opts)
|
108
|
+
return opts
|
109
|
+
}
|
110
|
+
let { paths, censor = CENSOR, remove } = opts
|
111
|
+
if (Array.isArray(paths) === false) { throw Error('pino – redact must contain an array of strings') }
|
112
|
+
if (remove === true) censor = undefined
|
113
|
+
validate({ paths, censor })
|
114
|
+
|
115
|
+
return { paths, censor }
|
116
|
+
}
|
117
|
+
|
118
|
+
module.exports = redaction
|
package/lib/symbols.js
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
'use strict'
|
2
|
+
|
3
|
+
const setLevelSym = Symbol('pino.setLevel')
|
4
|
+
const getLevelSym = Symbol('pino.getLevel')
|
5
|
+
const levelValSym = Symbol('pino.levelVal')
|
6
|
+
const levelCompSym = Symbol('pino.levelComp')
|
7
|
+
const useLevelLabelsSym = Symbol('pino.useLevelLabels')
|
8
|
+
const useOnlyCustomLevelsSym = Symbol('pino.useOnlyCustomLevels')
|
9
|
+
const mixinSym = Symbol('pino.mixin')
|
10
|
+
|
11
|
+
const lsCacheSym = Symbol('pino.lsCache')
|
12
|
+
const chindingsSym = Symbol('pino.chindings')
|
13
|
+
|
14
|
+
const asJsonSym = Symbol('pino.asJson')
|
15
|
+
const writeSym = Symbol('pino.write')
|
16
|
+
const redactFmtSym = Symbol('pino.redactFmt')
|
17
|
+
|
18
|
+
const timeSym = Symbol('pino.time')
|
19
|
+
const timeSliceIndexSym = Symbol('pino.timeSliceIndex')
|
20
|
+
const streamSym = Symbol('pino.stream')
|
21
|
+
const stringifySym = Symbol('pino.stringify')
|
22
|
+
const stringifySafeSym = Symbol('pino.stringifySafe')
|
23
|
+
const stringifiersSym = Symbol('pino.stringifiers')
|
24
|
+
const endSym = Symbol('pino.end')
|
25
|
+
const formatOptsSym = Symbol('pino.formatOpts')
|
26
|
+
const messageKeySym = Symbol('pino.messageKey')
|
27
|
+
const errorKeySym = Symbol('pino.errorKey')
|
28
|
+
const nestedKeySym = Symbol('pino.nestedKey')
|
29
|
+
const nestedKeyStrSym = Symbol('pino.nestedKeyStr')
|
30
|
+
const mixinMergeStrategySym = Symbol('pino.mixinMergeStrategy')
|
31
|
+
const msgPrefixSym = Symbol('pino.msgPrefix')
|
32
|
+
|
33
|
+
const wildcardFirstSym = Symbol('pino.wildcardFirst')
|
34
|
+
|
35
|
+
// public symbols, no need to use the same pino
|
36
|
+
// version for these
|
37
|
+
const serializersSym = Symbol.for('pino.serializers')
|
38
|
+
const formattersSym = Symbol.for('pino.formatters')
|
39
|
+
const hooksSym = Symbol.for('pino.hooks')
|
40
|
+
const needsMetadataGsym = Symbol.for('pino.metadata')
|
41
|
+
|
42
|
+
module.exports = {
|
43
|
+
setLevelSym,
|
44
|
+
getLevelSym,
|
45
|
+
levelValSym,
|
46
|
+
levelCompSym,
|
47
|
+
useLevelLabelsSym,
|
48
|
+
mixinSym,
|
49
|
+
lsCacheSym,
|
50
|
+
chindingsSym,
|
51
|
+
asJsonSym,
|
52
|
+
writeSym,
|
53
|
+
serializersSym,
|
54
|
+
redactFmtSym,
|
55
|
+
timeSym,
|
56
|
+
timeSliceIndexSym,
|
57
|
+
streamSym,
|
58
|
+
stringifySym,
|
59
|
+
stringifySafeSym,
|
60
|
+
stringifiersSym,
|
61
|
+
endSym,
|
62
|
+
formatOptsSym,
|
63
|
+
messageKeySym,
|
64
|
+
errorKeySym,
|
65
|
+
nestedKeySym,
|
66
|
+
wildcardFirstSym,
|
67
|
+
needsMetadataGsym,
|
68
|
+
useOnlyCustomLevelsSym,
|
69
|
+
formattersSym,
|
70
|
+
hooksSym,
|
71
|
+
nestedKeyStrSym,
|
72
|
+
mixinMergeStrategySym,
|
73
|
+
msgPrefixSym
|
74
|
+
}
|
package/lib/time.js
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
'use strict'
|
2
|
+
|
3
|
+
const nullTime = () => ''
|
4
|
+
|
5
|
+
const epochTime = () => `,"time":${Date.now()}`
|
6
|
+
|
7
|
+
const unixTime = () => `,"time":${Math.round(Date.now() / 1000.0)}`
|
8
|
+
|
9
|
+
const isoTime = () => `,"time":"${new Date(Date.now()).toISOString()}"` // using Date.now() for testability
|
10
|
+
|
11
|
+
module.exports = { nullTime, epochTime, unixTime, isoTime }
|
package/lib/tools.js
ADDED
@@ -0,0 +1,394 @@
|
|
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 onExit = require('on-exit-leak-free')
|
9
|
+
const {
|
10
|
+
lsCacheSym,
|
11
|
+
chindingsSym,
|
12
|
+
writeSym,
|
13
|
+
serializersSym,
|
14
|
+
formatOptsSym,
|
15
|
+
endSym,
|
16
|
+
stringifiersSym,
|
17
|
+
stringifySym,
|
18
|
+
stringifySafeSym,
|
19
|
+
wildcardFirstSym,
|
20
|
+
nestedKeySym,
|
21
|
+
formattersSym,
|
22
|
+
messageKeySym,
|
23
|
+
errorKeySym,
|
24
|
+
nestedKeyStrSym,
|
25
|
+
msgPrefixSym
|
26
|
+
} = require('./symbols')
|
27
|
+
const { isMainThread } = require('worker_threads')
|
28
|
+
const transport = require('./transport')
|
29
|
+
|
30
|
+
function noop () {
|
31
|
+
}
|
32
|
+
|
33
|
+
function genLog (level, hook) {
|
34
|
+
if (!hook) return LOG
|
35
|
+
|
36
|
+
return function hookWrappedLog (...args) {
|
37
|
+
hook.call(this, args, LOG, level)
|
38
|
+
}
|
39
|
+
|
40
|
+
function LOG (o, ...n) {
|
41
|
+
if (typeof o === 'object') {
|
42
|
+
let msg = o
|
43
|
+
if (o !== null) {
|
44
|
+
if (o.method && o.headers && o.socket) {
|
45
|
+
o = mapHttpRequest(o)
|
46
|
+
} else if (typeof o.setHeader === 'function') {
|
47
|
+
o = mapHttpResponse(o)
|
48
|
+
}
|
49
|
+
}
|
50
|
+
let formatParams
|
51
|
+
if (msg === null && n.length === 0) {
|
52
|
+
formatParams = [null]
|
53
|
+
} else {
|
54
|
+
msg = n.shift()
|
55
|
+
formatParams = n
|
56
|
+
}
|
57
|
+
// We do not use a coercive check for `msg` as it is
|
58
|
+
// measurably slower than the explicit checks.
|
59
|
+
if (typeof this[msgPrefixSym] === 'string' && msg !== undefined && msg !== null) {
|
60
|
+
msg = this[msgPrefixSym] + msg
|
61
|
+
}
|
62
|
+
this[writeSym](o, format(msg, formatParams, this[formatOptsSym]), level)
|
63
|
+
} else {
|
64
|
+
let msg = o === undefined ? n.shift() : o
|
65
|
+
|
66
|
+
// We do not use a coercive check for `msg` as it is
|
67
|
+
// measurably slower than the explicit checks.
|
68
|
+
if (typeof this[msgPrefixSym] === 'string' && msg !== undefined && msg !== null) {
|
69
|
+
msg = this[msgPrefixSym] + msg
|
70
|
+
}
|
71
|
+
this[writeSym](null, format(msg, n, this[formatOptsSym]), level)
|
72
|
+
}
|
73
|
+
}
|
74
|
+
}
|
75
|
+
|
76
|
+
// magically escape strings for json
|
77
|
+
// relying on their charCodeAt
|
78
|
+
// everything below 32 needs JSON.stringify()
|
79
|
+
// 34 and 92 happens all the time, so we
|
80
|
+
// have a fast case for them
|
81
|
+
function asString (str) {
|
82
|
+
let result = ''
|
83
|
+
let last = 0
|
84
|
+
let found = false
|
85
|
+
let point = 255
|
86
|
+
const l = str.length
|
87
|
+
if (l > 100) {
|
88
|
+
return JSON.stringify(str)
|
89
|
+
}
|
90
|
+
for (var i = 0; i < l && point >= 32; i++) {
|
91
|
+
point = str.charCodeAt(i)
|
92
|
+
if (point === 34 || point === 92) {
|
93
|
+
result += str.slice(last, i) + '\\'
|
94
|
+
last = i
|
95
|
+
found = true
|
96
|
+
}
|
97
|
+
}
|
98
|
+
if (!found) {
|
99
|
+
result = str
|
100
|
+
} else {
|
101
|
+
result += str.slice(last)
|
102
|
+
}
|
103
|
+
return point < 32 ? JSON.stringify(str) : '"' + result + '"'
|
104
|
+
}
|
105
|
+
|
106
|
+
function asJson (obj, msg, num, time) {
|
107
|
+
const stringify = this[stringifySym]
|
108
|
+
const stringifySafe = this[stringifySafeSym]
|
109
|
+
const stringifiers = this[stringifiersSym]
|
110
|
+
const end = this[endSym]
|
111
|
+
const chindings = this[chindingsSym]
|
112
|
+
const serializers = this[serializersSym]
|
113
|
+
const formatters = this[formattersSym]
|
114
|
+
const messageKey = this[messageKeySym]
|
115
|
+
const errorKey = this[errorKeySym]
|
116
|
+
let data = this[lsCacheSym][num] + time
|
117
|
+
|
118
|
+
// we need the child bindings added to the output first so instance logged
|
119
|
+
// objects can take precedence when JSON.parse-ing the resulting log line
|
120
|
+
data = data + chindings
|
121
|
+
|
122
|
+
let value
|
123
|
+
if (formatters.log) {
|
124
|
+
obj = formatters.log(obj)
|
125
|
+
}
|
126
|
+
const wildcardStringifier = stringifiers[wildcardFirstSym]
|
127
|
+
let propStr = ''
|
128
|
+
for (const key in obj) {
|
129
|
+
value = obj[key]
|
130
|
+
if (Object.prototype.hasOwnProperty.call(obj, key) && value !== undefined) {
|
131
|
+
if (serializers[key]) {
|
132
|
+
value = serializers[key](value)
|
133
|
+
} else if (key === errorKey && serializers.err) {
|
134
|
+
value = serializers.err(value)
|
135
|
+
}
|
136
|
+
|
137
|
+
const stringifier = stringifiers[key] || wildcardStringifier
|
138
|
+
|
139
|
+
switch (typeof value) {
|
140
|
+
case 'undefined':
|
141
|
+
case 'function':
|
142
|
+
continue
|
143
|
+
case 'number':
|
144
|
+
/* eslint no-fallthrough: "off" */
|
145
|
+
if (Number.isFinite(value) === false) {
|
146
|
+
value = null
|
147
|
+
}
|
148
|
+
// this case explicitly falls through to the next one
|
149
|
+
case 'boolean':
|
150
|
+
if (stringifier) value = stringifier(value)
|
151
|
+
break
|
152
|
+
case 'string':
|
153
|
+
value = (stringifier || asString)(value)
|
154
|
+
break
|
155
|
+
default:
|
156
|
+
value = (stringifier || stringify)(value, stringifySafe)
|
157
|
+
}
|
158
|
+
if (value === undefined) continue
|
159
|
+
const strKey = asString(key)
|
160
|
+
propStr += ',' + strKey + ':' + value
|
161
|
+
}
|
162
|
+
}
|
163
|
+
|
164
|
+
let msgStr = ''
|
165
|
+
if (msg !== undefined) {
|
166
|
+
value = serializers[messageKey] ? serializers[messageKey](msg) : msg
|
167
|
+
const stringifier = stringifiers[messageKey] || wildcardStringifier
|
168
|
+
|
169
|
+
switch (typeof value) {
|
170
|
+
case 'function':
|
171
|
+
break
|
172
|
+
case 'number':
|
173
|
+
/* eslint no-fallthrough: "off" */
|
174
|
+
if (Number.isFinite(value) === false) {
|
175
|
+
value = null
|
176
|
+
}
|
177
|
+
// this case explicitly falls through to the next one
|
178
|
+
case 'boolean':
|
179
|
+
if (stringifier) value = stringifier(value)
|
180
|
+
msgStr = ',"' + messageKey + '":' + value
|
181
|
+
break
|
182
|
+
case 'string':
|
183
|
+
value = (stringifier || asString)(value)
|
184
|
+
msgStr = ',"' + messageKey + '":' + value
|
185
|
+
break
|
186
|
+
default:
|
187
|
+
value = (stringifier || stringify)(value, stringifySafe)
|
188
|
+
msgStr = ',"' + messageKey + '":' + value
|
189
|
+
}
|
190
|
+
}
|
191
|
+
|
192
|
+
if (this[nestedKeySym] && propStr) {
|
193
|
+
// place all the obj properties under the specified key
|
194
|
+
// the nested key is already formatted from the constructor
|
195
|
+
return data + this[nestedKeyStrSym] + propStr.slice(1) + '}' + msgStr + end
|
196
|
+
} else {
|
197
|
+
return data + propStr + msgStr + end
|
198
|
+
}
|
199
|
+
}
|
200
|
+
|
201
|
+
function asChindings (instance, bindings) {
|
202
|
+
let value
|
203
|
+
let data = instance[chindingsSym]
|
204
|
+
const stringify = instance[stringifySym]
|
205
|
+
const stringifySafe = instance[stringifySafeSym]
|
206
|
+
const stringifiers = instance[stringifiersSym]
|
207
|
+
const wildcardStringifier = stringifiers[wildcardFirstSym]
|
208
|
+
const serializers = instance[serializersSym]
|
209
|
+
const formatter = instance[formattersSym].bindings
|
210
|
+
bindings = formatter(bindings)
|
211
|
+
|
212
|
+
for (const key in bindings) {
|
213
|
+
value = bindings[key]
|
214
|
+
const valid = key !== 'level' &&
|
215
|
+
key !== 'serializers' &&
|
216
|
+
key !== 'formatters' &&
|
217
|
+
key !== 'customLevels' &&
|
218
|
+
bindings.hasOwnProperty(key) &&
|
219
|
+
value !== undefined
|
220
|
+
if (valid === true) {
|
221
|
+
value = serializers[key] ? serializers[key](value) : value
|
222
|
+
value = (stringifiers[key] || wildcardStringifier || stringify)(value, stringifySafe)
|
223
|
+
if (value === undefined) continue
|
224
|
+
data += ',"' + key + '":' + value
|
225
|
+
}
|
226
|
+
}
|
227
|
+
return data
|
228
|
+
}
|
229
|
+
|
230
|
+
function hasBeenTampered (stream) {
|
231
|
+
return stream.write !== stream.constructor.prototype.write
|
232
|
+
}
|
233
|
+
|
234
|
+
const hasNodeCodeCoverage = process.env.NODE_V8_COVERAGE || process.env.V8_COVERAGE
|
235
|
+
|
236
|
+
function buildSafeSonicBoom (opts) {
|
237
|
+
const stream = new SonicBoom(opts)
|
238
|
+
stream.on('error', filterBrokenPipe)
|
239
|
+
// If we are sync: false, we must flush on exit
|
240
|
+
// We must disable this if there is node code coverage due to
|
241
|
+
// https://github.com/nodejs/node/issues/49344#issuecomment-1741776308.
|
242
|
+
if (!hasNodeCodeCoverage && !opts.sync && isMainThread) {
|
243
|
+
onExit.register(stream, autoEnd)
|
244
|
+
|
245
|
+
stream.on('close', function () {
|
246
|
+
onExit.unregister(stream)
|
247
|
+
})
|
248
|
+
}
|
249
|
+
return stream
|
250
|
+
|
251
|
+
function filterBrokenPipe (err) {
|
252
|
+
// Impossible to replicate across all operating systems
|
253
|
+
/* istanbul ignore next */
|
254
|
+
if (err.code === 'EPIPE') {
|
255
|
+
// If we get EPIPE, we should stop logging here
|
256
|
+
// however we have no control to the consumer of
|
257
|
+
// SonicBoom, so we just overwrite the write method
|
258
|
+
stream.write = noop
|
259
|
+
stream.end = noop
|
260
|
+
stream.flushSync = noop
|
261
|
+
stream.destroy = noop
|
262
|
+
return
|
263
|
+
}
|
264
|
+
stream.removeListener('error', filterBrokenPipe)
|
265
|
+
stream.emit('error', err)
|
266
|
+
}
|
267
|
+
}
|
268
|
+
|
269
|
+
function autoEnd (stream, eventName) {
|
270
|
+
// This check is needed only on some platforms
|
271
|
+
/* istanbul ignore next */
|
272
|
+
if (stream.destroyed) {
|
273
|
+
return
|
274
|
+
}
|
275
|
+
|
276
|
+
if (eventName === 'beforeExit') {
|
277
|
+
// We still have an event loop, let's use it
|
278
|
+
stream.flush()
|
279
|
+
stream.on('drain', function () {
|
280
|
+
stream.end()
|
281
|
+
})
|
282
|
+
} else {
|
283
|
+
// For some reason istanbul is not detecting this, but it's there
|
284
|
+
/* istanbul ignore next */
|
285
|
+
// We do not have an event loop, so flush synchronously
|
286
|
+
stream.flushSync()
|
287
|
+
}
|
288
|
+
}
|
289
|
+
|
290
|
+
function createArgsNormalizer (defaultOptions) {
|
291
|
+
return function normalizeArgs (instance, caller, opts = {}, stream) {
|
292
|
+
// support stream as a string
|
293
|
+
if (typeof opts === 'string') {
|
294
|
+
stream = buildSafeSonicBoom({ dest: opts })
|
295
|
+
opts = {}
|
296
|
+
} else if (typeof stream === 'string') {
|
297
|
+
if (opts && opts.transport) {
|
298
|
+
throw Error('only one of option.transport or stream can be specified')
|
299
|
+
}
|
300
|
+
stream = buildSafeSonicBoom({ dest: stream })
|
301
|
+
} else if (opts instanceof SonicBoom || opts.writable || opts._writableState) {
|
302
|
+
stream = opts
|
303
|
+
opts = {}
|
304
|
+
} else if (opts.transport) {
|
305
|
+
if (opts.transport instanceof SonicBoom || opts.transport.writable || opts.transport._writableState) {
|
306
|
+
throw Error('option.transport do not allow stream, please pass to option directly. e.g. pino(transport)')
|
307
|
+
}
|
308
|
+
if (opts.transport.targets && opts.transport.targets.length && opts.formatters && typeof opts.formatters.level === 'function') {
|
309
|
+
throw Error('option.transport.targets do not allow custom level formatters')
|
310
|
+
}
|
311
|
+
|
312
|
+
let customLevels
|
313
|
+
if (opts.customLevels) {
|
314
|
+
customLevels = opts.useOnlyCustomLevels ? opts.customLevels : Object.assign({}, opts.levels, opts.customLevels)
|
315
|
+
}
|
316
|
+
stream = transport({ caller, ...opts.transport, levels: customLevels })
|
317
|
+
}
|
318
|
+
opts = Object.assign({}, defaultOptions, opts)
|
319
|
+
opts.serializers = Object.assign({}, defaultOptions.serializers, opts.serializers)
|
320
|
+
opts.formatters = Object.assign({}, defaultOptions.formatters, opts.formatters)
|
321
|
+
|
322
|
+
if (opts.prettyPrint) {
|
323
|
+
throw new Error('prettyPrint option is no longer supported, see the pino-pretty package (https://github.com/pinojs/pino-pretty)')
|
324
|
+
}
|
325
|
+
|
326
|
+
const { enabled, onChild } = opts
|
327
|
+
if (enabled === false) opts.level = 'silent'
|
328
|
+
if (!onChild) opts.onChild = noop
|
329
|
+
if (!stream) {
|
330
|
+
if (!hasBeenTampered(process.stdout)) {
|
331
|
+
// If process.stdout.fd is undefined, it means that we are running
|
332
|
+
// in a worker thread. Let's assume we are logging to file descriptor 1.
|
333
|
+
stream = buildSafeSonicBoom({ fd: process.stdout.fd || 1 })
|
334
|
+
} else {
|
335
|
+
stream = process.stdout
|
336
|
+
}
|
337
|
+
}
|
338
|
+
return { opts, stream }
|
339
|
+
}
|
340
|
+
}
|
341
|
+
|
342
|
+
function stringify (obj, stringifySafeFn) {
|
343
|
+
try {
|
344
|
+
return JSON.stringify(obj)
|
345
|
+
} catch (_) {
|
346
|
+
try {
|
347
|
+
const stringify = stringifySafeFn || this[stringifySafeSym]
|
348
|
+
return stringify(obj)
|
349
|
+
} catch (_) {
|
350
|
+
return '"[unable to serialize, circular reference is too complex to analyze]"'
|
351
|
+
}
|
352
|
+
}
|
353
|
+
}
|
354
|
+
|
355
|
+
function buildFormatters (level, bindings, log) {
|
356
|
+
return {
|
357
|
+
level,
|
358
|
+
bindings,
|
359
|
+
log
|
360
|
+
}
|
361
|
+
}
|
362
|
+
|
363
|
+
/**
|
364
|
+
* Convert a string integer file descriptor to a proper native integer
|
365
|
+
* file descriptor.
|
366
|
+
*
|
367
|
+
* @param {string} destination The file descriptor string to attempt to convert.
|
368
|
+
*
|
369
|
+
* @returns {Number}
|
370
|
+
*/
|
371
|
+
function normalizeDestFileDescriptor (destination) {
|
372
|
+
const fd = Number(destination)
|
373
|
+
if (typeof destination === 'string' && Number.isFinite(fd)) {
|
374
|
+
return fd
|
375
|
+
}
|
376
|
+
// destination could be undefined if we are in a worker
|
377
|
+
if (destination === undefined) {
|
378
|
+
// This is stdout in UNIX systems
|
379
|
+
return 1
|
380
|
+
}
|
381
|
+
return destination
|
382
|
+
}
|
383
|
+
|
384
|
+
module.exports = {
|
385
|
+
noop,
|
386
|
+
buildSafeSonicBoom,
|
387
|
+
asChindings,
|
388
|
+
asJson,
|
389
|
+
genLog,
|
390
|
+
createArgsNormalizer,
|
391
|
+
stringify,
|
392
|
+
buildFormatters,
|
393
|
+
normalizeDestFileDescriptor
|
394
|
+
}
|
@@ -0,0 +1,56 @@
|
|
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 {Promise<function(object): Promise<import('node: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 = target.startsWith('file://') ? target : '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/pinojs/thread-stream/pull/34
|
32
|
+
if ((error.code === 'ENOTDIR' || error.code === 'ERR_MODULE_NOT_FOUND')) {
|
33
|
+
fn = realRequire(target)
|
34
|
+
} else if (error.code === undefined || error.code === 'ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING') {
|
35
|
+
// When bundled with pkg, an undefined error is thrown when called with realImport
|
36
|
+
// When bundled with pkg and using node v20, an ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING error is thrown when called with realImport
|
37
|
+
// More info at: https://github.com/pinojs/thread-stream/issues/143
|
38
|
+
try {
|
39
|
+
fn = realRequire(decodeURIComponent(target))
|
40
|
+
} catch {
|
41
|
+
throw error
|
42
|
+
}
|
43
|
+
} else {
|
44
|
+
throw error
|
45
|
+
}
|
46
|
+
}
|
47
|
+
|
48
|
+
// Depending on how the default export is performed, and on how the code is
|
49
|
+
// transpiled, we may find cases of two nested "default" objects.
|
50
|
+
// See https://github.com/pinojs/pino/issues/1243#issuecomment-982774762
|
51
|
+
if (typeof fn === 'object') fn = fn.default
|
52
|
+
if (typeof fn === 'object') fn = fn.default
|
53
|
+
if (typeof fn !== 'function') throw Error('exported worker is not a function')
|
54
|
+
|
55
|
+
return fn
|
56
|
+
}
|