loggily 0.7.0 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"worker.d.mts","names":[],"sources":["../src/worker.ts"],"mappings":";;;;UAuDiB,oBAAA;EACf,IAAA;EACA,KAAA;EACA,SAAA;EACA,IAAA;EACA,SAAA;AAAA;;UAIe,gBAAA;EACf,IAAA;EACA,KAAA;EACA,SAAA;EACA,OAAA;EACA,IAAA,GAAO,MAAA;EACP,SAAA;AAAA;;UAIe,iBAAA;EACf,IAAA;EACA,KAAA;EACA,SAAA;EACA,MAAA;EACA,OAAA;EACA,QAAA;EACA,SAAA;EACA,OAAA;EACA,QAAA;EACA,KAAA,EAAO,MAAA;EACP,QAAA,EAAU,MAAA;EACV,SAAA;AAAA;;KAIU,aAAA,GAAgB,oBAAA,GAAuB,gBAAA,GAAmB,iBAAA;;iBAGtD,sBAAA,CAAuB,GAAA,YAAe,GAAA,IAAO,oBAAA;AAoB7D;AAAA,iBAVgB,kBAAA,CAAmB,GAAA,YAAe,GAAA,IAAO,gBAAA;;iBAUzC,mBAAA,CAAoB,GAAA,YAAe,GAAA,IAAO,iBAAA;;iBAS1C,eAAA,CAAgB,GAAA,YAAe,GAAA,IAAO,aAAA;AAAA,KAMjD,aAAA,IAAiB,OAAA,EAAS,oBAAA;;;AAN/B;;;;;;;;;AAEC;;;;;AA+ED;;;;iBAAgB,cAAA,CAAe,WAAA,EAAa,aAAA,EAAe,SAAA;;;;;iBAiC3C,cAAA,CAAA;AAAA,KASX,gBAAA,IAAoB,OAAA,EAAS,aAAA;;iBAclB,cAAA,CAAA;AAAA,UAKN,mBAAA;EAnBL;EAqBH,YAAA;;EAEA,OAAA;AAAA;AATF;;;;;AAGC;;;;;AAoCD;;;;;;;;;;;;;;;;;AAvCA,iBAuCgB,kBAAA,CACd,WAAA,EAAa,gBAAA,EACb,SAAA,UACA,KAAA,GAAO,MAAA,mBACP,OAAA,GAAS,mBAAA,GACR,MAAA;AAAA,UAmNc,2BAAA;EAAA;EAEf,gBAAA;;EAEA,MAAA,GAAS,MAAA;AAAA;;;;;AAkFX;;;;;;;;;;AAyBA;;;;;AA6BA;;;;;;iBAtDgB,0BAAA,CACd,OAAA,GAAS,2BAAA,IACP,OAAA,EAAS,oBAAA;AAAA,UAuBI,uBAAA;EA6BqF;EA3BpG,WAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;;iBA2Bc,sBAAA,CAAuB,OAAA,GAAS,uBAAA,IAAgC,OAAA,EAAS,aAAA"}
1
+ {"version":3,"file":"worker.d.mts","names":[],"sources":["../src/worker.ts"],"mappings":";;;;;UA8CiB,oBAAA;EACf,IAAA;EACA,KAAA;EACA,SAAA;EACA,IAAA;EACA,SAAA;AAAA;;iBAMc,gBAAA,CAAiB,GAAA,YAAe,GAAA,IAAO,QAAA;AAyBvD;AAAA,iBApBgB,iBAAA,CAAkB,GAAA,YAAe,GAAA,IAAO,SAAA;;iBAKxC,aAAA,CAAc,GAAA,YAAe,GAAA,IAAO,KAAA;;iBAKpC,sBAAA,CAAuB,GAAA,YAAe,GAAA,IAAO,oBAAA;;iBAU7C,eAAA,CAAgB,GAAA,YAAe,GAAA,IAAO,oBAAA,GAAuB,KAAA;AAAA,KAMxE,aAAA,IAAiB,OAAA,EAAS,oBAAA;;AAJ9B;;;;;AAuBD;;;;;;;;iBAAgB,cAAA,CAAe,WAAA,EAAa,aAAA,EAAe,SAAA;AA8B3D;;;;AAAA,iBAAgB,cAAA,CAAA;AAiBhB;;;;;;;;AAAA,iBAAgB,oBAAA,CAAqB,WAAA,GAAc,GAAA,qBAAwB,KAAA;AA0C3E;;;;;;;;;;;;AAsBA;;;;;;;;;;;;AA4BA;;AAlDA,iBAAgB,kBAAA,CACd,WAAA,GAAc,GAAA,oBACd,SAAA,UACA,KAAA,GAAQ,MAAA,oBACP,iBAAA;;;AAwEH;;;;;;iBAtDgB,kBAAA,CACd,MAAA,EAAQ,iBAAA;EAAsB,QAAA,CAAS,KAAA,EAAO,KAAA;AAAA,KAC5C,GAAA;;;;AAwIJ;;;;;;;;;;;;;iBA9GgB,sBAAA,CAAA,IAA2B,OAAA;AAAA,UA0B1B,2BAAA;;EAEf,gBAAA;;EAEA,MAAA;IAAW,IAAA;IAAc,QAAA,CAAS,KAAA,EAAO,KAAA;EAAA;AAAA;;;;;;;;;;;;;;;;;;;;;;;;iBAgF3B,0BAAA,CACd,OAAA,GAAS,2BAAA,IACP,OAAA,EAAS,oBAAA"}
package/dist/worker.mjs CHANGED
@@ -1,22 +1,21 @@
1
- import { c as createLogger, l as createSpanDataProxy } from "./core-Du3sIje6.mjs";
2
- import "./index.mjs";
1
+ import { a as baseCreateLogger, j as withSpans, s as createLogger, v as pipe } from "./core-B3pox577.mjs";
3
2
  //#region src/worker.ts
4
3
  /**
5
4
  * Worker Thread Logger/Console Forwarding
6
5
  *
7
- * Provides utilities to forward loggily and console.* output from worker threads
8
- * to the main thread, ensuring proper integration with DEBUG_LOG and log files.
6
+ * Pipeline-based worker logging: worker loggers use a postMessage transport
7
+ * so events flow through the main thread's pipeline for output.
9
8
  *
10
- * ## Full Logger Forwarding (Recommended)
9
+ * ## Structured Logger (Recommended)
11
10
  *
12
11
  * @example Worker side:
13
12
  * ```typescript
14
13
  * import { createWorkerLogger } from "loggily/worker"
15
14
  * const log = createWorkerLogger(postMessage, "km:worker:parse")
16
15
  *
17
- * log.info("processing", { file: "test.md" })
16
+ * log.info?.("processing", { file: "test.md" })
18
17
  * {
19
- * using span = log.span("parse")
18
+ * using span = log.span?.("parse")
20
19
  * // ... work ...
21
20
  * span.spanData.lines = 100
22
21
  * }
@@ -27,9 +26,7 @@ import "./index.mjs";
27
26
  * import { createWorkerLogHandler } from "loggily/worker"
28
27
  *
29
28
  * const handleLog = createWorkerLogHandler()
30
- * worker.onmessage = (e) => {
31
- * if (e.data.type === "log" || e.data.type === "span") handleLog(e.data)
32
- * }
29
+ * worker.onmessage = (e) => handleLog(e.data)
33
30
  * ```
34
31
  *
35
32
  * ## Console Forwarding (Simple)
@@ -42,71 +39,40 @@ import "./index.mjs";
42
39
  * console.log("message") // Forwarded to main thread
43
40
  * ```
44
41
  */
42
+ /** Type guard for LogEvent (structured log from worker) */
43
+ function isWorkerLogEvent(msg) {
44
+ return typeof msg === "object" && msg?.kind === "log";
45
+ }
46
+ /** Type guard for SpanEvent (span from worker) */
47
+ function isWorkerSpanEvent(msg) {
48
+ return typeof msg === "object" && msg?.kind === "span";
49
+ }
50
+ /** Type guard for any pipeline Event (log or span) */
51
+ function isWorkerEvent(msg) {
52
+ return isWorkerLogEvent(msg) || isWorkerSpanEvent(msg);
53
+ }
45
54
  /** Type guard for WorkerConsoleMessage */
46
55
  function isWorkerConsoleMessage(msg) {
47
56
  return typeof msg === "object" && msg?.type === "console" && typeof msg.level === "string" && Array.isArray(msg.args);
48
57
  }
49
- /** Type guard for WorkerLogMessage */
50
- function isWorkerLogMessage(msg) {
51
- return typeof msg === "object" && msg?.type === "log" && typeof msg.level === "string" && typeof msg.namespace === "string";
52
- }
53
- /** Type guard for WorkerSpanMessage */
54
- function isWorkerSpanMessage(msg) {
55
- return typeof msg === "object" && msg?.type === "span" && typeof msg.event === "string";
56
- }
57
- /** Type guard for any worker message */
58
+ /** Type guard for any worker message (console or pipeline event) */
58
59
  function isWorkerMessage(msg) {
59
- return isWorkerConsoleMessage(msg) || isWorkerLogMessage(msg) || isWorkerSpanMessage(msg);
60
+ return isWorkerConsoleMessage(msg) || isWorkerEvent(msg);
60
61
  }
61
62
  /** Store original console methods for restoration */
62
63
  let originalConsole = null;
63
64
  /**
64
- * Serialize a value for transmission via postMessage.
65
- * Handles non-serializable values like functions and circular references.
66
- */
67
- function serializeArg(arg, depth = 0) {
68
- if (depth > 5) return "[max depth]";
69
- if (arg === null || arg === void 0) return arg;
70
- if (typeof arg === "function") return `[Function: ${arg.name || "anonymous"}]`;
71
- if (typeof arg === "symbol") return arg.toString();
72
- if (typeof arg === "bigint") return arg.toString() + "n";
73
- if (arg instanceof Error) return {
74
- name: arg.name,
75
- message: arg.message,
76
- stack: arg.stack
77
- };
78
- if (Array.isArray(arg)) return arg.map((v) => serializeArg(v, depth + 1));
79
- if (typeof arg === "object") try {
80
- structuredClone(arg);
81
- return arg;
82
- } catch {
83
- const result = {};
84
- const seen = /* @__PURE__ */ new Set();
85
- seen.add(arg);
86
- for (const [key, value] of Object.entries(arg)) if (typeof value === "object" && value !== null && seen.has(value)) result[key] = "[Circular]";
87
- else result[key] = serializeArg(value, depth + 1);
88
- return result;
89
- }
90
- return arg;
91
- }
92
- /**
93
- * Forward console.* calls from worker to main thread.
94
- *
95
- * Monkey-patches console methods to send messages via postMessage.
96
- * Call this at the start of your worker script.
65
+ * Forward console.* calls from worker to main thread via postMessage.
97
66
  *
98
- * @param postMessage - The worker's postMessage function
99
- * @param namespace - Optional namespace for log messages (e.g., "km:worker:parse")
67
+ * Monkey-patches console methods. postMessage uses structuredClone,
68
+ * which handles most values natively. If cloning fails (functions,
69
+ * symbols), falls back to original console.
100
70
  *
101
71
  * @example
102
72
  * ```typescript
103
- * // At top of worker file:
104
73
  * import { forwardConsole } from "loggily/worker"
105
74
  * forwardConsole(postMessage, "km:worker:parse")
106
- *
107
- * // Now all console.* calls are forwarded:
108
75
  * console.log("processing", { file: "test.md" })
109
- * console.error(new Error("failed"))
110
76
  * ```
111
77
  */
112
78
  function forwardConsole(postMessage, namespace) {
@@ -119,13 +85,16 @@ function forwardConsole(postMessage, namespace) {
119
85
  "error",
120
86
  "trace"
121
87
  ]) console[level] = (...args) => {
122
- const serializedArgs = args.map((arg) => serializeArg(arg));
123
88
  try {
124
89
  postMessage({
125
90
  type: "console",
126
91
  level,
127
92
  namespace,
128
- args: serializedArgs,
93
+ args: args.map((a) => typeof a === "function" ? `[Function: ${a.name || "anonymous"}]` : typeof a === "symbol" ? a.toString() : a instanceof Error ? {
94
+ name: a.name,
95
+ message: a.message,
96
+ stack: a.stack
97
+ } : a),
129
98
  timestamp: Date.now()
130
99
  });
131
100
  } catch {
@@ -143,29 +112,35 @@ function restoreConsole() {
143
112
  originalConsole = null;
144
113
  }
145
114
  }
146
- let workerSpanIdCounter = 0;
147
- let workerTraceIdCounter = 0;
148
- function generateWorkerSpanId() {
149
- return `wsp_${(++workerSpanIdCounter).toString(36)}`;
150
- }
151
- function generateWorkerTraceId() {
152
- return `wtr_${(++workerTraceIdCounter).toString(36)}`;
153
- }
154
- /** Reset worker ID counters (for testing) */
155
- function resetWorkerIds() {
156
- workerSpanIdCounter = 0;
157
- workerTraceIdCounter = 0;
115
+ /**
116
+ * Create a pipeline stage that forwards events via postMessage.
117
+ *
118
+ * Events are plain JSON objects that survive structuredClone natively.
119
+ * The stage consumes events (returns null) so nothing is output locally.
120
+ * The main thread uses handleWorkerEvents() or createWorkerLogHandler()
121
+ * to dispatch them through a local logger pipeline.
122
+ */
123
+ function workerTransportStage(postMessage) {
124
+ return (event) => {
125
+ try {
126
+ postMessage(event);
127
+ } catch {
128
+ try {
129
+ postMessage(JSON.parse(JSON.stringify(event)));
130
+ } catch {}
131
+ }
132
+ return null;
133
+ };
158
134
  }
159
135
  /**
160
- * Create a logger instance for use in a worker thread.
136
+ * Create a logger for use in a worker thread.
161
137
  *
162
- * All log calls and span events are forwarded to the main thread via postMessage.
163
- * The main thread should use createWorkerLogHandler to process these messages.
138
+ * All log and span events are forwarded to the main thread via postMessage.
139
+ * The main thread should use createWorkerLogHandler() to process these messages.
164
140
  *
165
141
  * @param postMessage - The worker's postMessage function
166
142
  * @param namespace - Logger namespace (e.g., "km:worker:parse")
167
143
  * @param props - Optional initial props
168
- * @param options - Optional configuration
169
144
  *
170
145
  * @example
171
146
  * ```typescript
@@ -173,168 +148,69 @@ function resetWorkerIds() {
173
148
  *
174
149
  * const log = createWorkerLogger(postMessage, "km:worker:parse")
175
150
  *
176
- * log.info("starting parse", { file: "test.md" })
151
+ * log.info?.("starting parse", { file: "test.md" })
177
152
  *
178
153
  * {
179
- * using span = log.span("process")
180
- * span.info("processing...")
181
- * span.spanData.lineCount = 100
154
+ * using span = log.span?.("process")
155
+ * span.info?.("processing...")
156
+ * span.spanData.count = 100
182
157
  * }
183
158
  * // Span end event automatically sent to main thread
184
159
  * ```
185
160
  */
186
- function createWorkerLogger(postMessage, namespace, props = {}, options = {}) {
187
- const { parentSpanId = null, traceId = null } = options;
188
- function log(level, message, data) {
189
- const resolved = typeof message === "function" ? message() : message;
190
- try {
191
- postMessage({
192
- type: "log",
193
- level,
194
- namespace,
195
- message: resolved,
196
- data: data ? {
197
- ...props,
198
- ...data
199
- } : Object.keys(props).length > 0 ? props : void 0,
200
- timestamp: Date.now()
201
- });
202
- } catch (err) {
203
- try {
204
- postMessage({
205
- type: "log",
206
- level: "error",
207
- namespace,
208
- message: `postMessage failed for ${level} "${resolved}": ${err instanceof Error ? err.message : String(err)}`,
209
- timestamp: Date.now()
210
- });
211
- } catch {}
161
+ function createWorkerLogger(postMessage, namespace, props) {
162
+ const config = [{ level: "trace" }, workerTransportStage(postMessage)];
163
+ const logger = pipe(baseCreateLogger, withSpans())(namespace, config);
164
+ return props ? logger.child(props) : logger;
165
+ }
166
+ /**
167
+ * Create a handler that dispatches worker events to a target logger.
168
+ *
169
+ * Use this when you have a specific logger to dispatch through.
170
+ *
171
+ * @param target - Logger or object with dispatch method
172
+ * @returns Handler function to call with worker messages
173
+ */
174
+ function handleWorkerEvents(target) {
175
+ return (msg) => {
176
+ if (typeof msg !== "object" || msg === null) return;
177
+ const event = msg;
178
+ if (event.kind === "log" || event.kind === "span") target.dispatch(msg);
179
+ };
180
+ }
181
+ /**
182
+ * Create a zero-config handler for worker logger messages.
183
+ *
184
+ * Automatically creates loggers per-namespace. For console messages,
185
+ * formats args and dispatches through a logger.
186
+ *
187
+ * @returns Handler function to call with any worker message
188
+ *
189
+ * @example
190
+ * ```typescript
191
+ * import { createWorkerLogHandler } from "loggily/worker"
192
+ *
193
+ * const handleLog = createWorkerLogHandler()
194
+ * worker.onmessage = (e) => handleLog(e.data)
195
+ * ```
196
+ */
197
+ function createWorkerLogHandler() {
198
+ const loggers = /* @__PURE__ */ new Map();
199
+ function getLogger(namespace) {
200
+ let logger = loggers.get(namespace);
201
+ if (!logger) {
202
+ logger = createLogger(namespace);
203
+ loggers.set(namespace, logger);
212
204
  }
205
+ return logger;
213
206
  }
214
- function createSpan(spanNamespace, spanProps) {
215
- const fullNamespace = spanNamespace ? `${namespace}:${spanNamespace}` : namespace;
216
- const mergedProps = {
217
- ...props,
218
- ...spanProps
219
- };
220
- const spanId = generateWorkerSpanId();
221
- const spanTraceId = traceId || generateWorkerTraceId();
222
- const startTime = Date.now();
223
- const customSpanData = {};
224
- try {
225
- postMessage({
226
- type: "span",
227
- event: "start",
228
- namespace: fullNamespace,
229
- spanId,
230
- traceId: spanTraceId,
231
- parentId: parentSpanId,
232
- startTime,
233
- props: mergedProps,
234
- spanData: {},
235
- timestamp: Date.now()
236
- });
237
- } catch (err) {
238
- try {
239
- postMessage({
240
- type: "log",
241
- level: "error",
242
- namespace: fullNamespace,
243
- message: `postMessage failed for span start "${fullNamespace}": ${err instanceof Error ? err.message : String(err)}`,
244
- timestamp: Date.now()
245
- });
246
- } catch {}
247
- }
248
- let ended = false;
249
- const spanData = createSpanDataProxy(() => ({
250
- id: spanId,
251
- traceId: spanTraceId,
252
- parentId: parentSpanId,
253
- startTime,
254
- endTime: ended ? Date.now() : null,
255
- duration: Date.now() - startTime
256
- }), customSpanData);
257
- function endSpan() {
258
- if (ended) return;
259
- ended = true;
260
- const endTime = Date.now();
261
- const duration = endTime - startTime;
262
- try {
263
- postMessage({
264
- type: "span",
265
- event: "end",
266
- namespace: fullNamespace,
267
- spanId,
268
- traceId: spanTraceId,
269
- parentId: parentSpanId,
270
- startTime,
271
- endTime,
272
- duration,
273
- props: mergedProps,
274
- spanData: customSpanData,
275
- timestamp: Date.now()
276
- });
277
- } catch (err) {
278
- try {
279
- postMessage({
280
- type: "log",
281
- level: "error",
282
- namespace: fullNamespace,
283
- message: `postMessage failed for span end "${fullNamespace}" (${duration}ms): ${err instanceof Error ? err.message : String(err)}`,
284
- timestamp: Date.now()
285
- });
286
- } catch {}
287
- }
207
+ return (message) => {
208
+ if (isWorkerEvent(message)) getLogger(message.namespace).dispatch(message);
209
+ else if (isWorkerConsoleMessage(message)) {
210
+ const logger = getLogger(message.namespace || "worker");
211
+ const { message: msg, data } = formatConsoleArgs(message.args);
212
+ dispatchToLogger(logger, message.level, msg, data);
288
213
  }
289
- return {
290
- ...createWorkerLogger(postMessage, fullNamespace, mergedProps, {
291
- parentSpanId: spanId,
292
- traceId: spanTraceId
293
- }),
294
- spanData,
295
- end: endSpan,
296
- [Symbol.dispose]: endSpan
297
- };
298
- }
299
- return {
300
- name: namespace,
301
- props: Object.freeze({ ...props }),
302
- spanData: null,
303
- trace: (msg, data) => log("trace", msg, data),
304
- debug: (msg, data) => log("debug", msg, data),
305
- info: (msg, data) => log("info", msg, data),
306
- warn: (msg, data) => log("warn", msg, data),
307
- error: (msgOrError, dataOrMsg, extraData) => {
308
- if (msgOrError instanceof Error) if (typeof dataOrMsg === "string") log("error", dataOrMsg, {
309
- ...extraData,
310
- error_type: msgOrError.name,
311
- error_message: msgOrError.message,
312
- error_stack: msgOrError.stack,
313
- error_code: msgOrError.code
314
- });
315
- else log("error", msgOrError.message, {
316
- ...dataOrMsg,
317
- error_type: msgOrError.name,
318
- error_stack: msgOrError.stack,
319
- error_code: msgOrError.code
320
- });
321
- else log("error", msgOrError, dataOrMsg);
322
- },
323
- logger(childNamespace, childProps) {
324
- return createWorkerLogger(postMessage, childNamespace ? `${namespace}:${childNamespace}` : namespace, {
325
- ...props,
326
- ...childProps
327
- }, options);
328
- },
329
- span: createSpan,
330
- child(context) {
331
- if (typeof context === "string") return this.logger(context);
332
- return createWorkerLogger(postMessage, namespace, {
333
- ...props,
334
- ...context
335
- }, options);
336
- },
337
- end() {}
338
214
  };
339
215
  }
340
216
  /** Safely stringify a value, handling circular refs and BigInt */
@@ -394,8 +270,6 @@ function dispatchToLogger(logger, level, message, data) {
394
270
  * worker.onmessage = (e) => {
395
271
  * if (e.data.type === "console") {
396
272
  * handleConsole(e.data)
397
- * } else {
398
- * // Handle other message types
399
273
  * }
400
274
  * }
401
275
  * ```
@@ -417,55 +291,7 @@ function createWorkerConsoleHandler(options = {}) {
417
291
  dispatchToLogger(logger, message.level, msg, data);
418
292
  };
419
293
  }
420
- /**
421
- * Create a handler for worker logger messages (logs and spans).
422
- *
423
- * Use this on the main thread to receive and output messages from workers
424
- * that use createWorkerLogger.
425
- *
426
- * @param options - Handler options
427
- * @returns Handler function to call with worker messages
428
- *
429
- * @example
430
- * ```typescript
431
- * import { createWorkerLogHandler, isWorkerMessage } from "loggily/worker"
432
- *
433
- * const handleLog = createWorkerLogHandler()
434
- *
435
- * worker.onmessage = (e) => {
436
- * if (isWorkerMessage(e.data)) {
437
- * handleLog(e.data)
438
- * } else {
439
- * // Handle other message types
440
- * }
441
- * }
442
- * ```
443
- */
444
- function createWorkerLogHandler(options = {}) {
445
- const loggers = /* @__PURE__ */ new Map();
446
- function getLogger(namespace) {
447
- let logger = loggers.get(namespace);
448
- if (!logger) {
449
- logger = createLogger(namespace);
450
- loggers.set(namespace, logger);
451
- }
452
- return logger;
453
- }
454
- return (message) => {
455
- if (isWorkerConsoleMessage(message)) {
456
- const logger = getLogger(message.namespace || "worker");
457
- const { message: msg, data } = formatConsoleArgs(message.args);
458
- dispatchToLogger(logger, message.level, msg, data);
459
- } else if (isWorkerLogMessage(message)) dispatchToLogger(getLogger(message.namespace), message.level, message.message, message.data);
460
- else if (isWorkerSpanMessage(message)) {
461
- if (message.event === "end") (getLogger(message.namespace).span?.(void 0, {
462
- ...message.props,
463
- ...message.spanData
464
- }))?.end();
465
- }
466
- };
467
- }
468
294
  //#endregion
469
- export { createWorkerConsoleHandler, createWorkerLogHandler, createWorkerLogger, forwardConsole, isWorkerConsoleMessage, isWorkerLogMessage, isWorkerMessage, isWorkerSpanMessage, resetWorkerIds, restoreConsole };
295
+ export { createWorkerConsoleHandler, createWorkerLogHandler, createWorkerLogger, forwardConsole, handleWorkerEvents, isWorkerConsoleMessage, isWorkerEvent, isWorkerLogEvent, isWorkerMessage, isWorkerSpanEvent, restoreConsole, workerTransportStage };
470
296
 
471
297
  //# sourceMappingURL=worker.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"worker.mjs","names":[],"sources":["../src/worker.ts"],"sourcesContent":["/**\n * Worker Thread Logger/Console Forwarding\n *\n * Provides utilities to forward loggily and console.* output from worker threads\n * to the main thread, ensuring proper integration with DEBUG_LOG and log files.\n *\n * ## Full Logger Forwarding (Recommended)\n *\n * @example Worker side:\n * ```typescript\n * import { createWorkerLogger } from \"loggily/worker\"\n * const log = createWorkerLogger(postMessage, \"km:worker:parse\")\n *\n * log.info(\"processing\", { file: \"test.md\" })\n * {\n * using span = log.span(\"parse\")\n * // ... work ...\n * span.spanData.lines = 100\n * }\n * ```\n *\n * @example Main thread side:\n * ```typescript\n * import { createWorkerLogHandler } from \"loggily/worker\"\n *\n * const handleLog = createWorkerLogHandler()\n * worker.onmessage = (e) => {\n * if (e.data.type === \"log\" || e.data.type === \"span\") handleLog(e.data)\n * }\n * ```\n *\n * ## Console Forwarding (Simple)\n *\n * @example Worker side:\n * ```typescript\n * import { forwardConsole } from \"loggily/worker\"\n * forwardConsole(postMessage)\n *\n * console.log(\"message\") // Forwarded to main thread\n * ```\n */\n\nimport {\n createLogger,\n createSpanDataProxy,\n type ConditionalLogger,\n type LazyMessage,\n type Logger,\n type SpanLogger,\n type SpanData,\n} from \"./index.ts\"\n\n// ============ Message Protocol ============\n\n/** Message sent from worker to main thread for console output */\nexport interface WorkerConsoleMessage {\n type: \"console\"\n level: \"log\" | \"debug\" | \"info\" | \"warn\" | \"error\" | \"trace\"\n namespace?: string\n args: unknown[]\n timestamp: number\n}\n\n/** Message sent from worker to main thread for structured log output */\nexport interface WorkerLogMessage {\n type: \"log\"\n level: \"trace\" | \"debug\" | \"info\" | \"warn\" | \"error\"\n namespace: string\n message: string\n data?: Record<string, unknown>\n timestamp: number\n}\n\n/** Message sent from worker to main thread for span events */\nexport interface WorkerSpanMessage {\n type: \"span\"\n event: \"start\" | \"end\"\n namespace: string\n spanId: string\n traceId: string\n parentId: string | null\n startTime: number\n endTime?: number\n duration?: number\n props: Record<string, unknown>\n spanData: Record<string, unknown>\n timestamp: number\n}\n\n/** Union type for all worker messages */\nexport type WorkerMessage = WorkerConsoleMessage | WorkerLogMessage | WorkerSpanMessage\n\n/** Type guard for WorkerConsoleMessage */\nexport function isWorkerConsoleMessage(msg: unknown): msg is WorkerConsoleMessage {\n return (\n typeof msg === \"object\" &&\n (msg as WorkerConsoleMessage)?.type === \"console\" &&\n typeof (msg as WorkerConsoleMessage).level === \"string\" &&\n Array.isArray((msg as WorkerConsoleMessage).args)\n )\n}\n\n/** Type guard for WorkerLogMessage */\nexport function isWorkerLogMessage(msg: unknown): msg is WorkerLogMessage {\n return (\n typeof msg === \"object\" &&\n (msg as WorkerLogMessage)?.type === \"log\" &&\n typeof (msg as WorkerLogMessage).level === \"string\" &&\n typeof (msg as WorkerLogMessage).namespace === \"string\"\n )\n}\n\n/** Type guard for WorkerSpanMessage */\nexport function isWorkerSpanMessage(msg: unknown): msg is WorkerSpanMessage {\n return (\n typeof msg === \"object\" &&\n (msg as WorkerSpanMessage)?.type === \"span\" &&\n typeof (msg as WorkerSpanMessage).event === \"string\"\n )\n}\n\n/** Type guard for any worker message */\nexport function isWorkerMessage(msg: unknown): msg is WorkerMessage {\n return isWorkerConsoleMessage(msg) || isWorkerLogMessage(msg) || isWorkerSpanMessage(msg)\n}\n\n// ============ Worker Side ============\n\ntype PostMessageFn = (message: WorkerConsoleMessage) => void\n\n/** Store original console methods for restoration */\nlet originalConsole: typeof console | null = null\n\n/**\n * Serialize a value for transmission via postMessage.\n * Handles non-serializable values like functions and circular references.\n */\nfunction serializeArg(arg: unknown, depth = 0): unknown {\n // Prevent infinite recursion\n if (depth > 5) return \"[max depth]\"\n\n if (arg === null || arg === undefined) return arg\n if (typeof arg === \"function\") return `[Function: ${arg.name || \"anonymous\"}]`\n if (typeof arg === \"symbol\") return arg.toString()\n if (typeof arg === \"bigint\") return arg.toString() + \"n\"\n\n if (arg instanceof Error) {\n return {\n name: arg.name,\n message: arg.message,\n stack: arg.stack,\n }\n }\n\n if (Array.isArray(arg)) {\n return arg.map((v) => serializeArg(v, depth + 1))\n }\n\n if (typeof arg === \"object\") {\n try {\n // Try structured clone first (handles most cases)\n structuredClone(arg)\n return arg\n } catch {\n // Fall back to manual serialization\n const result: Record<string, unknown> = {}\n const seen = new Set<object>()\n seen.add(arg)\n\n for (const [key, value] of Object.entries(arg)) {\n if (typeof value === \"object\" && value !== null && seen.has(value)) {\n result[key] = \"[Circular]\"\n } else {\n result[key] = serializeArg(value, depth + 1)\n }\n }\n return result\n }\n }\n\n return arg\n}\n\n/**\n * Forward console.* calls from worker to main thread.\n *\n * Monkey-patches console methods to send messages via postMessage.\n * Call this at the start of your worker script.\n *\n * @param postMessage - The worker's postMessage function\n * @param namespace - Optional namespace for log messages (e.g., \"km:worker:parse\")\n *\n * @example\n * ```typescript\n * // At top of worker file:\n * import { forwardConsole } from \"loggily/worker\"\n * forwardConsole(postMessage, \"km:worker:parse\")\n *\n * // Now all console.* calls are forwarded:\n * console.log(\"processing\", { file: \"test.md\" })\n * console.error(new Error(\"failed\"))\n * ```\n */\nexport function forwardConsole(postMessage: PostMessageFn, namespace?: string): void {\n // Store original console for restoration\n if (!originalConsole) {\n originalConsole = { ...console }\n }\n\n const levels = [\"log\", \"debug\", \"info\", \"warn\", \"error\", \"trace\"] as const\n\n for (const level of levels) {\n console[level] = (...args: unknown[]) => {\n const serializedArgs = args.map((arg) => serializeArg(arg))\n\n try {\n postMessage({\n type: \"console\",\n level,\n namespace,\n args: serializedArgs,\n timestamp: Date.now(),\n })\n } catch {\n // postMessage might fail if worker is shutting down\n // Fall back to original console\n originalConsole?.[level](...args)\n }\n }\n }\n}\n\n/**\n * Restore original console methods.\n * Call this if you need to disable console forwarding.\n */\nexport function restoreConsole(): void {\n if (originalConsole) {\n Object.assign(console, originalConsole)\n originalConsole = null\n }\n}\n\n// ============ Worker Logger (Full API) ============\n\ntype PostMessageAnyFn = (message: WorkerMessage) => void\n\nlet workerSpanIdCounter = 0\nlet workerTraceIdCounter = 0\n\nfunction generateWorkerSpanId(): string {\n return `wsp_${(++workerSpanIdCounter).toString(36)}`\n}\n\nfunction generateWorkerTraceId(): string {\n return `wtr_${(++workerTraceIdCounter).toString(36)}`\n}\n\n/** Reset worker ID counters (for testing) */\nexport function resetWorkerIds(): void {\n workerSpanIdCounter = 0\n workerTraceIdCounter = 0\n}\n\ninterface WorkerLoggerOptions {\n /** Parent span ID for nested spans */\n parentSpanId?: string | null\n /** Trace ID for distributed tracing */\n traceId?: string | null\n}\n\n/**\n * Create a logger instance for use in a worker thread.\n *\n * All log calls and span events are forwarded to the main thread via postMessage.\n * The main thread should use createWorkerLogHandler to process these messages.\n *\n * @param postMessage - The worker's postMessage function\n * @param namespace - Logger namespace (e.g., \"km:worker:parse\")\n * @param props - Optional initial props\n * @param options - Optional configuration\n *\n * @example\n * ```typescript\n * import { createWorkerLogger } from \"loggily/worker\"\n *\n * const log = createWorkerLogger(postMessage, \"km:worker:parse\")\n *\n * log.info(\"starting parse\", { file: \"test.md\" })\n *\n * {\n * using span = log.span(\"process\")\n * span.info(\"processing...\")\n * span.spanData.lineCount = 100\n * }\n * // Span end event automatically sent to main thread\n * ```\n */\nexport function createWorkerLogger(\n postMessage: PostMessageAnyFn,\n namespace: string,\n props: Record<string, unknown> = {},\n options: WorkerLoggerOptions = {},\n): Logger {\n const { parentSpanId = null, traceId = null } = options\n\n function log(\n level: \"trace\" | \"debug\" | \"info\" | \"warn\" | \"error\",\n message: LazyMessage,\n data?: Record<string, unknown>,\n ): void {\n const resolved = typeof message === \"function\" ? message() : message\n try {\n postMessage({\n type: \"log\",\n level,\n namespace,\n message: resolved,\n data: data ? { ...props, ...data } : Object.keys(props).length > 0 ? props : undefined,\n timestamp: Date.now(),\n })\n } catch (err) {\n // postMessage failed (e.g. uncloneable data) — send a diagnostic fallback\n try {\n postMessage({\n type: \"log\",\n level: \"error\",\n namespace,\n message: `postMessage failed for ${level} \"${resolved}\": ${err instanceof Error ? err.message : String(err)}`,\n timestamp: Date.now(),\n })\n } catch {\n // Worker might be shutting down — truly nothing we can do\n }\n }\n }\n\n function createSpan(spanNamespace?: string, spanProps?: Record<string, unknown>): SpanLogger {\n const fullNamespace = spanNamespace ? `${namespace}:${spanNamespace}` : namespace\n const mergedProps = { ...props, ...spanProps }\n const spanId = generateWorkerSpanId()\n const spanTraceId = traceId || generateWorkerTraceId()\n const startTime = Date.now()\n\n // Mutable span data that can be set by the user\n const customSpanData: Record<string, unknown> = {}\n\n // Send span start event\n try {\n postMessage({\n type: \"span\",\n event: \"start\",\n namespace: fullNamespace,\n spanId,\n traceId: spanTraceId,\n parentId: parentSpanId,\n startTime,\n props: mergedProps,\n spanData: {},\n timestamp: Date.now(),\n })\n } catch (err) {\n // postMessage failed (e.g. uncloneable props) — send a diagnostic fallback\n try {\n postMessage({\n type: \"log\",\n level: \"error\",\n namespace: fullNamespace,\n message: `postMessage failed for span start \"${fullNamespace}\": ${err instanceof Error ? err.message : String(err)}`,\n timestamp: Date.now(),\n })\n } catch {\n // Worker might be shutting down\n }\n }\n\n let ended = false\n\n const spanData: SpanData = createSpanDataProxy(\n () => ({\n id: spanId,\n traceId: spanTraceId,\n parentId: parentSpanId,\n startTime,\n endTime: ended ? Date.now() : null,\n duration: Date.now() - startTime,\n }),\n customSpanData,\n )\n\n function endSpan(): void {\n if (ended) return\n ended = true\n\n const endTime = Date.now()\n const duration = endTime - startTime\n\n try {\n postMessage({\n type: \"span\",\n event: \"end\",\n namespace: fullNamespace,\n spanId,\n traceId: spanTraceId,\n parentId: parentSpanId,\n startTime,\n endTime,\n duration,\n props: mergedProps,\n spanData: customSpanData,\n timestamp: Date.now(),\n })\n } catch (err) {\n // postMessage failed (e.g. uncloneable spanData) — send a diagnostic fallback\n try {\n postMessage({\n type: \"log\",\n level: \"error\",\n namespace: fullNamespace,\n message: `postMessage failed for span end \"${fullNamespace}\" (${duration}ms): ${err instanceof Error ? err.message : String(err)}`,\n timestamp: Date.now(),\n })\n } catch {\n // Worker might be shutting down\n }\n }\n }\n\n // Create child logger for the span\n const childLogger = createWorkerLogger(postMessage, fullNamespace, mergedProps, {\n parentSpanId: spanId,\n traceId: spanTraceId,\n })\n\n const spanLogger: SpanLogger = {\n ...childLogger,\n spanData,\n end: endSpan,\n [Symbol.dispose]: endSpan,\n }\n\n return spanLogger\n }\n\n const logger: Logger = {\n name: namespace,\n props: Object.freeze({ ...props }),\n spanData: null,\n\n trace: (msg, data) => log(\"trace\", msg, data),\n debug: (msg, data) => log(\"debug\", msg, data),\n info: (msg, data) => log(\"info\", msg, data),\n warn: (msg, data) => log(\"warn\", msg, data),\n error: (\n msgOrError: LazyMessage | Error,\n dataOrMsg?: Record<string, unknown> | string,\n extraData?: Record<string, unknown>,\n ) => {\n if (msgOrError instanceof Error) {\n if (typeof dataOrMsg === \"string\") {\n log(\"error\", dataOrMsg, {\n ...extraData,\n error_type: msgOrError.name,\n error_message: msgOrError.message,\n error_stack: msgOrError.stack,\n error_code: (msgOrError as NodeJS.ErrnoException).code,\n })\n } else {\n log(\"error\", msgOrError.message, {\n ...(dataOrMsg as Record<string, unknown>),\n error_type: msgOrError.name,\n error_stack: msgOrError.stack,\n error_code: (msgOrError as NodeJS.ErrnoException).code,\n })\n }\n } else {\n log(\"error\", msgOrError, dataOrMsg as Record<string, unknown>)\n }\n },\n\n logger(childNamespace?: string, childProps?: Record<string, unknown>): ConditionalLogger {\n const fullNamespace = childNamespace ? `${namespace}:${childNamespace}` : namespace\n return createWorkerLogger(\n postMessage,\n fullNamespace,\n { ...props, ...childProps },\n options,\n ) as unknown as ConditionalLogger\n },\n\n span: createSpan,\n\n child(context: Record<string, unknown> | string): ConditionalLogger {\n if (typeof context === \"string\") {\n return this.logger(context)\n }\n return createWorkerLogger(\n postMessage,\n namespace,\n { ...props, ...context },\n options,\n ) as unknown as ConditionalLogger\n },\n\n end(): void {\n // No-op for non-span logger\n },\n }\n\n return logger\n}\n\n// ============ Main Thread Side ============\n\nexport interface WorkerConsoleHandlerOptions {\n /** Default namespace if message doesn't include one */\n defaultNamespace?: string\n /** Custom logger to use (defaults to creating one with the namespace) */\n logger?: Logger\n}\n\n/** Safely stringify a value, handling circular refs and BigInt */\nfunction safeStringify(value: unknown): string {\n try {\n return JSON.stringify(value)\n } catch {\n return String(value)\n }\n}\n\n/** Format console args into a message string and optional data object */\nfunction formatConsoleArgs(args: unknown[]): { message: string; data: Record<string, unknown> | undefined } {\n const message =\n args.length === 0\n ? \"\"\n : args.length === 1 && typeof args[0] === \"string\"\n ? args[0]\n : args.map((a) => (typeof a === \"string\" ? a : safeStringify(a))).join(\" \")\n\n const lastArg = args[args.length - 1]\n const data =\n args.length > 1 && typeof lastArg === \"object\" && lastArg !== null && !Array.isArray(lastArg)\n ? (lastArg as Record<string, unknown>)\n : undefined\n\n return { message, data }\n}\n\n/** Dispatch a message to a logger at the given console level */\nfunction dispatchToLogger(\n logger: ConditionalLogger,\n level: \"log\" | \"debug\" | \"info\" | \"warn\" | \"error\" | \"trace\",\n message: string,\n data?: Record<string, unknown>,\n): void {\n switch (level) {\n case \"trace\":\n logger.trace?.(message, data)\n break\n case \"debug\":\n logger.debug?.(message, data)\n break\n case \"info\":\n case \"log\":\n logger.info?.(message, data)\n break\n case \"warn\":\n logger.warn?.(message, data)\n break\n case \"error\":\n logger.error?.(message, data)\n break\n }\n}\n\n/**\n * Create a handler for worker console messages.\n *\n * Use this on the main thread to receive and output messages from workers.\n *\n * @param options - Handler options\n * @returns Handler function to call with worker messages\n *\n * @example\n * ```typescript\n * import { createWorkerConsoleHandler } from \"loggily/worker\"\n *\n * const handleConsole = createWorkerConsoleHandler({\n * defaultNamespace: \"km:worker:parse\"\n * })\n *\n * worker.onmessage = (e) => {\n * if (e.data.type === \"console\") {\n * handleConsole(e.data)\n * } else {\n * // Handle other message types\n * }\n * }\n * ```\n */\nexport function createWorkerConsoleHandler(\n options: WorkerConsoleHandlerOptions = {},\n): (message: WorkerConsoleMessage) => void {\n const loggers = new Map<string, ConditionalLogger>()\n\n function getLogger(namespace?: string): ConditionalLogger {\n const ns = namespace || options.defaultNamespace || \"worker\"\n\n let logger = loggers.get(ns)\n if (!logger) {\n logger = options.logger ? (options.logger as ConditionalLogger) : createLogger(ns)\n loggers.set(ns, logger)\n }\n return logger\n }\n\n return (message: WorkerConsoleMessage) => {\n const logger = getLogger(message.namespace)\n const { message: msg, data } = formatConsoleArgs(message.args)\n dispatchToLogger(logger, message.level, msg, data)\n }\n}\n\n// ============ Full Logger Handler ============\n\nexport interface WorkerLogHandlerOptions {\n /** @deprecated Span output is now controlled by TRACE env var */\n enableSpans?: boolean\n}\n\n/**\n * Create a handler for worker logger messages (logs and spans).\n *\n * Use this on the main thread to receive and output messages from workers\n * that use createWorkerLogger.\n *\n * @param options - Handler options\n * @returns Handler function to call with worker messages\n *\n * @example\n * ```typescript\n * import { createWorkerLogHandler, isWorkerMessage } from \"loggily/worker\"\n *\n * const handleLog = createWorkerLogHandler()\n *\n * worker.onmessage = (e) => {\n * if (isWorkerMessage(e.data)) {\n * handleLog(e.data)\n * } else {\n * // Handle other message types\n * }\n * }\n * ```\n */\nexport function createWorkerLogHandler(options: WorkerLogHandlerOptions = {}): (message: WorkerMessage) => void {\n const loggers = new Map<string, ConditionalLogger>()\n\n function getLogger(namespace: string): ConditionalLogger {\n let logger = loggers.get(namespace)\n if (!logger) {\n logger = createLogger(namespace)\n loggers.set(namespace, logger)\n }\n return logger\n }\n\n return (message: WorkerMessage) => {\n if (isWorkerConsoleMessage(message)) {\n const logger = getLogger(message.namespace || \"worker\")\n const { message: msg, data } = formatConsoleArgs(message.args)\n dispatchToLogger(logger, message.level, msg, data)\n } else if (isWorkerLogMessage(message)) {\n const logger = getLogger(message.namespace)\n dispatchToLogger(logger, message.level, message.message, message.data)\n } else if (isWorkerSpanMessage(message)) {\n if (message.event === \"end\") {\n const logger = getLogger(message.namespace)\n const span = logger.span?.(undefined, { ...message.props, ...message.spanData })\n span?.end()\n }\n // Start events are informational only on main thread\n // (the actual timing happens in the worker)\n }\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"worker.mjs","names":[],"sources":["../src/worker.ts"],"sourcesContent":["/**\n * Worker Thread Logger/Console Forwarding\n *\n * Pipeline-based worker logging: worker loggers use a postMessage transport\n * so events flow through the main thread's pipeline for output.\n *\n * ## Structured Logger (Recommended)\n *\n * @example Worker side:\n * ```typescript\n * import { createWorkerLogger } from \"loggily/worker\"\n * const log = createWorkerLogger(postMessage, \"km:worker:parse\")\n *\n * log.info?.(\"processing\", { file: \"test.md\" })\n * {\n * using span = log.span?.(\"parse\")\n * // ... work ...\n * span.spanData.lines = 100\n * }\n * ```\n *\n * @example Main thread side:\n * ```typescript\n * import { createWorkerLogHandler } from \"loggily/worker\"\n *\n * const handleLog = createWorkerLogHandler()\n * worker.onmessage = (e) => handleLog(e.data)\n * ```\n *\n * ## Console Forwarding (Simple)\n *\n * @example Worker side:\n * ```typescript\n * import { forwardConsole } from \"loggily/worker\"\n * forwardConsole(postMessage)\n *\n * console.log(\"message\") // Forwarded to main thread\n * ```\n */\n\nimport { createLogger, baseCreateLogger, pipe, withSpans, type ConditionalLogger } from \"./core.js\"\nimport type { Event, LogEvent, SpanEvent, Stage, ConfigElement } from \"./pipeline.js\"\n\n// ============ Console Message Type ============\n\n/** Message sent from worker to main thread for console output */\nexport interface WorkerConsoleMessage {\n type: \"console\"\n level: \"log\" | \"debug\" | \"info\" | \"warn\" | \"error\" | \"trace\"\n namespace?: string\n args: unknown[]\n timestamp: number\n}\n\n// ============ Type Guards ============\n\n/** Type guard for LogEvent (structured log from worker) */\nexport function isWorkerLogEvent(msg: unknown): msg is LogEvent {\n return typeof msg === \"object\" && (msg as LogEvent)?.kind === \"log\"\n}\n\n/** Type guard for SpanEvent (span from worker) */\nexport function isWorkerSpanEvent(msg: unknown): msg is SpanEvent {\n return typeof msg === \"object\" && (msg as SpanEvent)?.kind === \"span\"\n}\n\n/** Type guard for any pipeline Event (log or span) */\nexport function isWorkerEvent(msg: unknown): msg is Event {\n return isWorkerLogEvent(msg) || isWorkerSpanEvent(msg)\n}\n\n/** Type guard for WorkerConsoleMessage */\nexport function isWorkerConsoleMessage(msg: unknown): msg is WorkerConsoleMessage {\n return (\n typeof msg === \"object\" &&\n (msg as WorkerConsoleMessage)?.type === \"console\" &&\n typeof (msg as WorkerConsoleMessage).level === \"string\" &&\n Array.isArray((msg as WorkerConsoleMessage).args)\n )\n}\n\n/** Type guard for any worker message (console or pipeline event) */\nexport function isWorkerMessage(msg: unknown): msg is WorkerConsoleMessage | Event {\n return isWorkerConsoleMessage(msg) || isWorkerEvent(msg)\n}\n\n// ============ Worker Side: Console Forwarding ============\n\ntype PostMessageFn = (message: WorkerConsoleMessage) => void\n\n/** Store original console methods for restoration */\nlet originalConsole: typeof console | null = null\n\n/**\n * Forward console.* calls from worker to main thread via postMessage.\n *\n * Monkey-patches console methods. postMessage uses structuredClone,\n * which handles most values natively. If cloning fails (functions,\n * symbols), falls back to original console.\n *\n * @example\n * ```typescript\n * import { forwardConsole } from \"loggily/worker\"\n * forwardConsole(postMessage, \"km:worker:parse\")\n * console.log(\"processing\", { file: \"test.md\" })\n * ```\n */\nexport function forwardConsole(postMessage: PostMessageFn, namespace?: string): void {\n if (!originalConsole) {\n originalConsole = { ...console }\n }\n\n for (const level of [\"log\", \"debug\", \"info\", \"warn\", \"error\", \"trace\"] as const) {\n console[level] = (...args: unknown[]) => {\n try {\n // Sanitize non-cloneable values before postMessage (structuredClone rejects them)\n const safe = args.map((a) =>\n typeof a === \"function\"\n ? `[Function: ${a.name || \"anonymous\"}]`\n : typeof a === \"symbol\"\n ? a.toString()\n : a instanceof Error\n ? { name: a.name, message: a.message, stack: a.stack }\n : a,\n )\n postMessage({ type: \"console\", level, namespace, args: safe, timestamp: Date.now() })\n } catch {\n originalConsole?.[level](...args)\n }\n }\n }\n}\n\n/**\n * Restore original console methods.\n * Call this if you need to disable console forwarding.\n */\nexport function restoreConsole(): void {\n if (originalConsole) {\n Object.assign(console, originalConsole)\n originalConsole = null\n }\n}\n\n// ============ Worker Side: Pipeline Transport ============\n\n/**\n * Create a pipeline stage that forwards events via postMessage.\n *\n * Events are plain JSON objects that survive structuredClone natively.\n * The stage consumes events (returns null) so nothing is output locally.\n * The main thread uses handleWorkerEvents() or createWorkerLogHandler()\n * to dispatch them through a local logger pipeline.\n */\nexport function workerTransportStage(postMessage: (msg: unknown) => void): Stage {\n return (event: Event): null => {\n try {\n postMessage(event)\n } catch {\n // If postMessage fails (non-cloneable), try with JSON round-trip\n try {\n postMessage(JSON.parse(JSON.stringify(event)))\n } catch {\n // Silently drop -- worker can't communicate\n }\n }\n return null // Consume the event (no local output)\n }\n}\n\n/**\n * Create a logger for use in a worker thread.\n *\n * All log and span events are forwarded to the main thread via postMessage.\n * The main thread should use createWorkerLogHandler() to process these messages.\n *\n * @param postMessage - The worker's postMessage function\n * @param namespace - Logger namespace (e.g., \"km:worker:parse\")\n * @param props - Optional initial props\n *\n * @example\n * ```typescript\n * import { createWorkerLogger } from \"loggily/worker\"\n *\n * const log = createWorkerLogger(postMessage, \"km:worker:parse\")\n *\n * log.info?.(\"starting parse\", { file: \"test.md\" })\n *\n * {\n * using span = log.span?.(\"process\")\n * span.info?.(\"processing...\")\n * span.spanData.count = 100\n * }\n * // Span end event automatically sent to main thread\n * ```\n */\nexport function createWorkerLogger(\n postMessage: (msg: unknown) => void,\n namespace: string,\n props?: Record<string, unknown>,\n): ConditionalLogger {\n const transport = workerTransportStage(postMessage)\n const config: ConfigElement[] = [{ level: \"trace\" as const }, transport]\n const factory = pipe(baseCreateLogger, withSpans())\n const logger = factory(namespace, config)\n return props ? logger.child(props) : logger\n}\n\n// ============ Main Thread Side: Event Handling ============\n\n/**\n * Create a handler that dispatches worker events to a target logger.\n *\n * Use this when you have a specific logger to dispatch through.\n *\n * @param target - Logger or object with dispatch method\n * @returns Handler function to call with worker messages\n */\nexport function handleWorkerEvents(\n target: ConditionalLogger | { dispatch(event: Event): void },\n): (msg: unknown) => void {\n return (msg: unknown) => {\n if (typeof msg !== \"object\" || msg === null) return\n const event = msg as Record<string, unknown>\n if (event.kind === \"log\" || event.kind === \"span\") {\n target.dispatch(msg as Event)\n }\n }\n}\n\n/**\n * Create a zero-config handler for worker logger messages.\n *\n * Automatically creates loggers per-namespace. For console messages,\n * formats args and dispatches through a logger.\n *\n * @returns Handler function to call with any worker message\n *\n * @example\n * ```typescript\n * import { createWorkerLogHandler } from \"loggily/worker\"\n *\n * const handleLog = createWorkerLogHandler()\n * worker.onmessage = (e) => handleLog(e.data)\n * ```\n */\nexport function createWorkerLogHandler(): (message: unknown) => void {\n const loggers = new Map<string, ConditionalLogger>()\n\n function getLogger(namespace: string): ConditionalLogger {\n let logger = loggers.get(namespace)\n if (!logger) {\n logger = createLogger(namespace)\n loggers.set(namespace, logger)\n }\n return logger\n }\n\n return (message: unknown) => {\n if (isWorkerEvent(message)) {\n const logger = getLogger(message.namespace)\n logger.dispatch(message)\n } else if (isWorkerConsoleMessage(message)) {\n const logger = getLogger(message.namespace || \"worker\")\n const { message: msg, data } = formatConsoleArgs(message.args)\n dispatchToLogger(logger, message.level, msg, data)\n }\n }\n}\n\n// ============ Main Thread Side: Console Handler ============\n\nexport interface WorkerConsoleHandlerOptions {\n /** Default namespace if message doesn't include one */\n defaultNamespace?: string\n /** Custom logger to use (defaults to creating one with the namespace) */\n logger?: { name: string; dispatch(event: Event): void }\n}\n\n/** Safely stringify a value, handling circular refs and BigInt */\nfunction safeStringify(value: unknown): string {\n try {\n return JSON.stringify(value)\n } catch {\n return String(value)\n }\n}\n\n/** Format console args into a message string and optional data object */\nfunction formatConsoleArgs(args: unknown[]): { message: string; data: Record<string, unknown> | undefined } {\n const message =\n args.length === 0\n ? \"\"\n : args.length === 1 && typeof args[0] === \"string\"\n ? args[0]\n : args.map((a) => (typeof a === \"string\" ? a : safeStringify(a))).join(\" \")\n\n const lastArg = args[args.length - 1]\n const data =\n args.length > 1 && typeof lastArg === \"object\" && lastArg !== null && !Array.isArray(lastArg)\n ? (lastArg as Record<string, unknown>)\n : undefined\n\n return { message, data }\n}\n\n/** Dispatch a message to a logger at the given console level */\nfunction dispatchToLogger(\n logger: ConditionalLogger,\n level: \"log\" | \"debug\" | \"info\" | \"warn\" | \"error\" | \"trace\",\n message: string,\n data?: Record<string, unknown>,\n): void {\n switch (level) {\n case \"trace\":\n logger.trace?.(message, data)\n break\n case \"debug\":\n logger.debug?.(message, data)\n break\n case \"info\":\n case \"log\":\n logger.info?.(message, data)\n break\n case \"warn\":\n logger.warn?.(message, data)\n break\n case \"error\":\n logger.error?.(message, data)\n break\n }\n}\n\n/**\n * Create a handler for worker console messages.\n *\n * Use this on the main thread to receive and output messages from workers.\n *\n * @param options - Handler options\n * @returns Handler function to call with worker messages\n *\n * @example\n * ```typescript\n * import { createWorkerConsoleHandler } from \"loggily/worker\"\n *\n * const handleConsole = createWorkerConsoleHandler({\n * defaultNamespace: \"km:worker:parse\"\n * })\n *\n * worker.onmessage = (e) => {\n * if (e.data.type === \"console\") {\n * handleConsole(e.data)\n * }\n * }\n * ```\n */\nexport function createWorkerConsoleHandler(\n options: WorkerConsoleHandlerOptions = {},\n): (message: WorkerConsoleMessage) => void {\n const loggers = new Map<string, ConditionalLogger>()\n\n function getLogger(namespace?: string): ConditionalLogger {\n const ns = namespace || options.defaultNamespace || \"worker\"\n\n let logger = loggers.get(ns)\n if (!logger) {\n logger = options.logger ? (options.logger as ConditionalLogger) : createLogger(ns)\n loggers.set(ns, logger)\n }\n return logger\n }\n\n return (message: WorkerConsoleMessage) => {\n const logger = getLogger(message.namespace)\n const { message: msg, data } = formatConsoleArgs(message.args)\n dispatchToLogger(logger, message.level, msg, data)\n }\n}\n"],"mappings":"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"}