@crimsonsunset/jsg-logger 1.8.2 → 1.8.3

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/CHANGELOG.md CHANGED
@@ -5,6 +5,20 @@ All notable changes to the JSG Logger project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [1.8.3] - 2026-03-28 🔌 **addTransport() API**
9
+
10
+ ### Added
11
+ - **`JSGLogger.addTransport(transport)`** — new static method to register a transport on the running singleton without reinitializing. Bypasses the reinit guard entirely. Idempotent (calling with the same instance twice is a no-op). Also exposed on the default export as `logger.addTransport()`.
12
+
13
+ ### Fixed
14
+ - **Transport registration after module-level init** — `jsg-logger` initializes itself with default config at module evaluation time (line 1042). This caused the reinit guard introduced in 1.8.2 to silently drop transports passed to `getInstanceSync(options)` in e.g. Next.js `instrumentation.ts`, because `initialized` was already `true`. `addTransport()` is the correct API for post-init transport registration — it pushes directly to `_instance.transports` and is unaffected by the reinit guard.
15
+
16
+ ### Migration
17
+ Replace `getInstanceSync({ ...config, transports: [myTransport] })` in post-init contexts (e.g. Next.js `register()`) with:
18
+ ```ts
19
+ JSGLogger.addTransport(myTransport);
20
+ ```
21
+
8
22
  ## [1.8.2] - 2026-03-27 🛡️ **Reinit Guard + configure() API**
9
23
 
10
24
  ### Added
package/index.d.ts CHANGED
@@ -195,6 +195,12 @@ export interface LoggerInstanceType {
195
195
  */
196
196
  getInstanceSync?: (config?: JSGLoggerConfig) => LoggerInstanceType;
197
197
 
198
+ /**
199
+ * Add a transport to the running singleton without reinitializing. Idempotent.
200
+ * @param transport - LogTransport instance to register
201
+ */
202
+ addTransport?: (transport: LogTransport) => void;
203
+
198
204
  /**
199
205
  * Static performance logging utility
200
206
  */
@@ -225,6 +231,21 @@ export interface JSGLogger {
225
231
  */
226
232
  getInstanceSync(config?: JSGLoggerConfig): LoggerInstanceType;
227
233
 
234
+ /**
235
+ * Add a transport to the running singleton without reinitializing.
236
+ * Safe to call even after the singleton was initialized by module-level code or a
237
+ * third-party library — bypasses the reinit guard entirely. Idempotent.
238
+ *
239
+ * @param transport - LogTransport instance to register
240
+ *
241
+ * @example
242
+ * ```ts
243
+ * // instrumentation.ts — runs after module-level init, still registers transport cleanly
244
+ * JSGLogger.addTransport(new PostHogServerTransport(posthogServer, { level: 'warn' }));
245
+ * ```
246
+ */
247
+ addTransport(transport: LogTransport): void;
248
+
228
249
  /**
229
250
  * Static performance logging utility
230
251
  * @param label - Performance label
package/index.js CHANGED
@@ -1019,6 +1019,29 @@ class JSGLogger {
1019
1019
  return JSGLogger._enhancedLoggers;
1020
1020
  }
1021
1021
 
1022
+ /**
1023
+ * Add a transport to the running singleton without reinitializing.
1024
+ * Safe to call even if the singleton was already initialized by module-level code
1025
+ * or a third-party library — bypasses the reinit guard entirely.
1026
+ * Idempotent: calling with the same transport instance twice is a no-op.
1027
+ * @param {Object} transport - LogTransport instance to register
1028
+ * @returns {void}
1029
+ */
1030
+ static addTransport(transport) {
1031
+ if (!transport || typeof transport.send !== 'function') {
1032
+ metaWarn('[JSGLogger] addTransport() received an invalid transport — must have a send() method');
1033
+ return;
1034
+ }
1035
+ if (!JSGLogger._instance) {
1036
+ metaWarn('[JSGLogger] addTransport() called before any initialization — initializing with defaults first');
1037
+ JSGLogger._instance = new JSGLogger();
1038
+ JSGLogger._enhancedLoggers = JSGLogger._instance.initSync({});
1039
+ }
1040
+ if (!JSGLogger._instance.transports.includes(transport)) {
1041
+ JSGLogger._instance.transports.push(transport);
1042
+ }
1043
+ }
1044
+
1022
1045
  /**
1023
1046
  * Get singleton controls without triggering initialization
1024
1047
  * Checks window.JSG_Logger first to ensure singleton works across separate bundles
@@ -1052,6 +1075,7 @@ if (isBrowser() && typeof window !== 'undefined') {
1052
1075
  enhancedLoggers.getInstance = JSGLogger.getInstance;
1053
1076
  enhancedLoggers.getInstanceSync = JSGLogger.getInstanceSync;
1054
1077
  enhancedLoggers.configure = JSGLogger.configure.bind(JSGLogger);
1078
+ enhancedLoggers.addTransport = JSGLogger.addTransport.bind(JSGLogger);
1055
1079
  enhancedLoggers.logPerformance = JSGLogger.logPerformance;
1056
1080
  enhancedLoggers.JSGLogger = JSGLogger;
1057
1081
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crimsonsunset/jsg-logger",
3
- "version": "1.8.2",
3
+ "version": "1.8.3",
4
4
  "type": "module",
5
5
  "description": "Multi-environment logger with smart detection, file-level overrides, and beautiful console formatting. Test it live: https://logger.joesangiorgio.com/",
6
6
  "main": "index.js",