@coherent.js/fastify 1.0.0-beta.3 → 1.0.0-beta.6

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/dist/index.cjs CHANGED
@@ -1,9 +1,7 @@
1
1
  "use strict";
2
- var __create = Object.create;
3
2
  var __defProp = Object.defineProperty;
4
3
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
4
  var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __getProtoOf = Object.getPrototypeOf;
7
5
  var __hasOwnProp = Object.prototype.hasOwnProperty;
8
6
  var __export = (target, all) => {
9
7
  for (var name in all)
@@ -17,14 +15,6 @@ var __copyProps = (to, from, except, desc) => {
17
15
  }
18
16
  return to;
19
17
  };
20
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
- // If the importer is in node compatibility mode or this is not an ESM
22
- // file that has been converted to a CommonJS file using a Babel-
23
- // compatible transform (i.e. "__esModule" has not been set), then set
24
- // "default" to the CommonJS "module.exports" for node compatibility.
25
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
- mod
27
- ));
28
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
19
 
30
20
  // src/coherent-fastify.js
@@ -36,1596 +26,7 @@ __export(coherent_fastify_exports, {
36
26
  setupCoherent: () => setupCoherent
37
27
  });
38
28
  module.exports = __toCommonJS(coherent_fastify_exports);
39
-
40
- // ../core/src/core/object-utils.js
41
- function validateComponent(component, path2 = "root") {
42
- if (component === null || component === void 0) {
43
- throw new Error(`Invalid component at ${path2}: null or undefined`);
44
- }
45
- if (["string", "number", "boolean"].includes(typeof component)) {
46
- return true;
47
- }
48
- if (typeof component === "function") {
49
- return true;
50
- }
51
- if (Array.isArray(component)) {
52
- component.forEach((child, index) => {
53
- validateComponent(child, `${path2}[${index}]`);
54
- });
55
- return true;
56
- }
57
- if (typeof component === "object") {
58
- const keys = Object.keys(component);
59
- if (keys.length === 0) {
60
- throw new Error(`Empty object at ${path2}`);
61
- }
62
- keys.forEach((key) => {
63
- const value = component[key];
64
- if (!/^[a-zA-Z][a-zA-Z0-9-]*$/.test(key) && key !== "text") {
65
- console.warn(`Potentially invalid tag name at ${path2}: ${key}`);
66
- }
67
- if (value && typeof value === "object" && !Array.isArray(value)) {
68
- if (value.children) {
69
- validateComponent(value.children, `${path2}.${key}.children`);
70
- }
71
- } else if (value && typeof value !== "string" && typeof value !== "number" && typeof value !== "function") {
72
- throw new Error(`Invalid value type at ${path2}.${key}: ${typeof value}`);
73
- }
74
- });
75
- return true;
76
- }
77
- throw new Error(`Invalid component type at ${path2}: ${typeof component}`);
78
- }
79
- function isCoherentObject(obj) {
80
- if (!obj || typeof obj !== "object" || Array.isArray(obj)) {
81
- return false;
82
- }
83
- const keys = Object.keys(obj);
84
- if (keys.length === 0) {
85
- return false;
86
- }
87
- return keys.every((key) => {
88
- if (key === "text") return true;
89
- return /^[a-zA-Z][a-zA-Z0-9-]*$/.test(key);
90
- });
91
- }
92
- function extractProps(coherentObj) {
93
- if (!isCoherentObject(coherentObj)) {
94
- return {};
95
- }
96
- const props = {};
97
- const keys = Object.keys(coherentObj);
98
- keys.forEach((tag) => {
99
- const value = coherentObj[tag];
100
- if (value && typeof value === "object" && !Array.isArray(value)) {
101
- props[tag] = { ...value };
102
- } else {
103
- props[tag] = { text: value };
104
- }
105
- });
106
- return props;
107
- }
108
- function hasChildren(component) {
109
- if (Array.isArray(component)) {
110
- return component.length > 0;
111
- }
112
- if (isCoherentObject(component)) {
113
- if (component.children !== void 0 && component.children !== null) {
114
- return Array.isArray(component.children) ? component.children.length > 0 : true;
115
- }
116
- const keys = Object.keys(component);
117
- return keys.some((key) => {
118
- const value = component[key];
119
- return value && typeof value === "object" && value.children;
120
- });
121
- }
122
- return false;
123
- }
124
- function normalizeChildren(children) {
125
- if (children === null || children === void 0) {
126
- return [];
127
- }
128
- if (Array.isArray(children)) {
129
- return children.flat().filter((child) => child !== null && child !== void 0);
130
- }
131
- return [children];
132
- }
133
-
134
- // ../core/src/performance/monitor.js
135
- function createPerformanceMonitor(options = {}) {
136
- const opts = {
137
- enabled: true,
138
- metrics: {
139
- custom: {}
140
- },
141
- sampling: {
142
- enabled: false,
143
- rate: 1,
144
- strategy: "random"
145
- },
146
- reporting: {
147
- enabled: false,
148
- interval: 6e4,
149
- format: "json",
150
- batch: {
151
- enabled: false,
152
- maxSize: 100,
153
- flushInterval: 5e3
154
- },
155
- onReport: null
156
- },
157
- alerts: {
158
- enabled: true,
159
- rules: []
160
- },
161
- resources: {
162
- enabled: false,
163
- track: ["memory"],
164
- interval: 1e3
165
- },
166
- profiling: {
167
- enabled: false,
168
- mode: "production",
169
- flamegraph: false,
170
- tracing: {
171
- enabled: false,
172
- sampleRate: 0.01
173
- }
174
- },
175
- ...options
176
- };
177
- opts.reporting.batch = {
178
- enabled: false,
179
- maxSize: 100,
180
- flushInterval: 5e3,
181
- ...options.reporting?.batch || {}
182
- };
183
- const metrics = {
184
- builtin: {
185
- renderTime: { type: "histogram", unit: "ms", values: [] },
186
- componentCount: { type: "counter", unit: "renders", value: 0 },
187
- errorCount: { type: "counter", unit: "errors", value: 0 },
188
- memoryUsage: { type: "gauge", unit: "MB", values: [] }
189
- },
190
- custom: {}
191
- };
192
- Object.entries(opts.metrics.custom).forEach(([name, config]) => {
193
- metrics.custom[name] = {
194
- type: config.type || "counter",
195
- unit: config.unit || "",
196
- threshold: config.threshold,
197
- values: config.type === "histogram" ? [] : void 0,
198
- value: config.type === "counter" || config.type === "gauge" ? 0 : void 0
199
- };
200
- });
201
- const samplingState = {
202
- count: 0,
203
- sampled: 0,
204
- adaptiveRate: opts.sampling.rate
205
- };
206
- const reportingState = {
207
- batch: [],
208
- lastReport: Date.now(),
209
- reportTimer: null,
210
- flushTimer: null
211
- };
212
- const alertState = {
213
- triggered: /* @__PURE__ */ new Map(),
214
- history: []
215
- };
216
- const resourceState = {
217
- samples: [],
218
- timer: null
219
- };
220
- const profilingState = {
221
- traces: [],
222
- flamegraphData: []
223
- };
224
- const stats = {
225
- metricsRecorded: 0,
226
- sampleRate: opts.sampling.rate,
227
- reportsGenerated: 0,
228
- alertsTriggered: 0
229
- };
230
- function shouldSample() {
231
- if (!opts.sampling.enabled) return true;
232
- samplingState.count++;
233
- if (opts.sampling.strategy === "random") {
234
- return Math.random() < samplingState.adaptiveRate;
235
- } else if (opts.sampling.strategy === "deterministic") {
236
- return samplingState.count % Math.ceil(1 / samplingState.adaptiveRate) === 0;
237
- } else if (opts.sampling.strategy === "adaptive") {
238
- const recentRenderTimes = metrics.builtin.renderTime.values.slice(-10);
239
- if (recentRenderTimes.length > 0) {
240
- const avgTime = recentRenderTimes.reduce((a, b) => a + b, 0) / recentRenderTimes.length;
241
- samplingState.adaptiveRate = avgTime > 16 ? Math.min(1, opts.sampling.rate * 2) : opts.sampling.rate;
242
- }
243
- return Math.random() < samplingState.adaptiveRate;
244
- }
245
- return true;
246
- }
247
- function recordMetric(name, value, metadata = {}) {
248
- if (!opts.enabled) return;
249
- if (!shouldSample()) return;
250
- stats.metricsRecorded++;
251
- const builtinMetric = metrics.builtin[name];
252
- if (builtinMetric) {
253
- if (builtinMetric.type === "histogram") {
254
- builtinMetric.values.push(value);
255
- if (builtinMetric.values.length > 1e3) {
256
- builtinMetric.values = builtinMetric.values.slice(-1e3);
257
- }
258
- } else if (builtinMetric.type === "counter") {
259
- builtinMetric.value += value;
260
- } else if (builtinMetric.type === "gauge") {
261
- builtinMetric.values.push(value);
262
- if (builtinMetric.values.length > 100) {
263
- builtinMetric.values = builtinMetric.values.slice(-100);
264
- }
265
- }
266
- }
267
- const customMetric = metrics.custom[name];
268
- if (customMetric) {
269
- if (customMetric.type === "histogram") {
270
- customMetric.values = customMetric.values || [];
271
- customMetric.values.push(value);
272
- if (customMetric.values.length > 1e3) {
273
- customMetric.values = customMetric.values.slice(-1e3);
274
- }
275
- } else if (customMetric.type === "counter") {
276
- customMetric.value = (customMetric.value || 0) + value;
277
- } else if (customMetric.type === "gauge") {
278
- customMetric.values = customMetric.values || [];
279
- customMetric.values.push(value);
280
- if (customMetric.values.length > 100) {
281
- customMetric.values = customMetric.values.slice(-100);
282
- }
283
- }
284
- if (customMetric.threshold) {
285
- const currentValue = customMetric.type === "histogram" || customMetric.type === "gauge" ? customMetric.values[customMetric.values.length - 1] : customMetric.value;
286
- if (currentValue > customMetric.threshold) {
287
- checkAlerts(name, currentValue);
288
- }
289
- }
290
- }
291
- if (opts.reporting.enabled && opts.reporting.batch.enabled) {
292
- reportingState.batch.push({
293
- metric: name,
294
- value,
295
- metadata,
296
- timestamp: Date.now()
297
- });
298
- if (reportingState.batch.length >= opts.reporting.batch.maxSize) {
299
- flushBatch();
300
- }
301
- }
302
- checkAlerts(name, value);
303
- }
304
- function checkAlerts(metric, value) {
305
- if (!opts.alerts.enabled) return;
306
- opts.alerts.rules.forEach((rule) => {
307
- if (rule.metric !== metric) return;
308
- let triggered = false;
309
- if (rule.condition === "exceeds" && value > rule.threshold) {
310
- triggered = true;
311
- } else if (rule.condition === "below" && value < rule.threshold) {
312
- triggered = true;
313
- } else if (rule.condition === "equals" && value === rule.threshold) {
314
- triggered = true;
315
- }
316
- if (triggered) {
317
- const alertKey = `${rule.metric}-${rule.condition}-${rule.threshold}`;
318
- const lastTriggered = alertState.triggered.get(alertKey);
319
- const now = Date.now();
320
- if (!lastTriggered || now - lastTriggered > 5e3) {
321
- alertState.triggered.set(alertKey, now);
322
- alertState.history.push({
323
- rule,
324
- value,
325
- timestamp: now
326
- });
327
- stats.alertsTriggered++;
328
- if (rule.action) {
329
- rule.action(value, rule);
330
- }
331
- }
332
- }
333
- });
334
- }
335
- function flushBatch() {
336
- if (reportingState.batch.length === 0) return;
337
- const batch = [...reportingState.batch];
338
- reportingState.batch = [];
339
- if (opts.reporting.onReport) {
340
- opts.reporting.onReport({ type: "batch", data: batch });
341
- }
342
- }
343
- function generateReport() {
344
- const report = {
345
- timestamp: Date.now(),
346
- statistics: { ...stats },
347
- metrics: {}
348
- };
349
- Object.entries(metrics.builtin).forEach(([name, metric]) => {
350
- if (metric.type === "histogram") {
351
- report.metrics[name] = {
352
- type: "histogram",
353
- unit: metric.unit,
354
- count: metric.values.length,
355
- min: metric.values.length > 0 ? Math.min(...metric.values) : 0,
356
- max: metric.values.length > 0 ? Math.max(...metric.values) : 0,
357
- avg: metric.values.length > 0 ? metric.values.reduce((a, b) => a + b, 0) / metric.values.length : 0,
358
- p50: percentile(metric.values, 0.5),
359
- p95: percentile(metric.values, 0.95),
360
- p99: percentile(metric.values, 0.99)
361
- };
362
- } else if (metric.type === "counter") {
363
- report.metrics[name] = {
364
- type: "counter",
365
- unit: metric.unit,
366
- value: metric.value
367
- };
368
- } else if (metric.type === "gauge") {
369
- report.metrics[name] = {
370
- type: "gauge",
371
- unit: metric.unit,
372
- current: metric.values.length > 0 ? metric.values[metric.values.length - 1] : 0,
373
- avg: metric.values.length > 0 ? metric.values.reduce((a, b) => a + b, 0) / metric.values.length : 0
374
- };
375
- }
376
- });
377
- Object.entries(metrics.custom).forEach(([name, metric]) => {
378
- if (metric.type === "histogram") {
379
- report.metrics[name] = {
380
- type: "histogram",
381
- unit: metric.unit,
382
- count: metric.values?.length || 0,
383
- min: metric.values?.length > 0 ? Math.min(...metric.values) : 0,
384
- max: metric.values?.length > 0 ? Math.max(...metric.values) : 0,
385
- avg: metric.values?.length > 0 ? metric.values.reduce((a, b) => a + b, 0) / metric.values.length : 0,
386
- p95: percentile(metric.values || [], 0.95),
387
- p99: percentile(metric.values || [], 0.99)
388
- };
389
- } else if (metric.type === "counter") {
390
- report.metrics[name] = {
391
- type: "counter",
392
- unit: metric.unit,
393
- value: metric.value || 0
394
- };
395
- } else if (metric.type === "gauge") {
396
- report.metrics[name] = {
397
- type: "gauge",
398
- unit: metric.unit,
399
- current: metric.values?.length > 0 ? metric.values[metric.values.length - 1] : 0,
400
- avg: metric.values?.length > 0 ? metric.values.reduce((a, b) => a + b, 0) / metric.values.length : 0
401
- };
402
- }
403
- });
404
- report.alerts = {
405
- total: alertState.history.length,
406
- recent: alertState.history.slice(-10)
407
- };
408
- if (opts.resources.enabled) {
409
- report.resources = {
410
- samples: resourceState.samples.slice(-20)
411
- };
412
- }
413
- stats.reportsGenerated++;
414
- if (opts.reporting.onReport) {
415
- opts.reporting.onReport({ type: "report", data: report });
416
- }
417
- return report;
418
- }
419
- function percentile(values, p) {
420
- if (values.length === 0) return 0;
421
- const sorted = [...values].sort((a, b) => a - b);
422
- const index = Math.ceil(sorted.length * p) - 1;
423
- return sorted[Math.max(0, index)];
424
- }
425
- function startResourceMonitoring() {
426
- if (!opts.resources.enabled) return;
427
- const collectResources = () => {
428
- const sample = {
429
- timestamp: Date.now()
430
- };
431
- if (opts.resources.track.includes("memory")) {
432
- if (typeof process !== "undefined" && process.memoryUsage) {
433
- const mem = process.memoryUsage();
434
- sample.memory = {
435
- heapUsed: mem.heapUsed / 1024 / 1024,
436
- heapTotal: mem.heapTotal / 1024 / 1024,
437
- external: mem.external / 1024 / 1024,
438
- rss: mem.rss / 1024 / 1024
439
- };
440
- } else if (typeof performance !== "undefined" && performance.memory) {
441
- sample.memory = {
442
- heapUsed: performance.memory.usedJSHeapSize / 1024 / 1024,
443
- heapTotal: performance.memory.totalJSHeapSize / 1024 / 1024
444
- };
445
- }
446
- }
447
- resourceState.samples.push(sample);
448
- if (resourceState.samples.length > 100) {
449
- resourceState.samples = resourceState.samples.slice(-100);
450
- }
451
- resourceState.timer = setTimeout(collectResources, opts.resources.interval);
452
- };
453
- collectResources();
454
- }
455
- function stopResourceMonitoring() {
456
- if (resourceState.timer) {
457
- clearTimeout(resourceState.timer);
458
- resourceState.timer = null;
459
- }
460
- }
461
- function startReporting() {
462
- if (!opts.reporting.enabled) return;
463
- reportingState.reportTimer = setInterval(() => {
464
- generateReport();
465
- }, opts.reporting.interval);
466
- if (opts.reporting.batch.enabled) {
467
- reportingState.flushTimer = setInterval(() => {
468
- flushBatch();
469
- }, opts.reporting.batch.flushInterval);
470
- }
471
- }
472
- function stopReporting() {
473
- if (reportingState.reportTimer) {
474
- clearInterval(reportingState.reportTimer);
475
- reportingState.reportTimer = null;
476
- }
477
- if (reportingState.flushTimer) {
478
- clearInterval(reportingState.flushTimer);
479
- reportingState.flushTimer = null;
480
- }
481
- flushBatch();
482
- }
483
- function startProfiling() {
484
- if (!opts.profiling.enabled) return;
485
- }
486
- function recordTrace(name, duration, metadata = {}) {
487
- if (!opts.profiling.enabled || !opts.profiling.tracing.enabled) return;
488
- if (Math.random() < opts.profiling.tracing.sampleRate) {
489
- profilingState.traces.push({
490
- name,
491
- duration,
492
- metadata,
493
- timestamp: Date.now()
494
- });
495
- if (profilingState.traces.length > 1e3) {
496
- profilingState.traces = profilingState.traces.slice(-1e3);
497
- }
498
- }
499
- }
500
- function measure(name, fn, metadata = {}) {
501
- if (!opts.enabled) return fn();
502
- const start = performance.now();
503
- try {
504
- const result = fn();
505
- const duration = performance.now() - start;
506
- recordMetric("renderTime", duration, { name, ...metadata });
507
- recordTrace(name, duration, metadata);
508
- return result;
509
- } catch (error) {
510
- recordMetric("errorCount", 1, { name, error: error.message });
511
- throw error;
512
- }
513
- }
514
- async function measureAsync(name, fn, metadata = {}) {
515
- if (!opts.enabled) return fn();
516
- const start = performance.now();
517
- try {
518
- const result = await fn();
519
- const duration = performance.now() - start;
520
- recordMetric("renderTime", duration, { name, ...metadata });
521
- recordTrace(name, duration, metadata);
522
- return result;
523
- } catch (error) {
524
- recordMetric("errorCount", 1, { name, error: error.message });
525
- throw error;
526
- }
527
- }
528
- function addMetric(name, config) {
529
- metrics.custom[name] = {
530
- type: config.type || "counter",
531
- unit: config.unit || "",
532
- threshold: config.threshold,
533
- values: config.type === "histogram" ? [] : void 0,
534
- value: config.type === "counter" || config.type === "gauge" ? 0 : void 0
535
- };
536
- }
537
- function addAlertRule(rule) {
538
- opts.alerts.rules.push(rule);
539
- }
540
- function getStats() {
541
- return {
542
- ...stats,
543
- sampleRate: samplingState.adaptiveRate,
544
- batchSize: reportingState.batch.length,
545
- resourceSamples: resourceState.samples.length,
546
- traces: profilingState.traces.length,
547
- alerts: {
548
- total: alertState.history.length,
549
- unique: alertState.triggered.size
550
- }
551
- };
552
- }
553
- function reset() {
554
- Object.values(metrics.builtin).forEach((metric) => {
555
- if (metric.type === "histogram" || metric.type === "gauge") {
556
- metric.values = [];
557
- } else if (metric.type === "counter") {
558
- metric.value = 0;
559
- }
560
- });
561
- Object.values(metrics.custom).forEach((metric) => {
562
- if (metric.type === "histogram" || metric.type === "gauge") {
563
- metric.values = [];
564
- } else if (metric.type === "counter") {
565
- metric.value = 0;
566
- }
567
- });
568
- samplingState.count = 0;
569
- samplingState.sampled = 0;
570
- reportingState.batch = [];
571
- alertState.history = [];
572
- alertState.triggered.clear();
573
- resourceState.samples = [];
574
- profilingState.traces = [];
575
- stats.metricsRecorded = 0;
576
- stats.reportsGenerated = 0;
577
- stats.alertsTriggered = 0;
578
- }
579
- if (opts.enabled) {
580
- startResourceMonitoring();
581
- startReporting();
582
- startProfiling();
583
- }
584
- return {
585
- recordMetric,
586
- measure,
587
- measureAsync,
588
- addMetric,
589
- addAlertRule,
590
- generateReport,
591
- getStats,
592
- reset,
593
- start() {
594
- opts.enabled = true;
595
- startResourceMonitoring();
596
- startReporting();
597
- startProfiling();
598
- },
599
- stop() {
600
- opts.enabled = false;
601
- stopResourceMonitoring();
602
- stopReporting();
603
- return generateReport();
604
- }
605
- };
606
- }
607
- var performanceMonitor = createPerformanceMonitor();
608
-
609
- // ../core/src/rendering/base-renderer.js
610
- var DEFAULT_RENDERER_CONFIG = {
611
- // Core rendering options
612
- maxDepth: 100,
613
- enableValidation: true,
614
- enableMonitoring: false,
615
- validateInput: true,
616
- // HTML Renderer specific options
617
- enableCache: true,
618
- minify: false,
619
- cacheSize: 1e3,
620
- cacheTTL: 3e5,
621
- // 5 minutes
622
- // Streaming Renderer specific options
623
- chunkSize: 1024,
624
- // Size of each chunk in bytes
625
- bufferSize: 4096,
626
- // Internal buffer size
627
- enableMetrics: false,
628
- // Track streaming metrics
629
- yieldThreshold: 100,
630
- // Yield control after N elements
631
- encoding: "utf8",
632
- // Output encoding
633
- // DOM Renderer specific options
634
- enableHydration: true,
635
- // Enable hydration support
636
- namespace: null,
637
- // SVG namespace support
638
- // Performance options
639
- enablePerformanceTracking: false,
640
- performanceThreshold: 10,
641
- // ms threshold for slow renders
642
- // Development options
643
- enableDevWarnings: typeof process !== "undefined" && process.env && true,
644
- enableDebugLogging: false,
645
- // Error handling options
646
- errorFallback: "",
647
- // Fallback content on errors
648
- throwOnError: true
649
- // Whether to throw or return fallback
650
- };
651
- var BaseRenderer = class {
652
- constructor(options = {}) {
653
- this.config = this.validateAndMergeConfig(options);
654
- this.metrics = {
655
- startTime: null,
656
- endTime: null,
657
- elementsProcessed: 0
658
- };
659
- }
660
- /**
661
- * Validate and merge configuration options
662
- */
663
- validateAndMergeConfig(options) {
664
- const config = { ...DEFAULT_RENDERER_CONFIG, ...options };
665
- if (typeof config.maxDepth !== "number") {
666
- throw new Error("maxDepth must be a number");
667
- }
668
- if (config.maxDepth <= 0) {
669
- throw new Error("maxDepth must be a positive number");
670
- }
671
- if (typeof config.chunkSize !== "number") {
672
- throw new Error("chunkSize must be a number");
673
- }
674
- if (config.chunkSize <= 0) {
675
- throw new Error("chunkSize must be a positive number");
676
- }
677
- if (typeof config.yieldThreshold !== "number") {
678
- throw new Error("yieldThreshold must be a number");
679
- }
680
- if (config.yieldThreshold <= 0) {
681
- throw new Error("yieldThreshold must be a positive number");
682
- }
683
- if (config.enableDevWarnings) {
684
- if (config.maxDepth > 1e3) {
685
- console.warn("Coherent.js: maxDepth > 1000 may cause performance issues");
686
- }
687
- if (config.chunkSize > 16384) {
688
- console.warn("Coherent.js: Large chunkSize may increase memory usage");
689
- }
690
- }
691
- return config;
692
- }
693
- /**
694
- * Get configuration for specific renderer type
695
- */
696
- getRendererConfig(rendererType) {
697
- const baseConfig = { ...this.config };
698
- switch (rendererType) {
699
- case "html":
700
- return {
701
- ...baseConfig,
702
- // HTML-specific defaults
703
- enableCache: baseConfig.enableCache !== false,
704
- enableMonitoring: baseConfig.enableMonitoring !== false
705
- };
706
- case "streaming":
707
- return {
708
- ...baseConfig,
709
- // Streaming-specific defaults
710
- enableMetrics: baseConfig.enableMetrics ?? false,
711
- maxDepth: baseConfig.maxDepth ?? 1e3
712
- // Higher default for streaming
713
- };
714
- case "dom":
715
- return {
716
- ...baseConfig,
717
- // DOM-specific defaults
718
- enableHydration: baseConfig.enableHydration !== false
719
- };
720
- default:
721
- return baseConfig;
722
- }
723
- }
724
- /**
725
- * Validate component structure
726
- */
727
- validateComponent(component) {
728
- if (this.config.validateInput !== false) {
729
- return validateComponent(component);
730
- }
731
- return true;
732
- }
733
- /**
734
- * Check if component is valid for rendering
735
- */
736
- isValidComponent(component) {
737
- if (component === null || component === void 0) return true;
738
- if (typeof component === "string" || typeof component === "number") return true;
739
- if (typeof component === "function") return true;
740
- if (Array.isArray(component)) return component.every((child) => this.isValidComponent(child));
741
- if (isCoherentObject(component)) return true;
742
- return false;
743
- }
744
- /**
745
- * Validate rendering depth to prevent stack overflow
746
- */
747
- validateDepth(depth) {
748
- if (depth > this.config.maxDepth) {
749
- throw new Error(`Maximum render depth (${this.config.maxDepth}) exceeded`);
750
- }
751
- }
752
- /**
753
- * Handle different component types with consistent logic
754
- */
755
- processComponentType(component) {
756
- if (component === null || component === void 0) {
757
- return { type: "empty", value: "" };
758
- }
759
- if (typeof component === "string") {
760
- return { type: "text", value: component };
761
- }
762
- if (typeof component === "number" || typeof component === "boolean") {
763
- return { type: "text", value: String(component) };
764
- }
765
- if (typeof component === "function") {
766
- return { type: "function", value: component };
767
- }
768
- if (Array.isArray(component)) {
769
- return { type: "array", value: component };
770
- }
771
- if (isCoherentObject(component)) {
772
- return { type: "element", value: component };
773
- }
774
- return { type: "unknown", value: component };
775
- }
776
- /**
777
- * Execute function components with _error handling
778
- */
779
- executeFunctionComponent(func, depth = 0) {
780
- try {
781
- const isContextProvider = func.length > 0 || func.isContextProvider;
782
- let result;
783
- if (isContextProvider) {
784
- result = func((children) => {
785
- return this.renderComponent(children, this.config, depth + 1);
786
- });
787
- } else {
788
- result = func();
789
- }
790
- if (typeof result === "function") {
791
- return this.executeFunctionComponent(result, depth);
792
- }
793
- return result;
794
- } catch (_error) {
795
- if (this.config.enableMonitoring) {
796
- performanceMonitor.recordError("functionComponent", _error);
797
- }
798
- if (typeof process !== "undefined" && process.env && true) {
799
- console.warn("Coherent.js Function Component Error:", _error.message);
800
- }
801
- return null;
802
- }
803
- }
804
- /**
805
- * Process element children consistently
806
- */
807
- processChildren(children, options, depth) {
808
- if (!hasChildren({ children })) {
809
- return [];
810
- }
811
- const normalizedChildren = normalizeChildren(children);
812
- return normalizedChildren.map(
813
- (child) => this.renderComponent(child, options, depth + 1)
814
- );
815
- }
816
- /**
817
- * Extract and process element attributes
818
- */
819
- extractElementAttributes(props) {
820
- if (!props || typeof props !== "object") return {};
821
- const attributes = { ...props };
822
- delete attributes.children;
823
- delete attributes.text;
824
- return attributes;
825
- }
826
- /**
827
- * Record performance metrics
828
- */
829
- recordPerformance(operation, startTime, fromCache = false, metadata = {}) {
830
- if (this.config.enableMonitoring) {
831
- performanceMonitor.recordRender(
832
- operation,
833
- this.getCurrentTime() - startTime,
834
- fromCache,
835
- metadata
836
- );
837
- }
838
- }
839
- /**
840
- * Record _error for monitoring
841
- */
842
- recordError(operation, _error, metadata = {}) {
843
- if (this.config.enableMonitoring) {
844
- performanceMonitor.recordError(operation, _error, metadata);
845
- }
846
- }
847
- /**
848
- * Get current timestamp with fallback
849
- */
850
- getCurrentTime() {
851
- if (typeof performance !== "undefined" && performance.now) {
852
- return performance.now();
853
- }
854
- return Date.now();
855
- }
856
- /**
857
- * Start performance timing
858
- */
859
- startTiming() {
860
- this.metrics.startTime = this.getCurrentTime();
861
- }
862
- /**
863
- * End performance timing
864
- */
865
- endTiming() {
866
- this.metrics.endTime = this.getCurrentTime();
867
- }
868
- /**
869
- * Get performance metrics
870
- */
871
- getMetrics() {
872
- const duration = this.metrics.endTime ? this.metrics.endTime - this.metrics.startTime : this.getCurrentTime() - this.metrics.startTime;
873
- return {
874
- ...this.metrics,
875
- duration,
876
- elementsPerSecond: this.metrics.elementsProcessed / (duration / 1e3)
877
- };
878
- }
879
- /**
880
- * Reset metrics for new render
881
- */
882
- resetMetrics() {
883
- this.metrics = {
884
- startTime: null,
885
- endTime: null,
886
- elementsProcessed: 0
887
- };
888
- }
889
- /**
890
- * Abstract method - must be implemented by subclasses
891
- */
892
- renderComponent() {
893
- throw new Error("renderComponent must be implemented by subclass");
894
- }
895
- /**
896
- * Abstract method - must be implemented by subclasses
897
- */
898
- render() {
899
- throw new Error("render must be implemented by subclass");
900
- }
901
- };
902
- var RendererUtils = {
903
- /**
904
- * Check if element is static (no functions)
905
- */
906
- isStaticElement(element) {
907
- if (!element || typeof element !== "object") {
908
- return typeof element === "string" || typeof element === "number";
909
- }
910
- for (const [key, value] of Object.entries(element)) {
911
- if (typeof value === "function") return false;
912
- if (key === "children" && Array.isArray(value)) {
913
- return value.every((child) => RendererUtils.isStaticElement(child));
914
- }
915
- if (key === "children" && typeof value === "object" && value !== null) {
916
- return RendererUtils.isStaticElement(value);
917
- }
918
- }
919
- return true;
920
- },
921
- /**
922
- * Check if object has functions (for caching decisions)
923
- */
924
- hasFunctions(obj, visited = /* @__PURE__ */ new WeakSet()) {
925
- if (visited.has(obj)) return false;
926
- visited.add(obj);
927
- for (const value of Object.values(obj)) {
928
- if (typeof value === "function") return true;
929
- if (typeof value === "object" && value !== null && RendererUtils.hasFunctions(value, visited)) {
930
- return true;
931
- }
932
- }
933
- return false;
934
- },
935
- /**
936
- * Get element complexity score
937
- */
938
- getElementComplexity(element) {
939
- if (!element || typeof element !== "object") return 1;
940
- let complexity = Object.keys(element).length;
941
- if (element.children && Array.isArray(element.children)) {
942
- complexity += element.children.reduce(
943
- (sum, child) => sum + RendererUtils.getElementComplexity(child),
944
- 0
945
- );
946
- }
947
- return complexity;
948
- },
949
- /**
950
- * Generate cache key for element
951
- */
952
- generateCacheKey(tagName, element) {
953
- try {
954
- const keyData = {
955
- tag: tagName,
956
- props: extractProps(element),
957
- hasChildren: hasChildren(element),
958
- childrenType: Array.isArray(element.children) ? "array" : typeof element.children
959
- };
960
- return `element:${JSON.stringify(keyData)}`;
961
- } catch (_error) {
962
- if (typeof process !== "undefined" && process.env && true) {
963
- console.warn("Failed to generate cache key:", _error);
964
- }
965
- return null;
966
- }
967
- },
968
- /**
969
- * Check if element is cacheable
970
- */
971
- isCacheable(element, options) {
972
- if (!options.enableCache) return false;
973
- if (RendererUtils.hasFunctions(element)) return false;
974
- if (RendererUtils.getElementComplexity(element) > 1e3) return false;
975
- const cacheKey = RendererUtils.generateCacheKey(element.tagName || "unknown", element);
976
- if (!cacheKey) return false;
977
- return true;
978
- }
979
- };
980
-
981
- // ../core/src/core/html-utils.js
982
- function escapeHtml(text) {
983
- if (typeof text !== "string") return text;
984
- return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
985
- }
986
- function isVoidElement(tagName) {
987
- if (typeof tagName !== "string") {
988
- return false;
989
- }
990
- const voidElements = /* @__PURE__ */ new Set([
991
- "area",
992
- "base",
993
- "br",
994
- "col",
995
- "embed",
996
- "hr",
997
- "img",
998
- "input",
999
- "link",
1000
- "meta",
1001
- "param",
1002
- "source",
1003
- "track",
1004
- "wbr"
1005
- ]);
1006
- return voidElements.has(tagName.toLowerCase());
1007
- }
1008
- function formatAttributes(props) {
1009
- let formatted = "";
1010
- for (const key in props) {
1011
- if (props.hasOwnProperty(key)) {
1012
- let value = props[key];
1013
- const attributeName = key === "className" ? "class" : key;
1014
- if (typeof value === "function") {
1015
- if (attributeName.startsWith("on")) {
1016
- const actionId = `__coherent_action_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
1017
- const DEBUG = typeof process !== "undefined" && process && process.env && (process.env.COHERENT_DEBUG === "1" || true) || typeof window !== "undefined" && window && window.COHERENT_DEBUG === true;
1018
- if (typeof global !== "undefined") {
1019
- if (!global.__coherentActionRegistry) {
1020
- global.__coherentActionRegistry = {};
1021
- if (DEBUG) console.log("Initialized global action registry");
1022
- }
1023
- global.__coherentActionRegistry[actionId] = value;
1024
- if (DEBUG) console.log(`Added action ${actionId} to global registry, total: ${Object.keys(global.__coherentActionRegistry).length}`);
1025
- if (DEBUG) console.log(`Global registry keys: ${Object.keys(global.__coherentActionRegistry).join(", ")}`);
1026
- if (DEBUG) {
1027
- if (typeof global.__coherentActionRegistryLog === "undefined") {
1028
- global.__coherentActionRegistryLog = [];
1029
- }
1030
- global.__coherentActionRegistryLog.push({
1031
- action: "add",
1032
- actionId,
1033
- timestamp: Date.now(),
1034
- registrySize: Object.keys(global.__coherentActionRegistry).length
1035
- });
1036
- }
1037
- } else if (typeof window !== "undefined") {
1038
- if (!window.__coherentActionRegistry) {
1039
- window.__coherentActionRegistry = {};
1040
- if (DEBUG) console.log("Initialized window action registry");
1041
- }
1042
- window.__coherentActionRegistry[actionId] = value;
1043
- if (DEBUG) console.log(`Added action ${actionId} to window registry, total: ${Object.keys(window.__coherentActionRegistry).length}`);
1044
- if (DEBUG) console.log(`Window registry keys: ${Object.keys(window.__coherentActionRegistry).join(", ")}`);
1045
- }
1046
- const eventType = attributeName.substring(2);
1047
- formatted += ` data-action="${actionId}" data-event="${eventType}"`;
1048
- continue;
1049
- } else {
1050
- try {
1051
- value = value();
1052
- } catch (_error) {
1053
- console.warn(`Error executing function for attribute '${key}':`, {
1054
- _error: _error.message,
1055
- stack: _error.stack,
1056
- attributeKey: key
1057
- });
1058
- value = "";
1059
- }
1060
- }
1061
- }
1062
- if (value === true) {
1063
- formatted += ` ${attributeName}`;
1064
- } else if (value !== false && value !== null && value !== void 0) {
1065
- formatted += ` ${attributeName}="${escapeHtml(String(value))}"`;
1066
- }
1067
- }
1068
- }
1069
- return formatted.trim();
1070
- }
1071
- function minifyHtml(html, options = {}) {
1072
- if (!options.minify) return html;
1073
- return html.replace(/<!--[\s\S]*?-->/g, "").replace(/\s+/g, " ").replace(/>\s+</g, "><").trim();
1074
- }
1075
-
1076
- // ../core/src/performance/cache-manager.js
1077
- function createCacheManager(options = {}) {
1078
- const {
1079
- maxCacheSize = 1e3,
1080
- maxMemoryMB = 100,
1081
- ttlMs = 1e3 * 60 * 5,
1082
- // 5 minutes
1083
- enableStatistics = true
1084
- } = options;
1085
- const caches = {
1086
- static: /* @__PURE__ */ new Map(),
1087
- // Never-changing components
1088
- component: /* @__PURE__ */ new Map(),
1089
- // Component results with deps
1090
- template: /* @__PURE__ */ new Map(),
1091
- // Template strings
1092
- data: /* @__PURE__ */ new Map()
1093
- // General purpose data
1094
- };
1095
- let memoryUsage = 0;
1096
- const stats = {
1097
- hits: 0,
1098
- misses: 0,
1099
- hitRate: {
1100
- static: 0,
1101
- component: 0,
1102
- template: 0,
1103
- data: 0
1104
- },
1105
- accessCount: {
1106
- static: 0,
1107
- component: 0,
1108
- template: 0,
1109
- data: 0
1110
- }
1111
- };
1112
- let cleanupInterval;
1113
- if (typeof setInterval === "function") {
1114
- cleanupInterval = setInterval(() => cleanup(), 3e4);
1115
- if (cleanupInterval.unref) {
1116
- cleanupInterval.unref();
1117
- }
1118
- }
1119
- function generateCacheKey(component, props = {}, context = {}) {
1120
- const componentStr = typeof component === "function" ? component.name || component.toString() : JSON.stringify(component);
1121
- const propsStr = JSON.stringify(props, Object.keys(props).sort());
1122
- const contextStr = JSON.stringify(context);
1123
- const hash = simpleHash(componentStr + propsStr + contextStr);
1124
- return `${extractComponentName(component)}_${hash}`;
1125
- }
1126
- function get(key, type = "component") {
1127
- const cache = caches[type] || caches.component;
1128
- const entry = cache.get(key);
1129
- if (!entry) {
1130
- stats.misses++;
1131
- if (enableStatistics) stats.accessCount[type]++;
1132
- return null;
1133
- }
1134
- if (Date.now() - entry.timestamp > ttlMs) {
1135
- cache.delete(key);
1136
- updateMemoryUsage(-entry.size);
1137
- stats.misses++;
1138
- if (enableStatistics) stats.accessCount[type]++;
1139
- return null;
1140
- }
1141
- entry.lastAccess = Date.now();
1142
- entry.accessCount++;
1143
- stats.hits++;
1144
- if (enableStatistics) {
1145
- stats.accessCount[type]++;
1146
- stats.hitRate[type] = stats.hits / (stats.hits + stats.misses) * 100;
1147
- }
1148
- return entry.value;
1149
- }
1150
- function set(key, value, type = "component", metadata = {}) {
1151
- const cache = caches[type] || caches.component;
1152
- const size = calculateSize(value);
1153
- if (memoryUsage + size > maxMemoryMB * 1024 * 1024) {
1154
- optimize(type, size);
1155
- }
1156
- const entry = {
1157
- value,
1158
- timestamp: Date.now(),
1159
- lastAccess: Date.now(),
1160
- size,
1161
- metadata,
1162
- accessCount: 0
1163
- };
1164
- const existing = cache.get(key);
1165
- if (existing) {
1166
- updateMemoryUsage(-existing.size);
1167
- }
1168
- cache.set(key, entry);
1169
- updateMemoryUsage(size);
1170
- if (cache.size > maxCacheSize) {
1171
- optimize(type);
1172
- }
1173
- }
1174
- function remove(key, type) {
1175
- if (type) {
1176
- const cache = caches[type];
1177
- if (!cache) return false;
1178
- const entry = cache.get(key);
1179
- if (entry) {
1180
- updateMemoryUsage(-entry.size);
1181
- return cache.delete(key);
1182
- }
1183
- return false;
1184
- }
1185
- for (const [, cache] of Object.entries(caches)) {
1186
- const entry = cache.get(key);
1187
- if (entry) {
1188
- updateMemoryUsage(-entry.size);
1189
- return cache.delete(key);
1190
- }
1191
- }
1192
- return false;
1193
- }
1194
- function clear(type) {
1195
- if (type) {
1196
- const cache = caches[type];
1197
- if (cache) {
1198
- cache.clear();
1199
- }
1200
- } else {
1201
- Object.values(caches).forEach((cache) => cache.clear());
1202
- }
1203
- memoryUsage = 0;
1204
- }
1205
- function getStats() {
1206
- const entries = Object.values(caches).reduce((sum, cache) => sum + cache.size, 0);
1207
- return {
1208
- hits: stats.hits,
1209
- misses: stats.misses,
1210
- size: memoryUsage,
1211
- entries,
1212
- hitRate: stats.hitRate,
1213
- accessCount: stats.accessCount
1214
- };
1215
- }
1216
- function cleanup() {
1217
- const now = Date.now();
1218
- let freed = 0;
1219
- for (const [, cache] of Object.entries(caches)) {
1220
- for (const [key, entry] of cache.entries()) {
1221
- if (now - entry.timestamp > ttlMs) {
1222
- cache.delete(key);
1223
- updateMemoryUsage(-entry.size);
1224
- freed++;
1225
- }
1226
- }
1227
- }
1228
- return { freed };
1229
- }
1230
- function calculateSize(value) {
1231
- if (value === null || value === void 0) return 0;
1232
- if (typeof value === "string") return value.length * 2;
1233
- if (typeof value === "number") return 8;
1234
- if (typeof value === "boolean") return 4;
1235
- if (Array.isArray(value)) {
1236
- return value.reduce((sum, item) => sum + calculateSize(item), 0);
1237
- }
1238
- if (typeof value === "object") {
1239
- return Object.values(value).reduce((sum, val) => sum + calculateSize(val), 0);
1240
- }
1241
- return 0;
1242
- }
1243
- function updateMemoryUsage(delta) {
1244
- memoryUsage = Math.max(0, memoryUsage + delta);
1245
- }
1246
- function optimize(type, requiredSpace = 0) {
1247
- const cache = caches[type] || caches.component;
1248
- const entries = Array.from(cache.entries()).sort(([, a], [, b]) => a.lastAccess - b.lastAccess);
1249
- let freed = 0;
1250
- for (const [key, entry] of entries) {
1251
- if (freed >= requiredSpace) break;
1252
- cache.delete(key);
1253
- updateMemoryUsage(-entry.size);
1254
- freed += entry.size;
1255
- }
1256
- return { freed };
1257
- }
1258
- function simpleHash(str) {
1259
- let hash = 0;
1260
- for (let i = 0; i < str.length; i++) {
1261
- const char = str.charCodeAt(i);
1262
- hash = (hash << 5) - hash + char;
1263
- hash = hash & hash;
1264
- }
1265
- return Math.abs(hash).toString(36);
1266
- }
1267
- function extractComponentName(component) {
1268
- if (typeof component === "function") {
1269
- return component.name || "AnonymousComponent";
1270
- }
1271
- if (component && typeof component === "object") {
1272
- const keys = Object.keys(component);
1273
- return keys.length > 0 ? keys[0] : "ObjectComponent";
1274
- }
1275
- return "UnknownComponent";
1276
- }
1277
- function destroy() {
1278
- if (cleanupInterval) {
1279
- clearInterval(cleanupInterval);
1280
- }
1281
- clear();
1282
- }
1283
- return {
1284
- get,
1285
- set,
1286
- remove,
1287
- clear,
1288
- getStats,
1289
- cleanup,
1290
- destroy,
1291
- generateCacheKey,
1292
- get memoryUsage() {
1293
- return memoryUsage;
1294
- },
1295
- get maxMemory() {
1296
- return maxMemoryMB * 1024 * 1024;
1297
- }
1298
- };
1299
- }
1300
- var cacheManager = createCacheManager();
1301
-
1302
- // ../core/src/rendering/css-manager.js
1303
- var import_promises = __toESM(require("node:fs/promises"), 1);
1304
- var import_node_path = __toESM(require("node:path"), 1);
1305
- var CSSManager = class {
1306
- constructor(options = {}) {
1307
- this.options = {
1308
- basePath: process.cwd(),
1309
- minify: false,
1310
- cache: true,
1311
- autoprefixer: false,
1312
- ...options
1313
- };
1314
- this.cache = /* @__PURE__ */ new Map();
1315
- this.loadedFiles = /* @__PURE__ */ new Set();
1316
- }
1317
- /**
1318
- * Load CSS file content
1319
- */
1320
- async loadCSSFile(filePath) {
1321
- const fullPath = import_node_path.default.resolve(this.options.basePath, filePath);
1322
- const cacheKey = fullPath;
1323
- if (this.options.cache && this.cache.has(cacheKey)) {
1324
- return this.cache.get(cacheKey);
1325
- }
1326
- try {
1327
- let content = await import_promises.default.readFile(fullPath, "utf8");
1328
- if (this.options.minify) {
1329
- content = this.minifyCSS(content);
1330
- }
1331
- if (this.options.cache) {
1332
- this.cache.set(cacheKey, content);
1333
- }
1334
- this.loadedFiles.add(filePath);
1335
- return content;
1336
- } catch (_error) {
1337
- console.warn(`Failed to load CSS file: ${filePath}`, _error.message);
1338
- return "";
1339
- }
1340
- }
1341
- /**
1342
- * Load multiple CSS files
1343
- */
1344
- async loadCSSFiles(filePaths) {
1345
- if (!Array.isArray(filePaths)) {
1346
- filePaths = [filePaths];
1347
- }
1348
- const cssContents = await Promise.all(
1349
- filePaths.map((filePath) => this.loadCSSFile(filePath))
1350
- );
1351
- return cssContents.join("\n");
1352
- }
1353
- /**
1354
- * Generate CSS link tags for external files
1355
- */
1356
- generateCSSLinks(filePaths, baseUrl = "/") {
1357
- if (!Array.isArray(filePaths)) {
1358
- filePaths = [filePaths];
1359
- }
1360
- return filePaths.map((filePath) => {
1361
- const href = filePath.startsWith("http") ? filePath : `${baseUrl}${filePath}`.replace(/\/+/g, "/");
1362
- return `<link rel="stylesheet" href="${this.escapeHtml(href)}" />`;
1363
- }).join("\n");
1364
- }
1365
- /**
1366
- * Generate inline style tag with CSS content
1367
- */
1368
- generateInlineStyles(cssContent) {
1369
- if (!cssContent) return "";
1370
- return `<style type="text/css">
1371
- ${cssContent}
1372
- </style>`;
1373
- }
1374
- /**
1375
- * Basic CSS minification
1376
- */
1377
- minifyCSS(css) {
1378
- return css.replace(/\/\*[\s\S]*?\*\//g, "").replace(/\s+/g, " ").replace(/;\s*}/g, "}").replace(/{\s+/g, "{").replace(/;\s+/g, ";").trim();
1379
- }
1380
- /**
1381
- * Escape HTML entities
1382
- */
1383
- escapeHtml(text) {
1384
- const div = { textContent: text };
1385
- return div.innerHTML || text;
1386
- }
1387
- /**
1388
- * Clear cache
1389
- */
1390
- clearCache() {
1391
- this.cache.clear();
1392
- this.loadedFiles.clear();
1393
- }
1394
- /**
1395
- * Get loaded file list
1396
- */
1397
- getLoadedFiles() {
1398
- return Array.from(this.loadedFiles);
1399
- }
1400
- };
1401
- var defaultCSSManager = new CSSManager();
1402
-
1403
- // ../core/src/rendering/html-renderer.js
1404
- var rendererCache = createCacheManager({
1405
- maxSize: 1e3,
1406
- ttlMs: 3e5
1407
- // 5 minutes
1408
- });
1409
- var HTMLRenderer = class extends BaseRenderer {
1410
- constructor(options = {}) {
1411
- super({
1412
- enableCache: options.enableCache !== false,
1413
- enableMonitoring: options.enableMonitoring !== false,
1414
- minify: options.minify || false,
1415
- streaming: options.streaming || false,
1416
- maxDepth: options.maxDepth || 100,
1417
- ...options
1418
- });
1419
- if (this.config.enableCache && !this.cache) {
1420
- this.cache = rendererCache;
1421
- }
1422
- }
1423
- /**
1424
- * Main render method - converts components to HTML string
1425
- *
1426
- * @param {Object|Array|string|Function} component - Component to render
1427
- * @param {Object} [options={}] - Rendering options
1428
- * @param {Object} [options.context] - Rendering context
1429
- * @param {boolean} [options.enableCache] - Override cache setting
1430
- * @param {number} [options.depth=0] - Current rendering depth
1431
- * @returns {string} Rendered HTML string
1432
- *
1433
- * @example
1434
- * const html = renderer.render({
1435
- * div: {
1436
- * className: 'container',
1437
- * children: [
1438
- * { h1: { text: 'Title' } },
1439
- * { p: { text: 'Content' } }
1440
- * ]
1441
- * }
1442
- * });
1443
- */
1444
- render(component, options = {}) {
1445
- const config = { ...this.config, ...options };
1446
- this.startTiming();
1447
- try {
1448
- if (config.validateInput && !this.isValidComponent(component)) {
1449
- throw new Error("Invalid component structure");
1450
- }
1451
- const html = this.renderComponent(component, config, 0);
1452
- const finalHtml = config.minify ? minifyHtml(html, config) : html;
1453
- this.endTiming();
1454
- this.recordPerformance("render", this.metrics.startTime, false, {
1455
- cacheEnabled: config.enableCache
1456
- });
1457
- return finalHtml;
1458
- } catch (_error) {
1459
- this.recordError("render", _error);
1460
- throw _error;
1461
- }
1462
- }
1463
- /**
1464
- * Render a single component with full optimization pipeline
1465
- */
1466
- renderComponent(component, options, depth = 0) {
1467
- this.validateDepth(depth);
1468
- const { type, value } = this.processComponentType(component);
1469
- switch (type) {
1470
- case "empty":
1471
- return "";
1472
- case "text":
1473
- return escapeHtml(value);
1474
- case "function":
1475
- const result = this.executeFunctionComponent(value, depth);
1476
- return this.renderComponent(result, options, depth + 1);
1477
- case "array":
1478
- return value.map((child) => this.renderComponent(child, options, depth + 1)).join("");
1479
- case "element":
1480
- const tagName = Object.keys(value)[0];
1481
- const elementContent = value[tagName];
1482
- return this.renderElement(tagName, elementContent, options, depth);
1483
- default:
1484
- this.recordError("renderComponent", new Error(`Unknown component type: ${type}`));
1485
- return "";
1486
- }
1487
- }
1488
- /**
1489
- * Render an HTML element with advanced caching and optimization
1490
- */
1491
- renderElement(tagName, element, options, depth = 0) {
1492
- const startTime = performance.now();
1493
- if (options.enableMonitoring && this.cache) {
1494
- }
1495
- if (options.enableCache && this.cache && RendererUtils.isStaticElement(element)) {
1496
- const cacheKey = `static:${tagName}:${JSON.stringify(element)}`;
1497
- const cached = this.cache.get("static", cacheKey);
1498
- if (cached) {
1499
- this.recordPerformance(tagName, startTime, true);
1500
- return cached.value;
1501
- }
1502
- }
1503
- if (typeof element === "string" || typeof element === "number" || typeof element === "boolean") {
1504
- const html2 = isVoidElement(tagName) ? `<${tagName}>` : `<${tagName}>${escapeHtml(String(element))}</${tagName}>`;
1505
- this.cacheIfStatic(tagName, element, html2, options);
1506
- this.recordPerformance(tagName, startTime, false);
1507
- return html2;
1508
- }
1509
- if (typeof element === "function") {
1510
- const result = this.executeFunctionComponent(element, depth);
1511
- return this.renderElement(tagName, result, options, depth);
1512
- }
1513
- if (element && typeof element === "object") {
1514
- return this.renderObjectElement(tagName, element, options, depth);
1515
- }
1516
- if (element === null || element === void 0) {
1517
- const html2 = isVoidElement(tagName) ? `<${tagName}>` : `<${tagName}></${tagName}>`;
1518
- this.recordPerformance(tagName, startTime, false);
1519
- return html2;
1520
- }
1521
- const html = `<${tagName}>${escapeHtml(String(element))}</${tagName}>`;
1522
- this.recordPerformance(tagName, startTime, false);
1523
- return html;
1524
- }
1525
- /**
1526
- * Cache element if it's static
1527
- */
1528
- cacheIfStatic(tagName, element, html) {
1529
- if (this.config.enableCache && this.cache && RendererUtils.isStaticElement(element)) {
1530
- const cacheKey = `static:${tagName}:${JSON.stringify(element)}`;
1531
- this.cache.set("static", cacheKey, html, {
1532
- ttlMs: this.config.cacheTTL || 5 * 60 * 1e3,
1533
- // 5 minutes default
1534
- size: html.length
1535
- // Approximate size
1536
- });
1537
- }
1538
- }
1539
- /**
1540
- * Render complex object elements with attributes and children
1541
- */
1542
- renderObjectElement(tagName, element, options, depth = 0) {
1543
- const startTime = performance.now();
1544
- if (options.enableCache && this.cache) {
1545
- const cacheKey = RendererUtils.generateCacheKey(tagName, element);
1546
- if (cacheKey) {
1547
- const cached = this.cache.get(cacheKey);
1548
- if (cached) {
1549
- this.recordPerformance(tagName, startTime, true);
1550
- return cached;
1551
- }
1552
- }
1553
- }
1554
- const { children, text, ...attributes } = element || {};
1555
- const attributeString = formatAttributes(attributes);
1556
- const openingTag = attributeString ? `<${tagName} ${attributeString}>` : `<${tagName}>`;
1557
- let textContent = "";
1558
- if (text !== void 0) {
1559
- const isScript = tagName === "script";
1560
- const isStyle = tagName === "style";
1561
- const isRawTag = isScript || isStyle;
1562
- const raw = typeof text === "function" ? String(text()) : String(text);
1563
- if (isRawTag) {
1564
- const safe = raw.replace(/<\/(script)/gi, "<\\/$1").replace(/<\/(style)/gi, "<\\/$1").replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
1565
- textContent = safe;
1566
- } else {
1567
- textContent = escapeHtml(raw);
1568
- }
1569
- }
1570
- let childrenHtml = "";
1571
- if (hasChildren(element)) {
1572
- const normalizedChildren = normalizeChildren(children);
1573
- childrenHtml = normalizedChildren.map((child) => this.renderComponent(child, options, depth + 1)).join("");
1574
- }
1575
- const html = `${openingTag}${textContent}${childrenHtml}</${tagName}>`;
1576
- if (options.enableCache && this.cache && RendererUtils.isCacheable(element, options)) {
1577
- const cacheKey = RendererUtils.generateCacheKey(tagName, element);
1578
- if (cacheKey) {
1579
- this.cache.set(cacheKey, html);
1580
- }
1581
- }
1582
- this.recordPerformance(tagName, startTime, false);
1583
- return html;
1584
- }
1585
- };
1586
- function render(component, options = {}) {
1587
- const mergedOptions = {
1588
- enableCache: true,
1589
- enableMonitoring: false,
1590
- ...options
1591
- };
1592
- const renderer = new HTMLRenderer(mergedOptions);
1593
- return renderer.render(component, mergedOptions);
1594
- }
1595
-
1596
- // ../core/src/utils/render-utils.js
1597
- function renderWithMonitoring(component, options = {}) {
1598
- const {
1599
- enablePerformanceMonitoring = false
1600
- } = options;
1601
- let html;
1602
- if (enablePerformanceMonitoring) {
1603
- const renderId = performanceMonitor.startRender();
1604
- html = render(component);
1605
- performanceMonitor.endRender(renderId);
1606
- } else {
1607
- html = render(component);
1608
- }
1609
- return html;
1610
- }
1611
- function renderWithTemplate(component, options = {}) {
1612
- const {
1613
- template = "<!DOCTYPE html>\n{{content}}"
1614
- } = options;
1615
- const html = renderWithMonitoring(component, options);
1616
- return template.replace("{{content}}", html);
1617
- }
1618
- async function renderComponentFactory(componentFactory, factoryArgs, options = {}) {
1619
- const component = await Promise.resolve(
1620
- componentFactory(...factoryArgs)
1621
- );
1622
- if (!component) {
1623
- throw new Error("Component factory returned null/undefined");
1624
- }
1625
- return renderWithTemplate(component, options);
1626
- }
1627
-
1628
- // src/coherent-fastify.js
29
+ var import_core = require("@coherent.js/core");
1629
30
  function coherentFastify(fastify, options, done) {
1630
31
  const {
1631
32
  enablePerformanceMonitoring = false,
@@ -1644,7 +45,7 @@ function coherentFastify(fastify, options, done) {
1644
45
  template: renderTemplate = template
1645
46
  } = renderOptions;
1646
47
  try {
1647
- const finalHtml = renderWithTemplate(component, {
48
+ const finalHtml = (0, import_core.renderWithTemplate)(component, {
1648
49
  enablePerformanceMonitoring: renderPerformanceMonitoring,
1649
50
  template: renderTemplate
1650
51
  });
@@ -1661,7 +62,7 @@ function coherentFastify(fastify, options, done) {
1661
62
  fastify.addHook("onSend", async (request, reply, payload) => {
1662
63
  if (reply.isCoherentObject(payload)) {
1663
64
  try {
1664
- const finalHtml = renderWithTemplate(payload, { enablePerformanceMonitoring, template });
65
+ const finalHtml = (0, import_core.renderWithTemplate)(payload, { enablePerformanceMonitoring, template });
1665
66
  reply.header("Content-Type", "text/html; charset=utf-8");
1666
67
  return finalHtml;
1667
68
  } catch (_error) {
@@ -1676,7 +77,7 @@ function coherentFastify(fastify, options, done) {
1676
77
  function createHandler(componentFactory, options = {}) {
1677
78
  return async (request, reply) => {
1678
79
  try {
1679
- const finalHtml = await renderComponentFactory(
80
+ const finalHtml = await (0, import_core.renderComponentFactory)(
1680
81
  componentFactory,
1681
82
  [request, reply],
1682
83
  options
@@ -1699,10 +100,4 @@ var coherent_fastify_default = coherentFastify;
1699
100
  createHandler,
1700
101
  setupCoherent
1701
102
  });
1702
- /**
1703
- * Advanced caching system with memory management and smart invalidation for Coherent.js
1704
- *
1705
- * @module @coherent/performance/cache-manager
1706
- * @license MIT
1707
- */
1708
103
  //# sourceMappingURL=index.cjs.map