@crimsonsunset/jsg-logger 1.6.0 → 1.7.2

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/index.js CHANGED
@@ -6,13 +6,38 @@
6
6
  import pino from 'pino';
7
7
  import {configManager} from './config/config-manager.js';
8
8
  import {COMPONENT_SCHEME} from './config/component-schemes.js';
9
- import defaultConfig from './config/default-config.json' with { type: 'json' };
10
- import {getEnvironment, isBrowser, isCLI, forceEnvironment} from './utils/environment-detector.js';
9
+ import defaultConfig from './config/default-config.json' with {type: 'json'};
10
+ import {forceEnvironment, getEnvironment, isBrowser, isCLI} from './utils/environment-detector.js';
11
11
  import {createBrowserFormatter} from './formatters/browser-formatter.js';
12
12
  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
 
16
+ // Check default config for devtools at module load time
17
+ // This allows bundlers to tree-shake if disabled
18
+ const defaultDevtoolsEnabled = defaultConfig.devtools?.enabled ?? false;
19
+
20
+ // Conditional static import - bundlers can eliminate if condition is false
21
+ // If defaultDevtoolsEnabled is false, bundler removes this entire block
22
+ // Use lazy initialization to avoid top-level await (which would make module async)
23
+ let devtoolsModule = null;
24
+ let devtoolsModulePromise = null;
25
+ if (defaultDevtoolsEnabled) {
26
+ console.log('[JSG-LOGGER] DevTools module pre-loading started (default config enabled)');
27
+ // Start loading immediately but don't await (non-blocking)
28
+ // Bundlers can still analyze this static import for tree-shaking
29
+ devtoolsModulePromise = import('./devtools/dist/panel-entry.js').then(module => {
30
+ devtoolsModule = module;
31
+ console.log('[JSG-LOGGER] DevTools module pre-loaded successfully');
32
+ return module;
33
+ }).catch(error => {
34
+ console.error('[JSG-LOGGER] DevTools module pre-load failed:', error);
35
+ return null;
36
+ });
37
+ } else {
38
+ console.log('[JSG-LOGGER] DevTools module NOT pre-loaded (default config disabled - will tree-shake)');
39
+ }
40
+
16
41
  /**
17
42
  * Main Logger Class
18
43
  * Manages logger instances and provides the public API
@@ -28,6 +53,9 @@ class JSGLogger {
28
53
  this.environment = null; // Will be set after config loads
29
54
  this.initialized = false;
30
55
  this.components = {}; // Auto-discovery getters
56
+
57
+ // Initialize component getters with safe factories that always return loggers
58
+ this._initializeSafeComponentGetters();
31
59
  }
32
60
 
33
61
  /**
@@ -36,21 +64,39 @@ class JSGLogger {
36
64
  * @returns {Promise<Object>} Enhanced logger exports with controls API
37
65
  */
38
66
  static async getInstance(options = {}) {
67
+ const hasOptions = options && Object.keys(options).length > 0;
68
+
39
69
  if (!JSGLogger._instance) {
70
+ // First time initialization
40
71
  JSGLogger._instance = new JSGLogger();
41
72
  JSGLogger._enhancedLoggers = await JSGLogger._instance.init(options);
73
+
74
+ // Make runtime controls available globally in browser for debugging
75
+ if (isBrowser() && typeof window !== 'undefined' && JSGLogger._enhancedLoggers?.controls) {
76
+ window.JSG_Logger = JSGLogger._enhancedLoggers.controls;
77
+ }
78
+ } else if (hasOptions) {
79
+ // Instance exists but new options provided - reinitialize
80
+ JSGLogger._enhancedLoggers = await JSGLogger._instance.init(options);
81
+
82
+ // Make runtime controls available globally in browser for debugging
83
+ // (same as getInstanceSync behavior)
84
+ if (isBrowser() && typeof window !== 'undefined' && JSGLogger._enhancedLoggers?.controls) {
85
+ window.JSG_Logger = JSGLogger._enhancedLoggers.controls;
86
+ }
42
87
  }
88
+
43
89
  return JSGLogger._enhancedLoggers;
44
90
  }
45
91
 
46
92
  /**
47
93
  * Get singleton instance synchronously (for environments without async support)
48
- * @param {Object} options - Initialization options (only used on first call)
94
+ * @param {Object} options - Initialization options (only used on first call)
49
95
  * @returns {Object} Enhanced logger exports with controls API
50
96
  */
51
97
  static getInstanceSync(options = {}) {
52
98
  const hasOptions = options && Object.keys(options).length > 0;
53
-
99
+
54
100
  if (!JSGLogger._instance) {
55
101
  // First time initialization
56
102
  JSGLogger._instance = new JSGLogger();
@@ -59,7 +105,7 @@ class JSGLogger {
59
105
  // Instance exists but new options provided - reinitialize
60
106
  JSGLogger._enhancedLoggers = JSGLogger._instance.initSync(options);
61
107
  }
62
-
108
+
63
109
  return JSGLogger._enhancedLoggers;
64
110
  }
65
111
 
@@ -70,6 +116,8 @@ class JSGLogger {
70
116
  */
71
117
  async init(options = {}) {
72
118
  try {
119
+ console.log('[JSG-LOGGER] Initializing logger...', options.configPath ? `configPath: ${options.configPath}` : options.config ? 'inline config provided' : 'using defaults');
120
+
73
121
  // Load configuration FIRST (before environment detection)
74
122
  if (options.configPath || options.config) {
75
123
  await configManager.loadConfig(options.configPath || options.config);
@@ -132,8 +180,14 @@ class JSGLogger {
132
180
  try {
133
181
  // Load inline config if provided (sync loading for objects)
134
182
  if (options && Object.keys(options).length > 0) {
135
- // Merge inline config with existing config
136
- configManager.config = configManager.mergeConfigs(configManager.config, options);
183
+ // Reset to default config for clean reinitialization
184
+ // This ensures each reinit starts from a known state
185
+ configManager.config = {...defaultConfig};
186
+
187
+ // Normalize the inline config first
188
+ const normalizedOptions = configManager._normalizeConfigStructure(options);
189
+ // Merge inline config with default config
190
+ configManager.config = configManager.mergeConfigs(configManager.config, normalizedOptions);
137
191
  }
138
192
 
139
193
  // Apply forceEnvironment if specified in config
@@ -144,6 +198,10 @@ class JSGLogger {
144
198
  // NOW determine environment (after config is loaded and forceEnvironment is applied)
145
199
  this.environment = getEnvironment();
146
200
 
201
+ // Clear existing loggers for clean reinitialization
202
+ this.loggers = {};
203
+ this.components = {};
204
+
147
205
  // Create loggers for all available components using default config
148
206
  const components = configManager.getAvailableComponents();
149
207
 
@@ -287,7 +345,7 @@ class JSGLogger {
287
345
  addUtilityMethods() {
288
346
  // Store reference to original createLogger before overriding
289
347
  const originalCreateLogger = this.createLogger.bind(this);
290
-
348
+
291
349
  // Create logger on demand (reuses existing loggers)
292
350
  this.createLogger = (componentName) => {
293
351
  if (!this.loggers[componentName]) {
@@ -295,7 +353,7 @@ class JSGLogger {
295
353
  }
296
354
  return this.loggers[componentName];
297
355
  };
298
-
356
+
299
357
  // Store the original for internal use
300
358
  this._createLoggerOriginal = originalCreateLogger;
301
359
  }
@@ -412,6 +470,8 @@ class JSGLogger {
412
470
 
413
471
  // Statistics and debugging
414
472
  getStats: () => this.logStore.getStats(),
473
+ subscribe: (callback) => this.logStore.subscribe(callback),
474
+ clearLogs: () => this.logStore.clear(),
415
475
  getConfigSummary: () => configManager.getSummary(),
416
476
 
417
477
  // Advanced configuration
@@ -428,42 +488,64 @@ class JSGLogger {
428
488
 
429
489
  // DevTools panel controls
430
490
  enableDevPanel: async () => {
491
+ // Early config check - uses consumer's runtime config
492
+ const runtimeDevtoolsEnabled = configManager.config.devtools?.enabled ?? false;
493
+
494
+ console.log(`[JSG-LOGGER] enableDevPanel() called - runtime config: ${runtimeDevtoolsEnabled ? 'ENABLED' : 'DISABLED'}`);
495
+
496
+ if (!runtimeDevtoolsEnabled) {
497
+ console.warn('[JSG-LOGGER] DevTools disabled via config. Set devtools.enabled: true to enable.');
498
+ return null;
499
+ }
500
+
431
501
  if (typeof window === 'undefined') {
432
502
  console.warn('[JSG-LOGGER] DevTools panel only available in browser environments');
433
503
  return null;
434
504
  }
435
505
 
436
506
  try {
437
- // In development: import source files directly for hot reload
438
- // In production: import built bundle
439
- const isDev = import.meta.env?.DEV || window.location.hostname === 'localhost';
440
-
441
- let module;
442
- if (isDev) {
443
- console.log('🔥 DEV MODE: Attempting to load DevTools from SOURCE for hot reload');
444
- try {
445
- // Fix the import path for Vite dev server
446
- const importPath = '/src/panel-entry.jsx';
447
- console.log('🔍 Importing:', importPath);
448
- module = await import(importPath);
449
- console.log('✅ Source import successful:', module);
450
- } catch (sourceError) {
451
- console.error('❌ Source import failed, falling back to bundle:', sourceError);
452
- const cacheBuster = Date.now();
453
- module = await import(`./devtools/dist/panel-entry.js?v=${cacheBuster}`);
507
+ // Use pre-loaded module (from default config) or load dynamically (consumer's runtime config override)
508
+ if (!devtoolsModule) {
509
+ // Check if we have a promise for pre-loading
510
+ if (devtoolsModulePromise) {
511
+ console.log('[JSG-LOGGER] Waiting for pre-loaded DevTools module...');
512
+ // Wait for pre-load to complete
513
+ devtoolsModule = await devtoolsModulePromise;
514
+ } else {
515
+ // Runtime config override: consumer enabled devtools but default was disabled
516
+ // Load on demand via dynamic import
517
+ console.log('[JSG-LOGGER] Loading DevTools module dynamically (runtime config override)...');
518
+ devtoolsModule = await import('./devtools/dist/panel-entry.js');
454
519
  }
455
520
  } else {
456
- console.log('📦 PROD MODE: Loading DevTools from built bundle');
457
- const cacheBuster = Date.now();
458
- module = await import(`./devtools/dist/panel-entry.js?v=${cacheBuster}`);
521
+ console.log('[JSG-LOGGER] Using pre-loaded DevTools module');
522
+ }
523
+
524
+ if (!devtoolsModule || !devtoolsModule.initializePanel) {
525
+ throw new Error('DevTools panel module missing initializePanel export');
459
526
  }
460
- return module.initializePanel();
527
+
528
+ console.log('[JSG-LOGGER] Initializing DevTools panel...');
529
+ const panel = devtoolsModule.initializePanel();
530
+ console.log('[JSG-LOGGER] DevTools panel initialized successfully');
531
+ return panel;
461
532
  } catch (error) {
462
533
  console.error('[JSG-LOGGER] Failed to load DevTools panel:', error);
534
+ console.error('[JSG-LOGGER] If using npm link, ensure Vite config has: server.fs.allow: [\'..\']');
463
535
  return null;
464
536
  }
465
537
  },
466
538
 
539
+ disableDevPanel: () => {
540
+ if (typeof window !== 'undefined' && window.JSG_DevTools?.destroy) {
541
+ window.JSG_DevTools.destroy();
542
+ console.log('[JSG-LOGGER] DevTools panel disabled and destroyed');
543
+ return true;
544
+ }
545
+ console.warn('[JSG-LOGGER] DevTools panel not loaded or already destroyed');
546
+ return false;
547
+ },
548
+
467
549
  // System controls
468
550
  refresh: () => this.refreshLoggers(),
469
551
  reset: () => {
@@ -483,19 +565,19 @@ class JSGLogger {
483
565
  createDirectBrowserLogger(componentName) {
484
566
  const formatter = createBrowserFormatter(componentName, this.logStore);
485
567
  const levels = ['trace', 'debug', 'info', 'warn', 'error', 'fatal'];
486
- const levelMap = { trace: 10, debug: 20, info: 30, warn: 40, error: 50, fatal: 60 };
487
-
568
+ const levelMap = {trace: 10, debug: 20, info: 30, warn: 40, error: 50, fatal: 60};
569
+
488
570
  const logger = {};
489
-
571
+
490
572
  levels.forEach(level => {
491
573
  logger[level] = (first, ...args) => {
492
574
  const logLevel = levelMap[level];
493
-
575
+
494
576
  // Check if level should be logged
495
577
  const effectiveLevel = configManager.getEffectiveLevel(componentName);
496
578
  const minLevel = levelMap[effectiveLevel] || 30;
497
579
  if (logLevel < minLevel) return;
498
-
580
+
499
581
  // Create log data object
500
582
  let logData = {
501
583
  level: logLevel,
@@ -503,7 +585,7 @@ class JSGLogger {
503
585
  name: componentName,
504
586
  v: 1
505
587
  };
506
-
588
+
507
589
  // Handle different argument patterns
508
590
  if (typeof first === 'string') {
509
591
  logData.msg = first;
@@ -519,18 +601,18 @@ class JSGLogger {
519
601
  logData.msg = args[0];
520
602
  }
521
603
  }
522
-
604
+
523
605
  // Use our beautiful formatter
524
606
  formatter.write(JSON.stringify(logData));
525
607
  };
526
608
  });
527
-
609
+
528
610
  // Add Pino-compatible properties
529
611
  logger._componentEmoji = configManager.getComponentConfig(componentName).emoji;
530
612
  logger._componentName = componentName;
531
613
  logger._effectiveLevel = configManager.getEffectiveLevel(componentName);
532
614
  logger.level = configManager.getEffectiveLevel(componentName);
533
-
615
+
534
616
  return logger;
535
617
  }
536
618
 
@@ -558,9 +640,13 @@ class JSGLogger {
558
640
  fatal: console.error
559
641
  };
560
642
 
643
+ // No-op logger factory for getComponent
644
+ const noOpLogger = () => fallback;
645
+
561
646
  return {
562
647
  core: fallback,
563
648
  createLogger: () => fallback,
649
+ getComponent: noOpLogger,
564
650
  config: {environment: 'fallback'},
565
651
  logStore: {getRecent: () => [], clear: () => {}},
566
652
  controls: {
@@ -574,20 +660,46 @@ class JSGLogger {
574
660
  }
575
661
 
576
662
  /**
577
- * Create auto-discovery getters for easy component access
578
- * Supports both kebab-case (original) and camelCase naming
663
+ * Initialize safe component getters that always return logger factories
664
+ * This ensures components can be accessed even before initialization
579
665
  * @private
580
666
  */
667
+ _initializeSafeComponentGetters() {
668
+ // Create safe getters for common components that always return a logger factory
669
+ // These will work even if logger isn't initialized yet
670
+ const commonComponents = [
671
+ 'reactComponents', 'react-components',
672
+ 'astroComponents', 'astro-components',
673
+ 'astroBuild', 'astro-build',
674
+ 'astroIntegration', 'astro-integration',
675
+ 'contentProcessing', 'content-processing',
676
+ 'textUtils', 'text-utils',
677
+ 'dateUtils', 'date-utils',
678
+ 'pages', 'webComponents', 'web-components',
679
+ 'core', 'api', 'ui', 'database', 'test', 'preact',
680
+ 'auth', 'analytics', 'performance', 'websocket',
681
+ 'notification', 'router', 'cache',
682
+ 'config', 'seo', 'devServer', 'dev-server'
683
+ ];
684
+
685
+ commonComponents.forEach(name => {
686
+ // Create getter that always returns a logger (no-op if not initialized)
687
+ this.components[name] = () => this.getComponent(name);
688
+ });
689
+ }
690
+
581
691
  _createAutoDiscoveryGetters() {
582
- this.components = {};
583
-
692
+ // Don't reset components - preserve safe getters created in constructor
693
+ // Only add getters for newly created loggers
584
694
  Object.keys(this.loggers).forEach(name => {
585
- // Original kebab-case name
586
- this.components[name] = () => this.getComponent(name);
587
-
695
+ // Only add if not already exists (preserve safe getters)
696
+ if (!this.components[name]) {
697
+ this.components[name] = () => this.getComponent(name);
698
+ }
699
+
588
700
  // camelCase convenience getter
589
701
  const camelName = name.replace(/-([a-z])/g, (match, letter) => letter.toUpperCase());
590
- if (camelName !== name) {
702
+ if (camelName !== name && !this.components[camelName]) {
591
703
  this.components[camelName] = () => this.getComponent(name);
592
704
  }
593
705
  });
@@ -595,35 +707,68 @@ class JSGLogger {
595
707
 
596
708
  /**
597
709
  * Get a specific component logger with auto-creation for custom components
710
+ * Always returns a logger instance (no-op if initialization failed)
598
711
  * @param {string} componentName - Component name to retrieve
599
- * @returns {Object} Logger instance (auto-created if needed)
712
+ * @returns {Object} Logger instance (always returns logger, never undefined)
600
713
  */
601
714
  getComponent(componentName) {
602
- // If logger doesn't exist, auto-create it for custom components
603
- if (!this.loggers[componentName]) {
715
+ // If logger instance isn't initialized, return no-op logger
716
+ if (!this.initialized || !this.loggers) {
717
+ return this._createNoOpLogger(componentName);
718
+ }
719
+
720
+ // If logger exists, return it
721
+ if (this.loggers[componentName]) {
722
+ return this.loggers[componentName];
723
+ }
724
+
725
+ // Try to create logger - if it fails, return no-op logger
726
+ try {
604
727
  // Check if this is a configured component or custom component
605
728
  const hasConfig = configManager.config.components?.[componentName];
606
729
  const hasScheme = COMPONENT_SCHEME[componentName];
607
-
730
+
608
731
  if (!hasConfig && !hasScheme) {
609
732
  // Custom component - log info and auto-create
610
733
  if (this.loggers.core) {
611
734
  this.loggers.core.debug(`Auto-creating custom component logger: ${componentName}`);
612
735
  }
613
736
  }
614
-
737
+
615
738
  // Create the logger (getComponentConfig will auto-generate config for custom components)
616
739
  this.loggers[componentName] = this.createLogger(componentName);
617
-
740
+
618
741
  // Also add to auto-discovery getters
619
742
  this.components[componentName] = () => this.getComponent(componentName);
620
743
  const camelName = componentName.replace(/-([a-z])/g, (match, letter) => letter.toUpperCase());
621
744
  if (camelName !== componentName) {
622
745
  this.components[camelName] = () => this.getComponent(componentName);
623
746
  }
747
+
748
+ return this.loggers[componentName];
749
+ } catch (error) {
750
+ // If logger creation fails, return no-op logger to prevent crashes
751
+ console.warn(`[JSG-LOGGER] Failed to create logger for component '${componentName}', using no-op logger:`, error);
752
+ return this._createNoOpLogger(componentName);
624
753
  }
625
-
626
- return this.loggers[componentName];
754
+ }
755
+
756
+ /**
757
+ * Create a silent no-op logger that can be safely used when logger isn't available
758
+ * @param {string} componentName - Component name (for consistency)
759
+ * @returns {Object} Logger instance with all methods as no-ops
760
+ * @private
761
+ */
762
+ _createNoOpLogger(componentName) {
763
+ // Silent no-op logger - all methods do nothing
764
+ return {
765
+ trace: () => {},
766
+ debug: () => {},
767
+ info: () => {},
768
+ warn: () => {},
769
+ error: () => {},
770
+ fatal: () => {}
771
+ };
627
772
  }
628
773
 
629
774
  /**
@@ -635,7 +780,7 @@ class JSGLogger {
635
780
  _createErrorLogger(componentName) {
636
781
  const prefix = `[${componentName.toUpperCase()}]`;
637
782
  const errorMsg = '⚠️ Component not configured -';
638
-
783
+
639
784
  return {
640
785
  trace: (msg, ...args) => console.log(`${prefix} ${errorMsg}`, msg, ...args),
641
786
  debug: (msg, ...args) => console.log(`${prefix} ${errorMsg}`, msg, ...args),
@@ -658,7 +803,7 @@ class JSGLogger {
658
803
  const instance = await JSGLogger.getInstance();
659
804
  const logger = instance.getComponent(component);
660
805
  const duration = performance.now() - startTime;
661
-
806
+
662
807
  if (duration > 1000) {
663
808
  logger.warn(`${operation} took ${duration.toFixed(2)}ms (slow)`);
664
809
  } else if (duration > 100) {
@@ -666,7 +811,7 @@ class JSGLogger {
666
811
  } else {
667
812
  logger.debug(`${operation} took ${duration.toFixed(2)}ms (fast)`);
668
813
  }
669
-
814
+
670
815
  return duration;
671
816
  } catch (error) {
672
817
  // Fallback to console if logger fails
package/package.json CHANGED
@@ -1,9 +1,10 @@
1
1
  {
2
2
  "name": "@crimsonsunset/jsg-logger",
3
- "version": "1.6.0",
3
+ "version": "1.7.2",
4
4
  "type": "module",
5
- "description": "JSG Logger - Multi-environment logger with smart detection, file-level overrides, and beautiful console formatting",
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",
7
+ "types": "./index.d.ts",
7
8
  "keywords": [
8
9
  "logging",
9
10
  "pino",
@@ -27,30 +28,48 @@
27
28
  },
28
29
  "homepage": "https://github.com/crimsonsunset/jsg-logger#readme",
29
30
  "dependencies": {
30
- "@preact/preset-vite": "^2.10.2",
31
- "evergreen-ui": "^7.1.9",
32
31
  "lodash.merge": "^4.6.2",
33
- "pino": "^9.7.0",
34
- "preact": "^10.27.1"
32
+ "pino": "^9.7.0"
33
+ },
34
+ "peerDependencies": {
35
+ "preact": "^10.27.1",
36
+ "evergreen-ui": "^7.1.9"
37
+ },
38
+ "peerDependenciesMeta": {
39
+ "preact": {
40
+ "optional": true
41
+ },
42
+ "evergreen-ui": {
43
+ "optional": true
44
+ }
35
45
  },
36
46
  "devDependencies": {
47
+ "@preact/preset-vite": "^2.10.2",
48
+ "evergreen-ui": "^7.1.9",
49
+ "preact": "^10.27.1",
37
50
  "vite": "^5.1.3"
38
51
  },
39
52
  "files": [
40
53
  "index.js",
54
+ "index.d.ts",
41
55
  "config/",
42
56
  "formatters/",
43
57
  "stores/",
44
58
  "utils/",
45
59
  "examples/",
46
60
  "docs/",
61
+ "devtools/dist/",
47
62
  "README.md",
48
63
  "CHANGELOG.md",
49
64
  "CONTRIBUTING.md",
50
65
  "LICENSE"
51
66
  ],
52
67
  "exports": {
53
- ".": "./index.js",
68
+ ".": {
69
+ "import": "./index.js",
70
+ "require": "./index.js",
71
+ "types": "./index.d.ts"
72
+ },
54
73
  "./config": "./config/config-manager.js",
55
74
  "./config/manager": "./config/config-manager.js",
56
75
  "./config/schemes": "./config/component-schemes.js",
@@ -62,25 +81,23 @@
62
81
  "./stores/log-store": "./stores/log-store.js",
63
82
  "./utils": "./utils/environment-detector.js",
64
83
  "./utils/environment": "./utils/environment-detector.js",
84
+ "./devtools": "./devtools/dist/panel-entry.js",
65
85
  "./examples/*": "./examples/*"
66
86
  },
67
87
  "scripts": {
68
88
  "test": "node tests/run-all.js",
69
89
  "test:watch": "nodemon --watch . --ext js --exec 'npm test'",
70
90
  "dev": "vite",
71
- "dev:devtools": "vite",
91
+ "dev:devtools": "cd devtools && npm run dev",
72
92
  "test:devtools": "vite",
73
93
  "build:devtools": "cd devtools && npm run build",
74
- "release:patch": "npm version patch && npm publish --access public",
75
- "release:minor": "npm version minor && npm publish --access public",
76
- "release:major": "npm version major && npm publish --access public",
77
- "release": "npm run release:patch",
94
+ "build:devtools:netlify": "npm install && cd devtools && npm install && npm run build:netlify",
95
+ "preview:devtools": "cd devtools && npm run preview",
96
+ "release:patch": "node scripts/release.js patch",
97
+ "release:minor": "node scripts/release.js minor",
98
+ "release:major": "node scripts/release.js major",
78
99
  "publish:public": "npm publish --access public",
79
100
  "publish:github": "npm publish --registry=https://npm.pkg.github.com/ --access public",
80
- "publish:dual": "npm publish --access public && npm publish --registry=https://npm.pkg.github.com/ --access public",
81
- "release:dual:patch": "npm version patch && npm run publish:dual",
82
- "release:dual:minor": "npm version minor && npm run publish:dual",
83
- "release:dual:major": "npm version major && npm run publish:dual",
84
101
  "check": "npm run test && echo 'Package ready for publishing'"
85
102
  }
86
103
  }