@useavalon/avalon 0.1.11 β 0.1.13
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/README.md +54 -54
- package/mod.ts +302 -302
- package/package.json +49 -26
- package/src/build/integration-bundler-plugin.ts +116 -116
- package/src/build/integration-config.ts +168 -168
- package/src/build/integration-detection-plugin.ts +117 -117
- package/src/build/integration-resolver-plugin.ts +90 -90
- package/src/build/island-manifest.ts +269 -269
- package/src/build/island-types-generator.ts +476 -476
- package/src/build/mdx-island-transform.ts +464 -464
- package/src/build/mdx-plugin.ts +98 -98
- package/src/build/page-island-transform.ts +598 -598
- package/src/build/prop-extractors/index.ts +21 -21
- package/src/build/prop-extractors/lit.ts +140 -140
- package/src/build/prop-extractors/qwik.ts +16 -16
- package/src/build/prop-extractors/solid.ts +125 -125
- package/src/build/prop-extractors/svelte.ts +194 -194
- package/src/build/prop-extractors/vue.ts +111 -111
- package/src/build/sidecar-file-manager.ts +104 -104
- package/src/build/sidecar-renderer.ts +30 -30
- package/src/client/adapters/index.ts +21 -13
- package/src/client/components.ts +35 -35
- package/src/client/css-hmr-handler.ts +344 -344
- package/src/client/framework-adapter.ts +462 -462
- package/src/client/hmr-coordinator.ts +396 -396
- package/src/client/hmr-error-overlay.js +533 -533
- package/src/client/main.js +824 -816
- package/src/client/types/framework-runtime.d.ts +68 -68
- package/src/client/types/vite-hmr.d.ts +46 -46
- package/src/client/types/vite-virtual-modules.d.ts +70 -60
- package/src/components/Image.tsx +123 -123
- package/src/components/IslandErrorBoundary.tsx +145 -145
- package/src/components/LayoutDataErrorBoundary.tsx +141 -141
- package/src/components/LayoutErrorBoundary.tsx +127 -127
- package/src/components/PersistentIsland.tsx +52 -52
- package/src/components/StreamingErrorBoundary.tsx +233 -233
- package/src/components/StreamingLayout.tsx +538 -538
- package/src/core/components/component-analyzer.ts +192 -192
- package/src/core/components/component-detection.ts +508 -508
- package/src/core/components/enhanced-framework-detector.ts +500 -500
- package/src/core/components/framework-registry.ts +563 -563
- package/src/core/content/mdx-processor.ts +46 -46
- package/src/core/integrations/index.ts +19 -19
- package/src/core/integrations/loader.ts +125 -125
- package/src/core/integrations/registry.ts +175 -175
- package/src/core/islands/island-persistence.ts +325 -325
- package/src/core/islands/island-state-serializer.ts +258 -258
- package/src/core/islands/persistent-island-context.tsx +80 -80
- package/src/core/islands/use-persistent-state.ts +68 -68
- package/src/core/layout/enhanced-layout-resolver.ts +322 -322
- package/src/core/layout/layout-cache-manager.ts +485 -485
- package/src/core/layout/layout-composer.ts +357 -357
- package/src/core/layout/layout-data-loader.ts +516 -516
- package/src/core/layout/layout-discovery.ts +243 -243
- package/src/core/layout/layout-matcher.ts +299 -299
- package/src/core/layout/layout-types.ts +110 -110
- package/src/core/modules/framework-module-resolver.ts +273 -273
- package/src/islands/component-analysis.ts +213 -213
- package/src/islands/css-utils.ts +565 -565
- package/src/islands/discovery/index.ts +80 -80
- package/src/islands/discovery/registry.ts +340 -340
- package/src/islands/discovery/resolver.ts +477 -477
- package/src/islands/discovery/scanner.ts +386 -386
- package/src/islands/discovery/types.ts +117 -117
- package/src/islands/discovery/validator.ts +544 -544
- package/src/islands/discovery/watcher.ts +368 -368
- package/src/islands/framework-detection.ts +428 -428
- package/src/islands/integration-loader.ts +490 -490
- package/src/islands/island.tsx +565 -565
- package/src/islands/render-cache.ts +550 -550
- package/src/islands/types.ts +80 -80
- package/src/islands/universal-css-collector.ts +157 -157
- package/src/islands/universal-head-collector.ts +137 -137
- package/src/layout-system.d.ts +592 -592
- package/src/layout-system.ts +218 -218
- package/src/middleware/discovery.ts +268 -268
- package/src/middleware/executor.ts +315 -315
- package/src/middleware/index.ts +76 -76
- package/src/middleware/types.ts +99 -99
- package/src/nitro/build-config.ts +575 -575
- package/src/nitro/config.ts +483 -483
- package/src/nitro/error-handler.ts +636 -636
- package/src/nitro/index.ts +173 -173
- package/src/nitro/island-manifest.ts +584 -584
- package/src/nitro/middleware-adapter.ts +260 -260
- package/src/nitro/renderer.ts +1471 -1471
- package/src/nitro/route-discovery.ts +439 -439
- package/src/nitro/types.ts +321 -321
- package/src/render/collect-css.ts +198 -198
- package/src/render/error-pages.ts +79 -79
- package/src/render/isolated-ssr-renderer.ts +654 -654
- package/src/render/ssr.ts +1030 -1030
- package/src/schemas/api.ts +30 -30
- package/src/schemas/core.ts +64 -64
- package/src/schemas/index.ts +212 -212
- package/src/schemas/layout.ts +279 -279
- package/src/schemas/routing/index.ts +38 -38
- package/src/schemas/routing.ts +376 -376
- package/src/types/as-island.ts +20 -20
- package/src/types/image.d.ts +106 -106
- package/src/types/index.d.ts +22 -22
- package/src/types/island-jsx.d.ts +33 -33
- package/src/types/island-prop.d.ts +20 -20
- package/src/types/layout.ts +285 -285
- package/src/types/mdx.d.ts +6 -6
- package/src/types/routing.ts +555 -555
- package/src/types/types.ts +5 -5
- package/src/types/urlpattern.d.ts +49 -49
- package/src/types/vite-env.d.ts +11 -11
- package/src/utils/dev-logger.ts +299 -299
- package/src/utils/fs.ts +151 -151
- package/src/vite-plugin/auto-discover.ts +551 -551
- package/src/vite-plugin/config.ts +266 -266
- package/src/vite-plugin/errors.ts +127 -127
- package/src/vite-plugin/image-optimization.ts +156 -156
- package/src/vite-plugin/integration-activator.ts +126 -126
- package/src/vite-plugin/island-sidecar-plugin.ts +176 -176
- package/src/vite-plugin/module-discovery.ts +189 -189
- package/src/vite-plugin/nitro-integration.ts +1354 -1354
- package/src/vite-plugin/plugin.ts +403 -409
- package/src/vite-plugin/types.ts +327 -327
- package/src/vite-plugin/validation.ts +228 -228
- package/src/client/adapters/index.js +0 -12
- package/src/client/adapters/lit-adapter.js +0 -467
- package/src/client/adapters/lit-adapter.ts +0 -654
- package/src/client/adapters/preact-adapter.js +0 -223
- package/src/client/adapters/preact-adapter.ts +0 -331
- package/src/client/adapters/qwik-adapter.js +0 -259
- package/src/client/adapters/qwik-adapter.ts +0 -345
- package/src/client/adapters/react-adapter.js +0 -220
- package/src/client/adapters/react-adapter.ts +0 -353
- package/src/client/adapters/solid-adapter.js +0 -295
- package/src/client/adapters/solid-adapter.ts +0 -451
- package/src/client/adapters/svelte-adapter.js +0 -368
- package/src/client/adapters/svelte-adapter.ts +0 -524
- package/src/client/adapters/vue-adapter.js +0 -278
- package/src/client/adapters/vue-adapter.ts +0 -467
- package/src/client/components.js +0 -23
- package/src/client/css-hmr-handler.js +0 -263
- package/src/client/framework-adapter.js +0 -283
- package/src/client/hmr-coordinator.js +0 -274
package/src/utils/dev-logger.ts
CHANGED
|
@@ -1,299 +1,299 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Dev-Only Logging Utilities
|
|
3
|
-
*
|
|
4
|
-
* These functions provide environment-aware logging that only outputs in development mode.
|
|
5
|
-
* In production (NODE_ENV=production), all logging is suppressed for better performance.
|
|
6
|
-
*
|
|
7
|
-
* @module dev-logger
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
// ============================================================================
|
|
11
|
-
// Environment Detection
|
|
12
|
-
// ============================================================================
|
|
13
|
-
|
|
14
|
-
/**
|
|
15
|
-
* Check if we're in development mode
|
|
16
|
-
* Returns true if NODE_ENV is not set to "production"
|
|
17
|
-
*/
|
|
18
|
-
export function isDev(): boolean {
|
|
19
|
-
try {
|
|
20
|
-
return process.env.NODE_ENV !== "production";
|
|
21
|
-
} catch {
|
|
22
|
-
return true; // Default to dev mode if we can't check
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Check if verbose logging is enabled
|
|
28
|
-
* Returns true only if AVALON_VERBOSE=1 is set
|
|
29
|
-
*/
|
|
30
|
-
export function isVerbose(): boolean {
|
|
31
|
-
try {
|
|
32
|
-
return process.env.AVALON_VERBOSE === "1";
|
|
33
|
-
} catch {
|
|
34
|
-
return false;
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
// ============================================================================
|
|
39
|
-
// Dev-Only Logging Functions
|
|
40
|
-
// ============================================================================
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Log a message only in development mode AND when AVALON_VERBOSE=1 is set.
|
|
44
|
-
* By default this is a no-op β set AVALON_VERBOSE=1 to enable diagnostic output.
|
|
45
|
-
*
|
|
46
|
-
* @param args - Arguments to pass to console.log
|
|
47
|
-
*/
|
|
48
|
-
export function devLog(...args: unknown[]): void {
|
|
49
|
-
if (isDev() && isVerbose()) {
|
|
50
|
-
console.log(...args);
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/**
|
|
55
|
-
* Log a warning only in development mode
|
|
56
|
-
* In production, this is a no-op for performance
|
|
57
|
-
*
|
|
58
|
-
* @param args - Arguments to pass to console.warn
|
|
59
|
-
*/
|
|
60
|
-
export function devWarn(...args: unknown[]): void {
|
|
61
|
-
if (isDev()) {
|
|
62
|
-
console.warn(...args);
|
|
63
|
-
}
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* Log an error only in development mode
|
|
68
|
-
* In production, this is a no-op for performance
|
|
69
|
-
*
|
|
70
|
-
* @param args - Arguments to pass to console.error
|
|
71
|
-
*/
|
|
72
|
-
export function devError(...args: unknown[]): void {
|
|
73
|
-
if (isDev()) {
|
|
74
|
-
console.error(...args);
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
// ============================================================================
|
|
79
|
-
// Performance Tracking
|
|
80
|
-
// ============================================================================
|
|
81
|
-
|
|
82
|
-
/** Default threshold for slow render warnings (in milliseconds) */
|
|
83
|
-
const DEFAULT_SLOW_RENDER_THRESHOLD = 100;
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* Log render timing information for an island component
|
|
87
|
-
* Only logs in development mode AND when AVALON_VERBOSE=1 is set
|
|
88
|
-
* Warns when render time exceeds the threshold
|
|
89
|
-
*
|
|
90
|
-
* @param src - The island source path
|
|
91
|
-
* @param durationMs - The render duration in milliseconds
|
|
92
|
-
* @param threshold - Optional threshold for slow render warning (default: 100ms)
|
|
93
|
-
*/
|
|
94
|
-
export function logRenderTiming(
|
|
95
|
-
src: string,
|
|
96
|
-
durationMs: number,
|
|
97
|
-
threshold: number = DEFAULT_SLOW_RENDER_THRESHOLD
|
|
98
|
-
): void {
|
|
99
|
-
if (!isDev() || !isVerbose()) return;
|
|
100
|
-
|
|
101
|
-
if (durationMs > threshold) {
|
|
102
|
-
console.warn(`β οΈ Slow island render: ${src} took ${durationMs.toFixed(2)}ms`);
|
|
103
|
-
} else {
|
|
104
|
-
console.log(`ποΈ ${src} rendered in ${durationMs.toFixed(2)}ms`);
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
/**
|
|
109
|
-
* Log a cache hit event (dev mode only)
|
|
110
|
-
*
|
|
111
|
-
* @param cacheType - The type of cache (e.g., 'analysis', 'path', 'framework')
|
|
112
|
-
* @param key - The cache key that was hit
|
|
113
|
-
*/
|
|
114
|
-
export function logCacheHit(cacheType: string, key: string): void {
|
|
115
|
-
if (!isDev() || !isVerbose()) return;
|
|
116
|
-
console.log(`π¦ Cache HIT [${cacheType}]: ${key}`);
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
/**
|
|
120
|
-
* Log a cache miss event (dev mode only)
|
|
121
|
-
*
|
|
122
|
-
* @param cacheType - The type of cache (e.g., 'analysis', 'path', 'framework')
|
|
123
|
-
* @param key - The cache key that was missed
|
|
124
|
-
*/
|
|
125
|
-
export function logCacheMiss(cacheType: string, key: string): void {
|
|
126
|
-
if (!isDev() || !isVerbose()) return;
|
|
127
|
-
console.log(`π Cache MISS [${cacheType}]: ${key}`);
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
// ============================================================================
|
|
131
|
-
// DevLogger Class (for Development Server UI)
|
|
132
|
-
// ============================================================================
|
|
133
|
-
|
|
134
|
-
const AVALON_ASCII = `
|
|
135
|
-
ββββββ βββ βββ ββββββ βββ βββββββ ββββ βββ
|
|
136
|
-
βββββββββββ ββββββββββββββ ββββββββββββββ βββ
|
|
137
|
-
βββββββββββ ββββββββββββββ βββ βββββββββ βββ
|
|
138
|
-
ββββββββββββ βββββββββββββββ βββ βββββββββββββ
|
|
139
|
-
βββ βββ βββββββ βββ βββββββββββββββββββββββ ββββββ
|
|
140
|
-
βββ βββ βββββ βββ βββββββββββ βββββββ βββ βββββ
|
|
141
|
-
`;
|
|
142
|
-
|
|
143
|
-
const COLORS = {
|
|
144
|
-
reset: '\x1b[0m',
|
|
145
|
-
cyan: '\x1b[36m',
|
|
146
|
-
green: '\x1b[32m',
|
|
147
|
-
yellow: '\x1b[33m',
|
|
148
|
-
blue: '\x1b[34m',
|
|
149
|
-
magenta: '\x1b[35m',
|
|
150
|
-
gray: '\x1b[90m',
|
|
151
|
-
bold: '\x1b[1m',
|
|
152
|
-
};
|
|
153
|
-
|
|
154
|
-
const SPINNER_FRAMES = ['β ', 'β ', 'β Ή', 'β Έ', 'β Ό', 'β ΄', 'β ¦', 'β §', 'β ', 'β '];
|
|
155
|
-
|
|
156
|
-
interface DevTask {
|
|
157
|
-
name: string;
|
|
158
|
-
status: 'pending' | 'running' | 'done';
|
|
159
|
-
startTime?: number;
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
export class DevLogger {
|
|
163
|
-
private readonly tasks: Map<string, DevTask> = new Map();
|
|
164
|
-
private spinnerInterval?: ReturnType<typeof setInterval>;
|
|
165
|
-
private currentFrame = 0;
|
|
166
|
-
private readonly startTime = Date.now();
|
|
167
|
-
private readonly originalConsoleLog: typeof console.log;
|
|
168
|
-
private readonly originalConsoleWarn: typeof console.warn;
|
|
169
|
-
private readonly originalConsoleError: typeof console.error;
|
|
170
|
-
private readonly suppressedLogs: string[] = [];
|
|
171
|
-
private readonly headerLines: number = 0;
|
|
172
|
-
|
|
173
|
-
constructor() {
|
|
174
|
-
this.originalConsoleLog = console.log;
|
|
175
|
-
this.originalConsoleWarn = console.warn;
|
|
176
|
-
this.originalConsoleError = console.error;
|
|
177
|
-
|
|
178
|
-
this.suppressConsole();
|
|
179
|
-
|
|
180
|
-
// Clear screen once at start
|
|
181
|
-
process.stdout.write('\x1b[2J\x1b[H');
|
|
182
|
-
|
|
183
|
-
const header = COLORS.cyan + AVALON_ASCII + COLORS.reset + '\n' +
|
|
184
|
-
COLORS.gray + ' Development Server' + COLORS.reset + '\n\n';
|
|
185
|
-
this.headerLines = AVALON_ASCII.split('\n').length + 2;
|
|
186
|
-
|
|
187
|
-
process.stdout.write(header);
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
private suppressConsole() {
|
|
191
|
-
console.log = (...args: unknown[]) => {
|
|
192
|
-
this.suppressedLogs.push(args.map(String).join(' '));
|
|
193
|
-
};
|
|
194
|
-
console.warn = (...args: unknown[]) => {
|
|
195
|
-
this.suppressedLogs.push('[WARN] ' + args.map(String).join(' '));
|
|
196
|
-
};
|
|
197
|
-
console.error = this.originalConsoleError;
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
restoreConsole() {
|
|
201
|
-
console.log = this.originalConsoleLog;
|
|
202
|
-
console.warn = this.originalConsoleWarn;
|
|
203
|
-
console.error = this.originalConsoleError;
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
addTask(id: string, name: string) {
|
|
209
|
-
this.tasks.set(id, { name, status: 'pending' });
|
|
210
|
-
this.render();
|
|
211
|
-
}
|
|
212
|
-
|
|
213
|
-
startTask(id: string) {
|
|
214
|
-
const task = this.tasks.get(id);
|
|
215
|
-
if (task) {
|
|
216
|
-
task.status = 'running';
|
|
217
|
-
task.startTime = Date.now();
|
|
218
|
-
this.render();
|
|
219
|
-
}
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
completeTask(id: string) {
|
|
223
|
-
const task = this.tasks.get(id);
|
|
224
|
-
if (task) {
|
|
225
|
-
task.status = 'done';
|
|
226
|
-
this.render();
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
private render() {
|
|
232
|
-
let currentTask: DevTask | null = null;
|
|
233
|
-
for (const task of this.tasks.values()) {
|
|
234
|
-
if (task.status === 'running') {
|
|
235
|
-
currentTask = task;
|
|
236
|
-
break;
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
// Use carriage return to overwrite the same line
|
|
241
|
-
let output = '\r'; // Return to start of line
|
|
242
|
-
|
|
243
|
-
if (currentTask) {
|
|
244
|
-
const spinner = COLORS.cyan + SPINNER_FRAMES[this.currentFrame] + COLORS.reset;
|
|
245
|
-
output += `${spinner} ${currentTask.name}`;
|
|
246
|
-
} else {
|
|
247
|
-
output += `${COLORS.gray}Initializing...${COLORS.reset}`;
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
// Clear to end of line
|
|
251
|
-
output += '\x1b[K';
|
|
252
|
-
|
|
253
|
-
process.stdout.write(output);
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
startSpinner() {
|
|
257
|
-
this.spinnerInterval = setInterval(() => {
|
|
258
|
-
this.currentFrame = (this.currentFrame + 1) % SPINNER_FRAMES.length;
|
|
259
|
-
this.render();
|
|
260
|
-
}, 100);
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
stopSpinner() {
|
|
264
|
-
if (this.spinnerInterval) {
|
|
265
|
-
clearInterval(this.spinnerInterval);
|
|
266
|
-
}
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
finish(serverUrl: string, viteUrl?: string, hmrUrl?: string) {
|
|
270
|
-
this.stopSpinner();
|
|
271
|
-
|
|
272
|
-
// Clear the status line
|
|
273
|
-
let output = `\x1b[${this.headerLines + 1};0H`;
|
|
274
|
-
output += '\x1b[J'; // Clear from cursor down
|
|
275
|
-
process.stdout.write(output);
|
|
276
|
-
|
|
277
|
-
const elapsed = ((Date.now() - this.startTime) / 1000).toFixed(1);
|
|
278
|
-
|
|
279
|
-
this.originalConsoleLog('');
|
|
280
|
-
this.originalConsoleLog(COLORS.green + COLORS.bold + 'β¨ Server ready!' + COLORS.reset);
|
|
281
|
-
this.originalConsoleLog('');
|
|
282
|
-
this.originalConsoleLog(COLORS.cyan + ' β ' + COLORS.reset + COLORS.bold + 'Local: ' + COLORS.reset + COLORS.cyan + serverUrl + COLORS.reset);
|
|
283
|
-
|
|
284
|
-
if (viteUrl) {
|
|
285
|
-
this.originalConsoleLog(COLORS.cyan + ' β ' + COLORS.reset + COLORS.bold + 'Vite: ' + COLORS.reset + COLORS.gray + viteUrl + COLORS.reset);
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
if (hmrUrl) {
|
|
289
|
-
this.originalConsoleLog(COLORS.cyan + ' β ' + COLORS.reset + COLORS.bold + 'HMR: ' + COLORS.reset + COLORS.gray + hmrUrl + COLORS.reset);
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
this.originalConsoleLog('');
|
|
293
|
-
this.originalConsoleLog(COLORS.gray + ` Ready in ${elapsed}s` + COLORS.reset);
|
|
294
|
-
this.originalConsoleLog('');
|
|
295
|
-
this.originalConsoleLog(COLORS.gray + ' Press Ctrl+C to stop' + COLORS.reset);
|
|
296
|
-
this.originalConsoleLog('');
|
|
297
|
-
|
|
298
|
-
}
|
|
299
|
-
}
|
|
1
|
+
/**
|
|
2
|
+
* Dev-Only Logging Utilities
|
|
3
|
+
*
|
|
4
|
+
* These functions provide environment-aware logging that only outputs in development mode.
|
|
5
|
+
* In production (NODE_ENV=production), all logging is suppressed for better performance.
|
|
6
|
+
*
|
|
7
|
+
* @module dev-logger
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
// ============================================================================
|
|
11
|
+
// Environment Detection
|
|
12
|
+
// ============================================================================
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Check if we're in development mode
|
|
16
|
+
* Returns true if NODE_ENV is not set to "production"
|
|
17
|
+
*/
|
|
18
|
+
export function isDev(): boolean {
|
|
19
|
+
try {
|
|
20
|
+
return process.env.NODE_ENV !== "production";
|
|
21
|
+
} catch {
|
|
22
|
+
return true; // Default to dev mode if we can't check
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Check if verbose logging is enabled
|
|
28
|
+
* Returns true only if AVALON_VERBOSE=1 is set
|
|
29
|
+
*/
|
|
30
|
+
export function isVerbose(): boolean {
|
|
31
|
+
try {
|
|
32
|
+
return process.env.AVALON_VERBOSE === "1";
|
|
33
|
+
} catch {
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// ============================================================================
|
|
39
|
+
// Dev-Only Logging Functions
|
|
40
|
+
// ============================================================================
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Log a message only in development mode AND when AVALON_VERBOSE=1 is set.
|
|
44
|
+
* By default this is a no-op β set AVALON_VERBOSE=1 to enable diagnostic output.
|
|
45
|
+
*
|
|
46
|
+
* @param args - Arguments to pass to console.log
|
|
47
|
+
*/
|
|
48
|
+
export function devLog(...args: unknown[]): void {
|
|
49
|
+
if (isDev() && isVerbose()) {
|
|
50
|
+
console.log(...args);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Log a warning only in development mode
|
|
56
|
+
* In production, this is a no-op for performance
|
|
57
|
+
*
|
|
58
|
+
* @param args - Arguments to pass to console.warn
|
|
59
|
+
*/
|
|
60
|
+
export function devWarn(...args: unknown[]): void {
|
|
61
|
+
if (isDev()) {
|
|
62
|
+
console.warn(...args);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Log an error only in development mode
|
|
68
|
+
* In production, this is a no-op for performance
|
|
69
|
+
*
|
|
70
|
+
* @param args - Arguments to pass to console.error
|
|
71
|
+
*/
|
|
72
|
+
export function devError(...args: unknown[]): void {
|
|
73
|
+
if (isDev()) {
|
|
74
|
+
console.error(...args);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// ============================================================================
|
|
79
|
+
// Performance Tracking
|
|
80
|
+
// ============================================================================
|
|
81
|
+
|
|
82
|
+
/** Default threshold for slow render warnings (in milliseconds) */
|
|
83
|
+
const DEFAULT_SLOW_RENDER_THRESHOLD = 100;
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Log render timing information for an island component
|
|
87
|
+
* Only logs in development mode AND when AVALON_VERBOSE=1 is set
|
|
88
|
+
* Warns when render time exceeds the threshold
|
|
89
|
+
*
|
|
90
|
+
* @param src - The island source path
|
|
91
|
+
* @param durationMs - The render duration in milliseconds
|
|
92
|
+
* @param threshold - Optional threshold for slow render warning (default: 100ms)
|
|
93
|
+
*/
|
|
94
|
+
export function logRenderTiming(
|
|
95
|
+
src: string,
|
|
96
|
+
durationMs: number,
|
|
97
|
+
threshold: number = DEFAULT_SLOW_RENDER_THRESHOLD
|
|
98
|
+
): void {
|
|
99
|
+
if (!isDev() || !isVerbose()) return;
|
|
100
|
+
|
|
101
|
+
if (durationMs > threshold) {
|
|
102
|
+
console.warn(`β οΈ Slow island render: ${src} took ${durationMs.toFixed(2)}ms`);
|
|
103
|
+
} else {
|
|
104
|
+
console.log(`ποΈ ${src} rendered in ${durationMs.toFixed(2)}ms`);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Log a cache hit event (dev mode only)
|
|
110
|
+
*
|
|
111
|
+
* @param cacheType - The type of cache (e.g., 'analysis', 'path', 'framework')
|
|
112
|
+
* @param key - The cache key that was hit
|
|
113
|
+
*/
|
|
114
|
+
export function logCacheHit(cacheType: string, key: string): void {
|
|
115
|
+
if (!isDev() || !isVerbose()) return;
|
|
116
|
+
console.log(`π¦ Cache HIT [${cacheType}]: ${key}`);
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Log a cache miss event (dev mode only)
|
|
121
|
+
*
|
|
122
|
+
* @param cacheType - The type of cache (e.g., 'analysis', 'path', 'framework')
|
|
123
|
+
* @param key - The cache key that was missed
|
|
124
|
+
*/
|
|
125
|
+
export function logCacheMiss(cacheType: string, key: string): void {
|
|
126
|
+
if (!isDev() || !isVerbose()) return;
|
|
127
|
+
console.log(`π Cache MISS [${cacheType}]: ${key}`);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// ============================================================================
|
|
131
|
+
// DevLogger Class (for Development Server UI)
|
|
132
|
+
// ============================================================================
|
|
133
|
+
|
|
134
|
+
const AVALON_ASCII = `
|
|
135
|
+
ββββββ βββ βββ ββββββ βββ βββββββ ββββ βββ
|
|
136
|
+
βββββββββββ ββββββββββββββ ββββββββββββββ βββ
|
|
137
|
+
βββββββββββ ββββββββββββββ βββ βββββββββ βββ
|
|
138
|
+
ββββββββββββ βββββββββββββββ βββ βββββββββββββ
|
|
139
|
+
βββ βββ βββββββ βββ βββββββββββββββββββββββ ββββββ
|
|
140
|
+
βββ βββ βββββ βββ βββββββββββ βββββββ βββ βββββ
|
|
141
|
+
`;
|
|
142
|
+
|
|
143
|
+
const COLORS = {
|
|
144
|
+
reset: '\x1b[0m',
|
|
145
|
+
cyan: '\x1b[36m',
|
|
146
|
+
green: '\x1b[32m',
|
|
147
|
+
yellow: '\x1b[33m',
|
|
148
|
+
blue: '\x1b[34m',
|
|
149
|
+
magenta: '\x1b[35m',
|
|
150
|
+
gray: '\x1b[90m',
|
|
151
|
+
bold: '\x1b[1m',
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
const SPINNER_FRAMES = ['β ', 'β ', 'β Ή', 'β Έ', 'β Ό', 'β ΄', 'β ¦', 'β §', 'β ', 'β '];
|
|
155
|
+
|
|
156
|
+
interface DevTask {
|
|
157
|
+
name: string;
|
|
158
|
+
status: 'pending' | 'running' | 'done';
|
|
159
|
+
startTime?: number;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export class DevLogger {
|
|
163
|
+
private readonly tasks: Map<string, DevTask> = new Map();
|
|
164
|
+
private spinnerInterval?: ReturnType<typeof setInterval>;
|
|
165
|
+
private currentFrame = 0;
|
|
166
|
+
private readonly startTime = Date.now();
|
|
167
|
+
private readonly originalConsoleLog: typeof console.log;
|
|
168
|
+
private readonly originalConsoleWarn: typeof console.warn;
|
|
169
|
+
private readonly originalConsoleError: typeof console.error;
|
|
170
|
+
private readonly suppressedLogs: string[] = [];
|
|
171
|
+
private readonly headerLines: number = 0;
|
|
172
|
+
|
|
173
|
+
constructor() {
|
|
174
|
+
this.originalConsoleLog = console.log;
|
|
175
|
+
this.originalConsoleWarn = console.warn;
|
|
176
|
+
this.originalConsoleError = console.error;
|
|
177
|
+
|
|
178
|
+
this.suppressConsole();
|
|
179
|
+
|
|
180
|
+
// Clear screen once at start
|
|
181
|
+
process.stdout.write('\x1b[2J\x1b[H');
|
|
182
|
+
|
|
183
|
+
const header = COLORS.cyan + AVALON_ASCII + COLORS.reset + '\n' +
|
|
184
|
+
COLORS.gray + ' Development Server' + COLORS.reset + '\n\n';
|
|
185
|
+
this.headerLines = AVALON_ASCII.split('\n').length + 2;
|
|
186
|
+
|
|
187
|
+
process.stdout.write(header);
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
private suppressConsole() {
|
|
191
|
+
console.log = (...args: unknown[]) => {
|
|
192
|
+
this.suppressedLogs.push(args.map(String).join(' '));
|
|
193
|
+
};
|
|
194
|
+
console.warn = (...args: unknown[]) => {
|
|
195
|
+
this.suppressedLogs.push('[WARN] ' + args.map(String).join(' '));
|
|
196
|
+
};
|
|
197
|
+
console.error = this.originalConsoleError;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
restoreConsole() {
|
|
201
|
+
console.log = this.originalConsoleLog;
|
|
202
|
+
console.warn = this.originalConsoleWarn;
|
|
203
|
+
console.error = this.originalConsoleError;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
|
|
208
|
+
addTask(id: string, name: string) {
|
|
209
|
+
this.tasks.set(id, { name, status: 'pending' });
|
|
210
|
+
this.render();
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
startTask(id: string) {
|
|
214
|
+
const task = this.tasks.get(id);
|
|
215
|
+
if (task) {
|
|
216
|
+
task.status = 'running';
|
|
217
|
+
task.startTime = Date.now();
|
|
218
|
+
this.render();
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
completeTask(id: string) {
|
|
223
|
+
const task = this.tasks.get(id);
|
|
224
|
+
if (task) {
|
|
225
|
+
task.status = 'done';
|
|
226
|
+
this.render();
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
private render() {
|
|
232
|
+
let currentTask: DevTask | null = null;
|
|
233
|
+
for (const task of this.tasks.values()) {
|
|
234
|
+
if (task.status === 'running') {
|
|
235
|
+
currentTask = task;
|
|
236
|
+
break;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// Use carriage return to overwrite the same line
|
|
241
|
+
let output = '\r'; // Return to start of line
|
|
242
|
+
|
|
243
|
+
if (currentTask) {
|
|
244
|
+
const spinner = COLORS.cyan + SPINNER_FRAMES[this.currentFrame] + COLORS.reset;
|
|
245
|
+
output += `${spinner} ${currentTask.name}`;
|
|
246
|
+
} else {
|
|
247
|
+
output += `${COLORS.gray}Initializing...${COLORS.reset}`;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
// Clear to end of line
|
|
251
|
+
output += '\x1b[K';
|
|
252
|
+
|
|
253
|
+
process.stdout.write(output);
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
startSpinner() {
|
|
257
|
+
this.spinnerInterval = setInterval(() => {
|
|
258
|
+
this.currentFrame = (this.currentFrame + 1) % SPINNER_FRAMES.length;
|
|
259
|
+
this.render();
|
|
260
|
+
}, 100);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
stopSpinner() {
|
|
264
|
+
if (this.spinnerInterval) {
|
|
265
|
+
clearInterval(this.spinnerInterval);
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
finish(serverUrl: string, viteUrl?: string, hmrUrl?: string) {
|
|
270
|
+
this.stopSpinner();
|
|
271
|
+
|
|
272
|
+
// Clear the status line
|
|
273
|
+
let output = `\x1b[${this.headerLines + 1};0H`;
|
|
274
|
+
output += '\x1b[J'; // Clear from cursor down
|
|
275
|
+
process.stdout.write(output);
|
|
276
|
+
|
|
277
|
+
const elapsed = ((Date.now() - this.startTime) / 1000).toFixed(1);
|
|
278
|
+
|
|
279
|
+
this.originalConsoleLog('');
|
|
280
|
+
this.originalConsoleLog(COLORS.green + COLORS.bold + 'β¨ Server ready!' + COLORS.reset);
|
|
281
|
+
this.originalConsoleLog('');
|
|
282
|
+
this.originalConsoleLog(COLORS.cyan + ' β ' + COLORS.reset + COLORS.bold + 'Local: ' + COLORS.reset + COLORS.cyan + serverUrl + COLORS.reset);
|
|
283
|
+
|
|
284
|
+
if (viteUrl) {
|
|
285
|
+
this.originalConsoleLog(COLORS.cyan + ' β ' + COLORS.reset + COLORS.bold + 'Vite: ' + COLORS.reset + COLORS.gray + viteUrl + COLORS.reset);
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
if (hmrUrl) {
|
|
289
|
+
this.originalConsoleLog(COLORS.cyan + ' β ' + COLORS.reset + COLORS.bold + 'HMR: ' + COLORS.reset + COLORS.gray + hmrUrl + COLORS.reset);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
this.originalConsoleLog('');
|
|
293
|
+
this.originalConsoleLog(COLORS.gray + ` Ready in ${elapsed}s` + COLORS.reset);
|
|
294
|
+
this.originalConsoleLog('');
|
|
295
|
+
this.originalConsoleLog(COLORS.gray + ' Press Ctrl+C to stop' + COLORS.reset);
|
|
296
|
+
this.originalConsoleLog('');
|
|
297
|
+
|
|
298
|
+
}
|
|
299
|
+
}
|