@crimsonsunset/jsg-logger 1.7.10 → 1.7.12

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.
Files changed (2) hide show
  1. package/index.js +74 -3
  2. package/package.json +1 -1
package/index.js CHANGED
@@ -13,6 +13,7 @@ import {createCLIFormatter} from './formatters/cli-formatter.js';
13
13
  import {createServerFormatter, getServerConfig} from './formatters/server-formatter.js';
14
14
  import {LogStore} from './stores/log-store.js';
15
15
  import {metaLog, metaWarn, metaError} from './utils/meta-logger.js';
16
+ import packageJson from './package.json' with {type: 'json'};
16
17
 
17
18
  // Check default config for devtools at module load time
18
19
  // This allows bundlers to tree-shake if disabled
@@ -48,6 +49,7 @@ class JSGLogger {
48
49
  static _instance = null;
49
50
  static _enhancedLoggers = null;
50
51
  static _hasLoggedInitialization = false;
52
+ static _initLock = false; // Lock to prevent concurrent initializations
51
53
 
52
54
  constructor() {
53
55
  this.loggers = {};
@@ -102,6 +104,8 @@ class JSGLogger {
102
104
  JSGLogger._enhancedLoggers = JSGLogger._instance.initSync(options);
103
105
  } else if (hasOptions) {
104
106
  // Instance exists but new options provided - reinitialize
107
+ // Only reinit if flag is not set (first init hasn't completed yet)
108
+ // or if we need to apply new config
105
109
  JSGLogger._enhancedLoggers = JSGLogger._instance.initSync(options);
106
110
  }
107
111
 
@@ -115,6 +119,17 @@ class JSGLogger {
115
119
  */
116
120
  async init(options = {}) {
117
121
  try {
122
+ // Track if this is a reinitialization (already initialized)
123
+ const isReinit = this.initialized;
124
+
125
+ // CRITICAL: Use global window flag to coordinate across bundled instances
126
+ const globalInitFlag = typeof window !== 'undefined'
127
+ ? (window.__JSG_LOGGER_INITIALIZED__ = window.__JSG_LOGGER_INITIALIZED__ || false)
128
+ : false;
129
+
130
+ // Check both static flag and global flag
131
+ const shouldLogInit = !JSGLogger._hasLoggedInitialization && !globalInitFlag && !isReinit;
132
+
118
133
  metaLog('[JSG-LOGGER] Initializing logger...', options.configPath ? `configPath: ${options.configPath}` : options.config ? 'inline config provided' : 'using defaults');
119
134
 
120
135
  // Load configuration FIRST (before environment detection)
@@ -154,15 +169,26 @@ class JSGLogger {
154
169
  this.initialized = true;
155
170
 
156
171
  // Log initialization success (only on first initialization)
157
- if (!JSGLogger._hasLoggedInitialization && this.loggers.core) {
172
+ // Double-check both flags here in case another call set it while we were initializing
173
+ const finalCheck = shouldLogInit &&
174
+ !JSGLogger._hasLoggedInitialization &&
175
+ !(typeof window !== 'undefined' && window.__JSG_LOGGER_INITIALIZED__) &&
176
+ this.loggers.core;
177
+
178
+ if (finalCheck) {
158
179
  this.loggers.core.info('JSG Logger initialized', {
180
+ version: packageJson.version,
159
181
  environment: this.environment,
160
182
  components: components.length,
161
183
  projectName: configManager.getProjectName(),
162
184
  configPaths: configManager.loadedPaths,
163
185
  fileOverrides: Object.keys(configManager.config.fileOverrides || {}).length
164
186
  });
187
+ // Set both static flag and global flag immediately after logging
165
188
  JSGLogger._hasLoggedInitialization = true;
189
+ if (typeof window !== 'undefined') {
190
+ window.__JSG_LOGGER_INITIALIZED__ = true;
191
+ }
166
192
  }
167
193
 
168
194
  return this.getLoggerExports();
@@ -185,6 +211,34 @@ class JSGLogger {
185
211
  */
186
212
  initSync(options = {}) {
187
213
  try {
214
+ // Track if this is a reinitialization (already initialized)
215
+ const isReinit = this.initialized;
216
+
217
+ // CRITICAL: Use global window flag to coordinate across bundled instances
218
+ // This handles cases where jsg-stylizer bundles its own copy of the logger
219
+ const globalInitFlag = typeof window !== 'undefined'
220
+ ? (window.__JSG_LOGGER_INITIALIZED__ = window.__JSG_LOGGER_INITIALIZED__ || false)
221
+ : false;
222
+
223
+ // CRITICAL: Use lock + flag to prevent race conditions
224
+ // If another call is already initializing, wait for it to complete
225
+ // This ensures only the first call logs, even if multiple calls happen simultaneously
226
+ if (!isReinit && JSGLogger._initLock) {
227
+ // Another initialization is in progress, skip this one
228
+ // Return existing instance if available, otherwise wait briefly
229
+ if (JSGLogger._enhancedLoggers) {
230
+ return JSGLogger._enhancedLoggers;
231
+ }
232
+ }
233
+
234
+ // Set lock if this is first initialization
235
+ if (!isReinit && !JSGLogger._hasLoggedInitialization && !globalInitFlag) {
236
+ JSGLogger._initLock = true;
237
+ }
238
+
239
+ // Check both static flag and global flag
240
+ const shouldLogInit = !JSGLogger._hasLoggedInitialization && !globalInitFlag && !isReinit;
241
+
188
242
  // Load inline config if provided (sync loading for objects)
189
243
  if (options && Object.keys(options).length > 0) {
190
244
  // Reset to default config for clean reinitialization
@@ -231,16 +285,33 @@ class JSGLogger {
231
285
 
232
286
  this.initialized = true;
233
287
 
234
- // Log initialization success (only on first initialization)
235
- if (!JSGLogger._hasLoggedInitialization && this.loggers.core) {
288
+ // Log initialization success (only on first initialization, not on reinit)
289
+ // This prevents duplicate logs when multiple libraries call getInstanceSync
290
+ // Double-check both flags here in case another call set it while we were initializing
291
+ const finalCheck = shouldLogInit &&
292
+ !JSGLogger._hasLoggedInitialization &&
293
+ !(typeof window !== 'undefined' && window.__JSG_LOGGER_INITIALIZED__) &&
294
+ this.loggers.core;
295
+
296
+ if (finalCheck) {
236
297
  this.loggers.core.info('JSG Logger initialized (sync)', {
298
+ version: packageJson.version,
237
299
  environment: this.environment,
238
300
  components: components.length,
239
301
  projectName: configManager.getProjectName(),
240
302
  fileOverrides: Object.keys(configManager.config.fileOverrides || {}).length,
241
303
  timestampMode: configManager.getTimestampMode()
242
304
  });
305
+ // Set both static flag and global flag immediately after logging
243
306
  JSGLogger._hasLoggedInitialization = true;
307
+ if (typeof window !== 'undefined') {
308
+ window.__JSG_LOGGER_INITIALIZED__ = true;
309
+ }
310
+ }
311
+
312
+ // Release lock after initialization completes
313
+ if (JSGLogger._initLock) {
314
+ JSGLogger._initLock = false;
244
315
  }
245
316
 
246
317
  return this.getLoggerExports();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crimsonsunset/jsg-logger",
3
- "version": "1.7.10",
3
+ "version": "1.7.12",
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",