@leftium/gg 0.0.41 → 0.0.42

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,9 +1,25 @@
1
1
  /**
2
2
  * Debug entry point — selects browser or node implementation.
3
3
  *
4
+ * Uses a lazy initialization pattern to avoid top-level await,
5
+ * which has incomplete Safari support and breaks SSR-disabled pages.
6
+ * The debug factory is loaded on first use via a synchronous getter
7
+ * backed by a pre-started import promise.
8
+ *
4
9
  * Re-exports the DebugFactory and Debugger types for consumers.
5
10
  */
6
11
  import type { DebugFactory } from './common.js';
7
12
  export type { DebugFactory, Debugger } from './common.js';
8
- declare const _default: DebugFactory;
9
- export default _default;
13
+ /**
14
+ * Promise that resolves when the debug factory is ready.
15
+ * Consumers that need to guarantee the factory is loaded can await this.
16
+ */
17
+ export declare const debugReady: Promise<void>;
18
+ /**
19
+ * Proxy-based default export that delegates to the real debug factory
20
+ * once loaded. This allows `import debug from './debug/index.js'` to
21
+ * work as a synchronous import while the actual implementation loads
22
+ * in the background.
23
+ */
24
+ declare const debug: DebugFactory;
25
+ export default debug;
@@ -1,11 +1,76 @@
1
1
  /**
2
2
  * Debug entry point — selects browser or node implementation.
3
3
  *
4
+ * Uses a lazy initialization pattern to avoid top-level await,
5
+ * which has incomplete Safari support and breaks SSR-disabled pages.
6
+ * The debug factory is loaded on first use via a synchronous getter
7
+ * backed by a pre-started import promise.
8
+ *
4
9
  * Re-exports the DebugFactory and Debugger types for consumers.
5
10
  */
6
11
  import { BROWSER } from 'esm-env';
7
- // Conditional import: browser.ts for browsers, node.ts for Node/Deno/Bun
8
- const { default: debug } = BROWSER
9
- ? await import('./browser.js')
10
- : await import('./node.js');
12
+ // Start loading the platform-specific implementation immediately (non-blocking).
13
+ // The promise begins resolving at module load time but doesn't block evaluation.
14
+ let _debug = null;
15
+ const _ready = (BROWSER ? import('./browser.js') : import('./node.js')).then((m) => {
16
+ _debug = m.default;
17
+ });
18
+ /**
19
+ * Ensure the debug factory is loaded. In practice, the dynamic import resolves
20
+ * almost instantly (it's a local module, not a network fetch), so by the time
21
+ * any consumer calls debugFactory() the promise is already settled.
22
+ *
23
+ * For the rare case where it's called before resolution, this returns a
24
+ * no-op debugger that buffers nothing — acceptable since gg diagnostics
25
+ * and early logging are already deferred in practice.
26
+ */
27
+ function getDebugFactory() {
28
+ if (_debug)
29
+ return _debug;
30
+ // Fallback: return a minimal no-op factory while the real one loads.
31
+ // This path is hit only if someone calls debugFactory() synchronously
32
+ // during module evaluation, before the microtask resolves.
33
+ const noop = Object.assign(function noopDebug(_namespace) {
34
+ // Return a disabled debugger stub
35
+ const stub = Object.assign(function (..._args) { }, {
36
+ namespace: _namespace,
37
+ enabled: false,
38
+ color: '0',
39
+ diff: 0,
40
+ useColors: false,
41
+ log: () => { },
42
+ extend: (sub) => noopDebug(`${_namespace}:${sub}`),
43
+ destroy: () => stub,
44
+ formatArgs: undefined
45
+ });
46
+ return stub;
47
+ }, {
48
+ enable: (_namespaces) => { },
49
+ disable: () => '',
50
+ enabled: (_namespace) => false,
51
+ names: [],
52
+ skips: []
53
+ });
54
+ return noop;
55
+ }
56
+ /**
57
+ * Promise that resolves when the debug factory is ready.
58
+ * Consumers that need to guarantee the factory is loaded can await this.
59
+ */
60
+ export const debugReady = _ready;
61
+ /**
62
+ * Proxy-based default export that delegates to the real debug factory
63
+ * once loaded. This allows `import debug from './debug/index.js'` to
64
+ * work as a synchronous import while the actual implementation loads
65
+ * in the background.
66
+ */
67
+ const debug = new Proxy((() => { }), {
68
+ apply(_target, _thisArg, args) {
69
+ return getDebugFactory()(args[0]);
70
+ },
71
+ get(_target, prop, _receiver) {
72
+ const factory = getDebugFactory();
73
+ return factory[prop];
74
+ }
75
+ });
11
76
  export default debug;
package/dist/gg.d.ts CHANGED
@@ -28,8 +28,8 @@ export declare function gg(): {
28
28
  };
29
29
  export declare function gg<T>(arg: T, ...args: unknown[]): T;
30
30
  export declare namespace gg {
31
- var disable: () => void;
32
- var enable: (namespaces: string) => void;
31
+ var disable: () => string;
32
+ var enable: (ns: string) => void;
33
33
  var clearPersist: () => void;
34
34
  }
35
35
  /**
package/dist/gg.js CHANGED
@@ -39,19 +39,30 @@ const isCloudflareWorker = () => {
39
39
  if (isCloudflareWorker()) {
40
40
  console.warn('gg: CloudFlare not supported.');
41
41
  }
42
- // Try to load Node.js modules if not in CloudFlare Workers
42
+ // Lazy-load Node.js modules to avoid top-level await (Safari compatibility).
43
+ // The imports start immediately but don't block module evaluation.
43
44
  let dotenvModule = null;
44
45
  let httpModule = null;
45
- if (!isCloudflareWorker() && !BROWSER) {
46
- try {
47
- dotenvModule = await import('dotenv');
48
- }
49
- catch {
50
- httpModule = await import('http');
51
- // Failed to import Node.js modules
52
- console.warn('gg: Node.js modules not available');
53
- }
46
+ function loadServerModules() {
47
+ if (isCloudflareWorker() || BROWSER)
48
+ return Promise.resolve();
49
+ return (async () => {
50
+ try {
51
+ dotenvModule = await import('dotenv');
52
+ }
53
+ catch {
54
+ // dotenv not available — optional dependency
55
+ }
56
+ try {
57
+ httpModule = await import('http');
58
+ }
59
+ catch {
60
+ console.warn('gg: Node.js http module not available');
61
+ }
62
+ })();
54
63
  }
64
+ // Start loading immediately (non-blocking)
65
+ const serverModulesReady = loadServerModules();
55
66
  function findAvailablePort(startingPort) {
56
67
  if (!httpModule)
57
68
  return Promise.resolve(startingPort);
@@ -80,15 +91,23 @@ function getServerPort() {
80
91
  resolve('5173');
81
92
  }
82
93
  else {
83
- // Node.js environment
84
- const startingPort = Number(process?.env?.PORT) || 5173; // Default to Vite's default port
85
- findAvailablePort(startingPort).then((actualPort) => {
86
- resolve(actualPort);
94
+ // Node.js environment — wait for http module to be available
95
+ serverModulesReady.then(() => {
96
+ const startingPort = Number(process?.env?.PORT) || 5173; // Default to Vite's default port
97
+ findAvailablePort(startingPort).then((actualPort) => {
98
+ resolve(actualPort);
99
+ });
87
100
  });
88
101
  }
89
102
  });
90
103
  }
91
- const port = await getServerPort();
104
+ // Port resolution starts immediately but doesn't block module evaluation.
105
+ // The template is updated asynchronously once the port is known.
106
+ let port = 5173; // Default fallback
107
+ void getServerPort().then((p) => {
108
+ port = p;
109
+ ggConfig.openInEditorUrlTemplate = `http://localhost:${port}/__open-in-editor?file=$FILENAME`;
110
+ });
92
111
  /**
93
112
  * Determines if gg should be enabled based on environment and runtime triggers.
94
113
  *
@@ -350,8 +369,8 @@ gg._ns = function (options, ...args) {
350
369
  gg._o = function (ns, file, line, col, src) {
351
370
  return { ns, file, line, col, src };
352
371
  };
353
- gg.disable = isCloudflareWorker() ? () => { } : debugFactory.disable;
354
- gg.enable = isCloudflareWorker() ? () => { } : debugFactory.enable;
372
+ gg.disable = isCloudflareWorker() ? () => '' : () => debugFactory.disable();
373
+ gg.enable = isCloudflareWorker() ? () => { } : (ns) => debugFactory.enable(ns);
355
374
  /**
356
375
  * Clear the persisted gg-enabled state from localStorage.
357
376
  * Useful to reset production trigger after testing with ?gg parameter.
@@ -956,6 +975,8 @@ export async function runGgDiagnostics() {
956
975
  if (!ggConfig.showHints || isCloudflareWorker() || diagnosticsRan)
957
976
  return;
958
977
  diagnosticsRan = true;
978
+ // Ensure server modules (dotenv) are loaded before diagnostics
979
+ await serverModulesReady;
959
980
  // Create test debugger for server-side enabled check
960
981
  const ggLogTest = debugFactory('gg:TEST');
961
982
  let ggMessage = '\n';
package/dist/vite.d.ts CHANGED
@@ -21,8 +21,6 @@ export interface GgPluginsOptions {
21
21
  * Includes:
22
22
  * - `ggCallSitesPlugin` — rewrites `gg()` calls with source file/line/col metadata
23
23
  * - `openInEditorPlugin` — adds `/__open-in-editor` dev server middleware
24
- * - Automatic `es2022` build target (required for top-level await)
25
- *
26
24
  * @example
27
25
  * ```ts
28
26
  * import ggPlugins from '@leftium/gg/vite';
package/dist/vite.js CHANGED
@@ -6,8 +6,6 @@ import openInEditorPlugin from './open-in-editor.js';
6
6
  * Includes:
7
7
  * - `ggCallSitesPlugin` — rewrites `gg()` calls with source file/line/col metadata
8
8
  * - `openInEditorPlugin` — adds `/__open-in-editor` dev server middleware
9
- * - Automatic `es2022` build target (required for top-level await)
10
- *
11
9
  * @example
12
10
  * ```ts
13
11
  * import ggPlugins from '@leftium/gg/vite';
@@ -19,23 +17,6 @@ import openInEditorPlugin from './open-in-editor.js';
19
17
  */
20
18
  export default function ggPlugins(options = {}) {
21
19
  const plugins = [];
22
- // Ensure es2022 target for top-level await support
23
- plugins.push({
24
- name: 'gg-config',
25
- config() {
26
- return {
27
- build: {
28
- target: 'es2022'
29
- },
30
- optimizeDeps: {
31
- esbuildOptions: {
32
- target: 'es2022',
33
- supported: { 'top-level-await': true }
34
- }
35
- }
36
- };
37
- }
38
- });
39
20
  plugins.push(ggCallSitesPlugin(options.callSites));
40
21
  if (options.openInEditor !== false) {
41
22
  plugins.push(openInEditorPlugin());
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@leftium/gg",
3
- "version": "0.0.41",
3
+ "version": "0.0.42",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/Leftium/gg.git"