@onesub/server 0.23.3 → 0.24.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/__tests__/log-format.test.d.ts +15 -0
- package/dist/__tests__/log-format.test.d.ts.map +1 -0
- package/dist/__tests__/logger.test.d.ts +13 -6
- package/dist/__tests__/logger.test.d.ts.map +1 -1
- package/dist/index.cjs +119 -9
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +119 -9
- package/dist/index.js.map +1 -1
- package/dist/log-format.d.ts +68 -0
- package/dist/log-format.d.ts.map +1 -0
- package/dist/logger.d.ts.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* formatLogArgs — the security properties of log rendering.
|
|
3
|
+
*
|
|
4
|
+
* These live here rather than in `logger.test.ts` because they are properties of a
|
|
5
|
+
* pure function from arguments to a string. `logger.ts` holds process-global state
|
|
6
|
+
* and needs `setLogger` juggling; nothing that carries a security claim should
|
|
7
|
+
* depend on that.
|
|
8
|
+
*
|
|
9
|
+
* The central claim is one property, asserted over a hostile matrix rather than
|
|
10
|
+
* case by case: **no byte supplied by a caller can begin a line.** Everything else
|
|
11
|
+
* here is either a corollary or a guard against the formatter throwing on input it
|
|
12
|
+
* will genuinely receive.
|
|
13
|
+
*/
|
|
14
|
+
export {};
|
|
15
|
+
//# sourceMappingURL=log-format.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log-format.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/log-format.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG"}
|
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The process-wide logger, and
|
|
2
|
+
* The process-wide logger: routing, and the shape of what reaches the sink.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
4
|
+
* The escaping and rendering details moved to `log-format.test.ts`, which tests them
|
|
5
|
+
* as properties of a pure function over a hostile matrix rather than one case at a
|
|
6
|
+
* time. What is left here is what only this module can answer: that each level goes
|
|
7
|
+
* where it should, and that a sink receives **exactly one string argument**.
|
|
8
|
+
*
|
|
9
|
+
* That last one is the load-bearing assertion. It is the contract every documented
|
|
10
|
+
* sink depends on — `pino` treats a second argument as a printf interpolation
|
|
11
|
+
* parameter, not as structured fields, so anything "helpfully" passing fields
|
|
12
|
+
* alongside the message would silently degrade for the sink this package recommends
|
|
13
|
+
* for production. There is also then no shape for a JSON serialiser to drop: an
|
|
14
|
+
* `Error` passed as an object would serialise to `{}`, because its own properties
|
|
15
|
+
* are non-enumerable.
|
|
9
16
|
*/
|
|
10
17
|
export {};
|
|
11
18
|
//# sourceMappingURL=logger.test.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"logger.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/logger.test.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"logger.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/logger.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG"}
|
package/dist/index.cjs
CHANGED
|
@@ -170,21 +170,131 @@ at+qIxUCMG1mihDK1A3UT82NQz60imOlM27jbdoXt2QfyFMm+YhidDkLF1vLUagM
|
|
|
170
170
|
-----END CERTIFICATE-----`;
|
|
171
171
|
var APPLE_ROOT_CA_PEMS = [APPLE_ROOT_CA_G3_PEM];
|
|
172
172
|
|
|
173
|
+
// src/log-format.ts
|
|
174
|
+
var LOG_CONTINUATION = "\n | ";
|
|
175
|
+
var BARE_VALUE = /^[\w.:/@+-]+$/;
|
|
176
|
+
var LINE_TERMINATORS = /\r\n|\r|\n|\u2028|\u2029/;
|
|
177
|
+
var MAX_CAUSE_DEPTH = 2;
|
|
178
|
+
var MAX_AGGREGATE_ERRORS = 3;
|
|
179
|
+
function esc(value) {
|
|
180
|
+
return value.replace(/\\/g, "\\\\").replace(/\r/g, "\\r").replace(/\n/g, "\\n").replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
|
|
181
|
+
}
|
|
182
|
+
function escQuoted(value) {
|
|
183
|
+
return value.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\r/g, "\\r").replace(/\n/g, "\\n").replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
|
|
184
|
+
}
|
|
185
|
+
function renderValue(value) {
|
|
186
|
+
if (value === void 0) return void 0;
|
|
187
|
+
if (value === null) return "null";
|
|
188
|
+
switch (typeof value) {
|
|
189
|
+
case "number":
|
|
190
|
+
case "boolean":
|
|
191
|
+
return String(value);
|
|
192
|
+
case "bigint":
|
|
193
|
+
return `${value}n`;
|
|
194
|
+
case "string":
|
|
195
|
+
return BARE_VALUE.test(value) ? value : `"${escQuoted(value)}"`;
|
|
196
|
+
case "object":
|
|
197
|
+
try {
|
|
198
|
+
return `"${escQuoted(JSON.stringify(value) ?? "null")}"`;
|
|
199
|
+
} catch {
|
|
200
|
+
return '"[unserialisable]"';
|
|
201
|
+
}
|
|
202
|
+
default:
|
|
203
|
+
try {
|
|
204
|
+
return `"${escQuoted(String(value))}"`;
|
|
205
|
+
} catch {
|
|
206
|
+
return '"[unrenderable]"';
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
function renderFields(fields) {
|
|
211
|
+
const pairs = [];
|
|
212
|
+
let err2;
|
|
213
|
+
for (const key of Object.keys(fields)) {
|
|
214
|
+
let value;
|
|
215
|
+
try {
|
|
216
|
+
value = fields[key];
|
|
217
|
+
} catch {
|
|
218
|
+
pairs.push(`${esc(key)}="[threw]"`);
|
|
219
|
+
continue;
|
|
220
|
+
}
|
|
221
|
+
if (key === "err") {
|
|
222
|
+
err2 = value;
|
|
223
|
+
continue;
|
|
224
|
+
}
|
|
225
|
+
const rendered = renderValue(value);
|
|
226
|
+
if (rendered !== void 0) pairs.push(`${esc(key)}=${rendered}`);
|
|
227
|
+
}
|
|
228
|
+
return { pairs, err: err2 };
|
|
229
|
+
}
|
|
230
|
+
function renderStack(stack) {
|
|
231
|
+
if (!stack) return "";
|
|
232
|
+
const lines = stack.split(LINE_TERMINATORS);
|
|
233
|
+
const firstFrame = lines.findIndex((line) => /^\s+at\s/.test(line));
|
|
234
|
+
const frames = firstFrame === -1 ? [] : lines.slice(firstFrame);
|
|
235
|
+
return frames.map((line) => LOG_CONTINUATION + esc(line.trim())).join("");
|
|
236
|
+
}
|
|
237
|
+
function renderError(value, depth = 0) {
|
|
238
|
+
if (!(value instanceof Error)) {
|
|
239
|
+
const rendered = renderValue(typeof value === "string" ? value : String(value));
|
|
240
|
+
return { pairs: [`err.msg=${rendered ?? '"[unrenderable]"'}`], lines: "" };
|
|
241
|
+
}
|
|
242
|
+
const pairs = [`err=${renderValue(value.name) ?? "Error"}`];
|
|
243
|
+
const message = renderValue(value.message);
|
|
244
|
+
if (message !== void 0) pairs.push(`err.msg=${message}`);
|
|
245
|
+
let lines = renderStack(value.stack);
|
|
246
|
+
if (depth < MAX_CAUSE_DEPTH && value.cause !== void 0 && value.cause !== null) {
|
|
247
|
+
const cause = renderError(value.cause, depth + 1);
|
|
248
|
+
lines += LOG_CONTINUATION + `cause: ${cause.pairs.join(" ")}` + cause.lines;
|
|
249
|
+
}
|
|
250
|
+
if (value instanceof AggregateError && Array.isArray(value.errors)) {
|
|
251
|
+
for (const inner of value.errors.slice(0, MAX_AGGREGATE_ERRORS)) {
|
|
252
|
+
const rendered = renderError(inner, MAX_CAUSE_DEPTH);
|
|
253
|
+
lines += LOG_CONTINUATION + `also: ${rendered.pairs.join(" ")}`;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
return { pairs, lines };
|
|
257
|
+
}
|
|
258
|
+
function formatLogArgs(args) {
|
|
259
|
+
const words = [];
|
|
260
|
+
const pairs = [];
|
|
261
|
+
let errorLines = "";
|
|
262
|
+
for (const arg of args) {
|
|
263
|
+
if (typeof arg === "string") {
|
|
264
|
+
words.push(esc(arg));
|
|
265
|
+
continue;
|
|
266
|
+
}
|
|
267
|
+
if (arg instanceof Error) {
|
|
268
|
+
const rendered2 = renderError(arg);
|
|
269
|
+
pairs.push(...rendered2.pairs);
|
|
270
|
+
errorLines += rendered2.lines;
|
|
271
|
+
continue;
|
|
272
|
+
}
|
|
273
|
+
if (arg !== null && typeof arg === "object" && !Array.isArray(arg)) {
|
|
274
|
+
const { pairs: fieldPairs, err: err2 } = renderFields(arg);
|
|
275
|
+
pairs.push(...fieldPairs);
|
|
276
|
+
if (err2 !== void 0) {
|
|
277
|
+
const rendered2 = renderError(err2);
|
|
278
|
+
pairs.push(...rendered2.pairs);
|
|
279
|
+
errorLines += rendered2.lines;
|
|
280
|
+
}
|
|
281
|
+
continue;
|
|
282
|
+
}
|
|
283
|
+
const rendered = renderValue(arg);
|
|
284
|
+
if (rendered !== void 0) words.push(rendered);
|
|
285
|
+
}
|
|
286
|
+
return [words.join(" "), ...pairs].filter((part) => part !== "").join(" ") + errorLines;
|
|
287
|
+
}
|
|
288
|
+
|
|
173
289
|
// src/logger.ts
|
|
174
290
|
var current = console;
|
|
175
291
|
function setLogger(logger) {
|
|
176
292
|
if (logger) current = logger;
|
|
177
293
|
}
|
|
178
|
-
function escapeLineBreaks(value) {
|
|
179
|
-
return value.replace(/\\/g, "\\\\").replace(/\r/g, "\\r").replace(/\n/g, "\\n").replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
|
|
180
|
-
}
|
|
181
|
-
function scrub(args) {
|
|
182
|
-
return args.map((arg) => typeof arg === "string" ? escapeLineBreaks(arg) : arg);
|
|
183
|
-
}
|
|
184
294
|
var log = {
|
|
185
|
-
info: (...args) => current.info(
|
|
186
|
-
warn: (...args) => current.warn(
|
|
187
|
-
error: (...args) => current.error(
|
|
295
|
+
info: (...args) => current.info(formatLogArgs(args)),
|
|
296
|
+
warn: (...args) => current.warn(formatLogArgs(args)),
|
|
297
|
+
error: (...args) => current.error(formatLogArgs(args))
|
|
188
298
|
};
|
|
189
299
|
|
|
190
300
|
// src/http.ts
|