@coherent.js/nextjs 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/README.md +521 -0
- package/dist/index.cjs +15 -3652
- package/dist/index.cjs.map +4 -4
- package/dist/index.js +6 -3628
- package/dist/index.js.map +4 -4
- package/package.json +3 -2
- package/types/index.d.ts +96 -7
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/index.js
|
|
@@ -39,3625 +29,12 @@ __export(index_exports, {
|
|
|
39
29
|
});
|
|
40
30
|
module.exports = __toCommonJS(index_exports);
|
|
41
31
|
|
|
42
|
-
// ../core/src/performance/monitor.js
|
|
43
|
-
function createPerformanceMonitor(options = {}) {
|
|
44
|
-
const opts = {
|
|
45
|
-
enabled: true,
|
|
46
|
-
metrics: {
|
|
47
|
-
custom: {}
|
|
48
|
-
},
|
|
49
|
-
sampling: {
|
|
50
|
-
enabled: false,
|
|
51
|
-
rate: 1,
|
|
52
|
-
strategy: "random"
|
|
53
|
-
},
|
|
54
|
-
reporting: {
|
|
55
|
-
enabled: false,
|
|
56
|
-
interval: 6e4,
|
|
57
|
-
format: "json",
|
|
58
|
-
batch: {
|
|
59
|
-
enabled: false,
|
|
60
|
-
maxSize: 100,
|
|
61
|
-
flushInterval: 5e3
|
|
62
|
-
},
|
|
63
|
-
onReport: null
|
|
64
|
-
},
|
|
65
|
-
alerts: {
|
|
66
|
-
enabled: true,
|
|
67
|
-
rules: []
|
|
68
|
-
},
|
|
69
|
-
resources: {
|
|
70
|
-
enabled: false,
|
|
71
|
-
track: ["memory"],
|
|
72
|
-
interval: 1e3
|
|
73
|
-
},
|
|
74
|
-
profiling: {
|
|
75
|
-
enabled: false,
|
|
76
|
-
mode: "production",
|
|
77
|
-
flamegraph: false,
|
|
78
|
-
tracing: {
|
|
79
|
-
enabled: false,
|
|
80
|
-
sampleRate: 0.01
|
|
81
|
-
}
|
|
82
|
-
},
|
|
83
|
-
...options
|
|
84
|
-
};
|
|
85
|
-
opts.reporting.batch = {
|
|
86
|
-
enabled: false,
|
|
87
|
-
maxSize: 100,
|
|
88
|
-
flushInterval: 5e3,
|
|
89
|
-
...options.reporting?.batch || {}
|
|
90
|
-
};
|
|
91
|
-
const metrics = {
|
|
92
|
-
builtin: {
|
|
93
|
-
renderTime: { type: "histogram", unit: "ms", values: [] },
|
|
94
|
-
componentCount: { type: "counter", unit: "renders", value: 0 },
|
|
95
|
-
errorCount: { type: "counter", unit: "errors", value: 0 },
|
|
96
|
-
memoryUsage: { type: "gauge", unit: "MB", values: [] }
|
|
97
|
-
},
|
|
98
|
-
custom: {}
|
|
99
|
-
};
|
|
100
|
-
Object.entries(opts.metrics.custom).forEach(([name, config]) => {
|
|
101
|
-
metrics.custom[name] = {
|
|
102
|
-
type: config.type || "counter",
|
|
103
|
-
unit: config.unit || "",
|
|
104
|
-
threshold: config.threshold,
|
|
105
|
-
values: config.type === "histogram" ? [] : void 0,
|
|
106
|
-
value: config.type === "counter" || config.type === "gauge" ? 0 : void 0
|
|
107
|
-
};
|
|
108
|
-
});
|
|
109
|
-
const samplingState = {
|
|
110
|
-
count: 0,
|
|
111
|
-
sampled: 0,
|
|
112
|
-
adaptiveRate: opts.sampling.rate
|
|
113
|
-
};
|
|
114
|
-
const reportingState = {
|
|
115
|
-
batch: [],
|
|
116
|
-
lastReport: Date.now(),
|
|
117
|
-
reportTimer: null,
|
|
118
|
-
flushTimer: null
|
|
119
|
-
};
|
|
120
|
-
const alertState = {
|
|
121
|
-
triggered: /* @__PURE__ */ new Map(),
|
|
122
|
-
history: []
|
|
123
|
-
};
|
|
124
|
-
const resourceState = {
|
|
125
|
-
samples: [],
|
|
126
|
-
timer: null
|
|
127
|
-
};
|
|
128
|
-
const profilingState = {
|
|
129
|
-
traces: [],
|
|
130
|
-
flamegraphData: []
|
|
131
|
-
};
|
|
132
|
-
const stats = {
|
|
133
|
-
metricsRecorded: 0,
|
|
134
|
-
sampleRate: opts.sampling.rate,
|
|
135
|
-
reportsGenerated: 0,
|
|
136
|
-
alertsTriggered: 0
|
|
137
|
-
};
|
|
138
|
-
function shouldSample() {
|
|
139
|
-
if (!opts.sampling.enabled) return true;
|
|
140
|
-
samplingState.count++;
|
|
141
|
-
if (opts.sampling.strategy === "random") {
|
|
142
|
-
return Math.random() < samplingState.adaptiveRate;
|
|
143
|
-
} else if (opts.sampling.strategy === "deterministic") {
|
|
144
|
-
return samplingState.count % Math.ceil(1 / samplingState.adaptiveRate) === 0;
|
|
145
|
-
} else if (opts.sampling.strategy === "adaptive") {
|
|
146
|
-
const recentRenderTimes = metrics.builtin.renderTime.values.slice(-10);
|
|
147
|
-
if (recentRenderTimes.length > 0) {
|
|
148
|
-
const avgTime = recentRenderTimes.reduce((a, b) => a + b, 0) / recentRenderTimes.length;
|
|
149
|
-
samplingState.adaptiveRate = avgTime > 16 ? Math.min(1, opts.sampling.rate * 2) : opts.sampling.rate;
|
|
150
|
-
}
|
|
151
|
-
return Math.random() < samplingState.adaptiveRate;
|
|
152
|
-
}
|
|
153
|
-
return true;
|
|
154
|
-
}
|
|
155
|
-
function recordMetric(name, value, metadata = {}) {
|
|
156
|
-
if (!opts.enabled) return;
|
|
157
|
-
if (!shouldSample()) return;
|
|
158
|
-
stats.metricsRecorded++;
|
|
159
|
-
const builtinMetric = metrics.builtin[name];
|
|
160
|
-
if (builtinMetric) {
|
|
161
|
-
if (builtinMetric.type === "histogram") {
|
|
162
|
-
builtinMetric.values.push(value);
|
|
163
|
-
if (builtinMetric.values.length > 1e3) {
|
|
164
|
-
builtinMetric.values = builtinMetric.values.slice(-1e3);
|
|
165
|
-
}
|
|
166
|
-
} else if (builtinMetric.type === "counter") {
|
|
167
|
-
builtinMetric.value += value;
|
|
168
|
-
} else if (builtinMetric.type === "gauge") {
|
|
169
|
-
builtinMetric.values.push(value);
|
|
170
|
-
if (builtinMetric.values.length > 100) {
|
|
171
|
-
builtinMetric.values = builtinMetric.values.slice(-100);
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
const customMetric = metrics.custom[name];
|
|
176
|
-
if (customMetric) {
|
|
177
|
-
if (customMetric.type === "histogram") {
|
|
178
|
-
customMetric.values = customMetric.values || [];
|
|
179
|
-
customMetric.values.push(value);
|
|
180
|
-
if (customMetric.values.length > 1e3) {
|
|
181
|
-
customMetric.values = customMetric.values.slice(-1e3);
|
|
182
|
-
}
|
|
183
|
-
} else if (customMetric.type === "counter") {
|
|
184
|
-
customMetric.value = (customMetric.value || 0) + value;
|
|
185
|
-
} else if (customMetric.type === "gauge") {
|
|
186
|
-
customMetric.values = customMetric.values || [];
|
|
187
|
-
customMetric.values.push(value);
|
|
188
|
-
if (customMetric.values.length > 100) {
|
|
189
|
-
customMetric.values = customMetric.values.slice(-100);
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
if (customMetric.threshold) {
|
|
193
|
-
const currentValue = customMetric.type === "histogram" || customMetric.type === "gauge" ? customMetric.values[customMetric.values.length - 1] : customMetric.value;
|
|
194
|
-
if (currentValue > customMetric.threshold) {
|
|
195
|
-
checkAlerts(name, currentValue);
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
if (opts.reporting.enabled && opts.reporting.batch.enabled) {
|
|
200
|
-
reportingState.batch.push({
|
|
201
|
-
metric: name,
|
|
202
|
-
value,
|
|
203
|
-
metadata,
|
|
204
|
-
timestamp: Date.now()
|
|
205
|
-
});
|
|
206
|
-
if (reportingState.batch.length >= opts.reporting.batch.maxSize) {
|
|
207
|
-
flushBatch();
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
checkAlerts(name, value);
|
|
211
|
-
}
|
|
212
|
-
function checkAlerts(metric, value) {
|
|
213
|
-
if (!opts.alerts.enabled) return;
|
|
214
|
-
opts.alerts.rules.forEach((rule) => {
|
|
215
|
-
if (rule.metric !== metric) return;
|
|
216
|
-
let triggered = false;
|
|
217
|
-
if (rule.condition === "exceeds" && value > rule.threshold) {
|
|
218
|
-
triggered = true;
|
|
219
|
-
} else if (rule.condition === "below" && value < rule.threshold) {
|
|
220
|
-
triggered = true;
|
|
221
|
-
} else if (rule.condition === "equals" && value === rule.threshold) {
|
|
222
|
-
triggered = true;
|
|
223
|
-
}
|
|
224
|
-
if (triggered) {
|
|
225
|
-
const alertKey = `${rule.metric}-${rule.condition}-${rule.threshold}`;
|
|
226
|
-
const lastTriggered = alertState.triggered.get(alertKey);
|
|
227
|
-
const now = Date.now();
|
|
228
|
-
if (!lastTriggered || now - lastTriggered > 5e3) {
|
|
229
|
-
alertState.triggered.set(alertKey, now);
|
|
230
|
-
alertState.history.push({
|
|
231
|
-
rule,
|
|
232
|
-
value,
|
|
233
|
-
timestamp: now
|
|
234
|
-
});
|
|
235
|
-
stats.alertsTriggered++;
|
|
236
|
-
if (rule.action) {
|
|
237
|
-
rule.action(value, rule);
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
}
|
|
241
|
-
});
|
|
242
|
-
}
|
|
243
|
-
function flushBatch() {
|
|
244
|
-
if (reportingState.batch.length === 0) return;
|
|
245
|
-
const batch = [...reportingState.batch];
|
|
246
|
-
reportingState.batch = [];
|
|
247
|
-
if (opts.reporting.onReport) {
|
|
248
|
-
opts.reporting.onReport({ type: "batch", data: batch });
|
|
249
|
-
}
|
|
250
|
-
}
|
|
251
|
-
function generateReport() {
|
|
252
|
-
const report = {
|
|
253
|
-
timestamp: Date.now(),
|
|
254
|
-
statistics: { ...stats },
|
|
255
|
-
metrics: {}
|
|
256
|
-
};
|
|
257
|
-
Object.entries(metrics.builtin).forEach(([name, metric]) => {
|
|
258
|
-
if (metric.type === "histogram") {
|
|
259
|
-
report.metrics[name] = {
|
|
260
|
-
type: "histogram",
|
|
261
|
-
unit: metric.unit,
|
|
262
|
-
count: metric.values.length,
|
|
263
|
-
min: metric.values.length > 0 ? Math.min(...metric.values) : 0,
|
|
264
|
-
max: metric.values.length > 0 ? Math.max(...metric.values) : 0,
|
|
265
|
-
avg: metric.values.length > 0 ? metric.values.reduce((a, b) => a + b, 0) / metric.values.length : 0,
|
|
266
|
-
p50: percentile(metric.values, 0.5),
|
|
267
|
-
p95: percentile(metric.values, 0.95),
|
|
268
|
-
p99: percentile(metric.values, 0.99)
|
|
269
|
-
};
|
|
270
|
-
} else if (metric.type === "counter") {
|
|
271
|
-
report.metrics[name] = {
|
|
272
|
-
type: "counter",
|
|
273
|
-
unit: metric.unit,
|
|
274
|
-
value: metric.value
|
|
275
|
-
};
|
|
276
|
-
} else if (metric.type === "gauge") {
|
|
277
|
-
report.metrics[name] = {
|
|
278
|
-
type: "gauge",
|
|
279
|
-
unit: metric.unit,
|
|
280
|
-
current: metric.values.length > 0 ? metric.values[metric.values.length - 1] : 0,
|
|
281
|
-
avg: metric.values.length > 0 ? metric.values.reduce((a, b) => a + b, 0) / metric.values.length : 0
|
|
282
|
-
};
|
|
283
|
-
}
|
|
284
|
-
});
|
|
285
|
-
Object.entries(metrics.custom).forEach(([name, metric]) => {
|
|
286
|
-
if (metric.type === "histogram") {
|
|
287
|
-
report.metrics[name] = {
|
|
288
|
-
type: "histogram",
|
|
289
|
-
unit: metric.unit,
|
|
290
|
-
count: metric.values?.length || 0,
|
|
291
|
-
min: metric.values?.length > 0 ? Math.min(...metric.values) : 0,
|
|
292
|
-
max: metric.values?.length > 0 ? Math.max(...metric.values) : 0,
|
|
293
|
-
avg: metric.values?.length > 0 ? metric.values.reduce((a, b) => a + b, 0) / metric.values.length : 0,
|
|
294
|
-
p95: percentile(metric.values || [], 0.95),
|
|
295
|
-
p99: percentile(metric.values || [], 0.99)
|
|
296
|
-
};
|
|
297
|
-
} else if (metric.type === "counter") {
|
|
298
|
-
report.metrics[name] = {
|
|
299
|
-
type: "counter",
|
|
300
|
-
unit: metric.unit,
|
|
301
|
-
value: metric.value || 0
|
|
302
|
-
};
|
|
303
|
-
} else if (metric.type === "gauge") {
|
|
304
|
-
report.metrics[name] = {
|
|
305
|
-
type: "gauge",
|
|
306
|
-
unit: metric.unit,
|
|
307
|
-
current: metric.values?.length > 0 ? metric.values[metric.values.length - 1] : 0,
|
|
308
|
-
avg: metric.values?.length > 0 ? metric.values.reduce((a, b) => a + b, 0) / metric.values.length : 0
|
|
309
|
-
};
|
|
310
|
-
}
|
|
311
|
-
});
|
|
312
|
-
report.alerts = {
|
|
313
|
-
total: alertState.history.length,
|
|
314
|
-
recent: alertState.history.slice(-10)
|
|
315
|
-
};
|
|
316
|
-
if (opts.resources.enabled) {
|
|
317
|
-
report.resources = {
|
|
318
|
-
samples: resourceState.samples.slice(-20)
|
|
319
|
-
};
|
|
320
|
-
}
|
|
321
|
-
stats.reportsGenerated++;
|
|
322
|
-
if (opts.reporting.onReport) {
|
|
323
|
-
opts.reporting.onReport({ type: "report", data: report });
|
|
324
|
-
}
|
|
325
|
-
return report;
|
|
326
|
-
}
|
|
327
|
-
function percentile(values, p) {
|
|
328
|
-
if (values.length === 0) return 0;
|
|
329
|
-
const sorted = [...values].sort((a, b) => a - b);
|
|
330
|
-
const index = Math.ceil(sorted.length * p) - 1;
|
|
331
|
-
return sorted[Math.max(0, index)];
|
|
332
|
-
}
|
|
333
|
-
function startResourceMonitoring() {
|
|
334
|
-
if (!opts.resources.enabled) return;
|
|
335
|
-
const collectResources = () => {
|
|
336
|
-
const sample = {
|
|
337
|
-
timestamp: Date.now()
|
|
338
|
-
};
|
|
339
|
-
if (opts.resources.track.includes("memory")) {
|
|
340
|
-
if (typeof process !== "undefined" && process.memoryUsage) {
|
|
341
|
-
const mem = process.memoryUsage();
|
|
342
|
-
sample.memory = {
|
|
343
|
-
heapUsed: mem.heapUsed / 1024 / 1024,
|
|
344
|
-
heapTotal: mem.heapTotal / 1024 / 1024,
|
|
345
|
-
external: mem.external / 1024 / 1024,
|
|
346
|
-
rss: mem.rss / 1024 / 1024
|
|
347
|
-
};
|
|
348
|
-
} else if (typeof performance !== "undefined" && performance.memory) {
|
|
349
|
-
sample.memory = {
|
|
350
|
-
heapUsed: performance.memory.usedJSHeapSize / 1024 / 1024,
|
|
351
|
-
heapTotal: performance.memory.totalJSHeapSize / 1024 / 1024
|
|
352
|
-
};
|
|
353
|
-
}
|
|
354
|
-
}
|
|
355
|
-
resourceState.samples.push(sample);
|
|
356
|
-
if (resourceState.samples.length > 100) {
|
|
357
|
-
resourceState.samples = resourceState.samples.slice(-100);
|
|
358
|
-
}
|
|
359
|
-
resourceState.timer = setTimeout(collectResources, opts.resources.interval);
|
|
360
|
-
};
|
|
361
|
-
collectResources();
|
|
362
|
-
}
|
|
363
|
-
function stopResourceMonitoring() {
|
|
364
|
-
if (resourceState.timer) {
|
|
365
|
-
clearTimeout(resourceState.timer);
|
|
366
|
-
resourceState.timer = null;
|
|
367
|
-
}
|
|
368
|
-
}
|
|
369
|
-
function startReporting() {
|
|
370
|
-
if (!opts.reporting.enabled) return;
|
|
371
|
-
reportingState.reportTimer = setInterval(() => {
|
|
372
|
-
generateReport();
|
|
373
|
-
}, opts.reporting.interval);
|
|
374
|
-
if (opts.reporting.batch.enabled) {
|
|
375
|
-
reportingState.flushTimer = setInterval(() => {
|
|
376
|
-
flushBatch();
|
|
377
|
-
}, opts.reporting.batch.flushInterval);
|
|
378
|
-
}
|
|
379
|
-
}
|
|
380
|
-
function stopReporting() {
|
|
381
|
-
if (reportingState.reportTimer) {
|
|
382
|
-
clearInterval(reportingState.reportTimer);
|
|
383
|
-
reportingState.reportTimer = null;
|
|
384
|
-
}
|
|
385
|
-
if (reportingState.flushTimer) {
|
|
386
|
-
clearInterval(reportingState.flushTimer);
|
|
387
|
-
reportingState.flushTimer = null;
|
|
388
|
-
}
|
|
389
|
-
flushBatch();
|
|
390
|
-
}
|
|
391
|
-
function startProfiling() {
|
|
392
|
-
if (!opts.profiling.enabled) return;
|
|
393
|
-
}
|
|
394
|
-
function recordTrace(name, duration, metadata = {}) {
|
|
395
|
-
if (!opts.profiling.enabled || !opts.profiling.tracing.enabled) return;
|
|
396
|
-
if (Math.random() < opts.profiling.tracing.sampleRate) {
|
|
397
|
-
profilingState.traces.push({
|
|
398
|
-
name,
|
|
399
|
-
duration,
|
|
400
|
-
metadata,
|
|
401
|
-
timestamp: Date.now()
|
|
402
|
-
});
|
|
403
|
-
if (profilingState.traces.length > 1e3) {
|
|
404
|
-
profilingState.traces = profilingState.traces.slice(-1e3);
|
|
405
|
-
}
|
|
406
|
-
}
|
|
407
|
-
}
|
|
408
|
-
function measure(name, fn, metadata = {}) {
|
|
409
|
-
if (!opts.enabled) return fn();
|
|
410
|
-
const start = performance.now();
|
|
411
|
-
try {
|
|
412
|
-
const result = fn();
|
|
413
|
-
const duration = performance.now() - start;
|
|
414
|
-
recordMetric("renderTime", duration, { name, ...metadata });
|
|
415
|
-
recordTrace(name, duration, metadata);
|
|
416
|
-
return result;
|
|
417
|
-
} catch (error) {
|
|
418
|
-
recordMetric("errorCount", 1, { name, error: error.message });
|
|
419
|
-
throw error;
|
|
420
|
-
}
|
|
421
|
-
}
|
|
422
|
-
async function measureAsync(name, fn, metadata = {}) {
|
|
423
|
-
if (!opts.enabled) return fn();
|
|
424
|
-
const start = performance.now();
|
|
425
|
-
try {
|
|
426
|
-
const result = await fn();
|
|
427
|
-
const duration = performance.now() - start;
|
|
428
|
-
recordMetric("renderTime", duration, { name, ...metadata });
|
|
429
|
-
recordTrace(name, duration, metadata);
|
|
430
|
-
return result;
|
|
431
|
-
} catch (error) {
|
|
432
|
-
recordMetric("errorCount", 1, { name, error: error.message });
|
|
433
|
-
throw error;
|
|
434
|
-
}
|
|
435
|
-
}
|
|
436
|
-
function addMetric(name, config) {
|
|
437
|
-
metrics.custom[name] = {
|
|
438
|
-
type: config.type || "counter",
|
|
439
|
-
unit: config.unit || "",
|
|
440
|
-
threshold: config.threshold,
|
|
441
|
-
values: config.type === "histogram" ? [] : void 0,
|
|
442
|
-
value: config.type === "counter" || config.type === "gauge" ? 0 : void 0
|
|
443
|
-
};
|
|
444
|
-
}
|
|
445
|
-
function addAlertRule(rule) {
|
|
446
|
-
opts.alerts.rules.push(rule);
|
|
447
|
-
}
|
|
448
|
-
function getStats() {
|
|
449
|
-
return {
|
|
450
|
-
...stats,
|
|
451
|
-
sampleRate: samplingState.adaptiveRate,
|
|
452
|
-
batchSize: reportingState.batch.length,
|
|
453
|
-
resourceSamples: resourceState.samples.length,
|
|
454
|
-
traces: profilingState.traces.length,
|
|
455
|
-
alerts: {
|
|
456
|
-
total: alertState.history.length,
|
|
457
|
-
unique: alertState.triggered.size
|
|
458
|
-
}
|
|
459
|
-
};
|
|
460
|
-
}
|
|
461
|
-
function reset() {
|
|
462
|
-
Object.values(metrics.builtin).forEach((metric) => {
|
|
463
|
-
if (metric.type === "histogram" || metric.type === "gauge") {
|
|
464
|
-
metric.values = [];
|
|
465
|
-
} else if (metric.type === "counter") {
|
|
466
|
-
metric.value = 0;
|
|
467
|
-
}
|
|
468
|
-
});
|
|
469
|
-
Object.values(metrics.custom).forEach((metric) => {
|
|
470
|
-
if (metric.type === "histogram" || metric.type === "gauge") {
|
|
471
|
-
metric.values = [];
|
|
472
|
-
} else if (metric.type === "counter") {
|
|
473
|
-
metric.value = 0;
|
|
474
|
-
}
|
|
475
|
-
});
|
|
476
|
-
samplingState.count = 0;
|
|
477
|
-
samplingState.sampled = 0;
|
|
478
|
-
reportingState.batch = [];
|
|
479
|
-
alertState.history = [];
|
|
480
|
-
alertState.triggered.clear();
|
|
481
|
-
resourceState.samples = [];
|
|
482
|
-
profilingState.traces = [];
|
|
483
|
-
stats.metricsRecorded = 0;
|
|
484
|
-
stats.reportsGenerated = 0;
|
|
485
|
-
stats.alertsTriggered = 0;
|
|
486
|
-
}
|
|
487
|
-
if (opts.enabled) {
|
|
488
|
-
startResourceMonitoring();
|
|
489
|
-
startReporting();
|
|
490
|
-
startProfiling();
|
|
491
|
-
}
|
|
492
|
-
return {
|
|
493
|
-
recordMetric,
|
|
494
|
-
measure,
|
|
495
|
-
measureAsync,
|
|
496
|
-
addMetric,
|
|
497
|
-
addAlertRule,
|
|
498
|
-
generateReport,
|
|
499
|
-
getStats,
|
|
500
|
-
reset,
|
|
501
|
-
start() {
|
|
502
|
-
opts.enabled = true;
|
|
503
|
-
startResourceMonitoring();
|
|
504
|
-
startReporting();
|
|
505
|
-
startProfiling();
|
|
506
|
-
},
|
|
507
|
-
stop() {
|
|
508
|
-
opts.enabled = false;
|
|
509
|
-
stopResourceMonitoring();
|
|
510
|
-
stopReporting();
|
|
511
|
-
return generateReport();
|
|
512
|
-
}
|
|
513
|
-
};
|
|
514
|
-
}
|
|
515
|
-
var performanceMonitor2 = createPerformanceMonitor();
|
|
516
|
-
|
|
517
|
-
// ../core/src/core/object-utils.js
|
|
518
|
-
function deepClone(obj, seen = /* @__PURE__ */ new WeakMap()) {
|
|
519
|
-
if (obj === null || typeof obj !== "object") {
|
|
520
|
-
return obj;
|
|
521
|
-
}
|
|
522
|
-
if (seen.has(obj)) {
|
|
523
|
-
return seen.get(obj);
|
|
524
|
-
}
|
|
525
|
-
if (obj instanceof Date) {
|
|
526
|
-
return new Date(obj.getTime());
|
|
527
|
-
}
|
|
528
|
-
if (obj instanceof RegExp) {
|
|
529
|
-
return new RegExp(obj.source, obj.flags);
|
|
530
|
-
}
|
|
531
|
-
if (Array.isArray(obj)) {
|
|
532
|
-
const clonedArray = [];
|
|
533
|
-
seen.set(obj, clonedArray);
|
|
534
|
-
for (let i = 0; i < obj.length; i++) {
|
|
535
|
-
clonedArray[i] = deepClone(obj[i], seen);
|
|
536
|
-
}
|
|
537
|
-
return clonedArray;
|
|
538
|
-
}
|
|
539
|
-
if (typeof obj === "function") {
|
|
540
|
-
return obj;
|
|
541
|
-
}
|
|
542
|
-
if (obj instanceof Map) {
|
|
543
|
-
const clonedMap = /* @__PURE__ */ new Map();
|
|
544
|
-
seen.set(obj, clonedMap);
|
|
545
|
-
for (const [key, value] of obj) {
|
|
546
|
-
clonedMap.set(deepClone(key, seen), deepClone(value, seen));
|
|
547
|
-
}
|
|
548
|
-
return clonedMap;
|
|
549
|
-
}
|
|
550
|
-
if (obj instanceof Set) {
|
|
551
|
-
const clonedSet = /* @__PURE__ */ new Set();
|
|
552
|
-
seen.set(obj, clonedSet);
|
|
553
|
-
for (const value of obj) {
|
|
554
|
-
clonedSet.add(deepClone(value, seen));
|
|
555
|
-
}
|
|
556
|
-
return clonedSet;
|
|
557
|
-
}
|
|
558
|
-
if (obj instanceof WeakMap) {
|
|
559
|
-
return /* @__PURE__ */ new WeakMap();
|
|
560
|
-
}
|
|
561
|
-
if (obj instanceof WeakSet) {
|
|
562
|
-
return /* @__PURE__ */ new WeakSet();
|
|
563
|
-
}
|
|
564
|
-
const clonedObj = {};
|
|
565
|
-
seen.set(obj, clonedObj);
|
|
566
|
-
if (obj.constructor && obj.constructor !== Object) {
|
|
567
|
-
try {
|
|
568
|
-
clonedObj.__proto__ = obj.__proto__;
|
|
569
|
-
} catch {
|
|
570
|
-
Object.setPrototypeOf(clonedObj, Object.getPrototypeOf(obj));
|
|
571
|
-
}
|
|
572
|
-
}
|
|
573
|
-
for (const key in obj) {
|
|
574
|
-
if (obj.hasOwnProperty(key)) {
|
|
575
|
-
clonedObj[key] = deepClone(obj[key], seen);
|
|
576
|
-
}
|
|
577
|
-
}
|
|
578
|
-
const descriptors = Object.getOwnPropertyDescriptors(obj);
|
|
579
|
-
for (const key of Object.keys(descriptors)) {
|
|
580
|
-
if (!descriptors[key].enumerable && descriptors[key].configurable) {
|
|
581
|
-
try {
|
|
582
|
-
Object.defineProperty(clonedObj, key, {
|
|
583
|
-
...descriptors[key],
|
|
584
|
-
value: deepClone(descriptors[key].value, seen)
|
|
585
|
-
});
|
|
586
|
-
} catch {
|
|
587
|
-
}
|
|
588
|
-
}
|
|
589
|
-
}
|
|
590
|
-
return clonedObj;
|
|
591
|
-
}
|
|
592
|
-
function validateComponent(component, path2 = "root") {
|
|
593
|
-
if (component === null || component === void 0) {
|
|
594
|
-
throw new Error(`Invalid component at ${path2}: null or undefined`);
|
|
595
|
-
}
|
|
596
|
-
if (["string", "number", "boolean"].includes(typeof component)) {
|
|
597
|
-
return true;
|
|
598
|
-
}
|
|
599
|
-
if (typeof component === "function") {
|
|
600
|
-
return true;
|
|
601
|
-
}
|
|
602
|
-
if (Array.isArray(component)) {
|
|
603
|
-
component.forEach((child, index) => {
|
|
604
|
-
validateComponent(child, `${path2}[${index}]`);
|
|
605
|
-
});
|
|
606
|
-
return true;
|
|
607
|
-
}
|
|
608
|
-
if (typeof component === "object") {
|
|
609
|
-
const keys = Object.keys(component);
|
|
610
|
-
if (keys.length === 0) {
|
|
611
|
-
throw new Error(`Empty object at ${path2}`);
|
|
612
|
-
}
|
|
613
|
-
keys.forEach((key) => {
|
|
614
|
-
const value = component[key];
|
|
615
|
-
if (!/^[a-zA-Z][a-zA-Z0-9-]*$/.test(key) && key !== "text") {
|
|
616
|
-
console.warn(`Potentially invalid tag name at ${path2}: ${key}`);
|
|
617
|
-
}
|
|
618
|
-
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
619
|
-
if (value.children) {
|
|
620
|
-
validateComponent(value.children, `${path2}.${key}.children`);
|
|
621
|
-
}
|
|
622
|
-
} else if (value && typeof value !== "string" && typeof value !== "number" && typeof value !== "function") {
|
|
623
|
-
throw new Error(`Invalid value type at ${path2}.${key}: ${typeof value}`);
|
|
624
|
-
}
|
|
625
|
-
});
|
|
626
|
-
return true;
|
|
627
|
-
}
|
|
628
|
-
throw new Error(`Invalid component type at ${path2}: ${typeof component}`);
|
|
629
|
-
}
|
|
630
|
-
function isCoherentObject(obj) {
|
|
631
|
-
if (!obj || typeof obj !== "object" || Array.isArray(obj)) {
|
|
632
|
-
return false;
|
|
633
|
-
}
|
|
634
|
-
const keys = Object.keys(obj);
|
|
635
|
-
if (keys.length === 0) {
|
|
636
|
-
return false;
|
|
637
|
-
}
|
|
638
|
-
return keys.every((key) => {
|
|
639
|
-
if (key === "text") return true;
|
|
640
|
-
return /^[a-zA-Z][a-zA-Z0-9-]*$/.test(key);
|
|
641
|
-
});
|
|
642
|
-
}
|
|
643
|
-
function extractProps(coherentObj) {
|
|
644
|
-
if (!isCoherentObject(coherentObj)) {
|
|
645
|
-
return {};
|
|
646
|
-
}
|
|
647
|
-
const props = {};
|
|
648
|
-
const keys = Object.keys(coherentObj);
|
|
649
|
-
keys.forEach((tag) => {
|
|
650
|
-
const value = coherentObj[tag];
|
|
651
|
-
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
652
|
-
props[tag] = { ...value };
|
|
653
|
-
} else {
|
|
654
|
-
props[tag] = { text: value };
|
|
655
|
-
}
|
|
656
|
-
});
|
|
657
|
-
return props;
|
|
658
|
-
}
|
|
659
|
-
function hasChildren(component) {
|
|
660
|
-
if (Array.isArray(component)) {
|
|
661
|
-
return component.length > 0;
|
|
662
|
-
}
|
|
663
|
-
if (isCoherentObject(component)) {
|
|
664
|
-
if (component.children !== void 0 && component.children !== null) {
|
|
665
|
-
return Array.isArray(component.children) ? component.children.length > 0 : true;
|
|
666
|
-
}
|
|
667
|
-
const keys = Object.keys(component);
|
|
668
|
-
return keys.some((key) => {
|
|
669
|
-
const value = component[key];
|
|
670
|
-
return value && typeof value === "object" && value.children;
|
|
671
|
-
});
|
|
672
|
-
}
|
|
673
|
-
return false;
|
|
674
|
-
}
|
|
675
|
-
function normalizeChildren(children) {
|
|
676
|
-
if (children === null || children === void 0) {
|
|
677
|
-
return [];
|
|
678
|
-
}
|
|
679
|
-
if (Array.isArray(children)) {
|
|
680
|
-
return children.flat().filter((child) => child !== null && child !== void 0);
|
|
681
|
-
}
|
|
682
|
-
return [children];
|
|
683
|
-
}
|
|
684
|
-
|
|
685
|
-
// ../core/src/components/component-system.js
|
|
686
|
-
var COMPONENT_METADATA = /* @__PURE__ */ new WeakMap();
|
|
687
|
-
var ComponentState = class {
|
|
688
|
-
constructor(initialState = {}) {
|
|
689
|
-
this.state = { ...initialState };
|
|
690
|
-
this.listeners = /* @__PURE__ */ new Set();
|
|
691
|
-
this.isUpdating = false;
|
|
692
|
-
}
|
|
693
|
-
/**
|
|
694
|
-
* Get state value by key or entire state
|
|
695
|
-
*
|
|
696
|
-
* @param {string} [key] - State key to retrieve
|
|
697
|
-
* @returns {*} State value or entire state object
|
|
698
|
-
*/
|
|
699
|
-
get(key) {
|
|
700
|
-
return key ? this.state[key] : { ...this.state };
|
|
701
|
-
}
|
|
702
|
-
/**
|
|
703
|
-
* Update state with new values
|
|
704
|
-
*
|
|
705
|
-
* @param {Object} updates - State updates to apply
|
|
706
|
-
* @returns {ComponentState} This instance for chaining
|
|
707
|
-
*/
|
|
708
|
-
set(updates) {
|
|
709
|
-
if (this.isUpdating) return this;
|
|
710
|
-
const oldState = { ...this.state };
|
|
711
|
-
if (typeof updates === "function") {
|
|
712
|
-
updates = updates(oldState);
|
|
713
|
-
}
|
|
714
|
-
this.state = { ...this.state, ...updates };
|
|
715
|
-
this.notifyListeners(oldState, this.state);
|
|
716
|
-
return this;
|
|
717
|
-
}
|
|
718
|
-
subscribe(listener) {
|
|
719
|
-
this.listeners.add(listener);
|
|
720
|
-
return () => this.listeners.delete(listener);
|
|
721
|
-
}
|
|
722
|
-
notifyListeners(oldState, newState) {
|
|
723
|
-
if (this.listeners.size === 0) return;
|
|
724
|
-
this.isUpdating = true;
|
|
725
|
-
this.listeners.forEach((listener) => {
|
|
726
|
-
try {
|
|
727
|
-
listener(newState, oldState);
|
|
728
|
-
} catch (_error) {
|
|
729
|
-
console.error("State listener _error:", _error);
|
|
730
|
-
}
|
|
731
|
-
});
|
|
732
|
-
this.isUpdating = false;
|
|
733
|
-
}
|
|
734
|
-
};
|
|
735
|
-
var Component = class _Component {
|
|
736
|
-
constructor(definition = {}) {
|
|
737
|
-
this.definition = definition;
|
|
738
|
-
this.name = definition.name || "AnonymousComponent";
|
|
739
|
-
this.props = {};
|
|
740
|
-
this.state = new ComponentState(definition.state || {});
|
|
741
|
-
this.children = [];
|
|
742
|
-
this.parent = null;
|
|
743
|
-
this.rendered = null;
|
|
744
|
-
this.isMounted = false;
|
|
745
|
-
this.isDestroyed = false;
|
|
746
|
-
this.hooks = {
|
|
747
|
-
beforeCreate: definition.beforeCreate || (() => {
|
|
748
|
-
}),
|
|
749
|
-
created: definition.created || (() => {
|
|
750
|
-
}),
|
|
751
|
-
beforeMount: definition.beforeMount || (() => {
|
|
752
|
-
}),
|
|
753
|
-
mounted: definition.mounted || (() => {
|
|
754
|
-
}),
|
|
755
|
-
beforeUpdate: definition.beforeUpdate || (() => {
|
|
756
|
-
}),
|
|
757
|
-
updated: definition.updated || (() => {
|
|
758
|
-
}),
|
|
759
|
-
beforeDestroy: definition.beforeDestroy || (() => {
|
|
760
|
-
}),
|
|
761
|
-
destroyed: definition.destroyed || (() => {
|
|
762
|
-
}),
|
|
763
|
-
errorCaptured: definition.errorCaptured || (() => {
|
|
764
|
-
})
|
|
765
|
-
};
|
|
766
|
-
this.methods = definition.methods || {};
|
|
767
|
-
Object.keys(this.methods).forEach((methodName) => {
|
|
768
|
-
if (typeof this.methods[methodName] === "function") {
|
|
769
|
-
this[methodName] = this.methods[methodName].bind(this);
|
|
770
|
-
}
|
|
771
|
-
});
|
|
772
|
-
this.computed = definition.computed || {};
|
|
773
|
-
this.computedCache = /* @__PURE__ */ new Map();
|
|
774
|
-
this.watchers = definition.watch || {};
|
|
775
|
-
this.setupWatchers();
|
|
776
|
-
COMPONENT_METADATA.set(this, {
|
|
777
|
-
createdAt: Date.now(),
|
|
778
|
-
updateCount: 0,
|
|
779
|
-
renderCount: 0
|
|
780
|
-
});
|
|
781
|
-
this.callHook("beforeCreate");
|
|
782
|
-
this.initialize();
|
|
783
|
-
this.callHook("created");
|
|
784
|
-
}
|
|
785
|
-
/**
|
|
786
|
-
* Initialize component
|
|
787
|
-
*/
|
|
788
|
-
initialize() {
|
|
789
|
-
this.unsubscribeState = this.state.subscribe((newState, oldState) => {
|
|
790
|
-
this.onStateChange(newState, oldState);
|
|
791
|
-
});
|
|
792
|
-
this.initializeComputed();
|
|
793
|
-
}
|
|
794
|
-
/**
|
|
795
|
-
* Set up watchers for reactive data
|
|
796
|
-
*/
|
|
797
|
-
setupWatchers() {
|
|
798
|
-
Object.keys(this.watchers).forEach((key) => {
|
|
799
|
-
const handler = this.watchers[key];
|
|
800
|
-
this.state.subscribe((newState, oldState) => {
|
|
801
|
-
if (newState[key] !== oldState[key]) {
|
|
802
|
-
handler.call(this, newState[key], oldState[key]);
|
|
803
|
-
}
|
|
804
|
-
});
|
|
805
|
-
});
|
|
806
|
-
}
|
|
807
|
-
/**
|
|
808
|
-
* Initialize computed properties
|
|
809
|
-
*/
|
|
810
|
-
initializeComputed() {
|
|
811
|
-
Object.keys(this.computed).forEach((key) => {
|
|
812
|
-
Object.defineProperty(this, key, {
|
|
813
|
-
get: () => {
|
|
814
|
-
if (!this.computedCache.has(key)) {
|
|
815
|
-
const value = this.computed[key].call(this);
|
|
816
|
-
this.computedCache.set(key, value);
|
|
817
|
-
}
|
|
818
|
-
return this.computedCache.get(key);
|
|
819
|
-
},
|
|
820
|
-
enumerable: true
|
|
821
|
-
});
|
|
822
|
-
});
|
|
823
|
-
}
|
|
824
|
-
/**
|
|
825
|
-
* Handle state changes
|
|
826
|
-
*/
|
|
827
|
-
onStateChange() {
|
|
828
|
-
if (this.isDestroyed) return;
|
|
829
|
-
this.computedCache.clear();
|
|
830
|
-
if (this.isMounted) {
|
|
831
|
-
this.update();
|
|
832
|
-
}
|
|
833
|
-
}
|
|
834
|
-
/**
|
|
835
|
-
* Call lifecycle hook
|
|
836
|
-
*/
|
|
837
|
-
callHook(hookName, ...args) {
|
|
838
|
-
try {
|
|
839
|
-
if (this.hooks[hookName]) {
|
|
840
|
-
return this.hooks[hookName].call(this, ...args);
|
|
841
|
-
}
|
|
842
|
-
} catch (_error) {
|
|
843
|
-
this.handleError(_error, `${hookName} hook`);
|
|
844
|
-
}
|
|
845
|
-
}
|
|
846
|
-
/**
|
|
847
|
-
* Handle component errors
|
|
848
|
-
*/
|
|
849
|
-
handleError(_error) {
|
|
850
|
-
console.error(`Component Error in ${this.name}:`, _error);
|
|
851
|
-
this.callHook("errorCaptured", _error);
|
|
852
|
-
if (this.parent && this.parent.handleError) {
|
|
853
|
-
this.parent.handleError(_error, `${this.name} -> ${context}`);
|
|
854
|
-
}
|
|
855
|
-
}
|
|
856
|
-
/**
|
|
857
|
-
* Render the component
|
|
858
|
-
*/
|
|
859
|
-
render(props = {}) {
|
|
860
|
-
if (this.isDestroyed) {
|
|
861
|
-
console.warn(`Attempting to render destroyed component: ${this.name}`);
|
|
862
|
-
return null;
|
|
863
|
-
}
|
|
864
|
-
try {
|
|
865
|
-
const metadata = COMPONENT_METADATA.get(this);
|
|
866
|
-
if (metadata) {
|
|
867
|
-
metadata.renderCount++;
|
|
868
|
-
}
|
|
869
|
-
this.props = { ...props };
|
|
870
|
-
if (typeof this.definition.render === "function") {
|
|
871
|
-
this.rendered = this.definition.render.call(this, this.props, this.state.get());
|
|
872
|
-
} else if (typeof this.definition.template !== "undefined") {
|
|
873
|
-
this.rendered = this.processTemplate(this.definition.template, this.props, this.state.get());
|
|
874
|
-
} else {
|
|
875
|
-
throw new Error(`Component ${this.name} must have either render method or template`);
|
|
876
|
-
}
|
|
877
|
-
if (this.rendered !== null) {
|
|
878
|
-
validateComponent(this.rendered, this.name);
|
|
879
|
-
}
|
|
880
|
-
return this.rendered;
|
|
881
|
-
} catch (_error) {
|
|
882
|
-
this.handleError(_error);
|
|
883
|
-
return { div: { className: "component-_error", text: `Error in ${this.name}` } };
|
|
884
|
-
}
|
|
885
|
-
}
|
|
886
|
-
/**
|
|
887
|
-
* Process template with data
|
|
888
|
-
*/
|
|
889
|
-
processTemplate(template, props, state) {
|
|
890
|
-
if (typeof template === "function") {
|
|
891
|
-
return template.call(this, props, state);
|
|
892
|
-
}
|
|
893
|
-
if (typeof template === "string") {
|
|
894
|
-
return template.replace(/\{\{(\w+)\}\}/g, (match, key) => {
|
|
895
|
-
return props[key] || state[key] || "";
|
|
896
|
-
});
|
|
897
|
-
}
|
|
898
|
-
const processed = deepClone(template);
|
|
899
|
-
this.interpolateObject(processed, { ...props, ...state });
|
|
900
|
-
return processed;
|
|
901
|
-
}
|
|
902
|
-
/**
|
|
903
|
-
* Interpolate object with data
|
|
904
|
-
*/
|
|
905
|
-
interpolateObject(obj, data) {
|
|
906
|
-
if (typeof obj === "string") {
|
|
907
|
-
return obj.replace(/\{\{(\w+)\}\}/g, (match, key) => data[key] || "");
|
|
908
|
-
}
|
|
909
|
-
if (Array.isArray(obj)) {
|
|
910
|
-
return obj.map((item) => this.interpolateObject(item, data));
|
|
911
|
-
}
|
|
912
|
-
if (obj && typeof obj === "object") {
|
|
913
|
-
Object.keys(obj).forEach((key) => {
|
|
914
|
-
obj[key] = this.interpolateObject(obj[key], data);
|
|
915
|
-
});
|
|
916
|
-
}
|
|
917
|
-
return obj;
|
|
918
|
-
}
|
|
919
|
-
/**
|
|
920
|
-
* Mount the component
|
|
921
|
-
*/
|
|
922
|
-
mount() {
|
|
923
|
-
if (this.isMounted || this.isDestroyed) return this;
|
|
924
|
-
this.callHook("beforeMount");
|
|
925
|
-
this.isMounted = true;
|
|
926
|
-
this.callHook("mounted");
|
|
927
|
-
return this;
|
|
928
|
-
}
|
|
929
|
-
/**
|
|
930
|
-
* Update the component
|
|
931
|
-
*/
|
|
932
|
-
update() {
|
|
933
|
-
if (!this.isMounted || this.isDestroyed) return this;
|
|
934
|
-
const metadata = COMPONENT_METADATA.get(this);
|
|
935
|
-
if (metadata) {
|
|
936
|
-
metadata.updateCount++;
|
|
937
|
-
}
|
|
938
|
-
this.callHook("beforeUpdate");
|
|
939
|
-
this.callHook("updated");
|
|
940
|
-
return this;
|
|
941
|
-
}
|
|
942
|
-
/**
|
|
943
|
-
* Destroy the component
|
|
944
|
-
*/
|
|
945
|
-
destroy() {
|
|
946
|
-
if (this.isDestroyed) return this;
|
|
947
|
-
this.callHook("beforeDestroy");
|
|
948
|
-
if (this.unsubscribeState) {
|
|
949
|
-
this.unsubscribeState();
|
|
950
|
-
}
|
|
951
|
-
this.children.forEach((child) => {
|
|
952
|
-
if (child.destroy) {
|
|
953
|
-
child.destroy();
|
|
954
|
-
}
|
|
955
|
-
});
|
|
956
|
-
this.isMounted = false;
|
|
957
|
-
this.isDestroyed = true;
|
|
958
|
-
this.children = [];
|
|
959
|
-
this.parent = null;
|
|
960
|
-
this.callHook("destroyed");
|
|
961
|
-
return this;
|
|
962
|
-
}
|
|
963
|
-
/**
|
|
964
|
-
* Get component metadata
|
|
965
|
-
*/
|
|
966
|
-
getMetadata() {
|
|
967
|
-
return COMPONENT_METADATA.get(this) || {};
|
|
968
|
-
}
|
|
969
|
-
/**
|
|
970
|
-
* Clone component with new props/state
|
|
971
|
-
*/
|
|
972
|
-
clone(overrides = {}) {
|
|
973
|
-
const newDefinition = { ...this.definition, ...overrides };
|
|
974
|
-
return new _Component(newDefinition);
|
|
975
|
-
}
|
|
976
|
-
};
|
|
977
|
-
if (performanceMonitor2) {
|
|
978
|
-
const originalRender = Component.prototype.render;
|
|
979
|
-
Component.prototype.render = function(...args) {
|
|
980
|
-
const start = performance.now();
|
|
981
|
-
const result = originalRender.apply(this, args);
|
|
982
|
-
const duration = performance.now() - start;
|
|
983
|
-
performanceMonitor2.recordMetric("renderTime", duration, {
|
|
984
|
-
type: "component",
|
|
985
|
-
name: this.name,
|
|
986
|
-
propsSize: JSON.stringify(this.props || {}).length,
|
|
987
|
-
hasState: Object.keys(this.state?.get() || {}).length > 0
|
|
988
|
-
});
|
|
989
|
-
return result;
|
|
990
|
-
};
|
|
991
|
-
}
|
|
992
|
-
|
|
993
|
-
// ../core/src/utils/error-handler.js
|
|
994
|
-
var CoherentError = class _CoherentError extends Error {
|
|
995
|
-
constructor(message, options = {}) {
|
|
996
|
-
super(message);
|
|
997
|
-
this.name = "CoherentError";
|
|
998
|
-
this.type = options.type || "generic";
|
|
999
|
-
this.component = options.component;
|
|
1000
|
-
this.context = options.context;
|
|
1001
|
-
this.suggestions = options.suggestions || [];
|
|
1002
|
-
this.timestamp = Date.now();
|
|
1003
|
-
if (Error.captureStackTrace) {
|
|
1004
|
-
Error.captureStackTrace(this, _CoherentError);
|
|
1005
|
-
}
|
|
1006
|
-
}
|
|
1007
|
-
toJSON() {
|
|
1008
|
-
return {
|
|
1009
|
-
name: this.name,
|
|
1010
|
-
message: this.message,
|
|
1011
|
-
type: this.type,
|
|
1012
|
-
component: this.component,
|
|
1013
|
-
context: this.context,
|
|
1014
|
-
suggestions: this.suggestions,
|
|
1015
|
-
timestamp: this.timestamp,
|
|
1016
|
-
stack: this.stack
|
|
1017
|
-
};
|
|
1018
|
-
}
|
|
1019
|
-
};
|
|
1020
|
-
var ComponentValidationError = class extends CoherentError {
|
|
1021
|
-
constructor(message, component, suggestions = []) {
|
|
1022
|
-
super(message, {
|
|
1023
|
-
type: "validation",
|
|
1024
|
-
component,
|
|
1025
|
-
suggestions: [
|
|
1026
|
-
"Check component structure and syntax",
|
|
1027
|
-
"Ensure all required properties are present",
|
|
1028
|
-
"Validate prop types and values",
|
|
1029
|
-
...suggestions
|
|
1030
|
-
]
|
|
1031
|
-
});
|
|
1032
|
-
this.name = "ComponentValidationError";
|
|
1033
|
-
}
|
|
1034
|
-
};
|
|
1035
|
-
var RenderingError = class extends CoherentError {
|
|
1036
|
-
constructor(message, component, context2, suggestions = []) {
|
|
1037
|
-
super(message, {
|
|
1038
|
-
type: "rendering",
|
|
1039
|
-
component,
|
|
1040
|
-
context: context2,
|
|
1041
|
-
suggestions: [
|
|
1042
|
-
"Check for circular references",
|
|
1043
|
-
"Validate component depth",
|
|
1044
|
-
"Ensure all functions return valid components",
|
|
1045
|
-
...suggestions
|
|
1046
|
-
]
|
|
1047
|
-
});
|
|
1048
|
-
this.name = "RenderingError";
|
|
1049
|
-
}
|
|
1050
|
-
};
|
|
1051
|
-
var PerformanceError = class extends CoherentError {
|
|
1052
|
-
constructor(message, metrics, suggestions = []) {
|
|
1053
|
-
super(message, {
|
|
1054
|
-
type: "performance",
|
|
1055
|
-
context: metrics,
|
|
1056
|
-
suggestions: [
|
|
1057
|
-
"Consider component memoization",
|
|
1058
|
-
"Reduce component complexity",
|
|
1059
|
-
"Enable caching",
|
|
1060
|
-
...suggestions
|
|
1061
|
-
]
|
|
1062
|
-
});
|
|
1063
|
-
this.name = "PerformanceError";
|
|
1064
|
-
}
|
|
1065
|
-
};
|
|
1066
|
-
var StateError = class extends CoherentError {
|
|
1067
|
-
constructor(message, state, suggestions = []) {
|
|
1068
|
-
super(message, {
|
|
1069
|
-
type: "state",
|
|
1070
|
-
context: state,
|
|
1071
|
-
suggestions: [
|
|
1072
|
-
"Check state mutations",
|
|
1073
|
-
"Ensure proper state initialization",
|
|
1074
|
-
"Validate state transitions",
|
|
1075
|
-
...suggestions
|
|
1076
|
-
]
|
|
1077
|
-
});
|
|
1078
|
-
this.name = "StateError";
|
|
1079
|
-
}
|
|
1080
|
-
};
|
|
1081
|
-
var ErrorHandler = class {
|
|
1082
|
-
constructor(options = {}) {
|
|
1083
|
-
this.options = {
|
|
1084
|
-
enableStackTrace: options.enableStackTrace !== false,
|
|
1085
|
-
enableSuggestions: options.enableSuggestions !== false,
|
|
1086
|
-
enableLogging: options.enableLogging !== false,
|
|
1087
|
-
logLevel: options.logLevel || "_error",
|
|
1088
|
-
maxErrorHistory: options.maxErrorHistory || 100,
|
|
1089
|
-
...options
|
|
1090
|
-
};
|
|
1091
|
-
this.errorHistory = [];
|
|
1092
|
-
this.errorCounts = /* @__PURE__ */ new Map();
|
|
1093
|
-
this.suppressedErrors = /* @__PURE__ */ new Set();
|
|
1094
|
-
}
|
|
1095
|
-
/**
|
|
1096
|
-
* Handle and report errors with detailed context
|
|
1097
|
-
*/
|
|
1098
|
-
handle(_error, context2 = {}) {
|
|
1099
|
-
const enhancedError = this.enhanceError(_error, context2);
|
|
1100
|
-
this.addToHistory(enhancedError);
|
|
1101
|
-
if (this.options.enableLogging) {
|
|
1102
|
-
this.logError(enhancedError);
|
|
1103
|
-
}
|
|
1104
|
-
return enhancedError;
|
|
1105
|
-
}
|
|
1106
|
-
/**
|
|
1107
|
-
* Enhance existing errors with more context
|
|
1108
|
-
*/
|
|
1109
|
-
enhanceError(_error, context2 = {}) {
|
|
1110
|
-
if (_error instanceof CoherentError) {
|
|
1111
|
-
return _error;
|
|
1112
|
-
}
|
|
1113
|
-
const errorType = this.classifyError(_error, context2);
|
|
1114
|
-
switch (errorType) {
|
|
1115
|
-
case "validation":
|
|
1116
|
-
return new ComponentValidationError(
|
|
1117
|
-
_error.message,
|
|
1118
|
-
context2.component,
|
|
1119
|
-
this.generateSuggestions(_error, context2)
|
|
1120
|
-
);
|
|
1121
|
-
case "rendering":
|
|
1122
|
-
return new RenderingError(
|
|
1123
|
-
_error.message,
|
|
1124
|
-
context2.component,
|
|
1125
|
-
context2.renderContext,
|
|
1126
|
-
this.generateSuggestions(_error, context2)
|
|
1127
|
-
);
|
|
1128
|
-
case "performance":
|
|
1129
|
-
return new PerformanceError(
|
|
1130
|
-
_error.message,
|
|
1131
|
-
context2.metrics,
|
|
1132
|
-
this.generateSuggestions(_error, context2)
|
|
1133
|
-
);
|
|
1134
|
-
case "state":
|
|
1135
|
-
return new StateError(
|
|
1136
|
-
_error.message,
|
|
1137
|
-
context2.state,
|
|
1138
|
-
this.generateSuggestions(_error, context2)
|
|
1139
|
-
);
|
|
1140
|
-
default:
|
|
1141
|
-
return new CoherentError(_error.message, {
|
|
1142
|
-
type: errorType,
|
|
1143
|
-
component: context2.component,
|
|
1144
|
-
context: context2.context,
|
|
1145
|
-
suggestions: this.generateSuggestions(_error, context2)
|
|
1146
|
-
});
|
|
1147
|
-
}
|
|
1148
|
-
}
|
|
1149
|
-
/**
|
|
1150
|
-
* Classify _error type based on message and context
|
|
1151
|
-
*/
|
|
1152
|
-
classifyError(_error, context2) {
|
|
1153
|
-
const message = _error.message.toLowerCase();
|
|
1154
|
-
if (message.includes("invalid") || message.includes("validation") || message.includes("required") || message.includes("type")) {
|
|
1155
|
-
return "validation";
|
|
1156
|
-
}
|
|
1157
|
-
if (message.includes("render") || message.includes("circular") || message.includes("depth") || message.includes("cannot render")) {
|
|
1158
|
-
return "rendering";
|
|
1159
|
-
}
|
|
1160
|
-
if (message.includes("slow") || message.includes("memory") || message.includes("performance") || message.includes("timeout")) {
|
|
1161
|
-
return "performance";
|
|
1162
|
-
}
|
|
1163
|
-
if (message.includes("state") || message.includes("mutation") || message.includes("store") || context2.state) {
|
|
1164
|
-
return "state";
|
|
1165
|
-
}
|
|
1166
|
-
if (context2.component) return "validation";
|
|
1167
|
-
if (context2.renderContext) return "rendering";
|
|
1168
|
-
if (context2.metrics) return "performance";
|
|
1169
|
-
return "generic";
|
|
1170
|
-
}
|
|
1171
|
-
/**
|
|
1172
|
-
* Generate helpful suggestions based on _error
|
|
1173
|
-
*/
|
|
1174
|
-
generateSuggestions(_error, context2 = {}) {
|
|
1175
|
-
const suggestions = [];
|
|
1176
|
-
const message = _error.message.toLowerCase();
|
|
1177
|
-
const patterns = [
|
|
1178
|
-
{
|
|
1179
|
-
pattern: /cannot render|render.*failed/,
|
|
1180
|
-
suggestions: [
|
|
1181
|
-
"Check if component returns a valid object structure",
|
|
1182
|
-
"Ensure all properties are properly defined",
|
|
1183
|
-
"Look for undefined variables or null references"
|
|
1184
|
-
]
|
|
1185
|
-
},
|
|
1186
|
-
{
|
|
1187
|
-
pattern: /circular.*reference/,
|
|
1188
|
-
suggestions: [
|
|
1189
|
-
"Remove circular references between components",
|
|
1190
|
-
"Use lazy loading or memoization to break cycles",
|
|
1191
|
-
"Check for self-referencing components"
|
|
1192
|
-
]
|
|
1193
|
-
},
|
|
1194
|
-
{
|
|
1195
|
-
pattern: /maximum.*depth/,
|
|
1196
|
-
suggestions: [
|
|
1197
|
-
"Reduce component nesting depth",
|
|
1198
|
-
"Break complex components into smaller parts",
|
|
1199
|
-
"Check for infinite recursion in component functions"
|
|
1200
|
-
]
|
|
1201
|
-
},
|
|
1202
|
-
{
|
|
1203
|
-
pattern: /invalid.*component/,
|
|
1204
|
-
suggestions: [
|
|
1205
|
-
"Ensure component follows the expected object structure",
|
|
1206
|
-
"Check property names and values for typos",
|
|
1207
|
-
"Verify component is not null or undefined"
|
|
1208
|
-
]
|
|
1209
|
-
},
|
|
1210
|
-
{
|
|
1211
|
-
pattern: /performance|slow|timeout/,
|
|
1212
|
-
suggestions: [
|
|
1213
|
-
"Enable component caching",
|
|
1214
|
-
"Use memoization for expensive operations",
|
|
1215
|
-
"Reduce component complexity",
|
|
1216
|
-
"Consider lazy loading for large components"
|
|
1217
|
-
]
|
|
1218
|
-
}
|
|
1219
|
-
];
|
|
1220
|
-
patterns.forEach(({ pattern, suggestions: patternSuggestions }) => {
|
|
1221
|
-
if (pattern.test(message)) {
|
|
1222
|
-
suggestions.push(...patternSuggestions);
|
|
1223
|
-
}
|
|
1224
|
-
});
|
|
1225
|
-
if (context2.component) {
|
|
1226
|
-
const componentType = typeof context2.component;
|
|
1227
|
-
if (componentType === "function") {
|
|
1228
|
-
suggestions.push("Check function component return value");
|
|
1229
|
-
} else if (componentType === "object" && context2.component === null) {
|
|
1230
|
-
suggestions.push("Component is null - ensure proper initialization");
|
|
1231
|
-
} else if (Array.isArray(context2.component)) {
|
|
1232
|
-
suggestions.push("Arrays should contain valid component objects");
|
|
1233
|
-
}
|
|
1234
|
-
}
|
|
1235
|
-
if (suggestions.length === 0) {
|
|
1236
|
-
suggestions.push(
|
|
1237
|
-
"Enable development tools for more detailed debugging",
|
|
1238
|
-
"Check browser console for additional _error details",
|
|
1239
|
-
"Use component validation tools to identify issues"
|
|
1240
|
-
);
|
|
1241
|
-
}
|
|
1242
|
-
return [...new Set(suggestions)];
|
|
1243
|
-
}
|
|
1244
|
-
/**
|
|
1245
|
-
* Add _error to history with deduplication
|
|
1246
|
-
*/
|
|
1247
|
-
addToHistory(_error) {
|
|
1248
|
-
const errorKey = `${_error.name}:${_error.message}`;
|
|
1249
|
-
this.errorCounts.set(errorKey, (this.errorCounts.get(errorKey) || 0) + 1);
|
|
1250
|
-
const historyEntry = {
|
|
1251
|
-
..._error.toJSON(),
|
|
1252
|
-
count: this.errorCounts.get(errorKey),
|
|
1253
|
-
firstSeen: this.errorHistory.find((e) => e.key === errorKey)?.firstSeen || _error.timestamp,
|
|
1254
|
-
key: errorKey
|
|
1255
|
-
};
|
|
1256
|
-
this.errorHistory = this.errorHistory.filter((e) => e.key !== errorKey);
|
|
1257
|
-
this.errorHistory.unshift(historyEntry);
|
|
1258
|
-
if (this.errorHistory.length > this.options.maxErrorHistory) {
|
|
1259
|
-
this.errorHistory = this.errorHistory.slice(0, this.options.maxErrorHistory);
|
|
1260
|
-
}
|
|
1261
|
-
}
|
|
1262
|
-
/**
|
|
1263
|
-
* Log _error with enhanced formatting
|
|
1264
|
-
*/
|
|
1265
|
-
logError(_error) {
|
|
1266
|
-
if (this.suppressedErrors.has(`${_error.name}:${_error.message}`)) {
|
|
1267
|
-
return;
|
|
1268
|
-
}
|
|
1269
|
-
const isRepeated = this.errorCounts.get(`${_error.name}:${_error.message}`) > 1;
|
|
1270
|
-
const errorGroup = `\u{1F6A8} ${_error.name}${isRepeated ? ` (\xD7${this.errorCounts.get(`${_error.name}:${_error.message}`)})` : ""}`;
|
|
1271
|
-
console.group(errorGroup);
|
|
1272
|
-
console.error(`\u274C ${_error.message}`);
|
|
1273
|
-
if (_error.component) {
|
|
1274
|
-
console.log("\u{1F50D} Component:", this.formatComponent(_error.component));
|
|
1275
|
-
}
|
|
1276
|
-
if (_error.context) {
|
|
1277
|
-
console.log("\u{1F4CB} Context:", _error.context);
|
|
1278
|
-
}
|
|
1279
|
-
if (this.options.enableSuggestions && _error.suggestions.length > 0) {
|
|
1280
|
-
console.group("\u{1F4A1} Suggestions:");
|
|
1281
|
-
_error.suggestions.forEach((suggestion, index) => {
|
|
1282
|
-
console.log(`${index + 1}. ${suggestion}`);
|
|
1283
|
-
});
|
|
1284
|
-
console.groupEnd();
|
|
1285
|
-
}
|
|
1286
|
-
if (this.options.enableStackTrace && _error.stack) {
|
|
1287
|
-
console.log("\u{1F4DA} Stack trace:", _error.stack);
|
|
1288
|
-
}
|
|
1289
|
-
console.groupEnd();
|
|
1290
|
-
}
|
|
1291
|
-
/**
|
|
1292
|
-
* Format component for logging
|
|
1293
|
-
*/
|
|
1294
|
-
formatComponent(component, maxDepth = 2, currentDepth = 0) {
|
|
1295
|
-
if (currentDepth > maxDepth) {
|
|
1296
|
-
return "[...deep]";
|
|
1297
|
-
}
|
|
1298
|
-
if (typeof component === "function") {
|
|
1299
|
-
return `[Function: ${component.name || "anonymous"}]`;
|
|
1300
|
-
}
|
|
1301
|
-
if (Array.isArray(component)) {
|
|
1302
|
-
return component.slice(0, 3).map(
|
|
1303
|
-
(item) => this.formatComponent(item, maxDepth, currentDepth + 1)
|
|
1304
|
-
);
|
|
1305
|
-
}
|
|
1306
|
-
if (component && typeof component === "object") {
|
|
1307
|
-
const formatted = {};
|
|
1308
|
-
const keys = Object.keys(component).slice(0, 5);
|
|
1309
|
-
for (const key of keys) {
|
|
1310
|
-
if (key === "children" && component[key]) {
|
|
1311
|
-
formatted[key] = this.formatComponent(component[key], maxDepth, currentDepth + 1);
|
|
1312
|
-
} else {
|
|
1313
|
-
formatted[key] = component[key];
|
|
1314
|
-
}
|
|
1315
|
-
}
|
|
1316
|
-
if (Object.keys(component).length > 5) {
|
|
1317
|
-
formatted["..."] = `(${Object.keys(component).length - 5} more)`;
|
|
1318
|
-
}
|
|
1319
|
-
return formatted;
|
|
1320
|
-
}
|
|
1321
|
-
return component;
|
|
1322
|
-
}
|
|
1323
|
-
/**
|
|
1324
|
-
* Suppress specific _error types
|
|
1325
|
-
*/
|
|
1326
|
-
suppress(errorPattern) {
|
|
1327
|
-
this.suppressedErrors.add(errorPattern);
|
|
1328
|
-
}
|
|
1329
|
-
/**
|
|
1330
|
-
* Clear _error history
|
|
1331
|
-
*/
|
|
1332
|
-
clearHistory() {
|
|
1333
|
-
this.errorHistory = [];
|
|
1334
|
-
this.errorCounts.clear();
|
|
1335
|
-
}
|
|
1336
|
-
/**
|
|
1337
|
-
* Get _error statistics
|
|
1338
|
-
*/
|
|
1339
|
-
getStats() {
|
|
1340
|
-
const errorsByType = {};
|
|
1341
|
-
const errorsByTime = {};
|
|
1342
|
-
this.errorHistory.forEach((_error) => {
|
|
1343
|
-
errorsByType[_error.type] = (errorsByType[_error.type] || 0) + _error.count;
|
|
1344
|
-
const hour = new Date(_error.timestamp).toISOString().slice(0, 13);
|
|
1345
|
-
errorsByTime[hour] = (errorsByTime[hour] || 0) + _error.count;
|
|
1346
|
-
});
|
|
1347
|
-
return {
|
|
1348
|
-
totalErrors: this.errorHistory.reduce((sum, e) => sum + e.count, 0),
|
|
1349
|
-
uniqueErrors: this.errorHistory.length,
|
|
1350
|
-
errorsByType,
|
|
1351
|
-
errorsByTime,
|
|
1352
|
-
mostCommonErrors: this.getMostCommonErrors(5),
|
|
1353
|
-
recentErrors: this.errorHistory.slice(0, 10)
|
|
1354
|
-
};
|
|
1355
|
-
}
|
|
1356
|
-
/**
|
|
1357
|
-
* Get most common errors
|
|
1358
|
-
*/
|
|
1359
|
-
getMostCommonErrors(limit = 10) {
|
|
1360
|
-
return this.errorHistory.sort((a, b) => b.count - a.count).slice(0, limit).map(({ name, message, count, type }) => ({
|
|
1361
|
-
name,
|
|
1362
|
-
message,
|
|
1363
|
-
count,
|
|
1364
|
-
type
|
|
1365
|
-
}));
|
|
1366
|
-
}
|
|
1367
|
-
};
|
|
1368
|
-
var globalErrorHandler = new ErrorHandler();
|
|
1369
|
-
|
|
1370
|
-
// ../core/src/components/lifecycle.js
|
|
1371
|
-
var LIFECYCLE_PHASES = {
|
|
1372
|
-
BEFORE_CREATE: "beforeCreate",
|
|
1373
|
-
CREATED: "created",
|
|
1374
|
-
BEFORE_MOUNT: "beforeMount",
|
|
1375
|
-
MOUNTED: "mounted",
|
|
1376
|
-
BEFORE_UPDATE: "beforeUpdate",
|
|
1377
|
-
UPDATED: "updated",
|
|
1378
|
-
BEFORE_UNMOUNT: "beforeUnmount",
|
|
1379
|
-
UNMOUNTED: "unmounted",
|
|
1380
|
-
ERROR: "_error"
|
|
1381
|
-
};
|
|
1382
|
-
var componentInstances = /* @__PURE__ */ new WeakMap();
|
|
1383
|
-
var ComponentEventSystem = class {
|
|
1384
|
-
constructor() {
|
|
1385
|
-
this.events = /* @__PURE__ */ new Map();
|
|
1386
|
-
this.globalHandlers = /* @__PURE__ */ new Map();
|
|
1387
|
-
}
|
|
1388
|
-
/**
|
|
1389
|
-
* Emit event to component or globally
|
|
1390
|
-
*/
|
|
1391
|
-
emit(eventName, data = {}, target = null) {
|
|
1392
|
-
const event = {
|
|
1393
|
-
name: eventName,
|
|
1394
|
-
data,
|
|
1395
|
-
target,
|
|
1396
|
-
timestamp: Date.now(),
|
|
1397
|
-
stopped: false,
|
|
1398
|
-
preventDefault: false
|
|
1399
|
-
};
|
|
1400
|
-
if (target) {
|
|
1401
|
-
const instance = componentInstances.get(target);
|
|
1402
|
-
if (instance) {
|
|
1403
|
-
this._notifyHandlers(instance.id, event);
|
|
1404
|
-
}
|
|
1405
|
-
} else {
|
|
1406
|
-
this._notifyGlobalHandlers(event);
|
|
1407
|
-
}
|
|
1408
|
-
return event;
|
|
1409
|
-
}
|
|
1410
|
-
/**
|
|
1411
|
-
* Listen for events on component or globally
|
|
1412
|
-
*/
|
|
1413
|
-
on(eventName, handler, componentId = null) {
|
|
1414
|
-
if (componentId) {
|
|
1415
|
-
if (!this.events.has(componentId)) {
|
|
1416
|
-
this.events.set(componentId, /* @__PURE__ */ new Map());
|
|
1417
|
-
}
|
|
1418
|
-
const componentEvents = this.events.get(componentId);
|
|
1419
|
-
if (!componentEvents.has(eventName)) {
|
|
1420
|
-
componentEvents.set(eventName, /* @__PURE__ */ new Set());
|
|
1421
|
-
}
|
|
1422
|
-
componentEvents.get(eventName).add(handler);
|
|
1423
|
-
} else {
|
|
1424
|
-
if (!this.globalHandlers.has(eventName)) {
|
|
1425
|
-
this.globalHandlers.set(eventName, /* @__PURE__ */ new Set());
|
|
1426
|
-
}
|
|
1427
|
-
this.globalHandlers.get(eventName).add(handler);
|
|
1428
|
-
}
|
|
1429
|
-
return () => this.off(eventName, handler, componentId);
|
|
1430
|
-
}
|
|
1431
|
-
/**
|
|
1432
|
-
* Remove event handler
|
|
1433
|
-
*/
|
|
1434
|
-
off(eventName, handler, componentId = null) {
|
|
1435
|
-
if (componentId) {
|
|
1436
|
-
const componentEvents = this.events.get(componentId);
|
|
1437
|
-
if (componentEvents && componentEvents.has(eventName)) {
|
|
1438
|
-
componentEvents.get(eventName).delete(handler);
|
|
1439
|
-
if (componentEvents.get(eventName).size === 0) {
|
|
1440
|
-
componentEvents.delete(eventName);
|
|
1441
|
-
if (componentEvents.size === 0) {
|
|
1442
|
-
this.events.delete(componentId);
|
|
1443
|
-
}
|
|
1444
|
-
}
|
|
1445
|
-
}
|
|
1446
|
-
} else {
|
|
1447
|
-
const handlers = this.globalHandlers.get(eventName);
|
|
1448
|
-
if (handlers) {
|
|
1449
|
-
handlers.delete(handler);
|
|
1450
|
-
if (handlers.size === 0) {
|
|
1451
|
-
this.globalHandlers.delete(eventName);
|
|
1452
|
-
}
|
|
1453
|
-
}
|
|
1454
|
-
}
|
|
1455
|
-
}
|
|
1456
|
-
/**
|
|
1457
|
-
* Listen once
|
|
1458
|
-
*/
|
|
1459
|
-
once(eventName, handler, componentId = null) {
|
|
1460
|
-
const onceHandler = (event) => {
|
|
1461
|
-
handler(event);
|
|
1462
|
-
this.off(eventName, onceHandler, componentId);
|
|
1463
|
-
};
|
|
1464
|
-
return this.on(eventName, onceHandler, componentId);
|
|
1465
|
-
}
|
|
1466
|
-
/**
|
|
1467
|
-
* Notify component handlers
|
|
1468
|
-
*/
|
|
1469
|
-
_notifyHandlers(componentId, event) {
|
|
1470
|
-
const componentEvents = this.events.get(componentId);
|
|
1471
|
-
if (componentEvents && componentEvents.has(event.name)) {
|
|
1472
|
-
const handlers = componentEvents.get(event.name);
|
|
1473
|
-
for (const handler of handlers) {
|
|
1474
|
-
if (event.stopped) break;
|
|
1475
|
-
try {
|
|
1476
|
-
handler(event);
|
|
1477
|
-
} catch (_error) {
|
|
1478
|
-
globalErrorHandler.handle(_error, {
|
|
1479
|
-
type: "event-handler-_error",
|
|
1480
|
-
context: { event, handler: handler.toString() }
|
|
1481
|
-
});
|
|
1482
|
-
}
|
|
1483
|
-
}
|
|
1484
|
-
}
|
|
1485
|
-
}
|
|
1486
|
-
/**
|
|
1487
|
-
* Notify global handlers
|
|
1488
|
-
*/
|
|
1489
|
-
_notifyGlobalHandlers(event) {
|
|
1490
|
-
const handlers = this.globalHandlers.get(event.name);
|
|
1491
|
-
if (handlers) {
|
|
1492
|
-
for (const handler of handlers) {
|
|
1493
|
-
if (event.stopped) break;
|
|
1494
|
-
try {
|
|
1495
|
-
handler(event);
|
|
1496
|
-
} catch (_error) {
|
|
1497
|
-
globalErrorHandler.handle(_error, {
|
|
1498
|
-
type: "global-event-handler-_error",
|
|
1499
|
-
context: { event, handler: handler.toString() }
|
|
1500
|
-
});
|
|
1501
|
-
}
|
|
1502
|
-
}
|
|
1503
|
-
}
|
|
1504
|
-
}
|
|
1505
|
-
/**
|
|
1506
|
-
* Clean up events for a component
|
|
1507
|
-
*/
|
|
1508
|
-
cleanup(componentId) {
|
|
1509
|
-
this.events.delete(componentId);
|
|
1510
|
-
}
|
|
1511
|
-
/**
|
|
1512
|
-
* Get event statistics
|
|
1513
|
-
*/
|
|
1514
|
-
getStats() {
|
|
1515
|
-
return {
|
|
1516
|
-
componentEvents: this.events.size,
|
|
1517
|
-
globalEvents: this.globalHandlers.size,
|
|
1518
|
-
totalHandlers: Array.from(this.events.values()).reduce((sum, events) => {
|
|
1519
|
-
return sum + Array.from(events.values()).reduce((eventSum, handlers) => {
|
|
1520
|
-
return eventSum + handlers.size;
|
|
1521
|
-
}, 0);
|
|
1522
|
-
}, 0) + Array.from(this.globalHandlers.values()).reduce((sum, handlers) => {
|
|
1523
|
-
return sum + handlers.size;
|
|
1524
|
-
}, 0)
|
|
1525
|
-
};
|
|
1526
|
-
}
|
|
1527
|
-
};
|
|
1528
|
-
var eventSystem = new ComponentEventSystem();
|
|
1529
|
-
function createLifecycleHooks() {
|
|
1530
|
-
const hooks = {};
|
|
1531
|
-
Object.values(LIFECYCLE_PHASES).forEach((phase) => {
|
|
1532
|
-
hooks[phase] = (callback) => {
|
|
1533
|
-
const instance = getCurrentInstance();
|
|
1534
|
-
if (instance) {
|
|
1535
|
-
instance.hook(phase, callback);
|
|
1536
|
-
}
|
|
1537
|
-
};
|
|
1538
|
-
});
|
|
1539
|
-
return hooks;
|
|
1540
|
-
}
|
|
1541
|
-
var currentInstance = null;
|
|
1542
|
-
function getCurrentInstance() {
|
|
1543
|
-
return currentInstance;
|
|
1544
|
-
}
|
|
1545
|
-
var useHooks = createLifecycleHooks();
|
|
1546
|
-
|
|
1547
|
-
// ../core/src/events/event-bus.js
|
|
1548
|
-
function throttle(func, delay) {
|
|
1549
|
-
let lastCall = 0;
|
|
1550
|
-
let timeoutId = null;
|
|
1551
|
-
return function throttled(...args) {
|
|
1552
|
-
const now = Date.now();
|
|
1553
|
-
const timeSinceLastCall = now - lastCall;
|
|
1554
|
-
if (timeSinceLastCall >= delay) {
|
|
1555
|
-
lastCall = now;
|
|
1556
|
-
return func.apply(this, args);
|
|
1557
|
-
} else {
|
|
1558
|
-
if (timeoutId) clearTimeout(timeoutId);
|
|
1559
|
-
timeoutId = setTimeout(() => {
|
|
1560
|
-
lastCall = Date.now();
|
|
1561
|
-
func.apply(this, args);
|
|
1562
|
-
}, delay - timeSinceLastCall);
|
|
1563
|
-
}
|
|
1564
|
-
};
|
|
1565
|
-
}
|
|
1566
|
-
var EventBus = class {
|
|
1567
|
-
constructor(options = {}) {
|
|
1568
|
-
this.listeners = /* @__PURE__ */ new Map();
|
|
1569
|
-
this.handlers = /* @__PURE__ */ new Map();
|
|
1570
|
-
this.actionHandlers = /* @__PURE__ */ new Map();
|
|
1571
|
-
this.middleware = [];
|
|
1572
|
-
this.throttledEmitters = /* @__PURE__ */ new Map();
|
|
1573
|
-
this.debouncedEmitters = /* @__PURE__ */ new Map();
|
|
1574
|
-
this.options = {
|
|
1575
|
-
debug: false,
|
|
1576
|
-
performance: true,
|
|
1577
|
-
maxListeners: 100,
|
|
1578
|
-
enableWildcards: true,
|
|
1579
|
-
enableAsync: true,
|
|
1580
|
-
wildcardSeparator: ":",
|
|
1581
|
-
enablePriority: true,
|
|
1582
|
-
defaultPriority: 0,
|
|
1583
|
-
errorHandler: null,
|
|
1584
|
-
filters: {
|
|
1585
|
-
allowList: null,
|
|
1586
|
-
// null means allow all
|
|
1587
|
-
blockList: []
|
|
1588
|
-
},
|
|
1589
|
-
throttle: {
|
|
1590
|
-
enabled: false,
|
|
1591
|
-
defaultDelay: 100,
|
|
1592
|
-
events: {}
|
|
1593
|
-
},
|
|
1594
|
-
batching: {
|
|
1595
|
-
enabled: false,
|
|
1596
|
-
maxBatchSize: 10,
|
|
1597
|
-
flushInterval: 16
|
|
1598
|
-
},
|
|
1599
|
-
...options
|
|
1600
|
-
};
|
|
1601
|
-
this.stats = {
|
|
1602
|
-
eventsEmitted: 0,
|
|
1603
|
-
listenersExecuted: 0,
|
|
1604
|
-
errorsOccurred: 0,
|
|
1605
|
-
averageEmitTime: 0,
|
|
1606
|
-
throttledEvents: 0,
|
|
1607
|
-
filteredEvents: 0
|
|
1608
|
-
};
|
|
1609
|
-
if (this.options.batching.enabled) {
|
|
1610
|
-
this.batchQueue = [];
|
|
1611
|
-
this.batchTimer = null;
|
|
1612
|
-
}
|
|
1613
|
-
if (this.options.debug) {
|
|
1614
|
-
this.use((event, data, next) => {
|
|
1615
|
-
console.log(`[EventBus] ${event}:`, data);
|
|
1616
|
-
next();
|
|
1617
|
-
});
|
|
1618
|
-
}
|
|
1619
|
-
}
|
|
1620
|
-
/**
|
|
1621
|
-
* Add middleware
|
|
1622
|
-
*/
|
|
1623
|
-
use(middleware) {
|
|
1624
|
-
if (typeof middleware !== "function") {
|
|
1625
|
-
throw new Error("Middleware must be a function");
|
|
1626
|
-
}
|
|
1627
|
-
this.middleware.push(middleware);
|
|
1628
|
-
return this;
|
|
1629
|
-
}
|
|
1630
|
-
/**
|
|
1631
|
-
* Check if event passes filters
|
|
1632
|
-
*/
|
|
1633
|
-
passesFilters(event) {
|
|
1634
|
-
const { allowList, blockList } = this.options.filters;
|
|
1635
|
-
if (blockList && blockList.length > 0) {
|
|
1636
|
-
for (const pattern of blockList) {
|
|
1637
|
-
if (this.matchPattern(pattern, event)) {
|
|
1638
|
-
this.stats.filteredEvents++;
|
|
1639
|
-
return false;
|
|
1640
|
-
}
|
|
1641
|
-
}
|
|
1642
|
-
}
|
|
1643
|
-
if (allowList && allowList.length > 0) {
|
|
1644
|
-
for (const pattern of allowList) {
|
|
1645
|
-
if (this.matchPattern(pattern, event)) {
|
|
1646
|
-
return true;
|
|
1647
|
-
}
|
|
1648
|
-
}
|
|
1649
|
-
this.stats.filteredEvents++;
|
|
1650
|
-
return false;
|
|
1651
|
-
}
|
|
1652
|
-
return true;
|
|
1653
|
-
}
|
|
1654
|
-
/**
|
|
1655
|
-
* Match event against pattern
|
|
1656
|
-
*/
|
|
1657
|
-
matchPattern(pattern, event) {
|
|
1658
|
-
const sep = this.options.wildcardSeparator;
|
|
1659
|
-
const patternParts = pattern.split(sep);
|
|
1660
|
-
const eventParts = event.split(sep);
|
|
1661
|
-
if (pattern.includes("*")) {
|
|
1662
|
-
if (patternParts.length !== eventParts.length) {
|
|
1663
|
-
return false;
|
|
1664
|
-
}
|
|
1665
|
-
return patternParts.every((part, i) => part === "*" || part === eventParts[i]);
|
|
1666
|
-
}
|
|
1667
|
-
return pattern === event;
|
|
1668
|
-
}
|
|
1669
|
-
/**
|
|
1670
|
-
* Emit an event
|
|
1671
|
-
*/
|
|
1672
|
-
async emit(event, data = null) {
|
|
1673
|
-
if (!this.passesFilters(event)) {
|
|
1674
|
-
if (this.options.debug) {
|
|
1675
|
-
console.warn(`[EventBus] Event filtered: ${event}`);
|
|
1676
|
-
}
|
|
1677
|
-
return;
|
|
1678
|
-
}
|
|
1679
|
-
if (this.options.batching.enabled) {
|
|
1680
|
-
return this.addToBatch(event, data);
|
|
1681
|
-
}
|
|
1682
|
-
if (this.options.throttle.enabled) {
|
|
1683
|
-
const throttleDelay = this.options.throttle.events && this.options.throttle.events[event] || this.options.throttle.defaultDelay;
|
|
1684
|
-
if (throttleDelay > 0) {
|
|
1685
|
-
return this.emitThrottled(event, data, throttleDelay);
|
|
1686
|
-
}
|
|
1687
|
-
}
|
|
1688
|
-
return this.emitImmediate(event, data);
|
|
1689
|
-
}
|
|
1690
|
-
/**
|
|
1691
|
-
* Emit immediately without throttling
|
|
1692
|
-
*/
|
|
1693
|
-
async emitImmediate(event, data = null) {
|
|
1694
|
-
const startTime = this.options.performance ? performance.now() : 0;
|
|
1695
|
-
try {
|
|
1696
|
-
await this.runMiddleware(event, data);
|
|
1697
|
-
const listeners = this.getEventListeners(event);
|
|
1698
|
-
if (listeners.length === 0) {
|
|
1699
|
-
if (this.options.debug) {
|
|
1700
|
-
console.warn(`[EventBus] No listeners for event: ${event}`);
|
|
1701
|
-
}
|
|
1702
|
-
return;
|
|
1703
|
-
}
|
|
1704
|
-
const promises = listeners.map(
|
|
1705
|
-
(listenerObj) => this.executeListener(listenerObj.listener, event, data, listenerObj.options)
|
|
1706
|
-
);
|
|
1707
|
-
if (this.options.enableAsync) {
|
|
1708
|
-
await Promise.allSettled(promises);
|
|
1709
|
-
} else {
|
|
1710
|
-
for (const promise of promises) {
|
|
1711
|
-
await promise;
|
|
1712
|
-
}
|
|
1713
|
-
}
|
|
1714
|
-
this.stats.eventsEmitted++;
|
|
1715
|
-
this.stats.listenersExecuted += listeners.length;
|
|
1716
|
-
} catch (error) {
|
|
1717
|
-
this.stats.errorsOccurred++;
|
|
1718
|
-
this.handleError(error, event, data);
|
|
1719
|
-
} finally {
|
|
1720
|
-
if (this.options.performance) {
|
|
1721
|
-
const duration = performance.now() - startTime;
|
|
1722
|
-
this.updatePerformanceStats(duration);
|
|
1723
|
-
}
|
|
1724
|
-
}
|
|
1725
|
-
}
|
|
1726
|
-
/**
|
|
1727
|
-
* Emit with throttling
|
|
1728
|
-
*/
|
|
1729
|
-
emitThrottled(event, data, delay) {
|
|
1730
|
-
if (!this.throttledEmitters.has(event)) {
|
|
1731
|
-
const throttled = throttle((evt, d) => this.emitImmediate(evt, d), delay);
|
|
1732
|
-
this.throttledEmitters.set(event, throttled);
|
|
1733
|
-
}
|
|
1734
|
-
this.stats.throttledEvents++;
|
|
1735
|
-
return this.throttledEmitters.get(event)(event, data);
|
|
1736
|
-
}
|
|
1737
|
-
/**
|
|
1738
|
-
* Add event to batch queue
|
|
1739
|
-
*/
|
|
1740
|
-
addToBatch(event, data) {
|
|
1741
|
-
this.batchQueue.push({ event, data, timestamp: Date.now() });
|
|
1742
|
-
if (this.batchQueue.length >= this.options.batching.maxBatchSize) {
|
|
1743
|
-
this.flushBatch();
|
|
1744
|
-
} else if (!this.batchTimer) {
|
|
1745
|
-
this.batchTimer = setTimeout(() => {
|
|
1746
|
-
this.flushBatch();
|
|
1747
|
-
}, this.options.batching.flushInterval);
|
|
1748
|
-
}
|
|
1749
|
-
}
|
|
1750
|
-
/**
|
|
1751
|
-
* Flush batch queue
|
|
1752
|
-
*/
|
|
1753
|
-
async flushBatch() {
|
|
1754
|
-
if (this.batchTimer) {
|
|
1755
|
-
clearTimeout(this.batchTimer);
|
|
1756
|
-
this.batchTimer = null;
|
|
1757
|
-
}
|
|
1758
|
-
const batch = this.batchQueue.splice(0);
|
|
1759
|
-
for (const { event, data } of batch) {
|
|
1760
|
-
await this.emitImmediate(event, data);
|
|
1761
|
-
}
|
|
1762
|
-
}
|
|
1763
|
-
/**
|
|
1764
|
-
* Register event listener with options
|
|
1765
|
-
*/
|
|
1766
|
-
on(event, listener, options = {}) {
|
|
1767
|
-
if (typeof listener !== "function") {
|
|
1768
|
-
throw new Error("Listener must be a function");
|
|
1769
|
-
}
|
|
1770
|
-
if (!this.listeners.has(event)) {
|
|
1771
|
-
this.listeners.set(event, []);
|
|
1772
|
-
}
|
|
1773
|
-
const listeners = this.listeners.get(event);
|
|
1774
|
-
if (listeners.length >= this.options.maxListeners) {
|
|
1775
|
-
console.warn(`[EventBus] Max listeners (${this.options.maxListeners}) reached for event: ${event}`);
|
|
1776
|
-
}
|
|
1777
|
-
const listenerId = this.generateListenerId(event);
|
|
1778
|
-
const listenerObj = {
|
|
1779
|
-
listener,
|
|
1780
|
-
listenerId,
|
|
1781
|
-
priority: options.priority !== void 0 ? options.priority : this.options.defaultPriority,
|
|
1782
|
-
condition: options.condition || null,
|
|
1783
|
-
timeout: options.timeout || null,
|
|
1784
|
-
options
|
|
1785
|
-
};
|
|
1786
|
-
listener.__listenerId = listenerId;
|
|
1787
|
-
listener.__event = event;
|
|
1788
|
-
if (this.options.enablePriority) {
|
|
1789
|
-
const insertIndex = listeners.findIndex((l) => l.priority < listenerObj.priority);
|
|
1790
|
-
if (insertIndex === -1) {
|
|
1791
|
-
listeners.push(listenerObj);
|
|
1792
|
-
} else {
|
|
1793
|
-
listeners.splice(insertIndex, 0, listenerObj);
|
|
1794
|
-
}
|
|
1795
|
-
} else {
|
|
1796
|
-
listeners.push(listenerObj);
|
|
1797
|
-
}
|
|
1798
|
-
return listenerId;
|
|
1799
|
-
}
|
|
1800
|
-
/**
|
|
1801
|
-
* Register one-time listener
|
|
1802
|
-
*/
|
|
1803
|
-
once(event, listener, options = {}) {
|
|
1804
|
-
const onceListener = (...args) => {
|
|
1805
|
-
this.off(event, onceListener.__listenerId);
|
|
1806
|
-
return listener.call(this, ...args);
|
|
1807
|
-
};
|
|
1808
|
-
if (options.timeout) {
|
|
1809
|
-
const timeoutId = setTimeout(() => {
|
|
1810
|
-
this.off(event, onceListener.__listenerId);
|
|
1811
|
-
if (this.options.debug) {
|
|
1812
|
-
console.warn(`[EventBus] Listener timeout for event: ${event}`);
|
|
1813
|
-
}
|
|
1814
|
-
}, options.timeout);
|
|
1815
|
-
onceListener.__cleanup = () => clearTimeout(timeoutId);
|
|
1816
|
-
}
|
|
1817
|
-
return this.on(event, onceListener, options);
|
|
1818
|
-
}
|
|
1819
|
-
/**
|
|
1820
|
-
* Remove listener
|
|
1821
|
-
*/
|
|
1822
|
-
off(event, listenerId) {
|
|
1823
|
-
if (!this.listeners.has(event)) {
|
|
1824
|
-
return false;
|
|
1825
|
-
}
|
|
1826
|
-
const listeners = this.listeners.get(event);
|
|
1827
|
-
const index = listeners.findIndex((l) => l.listenerId === listenerId);
|
|
1828
|
-
if (index !== -1) {
|
|
1829
|
-
const listenerObj = listeners[index];
|
|
1830
|
-
if (listenerObj.listener.__cleanup) {
|
|
1831
|
-
listenerObj.listener.__cleanup();
|
|
1832
|
-
}
|
|
1833
|
-
listeners.splice(index, 1);
|
|
1834
|
-
if (listeners.length === 0) {
|
|
1835
|
-
this.listeners.delete(event);
|
|
1836
|
-
}
|
|
1837
|
-
return true;
|
|
1838
|
-
}
|
|
1839
|
-
return false;
|
|
1840
|
-
}
|
|
1841
|
-
/**
|
|
1842
|
-
* Remove all listeners for an event
|
|
1843
|
-
*/
|
|
1844
|
-
removeAllListeners(event) {
|
|
1845
|
-
if (event) {
|
|
1846
|
-
this.listeners.delete(event);
|
|
1847
|
-
} else {
|
|
1848
|
-
this.listeners.clear();
|
|
1849
|
-
}
|
|
1850
|
-
}
|
|
1851
|
-
/**
|
|
1852
|
-
* Get event listeners with wildcard support
|
|
1853
|
-
*/
|
|
1854
|
-
getEventListeners(event) {
|
|
1855
|
-
const listeners = [];
|
|
1856
|
-
if (this.listeners.has(event)) {
|
|
1857
|
-
listeners.push(...this.listeners.get(event));
|
|
1858
|
-
}
|
|
1859
|
-
if (this.options.enableWildcards) {
|
|
1860
|
-
for (const [pattern, patternListeners] of this.listeners) {
|
|
1861
|
-
if (pattern.includes("*") && this.matchPattern(pattern, event)) {
|
|
1862
|
-
listeners.push(...patternListeners);
|
|
1863
|
-
}
|
|
1864
|
-
}
|
|
1865
|
-
}
|
|
1866
|
-
if (this.options.enablePriority) {
|
|
1867
|
-
listeners.sort((a, b) => b.priority - a.priority);
|
|
1868
|
-
}
|
|
1869
|
-
return listeners;
|
|
1870
|
-
}
|
|
1871
|
-
/**
|
|
1872
|
-
* Execute listener with options
|
|
1873
|
-
*/
|
|
1874
|
-
async executeListener(listener, event, data, options = {}) {
|
|
1875
|
-
try {
|
|
1876
|
-
if (options.condition && !options.condition(data)) {
|
|
1877
|
-
return;
|
|
1878
|
-
}
|
|
1879
|
-
const result = listener.call(this, data, event);
|
|
1880
|
-
if (result && typeof result.then === "function") {
|
|
1881
|
-
await result;
|
|
1882
|
-
}
|
|
1883
|
-
return result;
|
|
1884
|
-
} catch (error) {
|
|
1885
|
-
this.handleError(error, event, data);
|
|
1886
|
-
}
|
|
1887
|
-
}
|
|
1888
|
-
/**
|
|
1889
|
-
* Run middleware chain
|
|
1890
|
-
*/
|
|
1891
|
-
async runMiddleware(event, data) {
|
|
1892
|
-
if (this.middleware.length === 0) return;
|
|
1893
|
-
let index = 0;
|
|
1894
|
-
const next = async () => {
|
|
1895
|
-
if (index < this.middleware.length) {
|
|
1896
|
-
const middleware = this.middleware[index++];
|
|
1897
|
-
await middleware(event, data, next);
|
|
1898
|
-
}
|
|
1899
|
-
};
|
|
1900
|
-
await next();
|
|
1901
|
-
}
|
|
1902
|
-
/**
|
|
1903
|
-
* Handle errors
|
|
1904
|
-
*/
|
|
1905
|
-
handleError(error, event, data) {
|
|
1906
|
-
if (this.options.errorHandler) {
|
|
1907
|
-
this.options.errorHandler(error, event, data);
|
|
1908
|
-
} else if (this.options.debug) {
|
|
1909
|
-
console.error(`[EventBus] Error in event ${event}:`, error, data);
|
|
1910
|
-
}
|
|
1911
|
-
this.emitSync("eventbus:error", { error, event, data });
|
|
1912
|
-
}
|
|
1913
|
-
/**
|
|
1914
|
-
* Synchronous emit
|
|
1915
|
-
*/
|
|
1916
|
-
emitSync(event, data = null) {
|
|
1917
|
-
try {
|
|
1918
|
-
const listeners = this.getEventListeners(event);
|
|
1919
|
-
listeners.forEach((listenerObj) => {
|
|
1920
|
-
try {
|
|
1921
|
-
if (!listenerObj.options.condition || listenerObj.options.condition(data)) {
|
|
1922
|
-
listenerObj.listener.call(this, data, event);
|
|
1923
|
-
}
|
|
1924
|
-
} catch (error) {
|
|
1925
|
-
this.handleError(error, event, data);
|
|
1926
|
-
}
|
|
1927
|
-
});
|
|
1928
|
-
this.stats.eventsEmitted++;
|
|
1929
|
-
this.stats.listenersExecuted += listeners.length;
|
|
1930
|
-
} catch (error) {
|
|
1931
|
-
this.stats.errorsOccurred++;
|
|
1932
|
-
this.handleError(error, event, data);
|
|
1933
|
-
}
|
|
1934
|
-
}
|
|
1935
|
-
/**
|
|
1936
|
-
* Register action handler
|
|
1937
|
-
*/
|
|
1938
|
-
registerAction(action, handler) {
|
|
1939
|
-
if (typeof handler !== "function") {
|
|
1940
|
-
throw new Error("Action handler must be a function");
|
|
1941
|
-
}
|
|
1942
|
-
this.actionHandlers.set(action, handler);
|
|
1943
|
-
if (this.options.debug) {
|
|
1944
|
-
console.log(`[EventBus] Registered action: ${action}`);
|
|
1945
|
-
}
|
|
1946
|
-
}
|
|
1947
|
-
/**
|
|
1948
|
-
* Register multiple actions
|
|
1949
|
-
*/
|
|
1950
|
-
registerActions(actions) {
|
|
1951
|
-
Object.entries(actions).forEach(([action, handler]) => {
|
|
1952
|
-
this.registerAction(action, handler);
|
|
1953
|
-
});
|
|
1954
|
-
}
|
|
1955
|
-
/**
|
|
1956
|
-
* Get registered actions
|
|
1957
|
-
*/
|
|
1958
|
-
getRegisteredActions() {
|
|
1959
|
-
return Array.from(this.actionHandlers.keys());
|
|
1960
|
-
}
|
|
1961
|
-
/**
|
|
1962
|
-
* Handle action event (called by DOM integration)
|
|
1963
|
-
*/
|
|
1964
|
-
handleAction(action, element, event, data) {
|
|
1965
|
-
const handler = this.actionHandlers.get(action);
|
|
1966
|
-
if (!handler) {
|
|
1967
|
-
if (this.options.debug) {
|
|
1968
|
-
console.warn(`[EventBus] No handler registered for action: ${action}`);
|
|
1969
|
-
}
|
|
1970
|
-
return;
|
|
1971
|
-
}
|
|
1972
|
-
try {
|
|
1973
|
-
handler.call(element, {
|
|
1974
|
-
element,
|
|
1975
|
-
event,
|
|
1976
|
-
data,
|
|
1977
|
-
emit: this.emit.bind(this),
|
|
1978
|
-
emitSync: this.emitSync.bind(this)
|
|
1979
|
-
});
|
|
1980
|
-
} catch (error) {
|
|
1981
|
-
this.handleError(error, `action:${action}`, { element, event, data });
|
|
1982
|
-
}
|
|
1983
|
-
}
|
|
1984
|
-
/**
|
|
1985
|
-
* Generate unique listener ID
|
|
1986
|
-
*/
|
|
1987
|
-
generateListenerId(event) {
|
|
1988
|
-
return `${event}_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
1989
|
-
}
|
|
1990
|
-
/**
|
|
1991
|
-
* Update performance stats
|
|
1992
|
-
*/
|
|
1993
|
-
updatePerformanceStats(duration) {
|
|
1994
|
-
const count = this.stats.eventsEmitted;
|
|
1995
|
-
this.stats.averageEmitTime = (this.stats.averageEmitTime * (count - 1) + duration) / count;
|
|
1996
|
-
}
|
|
1997
|
-
/**
|
|
1998
|
-
* Get statistics
|
|
1999
|
-
*/
|
|
2000
|
-
getStats() {
|
|
2001
|
-
return { ...this.stats };
|
|
2002
|
-
}
|
|
2003
|
-
/**
|
|
2004
|
-
* Reset statistics
|
|
2005
|
-
*/
|
|
2006
|
-
resetStats() {
|
|
2007
|
-
this.stats = {
|
|
2008
|
-
eventsEmitted: 0,
|
|
2009
|
-
listenersExecuted: 0,
|
|
2010
|
-
errorsOccurred: 0,
|
|
2011
|
-
averageEmitTime: 0,
|
|
2012
|
-
throttledEvents: 0,
|
|
2013
|
-
filteredEvents: 0
|
|
2014
|
-
};
|
|
2015
|
-
}
|
|
2016
|
-
/**
|
|
2017
|
-
* Destroy event bus
|
|
2018
|
-
*/
|
|
2019
|
-
destroy() {
|
|
2020
|
-
this.removeAllListeners();
|
|
2021
|
-
this.actionHandlers.clear();
|
|
2022
|
-
this.handlers.clear();
|
|
2023
|
-
this.middleware = [];
|
|
2024
|
-
this.throttledEmitters.clear();
|
|
2025
|
-
this.debouncedEmitters.clear();
|
|
2026
|
-
if (this.batchTimer) {
|
|
2027
|
-
clearTimeout(this.batchTimer);
|
|
2028
|
-
}
|
|
2029
|
-
}
|
|
2030
|
-
};
|
|
2031
|
-
function createEventBus(options = {}) {
|
|
2032
|
-
return new EventBus(options);
|
|
2033
|
-
}
|
|
2034
|
-
var globalEventBus = createEventBus();
|
|
2035
|
-
var emit = globalEventBus.emit.bind(globalEventBus);
|
|
2036
|
-
var emitSync = globalEventBus.emitSync.bind(globalEventBus);
|
|
2037
|
-
var on = globalEventBus.on.bind(globalEventBus);
|
|
2038
|
-
var once = globalEventBus.once.bind(globalEventBus);
|
|
2039
|
-
var off = globalEventBus.off.bind(globalEventBus);
|
|
2040
|
-
var registerAction = globalEventBus.registerAction.bind(globalEventBus);
|
|
2041
|
-
var handleAction = globalEventBus.handleAction.bind(globalEventBus);
|
|
2042
|
-
|
|
2043
|
-
// ../core/src/events/dom-integration.js
|
|
2044
|
-
var DOMEventIntegration = class {
|
|
2045
|
-
constructor(eventBus = globalEventBus, options = {}) {
|
|
2046
|
-
this.eventBus = eventBus;
|
|
2047
|
-
this.options = {
|
|
2048
|
-
debug: false,
|
|
2049
|
-
debounceDelay: 150,
|
|
2050
|
-
throttleDelay: 100,
|
|
2051
|
-
enableDelegation: true,
|
|
2052
|
-
enableDebounce: true,
|
|
2053
|
-
enableThrottle: false,
|
|
2054
|
-
...options
|
|
2055
|
-
};
|
|
2056
|
-
this.boundHandlers = /* @__PURE__ */ new Map();
|
|
2057
|
-
this.activeElement = null;
|
|
2058
|
-
this.isInitialized = false;
|
|
2059
|
-
this.handleClick = this.handleClick.bind(this);
|
|
2060
|
-
this.handleChange = this.handleChange.bind(this);
|
|
2061
|
-
this.handleInput = this.handleInput.bind(this);
|
|
2062
|
-
this.handleSubmit = this.handleSubmit.bind(this);
|
|
2063
|
-
this.handleKeydown = this.handleKeydown.bind(this);
|
|
2064
|
-
this.handleFocus = this.handleFocus.bind(this);
|
|
2065
|
-
this.handleBlur = this.handleBlur.bind(this);
|
|
2066
|
-
}
|
|
2067
|
-
/**
|
|
2068
|
-
* Initialize DOM event listeners
|
|
2069
|
-
* @param {HTMLElement} rootElement - Root element to attach listeners to (default: document)
|
|
2070
|
-
*/
|
|
2071
|
-
initialize(rootElement = document) {
|
|
2072
|
-
if (this.isInitialized) {
|
|
2073
|
-
console.warn("[DOMEventIntegration] Already initialized");
|
|
2074
|
-
return;
|
|
2075
|
-
}
|
|
2076
|
-
if (typeof window === "undefined" || !rootElement) {
|
|
2077
|
-
console.warn("[DOMEventIntegration] Cannot initialize: no DOM environment");
|
|
2078
|
-
return;
|
|
2079
|
-
}
|
|
2080
|
-
this.rootElement = rootElement;
|
|
2081
|
-
this.setupDOMEventListeners();
|
|
2082
|
-
this.isInitialized = true;
|
|
2083
|
-
if (this.options.debug) {
|
|
2084
|
-
console.log("[DOMEventIntegration] Initialized with options:", this.options);
|
|
2085
|
-
}
|
|
2086
|
-
}
|
|
2087
|
-
/**
|
|
2088
|
-
* Set up delegated DOM event listeners
|
|
2089
|
-
* @private
|
|
2090
|
-
*/
|
|
2091
|
-
setupDOMEventListeners() {
|
|
2092
|
-
const clickHandler = this.createDelegatedHandler("click", this.handleClick);
|
|
2093
|
-
this.rootElement.addEventListener("click", clickHandler, { passive: false });
|
|
2094
|
-
this.boundHandlers.set("click", clickHandler);
|
|
2095
|
-
const changeHandler = this.options.enableDebounce ? this.debounce(this.createDelegatedHandler("change", this.handleChange), this.options.debounceDelay) : this.createDelegatedHandler("change", this.handleChange);
|
|
2096
|
-
this.rootElement.addEventListener("change", changeHandler, { passive: true });
|
|
2097
|
-
this.boundHandlers.set("change", changeHandler);
|
|
2098
|
-
const inputHandler = this.options.enableDebounce ? this.debounce(this.createDelegatedHandler("input", this.handleInput), this.options.debounceDelay) : this.createDelegatedHandler("input", this.handleInput);
|
|
2099
|
-
this.rootElement.addEventListener("input", inputHandler, { passive: true });
|
|
2100
|
-
this.boundHandlers.set("input", inputHandler);
|
|
2101
|
-
const submitHandler = this.createDelegatedHandler("submit", this.handleSubmit);
|
|
2102
|
-
this.rootElement.addEventListener("submit", submitHandler, { passive: false });
|
|
2103
|
-
this.boundHandlers.set("submit", submitHandler);
|
|
2104
|
-
const keydownHandler = this.createDelegatedHandler("keydown", this.handleKeydown);
|
|
2105
|
-
this.rootElement.addEventListener("keydown", keydownHandler, { passive: false });
|
|
2106
|
-
this.boundHandlers.set("keydown", keydownHandler);
|
|
2107
|
-
const focusHandler = this.createDelegatedHandler("focus", this.handleFocus);
|
|
2108
|
-
this.rootElement.addEventListener("focus", focusHandler, { passive: true, capture: true });
|
|
2109
|
-
this.boundHandlers.set("focus", focusHandler);
|
|
2110
|
-
const blurHandler = this.createDelegatedHandler("blur", this.handleBlur);
|
|
2111
|
-
this.rootElement.addEventListener("blur", blurHandler, { passive: true, capture: true });
|
|
2112
|
-
this.boundHandlers.set("blur", blurHandler);
|
|
2113
|
-
}
|
|
2114
|
-
/**
|
|
2115
|
-
* Create a delegated event handler
|
|
2116
|
-
* @private
|
|
2117
|
-
*/
|
|
2118
|
-
createDelegatedHandler(eventType, handler) {
|
|
2119
|
-
return (event) => {
|
|
2120
|
-
const target = event.target;
|
|
2121
|
-
if (!target) return;
|
|
2122
|
-
const actionElement = this.options.enableDelegation ? target.closest("[data-action]") : target.hasAttribute?.("data-action") ? target : null;
|
|
2123
|
-
if (actionElement) {
|
|
2124
|
-
handler(actionElement, event);
|
|
2125
|
-
} else {
|
|
2126
|
-
handler(target, event);
|
|
2127
|
-
}
|
|
2128
|
-
};
|
|
2129
|
-
}
|
|
2130
|
-
/**
|
|
2131
|
-
* Handle click events
|
|
2132
|
-
* @private
|
|
2133
|
-
*/
|
|
2134
|
-
handleClick(element, event) {
|
|
2135
|
-
const action = element.getAttribute?.("data-action");
|
|
2136
|
-
if (action) {
|
|
2137
|
-
this.handleDataAction(element, event, action);
|
|
2138
|
-
}
|
|
2139
|
-
this.eventBus.emitSync("dom:click", {
|
|
2140
|
-
element,
|
|
2141
|
-
event,
|
|
2142
|
-
action,
|
|
2143
|
-
data: this.parseDataAttributes(element)
|
|
2144
|
-
});
|
|
2145
|
-
}
|
|
2146
|
-
/**
|
|
2147
|
-
* Handle change events
|
|
2148
|
-
* @private
|
|
2149
|
-
*/
|
|
2150
|
-
handleChange(element, event) {
|
|
2151
|
-
const action = element.getAttribute?.("data-action");
|
|
2152
|
-
if (action) {
|
|
2153
|
-
this.handleDataAction(element, event, action);
|
|
2154
|
-
}
|
|
2155
|
-
this.eventBus.emitSync("dom:change", {
|
|
2156
|
-
element,
|
|
2157
|
-
event,
|
|
2158
|
-
value: element.value,
|
|
2159
|
-
action,
|
|
2160
|
-
data: this.parseDataAttributes(element)
|
|
2161
|
-
});
|
|
2162
|
-
}
|
|
2163
|
-
/**
|
|
2164
|
-
* Handle input events
|
|
2165
|
-
* @private
|
|
2166
|
-
*/
|
|
2167
|
-
handleInput(element, event) {
|
|
2168
|
-
const action = element.getAttribute?.("data-action");
|
|
2169
|
-
if (action) {
|
|
2170
|
-
this.handleDataAction(element, event, action);
|
|
2171
|
-
}
|
|
2172
|
-
this.eventBus.emitSync("dom:input", {
|
|
2173
|
-
element,
|
|
2174
|
-
event,
|
|
2175
|
-
value: element.value,
|
|
2176
|
-
action,
|
|
2177
|
-
data: this.parseDataAttributes(element)
|
|
2178
|
-
});
|
|
2179
|
-
}
|
|
2180
|
-
/**
|
|
2181
|
-
* Handle submit events
|
|
2182
|
-
* @private
|
|
2183
|
-
*/
|
|
2184
|
-
handleSubmit(element, event) {
|
|
2185
|
-
const action = element.getAttribute?.("data-action");
|
|
2186
|
-
if (action) {
|
|
2187
|
-
event.preventDefault();
|
|
2188
|
-
this.handleDataAction(element, event, action);
|
|
2189
|
-
}
|
|
2190
|
-
this.eventBus.emitSync("dom:submit", {
|
|
2191
|
-
element,
|
|
2192
|
-
event,
|
|
2193
|
-
action,
|
|
2194
|
-
formData: this.extractFormData(element),
|
|
2195
|
-
data: this.parseDataAttributes(element)
|
|
2196
|
-
});
|
|
2197
|
-
}
|
|
2198
|
-
/**
|
|
2199
|
-
* Handle keydown events
|
|
2200
|
-
* @private
|
|
2201
|
-
*/
|
|
2202
|
-
handleKeydown(element, event) {
|
|
2203
|
-
const action = element.getAttribute?.("data-action");
|
|
2204
|
-
const keyAction = element.getAttribute?.(`data-key-${event.key.toLowerCase()}`);
|
|
2205
|
-
if (action && this.shouldTriggerKeyAction(event)) {
|
|
2206
|
-
this.handleDataAction(element, event, action);
|
|
2207
|
-
}
|
|
2208
|
-
if (keyAction) {
|
|
2209
|
-
this.handleDataAction(element, event, keyAction);
|
|
2210
|
-
}
|
|
2211
|
-
this.eventBus.emitSync("dom:keydown", {
|
|
2212
|
-
element,
|
|
2213
|
-
event,
|
|
2214
|
-
key: event.key,
|
|
2215
|
-
code: event.code,
|
|
2216
|
-
action,
|
|
2217
|
-
keyAction,
|
|
2218
|
-
data: this.parseDataAttributes(element)
|
|
2219
|
-
});
|
|
2220
|
-
}
|
|
2221
|
-
/**
|
|
2222
|
-
* Handle focus events
|
|
2223
|
-
* @private
|
|
2224
|
-
*/
|
|
2225
|
-
handleFocus(element, event) {
|
|
2226
|
-
this.activeElement = element;
|
|
2227
|
-
this.eventBus.emitSync("dom:focus", {
|
|
2228
|
-
element,
|
|
2229
|
-
event,
|
|
2230
|
-
data: this.parseDataAttributes(element)
|
|
2231
|
-
});
|
|
2232
|
-
}
|
|
2233
|
-
/**
|
|
2234
|
-
* Handle blur events
|
|
2235
|
-
* @private
|
|
2236
|
-
*/
|
|
2237
|
-
handleBlur(element, event) {
|
|
2238
|
-
if (this.activeElement === element) {
|
|
2239
|
-
this.activeElement = null;
|
|
2240
|
-
}
|
|
2241
|
-
this.eventBus.emitSync("dom:blur", {
|
|
2242
|
-
element,
|
|
2243
|
-
event,
|
|
2244
|
-
data: this.parseDataAttributes(element)
|
|
2245
|
-
});
|
|
2246
|
-
}
|
|
2247
|
-
/**
|
|
2248
|
-
* Handle data-action attributes
|
|
2249
|
-
* @private
|
|
2250
|
-
*/
|
|
2251
|
-
handleDataAction(element, event, action) {
|
|
2252
|
-
if (!action) return;
|
|
2253
|
-
const data = this.parseDataAttributes(element);
|
|
2254
|
-
this.eventBus.emitSync("dom:action", {
|
|
2255
|
-
action,
|
|
2256
|
-
element,
|
|
2257
|
-
event,
|
|
2258
|
-
data
|
|
2259
|
-
});
|
|
2260
|
-
this.eventBus.handleAction(action, element, event, data);
|
|
2261
|
-
if (this.options.debug) {
|
|
2262
|
-
console.log(`[DOMEventIntegration] Action triggered: ${action}`, {
|
|
2263
|
-
element,
|
|
2264
|
-
event: event.type,
|
|
2265
|
-
data
|
|
2266
|
-
});
|
|
2267
|
-
}
|
|
2268
|
-
}
|
|
2269
|
-
/**
|
|
2270
|
-
* Parse data attributes from an element
|
|
2271
|
-
* @private
|
|
2272
|
-
*/
|
|
2273
|
-
parseDataAttributes(element) {
|
|
2274
|
-
if (!element?.attributes) return {};
|
|
2275
|
-
const data = {};
|
|
2276
|
-
Array.from(element.attributes).forEach((attr) => {
|
|
2277
|
-
if (attr.name.startsWith("data-") && attr.name !== "data-action") {
|
|
2278
|
-
const key = attr.name.slice(5).replace(/-([a-z])/g, (_, letter) => letter.toUpperCase());
|
|
2279
|
-
let value = attr.value;
|
|
2280
|
-
try {
|
|
2281
|
-
if (value === "true") value = true;
|
|
2282
|
-
else if (value === "false") value = false;
|
|
2283
|
-
else if (value === "null") value = null;
|
|
2284
|
-
else if (value === "undefined") value = void 0;
|
|
2285
|
-
else if (/^\d+$/.test(value)) value = parseInt(value, 10);
|
|
2286
|
-
else if (/^\d*\.\d+$/.test(value)) value = parseFloat(value);
|
|
2287
|
-
else if (value.startsWith("{") && value.endsWith("}") || value.startsWith("[") && value.endsWith("]")) {
|
|
2288
|
-
value = JSON.parse(value);
|
|
2289
|
-
}
|
|
2290
|
-
} catch {
|
|
2291
|
-
}
|
|
2292
|
-
data[key] = value;
|
|
2293
|
-
}
|
|
2294
|
-
});
|
|
2295
|
-
return data;
|
|
2296
|
-
}
|
|
2297
|
-
/**
|
|
2298
|
-
* Extract form data from a form element
|
|
2299
|
-
* @private
|
|
2300
|
-
*/
|
|
2301
|
-
extractFormData(formElement) {
|
|
2302
|
-
if (!formElement || formElement.tagName !== "FORM") {
|
|
2303
|
-
return {};
|
|
2304
|
-
}
|
|
2305
|
-
const formData = new FormData(formElement);
|
|
2306
|
-
const data = {};
|
|
2307
|
-
for (const [key, value] of formData.entries()) {
|
|
2308
|
-
if (data[key]) {
|
|
2309
|
-
if (Array.isArray(data[key])) {
|
|
2310
|
-
data[key].push(value);
|
|
2311
|
-
} else {
|
|
2312
|
-
data[key] = [data[key], value];
|
|
2313
|
-
}
|
|
2314
|
-
} else {
|
|
2315
|
-
data[key] = value;
|
|
2316
|
-
}
|
|
2317
|
-
}
|
|
2318
|
-
return data;
|
|
2319
|
-
}
|
|
2320
|
-
/**
|
|
2321
|
-
* Check if a key event should trigger an action
|
|
2322
|
-
* @private
|
|
2323
|
-
*/
|
|
2324
|
-
shouldTriggerKeyAction(event) {
|
|
2325
|
-
const triggerKeys = ["Enter", "Space", "Escape"];
|
|
2326
|
-
return triggerKeys.includes(event.key);
|
|
2327
|
-
}
|
|
2328
|
-
/**
|
|
2329
|
-
* Debounce utility function
|
|
2330
|
-
* @private
|
|
2331
|
-
*/
|
|
2332
|
-
debounce(func, wait) {
|
|
2333
|
-
let timeout;
|
|
2334
|
-
return function executedFunction(...args) {
|
|
2335
|
-
const later = () => {
|
|
2336
|
-
clearTimeout(timeout);
|
|
2337
|
-
func.apply(this, args);
|
|
2338
|
-
};
|
|
2339
|
-
clearTimeout(timeout);
|
|
2340
|
-
timeout = setTimeout(later, wait);
|
|
2341
|
-
};
|
|
2342
|
-
}
|
|
2343
|
-
/**
|
|
2344
|
-
* Throttle utility function
|
|
2345
|
-
* @private
|
|
2346
|
-
*/
|
|
2347
|
-
throttle(func, limit) {
|
|
2348
|
-
let inThrottle;
|
|
2349
|
-
return function executedFunction(...args) {
|
|
2350
|
-
if (!inThrottle) {
|
|
2351
|
-
func.apply(this, args);
|
|
2352
|
-
inThrottle = true;
|
|
2353
|
-
setTimeout(() => inThrottle = false, limit);
|
|
2354
|
-
}
|
|
2355
|
-
};
|
|
2356
|
-
}
|
|
2357
|
-
/**
|
|
2358
|
-
* Add custom event listener
|
|
2359
|
-
* @param {string} eventType - Event type
|
|
2360
|
-
* @param {Function} handler - Event handler
|
|
2361
|
-
* @param {Object} options - Event listener options
|
|
2362
|
-
*/
|
|
2363
|
-
addCustomListener(eventType, handler, options = {}) {
|
|
2364
|
-
const wrappedHandler = this.createDelegatedHandler(eventType, handler);
|
|
2365
|
-
this.rootElement.addEventListener(eventType, wrappedHandler, options);
|
|
2366
|
-
this.boundHandlers.set(`custom:${eventType}`, wrappedHandler);
|
|
2367
|
-
}
|
|
2368
|
-
/**
|
|
2369
|
-
* Remove custom event listener
|
|
2370
|
-
* @param {string} eventType - Event type
|
|
2371
|
-
*/
|
|
2372
|
-
removeCustomListener(eventType) {
|
|
2373
|
-
const handler = this.boundHandlers.get(`custom:${eventType}`);
|
|
2374
|
-
if (handler) {
|
|
2375
|
-
this.rootElement.removeEventListener(eventType, handler);
|
|
2376
|
-
this.boundHandlers.delete(`custom:${eventType}`);
|
|
2377
|
-
}
|
|
2378
|
-
}
|
|
2379
|
-
/**
|
|
2380
|
-
* Register action handlers in bulk
|
|
2381
|
-
* @param {Object} actions - Object mapping action names to handlers
|
|
2382
|
-
*/
|
|
2383
|
-
registerActions(actions) {
|
|
2384
|
-
this.eventBus.registerActions(actions);
|
|
2385
|
-
}
|
|
2386
|
-
/**
|
|
2387
|
-
* Get the currently active (focused) element
|
|
2388
|
-
* @returns {HTMLElement|null}
|
|
2389
|
-
*/
|
|
2390
|
-
getActiveElement() {
|
|
2391
|
-
return this.activeElement;
|
|
2392
|
-
}
|
|
2393
|
-
/**
|
|
2394
|
-
* Trigger an action programmatically
|
|
2395
|
-
* @param {string} action - Action name
|
|
2396
|
-
* @param {HTMLElement} element - Target element
|
|
2397
|
-
* @param {Object} data - Additional data
|
|
2398
|
-
*/
|
|
2399
|
-
triggerAction(action, element, data = {}) {
|
|
2400
|
-
const syntheticEvent = new CustomEvent("synthetic", {
|
|
2401
|
-
bubbles: true,
|
|
2402
|
-
cancelable: true,
|
|
2403
|
-
detail: data
|
|
2404
|
-
});
|
|
2405
|
-
this.eventBus.handleAction(action, element, syntheticEvent, data);
|
|
2406
|
-
}
|
|
2407
|
-
/**
|
|
2408
|
-
* Clean up event listeners
|
|
2409
|
-
*/
|
|
2410
|
-
destroy() {
|
|
2411
|
-
if (!this.isInitialized) return;
|
|
2412
|
-
this.boundHandlers.forEach((handler, eventType) => {
|
|
2413
|
-
this.rootElement.removeEventListener(
|
|
2414
|
-
eventType.replace("custom:", ""),
|
|
2415
|
-
handler
|
|
2416
|
-
);
|
|
2417
|
-
});
|
|
2418
|
-
this.boundHandlers.clear();
|
|
2419
|
-
this.activeElement = null;
|
|
2420
|
-
this.isInitialized = false;
|
|
2421
|
-
if (this.options.debug) {
|
|
2422
|
-
console.log("[DOMEventIntegration] Destroyed");
|
|
2423
|
-
}
|
|
2424
|
-
}
|
|
2425
|
-
};
|
|
2426
|
-
var globalDOMIntegration = new DOMEventIntegration(globalEventBus, {
|
|
2427
|
-
debug: typeof process !== "undefined" && true
|
|
2428
|
-
});
|
|
2429
|
-
if (typeof window !== "undefined") {
|
|
2430
|
-
if (document.readyState === "loading") {
|
|
2431
|
-
document.addEventListener("DOMContentLoaded", () => {
|
|
2432
|
-
globalDOMIntegration.initialize();
|
|
2433
|
-
});
|
|
2434
|
-
} else {
|
|
2435
|
-
globalDOMIntegration.initialize();
|
|
2436
|
-
}
|
|
2437
|
-
}
|
|
2438
|
-
|
|
2439
|
-
// ../core/src/events/index.js
|
|
2440
|
-
var eventSystem2 = {
|
|
2441
|
-
// Core bus
|
|
2442
|
-
bus: globalEventBus,
|
|
2443
|
-
dom: globalDOMIntegration,
|
|
2444
|
-
// Quick access methods
|
|
2445
|
-
emit: globalEventBus.emit.bind(globalEventBus),
|
|
2446
|
-
emitSync: globalEventBus.emitSync.bind(globalEventBus),
|
|
2447
|
-
on: globalEventBus.on.bind(globalEventBus),
|
|
2448
|
-
once: globalEventBus.once.bind(globalEventBus),
|
|
2449
|
-
off: globalEventBus.off.bind(globalEventBus),
|
|
2450
|
-
// Action methods
|
|
2451
|
-
registerAction: globalEventBus.registerAction.bind(globalEventBus),
|
|
2452
|
-
registerActions: globalEventBus.registerActions.bind(globalEventBus),
|
|
2453
|
-
handleAction: globalEventBus.handleAction.bind(globalEventBus),
|
|
2454
|
-
// Statistics and debugging
|
|
2455
|
-
getStats: globalEventBus.getStats.bind(globalEventBus),
|
|
2456
|
-
resetStats: globalEventBus.resetStats.bind(globalEventBus),
|
|
2457
|
-
// Lifecycle
|
|
2458
|
-
destroy() {
|
|
2459
|
-
globalEventBus.destroy();
|
|
2460
|
-
globalDOMIntegration.destroy();
|
|
2461
|
-
}
|
|
2462
|
-
};
|
|
2463
|
-
|
|
2464
|
-
// ../core/src/index.js
|
|
2465
|
-
var scopeCounter = { value: 0 };
|
|
2466
|
-
function generateScopeId() {
|
|
2467
|
-
return `coh-${scopeCounter.value++}`;
|
|
2468
|
-
}
|
|
2469
|
-
function scopeCSS(css, scopeId) {
|
|
2470
|
-
if (!css || typeof css !== "string") return css;
|
|
2471
|
-
return css.replace(/([^{}]*)\s*{/g, (match, selector) => {
|
|
2472
|
-
const selectors = selector.split(",").map((s) => {
|
|
2473
|
-
const trimmed = s.trim();
|
|
2474
|
-
if (!trimmed) return s;
|
|
2475
|
-
if (trimmed.includes(":")) {
|
|
2476
|
-
return trimmed.replace(/([^:]+)(:.*)?/, `$1[${scopeId}]$2`);
|
|
2477
|
-
}
|
|
2478
|
-
return `${trimmed}[${scopeId}]`;
|
|
2479
|
-
});
|
|
2480
|
-
return `${selectors.join(", ")} {`;
|
|
2481
|
-
});
|
|
2482
|
-
}
|
|
2483
|
-
function applyScopeToElement(element, scopeId) {
|
|
2484
|
-
if (typeof element === "string" || typeof element === "number" || !element) {
|
|
2485
|
-
return element;
|
|
2486
|
-
}
|
|
2487
|
-
if (Array.isArray(element)) {
|
|
2488
|
-
return element.map((item) => applyScopeToElement(item, scopeId));
|
|
2489
|
-
}
|
|
2490
|
-
if (typeof element === "object") {
|
|
2491
|
-
const scoped = {};
|
|
2492
|
-
for (const [tagName, props] of Object.entries(element)) {
|
|
2493
|
-
if (typeof props === "object" && props !== null) {
|
|
2494
|
-
const scopedProps = { ...props };
|
|
2495
|
-
scopedProps[scopeId] = "";
|
|
2496
|
-
if (scopedProps.children) {
|
|
2497
|
-
scopedProps.children = applyScopeToElement(scopedProps.children, scopeId);
|
|
2498
|
-
}
|
|
2499
|
-
scoped[tagName] = scopedProps;
|
|
2500
|
-
} else {
|
|
2501
|
-
scoped[tagName] = props;
|
|
2502
|
-
}
|
|
2503
|
-
}
|
|
2504
|
-
return scoped;
|
|
2505
|
-
}
|
|
2506
|
-
return element;
|
|
2507
|
-
}
|
|
2508
|
-
function escapeHtml(text) {
|
|
2509
|
-
if (typeof text !== "string") return text;
|
|
2510
|
-
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
2511
|
-
}
|
|
2512
|
-
function isTrustedContent(value) {
|
|
2513
|
-
return value && typeof value === "object" && value.__trusted === true && typeof value.__html === "string";
|
|
2514
|
-
}
|
|
2515
|
-
function isVoidElement(tagName) {
|
|
2516
|
-
const voidElements = /* @__PURE__ */ new Set([
|
|
2517
|
-
"area",
|
|
2518
|
-
"base",
|
|
2519
|
-
"br",
|
|
2520
|
-
"col",
|
|
2521
|
-
"embed",
|
|
2522
|
-
"hr",
|
|
2523
|
-
"img",
|
|
2524
|
-
"input",
|
|
2525
|
-
"link",
|
|
2526
|
-
"meta",
|
|
2527
|
-
"param",
|
|
2528
|
-
"source",
|
|
2529
|
-
"track",
|
|
2530
|
-
"wbr"
|
|
2531
|
-
]);
|
|
2532
|
-
return voidElements.has(tagName.toLowerCase());
|
|
2533
|
-
}
|
|
2534
|
-
function formatAttributes(attrs) {
|
|
2535
|
-
if (!attrs || typeof attrs !== "object") return "";
|
|
2536
|
-
return Object.entries(attrs).filter(([, value]) => value !== null && value !== void 0 && value !== false).map(([key, value]) => {
|
|
2537
|
-
if (typeof value === "function") {
|
|
2538
|
-
value = value();
|
|
2539
|
-
}
|
|
2540
|
-
const attrName = key === "className" ? "class" : key;
|
|
2541
|
-
if (value === true) return attrName;
|
|
2542
|
-
return `${attrName}="${escapeHtml(String(value))}"`;
|
|
2543
|
-
}).join(" ");
|
|
2544
|
-
}
|
|
2545
|
-
function renderRaw(obj) {
|
|
2546
|
-
if (obj === null || obj === void 0) return "";
|
|
2547
|
-
if (typeof obj === "string" || typeof obj === "number") return escapeHtml(String(obj));
|
|
2548
|
-
if (Array.isArray(obj)) return obj.map(renderRaw).join("");
|
|
2549
|
-
if (typeof obj === "function") {
|
|
2550
|
-
const result = obj(renderRaw);
|
|
2551
|
-
return renderRaw(result);
|
|
2552
|
-
}
|
|
2553
|
-
if (typeof obj !== "object") return escapeHtml(String(obj));
|
|
2554
|
-
if (obj.text !== void 0) {
|
|
2555
|
-
return escapeHtml(String(obj.text));
|
|
2556
|
-
}
|
|
2557
|
-
for (const [tagName, props] of Object.entries(obj)) {
|
|
2558
|
-
if (typeof props === "object" && props !== null) {
|
|
2559
|
-
const { children, text, ...attributes } = props;
|
|
2560
|
-
const attrsStr = formatAttributes(attributes);
|
|
2561
|
-
const openTag = attrsStr ? `<${tagName} ${attrsStr}>` : `<${tagName}>`;
|
|
2562
|
-
if (isVoidElement(tagName)) {
|
|
2563
|
-
return openTag.replace(">", " />");
|
|
2564
|
-
}
|
|
2565
|
-
let content = "";
|
|
2566
|
-
if (text !== void 0) {
|
|
2567
|
-
if (isTrustedContent(text)) {
|
|
2568
|
-
content = text.__html;
|
|
2569
|
-
} else {
|
|
2570
|
-
content = escapeHtml(String(text));
|
|
2571
|
-
}
|
|
2572
|
-
} else if (children) {
|
|
2573
|
-
content = renderRaw(children);
|
|
2574
|
-
}
|
|
2575
|
-
return `${openTag}${content}</${tagName}>`;
|
|
2576
|
-
} else if (typeof props === "string") {
|
|
2577
|
-
const content = isTrustedContent(props) ? props.__html : escapeHtml(props);
|
|
2578
|
-
return isVoidElement(tagName) ? `<${tagName} />` : `<${tagName}>${content}</${tagName}>`;
|
|
2579
|
-
}
|
|
2580
|
-
}
|
|
2581
|
-
return "";
|
|
2582
|
-
}
|
|
2583
|
-
function render(obj, options = {}) {
|
|
2584
|
-
const { scoped = false } = options;
|
|
2585
|
-
if (scoped) {
|
|
2586
|
-
return renderScopedComponent(obj);
|
|
2587
|
-
}
|
|
2588
|
-
return renderRaw(obj);
|
|
2589
|
-
}
|
|
2590
|
-
function renderScopedComponent(component) {
|
|
2591
|
-
const scopeId = generateScopeId();
|
|
2592
|
-
function processScopedElement(element) {
|
|
2593
|
-
if (!element || typeof element !== "object") {
|
|
2594
|
-
return element;
|
|
2595
|
-
}
|
|
2596
|
-
if (Array.isArray(element)) {
|
|
2597
|
-
return element.map(processScopedElement);
|
|
2598
|
-
}
|
|
2599
|
-
const result = {};
|
|
2600
|
-
for (const [tagName, props] of Object.entries(element)) {
|
|
2601
|
-
if (tagName === "style" && typeof props === "object" && props.text) {
|
|
2602
|
-
result[tagName] = {
|
|
2603
|
-
...props,
|
|
2604
|
-
text: scopeCSS(props.text, scopeId)
|
|
2605
|
-
};
|
|
2606
|
-
} else if (typeof props === "object" && props !== null) {
|
|
2607
|
-
const scopedProps = { ...props };
|
|
2608
|
-
if (scopedProps.children) {
|
|
2609
|
-
scopedProps.children = processScopedElement(scopedProps.children);
|
|
2610
|
-
}
|
|
2611
|
-
result[tagName] = scopedProps;
|
|
2612
|
-
} else {
|
|
2613
|
-
result[tagName] = props;
|
|
2614
|
-
}
|
|
2615
|
-
}
|
|
2616
|
-
return result;
|
|
2617
|
-
}
|
|
2618
|
-
const processedComponent = processScopedElement(component);
|
|
2619
|
-
const scopedComponent = applyScopeToElement(processedComponent, scopeId);
|
|
2620
|
-
return renderRaw(scopedComponent);
|
|
2621
|
-
}
|
|
2622
|
-
|
|
2623
|
-
// ../core/src/utils/dependency-utils.js
|
|
2624
|
-
async function importPeerDependency(packageName, integrationName) {
|
|
2625
|
-
try {
|
|
2626
|
-
return await import(packageName);
|
|
2627
|
-
} catch {
|
|
2628
|
-
throw new Error(
|
|
2629
|
-
`${integrationName} integration requires the '${packageName}' package to be installed.
|
|
2630
|
-
Please install it with: npm install ${packageName}
|
|
2631
|
-
Or with pnpm: pnpm add ${packageName}
|
|
2632
|
-
Or with yarn: yarn add ${packageName}`
|
|
2633
|
-
);
|
|
2634
|
-
}
|
|
2635
|
-
}
|
|
2636
|
-
|
|
2637
|
-
// ../core/src/rendering/base-renderer.js
|
|
2638
|
-
var DEFAULT_RENDERER_CONFIG = {
|
|
2639
|
-
// Core rendering options
|
|
2640
|
-
maxDepth: 100,
|
|
2641
|
-
enableValidation: true,
|
|
2642
|
-
enableMonitoring: false,
|
|
2643
|
-
validateInput: true,
|
|
2644
|
-
// HTML Renderer specific options
|
|
2645
|
-
enableCache: true,
|
|
2646
|
-
minify: false,
|
|
2647
|
-
cacheSize: 1e3,
|
|
2648
|
-
cacheTTL: 3e5,
|
|
2649
|
-
// 5 minutes
|
|
2650
|
-
// Streaming Renderer specific options
|
|
2651
|
-
chunkSize: 1024,
|
|
2652
|
-
// Size of each chunk in bytes
|
|
2653
|
-
bufferSize: 4096,
|
|
2654
|
-
// Internal buffer size
|
|
2655
|
-
enableMetrics: false,
|
|
2656
|
-
// Track streaming metrics
|
|
2657
|
-
yieldThreshold: 100,
|
|
2658
|
-
// Yield control after N elements
|
|
2659
|
-
encoding: "utf8",
|
|
2660
|
-
// Output encoding
|
|
2661
|
-
// DOM Renderer specific options
|
|
2662
|
-
enableHydration: true,
|
|
2663
|
-
// Enable hydration support
|
|
2664
|
-
namespace: null,
|
|
2665
|
-
// SVG namespace support
|
|
2666
|
-
// Performance options
|
|
2667
|
-
enablePerformanceTracking: false,
|
|
2668
|
-
performanceThreshold: 10,
|
|
2669
|
-
// ms threshold for slow renders
|
|
2670
|
-
// Development options
|
|
2671
|
-
enableDevWarnings: typeof process !== "undefined" && process.env && true,
|
|
2672
|
-
enableDebugLogging: false,
|
|
2673
|
-
// Error handling options
|
|
2674
|
-
errorFallback: "",
|
|
2675
|
-
// Fallback content on errors
|
|
2676
|
-
throwOnError: true
|
|
2677
|
-
// Whether to throw or return fallback
|
|
2678
|
-
};
|
|
2679
|
-
var BaseRenderer = class {
|
|
2680
|
-
constructor(options = {}) {
|
|
2681
|
-
this.config = this.validateAndMergeConfig(options);
|
|
2682
|
-
this.metrics = {
|
|
2683
|
-
startTime: null,
|
|
2684
|
-
endTime: null,
|
|
2685
|
-
elementsProcessed: 0
|
|
2686
|
-
};
|
|
2687
|
-
}
|
|
2688
|
-
/**
|
|
2689
|
-
* Validate and merge configuration options
|
|
2690
|
-
*/
|
|
2691
|
-
validateAndMergeConfig(options) {
|
|
2692
|
-
const config = { ...DEFAULT_RENDERER_CONFIG, ...options };
|
|
2693
|
-
if (typeof config.maxDepth !== "number") {
|
|
2694
|
-
throw new Error("maxDepth must be a number");
|
|
2695
|
-
}
|
|
2696
|
-
if (config.maxDepth <= 0) {
|
|
2697
|
-
throw new Error("maxDepth must be a positive number");
|
|
2698
|
-
}
|
|
2699
|
-
if (typeof config.chunkSize !== "number") {
|
|
2700
|
-
throw new Error("chunkSize must be a number");
|
|
2701
|
-
}
|
|
2702
|
-
if (config.chunkSize <= 0) {
|
|
2703
|
-
throw new Error("chunkSize must be a positive number");
|
|
2704
|
-
}
|
|
2705
|
-
if (typeof config.yieldThreshold !== "number") {
|
|
2706
|
-
throw new Error("yieldThreshold must be a number");
|
|
2707
|
-
}
|
|
2708
|
-
if (config.yieldThreshold <= 0) {
|
|
2709
|
-
throw new Error("yieldThreshold must be a positive number");
|
|
2710
|
-
}
|
|
2711
|
-
if (config.enableDevWarnings) {
|
|
2712
|
-
if (config.maxDepth > 1e3) {
|
|
2713
|
-
console.warn("Coherent.js: maxDepth > 1000 may cause performance issues");
|
|
2714
|
-
}
|
|
2715
|
-
if (config.chunkSize > 16384) {
|
|
2716
|
-
console.warn("Coherent.js: Large chunkSize may increase memory usage");
|
|
2717
|
-
}
|
|
2718
|
-
}
|
|
2719
|
-
return config;
|
|
2720
|
-
}
|
|
2721
|
-
/**
|
|
2722
|
-
* Get configuration for specific renderer type
|
|
2723
|
-
*/
|
|
2724
|
-
getRendererConfig(rendererType) {
|
|
2725
|
-
const baseConfig = { ...this.config };
|
|
2726
|
-
switch (rendererType) {
|
|
2727
|
-
case "html":
|
|
2728
|
-
return {
|
|
2729
|
-
...baseConfig,
|
|
2730
|
-
// HTML-specific defaults
|
|
2731
|
-
enableCache: baseConfig.enableCache !== false,
|
|
2732
|
-
enableMonitoring: baseConfig.enableMonitoring !== false
|
|
2733
|
-
};
|
|
2734
|
-
case "streaming":
|
|
2735
|
-
return {
|
|
2736
|
-
...baseConfig,
|
|
2737
|
-
// Streaming-specific defaults
|
|
2738
|
-
enableMetrics: baseConfig.enableMetrics ?? false,
|
|
2739
|
-
maxDepth: baseConfig.maxDepth ?? 1e3
|
|
2740
|
-
// Higher default for streaming
|
|
2741
|
-
};
|
|
2742
|
-
case "dom":
|
|
2743
|
-
return {
|
|
2744
|
-
...baseConfig,
|
|
2745
|
-
// DOM-specific defaults
|
|
2746
|
-
enableHydration: baseConfig.enableHydration !== false
|
|
2747
|
-
};
|
|
2748
|
-
default:
|
|
2749
|
-
return baseConfig;
|
|
2750
|
-
}
|
|
2751
|
-
}
|
|
2752
|
-
/**
|
|
2753
|
-
* Validate component structure
|
|
2754
|
-
*/
|
|
2755
|
-
validateComponent(component) {
|
|
2756
|
-
if (this.config.validateInput !== false) {
|
|
2757
|
-
return validateComponent(component);
|
|
2758
|
-
}
|
|
2759
|
-
return true;
|
|
2760
|
-
}
|
|
2761
|
-
/**
|
|
2762
|
-
* Check if component is valid for rendering
|
|
2763
|
-
*/
|
|
2764
|
-
isValidComponent(component) {
|
|
2765
|
-
if (component === null || component === void 0) return true;
|
|
2766
|
-
if (typeof component === "string" || typeof component === "number") return true;
|
|
2767
|
-
if (typeof component === "function") return true;
|
|
2768
|
-
if (Array.isArray(component)) return component.every((child) => this.isValidComponent(child));
|
|
2769
|
-
if (isCoherentObject(component)) return true;
|
|
2770
|
-
return false;
|
|
2771
|
-
}
|
|
2772
|
-
/**
|
|
2773
|
-
* Validate rendering depth to prevent stack overflow
|
|
2774
|
-
*/
|
|
2775
|
-
validateDepth(depth) {
|
|
2776
|
-
if (depth > this.config.maxDepth) {
|
|
2777
|
-
throw new Error(`Maximum render depth (${this.config.maxDepth}) exceeded`);
|
|
2778
|
-
}
|
|
2779
|
-
}
|
|
2780
|
-
/**
|
|
2781
|
-
* Handle different component types with consistent logic
|
|
2782
|
-
*/
|
|
2783
|
-
processComponentType(component) {
|
|
2784
|
-
if (component === null || component === void 0) {
|
|
2785
|
-
return { type: "empty", value: "" };
|
|
2786
|
-
}
|
|
2787
|
-
if (typeof component === "string") {
|
|
2788
|
-
return { type: "text", value: component };
|
|
2789
|
-
}
|
|
2790
|
-
if (typeof component === "number" || typeof component === "boolean") {
|
|
2791
|
-
return { type: "text", value: String(component) };
|
|
2792
|
-
}
|
|
2793
|
-
if (typeof component === "function") {
|
|
2794
|
-
return { type: "function", value: component };
|
|
2795
|
-
}
|
|
2796
|
-
if (Array.isArray(component)) {
|
|
2797
|
-
return { type: "array", value: component };
|
|
2798
|
-
}
|
|
2799
|
-
if (isCoherentObject(component)) {
|
|
2800
|
-
return { type: "element", value: component };
|
|
2801
|
-
}
|
|
2802
|
-
return { type: "unknown", value: component };
|
|
2803
|
-
}
|
|
2804
|
-
/**
|
|
2805
|
-
* Execute function components with _error handling
|
|
2806
|
-
*/
|
|
2807
|
-
executeFunctionComponent(func, depth = 0) {
|
|
2808
|
-
try {
|
|
2809
|
-
const isContextProvider = func.length > 0 || func.isContextProvider;
|
|
2810
|
-
let result;
|
|
2811
|
-
if (isContextProvider) {
|
|
2812
|
-
result = func((children) => {
|
|
2813
|
-
return this.renderComponent(children, this.config, depth + 1);
|
|
2814
|
-
});
|
|
2815
|
-
} else {
|
|
2816
|
-
result = func();
|
|
2817
|
-
}
|
|
2818
|
-
if (typeof result === "function") {
|
|
2819
|
-
return this.executeFunctionComponent(result, depth);
|
|
2820
|
-
}
|
|
2821
|
-
return result;
|
|
2822
|
-
} catch (_error) {
|
|
2823
|
-
if (this.config.enableMonitoring) {
|
|
2824
|
-
performanceMonitor2.recordError("functionComponent", _error);
|
|
2825
|
-
}
|
|
2826
|
-
if (typeof process !== "undefined" && process.env && true) {
|
|
2827
|
-
console.warn("Coherent.js Function Component Error:", _error.message);
|
|
2828
|
-
}
|
|
2829
|
-
return null;
|
|
2830
|
-
}
|
|
2831
|
-
}
|
|
2832
|
-
/**
|
|
2833
|
-
* Process element children consistently
|
|
2834
|
-
*/
|
|
2835
|
-
processChildren(children, options, depth) {
|
|
2836
|
-
if (!hasChildren({ children })) {
|
|
2837
|
-
return [];
|
|
2838
|
-
}
|
|
2839
|
-
const normalizedChildren = normalizeChildren(children);
|
|
2840
|
-
return normalizedChildren.map(
|
|
2841
|
-
(child) => this.renderComponent(child, options, depth + 1)
|
|
2842
|
-
);
|
|
2843
|
-
}
|
|
2844
|
-
/**
|
|
2845
|
-
* Extract and process element attributes
|
|
2846
|
-
*/
|
|
2847
|
-
extractElementAttributes(props) {
|
|
2848
|
-
if (!props || typeof props !== "object") return {};
|
|
2849
|
-
const attributes = { ...props };
|
|
2850
|
-
delete attributes.children;
|
|
2851
|
-
delete attributes.text;
|
|
2852
|
-
return attributes;
|
|
2853
|
-
}
|
|
2854
|
-
/**
|
|
2855
|
-
* Record performance metrics
|
|
2856
|
-
*/
|
|
2857
|
-
recordPerformance(operation, startTime, fromCache = false, metadata = {}) {
|
|
2858
|
-
if (this.config.enableMonitoring) {
|
|
2859
|
-
performanceMonitor2.recordRender(
|
|
2860
|
-
operation,
|
|
2861
|
-
this.getCurrentTime() - startTime,
|
|
2862
|
-
fromCache,
|
|
2863
|
-
metadata
|
|
2864
|
-
);
|
|
2865
|
-
}
|
|
2866
|
-
}
|
|
2867
|
-
/**
|
|
2868
|
-
* Record _error for monitoring
|
|
2869
|
-
*/
|
|
2870
|
-
recordError(operation, _error, metadata = {}) {
|
|
2871
|
-
if (this.config.enableMonitoring) {
|
|
2872
|
-
performanceMonitor2.recordError(operation, _error, metadata);
|
|
2873
|
-
}
|
|
2874
|
-
}
|
|
2875
|
-
/**
|
|
2876
|
-
* Get current timestamp with fallback
|
|
2877
|
-
*/
|
|
2878
|
-
getCurrentTime() {
|
|
2879
|
-
if (typeof performance !== "undefined" && performance.now) {
|
|
2880
|
-
return performance.now();
|
|
2881
|
-
}
|
|
2882
|
-
return Date.now();
|
|
2883
|
-
}
|
|
2884
|
-
/**
|
|
2885
|
-
* Start performance timing
|
|
2886
|
-
*/
|
|
2887
|
-
startTiming() {
|
|
2888
|
-
this.metrics.startTime = this.getCurrentTime();
|
|
2889
|
-
}
|
|
2890
|
-
/**
|
|
2891
|
-
* End performance timing
|
|
2892
|
-
*/
|
|
2893
|
-
endTiming() {
|
|
2894
|
-
this.metrics.endTime = this.getCurrentTime();
|
|
2895
|
-
}
|
|
2896
|
-
/**
|
|
2897
|
-
* Get performance metrics
|
|
2898
|
-
*/
|
|
2899
|
-
getMetrics() {
|
|
2900
|
-
const duration = this.metrics.endTime ? this.metrics.endTime - this.metrics.startTime : this.getCurrentTime() - this.metrics.startTime;
|
|
2901
|
-
return {
|
|
2902
|
-
...this.metrics,
|
|
2903
|
-
duration,
|
|
2904
|
-
elementsPerSecond: this.metrics.elementsProcessed / (duration / 1e3)
|
|
2905
|
-
};
|
|
2906
|
-
}
|
|
2907
|
-
/**
|
|
2908
|
-
* Reset metrics for new render
|
|
2909
|
-
*/
|
|
2910
|
-
resetMetrics() {
|
|
2911
|
-
this.metrics = {
|
|
2912
|
-
startTime: null,
|
|
2913
|
-
endTime: null,
|
|
2914
|
-
elementsProcessed: 0
|
|
2915
|
-
};
|
|
2916
|
-
}
|
|
2917
|
-
/**
|
|
2918
|
-
* Abstract method - must be implemented by subclasses
|
|
2919
|
-
*/
|
|
2920
|
-
renderComponent() {
|
|
2921
|
-
throw new Error("renderComponent must be implemented by subclass");
|
|
2922
|
-
}
|
|
2923
|
-
/**
|
|
2924
|
-
* Abstract method - must be implemented by subclasses
|
|
2925
|
-
*/
|
|
2926
|
-
render() {
|
|
2927
|
-
throw new Error("render must be implemented by subclass");
|
|
2928
|
-
}
|
|
2929
|
-
};
|
|
2930
|
-
var RendererUtils = {
|
|
2931
|
-
/**
|
|
2932
|
-
* Check if element is static (no functions)
|
|
2933
|
-
*/
|
|
2934
|
-
isStaticElement(element) {
|
|
2935
|
-
if (!element || typeof element !== "object") {
|
|
2936
|
-
return typeof element === "string" || typeof element === "number";
|
|
2937
|
-
}
|
|
2938
|
-
for (const [key, value] of Object.entries(element)) {
|
|
2939
|
-
if (typeof value === "function") return false;
|
|
2940
|
-
if (key === "children" && Array.isArray(value)) {
|
|
2941
|
-
return value.every((child) => RendererUtils.isStaticElement(child));
|
|
2942
|
-
}
|
|
2943
|
-
if (key === "children" && typeof value === "object" && value !== null) {
|
|
2944
|
-
return RendererUtils.isStaticElement(value);
|
|
2945
|
-
}
|
|
2946
|
-
}
|
|
2947
|
-
return true;
|
|
2948
|
-
},
|
|
2949
|
-
/**
|
|
2950
|
-
* Check if object has functions (for caching decisions)
|
|
2951
|
-
*/
|
|
2952
|
-
hasFunctions(obj, visited = /* @__PURE__ */ new WeakSet()) {
|
|
2953
|
-
if (visited.has(obj)) return false;
|
|
2954
|
-
visited.add(obj);
|
|
2955
|
-
for (const value of Object.values(obj)) {
|
|
2956
|
-
if (typeof value === "function") return true;
|
|
2957
|
-
if (typeof value === "object" && value !== null && RendererUtils.hasFunctions(value, visited)) {
|
|
2958
|
-
return true;
|
|
2959
|
-
}
|
|
2960
|
-
}
|
|
2961
|
-
return false;
|
|
2962
|
-
},
|
|
2963
|
-
/**
|
|
2964
|
-
* Get element complexity score
|
|
2965
|
-
*/
|
|
2966
|
-
getElementComplexity(element) {
|
|
2967
|
-
if (!element || typeof element !== "object") return 1;
|
|
2968
|
-
let complexity = Object.keys(element).length;
|
|
2969
|
-
if (element.children && Array.isArray(element.children)) {
|
|
2970
|
-
complexity += element.children.reduce(
|
|
2971
|
-
(sum, child) => sum + RendererUtils.getElementComplexity(child),
|
|
2972
|
-
0
|
|
2973
|
-
);
|
|
2974
|
-
}
|
|
2975
|
-
return complexity;
|
|
2976
|
-
},
|
|
2977
|
-
/**
|
|
2978
|
-
* Generate cache key for element
|
|
2979
|
-
*/
|
|
2980
|
-
generateCacheKey(tagName, element) {
|
|
2981
|
-
try {
|
|
2982
|
-
const keyData = {
|
|
2983
|
-
tag: tagName,
|
|
2984
|
-
props: extractProps(element),
|
|
2985
|
-
hasChildren: hasChildren(element),
|
|
2986
|
-
childrenType: Array.isArray(element.children) ? "array" : typeof element.children
|
|
2987
|
-
};
|
|
2988
|
-
return `element:${JSON.stringify(keyData)}`;
|
|
2989
|
-
} catch (_error) {
|
|
2990
|
-
if (typeof process !== "undefined" && process.env && true) {
|
|
2991
|
-
console.warn("Failed to generate cache key:", _error);
|
|
2992
|
-
}
|
|
2993
|
-
return null;
|
|
2994
|
-
}
|
|
2995
|
-
},
|
|
2996
|
-
/**
|
|
2997
|
-
* Check if element is cacheable
|
|
2998
|
-
*/
|
|
2999
|
-
isCacheable(element, options) {
|
|
3000
|
-
if (!options.enableCache) return false;
|
|
3001
|
-
if (RendererUtils.hasFunctions(element)) return false;
|
|
3002
|
-
if (RendererUtils.getElementComplexity(element) > 1e3) return false;
|
|
3003
|
-
const cacheKey = RendererUtils.generateCacheKey(element.tagName || "unknown", element);
|
|
3004
|
-
if (!cacheKey) return false;
|
|
3005
|
-
return true;
|
|
3006
|
-
}
|
|
3007
|
-
};
|
|
3008
|
-
|
|
3009
|
-
// ../core/src/core/html-utils.js
|
|
3010
|
-
function escapeHtml2(text) {
|
|
3011
|
-
if (typeof text !== "string") return text;
|
|
3012
|
-
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
3013
|
-
}
|
|
3014
|
-
function isVoidElement2(tagName) {
|
|
3015
|
-
if (typeof tagName !== "string") {
|
|
3016
|
-
return false;
|
|
3017
|
-
}
|
|
3018
|
-
const voidElements = /* @__PURE__ */ new Set([
|
|
3019
|
-
"area",
|
|
3020
|
-
"base",
|
|
3021
|
-
"br",
|
|
3022
|
-
"col",
|
|
3023
|
-
"embed",
|
|
3024
|
-
"hr",
|
|
3025
|
-
"img",
|
|
3026
|
-
"input",
|
|
3027
|
-
"link",
|
|
3028
|
-
"meta",
|
|
3029
|
-
"param",
|
|
3030
|
-
"source",
|
|
3031
|
-
"track",
|
|
3032
|
-
"wbr"
|
|
3033
|
-
]);
|
|
3034
|
-
return voidElements.has(tagName.toLowerCase());
|
|
3035
|
-
}
|
|
3036
|
-
function formatAttributes2(props) {
|
|
3037
|
-
let formatted = "";
|
|
3038
|
-
for (const key in props) {
|
|
3039
|
-
if (props.hasOwnProperty(key)) {
|
|
3040
|
-
let value = props[key];
|
|
3041
|
-
const attributeName = key === "className" ? "class" : key;
|
|
3042
|
-
if (typeof value === "function") {
|
|
3043
|
-
if (attributeName.startsWith("on")) {
|
|
3044
|
-
const actionId = `__coherent_action_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
3045
|
-
const DEBUG = typeof process !== "undefined" && process && process.env && (process.env.COHERENT_DEBUG === "1" || true) || typeof window !== "undefined" && window && window.COHERENT_DEBUG === true;
|
|
3046
|
-
if (typeof global !== "undefined") {
|
|
3047
|
-
if (!global.__coherentActionRegistry) {
|
|
3048
|
-
global.__coherentActionRegistry = {};
|
|
3049
|
-
if (DEBUG) console.log("Initialized global action registry");
|
|
3050
|
-
}
|
|
3051
|
-
global.__coherentActionRegistry[actionId] = value;
|
|
3052
|
-
if (DEBUG) console.log(`Added action ${actionId} to global registry, total: ${Object.keys(global.__coherentActionRegistry).length}`);
|
|
3053
|
-
if (DEBUG) console.log(`Global registry keys: ${Object.keys(global.__coherentActionRegistry).join(", ")}`);
|
|
3054
|
-
if (DEBUG) {
|
|
3055
|
-
if (typeof global.__coherentActionRegistryLog === "undefined") {
|
|
3056
|
-
global.__coherentActionRegistryLog = [];
|
|
3057
|
-
}
|
|
3058
|
-
global.__coherentActionRegistryLog.push({
|
|
3059
|
-
action: "add",
|
|
3060
|
-
actionId,
|
|
3061
|
-
timestamp: Date.now(),
|
|
3062
|
-
registrySize: Object.keys(global.__coherentActionRegistry).length
|
|
3063
|
-
});
|
|
3064
|
-
}
|
|
3065
|
-
} else if (typeof window !== "undefined") {
|
|
3066
|
-
if (!window.__coherentActionRegistry) {
|
|
3067
|
-
window.__coherentActionRegistry = {};
|
|
3068
|
-
if (DEBUG) console.log("Initialized window action registry");
|
|
3069
|
-
}
|
|
3070
|
-
window.__coherentActionRegistry[actionId] = value;
|
|
3071
|
-
if (DEBUG) console.log(`Added action ${actionId} to window registry, total: ${Object.keys(window.__coherentActionRegistry).length}`);
|
|
3072
|
-
if (DEBUG) console.log(`Window registry keys: ${Object.keys(window.__coherentActionRegistry).join(", ")}`);
|
|
3073
|
-
}
|
|
3074
|
-
const eventType = attributeName.substring(2);
|
|
3075
|
-
formatted += ` data-action="${actionId}" data-event="${eventType}"`;
|
|
3076
|
-
continue;
|
|
3077
|
-
} else {
|
|
3078
|
-
try {
|
|
3079
|
-
value = value();
|
|
3080
|
-
} catch (_error) {
|
|
3081
|
-
console.warn(`Error executing function for attribute '${key}':`, {
|
|
3082
|
-
_error: _error.message,
|
|
3083
|
-
stack: _error.stack,
|
|
3084
|
-
attributeKey: key
|
|
3085
|
-
});
|
|
3086
|
-
value = "";
|
|
3087
|
-
}
|
|
3088
|
-
}
|
|
3089
|
-
}
|
|
3090
|
-
if (value === true) {
|
|
3091
|
-
formatted += ` ${attributeName}`;
|
|
3092
|
-
} else if (value !== false && value !== null && value !== void 0) {
|
|
3093
|
-
formatted += ` ${attributeName}="${escapeHtml2(String(value))}"`;
|
|
3094
|
-
}
|
|
3095
|
-
}
|
|
3096
|
-
}
|
|
3097
|
-
return formatted.trim();
|
|
3098
|
-
}
|
|
3099
|
-
function minifyHtml(html, options = {}) {
|
|
3100
|
-
if (!options.minify) return html;
|
|
3101
|
-
return html.replace(/<!--[\s\S]*?-->/g, "").replace(/\s+/g, " ").replace(/>\s+</g, "><").trim();
|
|
3102
|
-
}
|
|
3103
|
-
|
|
3104
|
-
// ../core/src/performance/cache-manager.js
|
|
3105
|
-
function createCacheManager(options = {}) {
|
|
3106
|
-
const {
|
|
3107
|
-
maxCacheSize = 1e3,
|
|
3108
|
-
maxMemoryMB = 100,
|
|
3109
|
-
ttlMs = 1e3 * 60 * 5,
|
|
3110
|
-
// 5 minutes
|
|
3111
|
-
enableStatistics = true
|
|
3112
|
-
} = options;
|
|
3113
|
-
const caches = {
|
|
3114
|
-
static: /* @__PURE__ */ new Map(),
|
|
3115
|
-
// Never-changing components
|
|
3116
|
-
component: /* @__PURE__ */ new Map(),
|
|
3117
|
-
// Component results with deps
|
|
3118
|
-
template: /* @__PURE__ */ new Map(),
|
|
3119
|
-
// Template strings
|
|
3120
|
-
data: /* @__PURE__ */ new Map()
|
|
3121
|
-
// General purpose data
|
|
3122
|
-
};
|
|
3123
|
-
let memoryUsage = 0;
|
|
3124
|
-
const stats = {
|
|
3125
|
-
hits: 0,
|
|
3126
|
-
misses: 0,
|
|
3127
|
-
hitRate: {
|
|
3128
|
-
static: 0,
|
|
3129
|
-
component: 0,
|
|
3130
|
-
template: 0,
|
|
3131
|
-
data: 0
|
|
3132
|
-
},
|
|
3133
|
-
accessCount: {
|
|
3134
|
-
static: 0,
|
|
3135
|
-
component: 0,
|
|
3136
|
-
template: 0,
|
|
3137
|
-
data: 0
|
|
3138
|
-
}
|
|
3139
|
-
};
|
|
3140
|
-
let cleanupInterval;
|
|
3141
|
-
if (typeof setInterval === "function") {
|
|
3142
|
-
cleanupInterval = setInterval(() => cleanup(), 3e4);
|
|
3143
|
-
if (cleanupInterval.unref) {
|
|
3144
|
-
cleanupInterval.unref();
|
|
3145
|
-
}
|
|
3146
|
-
}
|
|
3147
|
-
function generateCacheKey(component, props = {}, context2 = {}) {
|
|
3148
|
-
const componentStr = typeof component === "function" ? component.name || component.toString() : JSON.stringify(component);
|
|
3149
|
-
const propsStr = JSON.stringify(props, Object.keys(props).sort());
|
|
3150
|
-
const contextStr = JSON.stringify(context2);
|
|
3151
|
-
const hash = simpleHash(componentStr + propsStr + contextStr);
|
|
3152
|
-
return `${extractComponentName(component)}_${hash}`;
|
|
3153
|
-
}
|
|
3154
|
-
function get(key, type = "component") {
|
|
3155
|
-
const cache = caches[type] || caches.component;
|
|
3156
|
-
const entry = cache.get(key);
|
|
3157
|
-
if (!entry) {
|
|
3158
|
-
stats.misses++;
|
|
3159
|
-
if (enableStatistics) stats.accessCount[type]++;
|
|
3160
|
-
return null;
|
|
3161
|
-
}
|
|
3162
|
-
if (Date.now() - entry.timestamp > ttlMs) {
|
|
3163
|
-
cache.delete(key);
|
|
3164
|
-
updateMemoryUsage(-entry.size);
|
|
3165
|
-
stats.misses++;
|
|
3166
|
-
if (enableStatistics) stats.accessCount[type]++;
|
|
3167
|
-
return null;
|
|
3168
|
-
}
|
|
3169
|
-
entry.lastAccess = Date.now();
|
|
3170
|
-
entry.accessCount++;
|
|
3171
|
-
stats.hits++;
|
|
3172
|
-
if (enableStatistics) {
|
|
3173
|
-
stats.accessCount[type]++;
|
|
3174
|
-
stats.hitRate[type] = stats.hits / (stats.hits + stats.misses) * 100;
|
|
3175
|
-
}
|
|
3176
|
-
return entry.value;
|
|
3177
|
-
}
|
|
3178
|
-
function set(key, value, type = "component", metadata = {}) {
|
|
3179
|
-
const cache = caches[type] || caches.component;
|
|
3180
|
-
const size = calculateSize(value);
|
|
3181
|
-
if (memoryUsage + size > maxMemoryMB * 1024 * 1024) {
|
|
3182
|
-
optimize(type, size);
|
|
3183
|
-
}
|
|
3184
|
-
const entry = {
|
|
3185
|
-
value,
|
|
3186
|
-
timestamp: Date.now(),
|
|
3187
|
-
lastAccess: Date.now(),
|
|
3188
|
-
size,
|
|
3189
|
-
metadata,
|
|
3190
|
-
accessCount: 0
|
|
3191
|
-
};
|
|
3192
|
-
const existing = cache.get(key);
|
|
3193
|
-
if (existing) {
|
|
3194
|
-
updateMemoryUsage(-existing.size);
|
|
3195
|
-
}
|
|
3196
|
-
cache.set(key, entry);
|
|
3197
|
-
updateMemoryUsage(size);
|
|
3198
|
-
if (cache.size > maxCacheSize) {
|
|
3199
|
-
optimize(type);
|
|
3200
|
-
}
|
|
3201
|
-
}
|
|
3202
|
-
function remove(key, type) {
|
|
3203
|
-
if (type) {
|
|
3204
|
-
const cache = caches[type];
|
|
3205
|
-
if (!cache) return false;
|
|
3206
|
-
const entry = cache.get(key);
|
|
3207
|
-
if (entry) {
|
|
3208
|
-
updateMemoryUsage(-entry.size);
|
|
3209
|
-
return cache.delete(key);
|
|
3210
|
-
}
|
|
3211
|
-
return false;
|
|
3212
|
-
}
|
|
3213
|
-
for (const [, cache] of Object.entries(caches)) {
|
|
3214
|
-
const entry = cache.get(key);
|
|
3215
|
-
if (entry) {
|
|
3216
|
-
updateMemoryUsage(-entry.size);
|
|
3217
|
-
return cache.delete(key);
|
|
3218
|
-
}
|
|
3219
|
-
}
|
|
3220
|
-
return false;
|
|
3221
|
-
}
|
|
3222
|
-
function clear(type) {
|
|
3223
|
-
if (type) {
|
|
3224
|
-
const cache = caches[type];
|
|
3225
|
-
if (cache) {
|
|
3226
|
-
cache.clear();
|
|
3227
|
-
}
|
|
3228
|
-
} else {
|
|
3229
|
-
Object.values(caches).forEach((cache) => cache.clear());
|
|
3230
|
-
}
|
|
3231
|
-
memoryUsage = 0;
|
|
3232
|
-
}
|
|
3233
|
-
function getStats() {
|
|
3234
|
-
const entries = Object.values(caches).reduce((sum, cache) => sum + cache.size, 0);
|
|
3235
|
-
return {
|
|
3236
|
-
hits: stats.hits,
|
|
3237
|
-
misses: stats.misses,
|
|
3238
|
-
size: memoryUsage,
|
|
3239
|
-
entries,
|
|
3240
|
-
hitRate: stats.hitRate,
|
|
3241
|
-
accessCount: stats.accessCount
|
|
3242
|
-
};
|
|
3243
|
-
}
|
|
3244
|
-
function cleanup() {
|
|
3245
|
-
const now = Date.now();
|
|
3246
|
-
let freed = 0;
|
|
3247
|
-
for (const [, cache] of Object.entries(caches)) {
|
|
3248
|
-
for (const [key, entry] of cache.entries()) {
|
|
3249
|
-
if (now - entry.timestamp > ttlMs) {
|
|
3250
|
-
cache.delete(key);
|
|
3251
|
-
updateMemoryUsage(-entry.size);
|
|
3252
|
-
freed++;
|
|
3253
|
-
}
|
|
3254
|
-
}
|
|
3255
|
-
}
|
|
3256
|
-
return { freed };
|
|
3257
|
-
}
|
|
3258
|
-
function calculateSize(value) {
|
|
3259
|
-
if (value === null || value === void 0) return 0;
|
|
3260
|
-
if (typeof value === "string") return value.length * 2;
|
|
3261
|
-
if (typeof value === "number") return 8;
|
|
3262
|
-
if (typeof value === "boolean") return 4;
|
|
3263
|
-
if (Array.isArray(value)) {
|
|
3264
|
-
return value.reduce((sum, item) => sum + calculateSize(item), 0);
|
|
3265
|
-
}
|
|
3266
|
-
if (typeof value === "object") {
|
|
3267
|
-
return Object.values(value).reduce((sum, val) => sum + calculateSize(val), 0);
|
|
3268
|
-
}
|
|
3269
|
-
return 0;
|
|
3270
|
-
}
|
|
3271
|
-
function updateMemoryUsage(delta) {
|
|
3272
|
-
memoryUsage = Math.max(0, memoryUsage + delta);
|
|
3273
|
-
}
|
|
3274
|
-
function optimize(type, requiredSpace = 0) {
|
|
3275
|
-
const cache = caches[type] || caches.component;
|
|
3276
|
-
const entries = Array.from(cache.entries()).sort(([, a], [, b]) => a.lastAccess - b.lastAccess);
|
|
3277
|
-
let freed = 0;
|
|
3278
|
-
for (const [key, entry] of entries) {
|
|
3279
|
-
if (freed >= requiredSpace) break;
|
|
3280
|
-
cache.delete(key);
|
|
3281
|
-
updateMemoryUsage(-entry.size);
|
|
3282
|
-
freed += entry.size;
|
|
3283
|
-
}
|
|
3284
|
-
return { freed };
|
|
3285
|
-
}
|
|
3286
|
-
function simpleHash(str) {
|
|
3287
|
-
let hash = 0;
|
|
3288
|
-
for (let i = 0; i < str.length; i++) {
|
|
3289
|
-
const char = str.charCodeAt(i);
|
|
3290
|
-
hash = (hash << 5) - hash + char;
|
|
3291
|
-
hash = hash & hash;
|
|
3292
|
-
}
|
|
3293
|
-
return Math.abs(hash).toString(36);
|
|
3294
|
-
}
|
|
3295
|
-
function extractComponentName(component) {
|
|
3296
|
-
if (typeof component === "function") {
|
|
3297
|
-
return component.name || "AnonymousComponent";
|
|
3298
|
-
}
|
|
3299
|
-
if (component && typeof component === "object") {
|
|
3300
|
-
const keys = Object.keys(component);
|
|
3301
|
-
return keys.length > 0 ? keys[0] : "ObjectComponent";
|
|
3302
|
-
}
|
|
3303
|
-
return "UnknownComponent";
|
|
3304
|
-
}
|
|
3305
|
-
function destroy() {
|
|
3306
|
-
if (cleanupInterval) {
|
|
3307
|
-
clearInterval(cleanupInterval);
|
|
3308
|
-
}
|
|
3309
|
-
clear();
|
|
3310
|
-
}
|
|
3311
|
-
return {
|
|
3312
|
-
get,
|
|
3313
|
-
set,
|
|
3314
|
-
remove,
|
|
3315
|
-
clear,
|
|
3316
|
-
getStats,
|
|
3317
|
-
cleanup,
|
|
3318
|
-
destroy,
|
|
3319
|
-
generateCacheKey,
|
|
3320
|
-
get memoryUsage() {
|
|
3321
|
-
return memoryUsage;
|
|
3322
|
-
},
|
|
3323
|
-
get maxMemory() {
|
|
3324
|
-
return maxMemoryMB * 1024 * 1024;
|
|
3325
|
-
}
|
|
3326
|
-
};
|
|
3327
|
-
}
|
|
3328
|
-
var cacheManager = createCacheManager();
|
|
3329
|
-
|
|
3330
|
-
// ../core/src/rendering/css-manager.js
|
|
3331
|
-
var import_promises = __toESM(require("node:fs/promises"), 1);
|
|
3332
|
-
var import_node_path = __toESM(require("node:path"), 1);
|
|
3333
|
-
var CSSManager = class {
|
|
3334
|
-
constructor(options = {}) {
|
|
3335
|
-
this.options = {
|
|
3336
|
-
basePath: process.cwd(),
|
|
3337
|
-
minify: false,
|
|
3338
|
-
cache: true,
|
|
3339
|
-
autoprefixer: false,
|
|
3340
|
-
...options
|
|
3341
|
-
};
|
|
3342
|
-
this.cache = /* @__PURE__ */ new Map();
|
|
3343
|
-
this.loadedFiles = /* @__PURE__ */ new Set();
|
|
3344
|
-
}
|
|
3345
|
-
/**
|
|
3346
|
-
* Load CSS file content
|
|
3347
|
-
*/
|
|
3348
|
-
async loadCSSFile(filePath) {
|
|
3349
|
-
const fullPath = import_node_path.default.resolve(this.options.basePath, filePath);
|
|
3350
|
-
const cacheKey = fullPath;
|
|
3351
|
-
if (this.options.cache && this.cache.has(cacheKey)) {
|
|
3352
|
-
return this.cache.get(cacheKey);
|
|
3353
|
-
}
|
|
3354
|
-
try {
|
|
3355
|
-
let content = await import_promises.default.readFile(fullPath, "utf8");
|
|
3356
|
-
if (this.options.minify) {
|
|
3357
|
-
content = this.minifyCSS(content);
|
|
3358
|
-
}
|
|
3359
|
-
if (this.options.cache) {
|
|
3360
|
-
this.cache.set(cacheKey, content);
|
|
3361
|
-
}
|
|
3362
|
-
this.loadedFiles.add(filePath);
|
|
3363
|
-
return content;
|
|
3364
|
-
} catch (_error) {
|
|
3365
|
-
console.warn(`Failed to load CSS file: ${filePath}`, _error.message);
|
|
3366
|
-
return "";
|
|
3367
|
-
}
|
|
3368
|
-
}
|
|
3369
|
-
/**
|
|
3370
|
-
* Load multiple CSS files
|
|
3371
|
-
*/
|
|
3372
|
-
async loadCSSFiles(filePaths) {
|
|
3373
|
-
if (!Array.isArray(filePaths)) {
|
|
3374
|
-
filePaths = [filePaths];
|
|
3375
|
-
}
|
|
3376
|
-
const cssContents = await Promise.all(
|
|
3377
|
-
filePaths.map((filePath) => this.loadCSSFile(filePath))
|
|
3378
|
-
);
|
|
3379
|
-
return cssContents.join("\n");
|
|
3380
|
-
}
|
|
3381
|
-
/**
|
|
3382
|
-
* Generate CSS link tags for external files
|
|
3383
|
-
*/
|
|
3384
|
-
generateCSSLinks(filePaths, baseUrl = "/") {
|
|
3385
|
-
if (!Array.isArray(filePaths)) {
|
|
3386
|
-
filePaths = [filePaths];
|
|
3387
|
-
}
|
|
3388
|
-
return filePaths.map((filePath) => {
|
|
3389
|
-
const href = filePath.startsWith("http") ? filePath : `${baseUrl}${filePath}`.replace(/\/+/g, "/");
|
|
3390
|
-
return `<link rel="stylesheet" href="${this.escapeHtml(href)}" />`;
|
|
3391
|
-
}).join("\n");
|
|
3392
|
-
}
|
|
3393
|
-
/**
|
|
3394
|
-
* Generate inline style tag with CSS content
|
|
3395
|
-
*/
|
|
3396
|
-
generateInlineStyles(cssContent) {
|
|
3397
|
-
if (!cssContent) return "";
|
|
3398
|
-
return `<style type="text/css">
|
|
3399
|
-
${cssContent}
|
|
3400
|
-
</style>`;
|
|
3401
|
-
}
|
|
3402
|
-
/**
|
|
3403
|
-
* Basic CSS minification
|
|
3404
|
-
*/
|
|
3405
|
-
minifyCSS(css) {
|
|
3406
|
-
return css.replace(/\/\*[\s\S]*?\*\//g, "").replace(/\s+/g, " ").replace(/;\s*}/g, "}").replace(/{\s+/g, "{").replace(/;\s+/g, ";").trim();
|
|
3407
|
-
}
|
|
3408
|
-
/**
|
|
3409
|
-
* Escape HTML entities
|
|
3410
|
-
*/
|
|
3411
|
-
escapeHtml(text) {
|
|
3412
|
-
const div = { textContent: text };
|
|
3413
|
-
return div.innerHTML || text;
|
|
3414
|
-
}
|
|
3415
|
-
/**
|
|
3416
|
-
* Clear cache
|
|
3417
|
-
*/
|
|
3418
|
-
clearCache() {
|
|
3419
|
-
this.cache.clear();
|
|
3420
|
-
this.loadedFiles.clear();
|
|
3421
|
-
}
|
|
3422
|
-
/**
|
|
3423
|
-
* Get loaded file list
|
|
3424
|
-
*/
|
|
3425
|
-
getLoadedFiles() {
|
|
3426
|
-
return Array.from(this.loadedFiles);
|
|
3427
|
-
}
|
|
3428
|
-
};
|
|
3429
|
-
var defaultCSSManager = new CSSManager();
|
|
3430
|
-
|
|
3431
|
-
// ../core/src/rendering/html-renderer.js
|
|
3432
|
-
var rendererCache = createCacheManager({
|
|
3433
|
-
maxSize: 1e3,
|
|
3434
|
-
ttlMs: 3e5
|
|
3435
|
-
// 5 minutes
|
|
3436
|
-
});
|
|
3437
|
-
var HTMLRenderer = class extends BaseRenderer {
|
|
3438
|
-
constructor(options = {}) {
|
|
3439
|
-
super({
|
|
3440
|
-
enableCache: options.enableCache !== false,
|
|
3441
|
-
enableMonitoring: options.enableMonitoring !== false,
|
|
3442
|
-
minify: options.minify || false,
|
|
3443
|
-
streaming: options.streaming || false,
|
|
3444
|
-
maxDepth: options.maxDepth || 100,
|
|
3445
|
-
...options
|
|
3446
|
-
});
|
|
3447
|
-
if (this.config.enableCache && !this.cache) {
|
|
3448
|
-
this.cache = rendererCache;
|
|
3449
|
-
}
|
|
3450
|
-
}
|
|
3451
|
-
/**
|
|
3452
|
-
* Main render method - converts components to HTML string
|
|
3453
|
-
*
|
|
3454
|
-
* @param {Object|Array|string|Function} component - Component to render
|
|
3455
|
-
* @param {Object} [options={}] - Rendering options
|
|
3456
|
-
* @param {Object} [options.context] - Rendering context
|
|
3457
|
-
* @param {boolean} [options.enableCache] - Override cache setting
|
|
3458
|
-
* @param {number} [options.depth=0] - Current rendering depth
|
|
3459
|
-
* @returns {string} Rendered HTML string
|
|
3460
|
-
*
|
|
3461
|
-
* @example
|
|
3462
|
-
* const html = renderer.render({
|
|
3463
|
-
* div: {
|
|
3464
|
-
* className: 'container',
|
|
3465
|
-
* children: [
|
|
3466
|
-
* { h1: { text: 'Title' } },
|
|
3467
|
-
* { p: { text: 'Content' } }
|
|
3468
|
-
* ]
|
|
3469
|
-
* }
|
|
3470
|
-
* });
|
|
3471
|
-
*/
|
|
3472
|
-
render(component, options = {}) {
|
|
3473
|
-
const config = { ...this.config, ...options };
|
|
3474
|
-
this.startTiming();
|
|
3475
|
-
try {
|
|
3476
|
-
if (config.validateInput && !this.isValidComponent(component)) {
|
|
3477
|
-
throw new Error("Invalid component structure");
|
|
3478
|
-
}
|
|
3479
|
-
const html = this.renderComponent(component, config, 0);
|
|
3480
|
-
const finalHtml = config.minify ? minifyHtml(html, config) : html;
|
|
3481
|
-
this.endTiming();
|
|
3482
|
-
this.recordPerformance("render", this.metrics.startTime, false, {
|
|
3483
|
-
cacheEnabled: config.enableCache
|
|
3484
|
-
});
|
|
3485
|
-
return finalHtml;
|
|
3486
|
-
} catch (_error) {
|
|
3487
|
-
this.recordError("render", _error);
|
|
3488
|
-
throw _error;
|
|
3489
|
-
}
|
|
3490
|
-
}
|
|
3491
|
-
/**
|
|
3492
|
-
* Render a single component with full optimization pipeline
|
|
3493
|
-
*/
|
|
3494
|
-
renderComponent(component, options, depth = 0) {
|
|
3495
|
-
this.validateDepth(depth);
|
|
3496
|
-
const { type, value } = this.processComponentType(component);
|
|
3497
|
-
switch (type) {
|
|
3498
|
-
case "empty":
|
|
3499
|
-
return "";
|
|
3500
|
-
case "text":
|
|
3501
|
-
return escapeHtml2(value);
|
|
3502
|
-
case "function":
|
|
3503
|
-
const result = this.executeFunctionComponent(value, depth);
|
|
3504
|
-
return this.renderComponent(result, options, depth + 1);
|
|
3505
|
-
case "array":
|
|
3506
|
-
return value.map((child) => this.renderComponent(child, options, depth + 1)).join("");
|
|
3507
|
-
case "element":
|
|
3508
|
-
const tagName = Object.keys(value)[0];
|
|
3509
|
-
const elementContent = value[tagName];
|
|
3510
|
-
return this.renderElement(tagName, elementContent, options, depth);
|
|
3511
|
-
default:
|
|
3512
|
-
this.recordError("renderComponent", new Error(`Unknown component type: ${type}`));
|
|
3513
|
-
return "";
|
|
3514
|
-
}
|
|
3515
|
-
}
|
|
3516
|
-
/**
|
|
3517
|
-
* Render an HTML element with advanced caching and optimization
|
|
3518
|
-
*/
|
|
3519
|
-
renderElement(tagName, element, options, depth = 0) {
|
|
3520
|
-
const startTime = performance.now();
|
|
3521
|
-
if (options.enableMonitoring && this.cache) {
|
|
3522
|
-
}
|
|
3523
|
-
if (options.enableCache && this.cache && RendererUtils.isStaticElement(element)) {
|
|
3524
|
-
const cacheKey = `static:${tagName}:${JSON.stringify(element)}`;
|
|
3525
|
-
const cached = this.cache.get("static", cacheKey);
|
|
3526
|
-
if (cached) {
|
|
3527
|
-
this.recordPerformance(tagName, startTime, true);
|
|
3528
|
-
return cached.value;
|
|
3529
|
-
}
|
|
3530
|
-
}
|
|
3531
|
-
if (typeof element === "string" || typeof element === "number" || typeof element === "boolean") {
|
|
3532
|
-
const html2 = isVoidElement2(tagName) ? `<${tagName}>` : `<${tagName}>${escapeHtml2(String(element))}</${tagName}>`;
|
|
3533
|
-
this.cacheIfStatic(tagName, element, html2, options);
|
|
3534
|
-
this.recordPerformance(tagName, startTime, false);
|
|
3535
|
-
return html2;
|
|
3536
|
-
}
|
|
3537
|
-
if (typeof element === "function") {
|
|
3538
|
-
const result = this.executeFunctionComponent(element, depth);
|
|
3539
|
-
return this.renderElement(tagName, result, options, depth);
|
|
3540
|
-
}
|
|
3541
|
-
if (element && typeof element === "object") {
|
|
3542
|
-
return this.renderObjectElement(tagName, element, options, depth);
|
|
3543
|
-
}
|
|
3544
|
-
if (element === null || element === void 0) {
|
|
3545
|
-
const html2 = isVoidElement2(tagName) ? `<${tagName}>` : `<${tagName}></${tagName}>`;
|
|
3546
|
-
this.recordPerformance(tagName, startTime, false);
|
|
3547
|
-
return html2;
|
|
3548
|
-
}
|
|
3549
|
-
const html = `<${tagName}>${escapeHtml2(String(element))}</${tagName}>`;
|
|
3550
|
-
this.recordPerformance(tagName, startTime, false);
|
|
3551
|
-
return html;
|
|
3552
|
-
}
|
|
3553
|
-
/**
|
|
3554
|
-
* Cache element if it's static
|
|
3555
|
-
*/
|
|
3556
|
-
cacheIfStatic(tagName, element, html) {
|
|
3557
|
-
if (this.config.enableCache && this.cache && RendererUtils.isStaticElement(element)) {
|
|
3558
|
-
const cacheKey = `static:${tagName}:${JSON.stringify(element)}`;
|
|
3559
|
-
this.cache.set("static", cacheKey, html, {
|
|
3560
|
-
ttlMs: this.config.cacheTTL || 5 * 60 * 1e3,
|
|
3561
|
-
// 5 minutes default
|
|
3562
|
-
size: html.length
|
|
3563
|
-
// Approximate size
|
|
3564
|
-
});
|
|
3565
|
-
}
|
|
3566
|
-
}
|
|
3567
|
-
/**
|
|
3568
|
-
* Render complex object elements with attributes and children
|
|
3569
|
-
*/
|
|
3570
|
-
renderObjectElement(tagName, element, options, depth = 0) {
|
|
3571
|
-
const startTime = performance.now();
|
|
3572
|
-
if (options.enableCache && this.cache) {
|
|
3573
|
-
const cacheKey = RendererUtils.generateCacheKey(tagName, element);
|
|
3574
|
-
if (cacheKey) {
|
|
3575
|
-
const cached = this.cache.get(cacheKey);
|
|
3576
|
-
if (cached) {
|
|
3577
|
-
this.recordPerformance(tagName, startTime, true);
|
|
3578
|
-
return cached;
|
|
3579
|
-
}
|
|
3580
|
-
}
|
|
3581
|
-
}
|
|
3582
|
-
const { children, text, ...attributes } = element || {};
|
|
3583
|
-
const attributeString = formatAttributes2(attributes);
|
|
3584
|
-
const openingTag = attributeString ? `<${tagName} ${attributeString}>` : `<${tagName}>`;
|
|
3585
|
-
let textContent = "";
|
|
3586
|
-
if (text !== void 0) {
|
|
3587
|
-
const isScript = tagName === "script";
|
|
3588
|
-
const isStyle = tagName === "style";
|
|
3589
|
-
const isRawTag = isScript || isStyle;
|
|
3590
|
-
const raw = typeof text === "function" ? String(text()) : String(text);
|
|
3591
|
-
if (isRawTag) {
|
|
3592
|
-
const safe = raw.replace(/<\/(script)/gi, "<\\/$1").replace(/<\/(style)/gi, "<\\/$1").replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
|
|
3593
|
-
textContent = safe;
|
|
3594
|
-
} else {
|
|
3595
|
-
textContent = escapeHtml2(raw);
|
|
3596
|
-
}
|
|
3597
|
-
}
|
|
3598
|
-
let childrenHtml = "";
|
|
3599
|
-
if (hasChildren(element)) {
|
|
3600
|
-
const normalizedChildren = normalizeChildren(children);
|
|
3601
|
-
childrenHtml = normalizedChildren.map((child) => this.renderComponent(child, options, depth + 1)).join("");
|
|
3602
|
-
}
|
|
3603
|
-
const html = `${openingTag}${textContent}${childrenHtml}</${tagName}>`;
|
|
3604
|
-
if (options.enableCache && this.cache && RendererUtils.isCacheable(element, options)) {
|
|
3605
|
-
const cacheKey = RendererUtils.generateCacheKey(tagName, element);
|
|
3606
|
-
if (cacheKey) {
|
|
3607
|
-
this.cache.set(cacheKey, html);
|
|
3608
|
-
}
|
|
3609
|
-
}
|
|
3610
|
-
this.recordPerformance(tagName, startTime, false);
|
|
3611
|
-
return html;
|
|
3612
|
-
}
|
|
3613
|
-
};
|
|
3614
|
-
function render2(component, options = {}) {
|
|
3615
|
-
const mergedOptions = {
|
|
3616
|
-
enableCache: true,
|
|
3617
|
-
enableMonitoring: false,
|
|
3618
|
-
...options
|
|
3619
|
-
};
|
|
3620
|
-
const renderer = new HTMLRenderer(mergedOptions);
|
|
3621
|
-
return renderer.render(component, mergedOptions);
|
|
3622
|
-
}
|
|
3623
|
-
|
|
3624
|
-
// ../core/src/utils/render-utils.js
|
|
3625
|
-
function renderWithMonitoring(component, options = {}) {
|
|
3626
|
-
const {
|
|
3627
|
-
enablePerformanceMonitoring = false
|
|
3628
|
-
} = options;
|
|
3629
|
-
let html;
|
|
3630
|
-
if (enablePerformanceMonitoring) {
|
|
3631
|
-
const renderId = performanceMonitor2.startRender();
|
|
3632
|
-
html = render2(component);
|
|
3633
|
-
performanceMonitor2.endRender(renderId);
|
|
3634
|
-
} else {
|
|
3635
|
-
html = render2(component);
|
|
3636
|
-
}
|
|
3637
|
-
return html;
|
|
3638
|
-
}
|
|
3639
|
-
function renderWithTemplate(component, options = {}) {
|
|
3640
|
-
const {
|
|
3641
|
-
template = "<!DOCTYPE html>\n{{content}}"
|
|
3642
|
-
} = options;
|
|
3643
|
-
const html = renderWithMonitoring(component, options);
|
|
3644
|
-
return template.replace("{{content}}", html);
|
|
3645
|
-
}
|
|
3646
|
-
async function renderComponentFactory(componentFactory, factoryArgs, options = {}) {
|
|
3647
|
-
const component = await Promise.resolve(
|
|
3648
|
-
componentFactory(...factoryArgs)
|
|
3649
|
-
);
|
|
3650
|
-
if (!component) {
|
|
3651
|
-
throw new Error("Component factory returned null/undefined");
|
|
3652
|
-
}
|
|
3653
|
-
return renderWithTemplate(component, options);
|
|
3654
|
-
}
|
|
3655
|
-
|
|
3656
32
|
// src/coherent-nextjs.js
|
|
33
|
+
var import_core = require("@coherent.js/core");
|
|
3657
34
|
function createCoherentNextHandler(componentFactory, options = {}) {
|
|
3658
35
|
return async (req, res) => {
|
|
3659
36
|
try {
|
|
3660
|
-
const finalHtml = await renderComponentFactory(
|
|
37
|
+
const finalHtml = await (0, import_core.renderComponentFactory)(
|
|
3661
38
|
componentFactory,
|
|
3662
39
|
[req, res],
|
|
3663
40
|
options
|
|
@@ -3673,7 +50,7 @@ function createCoherentNextHandler(componentFactory, options = {}) {
|
|
|
3673
50
|
function createCoherentAppRouterHandler(componentFactory, options = {}) {
|
|
3674
51
|
return async function handler(request) {
|
|
3675
52
|
try {
|
|
3676
|
-
const finalHtml = await renderComponentFactory(
|
|
53
|
+
const finalHtml = await (0, import_core.renderComponentFactory)(
|
|
3677
54
|
componentFactory,
|
|
3678
55
|
[request],
|
|
3679
56
|
options
|
|
@@ -3700,7 +77,7 @@ async function createCoherentServerComponent(componentFactory, options = {}) {
|
|
|
3700
77
|
} = options;
|
|
3701
78
|
let React;
|
|
3702
79
|
try {
|
|
3703
|
-
React = await importPeerDependency("react", "React");
|
|
80
|
+
React = await (0, import_core.importPeerDependency)("react", "React");
|
|
3704
81
|
} catch (_error) {
|
|
3705
82
|
throw new Error(
|
|
3706
83
|
`Next.js Server Component integration requires React. ${_error.message}`
|
|
@@ -3716,11 +93,11 @@ async function createCoherentServerComponent(componentFactory, options = {}) {
|
|
|
3716
93
|
}
|
|
3717
94
|
let html;
|
|
3718
95
|
if (enablePerformanceMonitoring) {
|
|
3719
|
-
const renderId = performanceMonitor.startRender();
|
|
3720
|
-
html = render(component);
|
|
3721
|
-
performanceMonitor.endRender(renderId);
|
|
96
|
+
const renderId = import_core.performanceMonitor.startRender();
|
|
97
|
+
html = (0, import_core.render)(component);
|
|
98
|
+
import_core.performanceMonitor.endRender(renderId);
|
|
3722
99
|
} else {
|
|
3723
|
-
html = render(component);
|
|
100
|
+
html = (0, import_core.render)(component);
|
|
3724
101
|
}
|
|
3725
102
|
return React.default.createElement("div", {
|
|
3726
103
|
dangerouslySetInnerHTML: { __html: html }
|
|
@@ -3737,7 +114,7 @@ async function createCoherentClientComponent(componentFactory, options = {}) {
|
|
|
3737
114
|
} = options;
|
|
3738
115
|
let React;
|
|
3739
116
|
try {
|
|
3740
|
-
React = await importPeerDependency("react", "React");
|
|
117
|
+
React = await (0, import_core.importPeerDependency)("react", "React");
|
|
3741
118
|
} catch (_error) {
|
|
3742
119
|
throw new Error(
|
|
3743
120
|
`Next.js Client Component integration requires React. ${_error.message}`
|
|
@@ -3757,11 +134,11 @@ async function createCoherentClientComponent(componentFactory, options = {}) {
|
|
|
3757
134
|
}
|
|
3758
135
|
let renderedHtml;
|
|
3759
136
|
if (enablePerformanceMonitoring) {
|
|
3760
|
-
const renderId = performanceMonitor.startRender();
|
|
3761
|
-
renderedHtml = render(component);
|
|
3762
|
-
performanceMonitor.endRender(renderId);
|
|
137
|
+
const renderId = import_core.performanceMonitor.startRender();
|
|
138
|
+
renderedHtml = (0, import_core.render)(component);
|
|
139
|
+
import_core.performanceMonitor.endRender(renderId);
|
|
3763
140
|
} else {
|
|
3764
|
-
renderedHtml = render(component);
|
|
141
|
+
renderedHtml = (0, import_core.render)(component);
|
|
3765
142
|
}
|
|
3766
143
|
setHtml(renderedHtml);
|
|
3767
144
|
} catch (_error) {
|
|
@@ -3778,8 +155,8 @@ async function createCoherentClientComponent(componentFactory, options = {}) {
|
|
|
3778
155
|
}
|
|
3779
156
|
async function createNextIntegration(options = {}) {
|
|
3780
157
|
try {
|
|
3781
|
-
await importPeerDependency("next", "Next.js");
|
|
3782
|
-
await importPeerDependency("react", "React");
|
|
158
|
+
await (0, import_core.importPeerDependency)("next", "Next.js");
|
|
159
|
+
await (0, import_core.importPeerDependency)("react", "React");
|
|
3783
160
|
return {
|
|
3784
161
|
createCoherentNextHandler: (componentFactory, handlerOptions = {}) => createCoherentNextHandler(componentFactory, { ...options, ...handlerOptions }),
|
|
3785
162
|
createCoherentAppRouterHandler: (componentFactory, handlerOptions = {}) => createCoherentAppRouterHandler(componentFactory, { ...options, ...handlerOptions }),
|
|
@@ -3805,18 +182,4 @@ var coherent_nextjs_default = {
|
|
|
3805
182
|
createCoherentServerComponent,
|
|
3806
183
|
createNextIntegration
|
|
3807
184
|
});
|
|
3808
|
-
/**
|
|
3809
|
-
* Coherent.js - Object-Based Rendering Framework
|
|
3810
|
-
* A pure JavaScript framework for server-side rendering using natural object syntax
|
|
3811
|
-
*
|
|
3812
|
-
* @version 2.0.0
|
|
3813
|
-
* @author Coherent Framework Team
|
|
3814
|
-
* @license MIT
|
|
3815
|
-
*/
|
|
3816
|
-
/**
|
|
3817
|
-
* Advanced caching system with memory management and smart invalidation for Coherent.js
|
|
3818
|
-
*
|
|
3819
|
-
* @module @coherent/performance/cache-manager
|
|
3820
|
-
* @license MIT
|
|
3821
|
-
*/
|
|
3822
185
|
//# sourceMappingURL=index.cjs.map
|