@loggerjs/codecs 0.1.0 → 0.3.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.
package/README.md CHANGED
@@ -16,7 +16,7 @@ npm install @loggerjs/codecs
16
16
  ## Usage
17
17
 
18
18
  ```ts
19
- import { fastEventJsonCodec, projectorCodec } from "@loggerjs/codecs";
19
+ import { fastEventJsonCodec, pinoCompatCodec, projectorCodec } from "@loggerjs/codecs";
20
20
  import { nodeHttpTransport } from "@loggerjs/node";
21
21
 
22
22
  // The performance codec for JSON payload transports.
@@ -30,6 +30,12 @@ nodeHttpTransport({
30
30
  url: "https://collector.example/logs",
31
31
  codec: fastEventJsonCodec({ includeId: false, includeSeq: false, includeLevelName: false }),
32
32
  });
33
+
34
+ // Pino-shaped NDJSON for migration paths.
35
+ nodeHttpTransport({
36
+ url: "https://collector.example/logs",
37
+ codec: pinoCompatCodec({ base: { pid: process.pid, hostname: "api-1" }, mergeData: true }),
38
+ });
33
39
  ```
34
40
 
35
41
  ## Codecs
@@ -37,6 +43,7 @@ nodeHttpTransport({
37
43
  | Codec | Format | Notes |
38
44
  | --- | --- | --- |
39
45
  | `fastEventJsonCodec` | JSON | The performance codec — fragment-cached serialization, fast by default, falls back instead of throwing on circular references. Toggle envelope fields (`includeId`, `includeSeq`, `includeLevelName`) to trade detail for speed. |
46
+ | `pinoCompatCodec` / `pinoNdjsonProjector` | NDJSON | Encode-only Pino-shaped migration output with `level`, `time`, optional base fields, `msg`, `err`, and opt-in root data merging with reserved-key protection. |
40
47
  | `msgpackrCodec` | MessagePack (binary) | Compact binary encoding via [`msgpackr`](https://github.com/kriszyp/msgpackr); ideal for worker, WebSocket, and HTTP transports that accept binary payloads. |
41
48
  | `projectorCodec` | custom | Build a codec from a `project` step (shape the events) plus a `serialize` step (turn them into the wire payload). |
42
49
 
@@ -7,7 +7,7 @@ import { type Codec, type SafeStringifyOptions } from "@loggerjs/core";
7
7
  * everywhere, which also preserves `Error` name/message/stack inside data payloads.
8
8
  *
9
9
  * `includeId`, `includeSeq`, and `includeLevelName` trim the envelope for
10
- * pino-shaped minimal NDJSON output; turning `includeId` off also skips id
10
+ * lean comparable JSON output; turning `includeId` off also skips id
11
11
  * computation entirely on the record path.
12
12
  */
13
13
  export interface FastEventJsonCodecOptions extends SafeStringifyOptions {
@@ -1 +1 @@
1
- {"version":3,"file":"fast-event-json.d.ts","sourceRoot":"","sources":["../src/fast-event-json.ts"],"names":[],"mappings":"AAAA,OAAO,EAQL,KAAK,KAAK,EAIV,KAAK,oBAAoB,EAC1B,MAAM,gBAAgB,CAAC;AAExB;;;;;;;;;;GAUG;AACH,MAAM,WAAW,yBAA0B,SAAQ,oBAAoB;IACrE,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AA4RD,wBAAgB,kBAAkB,CAAC,OAAO,GAAE,yBAA8B,GAAG,KAAK,CAAC,MAAM,CAAC,CAoCzF"}
1
+ {"version":3,"file":"fast-event-json.d.ts","sourceRoot":"","sources":["../src/fast-event-json.ts"],"names":[],"mappings":"AAAA,OAAO,EAQL,KAAK,KAAK,EAMV,KAAK,oBAAoB,EAC1B,MAAM,gBAAgB,CAAC;AAExB;;;;;;;;;;GAUG;AACH,MAAM,WAAW,yBAA0B,SAAQ,oBAAoB;IACrE,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AA+WD,wBAAgB,kBAAkB,CAAC,OAAO,GAAE,yBAA8B,GAAG,KAAK,CAAC,MAAM,CAAC,CAiEzF"}
package/dist/index.cjs CHANGED
@@ -2,17 +2,30 @@ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
2
  let _loggerjs_core = require("@loggerjs/core");
3
3
  let msgpackr = require("msgpackr");
4
4
  //#region src/fast-event-json.ts
5
- function hasSafeOptions(options) {
5
+ function hasSafeOptions$1(options) {
6
6
  return options.maxDepth !== void 0 || options.maxArrayLength !== void 0 || options.maxObjectKeys !== void 0 || options.includeStack !== void 0 || options.stable !== void 0 || options.space !== void 0;
7
7
  }
8
8
  function canUseNativeEventJson(options) {
9
- return !hasSafeOptions(options) && options.includeContext !== false && options.includeData !== false && options.includeError !== false && options.includeTrace !== false && options.includeSource !== false && options.includeId !== false && options.includeSeq !== false && options.includeLevelName !== false;
9
+ return !hasSafeOptions$1(options) && options.includeContext !== false && options.includeData !== false && options.includeError !== false && options.includeTrace !== false && options.includeSource !== false && options.includeId !== false && options.includeSeq !== false && options.includeLevelName !== false;
10
10
  }
11
11
  function hasFullHeader(options) {
12
12
  return (options.includeId ?? true) && (options.includeSeq ?? true) && (options.includeLevelName ?? true);
13
13
  }
14
+ function resolveFlags(options) {
15
+ return {
16
+ fullHeader: hasFullHeader(options),
17
+ includeId: options.includeId ?? true,
18
+ includeSeq: options.includeSeq ?? true,
19
+ includeLevelName: options.includeLevelName ?? true,
20
+ includeData: options.includeData ?? true,
21
+ includeError: options.includeError ?? true,
22
+ includeContext: options.includeContext ?? true,
23
+ includeTrace: options.includeTrace ?? true,
24
+ includeSource: options.includeSource ?? true
25
+ };
26
+ }
14
27
  function createStringify(options) {
15
- if (hasSafeOptions(options)) return (value) => (0, _loggerjs_core.safeJsonStringify)(value, options);
28
+ if (hasSafeOptions$1(options)) return (value) => (0, _loggerjs_core.safeJsonStringify)(value, options);
16
29
  return JSON.stringify;
17
30
  }
18
31
  function appendField(output, name, value, stringify) {
@@ -95,57 +108,68 @@ function errorForRecord(record) {
95
108
  if (record.err === null || record.err === void 0) return void 0;
96
109
  return (0, _loggerjs_core.normalizeError)(record.err);
97
110
  }
98
- function encodeEvent(event, options, stringify, tagsFragment) {
111
+ function tryPrepareTagsFragment(tags, tagsFragment) {
112
+ if (tags === null || !Object.isFrozen(tags)) return void 0;
113
+ try {
114
+ return tagsFragment(tags);
115
+ } catch {
116
+ return;
117
+ }
118
+ }
119
+ function loggerFragmentForRecord(record, prepared) {
120
+ if (prepared && record.category === prepared.category) return prepared.logger;
121
+ return loggerFragment(record.category);
122
+ }
123
+ function tagsFragmentForRecord(record, tagsFragment, prepared) {
124
+ if (record.tags === null) return "";
125
+ if (prepared && record.tags === prepared.tags && prepared.tagsFragment !== void 0) return prepared.tagsFragment;
126
+ return tagsFragment(record.tags);
127
+ }
128
+ function encodeEvent(event, flags, stringify, tagsFragment) {
99
129
  let output;
100
- if (hasFullHeader(options)) output = `{"id":${asJsonString(event.id)},"time":${event.time},"seq":${event.seq},"level":${event.level},"levelName":${asJsonString(event.levelName)},"logger":${asJsonString(event.logger)},"message":${asJsonString(event.message)}`;
130
+ if (flags.fullHeader) output = `{"id":${asJsonString(event.id)},"time":${event.time},"seq":${event.seq},"level":${event.level},"levelName":${asJsonString(event.levelName)},"logger":${asJsonString(event.logger)},"message":${asJsonString(event.message)}`;
101
131
  else {
102
- output = "{";
103
- if (options.includeId ?? true) output += `"id":${asJsonString(event.id)},`;
104
- output += `"time":${event.time}`;
105
- if (options.includeSeq ?? true) output += `,"seq":${event.seq}`;
106
- output += `,"level":${event.level}`;
107
- if (options.includeLevelName ?? true) output += `,"levelName":${asJsonString(event.levelName)}`;
108
- output += `,"logger":${asJsonString(event.logger)},"message":${asJsonString(event.message)}`;
132
+ const idPart = flags.includeId ? `"id":${asJsonString(event.id)},` : "";
133
+ const seqPart = flags.includeSeq ? `,"seq":${event.seq}` : "";
134
+ const levelNamePart = flags.includeLevelName ? `,"levelName":${asJsonString(event.levelName)}` : "";
135
+ output = `{${idPart}"time":${event.time}${seqPart},"level":${event.level}${levelNamePart},"logger":${asJsonString(event.logger)},"message":${asJsonString(event.message)}`;
109
136
  }
110
137
  if (event.type !== void 0) output += `,"type":${asJsonString(event.type)}`;
111
138
  if (event.tags !== void 0) output += tagsFragment(event.tags);
112
- if (options.includeData ?? true) output = appendField(output, "data", event.data, stringify);
113
- if (options.includeError ?? true) output = appendField(output, "error", event.error, stringify);
114
- if (options.includeContext ?? true) output = appendField(output, "context", event.context, stringify);
115
- if (options.includeTrace ?? true) output = appendField(output, "trace", event.trace, stringify);
116
- if (options.includeSource ?? true) output = appendField(output, "source", event.source, stringify);
139
+ if (flags.includeData && event.data !== void 0) output = appendField(output, "data", event.data, stringify);
140
+ if (flags.includeError && event.error !== void 0) output = appendField(output, "error", event.error, stringify);
141
+ if (flags.includeContext && event.context !== void 0) output = appendField(output, "context", event.context, stringify);
142
+ if (flags.includeTrace && event.trace !== void 0) output = appendField(output, "trace", event.trace, stringify);
143
+ if (flags.includeSource && event.source !== void 0) output = appendField(output, "source", event.source, stringify);
117
144
  return `${output}}`;
118
145
  }
119
- function encodeRecord(record, options, stringify, tagsFragment) {
120
- const levelName = (0, _loggerjs_core.toLevelName)(record.level);
146
+ function encodeRecord(record, flags, stringify, tagsFragment, prepared) {
121
147
  let output;
122
- if (hasFullHeader(options)) output = `{"id":"${(0, _loggerjs_core.defaultRecordId)(record, levelName)}${timeFragment(record.time)}${record.seq}${levelFragment(record.level)}${loggerFragment(record.category)},"message":${asJsonString((0, _loggerjs_core.resolveMessage)(record))}`;
148
+ if (flags.fullHeader) output = `{"id":"${(0, _loggerjs_core.defaultRecordId)(record, (0, _loggerjs_core.toLevelName)(record.level))}${timeFragment(record.time)}${record.seq}${levelFragment(record.level)}${loggerFragmentForRecord(record, prepared)},"message":${asJsonString((0, _loggerjs_core.resolveMessage)(record))}`;
123
149
  else {
124
- output = "{";
125
- if (options.includeId ?? true) output += `"id":"${(0, _loggerjs_core.defaultRecordId)(record, levelName)}",`;
126
- output += `"time":${record.time}`;
127
- if (options.includeSeq ?? true) output += `,"seq":${record.seq}`;
128
- output += `,"level":${record.level}`;
129
- if (options.includeLevelName ?? true) output += `,"levelName":"${levelName}"`;
130
- output += `,"logger":${loggerFragment(record.category)},"message":${asJsonString((0, _loggerjs_core.resolveMessage)(record))}`;
150
+ const levelName = flags.includeId || flags.includeLevelName ? (0, _loggerjs_core.toLevelName)(record.level) : "info";
151
+ const idPart = flags.includeId ? `"id":"${(0, _loggerjs_core.defaultRecordId)(record, levelName)}",` : "";
152
+ const seqPart = flags.includeSeq ? `,"seq":${record.seq}` : "";
153
+ const levelNamePart = flags.includeLevelName ? `,"levelName":"${levelName}"` : "";
154
+ output = `{${idPart}"time":${record.time}${seqPart},"level":${record.level}${levelNamePart},"logger":${loggerFragmentForRecord(record, prepared)},"message":${asJsonString((0, _loggerjs_core.resolveMessage)(record))}`;
131
155
  }
132
156
  if (record.type !== null) output += `,"type":${asJsonString(record.type)}`;
133
- if (record.tags !== null) output += tagsFragment(record.tags);
134
- if (options.includeData ?? true) output = appendDataField(output, record.props ?? void 0, stringify);
135
- if (options.includeError ?? true) output = appendField(output, "error", errorForRecord(record), stringify);
136
- if (options.includeContext ?? true) output = appendField(output, "context", record.ctx ?? void 0, stringify);
137
- if (options.includeTrace ?? true) output = appendField(output, "trace", record.trace ?? void 0, stringify);
138
- if ((options.includeSource ?? true) && record.source !== "app") output += `,"source":{"integration":${asJsonString(record.source)}}`;
157
+ output += tagsFragmentForRecord(record, tagsFragment, prepared);
158
+ if (flags.includeData && record.props != null) output = appendDataField(output, record.props, stringify);
159
+ if (flags.includeError && record.err != null) output = appendField(output, "error", errorForRecord(record), stringify);
160
+ if (flags.includeContext && record.ctx != null) output = appendField(output, "context", record.ctx, stringify);
161
+ if (flags.includeTrace && record.trace != null) output = appendField(output, "trace", record.trace, stringify);
162
+ if (flags.includeSource && record.source !== "app") output += `,"source":{"integration":${asJsonString(record.source)}}`;
139
163
  return `${output}}`;
140
164
  }
141
- function encodeItem(item, options, stringify, tagsFragment) {
142
- return (0, _loggerjs_core.isLogRecord)(item) ? encodeRecord(item, options, stringify, tagsFragment) : encodeEvent(item, options, stringify, tagsFragment);
165
+ function encodeItem(item, flags, stringify, tagsFragment) {
166
+ return (0, _loggerjs_core.isLogRecord)(item) ? encodeRecord(item, flags, stringify, tagsFragment) : encodeEvent(item, flags, stringify, tagsFragment);
143
167
  }
144
- function encodeArray(items, options, stringify, tagsFragment) {
168
+ function encodeArray(items, flags, stringify, tagsFragment) {
145
169
  let output = "[";
146
170
  for (let index = 0; index < items.length; index += 1) {
147
171
  if (index > 0) output += ",";
148
- output += encodeItem(items[index], options, stringify, tagsFragment);
172
+ output += encodeItem(items[index], flags, stringify, tagsFragment);
149
173
  }
150
174
  return `${output}]`;
151
175
  }
@@ -176,15 +200,17 @@ function fastEventJsonCodec(options = {}) {
176
200
  const stringify = createStringify(options);
177
201
  const safeStringify = (value) => (0, _loggerjs_core.safeJsonStringify)(value, options);
178
202
  const useNativeEventJson = canUseNativeEventJson(options);
203
+ const flags = resolveFlags(options);
179
204
  const tagsFragment = createTagsFragment(stringify, true);
180
205
  const safeTagsFragment = createTagsFragment(safeStringify, false);
181
206
  const fastEncode = (input) => {
182
207
  if (isCodecArray(input)) {
183
208
  if (useNativeEventJson && !hasLogRecord(input)) return JSON.stringify(input);
184
- return encodeArray(input, options, stringify, tagsFragment);
209
+ return encodeArray(input, flags, stringify, tagsFragment);
185
210
  }
186
- if (useNativeEventJson && !(0, _loggerjs_core.isLogRecord)(input)) return JSON.stringify(input);
187
- return encodeItem(input, options, stringify, tagsFragment);
211
+ if ((0, _loggerjs_core.isLogRecord)(input)) return encodeRecord(input, flags, stringify, tagsFragment);
212
+ if (useNativeEventJson) return JSON.stringify(input);
213
+ return encodeEvent(input, flags, stringify, tagsFragment);
188
214
  };
189
215
  return {
190
216
  name: "fast-event-json",
@@ -196,11 +222,32 @@ function fastEventJsonCodec(options = {}) {
196
222
  (0, _loggerjs_core.incrementLoggerMetaCounter)("codec.fallback");
197
223
  (0, _loggerjs_core.incrementLoggerMetaCounter)("codec.fallback.fast-event-json");
198
224
  }
199
- if (isCodecArray(input)) return encodeArray(input, options, safeStringify, safeTagsFragment);
200
- return encodeItem(input, options, safeStringify, safeTagsFragment);
225
+ if (isCodecArray(input)) return encodeArray(input, flags, safeStringify, safeTagsFragment);
226
+ return encodeItem(input, flags, safeStringify, safeTagsFragment);
201
227
  },
202
228
  decode(payload) {
203
229
  return JSON.parse(payload);
230
+ },
231
+ prepareRecordEncoder(hints) {
232
+ const prepared = {
233
+ category: hints.category,
234
+ logger: loggerFragment(hints.category),
235
+ tags: hints.tags,
236
+ tagsFragment: tryPrepareTagsFragment(hints.tags, tagsFragment)
237
+ };
238
+ return { encode(record) {
239
+ try {
240
+ return encodeRecord(record, flags, stringify, tagsFragment, prepared);
241
+ } catch {
242
+ (0, _loggerjs_core.incrementLoggerMetaCounter)("codec.fallback");
243
+ (0, _loggerjs_core.incrementLoggerMetaCounter)("codec.fallback.fast-event-json");
244
+ }
245
+ return encodeRecord(record, flags, safeStringify, safeTagsFragment, {
246
+ category: prepared.category,
247
+ logger: prepared.logger,
248
+ tags: prepared.tags
249
+ });
250
+ } };
204
251
  }
205
252
  };
206
253
  }
@@ -226,6 +273,113 @@ function msgpackrCodec(options = {}) {
226
273
  };
227
274
  }
228
275
  //#endregion
276
+ //#region src/pino-compat.ts
277
+ const baseReservedRootKeys = new Set([
278
+ "time",
279
+ "level",
280
+ "msg",
281
+ "err",
282
+ "logger",
283
+ "data"
284
+ ]);
285
+ const dataReservedRootKeys = new Set([
286
+ "time",
287
+ "level",
288
+ "msg",
289
+ "pid",
290
+ "hostname",
291
+ "err",
292
+ "logger",
293
+ "data"
294
+ ]);
295
+ function hasSafeOptions(options) {
296
+ return options.maxDepth !== void 0 || options.maxArrayLength !== void 0 || options.maxObjectKeys !== void 0 || options.includeStack !== void 0 || options.stable !== void 0 || options.space !== void 0;
297
+ }
298
+ function isRecord(value) {
299
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
300
+ }
301
+ function pinoError(error) {
302
+ return {
303
+ type: error.name ?? "Error",
304
+ message: error.message,
305
+ stack: error.stack,
306
+ code: error.code,
307
+ cause: error.cause
308
+ };
309
+ }
310
+ function assignWithCollision(output, nested, key, value, policy, reservedKeys = dataReservedRootKeys) {
311
+ if (!reservedKeys.has(key) && !(key in output)) {
312
+ output[key] = value;
313
+ return;
314
+ }
315
+ if (policy === "throw") throw new Error(`pinoCompatCodec cannot merge reserved key "${key}"`);
316
+ if (policy === "nest") nested[key] = value;
317
+ }
318
+ function mergeNestedData(existing, nested) {
319
+ if (isRecord(existing)) return {
320
+ ...nested,
321
+ ...existing
322
+ };
323
+ if (existing !== void 0) return {
324
+ ...nested,
325
+ value: existing
326
+ };
327
+ return nested;
328
+ }
329
+ function projectEvent(event, options) {
330
+ const dataKey = options.dataKey ?? "data";
331
+ const errorKey = options.errorKey ?? "err";
332
+ const collision = options.collision ?? "nest";
333
+ const output = {
334
+ level: event.level,
335
+ time: event.time
336
+ };
337
+ const nested = {};
338
+ const baseReservedKeys = new Set(baseReservedRootKeys);
339
+ baseReservedKeys.add(dataKey);
340
+ baseReservedKeys.add(errorKey);
341
+ for (const [key, value] of Object.entries(options.base ?? {})) assignWithCollision(output, nested, key, value, collision, baseReservedKeys);
342
+ if (options.includeLogger) output.logger = event.logger;
343
+ if (event.error) output[errorKey] = pinoError(event.error);
344
+ if (event.data !== void 0) if (options.mergeData && isRecord(event.data)) {
345
+ const dataReservedKeys = new Set(dataReservedRootKeys);
346
+ dataReservedKeys.add(dataKey);
347
+ dataReservedKeys.add(errorKey);
348
+ for (const [key, value] of Object.entries(event.data)) assignWithCollision(output, nested, key, value, collision, dataReservedKeys);
349
+ } else output[dataKey] = event.data;
350
+ if (Object.keys(nested).length > 0) output[dataKey] = mergeNestedData(output[dataKey], nested);
351
+ output.msg = event.message;
352
+ return output;
353
+ }
354
+ function encodeLine(event, options, safeMode) {
355
+ const projected = projectEvent(event, options);
356
+ if (safeMode) return (0, _loggerjs_core.safeJsonStringify)(projected, options);
357
+ try {
358
+ return JSON.stringify(projected) ?? "{}";
359
+ } catch {
360
+ (0, _loggerjs_core.incrementLoggerMetaCounter)("codec.fallback");
361
+ (0, _loggerjs_core.incrementLoggerMetaCounter)("codec.fallback.pino-compat");
362
+ return (0, _loggerjs_core.safeJsonStringify)(projected, options);
363
+ }
364
+ }
365
+ function encodeEvents(input, options, safeMode) {
366
+ if (!Array.isArray(input)) return `${encodeLine(input, options, safeMode)}\n`;
367
+ let output = "";
368
+ for (const event of input) output += `${encodeLine(event, options, safeMode)}\n`;
369
+ return output;
370
+ }
371
+ function pinoCompatCodec(options = {}) {
372
+ const safeMode = hasSafeOptions(options);
373
+ return {
374
+ name: "pino-compat",
375
+ contentType: "application/x-ndjson",
376
+ encode(input) {
377
+ return encodeEvents((0, _loggerjs_core.normalizeCodecInput)(input), options, safeMode);
378
+ }
379
+ };
380
+ }
381
+ const pinoNdjsonProjector = pinoCompatCodec;
382
+ //#endregion
229
383
  //#region src/projector.ts
230
384
  function projectorCodec(options) {
231
385
  return {
@@ -240,6 +394,8 @@ function projectorCodec(options) {
240
394
  //#endregion
241
395
  exports.fastEventJsonCodec = fastEventJsonCodec;
242
396
  exports.msgpackrCodec = msgpackrCodec;
397
+ exports.pinoCompatCodec = pinoCompatCodec;
398
+ exports.pinoNdjsonProjector = pinoNdjsonProjector;
243
399
  exports.projectorCodec = projectorCodec;
244
400
  Object.keys(_loggerjs_core).forEach(function(k) {
245
401
  if (k !== "default" && !Object.prototype.hasOwnProperty.call(exports, k)) Object.defineProperty(exports, k, {
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","names":["Packr"],"sources":["../src/fast-event-json.ts","../src/msgpackr.ts","../src/projector.ts"],"sourcesContent":["import {\n defaultRecordId,\n incrementLoggerMetaCounter,\n isLogRecord,\n normalizeError,\n resolveMessage,\n toLevelName,\n safeJsonStringify,\n type Codec,\n type CodecInput,\n type LogEvent,\n type LogRecord,\n type SafeStringifyOptions,\n} from \"@loggerjs/core\";\n\n/**\n * Without any option set, encode runs on a native `JSON.stringify` fast path: nested\n * `Error` values serialize as `{}` and circular or BigInt payloads trigger a safe\n * re-encode of the whole input (circular refs become \"[Circular]\", BigInt becomes a\n * string). Setting any {@link SafeStringifyOptions} field opts into the safe encoder\n * everywhere, which also preserves `Error` name/message/stack inside data payloads.\n *\n * `includeId`, `includeSeq`, and `includeLevelName` trim the envelope for\n * pino-shaped minimal NDJSON output; turning `includeId` off also skips id\n * computation entirely on the record path.\n */\nexport interface FastEventJsonCodecOptions extends SafeStringifyOptions {\n includeContext?: boolean;\n includeData?: boolean;\n includeError?: boolean;\n includeTrace?: boolean;\n includeSource?: boolean;\n includeId?: boolean;\n includeSeq?: boolean;\n includeLevelName?: boolean;\n}\n\ntype JsonStringify = (value: unknown) => string | undefined;\n\nfunction hasSafeOptions(options: SafeStringifyOptions): boolean {\n return (\n options.maxDepth !== undefined ||\n options.maxArrayLength !== undefined ||\n options.maxObjectKeys !== undefined ||\n options.includeStack !== undefined ||\n options.stable !== undefined ||\n options.space !== undefined\n );\n}\n\nfunction canUseNativeEventJson(options: FastEventJsonCodecOptions): boolean {\n return (\n !hasSafeOptions(options) &&\n options.includeContext !== false &&\n options.includeData !== false &&\n options.includeError !== false &&\n options.includeTrace !== false &&\n options.includeSource !== false &&\n options.includeId !== false &&\n options.includeSeq !== false &&\n options.includeLevelName !== false\n );\n}\n\nfunction hasFullHeader(options: FastEventJsonCodecOptions): boolean {\n return (\n (options.includeId ?? true) &&\n (options.includeSeq ?? true) &&\n (options.includeLevelName ?? true)\n );\n}\n\nfunction createStringify(options: SafeStringifyOptions): JsonStringify {\n if (hasSafeOptions(options)) return (value) => safeJsonStringify(value, options);\n return JSON.stringify;\n}\n\nfunction appendField(\n output: string,\n name: string,\n value: unknown,\n stringify: JsonStringify,\n): string {\n if (value === undefined) return output;\n const encoded = stringify(value);\n return encoded === undefined ? output : `${output},\"${name}\":${encoded}`;\n}\n\n// JSON.stringify costs ~35ns per short string mostly in call overhead. Short\n// strings without quotes, backslashes, or control characters can be quoted\n// directly after a linear scan.\nfunction asJsonString(value: string): string {\n if (value.length > 256) return JSON.stringify(value);\n for (let index = 0; index < value.length; index += 1) {\n const code = value.charCodeAt(index);\n if (code === 34 || code === 92 || code < 32) return JSON.stringify(value);\n }\n return `\"${value}\"`;\n}\n\n// Data payloads are usually small flat objects of primitives. Writing them\n// directly skips the native JSON.stringify call overhead; any nested or\n// exotic value bails out so the caller can use the configured stringifier.\nfunction tryFlatObjectJson(value: Record<string, unknown>): string | undefined {\n // Class instances may carry toJSON or accessors; only plain objects take\n // the fast path so behavior matches JSON.stringify.\n const proto = Object.getPrototypeOf(value) as unknown;\n if (proto !== Object.prototype && proto !== null) return undefined;\n let output = \"{\";\n let first = true;\n for (const key of Object.keys(value)) {\n const item = value[key];\n let encoded: string;\n switch (typeof item) {\n case \"string\":\n encoded = asJsonString(item);\n break;\n case \"number\":\n encoded = Number.isFinite(item) ? String(item) : \"null\";\n break;\n case \"boolean\":\n encoded = item ? \"true\" : \"false\";\n break;\n case \"object\":\n if (item !== null) return undefined;\n encoded = \"null\";\n break;\n case \"undefined\":\n continue;\n default:\n return undefined;\n }\n output += `${first ? \"\" : \",\"}${asJsonString(key)}:${encoded}`;\n first = false;\n }\n return `${output}}`;\n}\n\nfunction appendDataField(\n output: string,\n value: Record<string, unknown> | undefined,\n stringify: JsonStringify,\n): string {\n if (value === undefined) return output;\n const flat = tryFlatObjectJson(value);\n if (flat !== undefined) return `${output},\"data\":${flat}`;\n return appendField(output, \"data\", value, stringify);\n}\n\n// The timestamp changes once per millisecond while bursts of records share\n// it, so the rendered `\",\"time\":...,\"seq\":` fragment can be memoized the same\n// way the default id memoizes its time segment.\nlet lastFragmentTime = -1;\nlet lastTimeFragment = \"\";\n\nfunction timeFragment(time: number): string {\n if (time !== lastFragmentTime) {\n lastFragmentTime = time;\n lastTimeFragment = `\",\"time\":${time},\"seq\":`;\n }\n return lastTimeFragment;\n}\n\n// level -> ',\"level\":30,\"levelName\":\"info\",\"logger\":' — derived from the\n// numeric level alone, so a module-level cache is safe.\nconst levelFragments = new Map<number, string>();\n\nfunction levelFragment(level: number): string {\n let fragment = levelFragments.get(level);\n if (fragment === undefined) {\n fragment = `,\"level\":${level},\"levelName\":\"${toLevelName(level)}\",\"logger\":`;\n levelFragments.set(level, fragment);\n }\n return fragment;\n}\n\n// Loggers reuse one frozen category array for every record, so the joined and\n// escaped logger name can be cached per array identity.\nconst categoryFragments = new WeakMap<readonly string[], string>();\n\nfunction loggerFragment(category: readonly string[]): string {\n let fragment = categoryFragments.get(category);\n if (fragment === undefined) {\n fragment = asJsonString(category.join(\".\"));\n categoryFragments.set(category, fragment);\n }\n return fragment;\n}\n\nfunction errorForRecord(record: LogRecord): LogEvent[\"error\"] | undefined {\n if (record.err === null || record.err === undefined) return undefined;\n return normalizeError(record.err);\n}\n\nfunction encodeEvent(\n event: LogEvent,\n options: FastEventJsonCodecOptions,\n stringify: JsonStringify,\n tagsFragment: (tags: NonNullable<LogEvent[\"tags\"]>) => string,\n): string {\n let output: string;\n if (hasFullHeader(options)) {\n output = `{\"id\":${asJsonString(event.id)},\"time\":${event.time},\"seq\":${event.seq},\"level\":${event.level},\"levelName\":${asJsonString(event.levelName)},\"logger\":${asJsonString(event.logger)},\"message\":${asJsonString(event.message)}`;\n } else {\n output = \"{\";\n if (options.includeId ?? true) output += `\"id\":${asJsonString(event.id)},`;\n output += `\"time\":${event.time}`;\n if (options.includeSeq ?? true) output += `,\"seq\":${event.seq}`;\n output += `,\"level\":${event.level}`;\n if (options.includeLevelName ?? true) output += `,\"levelName\":${asJsonString(event.levelName)}`;\n output += `,\"logger\":${asJsonString(event.logger)},\"message\":${asJsonString(event.message)}`;\n }\n if (event.type !== undefined) output += `,\"type\":${asJsonString(event.type)}`;\n if (event.tags !== undefined) output += tagsFragment(event.tags);\n if (options.includeData ?? true) output = appendField(output, \"data\", event.data, stringify);\n if (options.includeError ?? true) output = appendField(output, \"error\", event.error, stringify);\n if (options.includeContext ?? true)\n output = appendField(output, \"context\", event.context, stringify);\n if (options.includeTrace ?? true) output = appendField(output, \"trace\", event.trace, stringify);\n if (options.includeSource ?? true)\n output = appendField(output, \"source\", event.source, stringify);\n return `${output}}`;\n}\n\nfunction encodeRecord(\n record: LogRecord,\n options: FastEventJsonCodecOptions,\n stringify: JsonStringify,\n tagsFragment: (tags: NonNullable<LogRecord[\"tags\"]>) => string,\n): string {\n const levelName = toLevelName(record.level);\n let output: string;\n if (hasFullHeader(options)) {\n // The default id only contains [0-9a-z-] and the level name, so it never\n // needs escaping.\n output = `{\"id\":\"${defaultRecordId(record, levelName)}${timeFragment(record.time)}${record.seq}${levelFragment(record.level)}${loggerFragment(record.category)},\"message\":${asJsonString(resolveMessage(record))}`;\n } else {\n output = \"{\";\n if (options.includeId ?? true) output += `\"id\":\"${defaultRecordId(record, levelName)}\",`;\n output += `\"time\":${record.time}`;\n if (options.includeSeq ?? true) output += `,\"seq\":${record.seq}`;\n output += `,\"level\":${record.level}`;\n if (options.includeLevelName ?? true) output += `,\"levelName\":\"${levelName}\"`;\n output += `,\"logger\":${loggerFragment(record.category)},\"message\":${asJsonString(resolveMessage(record))}`;\n }\n if (record.type !== null) output += `,\"type\":${asJsonString(record.type)}`;\n if (record.tags !== null) output += tagsFragment(record.tags);\n if (options.includeData ?? true)\n output = appendDataField(output, record.props ?? undefined, stringify);\n if (options.includeError ?? true)\n output = appendField(output, \"error\", errorForRecord(record), stringify);\n if (options.includeContext ?? true)\n output = appendField(output, \"context\", record.ctx ?? undefined, stringify);\n if (options.includeTrace ?? true)\n output = appendField(output, \"trace\", record.trace ?? undefined, stringify);\n if ((options.includeSource ?? true) && record.source !== \"app\")\n output += `,\"source\":{\"integration\":${asJsonString(record.source)}}`;\n return `${output}}`;\n}\n\ntype TagsFragment = (tags: NonNullable<LogEvent[\"tags\"]>) => string;\n\nfunction encodeItem(\n item: LogEvent | LogRecord,\n options: FastEventJsonCodecOptions,\n stringify: JsonStringify,\n tagsFragment: TagsFragment,\n): string {\n return isLogRecord(item)\n ? encodeRecord(item, options, stringify, tagsFragment)\n : encodeEvent(item, options, stringify, tagsFragment);\n}\n\nfunction encodeArray(\n items: readonly (LogEvent | LogRecord)[],\n options: FastEventJsonCodecOptions,\n stringify: JsonStringify,\n tagsFragment: TagsFragment,\n): string {\n let output = \"[\";\n for (let index = 0; index < items.length; index += 1) {\n if (index > 0) output += \",\";\n output += encodeItem(items[index]!, options, stringify, tagsFragment);\n }\n return `${output}]`;\n}\n\nfunction isCodecArray(input: CodecInput): input is readonly (LogEvent | LogRecord)[] {\n return Array.isArray(input);\n}\n\nfunction hasLogRecord(items: readonly (LogEvent | LogRecord)[]): boolean {\n for (const item of items) {\n if (isLogRecord(item)) return true;\n }\n return false;\n}\n\n// Loggers share one frozen tags object across records, so the encoded\n// fragment can be cached per object identity. Mutable tags objects are\n// re-encoded every time. Callers create one fragment encoder per codec\n// because it bakes in that codec's stringify options.\nfunction createTagsFragment(encoder: JsonStringify, cached: boolean): TagsFragment {\n const fragments = cached ? new WeakMap<object, string>() : undefined;\n return (tags) => {\n if (fragments && Object.isFrozen(tags)) {\n let fragment = fragments.get(tags);\n if (fragment === undefined) {\n const encoded = encoder(tags);\n fragment = encoded === undefined ? \"\" : `,\"tags\":${encoded}`;\n fragments.set(tags, fragment);\n }\n return fragment;\n }\n const encoded = encoder(tags);\n return encoded === undefined ? \"\" : `,\"tags\":${encoded}`;\n };\n}\n\nexport function fastEventJsonCodec(options: FastEventJsonCodecOptions = {}): Codec<string> {\n const stringify = createStringify(options);\n const safeStringify: JsonStringify = (value) => safeJsonStringify(value, options);\n const useNativeEventJson = canUseNativeEventJson(options);\n const tagsFragment = createTagsFragment(stringify, true);\n // The fallback must not reuse the fast fragments: a cached entry or the\n // fast stringify could throw on the exact payload that triggered fallback.\n const safeTagsFragment = createTagsFragment(safeStringify, false);\n const fastEncode = (input: CodecInput): string => {\n if (isCodecArray(input)) {\n if (useNativeEventJson && !hasLogRecord(input)) return JSON.stringify(input);\n return encodeArray(input, options, stringify, tagsFragment);\n }\n if (useNativeEventJson && !isLogRecord(input)) return JSON.stringify(input);\n return encodeItem(input, options, stringify, tagsFragment);\n };\n return {\n name: \"fast-event-json\",\n contentType: \"application/json\",\n encode(input: CodecInput) {\n // Circular references and BigInt values throw on the native fast path. Logs\n // must never be lost to encoding, so re-encode the input with the safe\n // stringifier instead of surfacing the error as a transport failure.\n try {\n return fastEncode(input);\n } catch {\n incrementLoggerMetaCounter(\"codec.fallback\");\n incrementLoggerMetaCounter(\"codec.fallback.fast-event-json\");\n }\n if (isCodecArray(input)) return encodeArray(input, options, safeStringify, safeTagsFragment);\n return encodeItem(input, options, safeStringify, safeTagsFragment);\n },\n decode(payload) {\n return JSON.parse(payload) as LogEvent | LogEvent[];\n },\n };\n}\n","import { normalizeCodecInput, type Codec, type CodecInput, type LogEvent } from \"@loggerjs/core\";\nimport { Packr, type Options as MsgpackrOptions } from \"msgpackr\";\n\nexport interface MsgpackRuntime {\n pack: (input: unknown) => Uint8Array;\n unpack: (payload: Uint8Array) => unknown;\n}\n\nexport type MsgpackrCodecOptions = MsgpackrOptions;\n\nfunction isMsgpackRuntime(value: MsgpackRuntime | MsgpackrCodecOptions): value is MsgpackRuntime {\n return (\n typeof (value as MsgpackRuntime).pack === \"function\" &&\n typeof (value as MsgpackRuntime).unpack === \"function\"\n );\n}\n\nexport function msgpackrCodec(\n options: MsgpackRuntime | MsgpackrCodecOptions = {},\n): Codec<Uint8Array> {\n const runtime = isMsgpackRuntime(options) ? options : new Packr({ useRecords: true, ...options });\n return {\n name: \"msgpackr\",\n contentType: \"application/msgpack\",\n encode(input: CodecInput) {\n return runtime.pack(normalizeCodecInput(input));\n },\n decode(payload: Uint8Array) {\n return runtime.unpack(payload) as LogEvent | LogEvent[];\n },\n };\n}\n","import { normalizeCodecInput, type Codec, type CodecInput, type LogEvent } from \"@loggerjs/core\";\n\nexport interface ProjectorCodecOptions<TWire> {\n name: string;\n contentType: string;\n project: (input: LogEvent | LogEvent[]) => TWire;\n serialize: (wire: TWire) => string | Uint8Array;\n parse?: (payload: string | Uint8Array) => TWire;\n unproject?: (wire: TWire) => LogEvent | LogEvent[];\n}\n\nexport function projectorCodec<TWire>(\n options: ProjectorCodecOptions<TWire>,\n): Codec<string | Uint8Array> {\n return {\n name: options.name,\n contentType: options.contentType,\n encode(input: CodecInput) {\n return options.serialize(options.project(normalizeCodecInput(input)));\n },\n decode:\n options.parse && options.unproject\n ? (payload) => options.unproject!(options.parse!(payload))\n : undefined,\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.cjs","names":["hasSafeOptions","Packr"],"sources":["../src/fast-event-json.ts","../src/msgpackr.ts","../src/pino-compat.ts","../src/projector.ts"],"sourcesContent":["import {\n defaultRecordId,\n incrementLoggerMetaCounter,\n isLogRecord,\n normalizeError,\n resolveMessage,\n toLevelName,\n safeJsonStringify,\n type Codec,\n type CodecInput,\n type PreparedRecordEncoder,\n type LogEvent,\n type LogRecord,\n type RecordEncoderHints,\n type SafeStringifyOptions,\n} from \"@loggerjs/core\";\n\n/**\n * Without any option set, encode runs on a native `JSON.stringify` fast path: nested\n * `Error` values serialize as `{}` and circular or BigInt payloads trigger a safe\n * re-encode of the whole input (circular refs become \"[Circular]\", BigInt becomes a\n * string). Setting any {@link SafeStringifyOptions} field opts into the safe encoder\n * everywhere, which also preserves `Error` name/message/stack inside data payloads.\n *\n * `includeId`, `includeSeq`, and `includeLevelName` trim the envelope for\n * lean comparable JSON output; turning `includeId` off also skips id\n * computation entirely on the record path.\n */\nexport interface FastEventJsonCodecOptions extends SafeStringifyOptions {\n includeContext?: boolean;\n includeData?: boolean;\n includeError?: boolean;\n includeTrace?: boolean;\n includeSource?: boolean;\n includeId?: boolean;\n includeSeq?: boolean;\n includeLevelName?: boolean;\n}\n\ntype JsonStringify = (value: unknown) => string | undefined;\n\nfunction hasSafeOptions(options: SafeStringifyOptions): boolean {\n return (\n options.maxDepth !== undefined ||\n options.maxArrayLength !== undefined ||\n options.maxObjectKeys !== undefined ||\n options.includeStack !== undefined ||\n options.stable !== undefined ||\n options.space !== undefined\n );\n}\n\nfunction canUseNativeEventJson(options: FastEventJsonCodecOptions): boolean {\n return (\n !hasSafeOptions(options) &&\n options.includeContext !== false &&\n options.includeData !== false &&\n options.includeError !== false &&\n options.includeTrace !== false &&\n options.includeSource !== false &&\n options.includeId !== false &&\n options.includeSeq !== false &&\n options.includeLevelName !== false\n );\n}\n\nfunction hasFullHeader(options: FastEventJsonCodecOptions): boolean {\n return (\n (options.includeId ?? true) &&\n (options.includeSeq ?? true) &&\n (options.includeLevelName ?? true)\n );\n}\n\n// Resolve every `includeX ?? true` toggle once per codec instead of on every\n// encode call. Threading these baked booleans through the encoders lets V8 keep\n// the hot path monomorphic and removes the per-call option lookups.\ninterface ResolvedFlags {\n fullHeader: boolean;\n includeId: boolean;\n includeSeq: boolean;\n includeLevelName: boolean;\n includeData: boolean;\n includeError: boolean;\n includeContext: boolean;\n includeTrace: boolean;\n includeSource: boolean;\n}\n\nfunction resolveFlags(options: FastEventJsonCodecOptions): ResolvedFlags {\n return {\n fullHeader: hasFullHeader(options),\n includeId: options.includeId ?? true,\n includeSeq: options.includeSeq ?? true,\n includeLevelName: options.includeLevelName ?? true,\n includeData: options.includeData ?? true,\n includeError: options.includeError ?? true,\n includeContext: options.includeContext ?? true,\n includeTrace: options.includeTrace ?? true,\n includeSource: options.includeSource ?? true,\n };\n}\n\nfunction createStringify(options: SafeStringifyOptions): JsonStringify {\n if (hasSafeOptions(options)) return (value) => safeJsonStringify(value, options);\n return JSON.stringify;\n}\n\nfunction appendField(\n output: string,\n name: string,\n value: unknown,\n stringify: JsonStringify,\n): string {\n if (value === undefined) return output;\n const encoded = stringify(value);\n return encoded === undefined ? output : `${output},\"${name}\":${encoded}`;\n}\n\n// JSON.stringify costs ~35ns per short string mostly in call overhead. Short\n// strings without quotes, backslashes, or control characters can be quoted\n// directly after a linear scan.\nfunction asJsonString(value: string): string {\n if (value.length > 256) return JSON.stringify(value);\n for (let index = 0; index < value.length; index += 1) {\n const code = value.charCodeAt(index);\n if (code === 34 || code === 92 || code < 32) return JSON.stringify(value);\n }\n return `\"${value}\"`;\n}\n\n// Data payloads are usually small flat objects of primitives. Writing them\n// directly skips the native JSON.stringify call overhead; any nested or\n// exotic value bails out so the caller can use the configured stringifier.\nfunction tryFlatObjectJson(value: Record<string, unknown>): string | undefined {\n // Class instances may carry toJSON or accessors; only plain objects take\n // the fast path so behavior matches JSON.stringify.\n const proto = Object.getPrototypeOf(value) as unknown;\n if (proto !== Object.prototype && proto !== null) return undefined;\n let output = \"{\";\n let first = true;\n // Object.keys (not for..in) on purpose: it returns only own enumerable keys,\n // so a polluted Object.prototype cannot leak inherited keys into log output.\n for (const key of Object.keys(value)) {\n const item = value[key];\n let encoded: string;\n switch (typeof item) {\n case \"string\":\n encoded = asJsonString(item);\n break;\n case \"number\":\n encoded = Number.isFinite(item) ? String(item) : \"null\";\n break;\n case \"boolean\":\n encoded = item ? \"true\" : \"false\";\n break;\n case \"object\":\n if (item !== null) return undefined;\n encoded = \"null\";\n break;\n case \"undefined\":\n continue;\n default:\n return undefined;\n }\n output += `${first ? \"\" : \",\"}${asJsonString(key)}:${encoded}`;\n first = false;\n }\n return `${output}}`;\n}\n\nfunction appendDataField(\n output: string,\n value: Record<string, unknown> | undefined,\n stringify: JsonStringify,\n): string {\n if (value === undefined) return output;\n const flat = tryFlatObjectJson(value);\n if (flat !== undefined) return `${output},\"data\":${flat}`;\n return appendField(output, \"data\", value, stringify);\n}\n\n// The timestamp changes once per millisecond while bursts of records share\n// it, so the rendered `\",\"time\":...,\"seq\":` fragment can be memoized the same\n// way the default id memoizes its time segment.\nlet lastFragmentTime = -1;\nlet lastTimeFragment = \"\";\n\nfunction timeFragment(time: number): string {\n if (time !== lastFragmentTime) {\n lastFragmentTime = time;\n lastTimeFragment = `\",\"time\":${time},\"seq\":`;\n }\n return lastTimeFragment;\n}\n\n// level -> ',\"level\":30,\"levelName\":\"info\",\"logger\":' — derived from the\n// numeric level alone, so a module-level cache is safe.\nconst levelFragments = new Map<number, string>();\n\nfunction levelFragment(level: number): string {\n let fragment = levelFragments.get(level);\n if (fragment === undefined) {\n fragment = `,\"level\":${level},\"levelName\":\"${toLevelName(level)}\",\"logger\":`;\n levelFragments.set(level, fragment);\n }\n return fragment;\n}\n\n// Loggers reuse one frozen category array for every record, so the joined and\n// escaped logger name can be cached per array identity.\nconst categoryFragments = new WeakMap<readonly string[], string>();\n\nfunction loggerFragment(category: readonly string[]): string {\n let fragment = categoryFragments.get(category);\n if (fragment === undefined) {\n fragment = asJsonString(category.join(\".\"));\n categoryFragments.set(category, fragment);\n }\n return fragment;\n}\n\nfunction errorForRecord(record: LogRecord): LogEvent[\"error\"] | undefined {\n if (record.err === null || record.err === undefined) return undefined;\n return normalizeError(record.err);\n}\n\ninterface PreparedRecordFragments {\n category: readonly string[];\n logger: string;\n tags: LogRecord[\"tags\"];\n tagsFragment?: string;\n}\n\nfunction tryPrepareTagsFragment(\n tags: LogRecord[\"tags\"],\n tagsFragment: (tags: NonNullable<LogRecord[\"tags\"]>) => string,\n): string | undefined {\n if (tags === null || !Object.isFrozen(tags)) return undefined;\n try {\n return tagsFragment(tags);\n } catch {\n return undefined;\n }\n}\n\nfunction loggerFragmentForRecord(\n record: LogRecord,\n prepared: PreparedRecordFragments | undefined,\n): string {\n if (prepared && record.category === prepared.category) return prepared.logger;\n return loggerFragment(record.category);\n}\n\nfunction tagsFragmentForRecord(\n record: LogRecord,\n tagsFragment: (tags: NonNullable<LogRecord[\"tags\"]>) => string,\n prepared: PreparedRecordFragments | undefined,\n): string {\n if (record.tags === null) return \"\";\n if (prepared && record.tags === prepared.tags && prepared.tagsFragment !== undefined) {\n return prepared.tagsFragment;\n }\n return tagsFragment(record.tags);\n}\n\nfunction encodeEvent(\n event: LogEvent,\n flags: ResolvedFlags,\n stringify: JsonStringify,\n tagsFragment: (tags: NonNullable<LogEvent[\"tags\"]>) => string,\n): string {\n let output: string;\n if (flags.fullHeader) {\n output = `{\"id\":${asJsonString(event.id)},\"time\":${event.time},\"seq\":${event.seq},\"level\":${event.level},\"levelName\":${asJsonString(event.levelName)},\"logger\":${asJsonString(event.logger)},\"message\":${asJsonString(event.message)}`;\n } else {\n // Build the header in one template literal: empty conditional fragments cost\n // nothing, and a single concatenation avoids the chain of intermediate\n // strings the previous `+=` sequence allocated per call.\n const idPart = flags.includeId ? `\"id\":${asJsonString(event.id)},` : \"\";\n const seqPart = flags.includeSeq ? `,\"seq\":${event.seq}` : \"\";\n const levelNamePart = flags.includeLevelName\n ? `,\"levelName\":${asJsonString(event.levelName)}`\n : \"\";\n output = `{${idPart}\"time\":${event.time}${seqPart},\"level\":${event.level}${levelNamePart},\"logger\":${asJsonString(event.logger)},\"message\":${asJsonString(event.message)}`;\n }\n if (event.type !== undefined) output += `,\"type\":${asJsonString(event.type)}`;\n if (event.tags !== undefined) output += tagsFragment(event.tags);\n if (flags.includeData && event.data !== undefined)\n output = appendField(output, \"data\", event.data, stringify);\n if (flags.includeError && event.error !== undefined)\n output = appendField(output, \"error\", event.error, stringify);\n if (flags.includeContext && event.context !== undefined)\n output = appendField(output, \"context\", event.context, stringify);\n if (flags.includeTrace && event.trace !== undefined)\n output = appendField(output, \"trace\", event.trace, stringify);\n if (flags.includeSource && event.source !== undefined)\n output = appendField(output, \"source\", event.source, stringify);\n return `${output}}`;\n}\n\nfunction encodeRecord(\n record: LogRecord,\n flags: ResolvedFlags,\n stringify: JsonStringify,\n tagsFragment: (tags: NonNullable<LogRecord[\"tags\"]>) => string,\n prepared?: PreparedRecordFragments,\n): string {\n let output: string;\n if (flags.fullHeader) {\n // The default id only contains [0-9a-z-] and the level name, so it never\n // needs escaping.\n const levelName = toLevelName(record.level);\n output = `{\"id\":\"${defaultRecordId(record, levelName)}${timeFragment(record.time)}${record.seq}${levelFragment(record.level)}${loggerFragmentForRecord(record, prepared)},\"message\":${asJsonString(resolveMessage(record))}`;\n } else {\n // The header is built in one template literal so it costs a single\n // concatenation per record; empty conditional fragments cost nothing. The\n // level name is resolved only when the id or the levelName field needs it,\n // so the lean envelope (both off) skips the lookup. The \"info\" default is\n // never emitted in that case — both fragments stay empty.\n const levelName =\n flags.includeId || flags.includeLevelName ? toLevelName(record.level) : \"info\";\n const idPart = flags.includeId ? `\"id\":\"${defaultRecordId(record, levelName)}\",` : \"\";\n const seqPart = flags.includeSeq ? `,\"seq\":${record.seq}` : \"\";\n const levelNamePart = flags.includeLevelName ? `,\"levelName\":\"${levelName}\"` : \"\";\n output = `{${idPart}\"time\":${record.time}${seqPart},\"level\":${record.level}${levelNamePart},\"logger\":${loggerFragmentForRecord(record, prepared)},\"message\":${asJsonString(resolveMessage(record))}`;\n }\n if (record.type !== null) output += `,\"type\":${asJsonString(record.type)}`;\n output += tagsFragmentForRecord(record, tagsFragment, prepared);\n // Guard each optional tail on the record field directly so a null field skips\n // the helper call (and its argument evaluation) entirely, matching the prior\n // `?? undefined` no-op behavior without the per-call cost.\n if (flags.includeData && record.props != null)\n output = appendDataField(output, record.props, stringify);\n if (flags.includeError && record.err != null)\n output = appendField(output, \"error\", errorForRecord(record), stringify);\n if (flags.includeContext && record.ctx != null)\n output = appendField(output, \"context\", record.ctx, stringify);\n if (flags.includeTrace && record.trace != null)\n output = appendField(output, \"trace\", record.trace, stringify);\n if (flags.includeSource && record.source !== \"app\")\n output += `,\"source\":{\"integration\":${asJsonString(record.source)}}`;\n return `${output}}`;\n}\n\ntype TagsFragment = (tags: NonNullable<LogEvent[\"tags\"]>) => string;\n\nfunction encodeItem(\n item: LogEvent | LogRecord,\n flags: ResolvedFlags,\n stringify: JsonStringify,\n tagsFragment: TagsFragment,\n): string {\n return isLogRecord(item)\n ? encodeRecord(item, flags, stringify, tagsFragment)\n : encodeEvent(item, flags, stringify, tagsFragment);\n}\n\nfunction encodeArray(\n items: readonly (LogEvent | LogRecord)[],\n flags: ResolvedFlags,\n stringify: JsonStringify,\n tagsFragment: TagsFragment,\n): string {\n let output = \"[\";\n for (let index = 0; index < items.length; index += 1) {\n if (index > 0) output += \",\";\n output += encodeItem(items[index]!, flags, stringify, tagsFragment);\n }\n return `${output}]`;\n}\n\nfunction isCodecArray(input: CodecInput): input is readonly (LogEvent | LogRecord)[] {\n return Array.isArray(input);\n}\n\nfunction hasLogRecord(items: readonly (LogEvent | LogRecord)[]): boolean {\n for (const item of items) {\n if (isLogRecord(item)) return true;\n }\n return false;\n}\n\n// Loggers share one frozen tags object across records, so the encoded\n// fragment can be cached per object identity. Mutable tags objects are\n// re-encoded every time. Callers create one fragment encoder per codec\n// because it bakes in that codec's stringify options.\nfunction createTagsFragment(encoder: JsonStringify, cached: boolean): TagsFragment {\n const fragments = cached ? new WeakMap<object, string>() : undefined;\n return (tags) => {\n if (fragments && Object.isFrozen(tags)) {\n let fragment = fragments.get(tags);\n if (fragment === undefined) {\n const encoded = encoder(tags);\n fragment = encoded === undefined ? \"\" : `,\"tags\":${encoded}`;\n fragments.set(tags, fragment);\n }\n return fragment;\n }\n const encoded = encoder(tags);\n return encoded === undefined ? \"\" : `,\"tags\":${encoded}`;\n };\n}\n\nexport function fastEventJsonCodec(options: FastEventJsonCodecOptions = {}): Codec<string> {\n const stringify = createStringify(options);\n const safeStringify: JsonStringify = (value) => safeJsonStringify(value, options);\n const useNativeEventJson = canUseNativeEventJson(options);\n // Bake the envelope toggles once so neither the fast nor the safe encoder\n // re-derives them per call.\n const flags = resolveFlags(options);\n const tagsFragment = createTagsFragment(stringify, true);\n // The fallback must not reuse the fast fragments: a cached entry or the\n // fast stringify could throw on the exact payload that triggered fallback.\n const safeTagsFragment = createTagsFragment(safeStringify, false);\n const fastEncode = (input: CodecInput): string => {\n if (isCodecArray(input)) {\n if (useNativeEventJson && !hasLogRecord(input)) return JSON.stringify(input);\n return encodeArray(input, flags, stringify, tagsFragment);\n }\n // Dispatch the single-item case directly to the concrete encoder, skipping\n // the encodeItem indirection and resolving the record/event branch once.\n if (isLogRecord(input)) return encodeRecord(input, flags, stringify, tagsFragment);\n if (useNativeEventJson) return JSON.stringify(input);\n return encodeEvent(input, flags, stringify, tagsFragment);\n };\n return {\n name: \"fast-event-json\",\n contentType: \"application/json\",\n encode(input: CodecInput) {\n // Circular references and BigInt values throw on the native fast path. Logs\n // must never be lost to encoding, so re-encode the input with the safe\n // stringifier instead of surfacing the error as a transport failure.\n try {\n return fastEncode(input);\n } catch {\n incrementLoggerMetaCounter(\"codec.fallback\");\n incrementLoggerMetaCounter(\"codec.fallback.fast-event-json\");\n }\n if (isCodecArray(input)) return encodeArray(input, flags, safeStringify, safeTagsFragment);\n return encodeItem(input, flags, safeStringify, safeTagsFragment);\n },\n decode(payload) {\n return JSON.parse(payload) as LogEvent | LogEvent[];\n },\n prepareRecordEncoder(hints: RecordEncoderHints): PreparedRecordEncoder<string> {\n const prepared: PreparedRecordFragments = {\n category: hints.category,\n logger: loggerFragment(hints.category),\n tags: hints.tags,\n tagsFragment: tryPrepareTagsFragment(hints.tags, tagsFragment),\n };\n return {\n encode(record: LogRecord) {\n try {\n return encodeRecord(record, flags, stringify, tagsFragment, prepared);\n } catch {\n incrementLoggerMetaCounter(\"codec.fallback\");\n incrementLoggerMetaCounter(\"codec.fallback.fast-event-json\");\n }\n return encodeRecord(record, flags, safeStringify, safeTagsFragment, {\n category: prepared.category,\n logger: prepared.logger,\n tags: prepared.tags,\n });\n },\n };\n },\n };\n}\n","import { normalizeCodecInput, type Codec, type CodecInput, type LogEvent } from \"@loggerjs/core\";\nimport { Packr, type Options as MsgpackrOptions } from \"msgpackr\";\n\nexport interface MsgpackRuntime {\n pack: (input: unknown) => Uint8Array;\n unpack: (payload: Uint8Array) => unknown;\n}\n\nexport type MsgpackrCodecOptions = MsgpackrOptions;\n\nfunction isMsgpackRuntime(value: MsgpackRuntime | MsgpackrCodecOptions): value is MsgpackRuntime {\n return (\n typeof (value as MsgpackRuntime).pack === \"function\" &&\n typeof (value as MsgpackRuntime).unpack === \"function\"\n );\n}\n\nexport function msgpackrCodec(\n options: MsgpackRuntime | MsgpackrCodecOptions = {},\n): Codec<Uint8Array> {\n const runtime = isMsgpackRuntime(options) ? options : new Packr({ useRecords: true, ...options });\n return {\n name: \"msgpackr\",\n contentType: \"application/msgpack\",\n encode(input: CodecInput) {\n return runtime.pack(normalizeCodecInput(input));\n },\n decode(payload: Uint8Array) {\n return runtime.unpack(payload) as LogEvent | LogEvent[];\n },\n };\n}\n","import {\n incrementLoggerMetaCounter,\n normalizeCodecInput,\n safeJsonStringify,\n type Codec,\n type CodecInput,\n type LogEvent,\n type SafeStringifyOptions,\n type SerializedError,\n} from \"@loggerjs/core\";\n\nexport type PinoCompatCollisionPolicy = \"nest\" | \"drop\" | \"throw\";\n\nexport interface PinoCompatCodecOptions extends SafeStringifyOptions {\n base?: Record<string, unknown>;\n dataKey?: string;\n errorKey?: string;\n includeLogger?: boolean;\n mergeData?: boolean;\n collision?: PinoCompatCollisionPolicy;\n}\n\nconst baseReservedRootKeys = new Set([\"time\", \"level\", \"msg\", \"err\", \"logger\", \"data\"]);\nconst dataReservedRootKeys = new Set([\n \"time\",\n \"level\",\n \"msg\",\n \"pid\",\n \"hostname\",\n \"err\",\n \"logger\",\n \"data\",\n]);\n\nfunction hasSafeOptions(options: SafeStringifyOptions): boolean {\n return (\n options.maxDepth !== undefined ||\n options.maxArrayLength !== undefined ||\n options.maxObjectKeys !== undefined ||\n options.includeStack !== undefined ||\n options.stable !== undefined ||\n options.space !== undefined\n );\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return Boolean(value) && typeof value === \"object\" && !Array.isArray(value);\n}\n\nfunction pinoError(error: SerializedError): Record<string, unknown> {\n return {\n type: error.name ?? \"Error\",\n message: error.message,\n stack: error.stack,\n code: error.code,\n cause: error.cause,\n };\n}\n\nfunction assignWithCollision(\n output: Record<string, unknown>,\n nested: Record<string, unknown>,\n key: string,\n value: unknown,\n policy: PinoCompatCollisionPolicy,\n reservedKeys = dataReservedRootKeys,\n) {\n if (!reservedKeys.has(key) && !(key in output)) {\n output[key] = value;\n return;\n }\n\n if (policy === \"throw\") {\n throw new Error(`pinoCompatCodec cannot merge reserved key \"${key}\"`);\n }\n if (policy === \"nest\") nested[key] = value;\n}\n\nfunction mergeNestedData(\n existing: unknown,\n nested: Record<string, unknown>,\n): Record<string, unknown> {\n if (isRecord(existing)) return { ...nested, ...existing };\n if (existing !== undefined) return { ...nested, value: existing };\n return nested;\n}\n\nfunction projectEvent(event: LogEvent, options: PinoCompatCodecOptions): Record<string, unknown> {\n const dataKey = options.dataKey ?? \"data\";\n const errorKey = options.errorKey ?? \"err\";\n const collision = options.collision ?? \"nest\";\n const output: Record<string, unknown> = {\n level: event.level,\n time: event.time,\n };\n const nested: Record<string, unknown> = {};\n\n const baseReservedKeys = new Set(baseReservedRootKeys);\n baseReservedKeys.add(dataKey);\n baseReservedKeys.add(errorKey);\n for (const [key, value] of Object.entries(options.base ?? {})) {\n assignWithCollision(output, nested, key, value, collision, baseReservedKeys);\n }\n\n if (options.includeLogger) output.logger = event.logger;\n if (event.error) output[errorKey] = pinoError(event.error);\n\n if (event.data !== undefined) {\n if (options.mergeData && isRecord(event.data)) {\n const dataReservedKeys = new Set(dataReservedRootKeys);\n dataReservedKeys.add(dataKey);\n dataReservedKeys.add(errorKey);\n for (const [key, value] of Object.entries(event.data)) {\n assignWithCollision(output, nested, key, value, collision, dataReservedKeys);\n }\n } else {\n output[dataKey] = event.data;\n }\n }\n\n if (Object.keys(nested).length > 0) {\n output[dataKey] = mergeNestedData(output[dataKey], nested);\n }\n\n output.msg = event.message;\n\n return output;\n}\n\nfunction encodeLine(event: LogEvent, options: PinoCompatCodecOptions, safeMode: boolean): string {\n const projected = projectEvent(event, options);\n if (safeMode) return safeJsonStringify(projected, options);\n try {\n const encoded = JSON.stringify(projected);\n return encoded ?? \"{}\";\n } catch {\n incrementLoggerMetaCounter(\"codec.fallback\");\n incrementLoggerMetaCounter(\"codec.fallback.pino-compat\");\n return safeJsonStringify(projected, options);\n }\n}\n\nfunction encodeEvents(\n input: LogEvent | LogEvent[],\n options: PinoCompatCodecOptions,\n safeMode: boolean,\n): string {\n if (!Array.isArray(input)) return `${encodeLine(input, options, safeMode)}\\n`;\n let output = \"\";\n for (const event of input) output += `${encodeLine(event, options, safeMode)}\\n`;\n return output;\n}\n\nexport function pinoCompatCodec(options: PinoCompatCodecOptions = {}): Codec<string> {\n const safeMode = hasSafeOptions(options);\n return {\n name: \"pino-compat\",\n contentType: \"application/x-ndjson\",\n encode(input: CodecInput) {\n return encodeEvents(normalizeCodecInput(input), options, safeMode);\n },\n };\n}\n\nexport const pinoNdjsonProjector = pinoCompatCodec;\n","import { normalizeCodecInput, type Codec, type CodecInput, type LogEvent } from \"@loggerjs/core\";\n\nexport interface ProjectorCodecOptions<TWire> {\n name: string;\n contentType: string;\n project: (input: LogEvent | LogEvent[]) => TWire;\n serialize: (wire: TWire) => string | Uint8Array;\n parse?: (payload: string | Uint8Array) => TWire;\n unproject?: (wire: TWire) => LogEvent | LogEvent[];\n}\n\nexport function projectorCodec<TWire>(\n options: ProjectorCodecOptions<TWire>,\n): Codec<string | Uint8Array> {\n return {\n name: options.name,\n contentType: options.contentType,\n encode(input: CodecInput) {\n return options.serialize(options.project(normalizeCodecInput(input)));\n },\n decode:\n options.parse && options.unproject\n ? (payload) => options.unproject!(options.parse!(payload))\n : undefined,\n };\n}\n"],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  export * from "@loggerjs/core";
2
2
  export * from "./fast-event-json.js";
3
3
  export * from "./msgpackr.js";
4
+ export * from "./pino-compat.js";
4
5
  export * from "./projector.js";
5
6
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,cAAc,aAAa,CAAC"}
package/dist/index.js CHANGED
@@ -2,17 +2,30 @@ import { defaultRecordId, incrementLoggerMetaCounter, isLogRecord, normalizeCode
2
2
  import { Packr } from "msgpackr";
3
3
  export * from "@loggerjs/core";
4
4
  //#region src/fast-event-json.ts
5
- function hasSafeOptions(options) {
5
+ function hasSafeOptions$1(options) {
6
6
  return options.maxDepth !== void 0 || options.maxArrayLength !== void 0 || options.maxObjectKeys !== void 0 || options.includeStack !== void 0 || options.stable !== void 0 || options.space !== void 0;
7
7
  }
8
8
  function canUseNativeEventJson(options) {
9
- return !hasSafeOptions(options) && options.includeContext !== false && options.includeData !== false && options.includeError !== false && options.includeTrace !== false && options.includeSource !== false && options.includeId !== false && options.includeSeq !== false && options.includeLevelName !== false;
9
+ return !hasSafeOptions$1(options) && options.includeContext !== false && options.includeData !== false && options.includeError !== false && options.includeTrace !== false && options.includeSource !== false && options.includeId !== false && options.includeSeq !== false && options.includeLevelName !== false;
10
10
  }
11
11
  function hasFullHeader(options) {
12
12
  return (options.includeId ?? true) && (options.includeSeq ?? true) && (options.includeLevelName ?? true);
13
13
  }
14
+ function resolveFlags(options) {
15
+ return {
16
+ fullHeader: hasFullHeader(options),
17
+ includeId: options.includeId ?? true,
18
+ includeSeq: options.includeSeq ?? true,
19
+ includeLevelName: options.includeLevelName ?? true,
20
+ includeData: options.includeData ?? true,
21
+ includeError: options.includeError ?? true,
22
+ includeContext: options.includeContext ?? true,
23
+ includeTrace: options.includeTrace ?? true,
24
+ includeSource: options.includeSource ?? true
25
+ };
26
+ }
14
27
  function createStringify(options) {
15
- if (hasSafeOptions(options)) return (value) => safeJsonStringify(value, options);
28
+ if (hasSafeOptions$1(options)) return (value) => safeJsonStringify(value, options);
16
29
  return JSON.stringify;
17
30
  }
18
31
  function appendField(output, name, value, stringify) {
@@ -95,57 +108,68 @@ function errorForRecord(record) {
95
108
  if (record.err === null || record.err === void 0) return void 0;
96
109
  return normalizeError(record.err);
97
110
  }
98
- function encodeEvent(event, options, stringify, tagsFragment) {
111
+ function tryPrepareTagsFragment(tags, tagsFragment) {
112
+ if (tags === null || !Object.isFrozen(tags)) return void 0;
113
+ try {
114
+ return tagsFragment(tags);
115
+ } catch {
116
+ return;
117
+ }
118
+ }
119
+ function loggerFragmentForRecord(record, prepared) {
120
+ if (prepared && record.category === prepared.category) return prepared.logger;
121
+ return loggerFragment(record.category);
122
+ }
123
+ function tagsFragmentForRecord(record, tagsFragment, prepared) {
124
+ if (record.tags === null) return "";
125
+ if (prepared && record.tags === prepared.tags && prepared.tagsFragment !== void 0) return prepared.tagsFragment;
126
+ return tagsFragment(record.tags);
127
+ }
128
+ function encodeEvent(event, flags, stringify, tagsFragment) {
99
129
  let output;
100
- if (hasFullHeader(options)) output = `{"id":${asJsonString(event.id)},"time":${event.time},"seq":${event.seq},"level":${event.level},"levelName":${asJsonString(event.levelName)},"logger":${asJsonString(event.logger)},"message":${asJsonString(event.message)}`;
130
+ if (flags.fullHeader) output = `{"id":${asJsonString(event.id)},"time":${event.time},"seq":${event.seq},"level":${event.level},"levelName":${asJsonString(event.levelName)},"logger":${asJsonString(event.logger)},"message":${asJsonString(event.message)}`;
101
131
  else {
102
- output = "{";
103
- if (options.includeId ?? true) output += `"id":${asJsonString(event.id)},`;
104
- output += `"time":${event.time}`;
105
- if (options.includeSeq ?? true) output += `,"seq":${event.seq}`;
106
- output += `,"level":${event.level}`;
107
- if (options.includeLevelName ?? true) output += `,"levelName":${asJsonString(event.levelName)}`;
108
- output += `,"logger":${asJsonString(event.logger)},"message":${asJsonString(event.message)}`;
132
+ const idPart = flags.includeId ? `"id":${asJsonString(event.id)},` : "";
133
+ const seqPart = flags.includeSeq ? `,"seq":${event.seq}` : "";
134
+ const levelNamePart = flags.includeLevelName ? `,"levelName":${asJsonString(event.levelName)}` : "";
135
+ output = `{${idPart}"time":${event.time}${seqPart},"level":${event.level}${levelNamePart},"logger":${asJsonString(event.logger)},"message":${asJsonString(event.message)}`;
109
136
  }
110
137
  if (event.type !== void 0) output += `,"type":${asJsonString(event.type)}`;
111
138
  if (event.tags !== void 0) output += tagsFragment(event.tags);
112
- if (options.includeData ?? true) output = appendField(output, "data", event.data, stringify);
113
- if (options.includeError ?? true) output = appendField(output, "error", event.error, stringify);
114
- if (options.includeContext ?? true) output = appendField(output, "context", event.context, stringify);
115
- if (options.includeTrace ?? true) output = appendField(output, "trace", event.trace, stringify);
116
- if (options.includeSource ?? true) output = appendField(output, "source", event.source, stringify);
139
+ if (flags.includeData && event.data !== void 0) output = appendField(output, "data", event.data, stringify);
140
+ if (flags.includeError && event.error !== void 0) output = appendField(output, "error", event.error, stringify);
141
+ if (flags.includeContext && event.context !== void 0) output = appendField(output, "context", event.context, stringify);
142
+ if (flags.includeTrace && event.trace !== void 0) output = appendField(output, "trace", event.trace, stringify);
143
+ if (flags.includeSource && event.source !== void 0) output = appendField(output, "source", event.source, stringify);
117
144
  return `${output}}`;
118
145
  }
119
- function encodeRecord(record, options, stringify, tagsFragment) {
120
- const levelName = toLevelName(record.level);
146
+ function encodeRecord(record, flags, stringify, tagsFragment, prepared) {
121
147
  let output;
122
- if (hasFullHeader(options)) output = `{"id":"${defaultRecordId(record, levelName)}${timeFragment(record.time)}${record.seq}${levelFragment(record.level)}${loggerFragment(record.category)},"message":${asJsonString(resolveMessage(record))}`;
148
+ if (flags.fullHeader) output = `{"id":"${defaultRecordId(record, toLevelName(record.level))}${timeFragment(record.time)}${record.seq}${levelFragment(record.level)}${loggerFragmentForRecord(record, prepared)},"message":${asJsonString(resolveMessage(record))}`;
123
149
  else {
124
- output = "{";
125
- if (options.includeId ?? true) output += `"id":"${defaultRecordId(record, levelName)}",`;
126
- output += `"time":${record.time}`;
127
- if (options.includeSeq ?? true) output += `,"seq":${record.seq}`;
128
- output += `,"level":${record.level}`;
129
- if (options.includeLevelName ?? true) output += `,"levelName":"${levelName}"`;
130
- output += `,"logger":${loggerFragment(record.category)},"message":${asJsonString(resolveMessage(record))}`;
150
+ const levelName = flags.includeId || flags.includeLevelName ? toLevelName(record.level) : "info";
151
+ const idPart = flags.includeId ? `"id":"${defaultRecordId(record, levelName)}",` : "";
152
+ const seqPart = flags.includeSeq ? `,"seq":${record.seq}` : "";
153
+ const levelNamePart = flags.includeLevelName ? `,"levelName":"${levelName}"` : "";
154
+ output = `{${idPart}"time":${record.time}${seqPart},"level":${record.level}${levelNamePart},"logger":${loggerFragmentForRecord(record, prepared)},"message":${asJsonString(resolveMessage(record))}`;
131
155
  }
132
156
  if (record.type !== null) output += `,"type":${asJsonString(record.type)}`;
133
- if (record.tags !== null) output += tagsFragment(record.tags);
134
- if (options.includeData ?? true) output = appendDataField(output, record.props ?? void 0, stringify);
135
- if (options.includeError ?? true) output = appendField(output, "error", errorForRecord(record), stringify);
136
- if (options.includeContext ?? true) output = appendField(output, "context", record.ctx ?? void 0, stringify);
137
- if (options.includeTrace ?? true) output = appendField(output, "trace", record.trace ?? void 0, stringify);
138
- if ((options.includeSource ?? true) && record.source !== "app") output += `,"source":{"integration":${asJsonString(record.source)}}`;
157
+ output += tagsFragmentForRecord(record, tagsFragment, prepared);
158
+ if (flags.includeData && record.props != null) output = appendDataField(output, record.props, stringify);
159
+ if (flags.includeError && record.err != null) output = appendField(output, "error", errorForRecord(record), stringify);
160
+ if (flags.includeContext && record.ctx != null) output = appendField(output, "context", record.ctx, stringify);
161
+ if (flags.includeTrace && record.trace != null) output = appendField(output, "trace", record.trace, stringify);
162
+ if (flags.includeSource && record.source !== "app") output += `,"source":{"integration":${asJsonString(record.source)}}`;
139
163
  return `${output}}`;
140
164
  }
141
- function encodeItem(item, options, stringify, tagsFragment) {
142
- return isLogRecord(item) ? encodeRecord(item, options, stringify, tagsFragment) : encodeEvent(item, options, stringify, tagsFragment);
165
+ function encodeItem(item, flags, stringify, tagsFragment) {
166
+ return isLogRecord(item) ? encodeRecord(item, flags, stringify, tagsFragment) : encodeEvent(item, flags, stringify, tagsFragment);
143
167
  }
144
- function encodeArray(items, options, stringify, tagsFragment) {
168
+ function encodeArray(items, flags, stringify, tagsFragment) {
145
169
  let output = "[";
146
170
  for (let index = 0; index < items.length; index += 1) {
147
171
  if (index > 0) output += ",";
148
- output += encodeItem(items[index], options, stringify, tagsFragment);
172
+ output += encodeItem(items[index], flags, stringify, tagsFragment);
149
173
  }
150
174
  return `${output}]`;
151
175
  }
@@ -176,15 +200,17 @@ function fastEventJsonCodec(options = {}) {
176
200
  const stringify = createStringify(options);
177
201
  const safeStringify = (value) => safeJsonStringify(value, options);
178
202
  const useNativeEventJson = canUseNativeEventJson(options);
203
+ const flags = resolveFlags(options);
179
204
  const tagsFragment = createTagsFragment(stringify, true);
180
205
  const safeTagsFragment = createTagsFragment(safeStringify, false);
181
206
  const fastEncode = (input) => {
182
207
  if (isCodecArray(input)) {
183
208
  if (useNativeEventJson && !hasLogRecord(input)) return JSON.stringify(input);
184
- return encodeArray(input, options, stringify, tagsFragment);
209
+ return encodeArray(input, flags, stringify, tagsFragment);
185
210
  }
186
- if (useNativeEventJson && !isLogRecord(input)) return JSON.stringify(input);
187
- return encodeItem(input, options, stringify, tagsFragment);
211
+ if (isLogRecord(input)) return encodeRecord(input, flags, stringify, tagsFragment);
212
+ if (useNativeEventJson) return JSON.stringify(input);
213
+ return encodeEvent(input, flags, stringify, tagsFragment);
188
214
  };
189
215
  return {
190
216
  name: "fast-event-json",
@@ -196,11 +222,32 @@ function fastEventJsonCodec(options = {}) {
196
222
  incrementLoggerMetaCounter("codec.fallback");
197
223
  incrementLoggerMetaCounter("codec.fallback.fast-event-json");
198
224
  }
199
- if (isCodecArray(input)) return encodeArray(input, options, safeStringify, safeTagsFragment);
200
- return encodeItem(input, options, safeStringify, safeTagsFragment);
225
+ if (isCodecArray(input)) return encodeArray(input, flags, safeStringify, safeTagsFragment);
226
+ return encodeItem(input, flags, safeStringify, safeTagsFragment);
201
227
  },
202
228
  decode(payload) {
203
229
  return JSON.parse(payload);
230
+ },
231
+ prepareRecordEncoder(hints) {
232
+ const prepared = {
233
+ category: hints.category,
234
+ logger: loggerFragment(hints.category),
235
+ tags: hints.tags,
236
+ tagsFragment: tryPrepareTagsFragment(hints.tags, tagsFragment)
237
+ };
238
+ return { encode(record) {
239
+ try {
240
+ return encodeRecord(record, flags, stringify, tagsFragment, prepared);
241
+ } catch {
242
+ incrementLoggerMetaCounter("codec.fallback");
243
+ incrementLoggerMetaCounter("codec.fallback.fast-event-json");
244
+ }
245
+ return encodeRecord(record, flags, safeStringify, safeTagsFragment, {
246
+ category: prepared.category,
247
+ logger: prepared.logger,
248
+ tags: prepared.tags
249
+ });
250
+ } };
204
251
  }
205
252
  };
206
253
  }
@@ -226,6 +273,113 @@ function msgpackrCodec(options = {}) {
226
273
  };
227
274
  }
228
275
  //#endregion
276
+ //#region src/pino-compat.ts
277
+ const baseReservedRootKeys = new Set([
278
+ "time",
279
+ "level",
280
+ "msg",
281
+ "err",
282
+ "logger",
283
+ "data"
284
+ ]);
285
+ const dataReservedRootKeys = new Set([
286
+ "time",
287
+ "level",
288
+ "msg",
289
+ "pid",
290
+ "hostname",
291
+ "err",
292
+ "logger",
293
+ "data"
294
+ ]);
295
+ function hasSafeOptions(options) {
296
+ return options.maxDepth !== void 0 || options.maxArrayLength !== void 0 || options.maxObjectKeys !== void 0 || options.includeStack !== void 0 || options.stable !== void 0 || options.space !== void 0;
297
+ }
298
+ function isRecord(value) {
299
+ return Boolean(value) && typeof value === "object" && !Array.isArray(value);
300
+ }
301
+ function pinoError(error) {
302
+ return {
303
+ type: error.name ?? "Error",
304
+ message: error.message,
305
+ stack: error.stack,
306
+ code: error.code,
307
+ cause: error.cause
308
+ };
309
+ }
310
+ function assignWithCollision(output, nested, key, value, policy, reservedKeys = dataReservedRootKeys) {
311
+ if (!reservedKeys.has(key) && !(key in output)) {
312
+ output[key] = value;
313
+ return;
314
+ }
315
+ if (policy === "throw") throw new Error(`pinoCompatCodec cannot merge reserved key "${key}"`);
316
+ if (policy === "nest") nested[key] = value;
317
+ }
318
+ function mergeNestedData(existing, nested) {
319
+ if (isRecord(existing)) return {
320
+ ...nested,
321
+ ...existing
322
+ };
323
+ if (existing !== void 0) return {
324
+ ...nested,
325
+ value: existing
326
+ };
327
+ return nested;
328
+ }
329
+ function projectEvent(event, options) {
330
+ const dataKey = options.dataKey ?? "data";
331
+ const errorKey = options.errorKey ?? "err";
332
+ const collision = options.collision ?? "nest";
333
+ const output = {
334
+ level: event.level,
335
+ time: event.time
336
+ };
337
+ const nested = {};
338
+ const baseReservedKeys = new Set(baseReservedRootKeys);
339
+ baseReservedKeys.add(dataKey);
340
+ baseReservedKeys.add(errorKey);
341
+ for (const [key, value] of Object.entries(options.base ?? {})) assignWithCollision(output, nested, key, value, collision, baseReservedKeys);
342
+ if (options.includeLogger) output.logger = event.logger;
343
+ if (event.error) output[errorKey] = pinoError(event.error);
344
+ if (event.data !== void 0) if (options.mergeData && isRecord(event.data)) {
345
+ const dataReservedKeys = new Set(dataReservedRootKeys);
346
+ dataReservedKeys.add(dataKey);
347
+ dataReservedKeys.add(errorKey);
348
+ for (const [key, value] of Object.entries(event.data)) assignWithCollision(output, nested, key, value, collision, dataReservedKeys);
349
+ } else output[dataKey] = event.data;
350
+ if (Object.keys(nested).length > 0) output[dataKey] = mergeNestedData(output[dataKey], nested);
351
+ output.msg = event.message;
352
+ return output;
353
+ }
354
+ function encodeLine(event, options, safeMode) {
355
+ const projected = projectEvent(event, options);
356
+ if (safeMode) return safeJsonStringify(projected, options);
357
+ try {
358
+ return JSON.stringify(projected) ?? "{}";
359
+ } catch {
360
+ incrementLoggerMetaCounter("codec.fallback");
361
+ incrementLoggerMetaCounter("codec.fallback.pino-compat");
362
+ return safeJsonStringify(projected, options);
363
+ }
364
+ }
365
+ function encodeEvents(input, options, safeMode) {
366
+ if (!Array.isArray(input)) return `${encodeLine(input, options, safeMode)}\n`;
367
+ let output = "";
368
+ for (const event of input) output += `${encodeLine(event, options, safeMode)}\n`;
369
+ return output;
370
+ }
371
+ function pinoCompatCodec(options = {}) {
372
+ const safeMode = hasSafeOptions(options);
373
+ return {
374
+ name: "pino-compat",
375
+ contentType: "application/x-ndjson",
376
+ encode(input) {
377
+ return encodeEvents(normalizeCodecInput(input), options, safeMode);
378
+ }
379
+ };
380
+ }
381
+ const pinoNdjsonProjector = pinoCompatCodec;
382
+ //#endregion
229
383
  //#region src/projector.ts
230
384
  function projectorCodec(options) {
231
385
  return {
@@ -238,6 +392,6 @@ function projectorCodec(options) {
238
392
  };
239
393
  }
240
394
  //#endregion
241
- export { fastEventJsonCodec, msgpackrCodec, projectorCodec };
395
+ export { fastEventJsonCodec, msgpackrCodec, pinoCompatCodec, pinoNdjsonProjector, projectorCodec };
242
396
 
243
397
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/fast-event-json.ts","../src/msgpackr.ts","../src/projector.ts"],"sourcesContent":["import {\n defaultRecordId,\n incrementLoggerMetaCounter,\n isLogRecord,\n normalizeError,\n resolveMessage,\n toLevelName,\n safeJsonStringify,\n type Codec,\n type CodecInput,\n type LogEvent,\n type LogRecord,\n type SafeStringifyOptions,\n} from \"@loggerjs/core\";\n\n/**\n * Without any option set, encode runs on a native `JSON.stringify` fast path: nested\n * `Error` values serialize as `{}` and circular or BigInt payloads trigger a safe\n * re-encode of the whole input (circular refs become \"[Circular]\", BigInt becomes a\n * string). Setting any {@link SafeStringifyOptions} field opts into the safe encoder\n * everywhere, which also preserves `Error` name/message/stack inside data payloads.\n *\n * `includeId`, `includeSeq`, and `includeLevelName` trim the envelope for\n * pino-shaped minimal NDJSON output; turning `includeId` off also skips id\n * computation entirely on the record path.\n */\nexport interface FastEventJsonCodecOptions extends SafeStringifyOptions {\n includeContext?: boolean;\n includeData?: boolean;\n includeError?: boolean;\n includeTrace?: boolean;\n includeSource?: boolean;\n includeId?: boolean;\n includeSeq?: boolean;\n includeLevelName?: boolean;\n}\n\ntype JsonStringify = (value: unknown) => string | undefined;\n\nfunction hasSafeOptions(options: SafeStringifyOptions): boolean {\n return (\n options.maxDepth !== undefined ||\n options.maxArrayLength !== undefined ||\n options.maxObjectKeys !== undefined ||\n options.includeStack !== undefined ||\n options.stable !== undefined ||\n options.space !== undefined\n );\n}\n\nfunction canUseNativeEventJson(options: FastEventJsonCodecOptions): boolean {\n return (\n !hasSafeOptions(options) &&\n options.includeContext !== false &&\n options.includeData !== false &&\n options.includeError !== false &&\n options.includeTrace !== false &&\n options.includeSource !== false &&\n options.includeId !== false &&\n options.includeSeq !== false &&\n options.includeLevelName !== false\n );\n}\n\nfunction hasFullHeader(options: FastEventJsonCodecOptions): boolean {\n return (\n (options.includeId ?? true) &&\n (options.includeSeq ?? true) &&\n (options.includeLevelName ?? true)\n );\n}\n\nfunction createStringify(options: SafeStringifyOptions): JsonStringify {\n if (hasSafeOptions(options)) return (value) => safeJsonStringify(value, options);\n return JSON.stringify;\n}\n\nfunction appendField(\n output: string,\n name: string,\n value: unknown,\n stringify: JsonStringify,\n): string {\n if (value === undefined) return output;\n const encoded = stringify(value);\n return encoded === undefined ? output : `${output},\"${name}\":${encoded}`;\n}\n\n// JSON.stringify costs ~35ns per short string mostly in call overhead. Short\n// strings without quotes, backslashes, or control characters can be quoted\n// directly after a linear scan.\nfunction asJsonString(value: string): string {\n if (value.length > 256) return JSON.stringify(value);\n for (let index = 0; index < value.length; index += 1) {\n const code = value.charCodeAt(index);\n if (code === 34 || code === 92 || code < 32) return JSON.stringify(value);\n }\n return `\"${value}\"`;\n}\n\n// Data payloads are usually small flat objects of primitives. Writing them\n// directly skips the native JSON.stringify call overhead; any nested or\n// exotic value bails out so the caller can use the configured stringifier.\nfunction tryFlatObjectJson(value: Record<string, unknown>): string | undefined {\n // Class instances may carry toJSON or accessors; only plain objects take\n // the fast path so behavior matches JSON.stringify.\n const proto = Object.getPrototypeOf(value) as unknown;\n if (proto !== Object.prototype && proto !== null) return undefined;\n let output = \"{\";\n let first = true;\n for (const key of Object.keys(value)) {\n const item = value[key];\n let encoded: string;\n switch (typeof item) {\n case \"string\":\n encoded = asJsonString(item);\n break;\n case \"number\":\n encoded = Number.isFinite(item) ? String(item) : \"null\";\n break;\n case \"boolean\":\n encoded = item ? \"true\" : \"false\";\n break;\n case \"object\":\n if (item !== null) return undefined;\n encoded = \"null\";\n break;\n case \"undefined\":\n continue;\n default:\n return undefined;\n }\n output += `${first ? \"\" : \",\"}${asJsonString(key)}:${encoded}`;\n first = false;\n }\n return `${output}}`;\n}\n\nfunction appendDataField(\n output: string,\n value: Record<string, unknown> | undefined,\n stringify: JsonStringify,\n): string {\n if (value === undefined) return output;\n const flat = tryFlatObjectJson(value);\n if (flat !== undefined) return `${output},\"data\":${flat}`;\n return appendField(output, \"data\", value, stringify);\n}\n\n// The timestamp changes once per millisecond while bursts of records share\n// it, so the rendered `\",\"time\":...,\"seq\":` fragment can be memoized the same\n// way the default id memoizes its time segment.\nlet lastFragmentTime = -1;\nlet lastTimeFragment = \"\";\n\nfunction timeFragment(time: number): string {\n if (time !== lastFragmentTime) {\n lastFragmentTime = time;\n lastTimeFragment = `\",\"time\":${time},\"seq\":`;\n }\n return lastTimeFragment;\n}\n\n// level -> ',\"level\":30,\"levelName\":\"info\",\"logger\":' — derived from the\n// numeric level alone, so a module-level cache is safe.\nconst levelFragments = new Map<number, string>();\n\nfunction levelFragment(level: number): string {\n let fragment = levelFragments.get(level);\n if (fragment === undefined) {\n fragment = `,\"level\":${level},\"levelName\":\"${toLevelName(level)}\",\"logger\":`;\n levelFragments.set(level, fragment);\n }\n return fragment;\n}\n\n// Loggers reuse one frozen category array for every record, so the joined and\n// escaped logger name can be cached per array identity.\nconst categoryFragments = new WeakMap<readonly string[], string>();\n\nfunction loggerFragment(category: readonly string[]): string {\n let fragment = categoryFragments.get(category);\n if (fragment === undefined) {\n fragment = asJsonString(category.join(\".\"));\n categoryFragments.set(category, fragment);\n }\n return fragment;\n}\n\nfunction errorForRecord(record: LogRecord): LogEvent[\"error\"] | undefined {\n if (record.err === null || record.err === undefined) return undefined;\n return normalizeError(record.err);\n}\n\nfunction encodeEvent(\n event: LogEvent,\n options: FastEventJsonCodecOptions,\n stringify: JsonStringify,\n tagsFragment: (tags: NonNullable<LogEvent[\"tags\"]>) => string,\n): string {\n let output: string;\n if (hasFullHeader(options)) {\n output = `{\"id\":${asJsonString(event.id)},\"time\":${event.time},\"seq\":${event.seq},\"level\":${event.level},\"levelName\":${asJsonString(event.levelName)},\"logger\":${asJsonString(event.logger)},\"message\":${asJsonString(event.message)}`;\n } else {\n output = \"{\";\n if (options.includeId ?? true) output += `\"id\":${asJsonString(event.id)},`;\n output += `\"time\":${event.time}`;\n if (options.includeSeq ?? true) output += `,\"seq\":${event.seq}`;\n output += `,\"level\":${event.level}`;\n if (options.includeLevelName ?? true) output += `,\"levelName\":${asJsonString(event.levelName)}`;\n output += `,\"logger\":${asJsonString(event.logger)},\"message\":${asJsonString(event.message)}`;\n }\n if (event.type !== undefined) output += `,\"type\":${asJsonString(event.type)}`;\n if (event.tags !== undefined) output += tagsFragment(event.tags);\n if (options.includeData ?? true) output = appendField(output, \"data\", event.data, stringify);\n if (options.includeError ?? true) output = appendField(output, \"error\", event.error, stringify);\n if (options.includeContext ?? true)\n output = appendField(output, \"context\", event.context, stringify);\n if (options.includeTrace ?? true) output = appendField(output, \"trace\", event.trace, stringify);\n if (options.includeSource ?? true)\n output = appendField(output, \"source\", event.source, stringify);\n return `${output}}`;\n}\n\nfunction encodeRecord(\n record: LogRecord,\n options: FastEventJsonCodecOptions,\n stringify: JsonStringify,\n tagsFragment: (tags: NonNullable<LogRecord[\"tags\"]>) => string,\n): string {\n const levelName = toLevelName(record.level);\n let output: string;\n if (hasFullHeader(options)) {\n // The default id only contains [0-9a-z-] and the level name, so it never\n // needs escaping.\n output = `{\"id\":\"${defaultRecordId(record, levelName)}${timeFragment(record.time)}${record.seq}${levelFragment(record.level)}${loggerFragment(record.category)},\"message\":${asJsonString(resolveMessage(record))}`;\n } else {\n output = \"{\";\n if (options.includeId ?? true) output += `\"id\":\"${defaultRecordId(record, levelName)}\",`;\n output += `\"time\":${record.time}`;\n if (options.includeSeq ?? true) output += `,\"seq\":${record.seq}`;\n output += `,\"level\":${record.level}`;\n if (options.includeLevelName ?? true) output += `,\"levelName\":\"${levelName}\"`;\n output += `,\"logger\":${loggerFragment(record.category)},\"message\":${asJsonString(resolveMessage(record))}`;\n }\n if (record.type !== null) output += `,\"type\":${asJsonString(record.type)}`;\n if (record.tags !== null) output += tagsFragment(record.tags);\n if (options.includeData ?? true)\n output = appendDataField(output, record.props ?? undefined, stringify);\n if (options.includeError ?? true)\n output = appendField(output, \"error\", errorForRecord(record), stringify);\n if (options.includeContext ?? true)\n output = appendField(output, \"context\", record.ctx ?? undefined, stringify);\n if (options.includeTrace ?? true)\n output = appendField(output, \"trace\", record.trace ?? undefined, stringify);\n if ((options.includeSource ?? true) && record.source !== \"app\")\n output += `,\"source\":{\"integration\":${asJsonString(record.source)}}`;\n return `${output}}`;\n}\n\ntype TagsFragment = (tags: NonNullable<LogEvent[\"tags\"]>) => string;\n\nfunction encodeItem(\n item: LogEvent | LogRecord,\n options: FastEventJsonCodecOptions,\n stringify: JsonStringify,\n tagsFragment: TagsFragment,\n): string {\n return isLogRecord(item)\n ? encodeRecord(item, options, stringify, tagsFragment)\n : encodeEvent(item, options, stringify, tagsFragment);\n}\n\nfunction encodeArray(\n items: readonly (LogEvent | LogRecord)[],\n options: FastEventJsonCodecOptions,\n stringify: JsonStringify,\n tagsFragment: TagsFragment,\n): string {\n let output = \"[\";\n for (let index = 0; index < items.length; index += 1) {\n if (index > 0) output += \",\";\n output += encodeItem(items[index]!, options, stringify, tagsFragment);\n }\n return `${output}]`;\n}\n\nfunction isCodecArray(input: CodecInput): input is readonly (LogEvent | LogRecord)[] {\n return Array.isArray(input);\n}\n\nfunction hasLogRecord(items: readonly (LogEvent | LogRecord)[]): boolean {\n for (const item of items) {\n if (isLogRecord(item)) return true;\n }\n return false;\n}\n\n// Loggers share one frozen tags object across records, so the encoded\n// fragment can be cached per object identity. Mutable tags objects are\n// re-encoded every time. Callers create one fragment encoder per codec\n// because it bakes in that codec's stringify options.\nfunction createTagsFragment(encoder: JsonStringify, cached: boolean): TagsFragment {\n const fragments = cached ? new WeakMap<object, string>() : undefined;\n return (tags) => {\n if (fragments && Object.isFrozen(tags)) {\n let fragment = fragments.get(tags);\n if (fragment === undefined) {\n const encoded = encoder(tags);\n fragment = encoded === undefined ? \"\" : `,\"tags\":${encoded}`;\n fragments.set(tags, fragment);\n }\n return fragment;\n }\n const encoded = encoder(tags);\n return encoded === undefined ? \"\" : `,\"tags\":${encoded}`;\n };\n}\n\nexport function fastEventJsonCodec(options: FastEventJsonCodecOptions = {}): Codec<string> {\n const stringify = createStringify(options);\n const safeStringify: JsonStringify = (value) => safeJsonStringify(value, options);\n const useNativeEventJson = canUseNativeEventJson(options);\n const tagsFragment = createTagsFragment(stringify, true);\n // The fallback must not reuse the fast fragments: a cached entry or the\n // fast stringify could throw on the exact payload that triggered fallback.\n const safeTagsFragment = createTagsFragment(safeStringify, false);\n const fastEncode = (input: CodecInput): string => {\n if (isCodecArray(input)) {\n if (useNativeEventJson && !hasLogRecord(input)) return JSON.stringify(input);\n return encodeArray(input, options, stringify, tagsFragment);\n }\n if (useNativeEventJson && !isLogRecord(input)) return JSON.stringify(input);\n return encodeItem(input, options, stringify, tagsFragment);\n };\n return {\n name: \"fast-event-json\",\n contentType: \"application/json\",\n encode(input: CodecInput) {\n // Circular references and BigInt values throw on the native fast path. Logs\n // must never be lost to encoding, so re-encode the input with the safe\n // stringifier instead of surfacing the error as a transport failure.\n try {\n return fastEncode(input);\n } catch {\n incrementLoggerMetaCounter(\"codec.fallback\");\n incrementLoggerMetaCounter(\"codec.fallback.fast-event-json\");\n }\n if (isCodecArray(input)) return encodeArray(input, options, safeStringify, safeTagsFragment);\n return encodeItem(input, options, safeStringify, safeTagsFragment);\n },\n decode(payload) {\n return JSON.parse(payload) as LogEvent | LogEvent[];\n },\n };\n}\n","import { normalizeCodecInput, type Codec, type CodecInput, type LogEvent } from \"@loggerjs/core\";\nimport { Packr, type Options as MsgpackrOptions } from \"msgpackr\";\n\nexport interface MsgpackRuntime {\n pack: (input: unknown) => Uint8Array;\n unpack: (payload: Uint8Array) => unknown;\n}\n\nexport type MsgpackrCodecOptions = MsgpackrOptions;\n\nfunction isMsgpackRuntime(value: MsgpackRuntime | MsgpackrCodecOptions): value is MsgpackRuntime {\n return (\n typeof (value as MsgpackRuntime).pack === \"function\" &&\n typeof (value as MsgpackRuntime).unpack === \"function\"\n );\n}\n\nexport function msgpackrCodec(\n options: MsgpackRuntime | MsgpackrCodecOptions = {},\n): Codec<Uint8Array> {\n const runtime = isMsgpackRuntime(options) ? options : new Packr({ useRecords: true, ...options });\n return {\n name: \"msgpackr\",\n contentType: \"application/msgpack\",\n encode(input: CodecInput) {\n return runtime.pack(normalizeCodecInput(input));\n },\n decode(payload: Uint8Array) {\n return runtime.unpack(payload) as LogEvent | LogEvent[];\n },\n };\n}\n","import { normalizeCodecInput, type Codec, type CodecInput, type LogEvent } from \"@loggerjs/core\";\n\nexport interface ProjectorCodecOptions<TWire> {\n name: string;\n contentType: string;\n project: (input: LogEvent | LogEvent[]) => TWire;\n serialize: (wire: TWire) => string | Uint8Array;\n parse?: (payload: string | Uint8Array) => TWire;\n unproject?: (wire: TWire) => LogEvent | LogEvent[];\n}\n\nexport function projectorCodec<TWire>(\n options: ProjectorCodecOptions<TWire>,\n): Codec<string | Uint8Array> {\n return {\n name: options.name,\n contentType: options.contentType,\n encode(input: CodecInput) {\n return options.serialize(options.project(normalizeCodecInput(input)));\n },\n decode:\n options.parse && options.unproject\n ? (payload) => options.unproject!(options.parse!(payload))\n : undefined,\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":["hasSafeOptions"],"sources":["../src/fast-event-json.ts","../src/msgpackr.ts","../src/pino-compat.ts","../src/projector.ts"],"sourcesContent":["import {\n defaultRecordId,\n incrementLoggerMetaCounter,\n isLogRecord,\n normalizeError,\n resolveMessage,\n toLevelName,\n safeJsonStringify,\n type Codec,\n type CodecInput,\n type PreparedRecordEncoder,\n type LogEvent,\n type LogRecord,\n type RecordEncoderHints,\n type SafeStringifyOptions,\n} from \"@loggerjs/core\";\n\n/**\n * Without any option set, encode runs on a native `JSON.stringify` fast path: nested\n * `Error` values serialize as `{}` and circular or BigInt payloads trigger a safe\n * re-encode of the whole input (circular refs become \"[Circular]\", BigInt becomes a\n * string). Setting any {@link SafeStringifyOptions} field opts into the safe encoder\n * everywhere, which also preserves `Error` name/message/stack inside data payloads.\n *\n * `includeId`, `includeSeq`, and `includeLevelName` trim the envelope for\n * lean comparable JSON output; turning `includeId` off also skips id\n * computation entirely on the record path.\n */\nexport interface FastEventJsonCodecOptions extends SafeStringifyOptions {\n includeContext?: boolean;\n includeData?: boolean;\n includeError?: boolean;\n includeTrace?: boolean;\n includeSource?: boolean;\n includeId?: boolean;\n includeSeq?: boolean;\n includeLevelName?: boolean;\n}\n\ntype JsonStringify = (value: unknown) => string | undefined;\n\nfunction hasSafeOptions(options: SafeStringifyOptions): boolean {\n return (\n options.maxDepth !== undefined ||\n options.maxArrayLength !== undefined ||\n options.maxObjectKeys !== undefined ||\n options.includeStack !== undefined ||\n options.stable !== undefined ||\n options.space !== undefined\n );\n}\n\nfunction canUseNativeEventJson(options: FastEventJsonCodecOptions): boolean {\n return (\n !hasSafeOptions(options) &&\n options.includeContext !== false &&\n options.includeData !== false &&\n options.includeError !== false &&\n options.includeTrace !== false &&\n options.includeSource !== false &&\n options.includeId !== false &&\n options.includeSeq !== false &&\n options.includeLevelName !== false\n );\n}\n\nfunction hasFullHeader(options: FastEventJsonCodecOptions): boolean {\n return (\n (options.includeId ?? true) &&\n (options.includeSeq ?? true) &&\n (options.includeLevelName ?? true)\n );\n}\n\n// Resolve every `includeX ?? true` toggle once per codec instead of on every\n// encode call. Threading these baked booleans through the encoders lets V8 keep\n// the hot path monomorphic and removes the per-call option lookups.\ninterface ResolvedFlags {\n fullHeader: boolean;\n includeId: boolean;\n includeSeq: boolean;\n includeLevelName: boolean;\n includeData: boolean;\n includeError: boolean;\n includeContext: boolean;\n includeTrace: boolean;\n includeSource: boolean;\n}\n\nfunction resolveFlags(options: FastEventJsonCodecOptions): ResolvedFlags {\n return {\n fullHeader: hasFullHeader(options),\n includeId: options.includeId ?? true,\n includeSeq: options.includeSeq ?? true,\n includeLevelName: options.includeLevelName ?? true,\n includeData: options.includeData ?? true,\n includeError: options.includeError ?? true,\n includeContext: options.includeContext ?? true,\n includeTrace: options.includeTrace ?? true,\n includeSource: options.includeSource ?? true,\n };\n}\n\nfunction createStringify(options: SafeStringifyOptions): JsonStringify {\n if (hasSafeOptions(options)) return (value) => safeJsonStringify(value, options);\n return JSON.stringify;\n}\n\nfunction appendField(\n output: string,\n name: string,\n value: unknown,\n stringify: JsonStringify,\n): string {\n if (value === undefined) return output;\n const encoded = stringify(value);\n return encoded === undefined ? output : `${output},\"${name}\":${encoded}`;\n}\n\n// JSON.stringify costs ~35ns per short string mostly in call overhead. Short\n// strings without quotes, backslashes, or control characters can be quoted\n// directly after a linear scan.\nfunction asJsonString(value: string): string {\n if (value.length > 256) return JSON.stringify(value);\n for (let index = 0; index < value.length; index += 1) {\n const code = value.charCodeAt(index);\n if (code === 34 || code === 92 || code < 32) return JSON.stringify(value);\n }\n return `\"${value}\"`;\n}\n\n// Data payloads are usually small flat objects of primitives. Writing them\n// directly skips the native JSON.stringify call overhead; any nested or\n// exotic value bails out so the caller can use the configured stringifier.\nfunction tryFlatObjectJson(value: Record<string, unknown>): string | undefined {\n // Class instances may carry toJSON or accessors; only plain objects take\n // the fast path so behavior matches JSON.stringify.\n const proto = Object.getPrototypeOf(value) as unknown;\n if (proto !== Object.prototype && proto !== null) return undefined;\n let output = \"{\";\n let first = true;\n // Object.keys (not for..in) on purpose: it returns only own enumerable keys,\n // so a polluted Object.prototype cannot leak inherited keys into log output.\n for (const key of Object.keys(value)) {\n const item = value[key];\n let encoded: string;\n switch (typeof item) {\n case \"string\":\n encoded = asJsonString(item);\n break;\n case \"number\":\n encoded = Number.isFinite(item) ? String(item) : \"null\";\n break;\n case \"boolean\":\n encoded = item ? \"true\" : \"false\";\n break;\n case \"object\":\n if (item !== null) return undefined;\n encoded = \"null\";\n break;\n case \"undefined\":\n continue;\n default:\n return undefined;\n }\n output += `${first ? \"\" : \",\"}${asJsonString(key)}:${encoded}`;\n first = false;\n }\n return `${output}}`;\n}\n\nfunction appendDataField(\n output: string,\n value: Record<string, unknown> | undefined,\n stringify: JsonStringify,\n): string {\n if (value === undefined) return output;\n const flat = tryFlatObjectJson(value);\n if (flat !== undefined) return `${output},\"data\":${flat}`;\n return appendField(output, \"data\", value, stringify);\n}\n\n// The timestamp changes once per millisecond while bursts of records share\n// it, so the rendered `\",\"time\":...,\"seq\":` fragment can be memoized the same\n// way the default id memoizes its time segment.\nlet lastFragmentTime = -1;\nlet lastTimeFragment = \"\";\n\nfunction timeFragment(time: number): string {\n if (time !== lastFragmentTime) {\n lastFragmentTime = time;\n lastTimeFragment = `\",\"time\":${time},\"seq\":`;\n }\n return lastTimeFragment;\n}\n\n// level -> ',\"level\":30,\"levelName\":\"info\",\"logger\":' — derived from the\n// numeric level alone, so a module-level cache is safe.\nconst levelFragments = new Map<number, string>();\n\nfunction levelFragment(level: number): string {\n let fragment = levelFragments.get(level);\n if (fragment === undefined) {\n fragment = `,\"level\":${level},\"levelName\":\"${toLevelName(level)}\",\"logger\":`;\n levelFragments.set(level, fragment);\n }\n return fragment;\n}\n\n// Loggers reuse one frozen category array for every record, so the joined and\n// escaped logger name can be cached per array identity.\nconst categoryFragments = new WeakMap<readonly string[], string>();\n\nfunction loggerFragment(category: readonly string[]): string {\n let fragment = categoryFragments.get(category);\n if (fragment === undefined) {\n fragment = asJsonString(category.join(\".\"));\n categoryFragments.set(category, fragment);\n }\n return fragment;\n}\n\nfunction errorForRecord(record: LogRecord): LogEvent[\"error\"] | undefined {\n if (record.err === null || record.err === undefined) return undefined;\n return normalizeError(record.err);\n}\n\ninterface PreparedRecordFragments {\n category: readonly string[];\n logger: string;\n tags: LogRecord[\"tags\"];\n tagsFragment?: string;\n}\n\nfunction tryPrepareTagsFragment(\n tags: LogRecord[\"tags\"],\n tagsFragment: (tags: NonNullable<LogRecord[\"tags\"]>) => string,\n): string | undefined {\n if (tags === null || !Object.isFrozen(tags)) return undefined;\n try {\n return tagsFragment(tags);\n } catch {\n return undefined;\n }\n}\n\nfunction loggerFragmentForRecord(\n record: LogRecord,\n prepared: PreparedRecordFragments | undefined,\n): string {\n if (prepared && record.category === prepared.category) return prepared.logger;\n return loggerFragment(record.category);\n}\n\nfunction tagsFragmentForRecord(\n record: LogRecord,\n tagsFragment: (tags: NonNullable<LogRecord[\"tags\"]>) => string,\n prepared: PreparedRecordFragments | undefined,\n): string {\n if (record.tags === null) return \"\";\n if (prepared && record.tags === prepared.tags && prepared.tagsFragment !== undefined) {\n return prepared.tagsFragment;\n }\n return tagsFragment(record.tags);\n}\n\nfunction encodeEvent(\n event: LogEvent,\n flags: ResolvedFlags,\n stringify: JsonStringify,\n tagsFragment: (tags: NonNullable<LogEvent[\"tags\"]>) => string,\n): string {\n let output: string;\n if (flags.fullHeader) {\n output = `{\"id\":${asJsonString(event.id)},\"time\":${event.time},\"seq\":${event.seq},\"level\":${event.level},\"levelName\":${asJsonString(event.levelName)},\"logger\":${asJsonString(event.logger)},\"message\":${asJsonString(event.message)}`;\n } else {\n // Build the header in one template literal: empty conditional fragments cost\n // nothing, and a single concatenation avoids the chain of intermediate\n // strings the previous `+=` sequence allocated per call.\n const idPart = flags.includeId ? `\"id\":${asJsonString(event.id)},` : \"\";\n const seqPart = flags.includeSeq ? `,\"seq\":${event.seq}` : \"\";\n const levelNamePart = flags.includeLevelName\n ? `,\"levelName\":${asJsonString(event.levelName)}`\n : \"\";\n output = `{${idPart}\"time\":${event.time}${seqPart},\"level\":${event.level}${levelNamePart},\"logger\":${asJsonString(event.logger)},\"message\":${asJsonString(event.message)}`;\n }\n if (event.type !== undefined) output += `,\"type\":${asJsonString(event.type)}`;\n if (event.tags !== undefined) output += tagsFragment(event.tags);\n if (flags.includeData && event.data !== undefined)\n output = appendField(output, \"data\", event.data, stringify);\n if (flags.includeError && event.error !== undefined)\n output = appendField(output, \"error\", event.error, stringify);\n if (flags.includeContext && event.context !== undefined)\n output = appendField(output, \"context\", event.context, stringify);\n if (flags.includeTrace && event.trace !== undefined)\n output = appendField(output, \"trace\", event.trace, stringify);\n if (flags.includeSource && event.source !== undefined)\n output = appendField(output, \"source\", event.source, stringify);\n return `${output}}`;\n}\n\nfunction encodeRecord(\n record: LogRecord,\n flags: ResolvedFlags,\n stringify: JsonStringify,\n tagsFragment: (tags: NonNullable<LogRecord[\"tags\"]>) => string,\n prepared?: PreparedRecordFragments,\n): string {\n let output: string;\n if (flags.fullHeader) {\n // The default id only contains [0-9a-z-] and the level name, so it never\n // needs escaping.\n const levelName = toLevelName(record.level);\n output = `{\"id\":\"${defaultRecordId(record, levelName)}${timeFragment(record.time)}${record.seq}${levelFragment(record.level)}${loggerFragmentForRecord(record, prepared)},\"message\":${asJsonString(resolveMessage(record))}`;\n } else {\n // The header is built in one template literal so it costs a single\n // concatenation per record; empty conditional fragments cost nothing. The\n // level name is resolved only when the id or the levelName field needs it,\n // so the lean envelope (both off) skips the lookup. The \"info\" default is\n // never emitted in that case — both fragments stay empty.\n const levelName =\n flags.includeId || flags.includeLevelName ? toLevelName(record.level) : \"info\";\n const idPart = flags.includeId ? `\"id\":\"${defaultRecordId(record, levelName)}\",` : \"\";\n const seqPart = flags.includeSeq ? `,\"seq\":${record.seq}` : \"\";\n const levelNamePart = flags.includeLevelName ? `,\"levelName\":\"${levelName}\"` : \"\";\n output = `{${idPart}\"time\":${record.time}${seqPart},\"level\":${record.level}${levelNamePart},\"logger\":${loggerFragmentForRecord(record, prepared)},\"message\":${asJsonString(resolveMessage(record))}`;\n }\n if (record.type !== null) output += `,\"type\":${asJsonString(record.type)}`;\n output += tagsFragmentForRecord(record, tagsFragment, prepared);\n // Guard each optional tail on the record field directly so a null field skips\n // the helper call (and its argument evaluation) entirely, matching the prior\n // `?? undefined` no-op behavior without the per-call cost.\n if (flags.includeData && record.props != null)\n output = appendDataField(output, record.props, stringify);\n if (flags.includeError && record.err != null)\n output = appendField(output, \"error\", errorForRecord(record), stringify);\n if (flags.includeContext && record.ctx != null)\n output = appendField(output, \"context\", record.ctx, stringify);\n if (flags.includeTrace && record.trace != null)\n output = appendField(output, \"trace\", record.trace, stringify);\n if (flags.includeSource && record.source !== \"app\")\n output += `,\"source\":{\"integration\":${asJsonString(record.source)}}`;\n return `${output}}`;\n}\n\ntype TagsFragment = (tags: NonNullable<LogEvent[\"tags\"]>) => string;\n\nfunction encodeItem(\n item: LogEvent | LogRecord,\n flags: ResolvedFlags,\n stringify: JsonStringify,\n tagsFragment: TagsFragment,\n): string {\n return isLogRecord(item)\n ? encodeRecord(item, flags, stringify, tagsFragment)\n : encodeEvent(item, flags, stringify, tagsFragment);\n}\n\nfunction encodeArray(\n items: readonly (LogEvent | LogRecord)[],\n flags: ResolvedFlags,\n stringify: JsonStringify,\n tagsFragment: TagsFragment,\n): string {\n let output = \"[\";\n for (let index = 0; index < items.length; index += 1) {\n if (index > 0) output += \",\";\n output += encodeItem(items[index]!, flags, stringify, tagsFragment);\n }\n return `${output}]`;\n}\n\nfunction isCodecArray(input: CodecInput): input is readonly (LogEvent | LogRecord)[] {\n return Array.isArray(input);\n}\n\nfunction hasLogRecord(items: readonly (LogEvent | LogRecord)[]): boolean {\n for (const item of items) {\n if (isLogRecord(item)) return true;\n }\n return false;\n}\n\n// Loggers share one frozen tags object across records, so the encoded\n// fragment can be cached per object identity. Mutable tags objects are\n// re-encoded every time. Callers create one fragment encoder per codec\n// because it bakes in that codec's stringify options.\nfunction createTagsFragment(encoder: JsonStringify, cached: boolean): TagsFragment {\n const fragments = cached ? new WeakMap<object, string>() : undefined;\n return (tags) => {\n if (fragments && Object.isFrozen(tags)) {\n let fragment = fragments.get(tags);\n if (fragment === undefined) {\n const encoded = encoder(tags);\n fragment = encoded === undefined ? \"\" : `,\"tags\":${encoded}`;\n fragments.set(tags, fragment);\n }\n return fragment;\n }\n const encoded = encoder(tags);\n return encoded === undefined ? \"\" : `,\"tags\":${encoded}`;\n };\n}\n\nexport function fastEventJsonCodec(options: FastEventJsonCodecOptions = {}): Codec<string> {\n const stringify = createStringify(options);\n const safeStringify: JsonStringify = (value) => safeJsonStringify(value, options);\n const useNativeEventJson = canUseNativeEventJson(options);\n // Bake the envelope toggles once so neither the fast nor the safe encoder\n // re-derives them per call.\n const flags = resolveFlags(options);\n const tagsFragment = createTagsFragment(stringify, true);\n // The fallback must not reuse the fast fragments: a cached entry or the\n // fast stringify could throw on the exact payload that triggered fallback.\n const safeTagsFragment = createTagsFragment(safeStringify, false);\n const fastEncode = (input: CodecInput): string => {\n if (isCodecArray(input)) {\n if (useNativeEventJson && !hasLogRecord(input)) return JSON.stringify(input);\n return encodeArray(input, flags, stringify, tagsFragment);\n }\n // Dispatch the single-item case directly to the concrete encoder, skipping\n // the encodeItem indirection and resolving the record/event branch once.\n if (isLogRecord(input)) return encodeRecord(input, flags, stringify, tagsFragment);\n if (useNativeEventJson) return JSON.stringify(input);\n return encodeEvent(input, flags, stringify, tagsFragment);\n };\n return {\n name: \"fast-event-json\",\n contentType: \"application/json\",\n encode(input: CodecInput) {\n // Circular references and BigInt values throw on the native fast path. Logs\n // must never be lost to encoding, so re-encode the input with the safe\n // stringifier instead of surfacing the error as a transport failure.\n try {\n return fastEncode(input);\n } catch {\n incrementLoggerMetaCounter(\"codec.fallback\");\n incrementLoggerMetaCounter(\"codec.fallback.fast-event-json\");\n }\n if (isCodecArray(input)) return encodeArray(input, flags, safeStringify, safeTagsFragment);\n return encodeItem(input, flags, safeStringify, safeTagsFragment);\n },\n decode(payload) {\n return JSON.parse(payload) as LogEvent | LogEvent[];\n },\n prepareRecordEncoder(hints: RecordEncoderHints): PreparedRecordEncoder<string> {\n const prepared: PreparedRecordFragments = {\n category: hints.category,\n logger: loggerFragment(hints.category),\n tags: hints.tags,\n tagsFragment: tryPrepareTagsFragment(hints.tags, tagsFragment),\n };\n return {\n encode(record: LogRecord) {\n try {\n return encodeRecord(record, flags, stringify, tagsFragment, prepared);\n } catch {\n incrementLoggerMetaCounter(\"codec.fallback\");\n incrementLoggerMetaCounter(\"codec.fallback.fast-event-json\");\n }\n return encodeRecord(record, flags, safeStringify, safeTagsFragment, {\n category: prepared.category,\n logger: prepared.logger,\n tags: prepared.tags,\n });\n },\n };\n },\n };\n}\n","import { normalizeCodecInput, type Codec, type CodecInput, type LogEvent } from \"@loggerjs/core\";\nimport { Packr, type Options as MsgpackrOptions } from \"msgpackr\";\n\nexport interface MsgpackRuntime {\n pack: (input: unknown) => Uint8Array;\n unpack: (payload: Uint8Array) => unknown;\n}\n\nexport type MsgpackrCodecOptions = MsgpackrOptions;\n\nfunction isMsgpackRuntime(value: MsgpackRuntime | MsgpackrCodecOptions): value is MsgpackRuntime {\n return (\n typeof (value as MsgpackRuntime).pack === \"function\" &&\n typeof (value as MsgpackRuntime).unpack === \"function\"\n );\n}\n\nexport function msgpackrCodec(\n options: MsgpackRuntime | MsgpackrCodecOptions = {},\n): Codec<Uint8Array> {\n const runtime = isMsgpackRuntime(options) ? options : new Packr({ useRecords: true, ...options });\n return {\n name: \"msgpackr\",\n contentType: \"application/msgpack\",\n encode(input: CodecInput) {\n return runtime.pack(normalizeCodecInput(input));\n },\n decode(payload: Uint8Array) {\n return runtime.unpack(payload) as LogEvent | LogEvent[];\n },\n };\n}\n","import {\n incrementLoggerMetaCounter,\n normalizeCodecInput,\n safeJsonStringify,\n type Codec,\n type CodecInput,\n type LogEvent,\n type SafeStringifyOptions,\n type SerializedError,\n} from \"@loggerjs/core\";\n\nexport type PinoCompatCollisionPolicy = \"nest\" | \"drop\" | \"throw\";\n\nexport interface PinoCompatCodecOptions extends SafeStringifyOptions {\n base?: Record<string, unknown>;\n dataKey?: string;\n errorKey?: string;\n includeLogger?: boolean;\n mergeData?: boolean;\n collision?: PinoCompatCollisionPolicy;\n}\n\nconst baseReservedRootKeys = new Set([\"time\", \"level\", \"msg\", \"err\", \"logger\", \"data\"]);\nconst dataReservedRootKeys = new Set([\n \"time\",\n \"level\",\n \"msg\",\n \"pid\",\n \"hostname\",\n \"err\",\n \"logger\",\n \"data\",\n]);\n\nfunction hasSafeOptions(options: SafeStringifyOptions): boolean {\n return (\n options.maxDepth !== undefined ||\n options.maxArrayLength !== undefined ||\n options.maxObjectKeys !== undefined ||\n options.includeStack !== undefined ||\n options.stable !== undefined ||\n options.space !== undefined\n );\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return Boolean(value) && typeof value === \"object\" && !Array.isArray(value);\n}\n\nfunction pinoError(error: SerializedError): Record<string, unknown> {\n return {\n type: error.name ?? \"Error\",\n message: error.message,\n stack: error.stack,\n code: error.code,\n cause: error.cause,\n };\n}\n\nfunction assignWithCollision(\n output: Record<string, unknown>,\n nested: Record<string, unknown>,\n key: string,\n value: unknown,\n policy: PinoCompatCollisionPolicy,\n reservedKeys = dataReservedRootKeys,\n) {\n if (!reservedKeys.has(key) && !(key in output)) {\n output[key] = value;\n return;\n }\n\n if (policy === \"throw\") {\n throw new Error(`pinoCompatCodec cannot merge reserved key \"${key}\"`);\n }\n if (policy === \"nest\") nested[key] = value;\n}\n\nfunction mergeNestedData(\n existing: unknown,\n nested: Record<string, unknown>,\n): Record<string, unknown> {\n if (isRecord(existing)) return { ...nested, ...existing };\n if (existing !== undefined) return { ...nested, value: existing };\n return nested;\n}\n\nfunction projectEvent(event: LogEvent, options: PinoCompatCodecOptions): Record<string, unknown> {\n const dataKey = options.dataKey ?? \"data\";\n const errorKey = options.errorKey ?? \"err\";\n const collision = options.collision ?? \"nest\";\n const output: Record<string, unknown> = {\n level: event.level,\n time: event.time,\n };\n const nested: Record<string, unknown> = {};\n\n const baseReservedKeys = new Set(baseReservedRootKeys);\n baseReservedKeys.add(dataKey);\n baseReservedKeys.add(errorKey);\n for (const [key, value] of Object.entries(options.base ?? {})) {\n assignWithCollision(output, nested, key, value, collision, baseReservedKeys);\n }\n\n if (options.includeLogger) output.logger = event.logger;\n if (event.error) output[errorKey] = pinoError(event.error);\n\n if (event.data !== undefined) {\n if (options.mergeData && isRecord(event.data)) {\n const dataReservedKeys = new Set(dataReservedRootKeys);\n dataReservedKeys.add(dataKey);\n dataReservedKeys.add(errorKey);\n for (const [key, value] of Object.entries(event.data)) {\n assignWithCollision(output, nested, key, value, collision, dataReservedKeys);\n }\n } else {\n output[dataKey] = event.data;\n }\n }\n\n if (Object.keys(nested).length > 0) {\n output[dataKey] = mergeNestedData(output[dataKey], nested);\n }\n\n output.msg = event.message;\n\n return output;\n}\n\nfunction encodeLine(event: LogEvent, options: PinoCompatCodecOptions, safeMode: boolean): string {\n const projected = projectEvent(event, options);\n if (safeMode) return safeJsonStringify(projected, options);\n try {\n const encoded = JSON.stringify(projected);\n return encoded ?? \"{}\";\n } catch {\n incrementLoggerMetaCounter(\"codec.fallback\");\n incrementLoggerMetaCounter(\"codec.fallback.pino-compat\");\n return safeJsonStringify(projected, options);\n }\n}\n\nfunction encodeEvents(\n input: LogEvent | LogEvent[],\n options: PinoCompatCodecOptions,\n safeMode: boolean,\n): string {\n if (!Array.isArray(input)) return `${encodeLine(input, options, safeMode)}\\n`;\n let output = \"\";\n for (const event of input) output += `${encodeLine(event, options, safeMode)}\\n`;\n return output;\n}\n\nexport function pinoCompatCodec(options: PinoCompatCodecOptions = {}): Codec<string> {\n const safeMode = hasSafeOptions(options);\n return {\n name: \"pino-compat\",\n contentType: \"application/x-ndjson\",\n encode(input: CodecInput) {\n return encodeEvents(normalizeCodecInput(input), options, safeMode);\n },\n };\n}\n\nexport const pinoNdjsonProjector = pinoCompatCodec;\n","import { normalizeCodecInput, type Codec, type CodecInput, type LogEvent } from \"@loggerjs/core\";\n\nexport interface ProjectorCodecOptions<TWire> {\n name: string;\n contentType: string;\n project: (input: LogEvent | LogEvent[]) => TWire;\n serialize: (wire: TWire) => string | Uint8Array;\n parse?: (payload: string | Uint8Array) => TWire;\n unproject?: (wire: TWire) => LogEvent | LogEvent[];\n}\n\nexport function projectorCodec<TWire>(\n options: ProjectorCodecOptions<TWire>,\n): Codec<string | Uint8Array> {\n return {\n name: options.name,\n contentType: options.contentType,\n encode(input: CodecInput) {\n return options.serialize(options.project(normalizeCodecInput(input)));\n },\n decode:\n options.parse && options.unproject\n ? (payload) => options.unproject!(options.parse!(payload))\n : undefined,\n };\n}\n"],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import { type Codec, type SafeStringifyOptions } from "@loggerjs/core";
2
+ export type PinoCompatCollisionPolicy = "nest" | "drop" | "throw";
3
+ export interface PinoCompatCodecOptions extends SafeStringifyOptions {
4
+ base?: Record<string, unknown>;
5
+ dataKey?: string;
6
+ errorKey?: string;
7
+ includeLogger?: boolean;
8
+ mergeData?: boolean;
9
+ collision?: PinoCompatCollisionPolicy;
10
+ }
11
+ export declare function pinoCompatCodec(options?: PinoCompatCodecOptions): Codec<string>;
12
+ export declare const pinoNdjsonProjector: typeof pinoCompatCodec;
13
+ //# sourceMappingURL=pino-compat.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pino-compat.d.ts","sourceRoot":"","sources":["../src/pino-compat.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,KAAK,EAGV,KAAK,oBAAoB,EAE1B,MAAM,gBAAgB,CAAC;AAExB,MAAM,MAAM,yBAAyB,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAElE,MAAM,WAAW,sBAAuB,SAAQ,oBAAoB;IAClE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,SAAS,CAAC,EAAE,yBAAyB,CAAC;CACvC;AAqID,wBAAgB,eAAe,CAAC,OAAO,GAAE,sBAA2B,GAAG,KAAK,CAAC,MAAM,CAAC,CASnF;AAED,eAAO,MAAM,mBAAmB,wBAAkB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@loggerjs/codecs",
3
- "version": "0.1.0",
3
+ "version": "0.3.1",
4
4
  "description": "Serialization codecs for loggerjs.",
5
5
  "homepage": "https://github.com/jskits/loggerjs/tree/main/packages/codecs#readme",
6
6
  "bugs": {
@@ -35,7 +35,7 @@
35
35
  },
36
36
  "dependencies": {
37
37
  "msgpackr": "^2.0.4",
38
- "@loggerjs/core": "0.1.0"
38
+ "@loggerjs/core": "0.3.1"
39
39
  },
40
40
  "scripts": {
41
41
  "build": "pnpm run clean && pnpm run build:js && pnpm run build:types",