@commercetools-backend/loggers 27.5.3 → 27.6.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.
- package/dist/commercetools-backend-loggers.cjs.dev.js +36 -17
- package/dist/commercetools-backend-loggers.cjs.prod.js +36 -17
- package/dist/commercetools-backend-loggers.esm.js +20 -5
- package/dist/declarations/src/formatters/redact-fields.d.ts +5 -0
- package/dist/declarations/src/index.d.ts +1 -0
- package/package.json +1 -1
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
3
5
|
var expressWinston = require('express-winston');
|
|
4
6
|
var winston = require('winston');
|
|
5
7
|
var _defineProperty = require('@babel/runtime-corejs3/helpers/defineProperty');
|
|
@@ -15,12 +17,13 @@ var _Object$getOwnPropertyDescriptors = require('@babel/runtime-corejs3/core-js-
|
|
|
15
17
|
var _Object$defineProperties = require('@babel/runtime-corejs3/core-js-stable/object/define-properties');
|
|
16
18
|
var _Object$defineProperty = require('@babel/runtime-corejs3/core-js-stable/object/define-property');
|
|
17
19
|
var cloneDeep = require('lodash/cloneDeep');
|
|
20
|
+
var has = require('lodash/has');
|
|
21
|
+
var set = require('lodash/set');
|
|
22
|
+
var logform = require('logform');
|
|
18
23
|
var getIn = require('lodash/get');
|
|
19
|
-
var setIn = require('lodash/set');
|
|
20
24
|
var unsetIn = require('lodash/unset');
|
|
21
|
-
var logform = require('logform');
|
|
22
25
|
|
|
23
|
-
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
26
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { 'default': e }; }
|
|
24
27
|
|
|
25
28
|
function _interopNamespace(e) {
|
|
26
29
|
if (e && e.__esModule) return e;
|
|
@@ -36,7 +39,7 @@ function _interopNamespace(e) {
|
|
|
36
39
|
}
|
|
37
40
|
});
|
|
38
41
|
}
|
|
39
|
-
n
|
|
42
|
+
n["default"] = e;
|
|
40
43
|
return Object.freeze(n);
|
|
41
44
|
}
|
|
42
45
|
|
|
@@ -53,18 +56,19 @@ var _Object$getOwnPropertyDescriptors__default = /*#__PURE__*/_interopDefault(_O
|
|
|
53
56
|
var _Object$defineProperties__default = /*#__PURE__*/_interopDefault(_Object$defineProperties);
|
|
54
57
|
var _Object$defineProperty__default = /*#__PURE__*/_interopDefault(_Object$defineProperty);
|
|
55
58
|
var cloneDeep__default = /*#__PURE__*/_interopDefault(cloneDeep);
|
|
59
|
+
var has__default = /*#__PURE__*/_interopDefault(has);
|
|
60
|
+
var set__default = /*#__PURE__*/_interopDefault(set);
|
|
56
61
|
var getIn__default = /*#__PURE__*/_interopDefault(getIn);
|
|
57
|
-
var setIn__default = /*#__PURE__*/_interopDefault(setIn);
|
|
58
62
|
var unsetIn__default = /*#__PURE__*/_interopDefault(unsetIn);
|
|
59
63
|
|
|
60
|
-
function ownKeys(e, r) { var t = _Object$keys__default
|
|
61
|
-
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var _context2, _context3; var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? _forEachInstanceProperty__default
|
|
64
|
+
function ownKeys(e, r) { var t = _Object$keys__default["default"](e); if (_Object$getOwnPropertySymbols__default["default"]) { var o = _Object$getOwnPropertySymbols__default["default"](e); r && (o = _filterInstanceProperty__default["default"](o).call(o, function (r) { return _Object$getOwnPropertyDescriptor__default["default"](e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
65
|
+
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var _context2, _context3; var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? _forEachInstanceProperty__default["default"](_context2 = ownKeys(Object(t), !0)).call(_context2, function (r) { _defineProperty(e, r, t[r]); }) : _Object$getOwnPropertyDescriptors__default["default"] ? _Object$defineProperties__default["default"](e, _Object$getOwnPropertyDescriptors__default["default"](t)) : _forEachInstanceProperty__default["default"](_context3 = ownKeys(Object(t))).call(_context3, function (r) { _Object$defineProperty__default["default"](e, r, _Object$getOwnPropertyDescriptor__default["default"](t, r)); }); } return e; }
|
|
62
66
|
const parseIps = request => {
|
|
63
67
|
const forwardedFor = request.headers['x-forwarded-for'];
|
|
64
68
|
if (!forwardedFor) {
|
|
65
69
|
return [];
|
|
66
70
|
}
|
|
67
|
-
const remoteAddresses = _Array$isArray__default
|
|
71
|
+
const remoteAddresses = _Array$isArray__default["default"](forwardedFor) ? forwardedFor : forwardedFor.split(',');
|
|
68
72
|
return remoteAddresses;
|
|
69
73
|
};
|
|
70
74
|
const createAccessLogSkipper = options => request => {
|
|
@@ -72,7 +76,7 @@ const createAccessLogSkipper = options => request => {
|
|
|
72
76
|
if (Boolean(options.silent)) {
|
|
73
77
|
return true;
|
|
74
78
|
}
|
|
75
|
-
const hasMatchingIgnoreUrl = _someInstanceProperty__default
|
|
79
|
+
const hasMatchingIgnoreUrl = _someInstanceProperty__default["default"](_context = options.ignoreUrls ?? []).call(_context, uriPathOrRegex => {
|
|
76
80
|
if (typeof uriPathOrRegex === 'string') {
|
|
77
81
|
return request.originalUrl === uriPathOrRegex;
|
|
78
82
|
}
|
|
@@ -101,11 +105,11 @@ const mapRequestMetadata = request => {
|
|
|
101
105
|
|
|
102
106
|
const createAccessLoggerMiddleware = function () {
|
|
103
107
|
let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
104
|
-
const formatters = winston__namespace
|
|
108
|
+
const formatters = winston__namespace["default"].format.combine(winston__namespace["default"].format.timestamp(), ...(options.formatters ?? []), options.json ? winston__namespace["default"].format.json() : winston__namespace["default"].format.cli());
|
|
105
109
|
const skip = createAccessLogSkipper(options);
|
|
106
|
-
return expressWinston__default
|
|
110
|
+
return expressWinston__default["default"].logger({
|
|
107
111
|
level: options.level ?? 'info',
|
|
108
|
-
transports: [new winston__namespace
|
|
112
|
+
transports: [new winston__namespace["default"].transports.Console()],
|
|
109
113
|
format: formatters,
|
|
110
114
|
meta: true,
|
|
111
115
|
expressFormat: true,
|
|
@@ -128,21 +132,35 @@ const createApplicationLogger = function () {
|
|
|
128
132
|
});
|
|
129
133
|
};
|
|
130
134
|
|
|
135
|
+
const REDACTED = '[REDACTED]';
|
|
136
|
+
function redactFieldsFormatter(options) {
|
|
137
|
+
return logform.format(info => {
|
|
138
|
+
var _context;
|
|
139
|
+
const clone = cloneDeep__default["default"](info);
|
|
140
|
+
_forEachInstanceProperty__default["default"](_context = options.fields).call(_context, field => {
|
|
141
|
+
if (has__default["default"](clone, field)) {
|
|
142
|
+
set__default["default"](clone, field, REDACTED);
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
return clone;
|
|
146
|
+
})(options);
|
|
147
|
+
}
|
|
148
|
+
|
|
131
149
|
function rewriteField(info, field) {
|
|
132
|
-
const fromFieldValue = getIn__default
|
|
150
|
+
const fromFieldValue = getIn__default["default"](info, field.from);
|
|
133
151
|
const preserveFromField = field.preserveFromField ?? false;
|
|
134
152
|
if (fromFieldValue) {
|
|
135
153
|
if (!preserveFromField) {
|
|
136
|
-
unsetIn__default
|
|
154
|
+
unsetIn__default["default"](info, field.from);
|
|
137
155
|
}
|
|
138
|
-
|
|
156
|
+
set__default["default"](info, field.to, field.replaceValue ? field.replaceValue(fromFieldValue) : fromFieldValue);
|
|
139
157
|
}
|
|
140
158
|
}
|
|
141
159
|
function rewriteFieldsFormatter(options) {
|
|
142
160
|
return logform.format(info => {
|
|
143
161
|
var _context;
|
|
144
|
-
const clone = cloneDeep__default
|
|
145
|
-
_forEachInstanceProperty__default
|
|
162
|
+
const clone = cloneDeep__default["default"](info);
|
|
163
|
+
_forEachInstanceProperty__default["default"](_context = options.fields).call(_context, field => {
|
|
146
164
|
rewriteField(clone, field);
|
|
147
165
|
});
|
|
148
166
|
return clone;
|
|
@@ -151,4 +169,5 @@ function rewriteFieldsFormatter(options) {
|
|
|
151
169
|
|
|
152
170
|
exports.createAccessLoggerMiddleware = createAccessLoggerMiddleware;
|
|
153
171
|
exports.createApplicationLogger = createApplicationLogger;
|
|
172
|
+
exports.redactFieldsFormatter = redactFieldsFormatter;
|
|
154
173
|
exports.rewriteFieldsFormatter = rewriteFieldsFormatter;
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
3
5
|
var expressWinston = require('express-winston');
|
|
4
6
|
var winston = require('winston');
|
|
5
7
|
var _defineProperty = require('@babel/runtime-corejs3/helpers/defineProperty');
|
|
@@ -15,12 +17,13 @@ var _Object$getOwnPropertyDescriptors = require('@babel/runtime-corejs3/core-js-
|
|
|
15
17
|
var _Object$defineProperties = require('@babel/runtime-corejs3/core-js-stable/object/define-properties');
|
|
16
18
|
var _Object$defineProperty = require('@babel/runtime-corejs3/core-js-stable/object/define-property');
|
|
17
19
|
var cloneDeep = require('lodash/cloneDeep');
|
|
20
|
+
var has = require('lodash/has');
|
|
21
|
+
var set = require('lodash/set');
|
|
22
|
+
var logform = require('logform');
|
|
18
23
|
var getIn = require('lodash/get');
|
|
19
|
-
var setIn = require('lodash/set');
|
|
20
24
|
var unsetIn = require('lodash/unset');
|
|
21
|
-
var logform = require('logform');
|
|
22
25
|
|
|
23
|
-
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
26
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { 'default': e }; }
|
|
24
27
|
|
|
25
28
|
function _interopNamespace(e) {
|
|
26
29
|
if (e && e.__esModule) return e;
|
|
@@ -36,7 +39,7 @@ function _interopNamespace(e) {
|
|
|
36
39
|
}
|
|
37
40
|
});
|
|
38
41
|
}
|
|
39
|
-
n
|
|
42
|
+
n["default"] = e;
|
|
40
43
|
return Object.freeze(n);
|
|
41
44
|
}
|
|
42
45
|
|
|
@@ -53,18 +56,19 @@ var _Object$getOwnPropertyDescriptors__default = /*#__PURE__*/_interopDefault(_O
|
|
|
53
56
|
var _Object$defineProperties__default = /*#__PURE__*/_interopDefault(_Object$defineProperties);
|
|
54
57
|
var _Object$defineProperty__default = /*#__PURE__*/_interopDefault(_Object$defineProperty);
|
|
55
58
|
var cloneDeep__default = /*#__PURE__*/_interopDefault(cloneDeep);
|
|
59
|
+
var has__default = /*#__PURE__*/_interopDefault(has);
|
|
60
|
+
var set__default = /*#__PURE__*/_interopDefault(set);
|
|
56
61
|
var getIn__default = /*#__PURE__*/_interopDefault(getIn);
|
|
57
|
-
var setIn__default = /*#__PURE__*/_interopDefault(setIn);
|
|
58
62
|
var unsetIn__default = /*#__PURE__*/_interopDefault(unsetIn);
|
|
59
63
|
|
|
60
|
-
function ownKeys(e, r) { var t = _Object$keys__default
|
|
61
|
-
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var _context2, _context3; var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? _forEachInstanceProperty__default
|
|
64
|
+
function ownKeys(e, r) { var t = _Object$keys__default["default"](e); if (_Object$getOwnPropertySymbols__default["default"]) { var o = _Object$getOwnPropertySymbols__default["default"](e); r && (o = _filterInstanceProperty__default["default"](o).call(o, function (r) { return _Object$getOwnPropertyDescriptor__default["default"](e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
65
|
+
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var _context2, _context3; var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? _forEachInstanceProperty__default["default"](_context2 = ownKeys(Object(t), !0)).call(_context2, function (r) { _defineProperty(e, r, t[r]); }) : _Object$getOwnPropertyDescriptors__default["default"] ? _Object$defineProperties__default["default"](e, _Object$getOwnPropertyDescriptors__default["default"](t)) : _forEachInstanceProperty__default["default"](_context3 = ownKeys(Object(t))).call(_context3, function (r) { _Object$defineProperty__default["default"](e, r, _Object$getOwnPropertyDescriptor__default["default"](t, r)); }); } return e; }
|
|
62
66
|
const parseIps = request => {
|
|
63
67
|
const forwardedFor = request.headers['x-forwarded-for'];
|
|
64
68
|
if (!forwardedFor) {
|
|
65
69
|
return [];
|
|
66
70
|
}
|
|
67
|
-
const remoteAddresses = _Array$isArray__default
|
|
71
|
+
const remoteAddresses = _Array$isArray__default["default"](forwardedFor) ? forwardedFor : forwardedFor.split(',');
|
|
68
72
|
return remoteAddresses;
|
|
69
73
|
};
|
|
70
74
|
const createAccessLogSkipper = options => request => {
|
|
@@ -72,7 +76,7 @@ const createAccessLogSkipper = options => request => {
|
|
|
72
76
|
if (Boolean(options.silent)) {
|
|
73
77
|
return true;
|
|
74
78
|
}
|
|
75
|
-
const hasMatchingIgnoreUrl = _someInstanceProperty__default
|
|
79
|
+
const hasMatchingIgnoreUrl = _someInstanceProperty__default["default"](_context = options.ignoreUrls ?? []).call(_context, uriPathOrRegex => {
|
|
76
80
|
if (typeof uriPathOrRegex === 'string') {
|
|
77
81
|
return request.originalUrl === uriPathOrRegex;
|
|
78
82
|
}
|
|
@@ -101,11 +105,11 @@ const mapRequestMetadata = request => {
|
|
|
101
105
|
|
|
102
106
|
const createAccessLoggerMiddleware = function () {
|
|
103
107
|
let options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
|
|
104
|
-
const formatters = winston__namespace
|
|
108
|
+
const formatters = winston__namespace["default"].format.combine(winston__namespace["default"].format.timestamp(), ...(options.formatters ?? []), options.json ? winston__namespace["default"].format.json() : winston__namespace["default"].format.cli());
|
|
105
109
|
const skip = createAccessLogSkipper(options);
|
|
106
|
-
return expressWinston__default
|
|
110
|
+
return expressWinston__default["default"].logger({
|
|
107
111
|
level: options.level ?? 'info',
|
|
108
|
-
transports: [new winston__namespace
|
|
112
|
+
transports: [new winston__namespace["default"].transports.Console()],
|
|
109
113
|
format: formatters,
|
|
110
114
|
meta: true,
|
|
111
115
|
expressFormat: true,
|
|
@@ -128,21 +132,35 @@ const createApplicationLogger = function () {
|
|
|
128
132
|
});
|
|
129
133
|
};
|
|
130
134
|
|
|
135
|
+
const REDACTED = '[REDACTED]';
|
|
136
|
+
function redactFieldsFormatter(options) {
|
|
137
|
+
return logform.format(info => {
|
|
138
|
+
var _context;
|
|
139
|
+
const clone = cloneDeep__default["default"](info);
|
|
140
|
+
_forEachInstanceProperty__default["default"](_context = options.fields).call(_context, field => {
|
|
141
|
+
if (has__default["default"](clone, field)) {
|
|
142
|
+
set__default["default"](clone, field, REDACTED);
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
return clone;
|
|
146
|
+
})(options);
|
|
147
|
+
}
|
|
148
|
+
|
|
131
149
|
function rewriteField(info, field) {
|
|
132
|
-
const fromFieldValue = getIn__default
|
|
150
|
+
const fromFieldValue = getIn__default["default"](info, field.from);
|
|
133
151
|
const preserveFromField = field.preserveFromField ?? false;
|
|
134
152
|
if (fromFieldValue) {
|
|
135
153
|
if (!preserveFromField) {
|
|
136
|
-
unsetIn__default
|
|
154
|
+
unsetIn__default["default"](info, field.from);
|
|
137
155
|
}
|
|
138
|
-
|
|
156
|
+
set__default["default"](info, field.to, field.replaceValue ? field.replaceValue(fromFieldValue) : fromFieldValue);
|
|
139
157
|
}
|
|
140
158
|
}
|
|
141
159
|
function rewriteFieldsFormatter(options) {
|
|
142
160
|
return logform.format(info => {
|
|
143
161
|
var _context;
|
|
144
|
-
const clone = cloneDeep__default
|
|
145
|
-
_forEachInstanceProperty__default
|
|
162
|
+
const clone = cloneDeep__default["default"](info);
|
|
163
|
+
_forEachInstanceProperty__default["default"](_context = options.fields).call(_context, field => {
|
|
146
164
|
rewriteField(clone, field);
|
|
147
165
|
});
|
|
148
166
|
return clone;
|
|
@@ -151,4 +169,5 @@ function rewriteFieldsFormatter(options) {
|
|
|
151
169
|
|
|
152
170
|
exports.createAccessLoggerMiddleware = createAccessLoggerMiddleware;
|
|
153
171
|
exports.createApplicationLogger = createApplicationLogger;
|
|
172
|
+
exports.redactFieldsFormatter = redactFieldsFormatter;
|
|
154
173
|
exports.rewriteFieldsFormatter = rewriteFieldsFormatter;
|
|
@@ -14,13 +14,14 @@ import _Object$getOwnPropertyDescriptors from '@babel/runtime-corejs3/core-js-st
|
|
|
14
14
|
import _Object$defineProperties from '@babel/runtime-corejs3/core-js-stable/object/define-properties';
|
|
15
15
|
import _Object$defineProperty from '@babel/runtime-corejs3/core-js-stable/object/define-property';
|
|
16
16
|
import cloneDeep from 'lodash/cloneDeep';
|
|
17
|
+
import has from 'lodash/has';
|
|
18
|
+
import set from 'lodash/set';
|
|
19
|
+
import { format } from 'logform';
|
|
17
20
|
import getIn from 'lodash/get';
|
|
18
|
-
import setIn from 'lodash/set';
|
|
19
21
|
import unsetIn from 'lodash/unset';
|
|
20
|
-
import { format } from 'logform';
|
|
21
22
|
|
|
22
23
|
function ownKeys(e, r) { var t = _Object$keys(e); if (_Object$getOwnPropertySymbols) { var o = _Object$getOwnPropertySymbols(e); r && (o = _filterInstanceProperty(o).call(o, function (r) { return _Object$getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
|
|
23
|
-
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var _context2, _context3; var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? _forEachInstanceProperty(_context2 = ownKeys(Object(t),
|
|
24
|
+
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var _context2, _context3; var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? _forEachInstanceProperty(_context2 = ownKeys(Object(t), !0)).call(_context2, function (r) { _defineProperty(e, r, t[r]); }) : _Object$getOwnPropertyDescriptors ? _Object$defineProperties(e, _Object$getOwnPropertyDescriptors(t)) : _forEachInstanceProperty(_context3 = ownKeys(Object(t))).call(_context3, function (r) { _Object$defineProperty(e, r, _Object$getOwnPropertyDescriptor(t, r)); }); } return e; }
|
|
24
25
|
const parseIps = request => {
|
|
25
26
|
const forwardedFor = request.headers['x-forwarded-for'];
|
|
26
27
|
if (!forwardedFor) {
|
|
@@ -90,6 +91,20 @@ const createApplicationLogger = function () {
|
|
|
90
91
|
});
|
|
91
92
|
};
|
|
92
93
|
|
|
94
|
+
const REDACTED = '[REDACTED]';
|
|
95
|
+
function redactFieldsFormatter(options) {
|
|
96
|
+
return format(info => {
|
|
97
|
+
var _context;
|
|
98
|
+
const clone = cloneDeep(info);
|
|
99
|
+
_forEachInstanceProperty(_context = options.fields).call(_context, field => {
|
|
100
|
+
if (has(clone, field)) {
|
|
101
|
+
set(clone, field, REDACTED);
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
return clone;
|
|
105
|
+
})(options);
|
|
106
|
+
}
|
|
107
|
+
|
|
93
108
|
function rewriteField(info, field) {
|
|
94
109
|
const fromFieldValue = getIn(info, field.from);
|
|
95
110
|
const preserveFromField = field.preserveFromField ?? false;
|
|
@@ -97,7 +112,7 @@ function rewriteField(info, field) {
|
|
|
97
112
|
if (!preserveFromField) {
|
|
98
113
|
unsetIn(info, field.from);
|
|
99
114
|
}
|
|
100
|
-
|
|
115
|
+
set(info, field.to, field.replaceValue ? field.replaceValue(fromFieldValue) : fromFieldValue);
|
|
101
116
|
}
|
|
102
117
|
}
|
|
103
118
|
function rewriteFieldsFormatter(options) {
|
|
@@ -111,4 +126,4 @@ function rewriteFieldsFormatter(options) {
|
|
|
111
126
|
})(options);
|
|
112
127
|
}
|
|
113
128
|
|
|
114
|
-
export { createAccessLoggerMiddleware, createApplicationLogger, rewriteFieldsFormatter };
|
|
129
|
+
export { createAccessLoggerMiddleware, createApplicationLogger, redactFieldsFormatter, rewriteFieldsFormatter };
|
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
export { default as createAccessLoggerMiddleware } from "./middlewares/create-access-logger.js";
|
|
2
2
|
export { default as createApplicationLogger } from "./create-application-logger.js";
|
|
3
|
+
export { default as redactFieldsFormatter } from "./formatters/redact-fields.js";
|
|
3
4
|
export { default as rewriteFieldsFormatter } from "./formatters/rewrite-fields.js";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@commercetools-backend/loggers",
|
|
3
|
-
"version": "27.
|
|
3
|
+
"version": "27.6.0",
|
|
4
4
|
"description": "Opinionated JSON loggers for HTTP server applications",
|
|
5
5
|
"bugs": "https://github.com/commercetools/merchant-center-application-kit/issues",
|
|
6
6
|
"repository": {
|